efct: Broadcom (Emulex) FC Target driver
Subsystems (2)
v8 cover efct: Broadcom (Emulex) FC Target driver
This patch set is a request to incorporate the new Broadcom (Emulex) FC target driver, efct, into the kernel source tree.
The driver source has been Announced a couple of times, the last version on 1/07/2021. The driver has been hosted on gitlab for review has had contributions from the community.
gitlab ([email protected]:jsmart/efct-Emulex_FC_Target.git)
The driver integrates into the source tree at the (new) drivers/scsi/elx subdirectory.
The driver consists of the following components:
- A libefc_sli subdirectory: This subdirectory contains a library that encapsulates common definitions and routines for an Emulex SLI-4 adapter.
- A libefc subdirectory: This subdirectory contains a library of common routines. Of major import is a number of routines that implement a FC Discovery engine for target mode.
- An efct subdirectory: This subdirectory contains the efct target mode device driver. The driver utilizes the above librarys and plugs into the SCSI LIO interfaces. The driver is SCSI only at this time.
The patches populate the libraries and device driver and can only be compiled as a complete set.
This driver is completely independent from the lpfc device driver and there is no overlap on PCI ID's.
The patches have been cut against the 5.11/scsi-queue branch.
Thank you to those that have contributed to the driver in the past.
Review comments welcome!
-- james
Note: cpu offline/online support will be added at a later time
V8 modifications:
Added link module type defines which are used for evaluating link
supported speeds.
Added sli_get_lmt helper function.
Rename struct efc_vport_spec to efc_vport.
efc_vport naming changes.
Mark els_io_enabled to true, when re-authenticating the node. Remove chip error checks, as we are anyway checking while submitting
the command.
efct_xport_detach to void, Simplified getting supported speeds routine. Return value fixes and function prototype changes.
Use READ_ONCE/WRITE_ONCE for abort_in_progress flag. Complete node registration after target backend session is established. Converted target_submit_cmd() to
target_init_cmd/target_submit_prep/target_submit
Converted efct_scsi_recv_cmd() prototype to a void
Check return values of efct_hw_command.
Remove waiting for flushing pending commands in reset and teardown path. Remove unused stubs,.
Add 64G and 128G to host speed reporting.
Use link speed to detect the port state.
V7 modifications:
Change els functions to return status from efc_els_send_rsp() Fix return codes in efct_hw_config_mrq()
Ensure an EFC_XXX status value is returned (not numerical constants)
Style: break declaration assignment into declaration and later value
assignment.
V6 modifications:
Refactor for better indentation and reduced else's
Refactor to use structure elements directly and avoid local vars Slight update to node_sm_trace macro
convert efc_nport_cb() to not return a value
moved libefc/efc_lib.c to libefc/efclib.c
Reword comment in efc_node_handle_explicit_logo() efc_disc_io_complete(): update WARN_ON to WARN_ON_ONCE Change els send functions to return status from efc_els_send_req() Ensure an EFC_XXX status value is returned (not numerical constants) Dynamically allocate wq_cpu_array rather than fixed size array Fix return variables to have same type as routine
Ensure an EFCT_HW_XXX status value is returned (not numerical constants) Kernel doc format changes for efct_io structure.
Cleanup of meaningless comments in efct_scsi_cmd_resp declaration in hw rtns: Replace EFC_FAIL status with EFCT_HW_XXX status values add kfree to efct_hw_teardown()
V5 modifications:
Copyright for 2021 year change.
Fixed kernel test robot reported warnings.
Changed BMBX_WRITE defines to static inline functions. Common naming for topology defines.
Remove efc_log_test.
Topology naming changes.
Indentation change.
Changed argument list for sli_cmd_reg_fcfi/ sli_cmd_reg_fcfi_mrq Added Mempool for ELS ios.
Remove EFC_HW_NODE_XXX and EFC_HW_NPORT_XXX events. Use EFC_EVT_XXX events directly for port and node callbacks. Remove node_list from nport and use xarray lookup. Use WRITE_ONCE/READ_ONCE for els_io_enabled flag. Replace nport_list with xarray lookup related changes. Topology naming changes.
ELS IO mempool changes.
EFC_EVT_XXX name changes.
Replace global efct_devices array with linked list. Add support for FC speed 64G and 128G
Use list_del_int() when needed.
V4 modifications:
Copyright year change.
Fixed cppcheck tool reported warnings.
Ran pahole tool, fixed padding for most of the structures. Support for Multiple RQs and EQs.
New user driver node structure to avoid lock contension in IO path. libefc_sli:
Add [email protected] in MAINTAINERS
Changed doorbell defines to inline functions
Code cleanup: Indentation, code simplification, unnecessary brackets Added SLI4_ prefix to missing defines
Moved driver specific structures to the end of the file. Page size calculation changes
Reduce function parameters for WQE filling functions Changed wait functions to use usleep_range and time_before apis Removed size input for all the cmds as its fixed to SLI4_BMBX_SIZE. Changed all SLI mbox routines to memset using SLI_BMBX_SIZE. All WQE helper routines to use sli->wqe_size for memset.
libefc:
Remove the " EFC_SM_EVENT_START" id and define SM events serially. Moved hold frames and pending frames handling to library. Added efc locking notes.
Added kref to domain, nport and node objects.
Renamed efc_sli_port object to efc_nport
Reworked on APIs and libefc_function_template.
Moved ELS handling to Library
Moved registering discovery objects to library.
Added issue_mbox_rqst, send_els, send_bls template functions. Changes to use new function template
Get Domain Ref count when a new nport is added
Release domain ref when nport is freed.
Renamed efc_sport.[ch] to efc_nport.[ch]
Add kref support for Nport structure.
Upon received PRLI, wait for LIO session registation before sending
the PRLI response.
Changes to call new els functions.
Move all state machine functions return value from void * to void. Replace fall through commnet with fallthrough statement. New patch added ELS handling to libefc library.
New els_io_req for discovery io object.
New patch cmds to register VFI, VPI and RPI.
Removed all hw related template calls and added issue_mbox_rqst
template call.
Consolidate all the discovery related mbox related cmds in discovery
library.
Replaced allocation of command buffer for mailbox with stack variable.
efct driver:
New library Template registration and associated functions Muti-RQ support, configure mrq.
Configure filter to send all ELS traffic to one RQ and remaining IOs
to all RQs.
CPU based WQ scaling.
Allocate loop map during initialization
Remove redundant includes in efc_driver.h
Remove els entries from scsi io object as discovery object handles it. Changed unsol frame handling.
Lookup for efct target node based on d_id and s_id.
Rework IO path to not look up discovery object every time. Changes to reduce function params for efct_hw_io_send Changes to create efct_node(user driver specific node) and store
lookup id.
Removed debugfs interface.
Reduced the argument list for WQE filling routines.
V3 modifications:
Changed anonymous enums to named enums
Split gaint enums into multiple enums
Use defines to spell out _MASK values directly
Changed multiple #defines to named enums and a few vice versa cases
for consistency
Added Link Speed support for up to 128G
Removed efc_assert define. Replaced with WARN_ON. Returned defined return values EFC_SUCCESS & EFC_FAIL Added return values for routines returning more than those 2 values Reduction of calling arguments in various routines. Expanded dump type and status handling
Fixed locking in discovery handling routines.
Fixed line formatting length and indentation issues. Removed code that was not used.
Removed Sparse Vector APIs and structures. Use xarray api instead. Changed node pool creation. Use mempool and allocate dma memory when
required
Bug Fix: Send LS_RJT for non FCP PRLIs
Removed Queue topology string and parsing routines and rework queue
creation. Adapter configuration is implicitly known by the driver
Used request_threaded_irq instead of using our thread Reworked efct_device_attach function to use if statements and gotos Changed efct_fw_reset, removed accessing other port Convert to used pci_alloc_irq_vectors api
Removed proc interface.
Changed assertion log messages.
Unified log message using cmd_name
Removed DIF related code which is not used
Removed SCSI get property
Incorporated LIO interface review comments
Reworked xxx_reg_vpi/vfi routines
Use SPDX license in elx/Makefile
Many more small changes.
V2 modifications:
Contains the following modifications based on prior review comments:
Indentation/Alignment/Spacing changes
Comments: format cleanup; removed obvious or unnecessary comments;
Added comments for clarity.
Headers use #ifndef comparing for prior inclusion
Cleanup structure names (remove _s suffix)
Encapsulate use of macro arguments
Refactor to remove static function declarations for static local routines Removed unused variables
Fix SLI4_INTF_VALID_MASK for 32bits
Ensure no BIT() use
Use __ffs() in page count macro
Reorg to move field defines out of structure definition Commonize command building routines to reduce duplication
LIO interface:
Removed scsi initiator includes
Cleaned up interface defines
Removed lio WWN version attribute.
Expanded macros within logging macros
Cleaned up lio state setting macro
Remove __force use
Modularized session debugfs code so can be easily replaced. Cleaned up abort task handling. Return after initiating. Modularized where possible to reduce duplication
Convert from kthread to workqueue use
Remove unused macros
Add missing TARGET_CORE build attribute
Fix kbuild test robot warnings
Comments not addressed:
Use of __packed: not believed necessary
Session debugfs code remains. There is not yet a common lio
mechanism to replace with.
James Smart (31):
elx: libefc_sli: SLI-4 register offsets and field definitions
elx: libefc_sli: SLI Descriptors and Queue entries
elx: libefc_sli: Data structures and defines for mbox commands
elx: libefc_sli: queue create/destroy/parse routines
elx: libefc_sli: Populate and post different WQEs
elx: libefc_sli: bmbx routines and SLI config commands
elx: libefc_sli: APIs to setup SLI library
elx: libefc: Generic state machine framework
elx: libefc: Emulex FC discovery library APIs and definitions
elx: libefc: FC Domain state machine interfaces
elx: libefc: SLI and FC PORT state machine interfaces
elx: libefc: Remote node state machine interfaces
elx: libefc: Fabric node state machine interfaces
elx: libefc: FC node ELS and state handling
elx: libefc: Extended link Service IO handling
elx: libefc: Register discovery objects with hardware
elx: efct: Data structures and defines for hw operations
elx: efct: Driver initialization routines
elx: efct: Hardware queues creation and deletion
elx: efct: RQ buffer, memory pool allocation and deallocation APIs
elx: efct: Hardware IO and SGL initialization
elx: efct: Hardware queues processing
elx: efct: Unsolicited FC frame processing routines
elx: efct: SCSI IO handling routines
elx: efct: LIO backend interface routines
elx: efct: Hardware IO submission routines
elx: efct: link and host statistics
elx: efct: xport and hardware teardown routines
elx: efct: scsi_transport_fc host interface support
elx: efct: Add Makefile and Kconfig for efct driver
elx: efct: Tie into kernel Kconfig and build process
MAINTAINERS | 9 + drivers/scsi/Kconfig | 2 + drivers/scsi/Makefile | 1 + drivers/scsi/elx/Kconfig | 9 + drivers/scsi/elx/Makefile | 18 + drivers/scsi/elx/efct/efct_driver.c | 788 ++++ drivers/scsi/elx/efct/efct_driver.h | 109 + drivers/scsi/elx/efct/efct_hw.c | 3610 +++++++++++++++++ drivers/scsi/elx/efct/efct_hw.h | 779 ++++ drivers/scsi/elx/efct/efct_hw_queues.c | 679 ++++ drivers/scsi/elx/efct/efct_io.c | 191 + drivers/scsi/elx/efct/efct_io.h | 174 + drivers/scsi/elx/efct/efct_lio.c | 1699 ++++++++ drivers/scsi/elx/efct/efct_lio.h | 189 + drivers/scsi/elx/efct/efct_scsi.c | 1164 ++++++ drivers/scsi/elx/efct/efct_scsi.h | 207 + drivers/scsi/elx/efct/efct_unsol.c | 493 +++ drivers/scsi/elx/efct/efct_unsol.h | 17 + drivers/scsi/elx/efct/efct_xport.c | 1204 ++++++ drivers/scsi/elx/efct/efct_xport.h | 186 + drivers/scsi/elx/include/efc_common.h | 41 + drivers/scsi/elx/libefc/efc.h | 69 + drivers/scsi/elx/libefc/efc_cmds.c | 777 ++++ drivers/scsi/elx/libefc/efc_cmds.h | 35 + drivers/scsi/elx/libefc/efc_device.c | 1601 ++++++++ drivers/scsi/elx/libefc/efc_device.h | 72 + drivers/scsi/elx/libefc/efc_domain.c | 1093 +++++ drivers/scsi/elx/libefc/efc_domain.h | 54 + drivers/scsi/elx/libefc/efc_els.c | 1099 +++++ drivers/scsi/elx/libefc/efc_els.h | 107 + drivers/scsi/elx/libefc/efc_fabric.c | 1565 +++++++ drivers/scsi/elx/libefc/efc_fabric.h | 116 + drivers/scsi/elx/libefc/efc_node.c | 1104 +++++ drivers/scsi/elx/libefc/efc_node.h | 191 + drivers/scsi/elx/libefc/efc_nport.c | 792 ++++ drivers/scsi/elx/libefc/efc_nport.h | 50 + drivers/scsi/elx/libefc/efc_sm.c | 54 + drivers/scsi/elx/libefc/efc_sm.h | 197 + drivers/scsi/elx/libefc/efclib.c | 81 + drivers/scsi/elx/libefc/efclib.h | 601 +++ drivers/scsi/elx/libefc_sli/sli4.c | 5170 ++++++++++++++++++++++++ drivers/scsi/elx/libefc_sli/sli4.h | 4133 +++++++++++++++++++ 42 files changed, 30530 insertions(+) create mode 100644 drivers/scsi/elx/Kconfig create mode 100644 drivers/scsi/elx/Makefile create mode 100644 drivers/scsi/elx/efct/efct_driver.c create mode 100644 drivers/scsi/elx/efct/efct_driver.h create mode 100644 drivers/scsi/elx/efct/efct_hw.c create mode 100644 drivers/scsi/elx/efct/efct_hw.h create mode 100644 drivers/scsi/elx/efct/efct_hw_queues.c create mode 100644 drivers/scsi/elx/efct/efct_io.c create mode 100644 drivers/scsi/elx/efct/efct_io.h create mode 100644 drivers/scsi/elx/efct/efct_lio.c create mode 100644 drivers/scsi/elx/efct/efct_lio.h create mode 100644 drivers/scsi/elx/efct/efct_scsi.c create mode 100644 drivers/scsi/elx/efct/efct_scsi.h create mode 100644 drivers/scsi/elx/efct/efct_unsol.c create mode 100644 drivers/scsi/elx/efct/efct_unsol.h create mode 100644 drivers/scsi/elx/efct/efct_xport.c create mode 100644 drivers/scsi/elx/efct/efct_xport.h create mode 100644 drivers/scsi/elx/include/efc_common.h create mode 100644 drivers/scsi/elx/libefc/efc.h create mode 100644 drivers/scsi/elx/libefc/efc_cmds.c create mode 100644 drivers/scsi/elx/libefc/efc_cmds.h create mode 100644 drivers/scsi/elx/libefc/efc_device.c create mode 100644 drivers/scsi/elx/libefc/efc_device.h create mode 100644 drivers/scsi/elx/libefc/efc_domain.c create mode 100644 drivers/scsi/elx/libefc/efc_domain.h create mode 100644 drivers/scsi/elx/libefc/efc_els.c create mode 100644 drivers/scsi/elx/libefc/efc_els.h create mode 100644 drivers/scsi/elx/libefc/efc_fabric.c create mode 100644 drivers/scsi/elx/libefc/efc_fabric.h create mode 100644 drivers/scsi/elx/libefc/efc_node.c create mode 100644 drivers/scsi/elx/libefc/efc_node.h create mode 100644 drivers/scsi/elx/libefc/efc_nport.c create mode 100644 drivers/scsi/elx/libefc/efc_nport.h create mode 100644 drivers/scsi/elx/libefc/efc_sm.c create mode 100644 drivers/scsi/elx/libefc/efc_sm.h create mode 100644 drivers/scsi/elx/libefc/efclib.c create mode 100644 drivers/scsi/elx/libefc/efclib.h create mode 100644 drivers/scsi/elx/libefc_sli/sli4.c create mode 100644 drivers/scsi/elx/libefc_sli/sli4.h
Signature · 1 line
2.26.2
PATCH v8 1/31 elx: libefc_sli: SLI-4 register offsets and field definitions
This is the initial patch for the new Emulex target mode SCSI driver sources.
This patch:
- Creates the new Emulex source level directory drivers/scsi/elx and adds the directory to the MAINTAINERS file.
- Creates the first library subdirectory drivers/scsi/elx/libefc_sli. This library is a SLI-4 interface library.
- Starts the population of the libefc_sli library with definitions of SLI-4 hardware register offsets and definitions.
--- MAINTAINERS | 9 + drivers/scsi/elx/libefc_sli/sli4.c | 22 +++ drivers/scsi/elx/libefc_sli/sli4.h | 308 +++++++++++++++++++++++++++++ 3 files changed, 339 insertions(+) create mode 100644 drivers/scsi/elx/libefc_sli/sli4.c create mode 100644 drivers/scsi/elx/libefc_sli/sli4.h
MAINTAINERS +9 -0
@@ -6610,6 +6610,15 @@ S: Supported W: http://www.broadcom.com F: drivers/scsi/lpfc/ +EMULEX/BROADCOM EFCT FC/FCOE SCSI TARGET DRIVER +M: James Smart <[email protected]> +M: Ram Vegesna <[email protected]> +L: [email protected] +L: [email protected] +S: Supported +W: http://www.broadcom.com +F: drivers/scsi/elx/ + ENE CB710 FLASH CARD READER DRIVER M: Michał Mirosław <[email protected]> S: Maintained
drivers/scsi/elx/libefc_sli/sli4.c new file +22 -0
@@ -0,0 +1,22 @@ +// SPDX-License-Identifier: GPL-2.0 +/* +* Copyright (C) 2021 Broadcom. All Rights Reserved. The term +* “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. +*/ + +/** +* All common (i.e. transport-independent) SLI-4 functions are implemented +* in this file. +*/ +#include "sli4.h" + +static struct sli4_asic_entry_t sli4_asic_table[] = { + {SLI4_ASIC_REV_B0 ,SLI4_ASIC_GEN_5 }, + {SLI4_ASIC_REV_D0 ,SLI4_ASIC_GEN_5 }, + {SLI4_ASIC_REV_A3 ,SLI4_ASIC_GEN_6 }, + {SLI4_ASIC_REV_A0 ,SLI4_ASIC_GEN_6 }, + {SLI4_ASIC_REV_A1 ,SLI4_ASIC_GEN_6 }, + {SLI4_ASIC_REV_A3 ,SLI4_ASIC_GEN_6 }, + {SLI4_ASIC_REV_A1 ,SLI4_ASIC_GEN_7 }, + {SLI4_ASIC_REV_A0 ,SLI4_ASIC_GEN_7 }, +};
drivers/scsi/elx/libefc_sli/sli4.h new file +308 -0
308 lines not on this page · raw message
Signature · 1 line
2.26.2
PATCH v8 2/31 elx: libefc_sli: SLI Descriptors and Queue entries
In reply to James SmartThis patch continues the libefc_sli SLI-4 library population.
This patch add SLI-4 Data structures and defines for:
- Buffer Descriptors (BDEs)
- Scatter/Gather List elements (SGEs)
- Queues and their Entry Descriptions for:
Event Queues (EQs), Completion Queues (CQs), Receive Queues (RQs), and the Mailbox Queue (MQ).
--- drivers/scsi/elx/include/efc_common.h | 25 + drivers/scsi/elx/libefc_sli/sli4.h | 1776 +++++++++++++++++++++++++ 2 files changed, 1801 insertions(+) create mode 100644 drivers/scsi/elx/include/efc_common.h
drivers/scsi/elx/include/efc_common.h new file +25 -0
@@ -0,0 +1,25 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* +* Copyright (C) 2021 Broadcom. All Rights Reserved. The term +* “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. +*/ + +#ifndef __EFC_COMMON_H__ +#define __EFC_COMMON_H__ + +#include <linux/pci.h> + +#define EFC_SUCCESS 0 +#define EFC_FAIL 1 + +struct efc_dma { +void *virt; +void *alloc; +dma_addr_t phys; + +size_t size; +size_t len; +struct pci_dev *pdev; +}; + +#endif /* __EFC_COMMON_H__ */
drivers/scsi/elx/libefc_sli/sli4.h +1776 -0
1,780 lines not on this page · raw message
Signature · 1 line
2.26.2
Re: [PATCH v8 02/31] elx: libefc_sli: SLI Descriptors and Queue entries
Quoted 13 lines · James Smart
This patch continues the
libefc_sliSLI-4 library population.This patch add SLI-4 Data structures and defines for:
- Buffer Descriptors (BDEs)
- Scatter/Gather List elements (SGEs)
- Queues and their Entry Descriptions for:
Event Queues (EQs), Completion Queues (CQs), Receive Queues (RQs), and the Mailbox Queue (MQ).Co-developed-by Ram Vegesna <[email protected]>Signed-off-by Ram Vegesna <[email protected]>Signed-off-by James Smart <[email protected]>Reviewed-by Daniel Wagner <[email protected]>
Quoted 6 lines
--- drivers/scsi/elx/include/efc_common.h | 25 + drivers/scsi/elx/libefc_sli/sli4.h | 1776 +++++++++++++++++++++++++ 2 files changed, 1801 insertions(+) create mode 100644 drivers/scsi/elx/include/efc_common.h
Cheers,
Hannes
Signature · 4 lines
Dr. Hannes Reinecke Kernel Storage Architect [email protected] +49 911 74053 688 SUSE Software Solutions Germany GmbH, 90409 Nürnberg GF: F. Imendörffer, HRB 36809 (AG Nürnberg)
PATCH v8 3/31 elx: libefc_sli: Data structures and defines for mbox commands
In reply to James SmartThis patch continues the libefc_sli SLI-4 library population.
This patch adds definitions for SLI-4 mailbox commands and responses.
---
v8:
Added link module type defines which are used for evaluating link supported speeds
--- drivers/scsi/elx/libefc_sli/sli4.h | 1640 +++++++++++++++++++++++++++- 1 file changed, 1639 insertions(+), 1 deletion(-)
drivers/scsi/elx/libefc_sli/sli4.h +1639 -1
@@ -1990,6 +1990,1532 @@ enum sli4_els_cmd_type { SLI4_ELS_REQUEST64_CMD_FABRIC = 0x0d, }; +#define SLI_PAGE_SIZE SZ_4K + +#define SLI4_BMBX_TIMEOUT_MSEC 30000 +#define SLI4_FW_READY_TIMEOUT_MSEC 30000 + +#define SLI4_BMBX_DELAY_US 1000/* 1 ms */ +#define SLI4_INIT_PORT_DELAY_US 10000/* 10 ms */ + +static inline u32 +sli_page_count (size_t bytes,u32 page_size) +{ +if (!page_size) +return 0 ; + +return (bytes + (page_size -1 )) >>__ffs (page_size); +} + +/************************************************************************* +* SLI-4 mailbox command formats and definitions +*/ + +struct sli4_mbox_command_header { +u8 resvd0; +u8 command; +__le16 status;/* Port writes to indicate success/fail */ +}; + +enum sli4_mbx_cmd_value { +SLI4_MBX_CMD_CONFIG_LINK =0x07 , +SLI4_MBX_CMD_DUMP =0x17 , +SLI4_MBX_CMD_DOWN_LINK =0x06 , +SLI4_MBX_CMD_INIT_LINK =0x05 , +SLI4_MBX_CMD_INIT_VFI =0xa3 , +SLI4_MBX_CMD_INIT_VPI =0xa4 , +SLI4_MBX_CMD_POST_XRI =0xa7 , +SLI4_MBX_CMD_RELEASE_XRI =0xac , +SLI4_MBX_CMD_READ_CONFIG =0x0b , +SLI4_MBX_CMD_READ_STATUS =0x0e , +SLI4_MBX_CMD_READ_NVPARMS =0x02 , +SLI4_MBX_CMD_READ_REV =0x11 , +SLI4_MBX_CMD_READ_LNK_STAT =0x12 , +SLI4_MBX_CMD_READ_SPARM64 =0x8d , +SLI4_MBX_CMD_READ_TOPOLOGY =0x95 , +SLI4_MBX_CMD_REG_FCFI =0xa0 , +SLI4_MBX_CMD_REG_FCFI_MRQ =0xaf , +SLI4_MBX_CMD_REG_RPI =0x93 , +SLI4_MBX_CMD_REG_RX_RQ =0xa6 , +SLI4_MBX_CMD_REG_VFI =0x9f , +SLI4_MBX_CMD_REG_VPI =0x96 , +SLI4_MBX_CMD_RQST_FEATURES =0x9d , +SLI4_MBX_CMD_SLI_CONFIG =0x9b , +SLI4_MBX_CMD_UNREG_FCFI =0xa2 , +SLI4_MBX_CMD_UNREG_RPI =0x14 , +SLI4_MBX_CMD_UNREG_VFI =0xa1 , +SLI4_MBX_CMD_UNREG_VPI =0x97 , +SLI4_MBX_CMD_WRITE_NVPARMS =0x03 , +SLI4_MBX_CMD_CFG_AUTO_XFER_RDY =0xad , +}; + +enum sli4_mbx_status { +SLI4_MBX_STATUS_SUCCESS =0x0000 , +SLI4_MBX_STATUS_FAILURE =0x0001 , +SLI4_MBX_STATUS_RPI_NOT_REG =0x1400 , +}; + +/* CONFIG_LINK - configure link-oriented parameters, +* such as default N_Port_ID address and various timers +*/ +enum sli4_cmd_config_link_flags { +SLI4_CFG_LINK_BBSCN =0xf00 , +SLI4_CFG_LINK_CSCN =0x1000 , +}; + +struct sli4_cmd_config_link { +struct sli4_mbox_command_header hdr; +u8 maxbbc; +u8 rsvd5; +u8 rsvd6; +u8 rsvd7; +u8 alpa; +__le16 n_port_id; +u8 rsvd11; +__le32 rsvd12; +__le32 e_d_tov; +__le32 lp_tov; +__le32 r_a_tov; +__le32 r_t_tov; +__le32 al_tov; +__le32 rsvd36; +__le32 bbscn_dword; +}; + +#define SLI4_DUMP4_TYPE 0xf + +#define SLI4_WKI_TAG_SAT_TEM 0x1040 + +struct sli4_cmd_dump4 { +struct sli4_mbox_command_header hdr; +__le32 type_dword; +__le16 wki_selection; +__le16 rsvd10; +__le32 rsvd12; +__le32 returned_byte_cnt; +__le32 resp_data[59 ]; +}; + +/* INIT_LINK - initialize the link for a FC port */ +enum sli4_init_link_flags { +SLI4_INIT_LINK_F_LOOPBACK =1 <<0 , + +SLI4_INIT_LINK_F_P2P_ONLY =1 <<1 , +SLI4_INIT_LINK_F_FCAL_ONLY =2 <<1 , +SLI4_INIT_LINK_F_FCAL_FAIL_OVER =0 <<1 , +SLI4_INIT_LINK_F_P2P_FAIL_OVER =1 <<1 , + +SLI4_INIT_LINK_F_UNFAIR =1 <<6 , +SLI4_INIT_LINK_F_NO_LIRP =1 <<7 , +SLI4_INIT_LINK_F_LOOP_VALID_CHK =1 <<8 , +SLI4_INIT_LINK_F_NO_LISA =1 <<9 , +SLI4_INIT_LINK_F_FAIL_OVER =1 <<10 , +SLI4_INIT_LINK_F_FIXED_SPEED =1 <<11 , +SLI4_INIT_LINK_F_PICK_HI_ALPA =1 <<15 , + +}; + +enum sli4_fc_link_speed { +SLI4_LINK_SPEED_1G =1 , +SLI4_LINK_SPEED_2G , +SLI4_LINK_SPEED_AUTO_1_2 , +SLI4_LINK_SPEED_4G , +SLI4_LINK_SPEED_AUTO_4_1 , +SLI4_LINK_SPEED_AUTO_4_2 , +SLI4_LINK_SPEED_AUTO_4_2_1 , +SLI4_LINK_SPEED_8G , +SLI4_LINK_SPEED_AUTO_8_1 , +SLI4_LINK_SPEED_AUTO_8_2 , +SLI4_LINK_SPEED_AUTO_8_2_1 , +SLI4_LINK_SPEED_AUTO_8_4 , +SLI4_LINK_SPEED_AUTO_8_4_1 , +SLI4_LINK_SPEED_AUTO_8_4_2 , +SLI4_LINK_SPEED_10G , +SLI4_LINK_SPEED_16G , +SLI4_LINK_SPEED_AUTO_16_8_4 , +SLI4_LINK_SPEED_AUTO_16_8 , +SLI4_LINK_SPEED_32G , +SLI4_LINK_SPEED_AUTO_32_16_8 , +SLI4_LINK_SPEED_AUTO_32_16 , +SLI4_LINK_SPEED_64G , +SLI4_LINK_SPEED_AUTO_64_32_16 , +SLI4_LINK_SPEED_AUTO_64_32 , +SLI4_LINK_SPEED_128G , +SLI4_LINK_SPEED_AUTO_128_64_32 , +SLI4_LINK_SPEED_AUTO_128_64 , +}; + +struct sli4_cmd_init_link { +struct sli4_mbox_command_header hdr; +__le32 sel_reset_al_pa_dword; +__le32 flags0; +__le32 link_speed_sel_code; +}; + +/* INIT_VFI - initialize the VFI resource */ +enum sli4_init_vfi_flags { +SLI4_INIT_VFI_FLAG_VP =0x1000 , +SLI4_INIT_VFI_FLAG_VF =0x2000 , +SLI4_INIT_VFI_FLAG_VT =0x4000 , +SLI4_INIT_VFI_FLAG_VR =0x8000 , + +SLI4_INIT_VFI_VFID =0x1fff , +SLI4_INIT_VFI_PRI =0xe000 , + +SLI4_INIT_VFI_HOP_COUNT =0xff000000 , +}; + +struct sli4_cmd_init_vfi { +struct sli4_mbox_command_header hdr; +__le16 vfi; +__le16 flags0_word; +__le16 fcfi; +__le16 vpi; +__le32 vf_id_pri_dword; +__le32 hop_cnt_dword; +}; + +/* INIT_VPI - initialize the VPI resource */ +struct sli4_cmd_init_vpi { +struct sli4_mbox_command_header hdr; +__le16 vpi; +__le16 vfi; +}; + +/* POST_XRI - post XRI resources to the SLI Port */ +enum sli4_post_xri_flags { +SLI4_POST_XRI_COUNT =0xfff , +SLI4_POST_XRI_FLAG_ENX =0x1000 , +SLI4_POST_XRI_FLAG_DL =0x2000 , +SLI4_POST_XRI_FLAG_DI =0x4000 , +SLI4_POST_XRI_FLAG_VAL =0x8000 , +}; + +struct sli4_cmd_post_xri { +struct sli4_mbox_command_header hdr; +__le16 xri_base; +__le16 xri_count_flags; +}; + +/* RELEASE_XRI - Release XRI resources from the SLI Port */ +enum sli4_release_xri_flags { +SLI4_RELEASE_XRI_REL_XRI_CNT =0x1f , +SLI4_RELEASE_XRI_COUNT =0x1f , +}; + +struct sli4_cmd_release_xri { +struct sli4_mbox_command_header hdr; +__le16 rel_xri_count_word; +__le16 xri_count_word; + +struct { +__le16 xri_tag0; +__le16 xri_tag1; + } xri_tbl[62 ]; +}; + +/* READ_CONFIG - read SLI port configuration parameters */ +struct sli4_cmd_read_config { +struct sli4_mbox_command_header hdr; +}; + +enum sli4_read_cfg_resp_flags { +SLI4_READ_CFG_RESP_RESOURCE_EXT =0x80000000 ,/* DW1 */ +SLI4_READ_CFG_RESP_TOPOLOGY =0xff000000 ,/* DW2 */ +}; + +enum sli4_read_cfg_topo { +SLI4_READ_CFG_TOPO_FC =0x1 ,/* FC topology unknown */ +SLI4_READ_CFG_TOPO_NON_FC_AL =0x2 ,/* FC point-to-point or fabric */ +SLI4_READ_CFG_TOPO_FC_AL =0x3 ,/* FC-AL topology */ +}; + +/* Link Module Type */ +enum sli4_read_cfg_lmt { +SLI4_LINK_MODULE_TYPE_1GB =0x0004 , +SLI4_LINK_MODULE_TYPE_2GB =0x0008 , +SLI4_LINK_MODULE_TYPE_4GB =0x0040 , +SLI4_LINK_MODULE_TYPE_8GB =0x0080 , +SLI4_LINK_MODULE_TYPE_16GB =0x0200 , +SLI4_LINK_MODULE_TYPE_32GB =0x0400 , +SLI4_LINK_MODULE_TYPE_64GB =0x0800 , +SLI4_LINK_MODULE_TYPE_128GB =0x1000 , +}; + +struct sli4_rsp_read_config { +struct sli4_mbox_command_header hdr; +__le32 ext_dword; +__le32 topology_dword; +__le32 resvd8; +__le16 e_d_tov; +__le16 resvd14; +__le32 resvd16; +__le16 r_a_tov; +__le16 resvd22; +__le32 resvd24; +__le32 resvd28; +__le16 lmt; +__le16 resvd34; +__le32 resvd36; +__le32 resvd40; +__le16 xri_base; +__le16 xri_count; +__le16 rpi_base; +__le16 rpi_count; +__le16 vpi_base; +__le16 vpi_count; +__le16 vfi_base; +__le16 vfi_count; +__le16 resvd60; +__le16 fcfi_count; +__le16 rq_count; +__le16 eq_count; +__le16 wq_count; +__le16 cq_count; +__le32 pad[45 ]; +}; + +/* READ_NVPARMS - read SLI port configuration parameters */ +enum sli4_read_nvparms_flags { +SLI4_READ_NVPARAMS_HARD_ALPA =0xff , +SLI4_READ_NVPARAMS_PREFERRED_D_ID =0xffffff00 , +}; + +struct sli4_cmd_read_nvparms { +struct sli4_mbox_command_header hdr; +__le32 resvd0; +__le32 resvd4; +__le32 resvd8; +__le32 resvd12; +u8 wwpn[8 ]; +u8 wwnn[8 ]; +__le32 hard_alpa_d_id; +}; + +/* WRITE_NVPARMS - write SLI port configuration parameters */ +struct sli4_cmd_write_nvparms { +struct sli4_mbox_command_header hdr; +__le32 resvd0; +__le32 resvd4; +__le32 resvd8; +__le32 resvd12; +u8 wwpn[8 ]; +u8 wwnn[8 ]; +__le32 hard_alpa_d_id; +}; + +/* READ_REV - read the Port revision levels */ +enum { +SLI4_READ_REV_FLAG_SLI_LEVEL =0xf , +SLI4_READ_REV_FLAG_FCOEM =0x10 , +SLI4_READ_REV_FLAG_CEEV =0x60 , +SLI4_READ_REV_FLAG_VPD =0x2000 , + +SLI4_READ_REV_AVAILABLE_LENGTH =0xffffff , +}; + +struct sli4_cmd_read_rev { +struct sli4_mbox_command_header hdr; +__le16 resvd0; +__le16 flags0_word; +__le32 first_hw_rev; +__le32 second_hw_rev; +__le32 resvd12; +__le32 third_hw_rev; +u8 fc_ph_low; +u8 fc_ph_high; +u8 feature_level_low; +u8 feature_level_high; +__le32 resvd24; +__le32 first_fw_id; +u8 first_fw_name[16 ]; +__le32 second_fw_id; +u8 second_fw_name[16 ]; +__le32 rsvd18[30 ]; +__le32 available_length_dword; +struct sli4_dmaaddr hostbuf; +__le32 returned_vpd_length; +__le32 actual_vpd_length; +}; + +/* READ_SPARM64 - read the Port service parameters */ +#define SLI4_READ_SPARM64_WWPN_OFFSET (4 * sizeof(u32)) +#define SLI4_READ_SPARM64_WWNN_OFFSET (6 * sizeof(u32)) + +struct sli4_cmd_read_sparm64 { +struct sli4_mbox_command_header hdr; +__le32 resvd0; +__le32 resvd4; +struct sli4_bde bde_64; +__le16 vpi; +__le16 resvd22; +__le16 port_name_start; +__le16 port_name_len; +__le16 node_name_start; +__le16 node_name_len; +}; + +/* READ_TOPOLOGY - read the link event information */ +enum sli4_read_topo_e { +SLI4_READTOPO_ATTEN_TYPE =0xff , +SLI4_READTOPO_FLAG_IL =0x100 , +SLI4_READTOPO_FLAG_PB_RECVD =0x200 , + +SLI4_READTOPO_LINKSTATE_RECV =0x3 , +SLI4_READTOPO_LINKSTATE_TRANS =0xc , +SLI4_READTOPO_LINKSTATE_MACHINE =0xf0 , +SLI4_READTOPO_LINKSTATE_SPEED =0xff00 , +SLI4_READTOPO_LINKSTATE_TF =0x40000000 , +SLI4_READTOPO_LINKSTATE_LU =0x80000000 , + +SLI4_READTOPO_SCN_BBSCN =0xf , +SLI4_READTOPO_SCN_CBBSCN =0xf0 , + +SLI4_READTOPO_R_T_TOV =0x1ff , +SLI4_READTOPO_AL_TOV =0xf000 , + +SLI4_READTOPO_PB_FLAG =0x80 , + +SLI4_READTOPO_INIT_N_PORTID =0xffffff , +}; + +#define SLI4_MIN_LOOP_MAP_BYTES 128 + +struct sli4_cmd_read_topology { +struct sli4_mbox_command_header hdr; +__le32 event_tag; +__le32 dw2_attentype; +u8 topology; +u8 lip_type; +u8 lip_al_ps; +u8 al_pa_granted; +struct sli4_bde bde_loop_map; +__le32 linkdown_state; +__le32 currlink_state; +u8 max_bbc; +u8 init_bbc; +u8 scn_flags; +u8 rsvd39; +__le16 dw10w0_al_rt_tov; +__le16 lp_tov; +u8 acquired_al_pa; +u8 pb_flags; +__le16 specified_al_pa; +__le32 dw12_init_n_port_id; +}; + +enum sli4_read_topo_link { +SLI4_READ_TOPOLOGY_LINK_UP =0x1 , +SLI4_READ_TOPOLOGY_LINK_DOWN , +SLI4_READ_TOPOLOGY_LINK_NO_ALPA , +}; + +enum sli4_read_topo { +SLI4_READ_TOPO_UNKNOWN =0x0 , +SLI4_READ_TOPO_NON_FC_AL , +SLI4_READ_TOPO_FC_AL , +}; + +enum sli4_read_topo_speed { +SLI4_READ_TOPOLOGY_SPEED_NONE =0x00 , +SLI4_READ_TOPOLOGY_SPEED_1G =0x04 , +SLI4_READ_TOPOLOGY_SPEED_2G =0x08 , +SLI4_READ_TOPOLOGY_SPEED_4G =0x10 , +SLI4_READ_TOPOLOGY_SPEED_8G =0x20 , +SLI4_READ_TOPOLOGY_SPEED_10G =0x40 , +SLI4_READ_TOPOLOGY_SPEED_16G =0x80 , +SLI4_READ_TOPOLOGY_SPEED_32G =0x90 , +SLI4_READ_TOPOLOGY_SPEED_64G =0xa0 , +SLI4_READ_TOPOLOGY_SPEED_128G =0xb0 , +}; + +/* REG_FCFI - activate a FC Forwarder */ +struct sli4_cmd_reg_fcfi_rq_cfg { +u8 r_ctl_mask; +u8 r_ctl_match; +u8 type_mask; +u8 type_match; +}; + +enum sli4_regfcfi_tag { +SLI4_REGFCFI_VLAN_TAG =0xfff , +SLI4_REGFCFI_VLANTAG_VALID =0x1000 , +}; + +#define SLI4_CMD_REG_FCFI_NUM_RQ_CFG 4 +struct sli4_cmd_reg_fcfi { +struct sli4_mbox_command_header hdr; +__le16 fcf_index; +__le16 fcfi; +__le16 rqid1; +__le16 rqid0; +__le16 rqid3; +__le16 rqid2; +struct sli4_cmd_reg_fcfi_rq_cfg + rq_cfg[SLI4_CMD_REG_FCFI_NUM_RQ_CFG ]; +__le32 dw8_vlan; +}; + +#define SLI4_CMD_REG_FCFI_MRQ_NUM_RQ_CFG 4 +#define SLI4_CMD_REG_FCFI_MRQ_MAX_NUM_RQ 32 +#define SLI4_CMD_REG_FCFI_SET_FCFI_MODE 0 +#define SLI4_CMD_REG_FCFI_SET_MRQ_MODE 1 + +enum sli4_reg_fcfi_mrq { +SLI4_REGFCFI_MRQ_VLAN_TAG =0xfff , +SLI4_REGFCFI_MRQ_VLANTAG_VALID =0x1000 , +SLI4_REGFCFI_MRQ_MODE =0x2000 , + +SLI4_REGFCFI_MRQ_MASK_NUM_PAIRS =0xff , +SLI4_REGFCFI_MRQ_FILTER_BITMASK =0xf00 , +SLI4_REGFCFI_MRQ_RQ_SEL_POLICY =0xf000 , +}; + +struct sli4_cmd_reg_fcfi_mrq { +struct sli4_mbox_command_header hdr; +__le16 fcf_index; +__le16 fcfi; +__le16 rqid1; +__le16 rqid0; +__le16 rqid3; +__le16 rqid2; +struct sli4_cmd_reg_fcfi_rq_cfg + rq_cfg[SLI4_CMD_REG_FCFI_MRQ_NUM_RQ_CFG ]; +__le32 dw8_vlan; +__le32 dw9_mrqflags; +}; + +struct sli4_cmd_rq_cfg { +__le16 rq_id; +u8 r_ctl_mask; +u8 r_ctl_match; +u8 type_mask; +u8 type_match; +}; + +/* REG_RPI - register a Remote Port Indicator */ +enum sli4_reg_rpi { +SLI4_REGRPI_REMOTE_N_PORTID =0xffffff ,/* DW2 */ +SLI4_REGRPI_UPD =0x1000000 , +SLI4_REGRPI_ETOW =0x8000000 , +SLI4_REGRPI_TERP =0x20000000 , +SLI4_REGRPI_CI =0x80000000 , +}; + +struct sli4_cmd_reg_rpi { +struct sli4_mbox_command_header hdr; +__le16 rpi; +__le16 rsvd2; +__le32 dw2_rportid_flags; +struct sli4_bde bde_64; +__le16 vpi; +__le16 rsvd26; +}; + +#define SLI4_REG_RPI_BUF_LEN 0x70 + +/* REG_VFI - register a Virtual Fabric Indicator */ +enum sli_reg_vfi { +SLI4_REGVFI_VP =0x1000 ,/* DW1 */ +SLI4_REGVFI_UPD =0x2000 , + +SLI4_REGVFI_LOCAL_N_PORTID =0xffffff ,/* DW10 */ +}; + +struct sli4_cmd_reg_vfi { +struct sli4_mbox_command_header hdr; +__le16 vfi; +__le16 dw0w1_flags; +__le16 fcfi; +__le16 vpi; +u8 wwpn[8 ]; +struct sli4_bde sparm; +__le32 e_d_tov; +__le32 r_a_tov; +__le32 dw10_lportid_flags; +}; + +/* REG_VPI - register a Virtual Port Indicator */ +enum sli4_reg_vpi { +SLI4_REGVPI_LOCAL_N_PORTID =0xffffff , +SLI4_REGVPI_UPD =0x1000000 , +}; + +struct sli4_cmd_reg_vpi { +struct sli4_mbox_command_header hdr; +__le32 rsvd0; +__le32 dw2_lportid_flags; +u8 wwpn[8 ]; +__le32 rsvd12; +__le16 vpi; +__le16 vfi; +}; + +/* REQUEST_FEATURES - request / query SLI features */ +enum sli4_req_features_flags { +SLI4_REQFEAT_QRY =0x1 ,/* Dw1 */ + +SLI4_REQFEAT_IAAB =1 <<0 ,/* DW2 & DW3 */ +SLI4_REQFEAT_NPIV =1 <<1 , +SLI4_REQFEAT_DIF =1 <<2 , +SLI4_REQFEAT_VF =1 <<3 , +SLI4_REQFEAT_FCPI =1 <<4 , +SLI4_REQFEAT_FCPT =1 <<5 , +SLI4_REQFEAT_FCPC =1 <<6 , +SLI4_REQFEAT_RSVD =1 <<7 , +SLI4_REQFEAT_RQD =1 <<8 , +SLI4_REQFEAT_IAAR =1 <<9 , +SLI4_REQFEAT_HLM =1 <<10 , +SLI4_REQFEAT_PERFH =1 <<11 , +SLI4_REQFEAT_RXSEQ =1 <<12 , +SLI4_REQFEAT_RXRI =1 <<13 , +SLI4_REQFEAT_DCL2 =1 <<14 , +SLI4_REQFEAT_RSCO =1 <<15 , +SLI4_REQFEAT_MRQP =1 <<16 , +}; + +struct sli4_cmd_request_features { +struct sli4_mbox_command_header hdr; +__le32 dw1_qry; +__le32 cmd; +__le32 resp; +}; + +/* +* SLI_CONFIG - submit a configuration command to Port +* +* Command is either embedded as part of the payload (embed) or located +* in a separate memory buffer (mem) +*/ +enum sli4_sli_config { +SLI4_SLICONF_EMB =0x1 ,/* DW1 */ +SLI4_SLICONF_PMDCMD_SHIFT =3 , +SLI4_SLICONF_PMDCMD_MASK =0xf8 , +SLI4_SLICONF_PMDCMD_VAL_1 =8 , +SLI4_SLICONF_PMDCNT =0xf8 , + +SLI4_SLICONF_PMD_LEN =0x00ffffff , +}; + +struct sli4_cmd_sli_config { +struct sli4_mbox_command_header hdr; +__le32 dw1_flags; +__le32 payload_len; +__le32 rsvd12[3 ]; +union { +u8 embed[58 *sizeof (u32)]; +struct sli4_bufptr mem; + } payload; +}; + +/* READ_STATUS - read tx/rx status of a particular port */ +#define SLI4_READSTATUS_CLEAR_COUNTERS 0x1 + +struct sli4_cmd_read_status { +struct sli4_mbox_command_header hdr; +__le32 dw1_flags; +__le32 rsvd4; +__le32 trans_kbyte_cnt; +__le32 recv_kbyte_cnt; +__le32 trans_frame_cnt; +__le32 recv_frame_cnt; +__le32 trans_seq_cnt; +__le32 recv_seq_cnt; +__le32 tot_exchanges_orig; +__le32 tot_exchanges_resp; +__le32 recv_p_bsy_cnt; +__le32 recv_f_bsy_cnt; +__le32 no_rq_buf_dropped_frames_cnt; +__le32 empty_rq_timeout_cnt; +__le32 no_xri_dropped_frames_cnt; +__le32 empty_xri_pool_cnt; +}; + +/* READ_LNK_STAT - read link status of a particular port */ +enum sli4_read_link_stats_flags { +SLI4_READ_LNKSTAT_REC =1u <<0 , +SLI4_READ_LNKSTAT_GEC =1u <<1 , +SLI4_READ_LNKSTAT_W02OF =1u <<2 , +SLI4_READ_LNKSTAT_W03OF =1u <<3 , +SLI4_READ_LNKSTAT_W04OF =1u <<4 , +SLI4_READ_LNKSTAT_W05OF =1u <<5 , +SLI4_READ_LNKSTAT_W06OF =1u <<6 , +SLI4_READ_LNKSTAT_W07OF =1u <<7 , +SLI4_READ_LNKSTAT_W08OF =1u <<8 , +SLI4_READ_LNKSTAT_W09OF =1u <<9 , +SLI4_READ_LNKSTAT_W10OF =1u <<10 , +SLI4_READ_LNKSTAT_W11OF =1u <<11 , +SLI4_READ_LNKSTAT_W12OF =1u <<12 , +SLI4_READ_LNKSTAT_W13OF =1u <<13 , +SLI4_READ_LNKSTAT_W14OF =1u <<14 , +SLI4_READ_LNKSTAT_W15OF =1u <<15 , +SLI4_READ_LNKSTAT_W16OF =1u <<16 , +SLI4_READ_LNKSTAT_W17OF =1u <<17 , +SLI4_READ_LNKSTAT_W18OF =1u <<18 , +SLI4_READ_LNKSTAT_W19OF =1u <<19 , +SLI4_READ_LNKSTAT_W20OF =1u <<20 , +SLI4_READ_LNKSTAT_W21OF =1u <<21 , +SLI4_READ_LNKSTAT_CLRC =1u <<30 , +SLI4_READ_LNKSTAT_CLOF =1u <<31 , +}; + +struct sli4_cmd_read_link_stats { +struct sli4_mbox_command_header hdr; +__le32 dw1_flags; +__le32 linkfail_errcnt; +__le32 losssync_errcnt; +__le32 losssignal_errcnt; +__le32 primseq_errcnt; +__le32 inval_txword_errcnt; +__le32 crc_errcnt; +__le32 primseq_eventtimeout_cnt; +__le32 elastic_bufoverrun_errcnt; +__le32 arbit_fc_al_timeout_cnt; +__le32 adv_rx_buftor_to_buf_credit; +__le32 curr_rx_buf_to_buf_credit; +__le32 adv_tx_buf_to_buf_credit; +__le32 curr_tx_buf_to_buf_credit; +__le32 rx_eofa_cnt; +__le32 rx_eofdti_cnt; +__le32 rx_eofni_cnt; +__le32 rx_soff_cnt; +__le32 rx_dropped_no_aer_cnt; +__le32 rx_dropped_no_avail_rpi_rescnt; +__le32 rx_dropped_no_avail_xri_rescnt; +}; + +/* Format a WQE with WQ_ID Association performance hint */ +static inline void +sli_set_wq_id_association (void *entry,u16 q_id) +{ +u32 *wqe = entry; + +/* +* Set Word 10, bit 0 to zero +* Set Word 10, bits 15:1 to the WQ ID +*/ + wqe[10 ] &= ~0xffff ; + wqe[10 ] |= q_id <<1 ; +} + +/* UNREG_FCFI - unregister a FCFI */ +struct sli4_cmd_unreg_fcfi { +struct sli4_mbox_command_header hdr; +__le32 rsvd0; +__le16 fcfi; +__le16 rsvd6; +}; + +/* UNREG_RPI - unregister one or more RPI */ +enum sli4_unreg_rpi { +SLI4_UNREG_RPI_DP =0x2000 , +SLI4_UNREG_RPI_II_SHIFT =14 , +SLI4_UNREG_RPI_II_MASK =0xc000 , +SLI4_UNREG_RPI_II_RPI =0x0000 , +SLI4_UNREG_RPI_II_VPI =0x4000 , +SLI4_UNREG_RPI_II_VFI =0x8000 , +SLI4_UNREG_RPI_II_FCFI =0xc000 , + +SLI4_UNREG_RPI_DEST_N_PORTID_MASK =0x00ffffff , +}; + +struct sli4_cmd_unreg_rpi { +struct sli4_mbox_command_header hdr; +__le16 index; +__le16 dw1w1_flags; +__le32 dw2_dest_n_portid; +}; + +/* UNREG_VFI - unregister one or more VFI */ +enum sli4_unreg_vfi { +SLI4_UNREG_VFI_II_SHIFT =14 , +SLI4_UNREG_VFI_II_MASK =0xc000 , +SLI4_UNREG_VFI_II_VFI =0x0000 , +SLI4_UNREG_VFI_II_FCFI =0xc000 , +}; + +struct sli4_cmd_unreg_vfi { +struct sli4_mbox_command_header hdr; +__le32 rsvd0; +__le16 index; +__le16 dw2_flags; +}; + +enum sli4_unreg_type { +SLI4_UNREG_TYPE_PORT , +SLI4_UNREG_TYPE_DOMAIN , +SLI4_UNREG_TYPE_FCF , +SLI4_UNREG_TYPE_ALL +}; + +/* UNREG_VPI - unregister one or more VPI */ +enum sli4_unreg_vpi { +SLI4_UNREG_VPI_II_SHIFT =14 , +SLI4_UNREG_VPI_II_MASK =0xc000 , +SLI4_UNREG_VPI_II_VPI =0x0000 , +SLI4_UNREG_VPI_II_VFI =0x8000 , +SLI4_UNREG_VPI_II_FCFI =0xc000 , +}; + +struct sli4_cmd_unreg_vpi { +struct sli4_mbox_command_header hdr; +__le32 rsvd0; +__le16 index; +__le16 dw2w0_flags; +}; + +/* AUTO_XFER_RDY - Configure the auto-generate XFER-RDY feature */ +struct sli4_cmd_config_auto_xfer_rdy { +struct sli4_mbox_command_header hdr; +__le32 rsvd0; +__le32 max_burst_len; +}; + +#define SLI4_CONFIG_AUTO_XFERRDY_BLKSIZE 0xffff + +struct sli4_cmd_config_auto_xfer_rdy_hp { +struct sli4_mbox_command_header hdr; +__le32 rsvd0; +__le32 max_burst_len; +__le32 dw3_esoc_flags; +__le16 block_size; +__le16 rsvd14; +}; + +/************************************************************************* +* SLI-4 common configuration command formats and definitions +*/ + +/* +* Subsystem values. +*/ +enum sli4_subsystem { +SLI4_SUBSYSTEM_COMMON =0x01 , +SLI4_SUBSYSTEM_LOWLEVEL =0x0b , +SLI4_SUBSYSTEM_FC =0x0c , +SLI4_SUBSYSTEM_DMTF =0x11 , +}; + +#define SLI4_OPC_LOWLEVEL_SET_WATCHDOG 0X36 + +/* +* Common opcode (OPC) values. +*/ +enum sli4_cmn_opcode { +SLI4_CMN_FUNCTION_RESET =0x3d , +SLI4_CMN_CREATE_CQ =0x0c , +SLI4_CMN_CREATE_CQ_SET =0x1d , +SLI4_CMN_DESTROY_CQ =0x36 , +SLI4_CMN_MODIFY_EQ_DELAY =0x29 , +SLI4_CMN_CREATE_EQ =0x0d , +SLI4_CMN_DESTROY_EQ =0x37 , +SLI4_CMN_CREATE_MQ_EXT =0x5a , +SLI4_CMN_DESTROY_MQ =0x35 , +SLI4_CMN_GET_CNTL_ATTRIBUTES =0x20 , +SLI4_CMN_NOP =0x21 , +SLI4_CMN_GET_RSC_EXTENT_INFO =0x9a , +SLI4_CMN_GET_SLI4_PARAMS =0xb5 , +SLI4_CMN_QUERY_FW_CONFIG =0x3a , +SLI4_CMN_GET_PORT_NAME =0x4d , + +SLI4_CMN_WRITE_FLASHROM =0x07 , +/* TRANSCEIVER Data */ +SLI4_CMN_READ_TRANS_DATA =0x49 , +SLI4_CMN_GET_CNTL_ADDL_ATTRS =0x79 , +SLI4_CMN_GET_FUNCTION_CFG =0xa0 , +SLI4_CMN_GET_PROFILE_CFG =0xa4 , +SLI4_CMN_SET_PROFILE_CFG =0xa5 , +SLI4_CMN_GET_PROFILE_LIST =0xa6 , +SLI4_CMN_GET_ACTIVE_PROFILE =0xa7 , +SLI4_CMN_SET_ACTIVE_PROFILE =0xa8 , +SLI4_CMN_READ_OBJECT =0xab , +SLI4_CMN_WRITE_OBJECT =0xac , +SLI4_CMN_DELETE_OBJECT =0xae , +SLI4_CMN_READ_OBJECT_LIST =0xad , +SLI4_CMN_SET_DUMP_LOCATION =0xb8 , +SLI4_CMN_SET_FEATURES =0xbf , +SLI4_CMN_GET_RECFG_LINK_INFO =0xc9 , +SLI4_CMN_SET_RECNG_LINK_ID =0xca , +}; + +/* DMTF opcode (OPC) values */ +#define DMTF_EXEC_CLP_CMD 0x01 + +/* +* COMMON_FUNCTION_RESET +* +* Resets the Port, returning it to a power-on state. This configuration +* command does not have a payload and should set/expect the lengths to +* be zero. +*/ +struct sli4_rqst_cmn_function_reset { +struct sli4_rqst_hdr hdr; +}; + +struct sli4_rsp_cmn_function_reset { +struct sli4_rsp_hdr hdr; +}; + + +/* +* COMMON_GET_CNTL_ATTRIBUTES +* +* Query for information about the SLI Port +*/ +enum sli4_cntrl_attr_flags { +SLI4_CNTL_ATTR_PORTNUM =0x3f , +SLI4_CNTL_ATTR_PORTTYPE =0xc0 , +}; + +struct sli4_rsp_cmn_get_cntl_attributes { +struct sli4_rsp_hdr hdr; +u8 version_str[32 ]; +u8 manufacturer_name[32 ]; +__le32 supported_modes; +u8 eprom_version_lo; +u8 eprom_version_hi; +__le16 rsvd17; +__le32 mbx_ds_version; +__le32 ep_fw_ds_version; +u8 ncsi_version_str[12 ]; +__le32 def_extended_timeout; +u8 model_number[32 ]; +u8 description[64 ]; +u8 serial_number[32 ]; +u8 ip_version_str[32 ]; +u8 fw_version_str[32 ]; +u8 bios_version_str[32 ]; +u8 redboot_version_str[32 ]; +u8 driver_version_str[32 ]; +u8 fw_on_flash_version_str[32 ]; +__le32 functionalities_supported; +__le16 max_cdb_length; +u8 asic_revision; +u8 generational_guid0; +__le32 generational_guid1_12[3 ]; +__le16 generational_guid13_14; +u8 generational_guid15; +u8 hba_port_count; +__le16 default_link_down_timeout; +u8 iscsi_version_min_max; +u8 multifunctional_device; +u8 cache_valid; +u8 hba_status; +u8 max_domains_supported; +u8 port_num_type_flags; +__le32 firmware_post_status; +__le32 hba_mtu; +u8 iscsi_features; +u8 rsvd121[3 ]; +__le16 pci_vendor_id; +__le16 pci_device_id; +__le16 pci_sub_vendor_id; +__le16 pci_sub_system_id; +u8 pci_bus_number; +u8 pci_device_number; +u8 pci_function_number; +u8 interface_type; +__le64 unique_identifier; +u8 number_of_netfilters; +u8 rsvd122[3 ]; +}; + +/* +* COMMON_GET_CNTL_ATTRIBUTES +* +* This command queries the controller information from the Flash ROM. +*/ +struct sli4_rqst_cmn_get_cntl_addl_attributes { +struct sli4_rqst_hdr hdr; +}; + +struct sli4_rsp_cmn_get_cntl_addl_attributes { +struct sli4_rsp_hdr hdr; +__le16 ipl_file_number; +u8 ipl_file_version; +u8 rsvd4; +u8 on_die_temperature; +u8 rsvd5[3 ]; +__le32 driver_advanced_features_supported; +__le32 rsvd7[4 ]; +char universal_bios_version[32 ]; +char x86_bios_version[32 ]; +char efi_bios_version[32 ]; +char fcode_version[32 ]; +char uefi_bios_version[32 ]; +char uefi_nic_version[32 ]; +char uefi_fcode_version[32 ]; +char uefi_iscsi_version[32 ]; +char iscsi_x86_bios_version[32 ]; +char pxe_x86_bios_version[32 ]; +u8 default_wwpn[8 ]; +u8 ext_phy_version[32 ]; +u8 fc_universal_bios_version[32 ]; +u8 fc_x86_bios_version[32 ]; +u8 fc_efi_bios_version[32 ]; +u8 fc_fcode_version[32 ]; +u8 ext_phy_crc_label[8 ]; +u8 ipl_file_name[16 ]; +u8 rsvd139[72 ]; +}; + +/* +* COMMON_NOP +* +* This command does not do anything; it only returns +* the payload in the completion. +*/ +struct sli4_rqst_cmn_nop { +struct sli4_rqst_hdr hdr; +__le32 context[2 ]; +}; + +struct sli4_rsp_cmn_nop { +struct sli4_rsp_hdr hdr; +__le32 context[2 ]; +}; + +struct sli4_rqst_cmn_get_resource_extent_info { +struct sli4_rqst_hdr hdr; +__le16 resource_type; +__le16 rsvd16; +}; + +enum sli4_rsc_type { +SLI4_RSC_TYPE_VFI =0x20 , +SLI4_RSC_TYPE_VPI =0x21 , +SLI4_RSC_TYPE_RPI =0x22 , +SLI4_RSC_TYPE_XRI =0x23 , +}; + +struct sli4_rsp_cmn_get_resource_extent_info { +struct sli4_rsp_hdr hdr; +__le16 resource_extent_count; +__le16 resource_extent_size; +}; + +#define SLI4_128BYTE_WQE_SUPPORT 0x02 + +#define GET_Q_CNT_METHOD (m) \ + (((m) & SLI4_PARAM_Q_CNT_MTHD_MASK) >> SLI4_PARAM_Q_CNT_MTHD_SHFT) +#define GET_Q_CREATE_VERSION (v) \ + (((v) & SLI4_PARAM_QV_MASK) >> SLI4_PARAM_QV_SHIFT) + +enum sli4_rsp_get_params_e { +/*GENERIC*/ +SLI4_PARAM_Q_CNT_MTHD_SHFT =24 , +SLI4_PARAM_Q_CNT_MTHD_MASK =0xf <<24 , +SLI4_PARAM_QV_SHIFT =14 , +SLI4_PARAM_QV_MASK =3 <<14 , + +/* DW4 */ +SLI4_PARAM_PROTO_TYPE_MASK =0xff , +/* DW5 */ +SLI4_PARAM_FT =1 <<0 , +SLI4_PARAM_SLI_REV_MASK =0xf <<4 , +SLI4_PARAM_SLI_FAM_MASK =0xf <<8 , +SLI4_PARAM_IF_TYPE_MASK =0xf <<12 , +SLI4_PARAM_SLI_HINT1_MASK =0xff <<16 , +SLI4_PARAM_SLI_HINT2_MASK =0x1f <<24 , +/* DW6 */ +SLI4_PARAM_EQ_PAGE_CNT_MASK =0xf <<0 , +SLI4_PARAM_EQE_SZS_MASK =0xf <<8 , +SLI4_PARAM_EQ_PAGE_SZS_MASK =0xff <<16 , +/* DW8 */ +SLI4_PARAM_CQ_PAGE_CNT_MASK =0xf <<0 , +SLI4_PARAM_CQE_SZS_MASK =0xf <<8 , +SLI4_PARAM_CQ_PAGE_SZS_MASK =0xff <<16 , +/* DW10 */ +SLI4_PARAM_MQ_PAGE_CNT_MASK =0xf <<0 , +SLI4_PARAM_MQ_PAGE_SZS_MASK =0xff <<16 , +/* DW12 */ +SLI4_PARAM_WQ_PAGE_CNT_MASK =0xf <<0 , +SLI4_PARAM_WQE_SZS_MASK =0xf <<8 , +SLI4_PARAM_WQ_PAGE_SZS_MASK =0xff <<16 , +/* DW14 */ +SLI4_PARAM_RQ_PAGE_CNT_MASK =0xf <<0 , +SLI4_PARAM_RQE_SZS_MASK =0xf <<8 , +SLI4_PARAM_RQ_PAGE_SZS_MASK =0xff <<16 , +/* DW15W1*/ +SLI4_PARAM_RQ_DB_WINDOW_MASK =0xf000 , +/* DW16 */ +SLI4_PARAM_FC =1 <<0 , +SLI4_PARAM_EXT =1 <<1 , +SLI4_PARAM_HDRR =1 <<2 , +SLI4_PARAM_SGLR =1 <<3 , +SLI4_PARAM_FBRR =1 <<4 , +SLI4_PARAM_AREG =1 <<5 , +SLI4_PARAM_TGT =1 <<6 , +SLI4_PARAM_TERP =1 <<7 , +SLI4_PARAM_ASSI =1 <<8 , +SLI4_PARAM_WCHN =1 <<9 , +SLI4_PARAM_TCCA =1 <<10 , +SLI4_PARAM_TRTY =1 <<11 , +SLI4_PARAM_TRIR =1 <<12 , +SLI4_PARAM_PHOFF =1 <<13 , +SLI4_PARAM_PHON =1 <<14 , +SLI4_PARAM_PHWQ =1 <<15 , +SLI4_PARAM_BOUND_4GA =1 <<16 , +SLI4_PARAM_RXC =1 <<17 , +SLI4_PARAM_HLM =1 <<18 , +SLI4_PARAM_IPR =1 <<19 , +SLI4_PARAM_RXRI =1 <<20 , +SLI4_PARAM_SGLC =1 <<21 , +SLI4_PARAM_TIMM =1 <<22 , +SLI4_PARAM_TSMM =1 <<23 , +SLI4_PARAM_OAS =1 <<25 , +SLI4_PARAM_LC =1 <<26 , +SLI4_PARAM_AGXF =1 <<27 , +SLI4_PARAM_LOOPBACK_MASK =0xf <<28 , +/* DW18 */ +SLI4_PARAM_SGL_PAGE_CNT_MASK =0xf <<0 , +SLI4_PARAM_SGL_PAGE_SZS_MASK =0xff <<8 , +SLI4_PARAM_SGL_PP_ALIGN_MASK =0xff <<16 , +}; + +struct sli4_rqst_cmn_get_sli4_params { +struct sli4_rqst_hdr hdr; +}; + +struct sli4_rsp_cmn_get_sli4_params { +struct sli4_rsp_hdr hdr; +__le32 dw4_protocol_type; +__le32 dw5_sli; +__le32 dw6_eq_page_cnt; +__le16 eqe_count_mask; +__le16 rsvd26; +__le32 dw8_cq_page_cnt; +__le16 cqe_count_mask; +__le16 rsvd34; +__le32 dw10_mq_page_cnt; +__le16 mqe_count_mask; +__le16 rsvd42; +__le32 dw12_wq_page_cnt; +__le16 wqe_count_mask; +__le16 rsvd50; +__le32 dw14_rq_page_cnt; +__le16 rqe_count_mask; +__le16 dw15w1_rq_db_window; +__le32 dw16_loopback_scope; +__le32 sge_supported_length; +__le32 dw18_sgl_page_cnt; +__le16 min_rq_buffer_size; +__le16 rsvd75; +__le32 max_rq_buffer_size; +__le16 physical_xri_max; +__le16 physical_rpi_max; +__le16 physical_vpi_max; +__le16 physical_vfi_max; +__le32 rsvd88; +__le16 frag_num_field_offset; +__le16 frag_num_field_size; +__le16 sgl_index_field_offset; +__le16 sgl_index_field_size; +__le32 chain_sge_initial_value_lo; +__le32 chain_sge_initial_value_hi; +}; + +/*Port Types*/ +enum sli4_port_types { +SLI4_PORT_TYPE_ETH =0 , +SLI4_PORT_TYPE_FC =1 , +}; + +struct sli4_rqst_cmn_get_port_name { +struct sli4_rqst_hdr hdr; +u8 port_type; +u8 rsvd4[3 ]; +}; + +struct sli4_rsp_cmn_get_port_name { +struct sli4_rsp_hdr hdr; +char port_name[4 ]; +}; + +struct sli4_rqst_cmn_write_flashrom { +struct sli4_rqst_hdr hdr; +__le32 flash_rom_access_opcode; +__le32 flash_rom_access_operation_type; +__le32 data_buffer_size; +__le32 offset; +u8 data_buffer[4 ]; +}; + +/* +* COMMON_READ_TRANSCEIVER_DATA +* +* This command reads SFF transceiver data(Format is defined +* by the SFF-8472 specification). +*/ +struct sli4_rqst_cmn_read_transceiver_data { +struct sli4_rqst_hdr hdr; +__le32 page_number; +__le32 port; +}; + +struct sli4_rsp_cmn_read_transceiver_data { +struct sli4_rsp_hdr hdr; +__le32 page_number; +__le32 port; +u8 page_data[128 ]; +u8 page_data_2[128 ]; +}; + +#define SLI4_REQ_DESIRE_READLEN 0xffffff + +struct sli4_rqst_cmn_read_object { +struct sli4_rqst_hdr hdr; +__le32 desired_read_length_dword; +__le32 read_offset; +u8 object_name[104 ]; +__le32 host_buffer_descriptor_count; +struct sli4_bde host_buffer_descriptor[0 ]; +}; + +#define RSP_COM_READ_OBJ_EOF 0x80000000 + +struct sli4_rsp_cmn_read_object { +struct sli4_rsp_hdr hdr; +__le32 actual_read_length; +__le32 eof_dword; +}; + +enum sli4_rqst_write_object_flags { +SLI4_RQ_DES_WRITE_LEN =0xffffff , +SLI4_RQ_DES_WRITE_LEN_NOC =0x40000000 , +SLI4_RQ_DES_WRITE_LEN_EOF =0x80000000 , +}; + +struct sli4_rqst_cmn_write_object { +struct sli4_rqst_hdr hdr; +__le32 desired_write_len_dword; +__le32 write_offset; +u8 object_name[104 ]; +__le32 host_buffer_descriptor_count; +struct sli4_bde host_buffer_descriptor[0 ]; +}; + +#define RSP_CHANGE_STATUS 0xff + +struct sli4_rsp_cmn_write_object { +struct sli4_rsp_hdr hdr; +__le32 actual_write_length; +__le32 change_status_dword; +}; + +struct sli4_rqst_cmn_delete_object { +struct sli4_rqst_hdr hdr; +__le32 rsvd4; +__le32 rsvd5; +u8 object_name[104 ]; +}; + +#define SLI4_RQ_OBJ_LIST_READ_LEN 0xffffff + +struct sli4_rqst_cmn_read_object_list { +struct sli4_rqst_hdr hdr; +__le32 desired_read_length_dword; +__le32 read_offset; +u8 object_name[104 ]; +__le32 host_buffer_descriptor_count; +struct sli4_bde host_buffer_descriptor[0 ]; +}; + +enum sli4_rqst_set_dump_flags { +SLI4_CMN_SET_DUMP_BUFFER_LEN =0xffffff , +SLI4_CMN_SET_DUMP_FDB =0x20000000 , +SLI4_CMN_SET_DUMP_BLP =0x40000000 , +SLI4_CMN_SET_DUMP_QRY =0x80000000 , +}; + +struct sli4_rqst_cmn_set_dump_location { +struct sli4_rqst_hdr hdr; +__le32 buffer_length_dword; +__le32 buf_addr_low; +__le32 buf_addr_high; +}; + +struct sli4_rsp_cmn_set_dump_location { +struct sli4_rsp_hdr hdr; +__le32 buffer_length_dword; +}; + +enum sli4_dump_level { +SLI4_DUMP_LEVEL_NONE , +SLI4_CHIP_LEVEL_DUMP , +SLI4_FUNC_DESC_DUMP , +}; + +enum sli4_dump_state { +SLI4_DUMP_STATE_NONE , +SLI4_CHIP_DUMP_STATE_VALID , +SLI4_FUNC_DUMP_STATE_VALID , +}; + +enum sli4_dump_status { +SLI4_DUMP_READY_STATUS_NOT_READY , +SLI4_DUMP_READY_STATUS_DD_PRESENT , +SLI4_DUMP_READY_STATUS_FDB_PRESENT , +SLI4_DUMP_READY_STATUS_SKIP_DUMP , +SLI4_DUMP_READY_STATUS_FAILED =-1 , +}; + +enum sli4_set_features { +SLI4_SET_FEATURES_DIF_SEED =0x01 , +SLI4_SET_FEATURES_XRI_TIMER =0x03 , +SLI4_SET_FEATURES_MAX_PCIE_SPEED =0x04 , +SLI4_SET_FEATURES_FCTL_CHECK =0x05 , +SLI4_SET_FEATURES_FEC =0x06 , +SLI4_SET_FEATURES_PCIE_RECV_DETECT =0x07 , +SLI4_SET_FEATURES_DIF_MEMORY_MODE =0x08 , +SLI4_SET_FEATURES_DISABLE_SLI_PORT_PAUSE_STATE =0x09 , +SLI4_SET_FEATURES_ENABLE_PCIE_OPTIONS =0x0a , +SLI4_SET_FEAT_CFG_AUTO_XFER_RDY_T10PI =0x0c , +SLI4_SET_FEATURES_ENABLE_MULTI_RECEIVE_QUEUE =0x0d , +SLI4_SET_FEATURES_SET_FTD_XFER_HINT =0x0f , +SLI4_SET_FEATURES_SLI_PORT_HEALTH_CHECK =0x11 , +}; + +struct sli4_rqst_cmn_set_features { +struct sli4_rqst_hdr hdr; +__le32 feature; +__le32 param_len; +__le32 params[8 ]; +}; + +struct sli4_rqst_cmn_set_features_dif_seed { +__le16 seed; +__le16 rsvd16; +}; + +enum sli4_rqst_set_mrq_features { +SLI4_RQ_MULTIRQ_ISR =0x1 , +SLI4_RQ_MULTIRQ_AUTOGEN_XFER_RDY =0x2 , + +SLI4_RQ_MULTIRQ_NUM_RQS =0xff , +SLI4_RQ_MULTIRQ_RQ_SELECT =0xf00 , +}; + +struct sli4_rqst_cmn_set_features_multirq { +__le32 auto_gen_xfer_dword; +__le32 num_rqs_dword; +}; + +enum sli4_rqst_health_check_flags { +SLI4_RQ_HEALTH_CHECK_ENABLE =0x1 , +SLI4_RQ_HEALTH_CHECK_QUERY =0x2 , +}; + +struct sli4_rqst_cmn_set_features_health_check { +__le32 health_check_dword; +}; + +struct sli4_rqst_cmn_set_features_set_fdt_xfer_hint { +__le32 fdt_xfer_hint; +}; + +struct sli4_rqst_dmtf_exec_clp_cmd { +struct sli4_rqst_hdr hdr; +__le32 cmd_buf_length; +__le32 resp_buf_length; +__le32 cmd_buf_addr_low; +__le32 cmd_buf_addr_high; +__le32 resp_buf_addr_low; +__le32 resp_buf_addr_high; +}; + +struct sli4_rsp_dmtf_exec_clp_cmd { +struct sli4_rsp_hdr hdr; +__le32 rsvd4; +__le32 resp_length; +__le32 rsvd6; +__le32 rsvd7; +__le32 rsvd8; +__le32 rsvd9; +__le32 clp_status; +__le32 clp_detailed_status; +}; + +#define SLI4_PROTOCOL_FC 0x10 +#define SLI4_PROTOCOL_DEFAULT 0xff + +struct sli4_rspource_descriptor_v1 { +u8 descriptor_type; +u8 descriptor_length; +__le16 rsvd16; +__le32 type_specific[0 ]; +}; + +enum sli4_pcie_desc_flags { +SLI4_PCIE_DESC_IMM =0x4000 , +SLI4_PCIE_DESC_NOSV =0x8000 , + +SLI4_PCIE_DESC_PF_NO =0x3ff0000 , + +SLI4_PCIE_DESC_MISSN_ROLE =0xff , +SLI4_PCIE_DESC_PCHG =0x8000000 , +SLI4_PCIE_DESC_SCHG =0x10000000 , +SLI4_PCIE_DESC_XCHG =0x20000000 , +SLI4_PCIE_DESC_XROM =0xc0000000 +}; + +struct sli4_pcie_resource_descriptor_v1 { +u8 descriptor_type; +u8 descriptor_length; +__le16 imm_nosv_dword; +__le32 pf_number_dword; +__le32 rsvd3; +u8 sriov_state; +u8 pf_state; +u8 pf_type; +u8 rsvd4; +__le16 number_of_vfs; +__le16 rsvd5; +__le32 mission_roles_dword; +__le32 rsvd7[16 ]; +}; + +struct sli4_rqst_cmn_get_function_config { +struct sli4_rqst_hdr hdr; +}; + +struct sli4_rsp_cmn_get_function_config { +struct sli4_rsp_hdr hdr; +__le32 desc_count; +__le32 desc[54 ]; +}; + +/* Link Config Descriptor for link config functions */ +struct sli4_link_config_descriptor { +u8 link_config_id; +u8 rsvd1[3 ]; +__le32 config_description[8 ]; +}; + +#define MAX_LINK_DES 10 + +struct sli4_rqst_cmn_get_reconfig_link_info { +struct sli4_rqst_hdr hdr; +}; + +struct sli4_rsp_cmn_get_reconfig_link_info { +struct sli4_rsp_hdr hdr; +u8 active_link_config_id; +u8 rsvd17; +u8 next_link_config_id; +u8 rsvd19; +__le32 link_configuration_descriptor_count; +struct sli4_link_config_descriptor + desc[MAX_LINK_DES ]; +}; + +enum sli4_set_reconfig_link_flags { +SLI4_SET_RECONFIG_LINKID_NEXT =0xff , +SLI4_SET_RECONFIG_LINKID_FD =1u <<31 , +}; + +struct sli4_rqst_cmn_set_reconfig_link_id { +struct sli4_rqst_hdr hdr; +__le32 dw4_flags; +}; + +struct sli4_rsp_cmn_set_reconfig_link_id { +struct sli4_rsp_hdr hdr; +}; + +struct sli4_rqst_lowlevel_set_watchdog { +struct sli4_rqst_hdr hdr; +__le16 watchdog_timeout; +__le16 rsvd18; +}; + +struct sli4_rsp_lowlevel_set_watchdog { +struct sli4_rsp_hdr hdr; +__le32 rsvd; +}; + +/* FC opcode (OPC) values */ +enum sli4_fc_opcodes { +SLI4_OPC_WQ_CREATE =0x1 , +SLI4_OPC_WQ_DESTROY =0x2 , +SLI4_OPC_POST_SGL_PAGES =0x3 , +SLI4_OPC_RQ_CREATE =0x5 , +SLI4_OPC_RQ_DESTROY =0x6 , +SLI4_OPC_READ_FCF_TABLE =0x8 , +SLI4_OPC_POST_HDR_TEMPLATES =0xb , +SLI4_OPC_REDISCOVER_FCF =0x10 , +}; + +/* Use the default CQ associated with the WQ */ +#define SLI4_CQ_DEFAULT 0xffff + +/* +* POST_SGL_PAGES +* +* Register the scatter gather list (SGL) memory and +* associate it with an XRI. +*/ +struct sli4_rqst_post_sgl_pages { +struct sli4_rqst_hdr hdr; +__le16 xri_start; +__le16 xri_count; +struct { +__le32 page0_low; +__le32 page0_high; +__le32 page1_low; +__le32 page1_high; + } page_set[10 ]; +}; + +struct sli4_rsp_post_sgl_pages { +struct sli4_rsp_hdr hdr; +}; + +struct sli4_rqst_post_hdr_templates { +struct sli4_rqst_hdr hdr; +__le16 rpi_offset; +__le16 page_count; +struct sli4_dmaaddr page_descriptor[0 ]; +}; + +#define SLI4_HDR_TEMPLATE_SIZE 64 + +enum sli4_io_flags { +/* The XRI associated with this IO is already active */ +SLI4_IO_CONTINUATION =1 <<0 , +/* Automatically generate a good RSP frame */ +SLI4_IO_AUTO_GOOD_RESPONSE =1 <<1 , +SLI4_IO_NO_ABORT =1 <<2 , +/* Set the DNRX bit because no auto xref rdy buffer is posted */ +SLI4_IO_DNRX =1 <<3 , +}; + +enum sli4_callback { +SLI4_CB_LINK , +SLI4_CB_MAX , +}; + +enum sli4_link_status { +SLI4_LINK_STATUS_UP , +SLI4_LINK_STATUS_DOWN , +SLI4_LINK_STATUS_NO_ALPA , +SLI4_LINK_STATUS_MAX , +}; + +enum sli4_link_topology { +SLI4_LINK_TOPO_NON_FC_AL =1 , +SLI4_LINK_TOPO_FC_AL , +SLI4_LINK_TOPO_LOOPBACK_INTERNAL , +SLI4_LINK_TOPO_LOOPBACK_EXTERNAL , +SLI4_LINK_TOPO_NONE , +SLI4_LINK_TOPO_MAX , +}; + +enum sli4_link_medium { +SLI4_LINK_MEDIUM_ETHERNET , +SLI4_LINK_MEDIUM_FC , +SLI4_LINK_MEDIUM_MAX , +};/******Driver specific structures******/ struct sli4_queue {
@@ -2020,7 +3546,7 @@ struct sli4_queue { } u; }; -/* Prameters used to populate WQE*/ +/* Parameters used to populate WQE*/ struct sli_bls_params {u32 s_id;u32 d_id;
@@ -2081,4 +3607,116 @@ struct sli_fcp_tgt_params {u16 tag; }; +struct sli4_link_event { +enum sli4_link_status status; +enum sli4_link_topology topology; +enum sli4_link_medium medium; +u32 speed; +u8 *loop_map; +u32 fc_id; +}; + +enum sli4_resource { +SLI4_RSRC_VFI , +SLI4_RSRC_VPI , +SLI4_RSRC_RPI , +SLI4_RSRC_XRI , +SLI4_RSRC_FCFI , +SLI4_RSRC_MAX , +}; + +struct sli4_extent { +u32 number; +u32 size; +u32 n_alloc; +u32 *base; +unsigned long *use_map; +u32 map_size; +}; + +struct sli4_queue_info { +u16 max_qcount[SLI4_QTYPE_MAX ]; +u32 max_qentries[SLI4_QTYPE_MAX ]; +u16 count_mask[SLI4_QTYPE_MAX ]; +u16 count_method[SLI4_QTYPE_MAX ]; +u32 qpage_count[SLI4_QTYPE_MAX ]; +}; + +struct sli4_params { +u8 has_extents; +u8 auto_reg; +u8 auto_xfer_rdy; +u8 hdr_template_req; +u8 perf_hint; +u8 perf_wq_id_association; +u8 cq_create_version; +u8 mq_create_version; +u8 high_login_mode; +u8 sgl_pre_registered; +u8 sgl_pre_reg_required; +u8 t10_dif_inline_capable; +u8 t10_dif_separate_capable; +}; + +struct sli4 { +void *os; +struct pci_dev *pci; +void __iomem *reg[PCI_STD_NUM_BARS ]; + +u32 sli_rev; +u32 sli_family; +u32 if_type; + +u16 asic_type; +u16 asic_rev; + +u16 e_d_tov; +u16 r_a_tov; +struct sli4_queue_info qinfo; +u16 link_module_type; +u8 rq_batch; +u8 port_number; +char port_name[2 ]; +u16 rq_min_buf_size; +u32 rq_max_buf_size; +u8 topology; +u8 wwpn[8 ]; +u8 wwnn[8 ]; +u32 fw_rev[2 ]; +u8 fw_name[2 ][16 ]; +char ipl_name[16 ]; +u32 hw_rev[3 ]; +char modeldesc[64 ]; +char bios_version_string[32 ]; +u32 wqe_size; +u32 vpd_length; +/* +* Tracks the port resources using extents metaphor. For +* devices that don't implement extents (i.e. +* has_extents == FALSE), the code models each resource as +* a single large extent. +*/ +struct sli4_extent ext[SLI4_RSRC_MAX ]; +u32 features; +struct sli4_params params; +u32 sge_supported_length; +u32 sgl_page_sizes; +u32 max_sgl_pages; + +/* +* Callback functions +*/ +int (*link)(void *ctx,void *event); +void *link_arg; + +struct efc_dma bmbx; + +/* Save pointer to physical memory descriptor for non-embedded +* SLI_CONFIG commands for BMBX dumping purposes +*/ +struct efc_dma *bmbx_non_emb_pmd; + +struct efc_dma vpd_data; +}; +#endif /* !_SLI4_H */
Signature · 1 line
2.26.2
Re: [PATCH v8 03/31] elx: libefc_sli: Data structures and defines for mbox commands
Quoted 455 lines · James Smart
This patch continues the
libefc_sliSLI-4 library population.This patch adds definitions for SLI-4 mailbox commands and responses.
Co-developed-by Ram Vegesna <[email protected]>Signed-off-by Ram Vegesna <[email protected]>Signed-off-by James Smart <[email protected]>Reviewed-by Daniel Wagner <[email protected]>---
v8:
Added link module type defines which are used for evaluating link supported speeds--- drivers/scsi/elx/libefc_sli/sli4.h | 1640 +++++++++++++++++++++++++++- 1 file changed, 1639 insertions(+), 1 deletion(-)drivers/scsi/elx/libefc_sli/sli4.h +429
-0@@ -1990,6 +1990,1532 @@ enum sli4_els_cmd_type { SLI4_ELS_REQUEST64_CMD_FABRIC = 0x0d, }; +#define SLI_PAGE_SIZE SZ_4K + +#define SLI4_BMBX_TIMEOUT_MSEC 30000 +#define SLI4_FW_READY_TIMEOUT_MSEC 30000 + +#define SLI4_BMBX_DELAY_US 1000/* 1 ms */ +#define SLI4_INIT_PORT_DELAY_US 10000/* 10 ms */ + +static inline u32 +sli_page_count (size_t bytes,u32 page_size) +{ +if (!page_size) +return 0 ; + +return (bytes + (page_size -1 )) >>__ffs (page_size); +} + +/************************************************************************* +* SLI-4 mailbox command formats and definitions +*/ + +struct sli4_mbox_command_header { +u8 resvd0; +u8 command; +__le16 status;/* Port writes to indicate success/fail */ +}; + +enum sli4_mbx_cmd_value { +SLI4_MBX_CMD_CONFIG_LINK =0x07 , +SLI4_MBX_CMD_DUMP =0x17 , +SLI4_MBX_CMD_DOWN_LINK =0x06 , +SLI4_MBX_CMD_INIT_LINK =0x05 , +SLI4_MBX_CMD_INIT_VFI =0xa3 , +SLI4_MBX_CMD_INIT_VPI =0xa4 , +SLI4_MBX_CMD_POST_XRI =0xa7 , +SLI4_MBX_CMD_RELEASE_XRI =0xac , +SLI4_MBX_CMD_READ_CONFIG =0x0b , +SLI4_MBX_CMD_READ_STATUS =0x0e , +SLI4_MBX_CMD_READ_NVPARMS =0x02 , +SLI4_MBX_CMD_READ_REV =0x11 , +SLI4_MBX_CMD_READ_LNK_STAT =0x12 , +SLI4_MBX_CMD_READ_SPARM64 =0x8d , +SLI4_MBX_CMD_READ_TOPOLOGY =0x95 , +SLI4_MBX_CMD_REG_FCFI =0xa0 , +SLI4_MBX_CMD_REG_FCFI_MRQ =0xaf , +SLI4_MBX_CMD_REG_RPI =0x93 , +SLI4_MBX_CMD_REG_RX_RQ =0xa6 , +SLI4_MBX_CMD_REG_VFI =0x9f , +SLI4_MBX_CMD_REG_VPI =0x96 , +SLI4_MBX_CMD_RQST_FEATURES =0x9d , +SLI4_MBX_CMD_SLI_CONFIG =0x9b , +SLI4_MBX_CMD_UNREG_FCFI =0xa2 , +SLI4_MBX_CMD_UNREG_RPI =0x14 , +SLI4_MBX_CMD_UNREG_VFI =0xa1 , +SLI4_MBX_CMD_UNREG_VPI =0x97 , +SLI4_MBX_CMD_WRITE_NVPARMS =0x03 , +SLI4_MBX_CMD_CFG_AUTO_XFER_RDY =0xad , +}; + +enum sli4_mbx_status { +SLI4_MBX_STATUS_SUCCESS =0x0000 , +SLI4_MBX_STATUS_FAILURE =0x0001 , +SLI4_MBX_STATUS_RPI_NOT_REG =0x1400 , +}; + +/* CONFIG_LINK - configure link-oriented parameters, +* such as default N_Port_ID address and various timers +*/ +enum sli4_cmd_config_link_flags { +SLI4_CFG_LINK_BBSCN =0xf00 , +SLI4_CFG_LINK_CSCN =0x1000 , +}; + +struct sli4_cmd_config_link { +struct sli4_mbox_command_header hdr; +u8 maxbbc; +u8 rsvd5; +u8 rsvd6; +u8 rsvd7; +u8 alpa; +__le16 n_port_id; +u8 rsvd11; +__le32 rsvd12; +__le32 e_d_tov; +__le32 lp_tov; +__le32 r_a_tov; +__le32 r_t_tov; +__le32 al_tov; +__le32 rsvd36; +__le32 bbscn_dword; +}; + +#define SLI4_DUMP4_TYPE 0xf + +#define SLI4_WKI_TAG_SAT_TEM 0x1040 + +struct sli4_cmd_dump4 { +struct sli4_mbox_command_header hdr; +__le32 type_dword; +__le16 wki_selection; +__le16 rsvd10; +__le32 rsvd12; +__le32 returned_byte_cnt; +__le32 resp_data[59 ]; +}; + +/* INIT_LINK - initialize the link for a FC port */ +enum sli4_init_link_flags { +SLI4_INIT_LINK_F_LOOPBACK =1 <<0 , + +SLI4_INIT_LINK_F_P2P_ONLY =1 <<1 , +SLI4_INIT_LINK_F_FCAL_ONLY =2 <<1 , +SLI4_INIT_LINK_F_FCAL_FAIL_OVER =0 <<1 , +SLI4_INIT_LINK_F_P2P_FAIL_OVER =1 <<1 , + +SLI4_INIT_LINK_F_UNFAIR =1 <<6 , +SLI4_INIT_LINK_F_NO_LIRP =1 <<7 , +SLI4_INIT_LINK_F_LOOP_VALID_CHK =1 <<8 , +SLI4_INIT_LINK_F_NO_LISA =1 <<9 , +SLI4_INIT_LINK_F_FAIL_OVER =1 <<10 , +SLI4_INIT_LINK_F_FIXED_SPEED =1 <<11 , +SLI4_INIT_LINK_F_PICK_HI_ALPA =1 <<15 , + +}; + +enum sli4_fc_link_speed { +SLI4_LINK_SPEED_1G =1 , +SLI4_LINK_SPEED_2G , +SLI4_LINK_SPEED_AUTO_1_2 , +SLI4_LINK_SPEED_4G , +SLI4_LINK_SPEED_AUTO_4_1 , +SLI4_LINK_SPEED_AUTO_4_2 , +SLI4_LINK_SPEED_AUTO_4_2_1 , +SLI4_LINK_SPEED_8G , +SLI4_LINK_SPEED_AUTO_8_1 , +SLI4_LINK_SPEED_AUTO_8_2 , +SLI4_LINK_SPEED_AUTO_8_2_1 , +SLI4_LINK_SPEED_AUTO_8_4 , +SLI4_LINK_SPEED_AUTO_8_4_1 , +SLI4_LINK_SPEED_AUTO_8_4_2 , +SLI4_LINK_SPEED_10G , +SLI4_LINK_SPEED_16G , +SLI4_LINK_SPEED_AUTO_16_8_4 , +SLI4_LINK_SPEED_AUTO_16_8 , +SLI4_LINK_SPEED_32G , +SLI4_LINK_SPEED_AUTO_32_16_8 , +SLI4_LINK_SPEED_AUTO_32_16 , +SLI4_LINK_SPEED_64G , +SLI4_LINK_SPEED_AUTO_64_32_16 , +SLI4_LINK_SPEED_AUTO_64_32 , +SLI4_LINK_SPEED_128G , +SLI4_LINK_SPEED_AUTO_128_64_32 , +SLI4_LINK_SPEED_AUTO_128_64 , +}; + +struct sli4_cmd_init_link { +struct sli4_mbox_command_header hdr; +__le32 sel_reset_al_pa_dword; +__le32 flags0; +__le32 link_speed_sel_code; +}; + +/* INIT_VFI - initialize the VFI resource */ +enum sli4_init_vfi_flags { +SLI4_INIT_VFI_FLAG_VP =0x1000 , +SLI4_INIT_VFI_FLAG_VF =0x2000 , +SLI4_INIT_VFI_FLAG_VT =0x4000 , +SLI4_INIT_VFI_FLAG_VR =0x8000 , + +SLI4_INIT_VFI_VFID =0x1fff , +SLI4_INIT_VFI_PRI =0xe000 , + +SLI4_INIT_VFI_HOP_COUNT =0xff000000 , +}; + +struct sli4_cmd_init_vfi { +struct sli4_mbox_command_header hdr; +__le16 vfi; +__le16 flags0_word; +__le16 fcfi; +__le16 vpi; +__le32 vf_id_pri_dword; +__le32 hop_cnt_dword; +}; + +/* INIT_VPI - initialize the VPI resource */ +struct sli4_cmd_init_vpi { +struct sli4_mbox_command_header hdr; +__le16 vpi; +__le16 vfi; +}; + +/* POST_XRI - post XRI resources to the SLI Port */ +enum sli4_post_xri_flags { +SLI4_POST_XRI_COUNT =0xfff , +SLI4_POST_XRI_FLAG_ENX =0x1000 , +SLI4_POST_XRI_FLAG_DL =0x2000 , +SLI4_POST_XRI_FLAG_DI =0x4000 , +SLI4_POST_XRI_FLAG_VAL =0x8000 , +}; + +struct sli4_cmd_post_xri { +struct sli4_mbox_command_header hdr; +__le16 xri_base; +__le16 xri_count_flags; +}; + +/* RELEASE_XRI - Release XRI resources from the SLI Port */ +enum sli4_release_xri_flags { +SLI4_RELEASE_XRI_REL_XRI_CNT =0x1f , +SLI4_RELEASE_XRI_COUNT =0x1f , +}; + +struct sli4_cmd_release_xri { +struct sli4_mbox_command_header hdr; +__le16 rel_xri_count_word; +__le16 xri_count_word; + +struct { +__le16 xri_tag0; +__le16 xri_tag1; + } xri_tbl[62 ]; +}; + +/* READ_CONFIG - read SLI port configuration parameters */ +struct sli4_cmd_read_config { +struct sli4_mbox_command_header hdr; +}; + +enum sli4_read_cfg_resp_flags { +SLI4_READ_CFG_RESP_RESOURCE_EXT =0x80000000 ,/* DW1 */ +SLI4_READ_CFG_RESP_TOPOLOGY =0xff000000 ,/* DW2 */ +}; + +enum sli4_read_cfg_topo { +SLI4_READ_CFG_TOPO_FC =0x1 ,/* FC topology unknown */ +SLI4_READ_CFG_TOPO_NON_FC_AL =0x2 ,/* FC point-to-point or fabric */ +SLI4_READ_CFG_TOPO_FC_AL =0x3 ,/* FC-AL topology */ +}; + +/* Link Module Type */ +enum sli4_read_cfg_lmt { +SLI4_LINK_MODULE_TYPE_1GB =0x0004 , +SLI4_LINK_MODULE_TYPE_2GB =0x0008 , +SLI4_LINK_MODULE_TYPE_4GB =0x0040 , +SLI4_LINK_MODULE_TYPE_8GB =0x0080 , +SLI4_LINK_MODULE_TYPE_16GB =0x0200 , +SLI4_LINK_MODULE_TYPE_32GB =0x0400 , +SLI4_LINK_MODULE_TYPE_64GB =0x0800 , +SLI4_LINK_MODULE_TYPE_128GB =0x1000 , +}; + +struct sli4_rsp_read_config { +struct sli4_mbox_command_header hdr; +__le32 ext_dword; +__le32 topology_dword; +__le32 resvd8; +__le16 e_d_tov; +__le16 resvd14; +__le32 resvd16; +__le16 r_a_tov; +__le16 resvd22; +__le32 resvd24; +__le32 resvd28; +__le16 lmt; +__le16 resvd34; +__le32 resvd36; +__le32 resvd40; +__le16 xri_base; +__le16 xri_count; +__le16 rpi_base; +__le16 rpi_count; +__le16 vpi_base; +__le16 vpi_count; +__le16 vfi_base; +__le16 vfi_count; +__le16 resvd60; +__le16 fcfi_count; +__le16 rq_count; +__le16 eq_count; +__le16 wq_count; +__le16 cq_count; +__le32 pad[45 ]; +}; + +/* READ_NVPARMS - read SLI port configuration parameters */ +enum sli4_read_nvparms_flags { +SLI4_READ_NVPARAMS_HARD_ALPA =0xff , +SLI4_READ_NVPARAMS_PREFERRED_D_ID =0xffffff00 , +}; + +struct sli4_cmd_read_nvparms { +struct sli4_mbox_command_header hdr; +__le32 resvd0; +__le32 resvd4; +__le32 resvd8; +__le32 resvd12; +u8 wwpn[8 ]; +u8 wwnn[8 ]; +__le32 hard_alpa_d_id; +}; + +/* WRITE_NVPARMS - write SLI port configuration parameters */ +struct sli4_cmd_write_nvparms { +struct sli4_mbox_command_header hdr; +__le32 resvd0; +__le32 resvd4; +__le32 resvd8; +__le32 resvd12; +u8 wwpn[8 ]; +u8 wwnn[8 ]; +__le32 hard_alpa_d_id; +}; + +/* READ_REV - read the Port revision levels */ +enum { +SLI4_READ_REV_FLAG_SLI_LEVEL =0xf , +SLI4_READ_REV_FLAG_FCOEM =0x10 , +SLI4_READ_REV_FLAG_CEEV =0x60 , +SLI4_READ_REV_FLAG_VPD =0x2000 , + +SLI4_READ_REV_AVAILABLE_LENGTH =0xffffff , +}; + +struct sli4_cmd_read_rev { +struct sli4_mbox_command_header hdr; +__le16 resvd0; +__le16 flags0_word; +__le32 first_hw_rev; +__le32 second_hw_rev; +__le32 resvd12; +__le32 third_hw_rev; +u8 fc_ph_low; +u8 fc_ph_high; +u8 feature_level_low; +u8 feature_level_high; +__le32 resvd24; +__le32 first_fw_id; +u8 first_fw_name[16 ]; +__le32 second_fw_id; +u8 second_fw_name[16 ]; +__le32 rsvd18[30 ]; +__le32 available_length_dword; +struct sli4_dmaaddr hostbuf; +__le32 returned_vpd_length; +__le32 actual_vpd_length; +}; + +/* READ_SPARM64 - read the Port service parameters */ +#define SLI4_READ_SPARM64_WWPN_OFFSET (4 * sizeof(u32)) +#define SLI4_READ_SPARM64_WWNN_OFFSET (6 * sizeof(u32)) + +struct sli4_cmd_read_sparm64 { +struct sli4_mbox_command_header hdr; +__le32 resvd0; +__le32 resvd4; +struct sli4_bde bde_64; +__le16 vpi; +__le16 resvd22; +__le16 port_name_start; +__le16 port_name_len; +__le16 node_name_start; +__le16 node_name_len; +}; + +/* READ_TOPOLOGY - read the link event information */ +enum sli4_read_topo_e { +SLI4_READTOPO_ATTEN_TYPE =0xff , +SLI4_READTOPO_FLAG_IL =0x100 , +SLI4_READTOPO_FLAG_PB_RECVD =0x200 , + +SLI4_READTOPO_LINKSTATE_RECV =0x3 , +SLI4_READTOPO_LINKSTATE_TRANS =0xc , +SLI4_READTOPO_LINKSTATE_MACHINE =0xf0 , +SLI4_READTOPO_LINKSTATE_SPEED =0xff00 , +SLI4_READTOPO_LINKSTATE_TF =0x40000000 , +SLI4_READTOPO_LINKSTATE_LU =0x80000000 , + +SLI4_READTOPO_SCN_BBSCN =0xf , +SLI4_READTOPO_SCN_CBBSCN =0xf0 , + +SLI4_READTOPO_R_T_TOV =0x1ff , +SLI4_READTOPO_AL_TOV =0xf000 , + +SLI4_READTOPO_PB_FLAG =0x80 , + +SLI4_READTOPO_INIT_N_PORTID =0xffffff , +}; + +#define SLI4_MIN_LOOP_MAP_BYTES 128 + +struct sli4_cmd_read_topology { +struct sli4_mbox_command_header hdr; +__le32 event_tag; +__le32 dw2_attentype; +u8 topology; +u8 lip_type; +u8 lip_al_ps; +u8 al_pa_granted; +struct sli4_bde bde_loop_map; +__le32 linkdown_state; +__le32 currlink_state; +u8 max_bbc; +u8 init_bbc; +u8 scn_flags; +u8 rsvd39; +__le16 dw10w0_al_rt_tov; +__le16 lp_tov; +u8 acquired_al_pa; +u8 pb_flags; +__le16 specified_al_pa; +__le32 dw12_init_n_port_id; +}; + +enum sli4_read_topo_link { +SLI4_READ_TOPOLOGY_LINK_UP =0x1 , +SLI4_READ_TOPOLOGY_LINK_DOWN , +SLI4_READ_TOPOLOGY_LINK_NO_ALPA , +}; + +enum sli4_read_topo { +SLI4_READ_TOPO_UNKNOWN =0x0 , +SLI4_READ_TOPO_NON_FC_AL , +SLI4_READ_TOPO_FC_AL , +}; + +enum sli4_read_topo_speed { +SLI4_READ_TOPOLOGY_SPEED_NONE =0x00 , +SLI4_READ_TOPOLOGY_SPEED_1G =0x04 ,
drivers/scsi/elx/libefc_sli/sli4.h enum sli4_els_cmd_type { · line 2431
Quoted 10 lines
drivers/scsi/elx/libefc_sli/sli4.h +10
-0+SLI4_READ_TOPOLOGY_SPEED_2G =0x08 , +SLI4_READ_TOPOLOGY_SPEED_4G =0x10 , +SLI4_READ_TOPOLOGY_SPEED_8G =0x20 , +SLI4_READ_TOPOLOGY_SPEED_10G =0x40 , +SLI4_READ_TOPOLOGY_SPEED_16G =0x80 , +SLI4_READ_TOPOLOGY_SPEED_32G =0x90 , +SLI4_READ_TOPOLOGY_SPEED_64G =0xa0 , + SLI4_READ_TOPOLOGY_SPEED_128G = 0xb0, +}; +
Slightly odd to have per-command types for the same thing, devolving to the same value ... (SLI4_READ_TOPOLOGY_XX vs SLI4_READ_CFG_XX). But probably a style issue ...
Quoted 1,207 lines
drivers/scsi/elx/libefc_sli/sli4.h +1191
-1+/* REG_FCFI - activate a FC Forwarder */ +struct sli4_cmd_reg_fcfi_rq_cfg { +u8 r_ctl_mask; +u8 r_ctl_match; +u8 type_mask; +u8 type_match; +}; + +enum sli4_regfcfi_tag { +SLI4_REGFCFI_VLAN_TAG =0xfff , +SLI4_REGFCFI_VLANTAG_VALID =0x1000 , +}; + +#define SLI4_CMD_REG_FCFI_NUM_RQ_CFG 4 +struct sli4_cmd_reg_fcfi { +struct sli4_mbox_command_header hdr; +__le16 fcf_index; +__le16 fcfi; +__le16 rqid1; +__le16 rqid0; +__le16 rqid3; +__le16 rqid2; +struct sli4_cmd_reg_fcfi_rq_cfg + rq_cfg[SLI4_CMD_REG_FCFI_NUM_RQ_CFG ]; +__le32 dw8_vlan; +}; + +#define SLI4_CMD_REG_FCFI_MRQ_NUM_RQ_CFG 4 +#define SLI4_CMD_REG_FCFI_MRQ_MAX_NUM_RQ 32 +#define SLI4_CMD_REG_FCFI_SET_FCFI_MODE 0 +#define SLI4_CMD_REG_FCFI_SET_MRQ_MODE 1 + +enum sli4_reg_fcfi_mrq { +SLI4_REGFCFI_MRQ_VLAN_TAG =0xfff , +SLI4_REGFCFI_MRQ_VLANTAG_VALID =0x1000 , +SLI4_REGFCFI_MRQ_MODE =0x2000 , + +SLI4_REGFCFI_MRQ_MASK_NUM_PAIRS =0xff , +SLI4_REGFCFI_MRQ_FILTER_BITMASK =0xf00 , +SLI4_REGFCFI_MRQ_RQ_SEL_POLICY =0xf000 , +}; + +struct sli4_cmd_reg_fcfi_mrq { +struct sli4_mbox_command_header hdr; +__le16 fcf_index; +__le16 fcfi; +__le16 rqid1; +__le16 rqid0; +__le16 rqid3; +__le16 rqid2; +struct sli4_cmd_reg_fcfi_rq_cfg + rq_cfg[SLI4_CMD_REG_FCFI_MRQ_NUM_RQ_CFG ]; +__le32 dw8_vlan; +__le32 dw9_mrqflags; +}; + +struct sli4_cmd_rq_cfg { +__le16 rq_id; +u8 r_ctl_mask; +u8 r_ctl_match; +u8 type_mask; +u8 type_match; +}; + +/* REG_RPI - register a Remote Port Indicator */ +enum sli4_reg_rpi { +SLI4_REGRPI_REMOTE_N_PORTID =0xffffff ,/* DW2 */ +SLI4_REGRPI_UPD =0x1000000 , +SLI4_REGRPI_ETOW =0x8000000 , +SLI4_REGRPI_TERP =0x20000000 , +SLI4_REGRPI_CI =0x80000000 , +}; + +struct sli4_cmd_reg_rpi { +struct sli4_mbox_command_header hdr; +__le16 rpi; +__le16 rsvd2; +__le32 dw2_rportid_flags; +struct sli4_bde bde_64; +__le16 vpi; +__le16 rsvd26; +}; + +#define SLI4_REG_RPI_BUF_LEN 0x70 + +/* REG_VFI - register a Virtual Fabric Indicator */ +enum sli_reg_vfi { +SLI4_REGVFI_VP =0x1000 ,/* DW1 */ +SLI4_REGVFI_UPD =0x2000 , + +SLI4_REGVFI_LOCAL_N_PORTID =0xffffff ,/* DW10 */ +}; + +struct sli4_cmd_reg_vfi { +struct sli4_mbox_command_header hdr; +__le16 vfi; +__le16 dw0w1_flags; +__le16 fcfi; +__le16 vpi; +u8 wwpn[8 ]; +struct sli4_bde sparm; +__le32 e_d_tov; +__le32 r_a_tov; +__le32 dw10_lportid_flags; +}; + +/* REG_VPI - register a Virtual Port Indicator */ +enum sli4_reg_vpi { +SLI4_REGVPI_LOCAL_N_PORTID =0xffffff , +SLI4_REGVPI_UPD =0x1000000 , +}; + +struct sli4_cmd_reg_vpi { +struct sli4_mbox_command_header hdr; +__le32 rsvd0; +__le32 dw2_lportid_flags; +u8 wwpn[8 ]; +__le32 rsvd12; +__le16 vpi; +__le16 vfi; +}; + +/* REQUEST_FEATURES - request / query SLI features */ +enum sli4_req_features_flags { +SLI4_REQFEAT_QRY =0x1 ,/* Dw1 */ + +SLI4_REQFEAT_IAAB =1 <<0 ,/* DW2 & DW3 */ +SLI4_REQFEAT_NPIV =1 <<1 , +SLI4_REQFEAT_DIF =1 <<2 , +SLI4_REQFEAT_VF =1 <<3 , +SLI4_REQFEAT_FCPI =1 <<4 , +SLI4_REQFEAT_FCPT =1 <<5 , +SLI4_REQFEAT_FCPC =1 <<6 , +SLI4_REQFEAT_RSVD =1 <<7 , +SLI4_REQFEAT_RQD =1 <<8 , +SLI4_REQFEAT_IAAR =1 <<9 , +SLI4_REQFEAT_HLM =1 <<10 , +SLI4_REQFEAT_PERFH =1 <<11 , +SLI4_REQFEAT_RXSEQ =1 <<12 , +SLI4_REQFEAT_RXRI =1 <<13 , +SLI4_REQFEAT_DCL2 =1 <<14 , +SLI4_REQFEAT_RSCO =1 <<15 , +SLI4_REQFEAT_MRQP =1 <<16 , +}; + +struct sli4_cmd_request_features { +struct sli4_mbox_command_header hdr; +__le32 dw1_qry; +__le32 cmd; +__le32 resp; +}; + +/* +* SLI_CONFIG - submit a configuration command to Port +* +* Command is either embedded as part of the payload (embed) or located +* in a separate memory buffer (mem) +*/ +enum sli4_sli_config { +SLI4_SLICONF_EMB =0x1 ,/* DW1 */ +SLI4_SLICONF_PMDCMD_SHIFT =3 , +SLI4_SLICONF_PMDCMD_MASK =0xf8 , +SLI4_SLICONF_PMDCMD_VAL_1 =8 , +SLI4_SLICONF_PMDCNT =0xf8 , + +SLI4_SLICONF_PMD_LEN =0x00ffffff , +}; + +struct sli4_cmd_sli_config { +struct sli4_mbox_command_header hdr; +__le32 dw1_flags; +__le32 payload_len; +__le32 rsvd12[3 ]; +union { +u8 embed[58 *sizeof (u32)]; +struct sli4_bufptr mem; + } payload; +}; + +/* READ_STATUS - read tx/rx status of a particular port */ +#define SLI4_READSTATUS_CLEAR_COUNTERS 0x1 + +struct sli4_cmd_read_status { +struct sli4_mbox_command_header hdr; +__le32 dw1_flags; +__le32 rsvd4; +__le32 trans_kbyte_cnt; +__le32 recv_kbyte_cnt; +__le32 trans_frame_cnt; +__le32 recv_frame_cnt; +__le32 trans_seq_cnt; +__le32 recv_seq_cnt; +__le32 tot_exchanges_orig; +__le32 tot_exchanges_resp; +__le32 recv_p_bsy_cnt; +__le32 recv_f_bsy_cnt; +__le32 no_rq_buf_dropped_frames_cnt; +__le32 empty_rq_timeout_cnt; +__le32 no_xri_dropped_frames_cnt; +__le32 empty_xri_pool_cnt; +}; + +/* READ_LNK_STAT - read link status of a particular port */ +enum sli4_read_link_stats_flags { +SLI4_READ_LNKSTAT_REC =1u <<0 , +SLI4_READ_LNKSTAT_GEC =1u <<1 , +SLI4_READ_LNKSTAT_W02OF =1u <<2 , +SLI4_READ_LNKSTAT_W03OF =1u <<3 , +SLI4_READ_LNKSTAT_W04OF =1u <<4 , +SLI4_READ_LNKSTAT_W05OF =1u <<5 , +SLI4_READ_LNKSTAT_W06OF =1u <<6 , +SLI4_READ_LNKSTAT_W07OF =1u <<7 , +SLI4_READ_LNKSTAT_W08OF =1u <<8 , +SLI4_READ_LNKSTAT_W09OF =1u <<9 , +SLI4_READ_LNKSTAT_W10OF =1u <<10 , +SLI4_READ_LNKSTAT_W11OF =1u <<11 , +SLI4_READ_LNKSTAT_W12OF =1u <<12 , +SLI4_READ_LNKSTAT_W13OF =1u <<13 , +SLI4_READ_LNKSTAT_W14OF =1u <<14 , +SLI4_READ_LNKSTAT_W15OF =1u <<15 , +SLI4_READ_LNKSTAT_W16OF =1u <<16 , +SLI4_READ_LNKSTAT_W17OF =1u <<17 , +SLI4_READ_LNKSTAT_W18OF =1u <<18 , +SLI4_READ_LNKSTAT_W19OF =1u <<19 , +SLI4_READ_LNKSTAT_W20OF =1u <<20 , +SLI4_READ_LNKSTAT_W21OF =1u <<21 , +SLI4_READ_LNKSTAT_CLRC =1u <<30 , +SLI4_READ_LNKSTAT_CLOF =1u <<31 , +}; + +struct sli4_cmd_read_link_stats { +struct sli4_mbox_command_header hdr; +__le32 dw1_flags; +__le32 linkfail_errcnt; +__le32 losssync_errcnt; +__le32 losssignal_errcnt; +__le32 primseq_errcnt; +__le32 inval_txword_errcnt; +__le32 crc_errcnt; +__le32 primseq_eventtimeout_cnt; +__le32 elastic_bufoverrun_errcnt; +__le32 arbit_fc_al_timeout_cnt; +__le32 adv_rx_buftor_to_buf_credit; +__le32 curr_rx_buf_to_buf_credit; +__le32 adv_tx_buf_to_buf_credit; +__le32 curr_tx_buf_to_buf_credit; +__le32 rx_eofa_cnt; +__le32 rx_eofdti_cnt; +__le32 rx_eofni_cnt; +__le32 rx_soff_cnt; +__le32 rx_dropped_no_aer_cnt; +__le32 rx_dropped_no_avail_rpi_rescnt; +__le32 rx_dropped_no_avail_xri_rescnt; +}; + +/* Format a WQE with WQ_ID Association performance hint */ +static inline void +sli_set_wq_id_association (void *entry,u16 q_id) +{ +u32 *wqe = entry; + +/* +* Set Word 10, bit 0 to zero +* Set Word 10, bits 15:1 to the WQ ID +*/ + wqe[10 ] &= ~0xffff ; + wqe[10 ] |= q_id <<1 ; +} + +/* UNREG_FCFI - unregister a FCFI */ +struct sli4_cmd_unreg_fcfi { +struct sli4_mbox_command_header hdr; +__le32 rsvd0; +__le16 fcfi; +__le16 rsvd6; +}; + +/* UNREG_RPI - unregister one or more RPI */ +enum sli4_unreg_rpi { +SLI4_UNREG_RPI_DP =0x2000 , +SLI4_UNREG_RPI_II_SHIFT =14 , +SLI4_UNREG_RPI_II_MASK =0xc000 , +SLI4_UNREG_RPI_II_RPI =0x0000 , +SLI4_UNREG_RPI_II_VPI =0x4000 , +SLI4_UNREG_RPI_II_VFI =0x8000 , +SLI4_UNREG_RPI_II_FCFI =0xc000 , + +SLI4_UNREG_RPI_DEST_N_PORTID_MASK =0x00ffffff , +}; + +struct sli4_cmd_unreg_rpi { +struct sli4_mbox_command_header hdr; +__le16 index; +__le16 dw1w1_flags; +__le32 dw2_dest_n_portid; +}; + +/* UNREG_VFI - unregister one or more VFI */ +enum sli4_unreg_vfi { +SLI4_UNREG_VFI_II_SHIFT =14 , +SLI4_UNREG_VFI_II_MASK =0xc000 , +SLI4_UNREG_VFI_II_VFI =0x0000 , +SLI4_UNREG_VFI_II_FCFI =0xc000 , +}; + +struct sli4_cmd_unreg_vfi { +struct sli4_mbox_command_header hdr; +__le32 rsvd0; +__le16 index; +__le16 dw2_flags; +}; + +enum sli4_unreg_type { +SLI4_UNREG_TYPE_PORT , +SLI4_UNREG_TYPE_DOMAIN , +SLI4_UNREG_TYPE_FCF , +SLI4_UNREG_TYPE_ALL +}; + +/* UNREG_VPI - unregister one or more VPI */ +enum sli4_unreg_vpi { +SLI4_UNREG_VPI_II_SHIFT =14 , +SLI4_UNREG_VPI_II_MASK =0xc000 , +SLI4_UNREG_VPI_II_VPI =0x0000 , +SLI4_UNREG_VPI_II_VFI =0x8000 , +SLI4_UNREG_VPI_II_FCFI =0xc000 , +}; + +struct sli4_cmd_unreg_vpi { +struct sli4_mbox_command_header hdr; +__le32 rsvd0; +__le16 index; +__le16 dw2w0_flags; +}; + +/* AUTO_XFER_RDY - Configure the auto-generate XFER-RDY feature */ +struct sli4_cmd_config_auto_xfer_rdy { +struct sli4_mbox_command_header hdr; +__le32 rsvd0; +__le32 max_burst_len; +}; + +#define SLI4_CONFIG_AUTO_XFERRDY_BLKSIZE 0xffff + +struct sli4_cmd_config_auto_xfer_rdy_hp { +struct sli4_mbox_command_header hdr; +__le32 rsvd0; +__le32 max_burst_len; +__le32 dw3_esoc_flags; +__le16 block_size; +__le16 rsvd14; +}; + +/************************************************************************* +* SLI-4 common configuration command formats and definitions +*/ + +/* +* Subsystem values. +*/ +enum sli4_subsystem { +SLI4_SUBSYSTEM_COMMON =0x01 , +SLI4_SUBSYSTEM_LOWLEVEL =0x0b , +SLI4_SUBSYSTEM_FC =0x0c , +SLI4_SUBSYSTEM_DMTF =0x11 , +}; + +#define SLI4_OPC_LOWLEVEL_SET_WATCHDOG 0X36 + +/* +* Common opcode (OPC) values. +*/ +enum sli4_cmn_opcode { +SLI4_CMN_FUNCTION_RESET =0x3d , +SLI4_CMN_CREATE_CQ =0x0c , +SLI4_CMN_CREATE_CQ_SET =0x1d , +SLI4_CMN_DESTROY_CQ =0x36 , +SLI4_CMN_MODIFY_EQ_DELAY =0x29 , +SLI4_CMN_CREATE_EQ =0x0d , +SLI4_CMN_DESTROY_EQ =0x37 , +SLI4_CMN_CREATE_MQ_EXT =0x5a , +SLI4_CMN_DESTROY_MQ =0x35 , +SLI4_CMN_GET_CNTL_ATTRIBUTES =0x20 , +SLI4_CMN_NOP =0x21 , +SLI4_CMN_GET_RSC_EXTENT_INFO =0x9a , +SLI4_CMN_GET_SLI4_PARAMS =0xb5 , +SLI4_CMN_QUERY_FW_CONFIG =0x3a , +SLI4_CMN_GET_PORT_NAME =0x4d , + +SLI4_CMN_WRITE_FLASHROM =0x07 , +/* TRANSCEIVER Data */ +SLI4_CMN_READ_TRANS_DATA =0x49 , +SLI4_CMN_GET_CNTL_ADDL_ATTRS =0x79 , +SLI4_CMN_GET_FUNCTION_CFG =0xa0 , +SLI4_CMN_GET_PROFILE_CFG =0xa4 , +SLI4_CMN_SET_PROFILE_CFG =0xa5 , +SLI4_CMN_GET_PROFILE_LIST =0xa6 , +SLI4_CMN_GET_ACTIVE_PROFILE =0xa7 , +SLI4_CMN_SET_ACTIVE_PROFILE =0xa8 , +SLI4_CMN_READ_OBJECT =0xab , +SLI4_CMN_WRITE_OBJECT =0xac , +SLI4_CMN_DELETE_OBJECT =0xae , +SLI4_CMN_READ_OBJECT_LIST =0xad , +SLI4_CMN_SET_DUMP_LOCATION =0xb8 , +SLI4_CMN_SET_FEATURES =0xbf , +SLI4_CMN_GET_RECFG_LINK_INFO =0xc9 , +SLI4_CMN_SET_RECNG_LINK_ID =0xca , +}; + +/* DMTF opcode (OPC) values */ +#define DMTF_EXEC_CLP_CMD 0x01 + +/* +* COMMON_FUNCTION_RESET +* +* Resets the Port, returning it to a power-on state. This configuration +* command does not have a payload and should set/expect the lengths to +* be zero. +*/ +struct sli4_rqst_cmn_function_reset { +struct sli4_rqst_hdr hdr; +}; + +struct sli4_rsp_cmn_function_reset { +struct sli4_rsp_hdr hdr; +}; + + +/* +* COMMON_GET_CNTL_ATTRIBUTES +* +* Query for information about the SLI Port +*/ +enum sli4_cntrl_attr_flags { +SLI4_CNTL_ATTR_PORTNUM =0x3f , +SLI4_CNTL_ATTR_PORTTYPE =0xc0 , +}; + +struct sli4_rsp_cmn_get_cntl_attributes { +struct sli4_rsp_hdr hdr; +u8 version_str[32 ]; +u8 manufacturer_name[32 ]; +__le32 supported_modes; +u8 eprom_version_lo; +u8 eprom_version_hi; +__le16 rsvd17; +__le32 mbx_ds_version; +__le32 ep_fw_ds_version; +u8 ncsi_version_str[12 ]; +__le32 def_extended_timeout; +u8 model_number[32 ]; +u8 description[64 ]; +u8 serial_number[32 ]; +u8 ip_version_str[32 ]; +u8 fw_version_str[32 ]; +u8 bios_version_str[32 ]; +u8 redboot_version_str[32 ]; +u8 driver_version_str[32 ]; +u8 fw_on_flash_version_str[32 ]; +__le32 functionalities_supported; +__le16 max_cdb_length; +u8 asic_revision; +u8 generational_guid0; +__le32 generational_guid1_12[3 ]; +__le16 generational_guid13_14; +u8 generational_guid15; +u8 hba_port_count; +__le16 default_link_down_timeout; +u8 iscsi_version_min_max; +u8 multifunctional_device; +u8 cache_valid; +u8 hba_status; +u8 max_domains_supported; +u8 port_num_type_flags; +__le32 firmware_post_status; +__le32 hba_mtu; +u8 iscsi_features; +u8 rsvd121[3 ]; +__le16 pci_vendor_id; +__le16 pci_device_id; +__le16 pci_sub_vendor_id; +__le16 pci_sub_system_id; +u8 pci_bus_number; +u8 pci_device_number; +u8 pci_function_number; +u8 interface_type; +__le64 unique_identifier; +u8 number_of_netfilters; +u8 rsvd122[3 ]; +}; + +/* +* COMMON_GET_CNTL_ATTRIBUTES +* +* This command queries the controller information from the Flash ROM. +*/ +struct sli4_rqst_cmn_get_cntl_addl_attributes { +struct sli4_rqst_hdr hdr; +}; + +struct sli4_rsp_cmn_get_cntl_addl_attributes { +struct sli4_rsp_hdr hdr; +__le16 ipl_file_number; +u8 ipl_file_version; +u8 rsvd4; +u8 on_die_temperature; +u8 rsvd5[3 ]; +__le32 driver_advanced_features_supported; +__le32 rsvd7[4 ]; +char universal_bios_version[32 ]; +char x86_bios_version[32 ]; +char efi_bios_version[32 ]; +char fcode_version[32 ]; +char uefi_bios_version[32 ]; +char uefi_nic_version[32 ]; +char uefi_fcode_version[32 ]; +char uefi_iscsi_version[32 ]; +char iscsi_x86_bios_version[32 ]; +char pxe_x86_bios_version[32 ]; +u8 default_wwpn[8 ]; +u8 ext_phy_version[32 ]; +u8 fc_universal_bios_version[32 ]; +u8 fc_x86_bios_version[32 ]; +u8 fc_efi_bios_version[32 ]; +u8 fc_fcode_version[32 ]; +u8 ext_phy_crc_label[8 ]; +u8 ipl_file_name[16 ]; +u8 rsvd139[72 ]; +}; + +/* +* COMMON_NOP +* +* This command does not do anything; it only returns +* the payload in the completion. +*/ +struct sli4_rqst_cmn_nop { +struct sli4_rqst_hdr hdr; +__le32 context[2 ]; +}; + +struct sli4_rsp_cmn_nop { +struct sli4_rsp_hdr hdr; +__le32 context[2 ]; +}; + +struct sli4_rqst_cmn_get_resource_extent_info { +struct sli4_rqst_hdr hdr; +__le16 resource_type; +__le16 rsvd16; +}; + +enum sli4_rsc_type { +SLI4_RSC_TYPE_VFI =0x20 , +SLI4_RSC_TYPE_VPI =0x21 , +SLI4_RSC_TYPE_RPI =0x22 , +SLI4_RSC_TYPE_XRI =0x23 , +}; + +struct sli4_rsp_cmn_get_resource_extent_info { +struct sli4_rsp_hdr hdr; +__le16 resource_extent_count; +__le16 resource_extent_size; +}; + +#define SLI4_128BYTE_WQE_SUPPORT 0x02 + +#define GET_Q_CNT_METHOD (m) \ + (((m) & SLI4_PARAM_Q_CNT_MTHD_MASK) >> SLI4_PARAM_Q_CNT_MTHD_SHFT) +#define GET_Q_CREATE_VERSION (v) \ + (((v) & SLI4_PARAM_QV_MASK) >> SLI4_PARAM_QV_SHIFT) + +enum sli4_rsp_get_params_e { +/*GENERIC*/ +SLI4_PARAM_Q_CNT_MTHD_SHFT =24 , +SLI4_PARAM_Q_CNT_MTHD_MASK =0xf <<24 , +SLI4_PARAM_QV_SHIFT =14 , +SLI4_PARAM_QV_MASK =3 <<14 , + +/* DW4 */ +SLI4_PARAM_PROTO_TYPE_MASK =0xff , +/* DW5 */ +SLI4_PARAM_FT =1 <<0 , +SLI4_PARAM_SLI_REV_MASK =0xf <<4 , +SLI4_PARAM_SLI_FAM_MASK =0xf <<8 , +SLI4_PARAM_IF_TYPE_MASK =0xf <<12 , +SLI4_PARAM_SLI_HINT1_MASK =0xff <<16 , +SLI4_PARAM_SLI_HINT2_MASK =0x1f <<24 , +/* DW6 */ +SLI4_PARAM_EQ_PAGE_CNT_MASK =0xf <<0 , +SLI4_PARAM_EQE_SZS_MASK =0xf <<8 , +SLI4_PARAM_EQ_PAGE_SZS_MASK =0xff <<16 , +/* DW8 */ +SLI4_PARAM_CQ_PAGE_CNT_MASK =0xf <<0 , +SLI4_PARAM_CQE_SZS_MASK =0xf <<8 , +SLI4_PARAM_CQ_PAGE_SZS_MASK =0xff <<16 , +/* DW10 */ +SLI4_PARAM_MQ_PAGE_CNT_MASK =0xf <<0 , +SLI4_PARAM_MQ_PAGE_SZS_MASK =0xff <<16 , +/* DW12 */ +SLI4_PARAM_WQ_PAGE_CNT_MASK =0xf <<0 , +SLI4_PARAM_WQE_SZS_MASK =0xf <<8 , +SLI4_PARAM_WQ_PAGE_SZS_MASK =0xff <<16 , +/* DW14 */ +SLI4_PARAM_RQ_PAGE_CNT_MASK =0xf <<0 , +SLI4_PARAM_RQE_SZS_MASK =0xf <<8 , +SLI4_PARAM_RQ_PAGE_SZS_MASK =0xff <<16 , +/* DW15W1*/ +SLI4_PARAM_RQ_DB_WINDOW_MASK =0xf000 , +/* DW16 */ +SLI4_PARAM_FC =1 <<0 , +SLI4_PARAM_EXT =1 <<1 , +SLI4_PARAM_HDRR =1 <<2 , +SLI4_PARAM_SGLR =1 <<3 , +SLI4_PARAM_FBRR =1 <<4 , +SLI4_PARAM_AREG =1 <<5 , +SLI4_PARAM_TGT =1 <<6 , +SLI4_PARAM_TERP =1 <<7 , +SLI4_PARAM_ASSI =1 <<8 , +SLI4_PARAM_WCHN =1 <<9 , +SLI4_PARAM_TCCA =1 <<10 , +SLI4_PARAM_TRTY =1 <<11 , +SLI4_PARAM_TRIR =1 <<12 , +SLI4_PARAM_PHOFF =1 <<13 , +SLI4_PARAM_PHON =1 <<14 , +SLI4_PARAM_PHWQ =1 <<15 , +SLI4_PARAM_BOUND_4GA =1 <<16 , +SLI4_PARAM_RXC =1 <<17 , +SLI4_PARAM_HLM =1 <<18 , +SLI4_PARAM_IPR =1 <<19 , +SLI4_PARAM_RXRI =1 <<20 , +SLI4_PARAM_SGLC =1 <<21 , +SLI4_PARAM_TIMM =1 <<22 , +SLI4_PARAM_TSMM =1 <<23 , +SLI4_PARAM_OAS =1 <<25 , +SLI4_PARAM_LC =1 <<26 , +SLI4_PARAM_AGXF =1 <<27 , +SLI4_PARAM_LOOPBACK_MASK =0xf <<28 , +/* DW18 */ +SLI4_PARAM_SGL_PAGE_CNT_MASK =0xf <<0 , +SLI4_PARAM_SGL_PAGE_SZS_MASK =0xff <<8 , +SLI4_PARAM_SGL_PP_ALIGN_MASK =0xff <<16 , +}; + +struct sli4_rqst_cmn_get_sli4_params { +struct sli4_rqst_hdr hdr; +}; + +struct sli4_rsp_cmn_get_sli4_params { +struct sli4_rsp_hdr hdr; +__le32 dw4_protocol_type; +__le32 dw5_sli; +__le32 dw6_eq_page_cnt; +__le16 eqe_count_mask; +__le16 rsvd26; +__le32 dw8_cq_page_cnt; +__le16 cqe_count_mask; +__le16 rsvd34; +__le32 dw10_mq_page_cnt; +__le16 mqe_count_mask; +__le16 rsvd42; +__le32 dw12_wq_page_cnt; +__le16 wqe_count_mask; +__le16 rsvd50; +__le32 dw14_rq_page_cnt; +__le16 rqe_count_mask; +__le16 dw15w1_rq_db_window; +__le32 dw16_loopback_scope; +__le32 sge_supported_length; +__le32 dw18_sgl_page_cnt; +__le16 min_rq_buffer_size; +__le16 rsvd75; +__le32 max_rq_buffer_size; +__le16 physical_xri_max; +__le16 physical_rpi_max; +__le16 physical_vpi_max; +__le16 physical_vfi_max; +__le32 rsvd88; +__le16 frag_num_field_offset; +__le16 frag_num_field_size; +__le16 sgl_index_field_offset; +__le16 sgl_index_field_size; +__le32 chain_sge_initial_value_lo; +__le32 chain_sge_initial_value_hi; +}; + +/*Port Types*/ +enum sli4_port_types { +SLI4_PORT_TYPE_ETH =0 , +SLI4_PORT_TYPE_FC =1 , +}; + +struct sli4_rqst_cmn_get_port_name { +struct sli4_rqst_hdr hdr; +u8 port_type; +u8 rsvd4[3 ]; +}; + +struct sli4_rsp_cmn_get_port_name { +struct sli4_rsp_hdr hdr; +char port_name[4 ]; +}; + +struct sli4_rqst_cmn_write_flashrom { +struct sli4_rqst_hdr hdr; +__le32 flash_rom_access_opcode; +__le32 flash_rom_access_operation_type; +__le32 data_buffer_size; +__le32 offset; +u8 data_buffer[4 ]; +}; + +/* +* COMMON_READ_TRANSCEIVER_DATA +* +* This command reads SFF transceiver data(Format is defined +* by the SFF-8472 specification). +*/ +struct sli4_rqst_cmn_read_transceiver_data { +struct sli4_rqst_hdr hdr; +__le32 page_number; +__le32 port; +}; + +struct sli4_rsp_cmn_read_transceiver_data { +struct sli4_rsp_hdr hdr; +__le32 page_number; +__le32 port; +u8 page_data[128 ]; +u8 page_data_2[128 ]; +}; + +#define SLI4_REQ_DESIRE_READLEN 0xffffff + +struct sli4_rqst_cmn_read_object { +struct sli4_rqst_hdr hdr; +__le32 desired_read_length_dword; +__le32 read_offset; +u8 object_name[104 ]; +__le32 host_buffer_descriptor_count; +struct sli4_bde host_buffer_descriptor[0 ]; +}; + +#define RSP_COM_READ_OBJ_EOF 0x80000000 + +struct sli4_rsp_cmn_read_object { +struct sli4_rsp_hdr hdr; +__le32 actual_read_length; +__le32 eof_dword; +}; + +enum sli4_rqst_write_object_flags { +SLI4_RQ_DES_WRITE_LEN =0xffffff , +SLI4_RQ_DES_WRITE_LEN_NOC =0x40000000 , +SLI4_RQ_DES_WRITE_LEN_EOF =0x80000000 , +}; + +struct sli4_rqst_cmn_write_object { +struct sli4_rqst_hdr hdr; +__le32 desired_write_len_dword; +__le32 write_offset; +u8 object_name[104 ]; +__le32 host_buffer_descriptor_count; +struct sli4_bde host_buffer_descriptor[0 ]; +}; + +#define RSP_CHANGE_STATUS 0xff + +struct sli4_rsp_cmn_write_object { +struct sli4_rsp_hdr hdr; +__le32 actual_write_length; +__le32 change_status_dword; +}; + +struct sli4_rqst_cmn_delete_object { +struct sli4_rqst_hdr hdr; +__le32 rsvd4; +__le32 rsvd5; +u8 object_name[104 ]; +}; + +#define SLI4_RQ_OBJ_LIST_READ_LEN 0xffffff + +struct sli4_rqst_cmn_read_object_list { +struct sli4_rqst_hdr hdr; +__le32 desired_read_length_dword; +__le32 read_offset; +u8 object_name[104 ]; +__le32 host_buffer_descriptor_count; +struct sli4_bde host_buffer_descriptor[0 ]; +}; + +enum sli4_rqst_set_dump_flags { +SLI4_CMN_SET_DUMP_BUFFER_LEN =0xffffff , +SLI4_CMN_SET_DUMP_FDB =0x20000000 , +SLI4_CMN_SET_DUMP_BLP =0x40000000 , +SLI4_CMN_SET_DUMP_QRY =0x80000000 , +}; + +struct sli4_rqst_cmn_set_dump_location { +struct sli4_rqst_hdr hdr; +__le32 buffer_length_dword; +__le32 buf_addr_low; +__le32 buf_addr_high; +}; + +struct sli4_rsp_cmn_set_dump_location { +struct sli4_rsp_hdr hdr; +__le32 buffer_length_dword; +}; + +enum sli4_dump_level { +SLI4_DUMP_LEVEL_NONE , +SLI4_CHIP_LEVEL_DUMP , +SLI4_FUNC_DESC_DUMP , +}; + +enum sli4_dump_state { +SLI4_DUMP_STATE_NONE , +SLI4_CHIP_DUMP_STATE_VALID , +SLI4_FUNC_DUMP_STATE_VALID , +}; + +enum sli4_dump_status { +SLI4_DUMP_READY_STATUS_NOT_READY , +SLI4_DUMP_READY_STATUS_DD_PRESENT , +SLI4_DUMP_READY_STATUS_FDB_PRESENT , +SLI4_DUMP_READY_STATUS_SKIP_DUMP , +SLI4_DUMP_READY_STATUS_FAILED =-1 , +}; + +enum sli4_set_features { +SLI4_SET_FEATURES_DIF_SEED =0x01 , +SLI4_SET_FEATURES_XRI_TIMER =0x03 , +SLI4_SET_FEATURES_MAX_PCIE_SPEED =0x04 , +SLI4_SET_FEATURES_FCTL_CHECK =0x05 , +SLI4_SET_FEATURES_FEC =0x06 , +SLI4_SET_FEATURES_PCIE_RECV_DETECT =0x07 , +SLI4_SET_FEATURES_DIF_MEMORY_MODE =0x08 , +SLI4_SET_FEATURES_DISABLE_SLI_PORT_PAUSE_STATE =0x09 , +SLI4_SET_FEATURES_ENABLE_PCIE_OPTIONS =0x0a , +SLI4_SET_FEAT_CFG_AUTO_XFER_RDY_T10PI =0x0c , +SLI4_SET_FEATURES_ENABLE_MULTI_RECEIVE_QUEUE =0x0d , +SLI4_SET_FEATURES_SET_FTD_XFER_HINT =0x0f , +SLI4_SET_FEATURES_SLI_PORT_HEALTH_CHECK =0x11 , +}; + +struct sli4_rqst_cmn_set_features { +struct sli4_rqst_hdr hdr; +__le32 feature; +__le32 param_len; +__le32 params[8 ]; +}; + +struct sli4_rqst_cmn_set_features_dif_seed { +__le16 seed; +__le16 rsvd16; +}; + +enum sli4_rqst_set_mrq_features { +SLI4_RQ_MULTIRQ_ISR =0x1 , +SLI4_RQ_MULTIRQ_AUTOGEN_XFER_RDY =0x2 , + +SLI4_RQ_MULTIRQ_NUM_RQS =0xff , +SLI4_RQ_MULTIRQ_RQ_SELECT =0xf00 , +}; + +struct sli4_rqst_cmn_set_features_multirq { +__le32 auto_gen_xfer_dword; +__le32 num_rqs_dword; +}; + +enum sli4_rqst_health_check_flags { +SLI4_RQ_HEALTH_CHECK_ENABLE =0x1 , +SLI4_RQ_HEALTH_CHECK_QUERY =0x2 , +}; + +struct sli4_rqst_cmn_set_features_health_check { +__le32 health_check_dword; +}; + +struct sli4_rqst_cmn_set_features_set_fdt_xfer_hint { +__le32 fdt_xfer_hint; +}; + +struct sli4_rqst_dmtf_exec_clp_cmd { +struct sli4_rqst_hdr hdr; +__le32 cmd_buf_length; +__le32 resp_buf_length; +__le32 cmd_buf_addr_low; +__le32 cmd_buf_addr_high; +__le32 resp_buf_addr_low; +__le32 resp_buf_addr_high; +}; + +struct sli4_rsp_dmtf_exec_clp_cmd { +struct sli4_rsp_hdr hdr; +__le32 rsvd4; +__le32 resp_length; +__le32 rsvd6; +__le32 rsvd7; +__le32 rsvd8; +__le32 rsvd9; +__le32 clp_status; +__le32 clp_detailed_status; +}; + +#define SLI4_PROTOCOL_FC 0x10 +#define SLI4_PROTOCOL_DEFAULT 0xff + +struct sli4_rspource_descriptor_v1 { +u8 descriptor_type; +u8 descriptor_length; +__le16 rsvd16; +__le32 type_specific[0 ]; +}; + +enum sli4_pcie_desc_flags { +SLI4_PCIE_DESC_IMM =0x4000 , +SLI4_PCIE_DESC_NOSV =0x8000 , + +SLI4_PCIE_DESC_PF_NO =0x3ff0000 , + +SLI4_PCIE_DESC_MISSN_ROLE =0xff , +SLI4_PCIE_DESC_PCHG =0x8000000 , +SLI4_PCIE_DESC_SCHG =0x10000000 , +SLI4_PCIE_DESC_XCHG =0x20000000 , +SLI4_PCIE_DESC_XROM =0xc0000000 +}; + +struct sli4_pcie_resource_descriptor_v1 { +u8 descriptor_type; +u8 descriptor_length; +__le16 imm_nosv_dword; +__le32 pf_number_dword; +__le32 rsvd3; +u8 sriov_state; +u8 pf_state; +u8 pf_type; +u8 rsvd4; +__le16 number_of_vfs; +__le16 rsvd5; +__le32 mission_roles_dword; +__le32 rsvd7[16 ]; +}; + +struct sli4_rqst_cmn_get_function_config { +struct sli4_rqst_hdr hdr; +}; + +struct sli4_rsp_cmn_get_function_config { +struct sli4_rsp_hdr hdr; +__le32 desc_count; +__le32 desc[54 ]; +}; + +/* Link Config Descriptor for link config functions */ +struct sli4_link_config_descriptor { +u8 link_config_id; +u8 rsvd1[3 ]; +__le32 config_description[8 ]; +}; + +#define MAX_LINK_DES 10 + +struct sli4_rqst_cmn_get_reconfig_link_info { +struct sli4_rqst_hdr hdr; +}; + +struct sli4_rsp_cmn_get_reconfig_link_info { +struct sli4_rsp_hdr hdr; +u8 active_link_config_id; +u8 rsvd17; +u8 next_link_config_id; +u8 rsvd19; +__le32 link_configuration_descriptor_count; +struct sli4_link_config_descriptor + desc[MAX_LINK_DES ]; +}; + +enum sli4_set_reconfig_link_flags { +SLI4_SET_RECONFIG_LINKID_NEXT =0xff , +SLI4_SET_RECONFIG_LINKID_FD =1u <<31 , +}; + +struct sli4_rqst_cmn_set_reconfig_link_id { +struct sli4_rqst_hdr hdr; +__le32 dw4_flags; +}; + +struct sli4_rsp_cmn_set_reconfig_link_id { +struct sli4_rsp_hdr hdr; +}; + +struct sli4_rqst_lowlevel_set_watchdog { +struct sli4_rqst_hdr hdr; +__le16 watchdog_timeout; +__le16 rsvd18; +}; + +struct sli4_rsp_lowlevel_set_watchdog { +struct sli4_rsp_hdr hdr; +__le32 rsvd; +}; + +/* FC opcode (OPC) values */ +enum sli4_fc_opcodes { +SLI4_OPC_WQ_CREATE =0x1 , +SLI4_OPC_WQ_DESTROY =0x2 , +SLI4_OPC_POST_SGL_PAGES =0x3 , +SLI4_OPC_RQ_CREATE =0x5 , +SLI4_OPC_RQ_DESTROY =0x6 , +SLI4_OPC_READ_FCF_TABLE =0x8 , +SLI4_OPC_POST_HDR_TEMPLATES =0xb , +SLI4_OPC_REDISCOVER_FCF =0x10 , +}; + +/* Use the default CQ associated with the WQ */ +#define SLI4_CQ_DEFAULT 0xffff + +/* +* POST_SGL_PAGES +* +* Register the scatter gather list (SGL) memory and +* associate it with an XRI. +*/ +struct sli4_rqst_post_sgl_pages { +struct sli4_rqst_hdr hdr; +__le16 xri_start; +__le16 xri_count; +struct { +__le32 page0_low; +__le32 page0_high; +__le32 page1_low; +__le32 page1_high; + } page_set[10 ]; +}; + +struct sli4_rsp_post_sgl_pages { +struct sli4_rsp_hdr hdr; +}; + +struct sli4_rqst_post_hdr_templates { +struct sli4_rqst_hdr hdr; +__le16 rpi_offset; +__le16 page_count; +struct sli4_dmaaddr page_descriptor[0 ]; +}; + +#define SLI4_HDR_TEMPLATE_SIZE 64 + +enum sli4_io_flags { +/* The XRI associated with this IO is already active */ +SLI4_IO_CONTINUATION =1 <<0 , +/* Automatically generate a good RSP frame */ +SLI4_IO_AUTO_GOOD_RESPONSE =1 <<1 , +SLI4_IO_NO_ABORT =1 <<2 , +/* Set the DNRX bit because no auto xref rdy buffer is posted */ +SLI4_IO_DNRX =1 <<3 , +}; + +enum sli4_callback { +SLI4_CB_LINK , +SLI4_CB_MAX , +}; + +enum sli4_link_status { +SLI4_LINK_STATUS_UP , +SLI4_LINK_STATUS_DOWN , +SLI4_LINK_STATUS_NO_ALPA , +SLI4_LINK_STATUS_MAX , +}; + +enum sli4_link_topology { +SLI4_LINK_TOPO_NON_FC_AL =1 , +SLI4_LINK_TOPO_FC_AL , +SLI4_LINK_TOPO_LOOPBACK_INTERNAL , +SLI4_LINK_TOPO_LOOPBACK_EXTERNAL , +SLI4_LINK_TOPO_NONE , +SLI4_LINK_TOPO_MAX , +}; + +enum sli4_link_medium { +SLI4_LINK_MEDIUM_ETHERNET , +SLI4_LINK_MEDIUM_FC , +SLI4_LINK_MEDIUM_MAX , +};/******Driver specific structures******/ struct sli4_queue {@@ -2020,7 +3546,7 @@ struct sli4_queue { } u; }; -/* Prameters used to populate WQE*/ +/* Parameters used to populate WQE*/ struct sli_bls_params {u32 s_id;u32 d_id;@@ -2081,4 +3607,116 @@ struct sli_fcp_tgt_params {u16 tag; }; +struct sli4_link_event { +enum sli4_link_status status; +enum sli4_link_topology topology; +enum sli4_link_medium medium; +u32 speed; +u8 *loop_map; +u32 fc_id; +}; + +enum sli4_resource { +SLI4_RSRC_VFI , +SLI4_RSRC_VPI , +SLI4_RSRC_RPI , +SLI4_RSRC_XRI , +SLI4_RSRC_FCFI , +SLI4_RSRC_MAX , +}; + +struct sli4_extent { +u32 number; +u32 size; +u32 n_alloc; +u32 *base; +unsigned long *use_map; +u32 map_size; +}; + +struct sli4_queue_info { +u16 max_qcount[SLI4_QTYPE_MAX ]; +u32 max_qentries[SLI4_QTYPE_MAX ]; +u16 count_mask[SLI4_QTYPE_MAX ]; +u16 count_method[SLI4_QTYPE_MAX ]; +u32 qpage_count[SLI4_QTYPE_MAX ]; +}; + +struct sli4_params { +u8 has_extents; +u8 auto_reg; +u8 auto_xfer_rdy; +u8 hdr_template_req; +u8 perf_hint; +u8 perf_wq_id_association; +u8 cq_create_version; +u8 mq_create_version; +u8 high_login_mode; +u8 sgl_pre_registered; +u8 sgl_pre_reg_required; +u8 t10_dif_inline_capable; +u8 t10_dif_separate_capable; +}; + +struct sli4 { +void *os; +struct pci_dev *pci; +void __iomem *reg[PCI_STD_NUM_BARS ]; + +u32 sli_rev; +u32 sli_family; +u32 if_type; + +u16 asic_type; +u16 asic_rev; + +u16 e_d_tov; +u16 r_a_tov; +struct sli4_queue_info qinfo; +u16 link_module_type; +u8 rq_batch; +u8 port_number; +char port_name[2 ]; +u16 rq_min_buf_size; +u32 rq_max_buf_size; +u8 topology; +u8 wwpn[8 ]; +u8 wwnn[8 ]; +u32 fw_rev[2 ]; +u8 fw_name[2 ][16 ]; +char ipl_name[16 ]; +u32 hw_rev[3 ]; +char modeldesc[64 ]; +char bios_version_string[32 ]; +u32 wqe_size; +u32 vpd_length; +/* +* Tracks the port resources using extents metaphor. For +* devices that don't implement extents (i.e. +* has_extents == FALSE), the code models each resource as +* a single large extent. +*/ +struct sli4_extent ext[SLI4_RSRC_MAX ]; +u32 features; +struct sli4_params params; +u32 sge_supported_length; +u32 sgl_page_sizes; +u32 max_sgl_pages; + +/* +* Callback functions +*/ +int (*link)(void *ctx,void *event); +void *link_arg; + +struct efc_dma bmbx;
drivers/scsi/elx/libefc_sli/sli4.h struct sli_fcp_tgt_params { · line 3722
Quoted 10 lines
drivers/scsi/elx/libefc_sli/sli4.h +9
-0+ +/* Save pointer to physical memory descriptor for non-embedded +* SLI_CONFIG commands for BMBX dumping purposes +*/ +struct efc_dma *bmbx_non_emb_pmd; + + struct efc_dma vpd_data; +}; +#endif /* !_SLI4_H */
Other than that:
Cheers,
Hannes
Signature · 4 lines
Dr. Hannes Reinecke Kernel Storage Architect [email protected] +49 911 74053 688 SUSE Software Solutions Germany GmbH, 90409 Nürnberg GF: F. Imendörffer, HRB 36809 (AG Nürnberg)
PATCH v8 4/31 elx: libefc_sli: queue create/destroy/parse routines
In reply to James SmartThis patch continues the libefc_sli SLI-4 library population.
This patch adds service routines to create mailbox commands and adds APIs to create/destroy/parse SLI-4 EQ, CQ, RQ and MQ queues.
--- drivers/scsi/elx/include/efc_common.h | 16 + drivers/scsi/elx/libefc_sli/sli4.c | 1347 +++++++++++++++++++++++++ drivers/scsi/elx/libefc_sli/sli4.h | 9 + 3 files changed, 1372 insertions(+)
drivers/scsi/elx/include/efc_common.h +16 -0
@@ -22,4 +22,20 @@ struct efc_dma {struct pci_dev *pdev; }; +#define efc_log_crit(efc, fmt, args...) \ + dev_crit(&((efc)->pci)->dev, fmt, ##args) + +#define efc_log_err(efc, fmt, args...) \ + dev_err(&((efc)->pci)->dev, fmt, ##args) + +#define efc_log_warn(efc, fmt, args...) \ + dev_warn(&((efc)->pci)->dev, fmt, ##args) + +#define efc_log_info(efc, fmt, args...) \ + dev_info(&((efc)->pci)->dev, fmt, ##args) + +#define efc_log_debug(efc, fmt, args...) \ + dev_dbg(&((efc)->pci)->dev, fmt, ##args) + +#endif /* __EFC_COMMON_H__ */
drivers/scsi/elx/libefc_sli/sli4.c +1347 -0
1,350 lines not on this page · raw message
drivers/scsi/elx/libefc_sli/sli4.h +9 -0
@@ -3719,4 +3719,13 @@ struct sli4 { struct efc_dma vpd_data; }; +static inline void +sli_cmd_fill_hdr (struct sli4_rqst_hdr *hdr,u8 opc,u8 sub,u32 ver,__le32 len) +{ + hdr->opcode = opc; + hdr->subsystem = sub; + hdr->dw3_version =cpu_to_le32 (ver); + hdr->request_length = len; +} +#endif /* !_SLI4_H */
Signature · 1 line
2.26.2
Re: [PATCH v8 04/31] elx: libefc_sli: queue create/destroy/parse routines
Quoted 9 lines · James Smart
This patch continues the
libefc_sliSLI-4 library population.This patch adds service routines to create mailbox commands and adds APIs to create/destroy/parse SLI-4 EQ, CQ, RQ and MQ queues.
Co-developed-by Ram Vegesna <[email protected]>Signed-off-by Ram Vegesna <[email protected]>Signed-off-by James Smart <[email protected]>Reviewed-by Daniel Wagner <[email protected]>
Quoted 6 lines
--- drivers/scsi/elx/include/efc_common.h | 16 + drivers/scsi/elx/libefc_sli/sli4.c | 1347 +++++++++++++++++++++++++ drivers/scsi/elx/libefc_sli/sli4.h | 9 + 3 files changed, 1372 insertions(+)
Cheers,
Hannes
Signature · 4 lines
Dr. Hannes Reinecke Kernel Storage Architect [email protected] +49 911 74053 688 SUSE Software Solutions Germany GmbH, 90409 Nürnberg GF: F. Imendörffer, HRB 36809 (AG Nürnberg)
PATCH v8 5/31 elx: libefc_sli: Populate and post different WQEs
In reply to James SmartThis patch continues the libefc_sli SLI-4 library population.
This patch adds service routines to create different WQEs and adds APIs to issue iread, iwrite, treceive, tsend and other work queue entries.
--- drivers/scsi/elx/libefc_sli/sli4.c | 1500 ++++++++++++++++++++++++++++ 1 file changed, 1500 insertions(+)
drivers/scsi/elx/libefc_sli/sli4.c +1500 -0
@@ -1367,3 +1367,1503 @@ sli_cq_parse(struct sli4 *sli4, struct sli4_queue *cq, u8 *cqe,return rc; } + +int +sli_abort_wqe (struct sli4 *sli,void *buf,enum sli4_abort_type type, +bool send_abts,u32 ids,u32 mask,u16 tag,u16 cq_id) +{ +struct sli4_abort_wqe *abort = buf; + +memset (buf,0 , sli->wqe_size); + +switch (type) { +case SLI4_ABORT_XRI : + abort->criteria =SLI4_ABORT_CRITERIA_XRI_TAG ; +if (mask) { +efc_log_warn (sli,"%#x aborting XRI %#x warning non-zero mask" , + mask, ids); + mask =0 ; + } +break ; +case SLI4_ABORT_ABORT_ID : + abort->criteria =SLI4_ABORT_CRITERIA_ABORT_TAG ; +break ; +case SLI4_ABORT_REQUEST_ID : + abort->criteria =SLI4_ABORT_CRITERIA_REQUEST_TAG ; +break ; +default : +efc_log_info (sli,"unsupported type %#x\n" , type); +return EFC_FAIL ; + } + + abort->ia_ir_byte |= send_abts ?0 :1 ; + +/* Suppress ABTS retries */ + abort->ia_ir_byte |=SLI4_ABRT_WQE_IR ; + + abort->t_mask =cpu_to_le32 (mask); + abort->t_tag =cpu_to_le32 (ids); + abort->command =SLI4_WQE_ABORT ; + abort->request_tag =cpu_to_le16 (tag); + + abort->dw10w0_flags =cpu_to_le16 (SLI4_ABRT_WQE_QOSD ); + + abort->cq_id =cpu_to_le16 (cq_id); + abort->cmdtype_wqec_byte |=SLI4_CMD_ABORT_WQE ; + +return EFC_SUCCESS ; +} + +int +sli_els_request64_wqe (struct sli4 *sli,void *buf,struct efc_dma *sgl, +struct sli_els_params *params) +{ +struct sli4_els_request64_wqe *els = buf; +struct sli4_sge *sge = sgl->virt; +bool is_fabric = false; +struct sli4_bde *bptr; + +memset (buf,0 , sli->wqe_size); + + bptr = &els->els_request_payload; +if (sli->params.sgl_pre_registered) { + els->qosd_xbl_hlm_iod_dbde_wqes &= ~SLI4_REQ_WQE_XBL ; + + els->qosd_xbl_hlm_iod_dbde_wqes |=SLI4_REQ_WQE_DBDE ; + bptr->bde_type_buflen = +cpu_to_le32 ((SLI4_BDE_TYPE_VAL (64 )) | + (params->xmit_len &SLI4_BDE_LEN_MASK )); + + bptr->u.data.low = sge[0 ].buffer_address_low; + bptr->u.data.high = sge[0 ].buffer_address_high; + }else { + els->qosd_xbl_hlm_iod_dbde_wqes |=SLI4_REQ_WQE_XBL ; + + bptr->bde_type_buflen = +cpu_to_le32 ((SLI4_BDE_TYPE_VAL (BLP )) | + ((2 *sizeof (struct sli4_sge )) & +SLI4_BDE_LEN_MASK )); + bptr->u.blp.low =cpu_to_le32 (lower_32_bits (sgl->phys)); + bptr->u.blp.high =cpu_to_le32 (upper_32_bits (sgl->phys)); + } + + els->els_request_payload_length =cpu_to_le32 (params->xmit_len); + els->max_response_payload_length =cpu_to_le32 (params->rsp_len); + + els->xri_tag =cpu_to_le16 (params->xri); + els->timer = params->timeout; + els->class_byte |=SLI4_GENERIC_CLASS_CLASS_3 ; + + els->command =SLI4_WQE_ELS_REQUEST64 ; + + els->request_tag =cpu_to_le16 (params->tag); + + els->qosd_xbl_hlm_iod_dbde_wqes |=SLI4_REQ_WQE_IOD ; + + els->qosd_xbl_hlm_iod_dbde_wqes |=SLI4_REQ_WQE_QOSD ; + +/* figure out the ELS_ID value from the request buffer */ + +switch (params->cmd) { +case ELS_LOGO : + els->cmdtype_elsid_byte |= +SLI4_ELS_REQUEST64_LOGO <<SLI4_REQ_WQE_ELSID_SHFT ; +if (params->rpi_registered) { + els->ct_byte |= +SLI4_GENERIC_CONTEXT_RPI <<SLI4_REQ_WQE_CT_SHFT ; + els->context_tag =cpu_to_le16 (params->rpi); + }else { + els->ct_byte |= +SLI4_GENERIC_CONTEXT_VPI <<SLI4_REQ_WQE_CT_SHFT ; + els->context_tag =cpu_to_le16 (params->vpi); + } +if (params->d_id ==FC_FID_FLOGI ) + is_fabric = true; +break ; +case ELS_FDISC : +if (params->d_id ==FC_FID_FLOGI ) + is_fabric = true; +if (params->s_id ==0 ) { + els->cmdtype_elsid_byte |= +SLI4_ELS_REQUEST64_FDISC <<SLI4_REQ_WQE_ELSID_SHFT ; + is_fabric = true; + }else { + els->cmdtype_elsid_byte |= +SLI4_ELS_REQUEST64_OTHER <<SLI4_REQ_WQE_ELSID_SHFT ; + } + els->ct_byte |= +SLI4_GENERIC_CONTEXT_VPI <<SLI4_REQ_WQE_CT_SHFT ; + els->context_tag =cpu_to_le16 (params->vpi); + els->sid_sp_dword |=cpu_to_le32 (1 <<SLI4_REQ_WQE_SP_SHFT ); +break ; +case ELS_FLOGI : + els->ct_byte |= +SLI4_GENERIC_CONTEXT_VPI <<SLI4_REQ_WQE_CT_SHFT ; + els->context_tag =cpu_to_le16 (params->vpi); +/* +* Set SP here ... we haven't done a REG_VPI yet +* need to maybe not set this when we have +* completed VFI/VPI registrations ... +* +* Use the FC_ID of the SPORT if it has been allocated, +* otherwise use an S_ID of zero. +*/ + els->sid_sp_dword |=cpu_to_le32 (1 <<SLI4_REQ_WQE_SP_SHFT ); +if (params->s_id !=U32_MAX ) + els->sid_sp_dword |=cpu_to_le32 (params->s_id); +break ; +case ELS_PLOGI : + els->cmdtype_elsid_byte |= +SLI4_ELS_REQUEST64_PLOGI <<SLI4_REQ_WQE_ELSID_SHFT ; + els->ct_byte |= +SLI4_GENERIC_CONTEXT_VPI <<SLI4_REQ_WQE_CT_SHFT ; + els->context_tag =cpu_to_le16 (params->vpi); +break ; +case ELS_SCR : + els->cmdtype_elsid_byte |= +SLI4_ELS_REQUEST64_OTHER <<SLI4_REQ_WQE_ELSID_SHFT ; + els->ct_byte |= +SLI4_GENERIC_CONTEXT_VPI <<SLI4_REQ_WQE_CT_SHFT ; + els->context_tag =cpu_to_le16 (params->vpi); +break ; +default : + els->cmdtype_elsid_byte |= +SLI4_ELS_REQUEST64_OTHER <<SLI4_REQ_WQE_ELSID_SHFT ; +if (params->rpi_registered) { + els->ct_byte |= (SLI4_GENERIC_CONTEXT_RPI << +SLI4_REQ_WQE_CT_SHFT ); + els->context_tag =cpu_to_le16 (params->vpi); + }else { + els->ct_byte |= +SLI4_GENERIC_CONTEXT_VPI <<SLI4_REQ_WQE_CT_SHFT ; + els->context_tag =cpu_to_le16 (params->vpi); + } +break ; + } + +if (is_fabric) + els->cmdtype_elsid_byte |=SLI4_ELS_REQUEST64_CMD_FABRIC ; +else + els->cmdtype_elsid_byte |=SLI4_ELS_REQUEST64_CMD_NON_FABRIC ; + + els->cq_id =cpu_to_le16 (SLI4_CQ_DEFAULT ); + +if (((els->ct_byte &SLI4_REQ_WQE_CT ) >>SLI4_REQ_WQE_CT_SHFT ) != +SLI4_GENERIC_CONTEXT_RPI ) + els->remote_id_dword =cpu_to_le32 (params->d_id); + +if (((els->ct_byte &SLI4_REQ_WQE_CT ) >>SLI4_REQ_WQE_CT_SHFT ) == +SLI4_GENERIC_CONTEXT_VPI ) + els->temporary_rpi =cpu_to_le16 (params->rpi); + +return EFC_SUCCESS ; +} + +int +sli_fcp_icmnd64_wqe (struct sli4 *sli,void *buf,struct efc_dma *sgl,u16 xri, +u16 tag,u16 cq_id,u32 rpi,u32 rnode_fcid,u8 timeout) +{ +struct sli4_fcp_icmnd64_wqe *icmnd = buf; +struct sli4_sge *sge =NULL ; +struct sli4_bde *bptr; +u32 len; + +memset (buf,0 , sli->wqe_size); + +if (!sgl || !sgl->virt) { +efc_log_err (sli,"bad parameter sgl=%p virt=%p\n" , + sgl, sgl ? sgl->virt :NULL ); +return EFC_FAIL ; + } + sge = sgl->virt; + bptr = &icmnd->bde; +if (sli->params.sgl_pre_registered) { + icmnd->qosd_xbl_hlm_iod_dbde_wqes &= ~SLI4_ICMD_WQE_XBL ; + + icmnd->qosd_xbl_hlm_iod_dbde_wqes |=SLI4_ICMD_WQE_DBDE ; + bptr->bde_type_buflen = +cpu_to_le32 ((SLI4_BDE_TYPE_VAL (64 )) | + (le32_to_cpu (sge[0 ].buffer_length) & +SLI4_BDE_LEN_MASK )); + + bptr->u.data.low = sge[0 ].buffer_address_low; + bptr->u.data.high = sge[0 ].buffer_address_high; + }else { + icmnd->qosd_xbl_hlm_iod_dbde_wqes |=SLI4_ICMD_WQE_XBL ; + + bptr->bde_type_buflen = +cpu_to_le32 ((SLI4_BDE_TYPE_VAL (BLP )) | + (sgl->size &SLI4_BDE_LEN_MASK )); + + bptr->u.blp.low =cpu_to_le32 (lower_32_bits (sgl->phys)); + bptr->u.blp.high =cpu_to_le32 (upper_32_bits (sgl->phys)); + } + + len =le32_to_cpu (sge[0 ].buffer_length) + +le32_to_cpu (sge[1 ].buffer_length); + icmnd->payload_offset_length =cpu_to_le16 (len); + icmnd->xri_tag =cpu_to_le16 (xri); + icmnd->context_tag =cpu_to_le16 (rpi); + icmnd->timer = timeout; + +/* WQE word 4 contains read transfer length */ + icmnd->class_pu_byte |=2 <<SLI4_ICMD_WQE_PU_SHFT ; + icmnd->class_pu_byte |=SLI4_GENERIC_CLASS_CLASS_3 ; + icmnd->command =SLI4_WQE_FCP_ICMND64 ; + icmnd->dif_ct_bs_byte |= +SLI4_GENERIC_CONTEXT_RPI <<SLI4_ICMD_WQE_CT_SHFT ; + + icmnd->abort_tag =cpu_to_le32 (xri); + + icmnd->request_tag =cpu_to_le16 (tag); + icmnd->len_loc1_byte |=SLI4_ICMD_WQE_LEN_LOC_BIT1 ; + icmnd->qosd_xbl_hlm_iod_dbde_wqes |=SLI4_ICMD_WQE_LEN_LOC_BIT2 ; + icmnd->cmd_type_byte |=SLI4_CMD_FCP_ICMND64_WQE ; + icmnd->cq_id =cpu_to_le16 (cq_id); + +return EFC_SUCCESS ; +} + +int +sli_fcp_iread64_wqe (struct sli4 *sli,void *buf,struct efc_dma *sgl, +u32 first_data_sge,u32 xfer_len,u16 xri,u16 tag, +u16 cq_id,u32 rpi,u32 rnode_fcid, +u8 dif,u8 bs,u8 timeout) +{ +struct sli4_fcp_iread64_wqe *iread = buf; +struct sli4_sge *sge =NULL ; +struct sli4_bde *bptr; +u32 sge_flags, len; + +memset (buf,0 , sli->wqe_size); + +if (!sgl || !sgl->virt) { +efc_log_err (sli,"bad parameter sgl=%p virt=%p\n" , + sgl, sgl ? sgl->virt :NULL ); +return EFC_FAIL ; + } + + sge = sgl->virt; + bptr = &iread->bde; +if (sli->params.sgl_pre_registered) { + iread->qosd_xbl_hlm_iod_dbde_wqes &= ~SLI4_IR_WQE_XBL ; + + iread->qosd_xbl_hlm_iod_dbde_wqes |=SLI4_IR_WQE_DBDE ; + + bptr->bde_type_buflen = +cpu_to_le32 ((SLI4_BDE_TYPE_VAL (64 )) | + (le32_to_cpu (sge[0 ].buffer_length) & +SLI4_BDE_LEN_MASK )); + + bptr->u.blp.low = sge[0 ].buffer_address_low; + bptr->u.blp.high = sge[0 ].buffer_address_high; + }else { + iread->qosd_xbl_hlm_iod_dbde_wqes |=SLI4_IR_WQE_XBL ; + + bptr->bde_type_buflen = +cpu_to_le32 ((SLI4_BDE_TYPE_VAL (BLP )) | + (sgl->size &SLI4_BDE_LEN_MASK )); + + bptr->u.blp.low = +cpu_to_le32 (lower_32_bits (sgl->phys)); + bptr->u.blp.high = +cpu_to_le32 (upper_32_bits (sgl->phys)); + +/* +* fill out fcp_cmnd buffer len and change resp buffer to be of +* type "skip" (note: response will still be written to sge[1] +* if necessary) +*/ + len =le32_to_cpu (sge[0 ].buffer_length); + iread->fcp_cmd_buffer_length =cpu_to_le16 (len); + + sge_flags =le32_to_cpu (sge[1 ].dw2_flags); + sge_flags &= (~SLI4_SGE_TYPE_MASK ); + sge_flags |= (SLI4_SGE_TYPE_SKIP <<SLI4_SGE_TYPE_SHIFT ); + sge[1 ].dw2_flags =cpu_to_le32 (sge_flags); + } + + len =le32_to_cpu (sge[0 ].buffer_length) + +le32_to_cpu (sge[1 ].buffer_length); + iread->payload_offset_length =cpu_to_le16 (len); + iread->total_transfer_length =cpu_to_le32 (xfer_len); + + iread->xri_tag =cpu_to_le16 (xri); + iread->context_tag =cpu_to_le16 (rpi); + + iread->timer = timeout; + +/* WQE word 4 contains read transfer length */ + iread->class_pu_byte |=2 <<SLI4_IR_WQE_PU_SHFT ; + iread->class_pu_byte |=SLI4_GENERIC_CLASS_CLASS_3 ; + iread->command =SLI4_WQE_FCP_IREAD64 ; + iread->dif_ct_bs_byte |= +SLI4_GENERIC_CONTEXT_RPI <<SLI4_IR_WQE_CT_SHFT ; + iread->dif_ct_bs_byte |= dif; + iread->dif_ct_bs_byte |= bs <<SLI4_IR_WQE_BS_SHFT ; + + iread->abort_tag =cpu_to_le32 (xri); + + iread->request_tag =cpu_to_le16 (tag); + iread->len_loc1_byte |=SLI4_IR_WQE_LEN_LOC_BIT1 ; + iread->qosd_xbl_hlm_iod_dbde_wqes |=SLI4_IR_WQE_LEN_LOC_BIT2 ; + iread->qosd_xbl_hlm_iod_dbde_wqes |=SLI4_IR_WQE_IOD ; + iread->cmd_type_byte |=SLI4_CMD_FCP_IREAD64_WQE ; + iread->cq_id =cpu_to_le16 (cq_id); + +if (sli->params.perf_hint) { + bptr = &iread->first_data_bde; + bptr->bde_type_buflen =cpu_to_le32 ((SLI4_BDE_TYPE_VAL (64 )) | + (le32_to_cpu (sge[first_data_sge].buffer_length) & +SLI4_BDE_LEN_MASK )); + bptr->u.data.low = + sge[first_data_sge].buffer_address_low; + bptr->u.data.high = + sge[first_data_sge].buffer_address_high; + } + +return EFC_SUCCESS ; +} + +int +sli_fcp_iwrite64_wqe (struct sli4 *sli,void *buf,struct efc_dma *sgl, +u32 first_data_sge,u32 xfer_len, +u32 first_burst,u16 xri,u16 tag, +u16 cq_id,u32 rpi, +u32 rnode_fcid, +u8 dif,u8 bs,u8 timeout) +{ +struct sli4_fcp_iwrite64_wqe *iwrite = buf; +struct sli4_sge *sge =NULL ; +struct sli4_bde *bptr; +u32 sge_flags, min, len; + +memset (buf,0 , sli->wqe_size); + +if (!sgl || !sgl->virt) { +efc_log_err (sli,"bad parameter sgl=%p virt=%p\n" , + sgl, sgl ? sgl->virt :NULL ); +return EFC_FAIL ; + } + sge = sgl->virt; + bptr = &iwrite->bde; +if (sli->params.sgl_pre_registered) { + iwrite->qosd_xbl_hlm_iod_dbde_wqes &= ~SLI4_IWR_WQE_XBL ; + + iwrite->qosd_xbl_hlm_iod_dbde_wqes |=SLI4_IWR_WQE_DBDE ; + bptr->bde_type_buflen =cpu_to_le32 ((SLI4_BDE_TYPE_VAL (64 )) | + (le32_to_cpu (sge[0 ].buffer_length) &SLI4_BDE_LEN_MASK )); + bptr->u.data.low = sge[0 ].buffer_address_low; + bptr->u.data.high = sge[0 ].buffer_address_high; + }else { + iwrite->qosd_xbl_hlm_iod_dbde_wqes |=SLI4_IWR_WQE_XBL ; + + bptr->bde_type_buflen =cpu_to_le32 ((SLI4_BDE_TYPE_VAL (64 )) | + (sgl->size &SLI4_BDE_LEN_MASK )); + + bptr->u.blp.low =cpu_to_le32 (lower_32_bits (sgl->phys)); + bptr->u.blp.high =cpu_to_le32 (upper_32_bits (sgl->phys)); + +/* +* fill out fcp_cmnd buffer len and change resp buffer to be of +* type "skip" (note: response will still be written to sge[1] +* if necessary) +*/ + len =le32_to_cpu (sge[0 ].buffer_length); + iwrite->fcp_cmd_buffer_length =cpu_to_le16 (len); + sge_flags =le32_to_cpu (sge[1 ].dw2_flags); + sge_flags &= ~SLI4_SGE_TYPE_MASK ; + sge_flags |= (SLI4_SGE_TYPE_SKIP <<SLI4_SGE_TYPE_SHIFT ); + sge[1 ].dw2_flags =cpu_to_le32 (sge_flags); + } + + len =le32_to_cpu (sge[0 ].buffer_length) + +le32_to_cpu (sge[1 ].buffer_length); + iwrite->payload_offset_length =cpu_to_le16 (len); + iwrite->total_transfer_length =cpu_to_le16 (xfer_len); + min = (xfer_len < first_burst) ? xfer_len : first_burst; + iwrite->initial_transfer_length =cpu_to_le16 (min); + + iwrite->xri_tag =cpu_to_le16 (xri); + iwrite->context_tag =cpu_to_le16 (rpi); + + iwrite->timer = timeout; +/* WQE word 4 contains read transfer length */ + iwrite->class_pu_byte |=2 <<SLI4_IWR_WQE_PU_SHFT ; + iwrite->class_pu_byte |=SLI4_GENERIC_CLASS_CLASS_3 ; + iwrite->command =SLI4_WQE_FCP_IWRITE64 ; + iwrite->dif_ct_bs_byte |= +SLI4_GENERIC_CONTEXT_RPI <<SLI4_IWR_WQE_CT_SHFT ; + iwrite->dif_ct_bs_byte |= dif; + iwrite->dif_ct_bs_byte |= bs <<SLI4_IWR_WQE_BS_SHFT ; + + iwrite->abort_tag =cpu_to_le32 (xri); + + iwrite->request_tag =cpu_to_le16 (tag); + iwrite->len_loc1_byte |=SLI4_IWR_WQE_LEN_LOC_BIT1 ; + iwrite->qosd_xbl_hlm_iod_dbde_wqes |=SLI4_IWR_WQE_LEN_LOC_BIT2 ; + iwrite->cmd_type_byte |=SLI4_CMD_FCP_IWRITE64_WQE ; + iwrite->cq_id =cpu_to_le16 (cq_id); + +if (sli->params.perf_hint) { + bptr = &iwrite->first_data_bde; + + bptr->bde_type_buflen =cpu_to_le32 ((SLI4_BDE_TYPE_VAL (64 )) | + (le32_to_cpu (sge[first_data_sge].buffer_length) & +SLI4_BDE_LEN_MASK )); + + bptr->u.data.low = sge[first_data_sge].buffer_address_low; + bptr->u.data.high = sge[first_data_sge].buffer_address_high; + } + +return EFC_SUCCESS ; +} + +int +sli_fcp_treceive64_wqe (struct sli4 *sli,void *buf,struct efc_dma *sgl, +u32 first_data_sge,u16 cq_id,u8 dif,u8 bs, +struct sli_fcp_tgt_params *params) +{ +struct sli4_fcp_treceive64_wqe *trecv = buf; +struct sli4_fcp_128byte_wqe *trecv_128 = buf; +struct sli4_sge *sge =NULL ; +struct sli4_bde *bptr; + +memset (buf,0 , sli->wqe_size); + +if (!sgl || !sgl->virt) { +efc_log_err (sli,"bad parameter sgl=%p virt=%p\n" , + sgl, sgl ? sgl->virt :NULL ); +return EFC_FAIL ; + } + sge = sgl->virt; + bptr = &trecv->bde; +if (sli->params.sgl_pre_registered) { + trecv->qosd_xbl_hlm_iod_dbde_wqes &= ~SLI4_TRCV_WQE_XBL ; + + trecv->qosd_xbl_hlm_iod_dbde_wqes |=SLI4_TRCV_WQE_DBDE ; + + bptr->bde_type_buflen = +cpu_to_le32 ((SLI4_BDE_TYPE_VAL (64 )) | + (le32_to_cpu (sge[0 ].buffer_length) + &SLI4_BDE_LEN_MASK )); + + bptr->u.data.low = sge[0 ].buffer_address_low; + bptr->u.data.high = sge[0 ].buffer_address_high; + + trecv->payload_offset_length = sge[0 ].buffer_length; + }else { + trecv->qosd_xbl_hlm_iod_dbde_wqes |=SLI4_TRCV_WQE_XBL ; + +/* if data is a single physical address, use a BDE */ +if (!dif && + params->xmit_len <=le32_to_cpu (sge[2 ].buffer_length)) { + trecv->qosd_xbl_hlm_iod_dbde_wqes |=SLI4_TRCV_WQE_DBDE ; + bptr->bde_type_buflen = +cpu_to_le32 ((SLI4_BDE_TYPE_VAL (64 )) | + (le32_to_cpu (sge[2 ].buffer_length) + &SLI4_BDE_LEN_MASK )); + + bptr->u.data.low = sge[2 ].buffer_address_low; + bptr->u.data.high = sge[2 ].buffer_address_high; + }else { + bptr->bde_type_buflen = +cpu_to_le32 ((SLI4_BDE_TYPE_VAL (BLP )) | + (sgl->size &SLI4_BDE_LEN_MASK )); + bptr->u.blp.low =cpu_to_le32 (lower_32_bits (sgl->phys)); + bptr->u.blp.high = +cpu_to_le32 (upper_32_bits (sgl->phys)); + } + } + + trecv->relative_offset =cpu_to_le32 (params->offset); + +if (params->flags &SLI4_IO_CONTINUATION ) + trecv->eat_xc_ccpe |=SLI4_TRCV_WQE_XC ; + + trecv->xri_tag =cpu_to_le16 (params->xri); + + trecv->context_tag =cpu_to_le16 (params->rpi); + +/* WQE uses relative offset */ + trecv->class_ar_pu_byte |=1 <<SLI4_TRCV_WQE_PU_SHFT ; + +if (params->flags &SLI4_IO_AUTO_GOOD_RESPONSE ) + trecv->class_ar_pu_byte |=SLI4_TRCV_WQE_AR ; + + trecv->command =SLI4_WQE_FCP_TRECEIVE64 ; + trecv->class_ar_pu_byte |=SLI4_GENERIC_CLASS_CLASS_3 ; + trecv->dif_ct_bs_byte |= +SLI4_GENERIC_CONTEXT_RPI <<SLI4_TRCV_WQE_CT_SHFT ; + trecv->dif_ct_bs_byte |= bs <<SLI4_TRCV_WQE_BS_SHFT ; + + trecv->remote_xid =cpu_to_le16 (params->ox_id); + + trecv->request_tag =cpu_to_le16 (params->tag); + + trecv->qosd_xbl_hlm_iod_dbde_wqes |=SLI4_TRCV_WQE_IOD ; + + trecv->qosd_xbl_hlm_iod_dbde_wqes |=SLI4_TRCV_WQE_LEN_LOC_BIT2 ; + + trecv->cmd_type_byte |=SLI4_CMD_FCP_TRECEIVE64_WQE ; + + trecv->cq_id =cpu_to_le16 (cq_id); + + trecv->fcp_data_receive_length =cpu_to_le32 (params->xmit_len); + +if (sli->params.perf_hint) { + bptr = &trecv->first_data_bde; + + bptr->bde_type_buflen = +cpu_to_le32 ((SLI4_BDE_TYPE_VAL (64 )) | + (le32_to_cpu (sge[first_data_sge].buffer_length) & +SLI4_BDE_LEN_MASK )); + bptr->u.data.low = sge[first_data_sge].buffer_address_low; + bptr->u.data.high = sge[first_data_sge].buffer_address_high; + } + +/* The upper 7 bits of csctl is the priority */ +if (params->cs_ctl &SLI4_MASK_CCP ) { + trecv->eat_xc_ccpe |=SLI4_TRCV_WQE_CCPE ; + trecv->ccp = (params->cs_ctl &SLI4_MASK_CCP ); + } + +if (params->app_id && sli->wqe_size ==SLI4_WQE_EXT_BYTES && + !(trecv->eat_xc_ccpe &SLI4_TRSP_WQE_EAT )) { + trecv->lloc1_appid |=SLI4_TRCV_WQE_APPID ; + trecv->qosd_xbl_hlm_iod_dbde_wqes |=SLI4_TRCV_WQE_WQES ; + trecv_128->dw[31 ] = params->app_id; + } +return EFC_SUCCESS ; +} + +int +sli_fcp_cont_treceive64_wqe (struct sli4 *sli,void *buf, +struct efc_dma *sgl,u32 first_data_sge, +u16 sec_xri,u16 cq_id,u8 dif,u8 bs, +struct sli_fcp_tgt_params *params) +{ +int rc; + + rc =sli_fcp_treceive64_wqe (sli, buf, sgl, first_data_sge, + cq_id, dif, bs, params); +if (!rc) { +struct sli4_fcp_treceive64_wqe *trecv = buf; + + trecv->command =SLI4_WQE_FCP_CONT_TRECEIVE64 ; + trecv->dword5.sec_xri_tag =cpu_to_le16 (sec_xri); + } +return rc; +} + +int +sli_fcp_trsp64_wqe (struct sli4 *sli4,void *buf,struct efc_dma *sgl, +u16 cq_id,u8 port_owned,struct sli_fcp_tgt_params *params) +{ +struct sli4_fcp_trsp64_wqe *trsp = buf; +struct sli4_fcp_128byte_wqe *trsp_128 = buf; + +memset (buf,0 , sli4->wqe_size); + +if (params->flags &SLI4_IO_AUTO_GOOD_RESPONSE ) { + trsp->class_ag_byte |=SLI4_TRSP_WQE_AG ; + }else { +struct sli4_sge *sge = sgl->virt; +struct sli4_bde *bptr; + +if (sli4->params.sgl_pre_registered || port_owned) + trsp->qosd_xbl_hlm_dbde_wqes |=SLI4_TRSP_WQE_DBDE ; +else + trsp->qosd_xbl_hlm_dbde_wqes |=SLI4_TRSP_WQE_XBL ; + bptr = &trsp->bde; + + bptr->bde_type_buflen = +cpu_to_le32 ((SLI4_BDE_TYPE_VAL (64 )) | + (le32_to_cpu (sge[0 ].buffer_length) & +SLI4_BDE_LEN_MASK )); + bptr->u.data.low = sge[0 ].buffer_address_low; + bptr->u.data.high = sge[0 ].buffer_address_high; + + trsp->fcp_response_length =cpu_to_le32 (params->xmit_len); + } + +if (params->flags &SLI4_IO_CONTINUATION ) + trsp->eat_xc_ccpe |=SLI4_TRSP_WQE_XC ; + + trsp->xri_tag =cpu_to_le16 (params->xri); + trsp->rpi =cpu_to_le16 (params->rpi); + + trsp->command =SLI4_WQE_FCP_TRSP64 ; + trsp->class_ag_byte |=SLI4_GENERIC_CLASS_CLASS_3 ; + + trsp->remote_xid =cpu_to_le16 (params->ox_id); + trsp->request_tag =cpu_to_le16 (params->tag); +if (params->flags &SLI4_IO_DNRX ) + trsp->ct_dnrx_byte |=SLI4_TRSP_WQE_DNRX ; +else + trsp->ct_dnrx_byte &= ~SLI4_TRSP_WQE_DNRX ; + + trsp->lloc1_appid |=0x1 ; + trsp->cq_id =cpu_to_le16 (cq_id); + trsp->cmd_type_byte =SLI4_CMD_FCP_TRSP64_WQE ; + +/* The upper 7 bits of csctl is the priority */ +if (params->cs_ctl &SLI4_MASK_CCP ) { + trsp->eat_xc_ccpe |=SLI4_TRSP_WQE_CCPE ; + trsp->ccp = (params->cs_ctl &SLI4_MASK_CCP ); + } + +if (params->app_id && sli4->wqe_size ==SLI4_WQE_EXT_BYTES && + !(trsp->eat_xc_ccpe &SLI4_TRSP_WQE_EAT )) { + trsp->lloc1_appid |=SLI4_TRSP_WQE_APPID ; + trsp->qosd_xbl_hlm_dbde_wqes |=SLI4_TRSP_WQE_WQES ; + trsp_128->dw[31 ] = params->app_id; + } +return EFC_SUCCESS ; +} + +int +sli_fcp_tsend64_wqe (struct sli4 *sli4,void *buf,struct efc_dma *sgl, +u32 first_data_sge,u16 cq_id,u8 dif,u8 bs, +struct sli_fcp_tgt_params *params) +{ +struct sli4_fcp_tsend64_wqe *tsend = buf; +struct sli4_fcp_128byte_wqe *tsend_128 = buf; +struct sli4_sge *sge =NULL ; +struct sli4_bde *bptr; + +memset (buf,0 , sli4->wqe_size); + +if (!sgl || !sgl->virt) { +efc_log_err (sli4,"bad parameter sgl=%p virt=%p\n" , + sgl, sgl ? sgl->virt :NULL ); +return EFC_FAIL ; + } + sge = sgl->virt; + + bptr = &tsend->bde; +if (sli4->params.sgl_pre_registered) { + tsend->ll_qd_xbl_hlm_iod_dbde &= ~SLI4_TSEND_WQE_XBL ; + + tsend->ll_qd_xbl_hlm_iod_dbde |=SLI4_TSEND_WQE_DBDE ; + + bptr->bde_type_buflen = +cpu_to_le32 ((SLI4_BDE_TYPE_VAL (64 )) | + (le32_to_cpu (sge[2 ].buffer_length) & +SLI4_BDE_LEN_MASK )); + +/* TSEND64_WQE specifies first two SGE are skipped (3rd is +* valid) +*/ + bptr->u.data.low = sge[2 ].buffer_address_low; + bptr->u.data.high = sge[2 ].buffer_address_high; + }else { + tsend->ll_qd_xbl_hlm_iod_dbde |=SLI4_TSEND_WQE_XBL ; + +/* if data is a single physical address, use a BDE */ +if (!dif && + params->xmit_len <=le32_to_cpu (sge[2 ].buffer_length)) { + tsend->ll_qd_xbl_hlm_iod_dbde |=SLI4_TSEND_WQE_DBDE ; + + bptr->bde_type_buflen = +cpu_to_le32 ((SLI4_BDE_TYPE_VAL (64 )) | + (le32_to_cpu (sge[2 ].buffer_length) & +SLI4_BDE_LEN_MASK )); +/* +* TSEND64_WQE specifies first two SGE are skipped +* (i.e. 3rd is valid) +*/ + bptr->u.data.low = + sge[2 ].buffer_address_low; + bptr->u.data.high = + sge[2 ].buffer_address_high; + }else { + bptr->bde_type_buflen = +cpu_to_le32 ((SLI4_BDE_TYPE_VAL (BLP )) | + (sgl->size & +SLI4_BDE_LEN_MASK )); + bptr->u.blp.low = +cpu_to_le32 (lower_32_bits (sgl->phys)); + bptr->u.blp.high = +cpu_to_le32 (upper_32_bits (sgl->phys)); + } + } + + tsend->relative_offset =cpu_to_le32 (params->offset); + +if (params->flags &SLI4_IO_CONTINUATION ) + tsend->dw10byte2 |=SLI4_TSEND_XC ; + + tsend->xri_tag =cpu_to_le16 (params->xri); + + tsend->rpi =cpu_to_le16 (params->rpi); +/* WQE uses relative offset */ + tsend->class_pu_ar_byte |=1 <<SLI4_TSEND_WQE_PU_SHFT ; + +if (params->flags &SLI4_IO_AUTO_GOOD_RESPONSE ) + tsend->class_pu_ar_byte |=SLI4_TSEND_WQE_AR ; + + tsend->command =SLI4_WQE_FCP_TSEND64 ; + tsend->class_pu_ar_byte |=SLI4_GENERIC_CLASS_CLASS_3 ; + tsend->ct_byte |=SLI4_GENERIC_CONTEXT_RPI <<SLI4_TSEND_CT_SHFT ; + tsend->ct_byte |= dif; + tsend->ct_byte |= bs <<SLI4_TSEND_BS_SHFT ; + + tsend->remote_xid =cpu_to_le16 (params->ox_id); + + tsend->request_tag =cpu_to_le16 (params->tag); + + tsend->ll_qd_xbl_hlm_iod_dbde |=SLI4_TSEND_LEN_LOC_BIT2 ; + + tsend->cq_id =cpu_to_le16 (cq_id); + + tsend->cmd_type_byte |=SLI4_CMD_FCP_TSEND64_WQE ; + + tsend->fcp_data_transmit_length =cpu_to_le32 (params->xmit_len); + +if (sli4->params.perf_hint) { + bptr = &tsend->first_data_bde; + bptr->bde_type_buflen = +cpu_to_le32 ((SLI4_BDE_TYPE_VAL (64 )) | + (le32_to_cpu (sge[first_data_sge].buffer_length) & +SLI4_BDE_LEN_MASK )); + bptr->u.data.low = + sge[first_data_sge].buffer_address_low; + bptr->u.data.high = + sge[first_data_sge].buffer_address_high; + } + +/* The upper 7 bits of csctl is the priority */ +if (params->cs_ctl &SLI4_MASK_CCP ) { + tsend->dw10byte2 |=SLI4_TSEND_CCPE ; + tsend->ccp = (params->cs_ctl &SLI4_MASK_CCP ); + } + +if (params->app_id && sli4->wqe_size ==SLI4_WQE_EXT_BYTES && + !(tsend->dw10byte2 &SLI4_TSEND_EAT )) { + tsend->dw10byte0 |=SLI4_TSEND_APPID_VALID ; + tsend->ll_qd_xbl_hlm_iod_dbde |=SLI4_TSEND_WQES ; + tsend_128->dw[31 ] = params->app_id; + } +return EFC_SUCCESS ; +} + +int +sli_gen_request64_wqe (struct sli4 *sli4,void *buf,struct efc_dma *sgl, +struct sli_ct_params *params) +{ +struct sli4_gen_request64_wqe *gen = buf; +struct sli4_sge *sge =NULL ; +struct sli4_bde *bptr; + +memset (buf,0 , sli4->wqe_size); + +if (!sgl || !sgl->virt) { +efc_log_err (sli4,"bad parameter sgl=%p virt=%p\n" , + sgl, sgl ? sgl->virt :NULL ); +return EFC_FAIL ; + } + sge = sgl->virt; + bptr = &gen->bde; + +if (sli4->params.sgl_pre_registered) { + gen->dw10flags1 &= ~SLI4_GEN_REQ64_WQE_XBL ; + + gen->dw10flags1 |=SLI4_GEN_REQ64_WQE_DBDE ; + bptr->bde_type_buflen = +cpu_to_le32 ((SLI4_BDE_TYPE_VAL (64 )) | + (params->xmit_len &SLI4_BDE_LEN_MASK )); + + bptr->u.data.low = sge[0 ].buffer_address_low; + bptr->u.data.high = sge[0 ].buffer_address_high; + }else { + gen->dw10flags1 |=SLI4_GEN_REQ64_WQE_XBL ; + + bptr->bde_type_buflen = +cpu_to_le32 ((SLI4_BDE_TYPE_VAL (BLP )) | + ((2 *sizeof (struct sli4_sge )) & +SLI4_BDE_LEN_MASK )); + + bptr->u.blp.low = +cpu_to_le32 (lower_32_bits (sgl->phys)); + bptr->u.blp.high = +cpu_to_le32 (upper_32_bits (sgl->phys)); + } + + gen->request_payload_length =cpu_to_le32 (params->xmit_len); + gen->max_response_payload_length =cpu_to_le32 (params->rsp_len); + + gen->df_ctl = params->df_ctl; + gen->type = params->type; + gen->r_ctl = params->r_ctl; + + gen->xri_tag =cpu_to_le16 (params->xri); + + gen->ct_byte =SLI4_GENERIC_CONTEXT_RPI <<SLI4_GEN_REQ64_CT_SHFT ; + gen->context_tag =cpu_to_le16 (params->rpi); + + gen->class_byte =SLI4_GENERIC_CLASS_CLASS_3 ; + + gen->command =SLI4_WQE_GEN_REQUEST64 ; + + gen->timer = params->timeout; + + gen->request_tag =cpu_to_le16 (params->tag); + + gen->dw10flags1 |=SLI4_GEN_REQ64_WQE_IOD ; + + gen->dw10flags0 |=SLI4_GEN_REQ64_WQE_QOSD ; + + gen->cmd_type_byte =SLI4_CMD_GEN_REQUEST64_WQE ; + + gen->cq_id =cpu_to_le16 (SLI4_CQ_DEFAULT ); + +return EFC_SUCCESS ; +} + +int +sli_send_frame_wqe (struct sli4 *sli,void *buf,u8 sof,u8 eof,u32 *hdr, +struct efc_dma *payload,u32 req_len, +u8 timeout,u16 xri,u16 req_tag) +{ +struct sli4_send_frame_wqe *sf = buf; + +memset (buf,0 , sli->wqe_size); + + sf->dw10flags1 |=SLI4_SF_WQE_DBDE ; + sf->bde.bde_type_buflen =cpu_to_le32 (req_len & +SLI4_BDE_LEN_MASK ); + sf->bde.u.data.low =cpu_to_le32 (lower_32_bits (payload->phys)); + sf->bde.u.data.high =cpu_to_le32 (upper_32_bits (payload->phys)); + +/* Copy FC header */ + sf->fc_header_0_1[0 ] =cpu_to_le32 (hdr[0 ]); + sf->fc_header_0_1[1 ] =cpu_to_le32 (hdr[1 ]); + sf->fc_header_2_5[0 ] =cpu_to_le32 (hdr[2 ]); + sf->fc_header_2_5[1 ] =cpu_to_le32 (hdr[3 ]); + sf->fc_header_2_5[2 ] =cpu_to_le32 (hdr[4 ]); + sf->fc_header_2_5[3 ] =cpu_to_le32 (hdr[5 ]); + + sf->frame_length =cpu_to_le32 (req_len); + + sf->xri_tag =cpu_to_le16 (xri); + sf->dw7flags0 &= ~SLI4_SF_PU ; + sf->context_tag =0 ; + + sf->ct_byte &= ~SLI4_SF_CT ; + sf->command =SLI4_WQE_SEND_FRAME ; + sf->dw7flags0 |=SLI4_GENERIC_CLASS_CLASS_3 ; + sf->timer = timeout; + + sf->request_tag =cpu_to_le16 (req_tag); + sf->eof = eof; + sf->sof = sof; + + sf->dw10flags1 &= ~SLI4_SF_QOSD ; + sf->dw10flags0 |=SLI4_SF_LEN_LOC_BIT1 ; + sf->dw10flags2 &= ~SLI4_SF_XC ; + + sf->dw10flags1 |=SLI4_SF_XBL ; + + sf->cmd_type_byte |=SLI4_CMD_SEND_FRAME_WQE ; + sf->cq_id =cpu_to_le16 (0xffff ); + +return EFC_SUCCESS ; +} + +int +sli_xmit_bls_rsp64_wqe (struct sli4 *sli,void *buf, +struct sli_bls_payload *payload,struct sli_bls_params *params) +{ +struct sli4_xmit_bls_rsp_wqe *bls = buf; +u32 dw_ridflags =0 ; + +/* +* Callers can either specify RPI or S_ID, but not both +*/ +if (params->rpi_registered && params->s_id !=U32_MAX ) { +efc_log_info (sli,"S_ID specified for attached remote node %d\n" , + params->rpi); +return EFC_FAIL ; + } + +memset (buf,0 , sli->wqe_size); + +if (payload->type ==SLI4_SLI_BLS_ACC ) { + bls->payload_word0 = +cpu_to_le32 ((payload->u.acc.seq_id_last <<16 ) | + (payload->u.acc.seq_id_validity <<24 )); + bls->high_seq_cnt = payload->u.acc.high_seq_cnt; + bls->low_seq_cnt = payload->u.acc.low_seq_cnt; + }else if (payload->type ==SLI4_SLI_BLS_RJT ) { + bls->payload_word0 = +cpu_to_le32 (*((u32 *)&payload->u.rjt)); + dw_ridflags |=SLI4_BLS_RSP_WQE_AR ; + }else { +efc_log_info (sli,"bad BLS type %#x\n" , payload->type); +return EFC_FAIL ; + } + + bls->ox_id = payload->ox_id; + bls->rx_id = payload->rx_id; + +if (params->rpi_registered) { + bls->dw8flags0 |= +SLI4_GENERIC_CONTEXT_RPI <<SLI4_BLS_RSP_WQE_CT_SHFT ; + bls->context_tag =cpu_to_le16 (params->rpi); + }else { + bls->dw8flags0 |= +SLI4_GENERIC_CONTEXT_VPI <<SLI4_BLS_RSP_WQE_CT_SHFT ; + bls->context_tag =cpu_to_le16 (params->vpi); + +if (params->s_id !=U32_MAX ) + bls->local_n_port_id_dword |= +cpu_to_le32 (params->s_id &0x00ffffff ); +else + bls->local_n_port_id_dword |= +cpu_to_le32 (params->s_id &0x00ffffff ); + + dw_ridflags = (dw_ridflags & ~SLI4_BLS_RSP_RID ) | + (params->d_id &SLI4_BLS_RSP_RID ); + + bls->temporary_rpi =cpu_to_le16 (params->rpi); + } + + bls->xri_tag =cpu_to_le16 (params->xri); + + bls->dw8flags1 |=SLI4_GENERIC_CLASS_CLASS_3 ; + + bls->command =SLI4_WQE_XMIT_BLS_RSP ; + + bls->request_tag =cpu_to_le16 (params->tag); + + bls->dw11flags1 |=SLI4_BLS_RSP_WQE_QOSD ; + + bls->remote_id_dword =cpu_to_le32 (dw_ridflags); + bls->cq_id =cpu_to_le16 (SLI4_CQ_DEFAULT ); + + bls->dw12flags0 |=SLI4_CMD_XMIT_BLS_RSP64_WQE ; + +return EFC_SUCCESS ; +} + +int +sli_xmit_els_rsp64_wqe (struct sli4 *sli,void *buf,struct efc_dma *rsp, +struct sli_els_params *params) +{ +struct sli4_xmit_els_rsp64_wqe *els = buf; + +memset (buf,0 , sli->wqe_size); + +if (sli->params.sgl_pre_registered) + els->flags2 |=SLI4_ELS_DBDE ; +else + els->flags2 |=SLI4_ELS_XBL ; + + els->els_response_payload.bde_type_buflen = +cpu_to_le32 ((SLI4_BDE_TYPE_VAL (64 )) | + (params->rsp_len &SLI4_BDE_LEN_MASK )); + els->els_response_payload.u.data.low = +cpu_to_le32 (lower_32_bits (rsp->phys)); + els->els_response_payload.u.data.high = +cpu_to_le32 (upper_32_bits (rsp->phys)); + + els->els_response_payload_length =cpu_to_le32 (params->rsp_len); + + els->xri_tag =cpu_to_le16 (params->xri); + + els->class_byte |=SLI4_GENERIC_CLASS_CLASS_3 ; + + els->command =SLI4_WQE_ELS_RSP64 ; + + els->request_tag =cpu_to_le16 (params->tag); + + els->ox_id =cpu_to_le16 (params->ox_id); + + els->flags2 |=SLI4_ELS_IOD &SLI4_ELS_REQUEST64_DIR_WRITE ; + + els->flags2 |=SLI4_ELS_QOSD ; + + els->cmd_type_wqec =SLI4_ELS_REQUEST64_CMD_GEN ; + + els->cq_id =cpu_to_le16 (SLI4_CQ_DEFAULT ); + +if (params->rpi_registered) { + els->ct_byte |= +SLI4_GENERIC_CONTEXT_RPI <<SLI4_ELS_CT_OFFSET ; + els->context_tag =cpu_to_le16 (params->rpi); +return EFC_SUCCESS ; + } + + els->ct_byte |=SLI4_GENERIC_CONTEXT_VPI <<SLI4_ELS_CT_OFFSET ; + els->context_tag =cpu_to_le16 (params->vpi); + els->rid_dw =cpu_to_le32 (params->d_id &SLI4_ELS_RID ); + els->temporary_rpi =cpu_to_le16 (params->rpi); +if (params->s_id !=U32_MAX ) { + els->sid_dw |= +cpu_to_le32 (SLI4_ELS_SP | (params->s_id &SLI4_ELS_SID )); + } + +return EFC_SUCCESS ; +} + +int +sli_xmit_sequence64_wqe (struct sli4 *sli4,void *buf,struct efc_dma *payload, +struct sli_ct_params *params) +{ +struct sli4_xmit_sequence64_wqe *xmit = buf; + +memset (buf,0 , sli4->wqe_size); + +if (!payload || !payload->virt) { +efc_log_err (sli4,"bad parameter sgl=%p virt=%p\n" , + payload, payload ? payload->virt :NULL ); +return EFC_FAIL ; + } + +if (sli4->params.sgl_pre_registered) + xmit->dw10w0 |=cpu_to_le16 (SLI4_SEQ_WQE_DBDE ); +else + xmit->dw10w0 |=cpu_to_le16 (SLI4_SEQ_WQE_XBL ); + + xmit->bde.bde_type_buflen = +cpu_to_le32 ((SLI4_BDE_TYPE_VAL (64 )) | + (params->rsp_len &SLI4_BDE_LEN_MASK )); + xmit->bde.u.data.low = +cpu_to_le32 (lower_32_bits (payload->phys)); + xmit->bde.u.data.high = +cpu_to_le32 (upper_32_bits (payload->phys)); + xmit->sequence_payload_len =cpu_to_le32 (params->rsp_len); + + xmit->remote_n_port_id_dword |=cpu_to_le32 (params->d_id &0x00ffffff ); + + xmit->relative_offset =0 ; + +/* sequence initiative - this matches what is seen from +* FC switches in response to FCGS commands +*/ + xmit->dw5flags0 &= (~SLI4_SEQ_WQE_SI ); + xmit->dw5flags0 &= (~SLI4_SEQ_WQE_FT );/* force transmit */ + xmit->dw5flags0 &= (~SLI4_SEQ_WQE_XO );/* exchange responder */ + xmit->dw5flags0 |=SLI4_SEQ_WQE_LS ;/* last in seqence */ + xmit->df_ctl = params->df_ctl; + xmit->type = params->type; + xmit->r_ctl = params->r_ctl; + + xmit->xri_tag =cpu_to_le16 (params->xri); + xmit->context_tag =cpu_to_le16 (params->rpi); + + xmit->dw7flags0 &= ~SLI4_SEQ_WQE_DIF ; + xmit->dw7flags0 |= +SLI4_GENERIC_CONTEXT_RPI <<SLI4_SEQ_WQE_CT_SHIFT ; + xmit->dw7flags0 &= ~SLI4_SEQ_WQE_BS ; + + xmit->command =SLI4_WQE_XMIT_SEQUENCE64 ; + xmit->dw7flags1 |=SLI4_GENERIC_CLASS_CLASS_3 ; + xmit->dw7flags1 &= ~SLI4_SEQ_WQE_PU ; + xmit->timer = params->timeout; + + xmit->abort_tag =0 ; + xmit->request_tag =cpu_to_le16 (params->tag); + xmit->remote_xid =cpu_to_le16 (params->ox_id); + + xmit->dw10w0 |= +cpu_to_le16 (SLI4_ELS_REQUEST64_DIR_READ <<SLI4_SEQ_WQE_IOD_SHIFT ); + + xmit->cmd_type_wqec_byte |=SLI4_CMD_XMIT_SEQUENCE64_WQE ; + + xmit->dw10w0 |=cpu_to_le16 (2 <<SLI4_SEQ_WQE_LEN_LOC_SHIFT ); + + xmit->cq_id =cpu_to_le16 (0xFFFF ); + +return EFC_SUCCESS ; +} + +int +sli_requeue_xri_wqe (struct sli4 *sli4,void *buf,u16 xri,u16 tag,u16 cq_id) +{ +struct sli4_requeue_xri_wqe *requeue = buf; + +memset (buf,0 , sli4->wqe_size); + + requeue->command =SLI4_WQE_REQUEUE_XRI ; + requeue->xri_tag =cpu_to_le16 (xri); + requeue->request_tag =cpu_to_le16 (tag); + requeue->flags2 |=cpu_to_le16 (SLI4_REQU_XRI_WQE_XC ); + requeue->flags1 |=cpu_to_le16 (SLI4_REQU_XRI_WQE_QOSD ); + requeue->cq_id =cpu_to_le16 (cq_id); + requeue->cmd_type_wqec_byte =SLI4_CMD_REQUEUE_XRI_WQE ; +return EFC_SUCCESS ; +} + +int +sli_fc_process_link_attention (struct sli4 *sli4,void *acqe) +{ +struct sli4_link_attention *link_attn = acqe; +struct sli4_link_event event = {0 }; + +efc_log_info (sli4,"link=%d attn_type=%#x top=%#x speed=%#x pfault=%#x\n" , + link_attn->link_number, link_attn->attn_type, + link_attn->topology, link_attn->port_speed, + link_attn->port_fault); +efc_log_info (sli4,"shared_lnk_status=%#x logl_lnk_speed=%#x evttag=%#x\n" , + link_attn->shared_link_status, +le16_to_cpu (link_attn->logical_link_speed), +le32_to_cpu (link_attn->event_tag)); + +if (!sli4->link) +return EFC_FAIL ; + + event.medium =SLI4_LINK_MEDIUM_FC ; + +switch (link_attn->attn_type) { +case SLI4_LNK_ATTN_TYPE_LINK_UP : + event.status =SLI4_LINK_STATUS_UP ; +break ; +case SLI4_LNK_ATTN_TYPE_LINK_DOWN : + event.status =SLI4_LINK_STATUS_DOWN ; +break ; +case SLI4_LNK_ATTN_TYPE_NO_HARD_ALPA : +efc_log_info (sli4,"attn_type: no hard alpa\n" ); + event.status =SLI4_LINK_STATUS_NO_ALPA ; +break ; +default : +efc_log_info (sli4,"attn_type: unknown\n" ); +break ; + } + +switch (link_attn->event_type) { +case SLI4_EVENT_LINK_ATTENTION : +break ; +case SLI4_EVENT_SHARED_LINK_ATTENTION : +efc_log_info (sli4,"event_type: FC shared link event\n" ); +break ; +default : +efc_log_info (sli4,"event_type: unknown\n" ); +break ; + } + +switch (link_attn->topology) { +case SLI4_LNK_ATTN_P2P : + event.topology =SLI4_LINK_TOPO_NON_FC_AL ; +break ; +case SLI4_LNK_ATTN_FC_AL : + event.topology =SLI4_LINK_TOPO_FC_AL ; +break ; +case SLI4_LNK_ATTN_INTERNAL_LOOPBACK : +efc_log_info (sli4,"topology Internal loopback\n" ); + event.topology =SLI4_LINK_TOPO_LOOPBACK_INTERNAL ; +break ; +case SLI4_LNK_ATTN_SERDES_LOOPBACK : +efc_log_info (sli4,"topology serdes loopback\n" ); + event.topology =SLI4_LINK_TOPO_LOOPBACK_EXTERNAL ; +break ; +default : +efc_log_info (sli4,"topology: unknown\n" ); +break ; + } + + event.speed = link_attn->port_speed *1000 ; + + sli4->link (sli4->link_arg, (void *)&event); + +return EFC_SUCCESS ; +} + +int +sli_fc_cqe_parse (struct sli4 *sli4,struct sli4_queue *cq, +u8 *cqe,enum sli4_qentry *etype,u16 *r_id) +{ +u8 code = cqe[SLI4_CQE_CODE_OFFSET ]; +int rc; + +switch (code) { +case SLI4_CQE_CODE_WORK_REQUEST_COMPLETION : + { +struct sli4_fc_wcqe *wcqe = (void *)cqe; + + *etype =SLI4_QENTRY_WQ ; + *r_id =le16_to_cpu (wcqe->request_tag); + rc = wcqe->status; + +/* Flag errors except for FCP_RSP_FAILURE */ +if (rc && rc !=SLI4_FC_WCQE_STATUS_FCP_RSP_FAILURE ) { +efc_log_info (sli4,"WCQE: status=%#x hw_status=%#x tag=%#x\n" , + wcqe->status, wcqe->hw_status, +le16_to_cpu (wcqe->request_tag)); +efc_log_info (sli4,"w1=%#x w2=%#x xb=%d\n" , +le32_to_cpu (wcqe->wqe_specific_1), +le32_to_cpu (wcqe->wqe_specific_2), + (wcqe->flags &SLI4_WCQE_XB )); +efc_log_info (sli4," %08X %08X %08X %08X\n" , + ((u32 *)cqe)[0 ], + ((u32 *)cqe)[1 ], + ((u32 *)cqe)[2 ], + ((u32 *)cqe)[3 ]); + } + +break ; + } +case SLI4_CQE_CODE_RQ_ASYNC : + { +struct sli4_fc_async_rcqe *rcqe = (void *)cqe; + + *etype =SLI4_QENTRY_RQ ; + *r_id =le16_to_cpu (rcqe->fcfi_rq_id_word) &SLI4_RACQE_RQ_ID ; + rc = rcqe->status; +break ; + } +case SLI4_CQE_CODE_RQ_ASYNC_V1 : + { +struct sli4_fc_async_rcqe_v1 *rcqe = (void *)cqe; + + *etype =SLI4_QENTRY_RQ ; + *r_id =le16_to_cpu (rcqe->rq_id); + rc = rcqe->status; +break ; + } +case SLI4_CQE_CODE_OPTIMIZED_WRITE_CMD : + { +struct sli4_fc_optimized_write_cmd_cqe *optcqe = (void *)cqe; + + *etype =SLI4_QENTRY_OPT_WRITE_CMD ; + *r_id =le16_to_cpu (optcqe->rq_id); + rc = optcqe->status; +break ; + } +case SLI4_CQE_CODE_OPTIMIZED_WRITE_DATA : + { +struct sli4_fc_optimized_write_data_cqe *dcqe = (void *)cqe; + + *etype =SLI4_QENTRY_OPT_WRITE_DATA ; + *r_id =le16_to_cpu (dcqe->xri); + rc = dcqe->status; + +/* Flag errors */ +if (rc !=SLI4_FC_WCQE_STATUS_SUCCESS ) { +efc_log_info (sli4,"Optimized DATA CQE: status=%#x\n" , + dcqe->status); +efc_log_info (sli4,"hstat=%#x xri=%#x dpl=%#x w3=%#x xb=%d\n" , + dcqe->hw_status,le16_to_cpu (dcqe->xri), +le32_to_cpu (dcqe->total_data_placed), + ((u32 *)cqe)[3 ], + (dcqe->flags &SLI4_OCQE_XB )); + } +break ; + } +case SLI4_CQE_CODE_RQ_COALESCING : + { +struct sli4_fc_coalescing_rcqe *rcqe = (void *)cqe; + + *etype =SLI4_QENTRY_RQ ; + *r_id =le16_to_cpu (rcqe->rq_id); + rc = rcqe->status; +break ; + } +case SLI4_CQE_CODE_XRI_ABORTED : + { +struct sli4_fc_xri_aborted_cqe *xa = (void *)cqe; + + *etype =SLI4_QENTRY_XABT ; + *r_id =le16_to_cpu (xa->xri); + rc =EFC_SUCCESS ; +break ; + } +case SLI4_CQE_CODE_RELEASE_WQE : + { +struct sli4_fc_wqec *wqec = (void *)cqe; + + *etype =SLI4_QENTRY_WQ_RELEASE ; + *r_id =le16_to_cpu (wqec->wq_id); + rc =EFC_SUCCESS ; +break ; + } +default : +efc_log_info (sli4,"CQE completion code %d not handled\n" , + code); + *etype =SLI4_QENTRY_MAX ; + *r_id =U16_MAX ; + rc = -EINVAL ; + } + +return rc; +} + +u32 +sli_fc_response_length (struct sli4 *sli4,u8 *cqe) +{ +struct sli4_fc_wcqe *wcqe = (void *)cqe; + +return le32_to_cpu (wcqe->wqe_specific_1); +} + +u32 +sli_fc_io_length (struct sli4 *sli4,u8 *cqe) +{ +struct sli4_fc_wcqe *wcqe = (void *)cqe; + +return le32_to_cpu (wcqe->wqe_specific_1); +} + +int +sli_fc_els_did (struct sli4 *sli4,u8 *cqe,u32 *d_id) +{ +struct sli4_fc_wcqe *wcqe = (void *)cqe; + + *d_id =0 ; + +if (wcqe->status) +return EFC_FAIL ; + *d_id =le32_to_cpu (wcqe->wqe_specific_2) &0x00ffffff ; +return EFC_SUCCESS ; +} + +u32 +sli_fc_ext_status (struct sli4 *sli4,u8 *cqe) +{ +struct sli4_fc_wcqe *wcqe = (void *)cqe; +u32 mask; + +switch (wcqe->status) { +case SLI4_FC_WCQE_STATUS_FCP_RSP_FAILURE : + mask =U32_MAX ; +break ; +case SLI4_FC_WCQE_STATUS_LOCAL_REJECT : +case SLI4_FC_WCQE_STATUS_CMD_REJECT : + mask =0xff ; +break ; +case SLI4_FC_WCQE_STATUS_NPORT_RJT : +case SLI4_FC_WCQE_STATUS_FABRIC_RJT : +case SLI4_FC_WCQE_STATUS_NPORT_BSY : +case SLI4_FC_WCQE_STATUS_FABRIC_BSY : +case SLI4_FC_WCQE_STATUS_LS_RJT : + mask =U32_MAX ; +break ; +case SLI4_FC_WCQE_STATUS_DI_ERROR : + mask =U32_MAX ; +break ; +default : + mask =0 ; + } + +return le32_to_cpu (wcqe->wqe_specific_2) & mask; +} + +int +sli_fc_rqe_rqid_and_index (struct sli4 *sli4,u8 *cqe,u16 *rq_id,u32 *index) +{ +int rc =EFC_FAIL ; +u8 code =0 ; +u16 rq_element_index; + + *rq_id =0 ; + *index =U32_MAX ; + + code = cqe[SLI4_CQE_CODE_OFFSET ]; + +/* Retrieve the RQ index from the completion */ +if (code ==SLI4_CQE_CODE_RQ_ASYNC ) { +struct sli4_fc_async_rcqe *rcqe = (void *)cqe; + + *rq_id =le16_to_cpu (rcqe->fcfi_rq_id_word) &SLI4_RACQE_RQ_ID ; + rq_element_index = +le16_to_cpu (rcqe->rq_elmt_indx_word) &SLI4_RACQE_RQ_EL_INDX ; + *index = rq_element_index; +if (rcqe->status ==SLI4_FC_ASYNC_RQ_SUCCESS ) { + rc =EFC_SUCCESS ; + }else { + rc = rcqe->status; +efc_log_info (sli4,"status=%02x (%s) rq_id=%d\n" , + rcqe->status, +sli_fc_get_status_string (rcqe->status), +le16_to_cpu (rcqe->fcfi_rq_id_word) & +SLI4_RACQE_RQ_ID ); + +efc_log_info (sli4,"pdpl=%x sof=%02x eof=%02x hdpl=%x\n" , +le16_to_cpu (rcqe->data_placement_length), + rcqe->sof_byte, rcqe->eof_byte, + rcqe->hdpl_byte &SLI4_RACQE_HDPL ); + } + }else if (code ==SLI4_CQE_CODE_RQ_ASYNC_V1 ) { +struct sli4_fc_async_rcqe_v1 *rcqe_v1 = (void *)cqe; + + *rq_id =le16_to_cpu (rcqe_v1->rq_id); + rq_element_index = + (le16_to_cpu (rcqe_v1->rq_elmt_indx_word) & +SLI4_RACQE_RQ_EL_INDX ); + *index = rq_element_index; +if (rcqe_v1->status ==SLI4_FC_ASYNC_RQ_SUCCESS ) { + rc =EFC_SUCCESS ; + }else { + rc = rcqe_v1->status; +efc_log_info (sli4,"status=%02x (%s) rq_id=%d, index=%x\n" , + rcqe_v1->status, +sli_fc_get_status_string (rcqe_v1->status), +le16_to_cpu (rcqe_v1->rq_id), rq_element_index); + +efc_log_info (sli4,"pdpl=%x sof=%02x eof=%02x hdpl=%x\n" , +le16_to_cpu (rcqe_v1->data_placement_length), + rcqe_v1->sof_byte, rcqe_v1->eof_byte, + rcqe_v1->hdpl_byte &SLI4_RACQE_HDPL ); + } + }else if (code ==SLI4_CQE_CODE_OPTIMIZED_WRITE_CMD ) { +struct sli4_fc_optimized_write_cmd_cqe *optcqe = (void *)cqe; + + *rq_id =le16_to_cpu (optcqe->rq_id); + *index =le16_to_cpu (optcqe->w1) &SLI4_OCQE_RQ_EL_INDX ; +if (optcqe->status ==SLI4_FC_ASYNC_RQ_SUCCESS ) { + rc =EFC_SUCCESS ; + }else { + rc = optcqe->status; +efc_log_info (sli4,"stat=%02x (%s) rqid=%d, idx=%x pdpl=%x\n" , + optcqe->status, +sli_fc_get_status_string (optcqe->status), +le16_to_cpu (optcqe->rq_id), *index, +le16_to_cpu (optcqe->data_placement_length)); + +efc_log_info (sli4,"hdpl=%x oox=%d agxr=%d xri=0x%x rpi=%x\n" , + (optcqe->hdpl_vld &SLI4_OCQE_HDPL ), + (optcqe->flags1 &SLI4_OCQE_OOX ), + (optcqe->flags1 &SLI4_OCQE_AGXR ), optcqe->xri, +le16_to_cpu (optcqe->rpi)); + } + }else if (code ==SLI4_CQE_CODE_RQ_COALESCING ) { +struct sli4_fc_coalescing_rcqe *rcqe = (void *)cqe; + + rq_element_index = (le16_to_cpu (rcqe->rq_elmt_indx_word) & +SLI4_RCQE_RQ_EL_INDX ); + + *rq_id =le16_to_cpu (rcqe->rq_id); +if (rcqe->status ==SLI4_FC_COALESCE_RQ_SUCCESS ) { + *index = rq_element_index; + rc =EFC_SUCCESS ; + }else { + *index =U32_MAX ; + rc = rcqe->status; + +efc_log_info (sli4,"stat=%02x (%s) rq_id=%d, idx=%x\n" , + rcqe->status, +sli_fc_get_status_string (rcqe->status), +le16_to_cpu (rcqe->rq_id), rq_element_index); +efc_log_info (sli4,"rq_id=%#x sdpl=%x\n" , +le16_to_cpu (rcqe->rq_id), +le16_to_cpu (rcqe->sequence_reporting_placement_length)); + } + }else { +struct sli4_fc_async_rcqe *rcqe = (void *)cqe; + + *index =U32_MAX ; + rc = rcqe->status; + +efc_log_info (sli4,"status=%02x rq_id=%d, index=%x pdpl=%x\n" , + rcqe->status, +le16_to_cpu (rcqe->fcfi_rq_id_word) &SLI4_RACQE_RQ_ID , + (le16_to_cpu (rcqe->rq_elmt_indx_word) &SLI4_RACQE_RQ_EL_INDX ), +le16_to_cpu (rcqe->data_placement_length)); +efc_log_info (sli4,"sof=%02x eof=%02x hdpl=%x\n" , + rcqe->sof_byte, rcqe->eof_byte, + rcqe->hdpl_byte &SLI4_RACQE_HDPL ); + } + +return rc; +}
Signature · 1 line
2.26.2
PATCH v8 6/31 elx: libefc_sli: bmbx routines and SLI config commands
In reply to James SmartThis patch continues the libefc_sli SLI-4 library population.
This patch adds routines to create mailbox commands used during adapter initialization and adds APIs to issue mailbox commands to the adapter through the bootstrap mailbox register.
--- drivers/scsi/elx/libefc_sli/sli4.c | 1166 ++++++++++++++++++++++++++++ 1 file changed, 1166 insertions(+)
drivers/scsi/elx/libefc_sli/sli4.c +1166 -0
@@ -2867,3 +2867,1169 @@ sli_fc_rqe_rqid_and_index(struct sli4 *sli4, u8 *cqe, u16 *rq_id, u32 *index)return rc; } + +static int +sli_bmbx_wait (struct sli4 *sli4,u32 msec) +{ +u32 val; +unsigned long end; + +/* Wait for the bootstrap mailbox to report "ready" */ + end = jiffies +msecs_to_jiffies (msec); +do { + val =readl (sli4->reg[0 ] +SLI4_BMBX_REG ); +if (val &SLI4_BMBX_RDY ) +return EFC_SUCCESS ; + +usleep_range (1000 ,2000 ); + }while (time_before (jiffies, end)); + +return EFC_FAIL ; +} + +static int +sli_bmbx_write (struct sli4 *sli4) +{ +u32 val; + +/* write buffer location to bootstrap mailbox register */ + val =sli_bmbx_write_hi (sli4->bmbx.phys); +writel (val, (sli4->reg[0 ] +SLI4_BMBX_REG )); + +if (sli_bmbx_wait (sli4,SLI4_BMBX_DELAY_US )) { +efc_log_crit (sli4,"BMBX WRITE_HI failed\n" ); +return EFC_FAIL ; + } + val =sli_bmbx_write_lo (sli4->bmbx.phys); +writel (val, (sli4->reg[0 ] +SLI4_BMBX_REG )); + +/* wait for SLI Port to set ready bit */ +return sli_bmbx_wait (sli4,SLI4_BMBX_TIMEOUT_MSEC ); +} + +int +sli_bmbx_command (struct sli4 *sli4) +{ +void *cqe = (u8 *)sli4->bmbx.virt +SLI4_BMBX_SIZE ; + +if (sli_fw_error_status (sli4) >0 ) { +efc_log_crit (sli4,"Chip is in an error state -Mailbox command rejected" ); +efc_log_crit (sli4," status=%#x error1=%#x error2=%#x\n" , +sli_reg_read_status (sli4), +sli_reg_read_err1 (sli4), +sli_reg_read_err2 (sli4)); +return EFC_FAIL ; + } + +/* Submit a command to the bootstrap mailbox and check the status */ +if (sli_bmbx_write (sli4)) { +efc_log_crit (sli4,"bmbx write fail phys=%pad reg=%#x\n" , + &sli4->bmbx.phys,readl (sli4->reg[0 ] +SLI4_BMBX_REG )); +return EFC_FAIL ; + } + +/* check completion queue entry status */ +if (le32_to_cpu (((struct sli4_mcqe *)cqe)->dw3_flags) & +SLI4_MCQE_VALID ) { +return sli_cqe_mq (sli4, cqe); + } +efc_log_crit (sli4,"invalid or wrong type\n" ); +return EFC_FAIL ; +} + +int +sli_cmd_config_link (struct sli4 *sli4,void *buf) +{ +struct sli4_cmd_config_link *config_link = buf; + +memset (buf,0 ,SLI4_BMBX_SIZE ); + + config_link->hdr.command =SLI4_MBX_CMD_CONFIG_LINK ; + +/* Port interprets zero in a field as "use default value" */ + +return EFC_SUCCESS ; +} + +int +sli_cmd_down_link (struct sli4 *sli4,void *buf) +{ +struct sli4_mbox_command_header *hdr = buf; + +memset (buf,0 ,SLI4_BMBX_SIZE ); + + hdr->command =SLI4_MBX_CMD_DOWN_LINK ; + +/* Port interprets zero in a field as "use default value" */ + +return EFC_SUCCESS ; +} + +int +sli_cmd_dump_type4 (struct sli4 *sli4,void *buf,u16 wki) +{ +struct sli4_cmd_dump4 *cmd = buf; + +memset (buf,0 ,SLI4_BMBX_SIZE ); + + cmd->hdr.command =SLI4_MBX_CMD_DUMP ; + cmd->type_dword =cpu_to_le32 (0x4 ); + cmd->wki_selection =cpu_to_le16 (wki); +return EFC_SUCCESS ; +} + +int +sli_cmd_common_read_transceiver_data (struct sli4 *sli4,void *buf,u32 page_num, +struct efc_dma *dma) +{ +struct sli4_rqst_cmn_read_transceiver_data *req =NULL ; +u32 psize; + +if (!dma) + psize =SLI4_CFG_PYLD_LENGTH (cmn_read_transceiver_data); +else + psize = dma->size; + + req =sli_config_cmd_init (sli4, buf, psize, dma); +if (!req) +return EFC_FAIL ; + +sli_cmd_fill_hdr (&req->hdr,SLI4_CMN_READ_TRANS_DATA , +SLI4_SUBSYSTEM_COMMON ,CMD_V0 , +SLI4_RQST_PYLD_LEN (cmn_read_transceiver_data)); + + req->page_number =cpu_to_le32 (page_num); + req->port =cpu_to_le32 (sli4->port_number); + +return EFC_SUCCESS ; +} + +int +sli_cmd_read_link_stats (struct sli4 *sli4,void *buf,u8 req_ext_counters, +u8 clear_overflow_flags, +u8 clear_all_counters) +{ +struct sli4_cmd_read_link_stats *cmd = buf; +u32 flags; + +memset (buf,0 ,SLI4_BMBX_SIZE ); + + cmd->hdr.command =SLI4_MBX_CMD_READ_LNK_STAT ; + + flags =0 ; +if (req_ext_counters) + flags |=SLI4_READ_LNKSTAT_REC ; +if (clear_all_counters) + flags |=SLI4_READ_LNKSTAT_CLRC ; +if (clear_overflow_flags) + flags |=SLI4_READ_LNKSTAT_CLOF ; + + cmd->dw1_flags =cpu_to_le32 (flags); +return EFC_SUCCESS ; +} + +int +sli_cmd_read_status (struct sli4 *sli4,void *buf,u8 clear_counters) +{ +struct sli4_cmd_read_status *cmd = buf; +u32 flags =0 ; + +memset (buf,0 ,SLI4_BMBX_SIZE ); + + cmd->hdr.command =SLI4_MBX_CMD_READ_STATUS ; +if (clear_counters) + flags |=SLI4_READSTATUS_CLEAR_COUNTERS ; +else + flags &= ~SLI4_READSTATUS_CLEAR_COUNTERS ; + + cmd->dw1_flags =cpu_to_le32 (flags); +return EFC_SUCCESS ; +} + +int +sli_cmd_init_link (struct sli4 *sli4,void *buf,u32 speed,u8 reset_alpa) +{ +struct sli4_cmd_init_link *init_link = buf; +u32 flags =0 ; + +memset (buf,0 ,SLI4_BMBX_SIZE ); + + init_link->hdr.command =SLI4_MBX_CMD_INIT_LINK ; + + init_link->sel_reset_al_pa_dword = +cpu_to_le32 (reset_alpa); + flags &= ~SLI4_INIT_LINK_F_LOOPBACK ; + + init_link->link_speed_sel_code =cpu_to_le32 (speed); +switch (speed) { +case SLI4_LINK_SPEED_1G : +case SLI4_LINK_SPEED_2G : +case SLI4_LINK_SPEED_4G : +case SLI4_LINK_SPEED_8G : +case SLI4_LINK_SPEED_16G : +case SLI4_LINK_SPEED_32G : +case SLI4_LINK_SPEED_64G : + flags |=SLI4_INIT_LINK_F_FIXED_SPEED ; +break ; +case SLI4_LINK_SPEED_10G : +efc_log_info (sli4,"unsupported FC speed %d\n" , speed); + init_link->flags0 =cpu_to_le32 (flags); +return EFC_FAIL ; + } + +switch (sli4->topology) { +case SLI4_READ_CFG_TOPO_FC : +/* Attempt P2P but failover to FC-AL */ + flags |=SLI4_INIT_LINK_F_FAIL_OVER ; + flags |=SLI4_INIT_LINK_F_P2P_FAIL_OVER ; +break ; +case SLI4_READ_CFG_TOPO_FC_AL : + flags |=SLI4_INIT_LINK_F_FCAL_ONLY ; +if (speed ==SLI4_LINK_SPEED_16G || + speed ==SLI4_LINK_SPEED_32G ) { +efc_log_info (sli4,"unsupported FC-AL speed %d\n" , + speed); + init_link->flags0 =cpu_to_le32 (flags); +return EFC_FAIL ; + } +break ; +case SLI4_READ_CFG_TOPO_NON_FC_AL : + flags |=SLI4_INIT_LINK_F_P2P_ONLY ; +break ; +default : + +efc_log_info (sli4,"unsupported topology %#x\n" , + sli4->topology); + + init_link->flags0 =cpu_to_le32 (flags); +return EFC_FAIL ; + } + + flags &= ~SLI4_INIT_LINK_F_UNFAIR ; + flags &= ~SLI4_INIT_LINK_F_NO_LIRP ; + flags &= ~SLI4_INIT_LINK_F_LOOP_VALID_CHK ; + flags &= ~SLI4_INIT_LINK_F_NO_LISA ; + flags &= ~SLI4_INIT_LINK_F_PICK_HI_ALPA ; + init_link->flags0 =cpu_to_le32 (flags); + +return EFC_SUCCESS ; +} + +int +sli_cmd_init_vfi (struct sli4 *sli4,void *buf,u16 vfi,u16 fcfi,u16 vpi) +{ +struct sli4_cmd_init_vfi *init_vfi = buf; +u16 flags =0 ; + +memset (buf,0 ,SLI4_BMBX_SIZE ); + + init_vfi->hdr.command =SLI4_MBX_CMD_INIT_VFI ; + init_vfi->vfi =cpu_to_le16 (vfi); + init_vfi->fcfi =cpu_to_le16 (fcfi); + +/* +* If the VPI is valid, initialize it at the same time as +* the VFI +*/ +if (vpi !=U16_MAX ) { + flags |=SLI4_INIT_VFI_FLAG_VP ; + init_vfi->flags0_word =cpu_to_le16 (flags); + init_vfi->vpi =cpu_to_le16 (vpi); + } + +return EFC_SUCCESS ; +} + +int +sli_cmd_init_vpi (struct sli4 *sli4,void *buf,u16 vpi,u16 vfi) +{ +struct sli4_cmd_init_vpi *init_vpi = buf; + +memset (buf,0 ,SLI4_BMBX_SIZE ); + + init_vpi->hdr.command =SLI4_MBX_CMD_INIT_VPI ; + init_vpi->vpi =cpu_to_le16 (vpi); + init_vpi->vfi =cpu_to_le16 (vfi); + +return EFC_SUCCESS ; +} + +int +sli_cmd_post_xri (struct sli4 *sli4,void *buf,u16 xri_base,u16 xri_count) +{ +struct sli4_cmd_post_xri *post_xri = buf; +u16 xri_count_flags =0 ; + +memset (buf,0 ,SLI4_BMBX_SIZE ); + + post_xri->hdr.command =SLI4_MBX_CMD_POST_XRI ; + post_xri->xri_base =cpu_to_le16 (xri_base); + xri_count_flags = xri_count &SLI4_POST_XRI_COUNT ; + xri_count_flags |=SLI4_POST_XRI_FLAG_ENX ; + xri_count_flags |=SLI4_POST_XRI_FLAG_VAL ; + post_xri->xri_count_flags =cpu_to_le16 (xri_count_flags); + +return EFC_SUCCESS ; +} + +int +sli_cmd_release_xri (struct sli4 *sli4,void *buf,u8 num_xri) +{ +struct sli4_cmd_release_xri *release_xri = buf; + +memset (buf,0 ,SLI4_BMBX_SIZE ); + + release_xri->hdr.command =SLI4_MBX_CMD_RELEASE_XRI ; + release_xri->xri_count_word =cpu_to_le16 (num_xri & +SLI4_RELEASE_XRI_COUNT ); + +return EFC_SUCCESS ; +} + +static int +sli_cmd_read_config (struct sli4 *sli4,void *buf) +{ +struct sli4_cmd_read_config *read_config = buf; + +memset (buf,0 ,SLI4_BMBX_SIZE ); + + read_config->hdr.command =SLI4_MBX_CMD_READ_CONFIG ; + +return EFC_SUCCESS ; +} + +int +sli_cmd_read_nvparms (struct sli4 *sli4,void *buf) +{ +struct sli4_cmd_read_nvparms *read_nvparms = buf; + +memset (buf,0 ,SLI4_BMBX_SIZE ); + + read_nvparms->hdr.command =SLI4_MBX_CMD_READ_NVPARMS ; + +return EFC_SUCCESS ; +} + +int +sli_cmd_write_nvparms (struct sli4 *sli4,void *buf,u8 *wwpn,u8 *wwnn, +u8 hard_alpa,u32 preferred_d_id) +{ +struct sli4_cmd_write_nvparms *write_nvparms = buf; + +memset (buf,0 ,SLI4_BMBX_SIZE ); + + write_nvparms->hdr.command =SLI4_MBX_CMD_WRITE_NVPARMS ; +memcpy (write_nvparms->wwpn, wwpn,8 ); +memcpy (write_nvparms->wwnn, wwnn,8 ); + + write_nvparms->hard_alpa_d_id = +cpu_to_le32 ((preferred_d_id <<8 ) | hard_alpa); +return EFC_SUCCESS ; +} + +static int +sli_cmd_read_rev (struct sli4 *sli4,void *buf,struct efc_dma *vpd) +{ +struct sli4_cmd_read_rev *read_rev = buf; + +memset (buf,0 ,SLI4_BMBX_SIZE ); + + read_rev->hdr.command =SLI4_MBX_CMD_READ_REV ; + +if (vpd && vpd->size) { + read_rev->flags0_word |=cpu_to_le16 (SLI4_READ_REV_FLAG_VPD ); + + read_rev->available_length_dword = +cpu_to_le32 (vpd->size & +SLI4_READ_REV_AVAILABLE_LENGTH ); + + read_rev->hostbuf.low = +cpu_to_le32 (lower_32_bits (vpd->phys)); + read_rev->hostbuf.high = +cpu_to_le32 (upper_32_bits (vpd->phys)); + } + +return EFC_SUCCESS ; +} + +int +sli_cmd_read_sparm64 (struct sli4 *sli4,void *buf,struct efc_dma *dma,u16 vpi) +{ +struct sli4_cmd_read_sparm64 *read_sparm64 = buf; + +if (vpi ==U16_MAX ) { +efc_log_err (sli4,"special VPI not supported!!!\n" ); +return EFC_FAIL ; + } + +if (!dma || !dma->phys) { +efc_log_err (sli4,"bad DMA buffer\n" ); +return EFC_FAIL ; + } + +memset (buf,0 ,SLI4_BMBX_SIZE ); + + read_sparm64->hdr.command =SLI4_MBX_CMD_READ_SPARM64 ; + + read_sparm64->bde_64.bde_type_buflen = +cpu_to_le32 ((SLI4_BDE_TYPE_VAL (64 )) | + (dma->size &SLI4_BDE_LEN_MASK )); + read_sparm64->bde_64.u.data.low = +cpu_to_le32 (lower_32_bits (dma->phys)); + read_sparm64->bde_64.u.data.high = +cpu_to_le32 (upper_32_bits (dma->phys)); + + read_sparm64->vpi =cpu_to_le16 (vpi); + +return EFC_SUCCESS ; +} + +int +sli_cmd_read_topology (struct sli4 *sli4,void *buf,struct efc_dma *dma) +{ +struct sli4_cmd_read_topology *read_topo = buf; + +if (!dma || !dma->size) +return EFC_FAIL ; + +if (dma->size <SLI4_MIN_LOOP_MAP_BYTES ) { +efc_log_err (sli4,"loop map buffer too small %zx\n" , dma->size); +return EFC_FAIL ; + } + +memset (buf,0 ,SLI4_BMBX_SIZE ); + + read_topo->hdr.command =SLI4_MBX_CMD_READ_TOPOLOGY ; + +memset (dma->virt,0 , dma->size); + + read_topo->bde_loop_map.bde_type_buflen = +cpu_to_le32 ((SLI4_BDE_TYPE_VAL (64 )) | + (dma->size &SLI4_BDE_LEN_MASK )); + read_topo->bde_loop_map.u.data.low = +cpu_to_le32 (lower_32_bits (dma->phys)); + read_topo->bde_loop_map.u.data.high = +cpu_to_le32 (upper_32_bits (dma->phys)); + +return EFC_SUCCESS ; +} + +int +sli_cmd_reg_fcfi (struct sli4 *sli4,void *buf,u16 index, +struct sli4_cmd_rq_cfg *rq_cfg) +{ +struct sli4_cmd_reg_fcfi *reg_fcfi = buf; +u32 i; + +memset (buf,0 ,SLI4_BMBX_SIZE ); + + reg_fcfi->hdr.command =SLI4_MBX_CMD_REG_FCFI ; + + reg_fcfi->fcf_index =cpu_to_le16 (index); + +for (i =0 ; i <SLI4_CMD_REG_FCFI_NUM_RQ_CFG ; i++) { +switch (i) { +case 0 : + reg_fcfi->rqid0 = rq_cfg[0 ].rq_id; +break ; +case 1 : + reg_fcfi->rqid1 = rq_cfg[1 ].rq_id; +break ; +case 2 : + reg_fcfi->rqid2 = rq_cfg[2 ].rq_id; +break ; +case 3 : + reg_fcfi->rqid3 = rq_cfg[3 ].rq_id; +break ; + } + reg_fcfi->rq_cfg[i].r_ctl_mask = rq_cfg[i].r_ctl_mask; + reg_fcfi->rq_cfg[i].r_ctl_match = rq_cfg[i].r_ctl_match; + reg_fcfi->rq_cfg[i].type_mask = rq_cfg[i].type_mask; + reg_fcfi->rq_cfg[i].type_match = rq_cfg[i].type_match; + } + +return EFC_SUCCESS ; +} + +int +sli_cmd_reg_fcfi_mrq (struct sli4 *sli4,void *buf,u8 mode,u16 fcf_index, +u8 rq_selection_policy,u8 mrq_bit_mask,u16 num_mrqs, +struct sli4_cmd_rq_cfg *rq_cfg) +{ +struct sli4_cmd_reg_fcfi_mrq *reg_fcfi_mrq = buf; +u32 i; +u32 mrq_flags =0 ; + +memset (buf,0 ,SLI4_BMBX_SIZE ); + + reg_fcfi_mrq->hdr.command =SLI4_MBX_CMD_REG_FCFI_MRQ ; +if (mode ==SLI4_CMD_REG_FCFI_SET_FCFI_MODE ) { + reg_fcfi_mrq->fcf_index =cpu_to_le16 (fcf_index); + goto done; + } + + reg_fcfi_mrq->dw8_vlan =cpu_to_le32 (SLI4_REGFCFI_MRQ_MODE ); + +for (i =0 ; i <SLI4_CMD_REG_FCFI_NUM_RQ_CFG ; i++) { + reg_fcfi_mrq->rq_cfg[i].r_ctl_mask = rq_cfg[i].r_ctl_mask; + reg_fcfi_mrq->rq_cfg[i].r_ctl_match = rq_cfg[i].r_ctl_match; + reg_fcfi_mrq->rq_cfg[i].type_mask = rq_cfg[i].type_mask; + reg_fcfi_mrq->rq_cfg[i].type_match = rq_cfg[i].type_match; + +switch (i) { +case 3 : + reg_fcfi_mrq->rqid3 = rq_cfg[i].rq_id; +break ; +case 2 : + reg_fcfi_mrq->rqid2 = rq_cfg[i].rq_id; +break ; +case 1 : + reg_fcfi_mrq->rqid1 = rq_cfg[i].rq_id; +break ; +case 0 : + reg_fcfi_mrq->rqid0 = rq_cfg[i].rq_id; +break ; + } + } + + mrq_flags = num_mrqs &SLI4_REGFCFI_MRQ_MASK_NUM_PAIRS ; + mrq_flags |= (mrq_bit_mask <<8 ); + mrq_flags |= (rq_selection_policy <<12 ); + reg_fcfi_mrq->dw9_mrqflags =cpu_to_le32 (mrq_flags); +done: +return EFC_SUCCESS ; +} + +int +sli_cmd_reg_rpi (struct sli4 *sli4,void *buf,u32 rpi,u32 vpi,u32 fc_id, +struct efc_dma *dma,u8 update,u8 enable_t10_pi) +{ +struct sli4_cmd_reg_rpi *reg_rpi = buf; +u32 rportid_flags =0 ; + +memset (buf,0 ,SLI4_BMBX_SIZE ); + + reg_rpi->hdr.command =SLI4_MBX_CMD_REG_RPI ; + + reg_rpi->rpi =cpu_to_le16 (rpi); + + rportid_flags = fc_id &SLI4_REGRPI_REMOTE_N_PORTID ; + +if (update) + rportid_flags |=SLI4_REGRPI_UPD ; +else + rportid_flags &= ~SLI4_REGRPI_UPD ; + +if (enable_t10_pi) + rportid_flags |=SLI4_REGRPI_ETOW ; +else + rportid_flags &= ~SLI4_REGRPI_ETOW ; + + reg_rpi->dw2_rportid_flags =cpu_to_le32 (rportid_flags); + + reg_rpi->bde_64.bde_type_buflen = +cpu_to_le32 ((SLI4_BDE_TYPE_VAL (64 )) | + (SLI4_REG_RPI_BUF_LEN &SLI4_BDE_LEN_MASK )); + reg_rpi->bde_64.u.data.low = +cpu_to_le32 (lower_32_bits (dma->phys)); + reg_rpi->bde_64.u.data.high = +cpu_to_le32 (upper_32_bits (dma->phys)); + + reg_rpi->vpi =cpu_to_le16 (vpi); + +return EFC_SUCCESS ; +} + +int +sli_cmd_reg_vfi (struct sli4 *sli4,void *buf,size_t size, +u16 vfi,u16 fcfi,struct efc_dma dma, +u16 vpi,__be64 sli_wwpn,u32 fc_id) +{ +struct sli4_cmd_reg_vfi *reg_vfi = buf; + +memset (buf,0 ,SLI4_BMBX_SIZE ); + + reg_vfi->hdr.command =SLI4_MBX_CMD_REG_VFI ; + + reg_vfi->vfi =cpu_to_le16 (vfi); + + reg_vfi->fcfi =cpu_to_le16 (fcfi); + + reg_vfi->sparm.bde_type_buflen = +cpu_to_le32 ((SLI4_BDE_TYPE_VAL (64 )) | + (SLI4_REG_RPI_BUF_LEN &SLI4_BDE_LEN_MASK )); + reg_vfi->sparm.u.data.low = +cpu_to_le32 (lower_32_bits (dma.phys)); + reg_vfi->sparm.u.data.high = +cpu_to_le32 (upper_32_bits (dma.phys)); + + reg_vfi->e_d_tov =cpu_to_le32 (sli4->e_d_tov); + reg_vfi->r_a_tov =cpu_to_le32 (sli4->r_a_tov); + + reg_vfi->dw0w1_flags |=cpu_to_le16 (SLI4_REGVFI_VP ); + reg_vfi->vpi =cpu_to_le16 (vpi); +memcpy (reg_vfi->wwpn, &sli_wwpn,sizeof (reg_vfi->wwpn)); + reg_vfi->dw10_lportid_flags =cpu_to_le32 (fc_id); + +return EFC_SUCCESS ; +} + +int +sli_cmd_reg_vpi (struct sli4 *sli4,void *buf,u32 fc_id,__be64 sli_wwpn, +u16 vpi,u16 vfi,bool update) +{ +struct sli4_cmd_reg_vpi *reg_vpi = buf; +u32 flags =0 ; + +memset (buf,0 ,SLI4_BMBX_SIZE ); + + reg_vpi->hdr.command =SLI4_MBX_CMD_REG_VPI ; + + flags = (fc_id &SLI4_REGVPI_LOCAL_N_PORTID ); +if (update) + flags |=SLI4_REGVPI_UPD ; +else + flags &= ~SLI4_REGVPI_UPD ; + + reg_vpi->dw2_lportid_flags =cpu_to_le32 (flags); +memcpy (reg_vpi->wwpn, &sli_wwpn,sizeof (reg_vpi->wwpn)); + reg_vpi->vpi =cpu_to_le16 (vpi); + reg_vpi->vfi =cpu_to_le16 (vfi); + +return EFC_SUCCESS ; +} + +static int +sli_cmd_request_features (struct sli4 *sli4,void *buf,u32 features_mask, +bool query) +{ +struct sli4_cmd_request_features *req_features = buf; + +memset (buf,0 ,SLI4_BMBX_SIZE ); + + req_features->hdr.command =SLI4_MBX_CMD_RQST_FEATURES ; + +if (query) + req_features->dw1_qry =cpu_to_le32 (SLI4_REQFEAT_QRY ); + + req_features->cmd =cpu_to_le32 (features_mask); + +return EFC_SUCCESS ; +} + +int +sli_cmd_unreg_fcfi (struct sli4 *sli4,void *buf,u16 indicator) +{ +struct sli4_cmd_unreg_fcfi *unreg_fcfi = buf; + +memset (buf,0 ,SLI4_BMBX_SIZE ); + + unreg_fcfi->hdr.command =SLI4_MBX_CMD_UNREG_FCFI ; + unreg_fcfi->fcfi =cpu_to_le16 (indicator); + +return EFC_SUCCESS ; +} + +int +sli_cmd_unreg_rpi (struct sli4 *sli4,void *buf,u16 indicator, +enum sli4_resource which,u32 fc_id) +{ +struct sli4_cmd_unreg_rpi *unreg_rpi = buf; +u32 flags =0 ; + +memset (buf,0 ,SLI4_BMBX_SIZE ); + + unreg_rpi->hdr.command =SLI4_MBX_CMD_UNREG_RPI ; +switch (which) { +case SLI4_RSRC_RPI : + flags |=SLI4_UNREG_RPI_II_RPI ; +if (fc_id ==U32_MAX ) +break ; + + flags |=SLI4_UNREG_RPI_DP ; + unreg_rpi->dw2_dest_n_portid = +cpu_to_le32 (fc_id &SLI4_UNREG_RPI_DEST_N_PORTID_MASK ); +break ; +case SLI4_RSRC_VPI : + flags |=SLI4_UNREG_RPI_II_VPI ; +break ; +case SLI4_RSRC_VFI : + flags |=SLI4_UNREG_RPI_II_VFI ; +break ; +case SLI4_RSRC_FCFI : + flags |=SLI4_UNREG_RPI_II_FCFI ; +break ; +default : +efc_log_info (sli4,"unknown type %#x\n" , which); +return EFC_FAIL ; + } + + unreg_rpi->dw1w1_flags =cpu_to_le16 (flags); + unreg_rpi->index =cpu_to_le16 (indicator); + +return EFC_SUCCESS ; +} + +int +sli_cmd_unreg_vfi (struct sli4 *sli4,void *buf,u16 index,u32 which) +{ +struct sli4_cmd_unreg_vfi *unreg_vfi = buf; + +memset (buf,0 ,SLI4_BMBX_SIZE ); + + unreg_vfi->hdr.command =SLI4_MBX_CMD_UNREG_VFI ; +switch (which) { +case SLI4_UNREG_TYPE_DOMAIN : + unreg_vfi->index =cpu_to_le16 (index); +break ; +case SLI4_UNREG_TYPE_FCF : + unreg_vfi->index =cpu_to_le16 (index); +break ; +case SLI4_UNREG_TYPE_ALL : + unreg_vfi->index =cpu_to_le16 (U32_MAX ); +break ; +default : +return EFC_FAIL ; + } + +if (which !=SLI4_UNREG_TYPE_DOMAIN ) + unreg_vfi->dw2_flags =cpu_to_le16 (SLI4_UNREG_VFI_II_FCFI ); + +return EFC_SUCCESS ; +} + +int +sli_cmd_unreg_vpi (struct sli4 *sli4,void *buf,u16 indicator,u32 which) +{ +struct sli4_cmd_unreg_vpi *unreg_vpi = buf; +u32 flags =0 ; + +memset (buf,0 ,SLI4_BMBX_SIZE ); + + unreg_vpi->hdr.command =SLI4_MBX_CMD_UNREG_VPI ; + unreg_vpi->index =cpu_to_le16 (indicator); +switch (which) { +case SLI4_UNREG_TYPE_PORT : + flags |=SLI4_UNREG_VPI_II_VPI ; +break ; +case SLI4_UNREG_TYPE_DOMAIN : + flags |=SLI4_UNREG_VPI_II_VFI ; +break ; +case SLI4_UNREG_TYPE_FCF : + flags |=SLI4_UNREG_VPI_II_FCFI ; +break ; +case SLI4_UNREG_TYPE_ALL : +/* override indicator */ + unreg_vpi->index =cpu_to_le16 (U32_MAX ); + flags |=SLI4_UNREG_VPI_II_FCFI ; +break ; +default : +return EFC_FAIL ; + } + + unreg_vpi->dw2w0_flags =cpu_to_le16 (flags); +return EFC_SUCCESS ; +} + +static int +sli_cmd_common_modify_eq_delay (struct sli4 *sli4,void *buf, +struct sli4_queue *q,int num_q,u32 shift, +u32 delay_mult) +{ +struct sli4_rqst_cmn_modify_eq_delay *req =NULL ; +int i; + + req =sli_config_cmd_init (sli4, buf, +SLI4_CFG_PYLD_LENGTH (cmn_modify_eq_delay),NULL ); +if (!req) +return EFC_FAIL ; + +sli_cmd_fill_hdr (&req->hdr,SLI4_CMN_MODIFY_EQ_DELAY , +SLI4_SUBSYSTEM_COMMON ,CMD_V0 , +SLI4_RQST_PYLD_LEN (cmn_modify_eq_delay)); + req->num_eq =cpu_to_le32 (num_q); + +for (i =0 ; i < num_q; i++) { + req->eq_delay_record[i].eq_id =cpu_to_le32 (q[i].id); + req->eq_delay_record[i].phase =cpu_to_le32 (shift); + req->eq_delay_record[i].delay_multiplier = +cpu_to_le32 (delay_mult); + } + +return EFC_SUCCESS ; +} + +void +sli4_cmd_lowlevel_set_watchdog (struct sli4 *sli4,void *buf, +size_t size,u16 timeout) +{ +struct sli4_rqst_lowlevel_set_watchdog *req =NULL ; + + req =sli_config_cmd_init (sli4, buf, +SLI4_CFG_PYLD_LENGTH (lowlevel_set_watchdog),NULL ); +if (!req) +return ; + +sli_cmd_fill_hdr (&req->hdr,SLI4_OPC_LOWLEVEL_SET_WATCHDOG , +SLI4_SUBSYSTEM_LOWLEVEL ,CMD_V0 , +SLI4_RQST_PYLD_LEN (lowlevel_set_watchdog)); + req->watchdog_timeout =cpu_to_le16 (timeout); +} + +static int +sli_cmd_common_get_cntl_attributes (struct sli4 *sli4,void *buf, +struct efc_dma *dma) +{ +struct sli4_rqst_hdr *hdr =NULL ; + + hdr =sli_config_cmd_init (sli4, buf,SLI4_RQST_CMDSZ (hdr), dma); +if (!hdr) +return EFC_FAIL ; + + hdr->opcode =SLI4_CMN_GET_CNTL_ATTRIBUTES ; + hdr->subsystem =SLI4_SUBSYSTEM_COMMON ; + hdr->request_length =cpu_to_le32 (dma->size); + +return EFC_SUCCESS ; +} + +static int +sli_cmd_common_get_cntl_addl_attributes (struct sli4 *sli4,void *buf, +struct efc_dma *dma) +{ +struct sli4_rqst_hdr *hdr =NULL ; + + hdr =sli_config_cmd_init (sli4, buf,SLI4_RQST_CMDSZ (hdr), dma); +if (!hdr) +return EFC_FAIL ; + + hdr->opcode =SLI4_CMN_GET_CNTL_ADDL_ATTRS ; + hdr->subsystem =SLI4_SUBSYSTEM_COMMON ; + hdr->request_length =cpu_to_le32 (dma->size); + +return EFC_SUCCESS ; +} + +int +sli_cmd_common_nop (struct sli4 *sli4,void *buf,uint64_t context) +{ +struct sli4_rqst_cmn_nop *nop =NULL ; + + nop =sli_config_cmd_init (sli4, buf,SLI4_CFG_PYLD_LENGTH (cmn_nop), +NULL ); +if (!nop) +return EFC_FAIL ; + +sli_cmd_fill_hdr (&nop->hdr,SLI4_CMN_NOP ,SLI4_SUBSYSTEM_COMMON , +CMD_V0 ,SLI4_RQST_PYLD_LEN (cmn_nop)); + +memcpy (&nop->context, &context,sizeof (context)); + +return EFC_SUCCESS ; +} + +int +sli_cmd_common_get_resource_extent_info (struct sli4 *sli4,void *buf,u16 rtype) +{ +struct sli4_rqst_cmn_get_resource_extent_info *ext =NULL ; + + ext =sli_config_cmd_init (sli4, buf, +SLI4_RQST_CMDSZ (cmn_get_resource_extent_info),NULL ); +if (!ext) +return EFC_FAIL ; + +sli_cmd_fill_hdr (&ext->hdr,SLI4_CMN_GET_RSC_EXTENT_INFO , +SLI4_SUBSYSTEM_COMMON ,CMD_V0 , +SLI4_RQST_PYLD_LEN (cmn_get_resource_extent_info)); + + ext->resource_type =cpu_to_le16 (rtype); + +return EFC_SUCCESS ; +} + +int +sli_cmd_common_get_sli4_parameters (struct sli4 *sli4,void *buf) +{ +struct sli4_rqst_hdr *hdr =NULL ; + + hdr =sli_config_cmd_init (sli4, buf, +SLI4_CFG_PYLD_LENGTH (cmn_get_sli4_params),NULL ); +if (!hdr) +return EFC_FAIL ; + + hdr->opcode =SLI4_CMN_GET_SLI4_PARAMS ; + hdr->subsystem =SLI4_SUBSYSTEM_COMMON ; + hdr->request_length =SLI4_RQST_PYLD_LEN (cmn_get_sli4_params); + +return EFC_SUCCESS ; +} + +static int +sli_cmd_common_get_port_name (struct sli4 *sli4,void *buf) +{ +struct sli4_rqst_cmn_get_port_name *pname; + + pname =sli_config_cmd_init (sli4, buf, +SLI4_CFG_PYLD_LENGTH (cmn_get_port_name),NULL ); +if (!pname) +return EFC_FAIL ; + +sli_cmd_fill_hdr (&pname->hdr,SLI4_CMN_GET_PORT_NAME , +SLI4_SUBSYSTEM_COMMON ,CMD_V1 , +SLI4_RQST_PYLD_LEN (cmn_get_port_name)); + +/* Set the port type value (ethernet=0, FC=1) for V1 commands */ + pname->port_type =SLI4_PORT_TYPE_FC ; + +return EFC_SUCCESS ; +} + +int +sli_cmd_common_write_object (struct sli4 *sli4,void *buf,u16 noc, +u16 eof,u32 desired_write_length, +u32 offset,char *obj_name, +struct efc_dma *dma) +{ +struct sli4_rqst_cmn_write_object *wr_obj =NULL ; +struct sli4_bde *bde; +u32 dwflags =0 ; + + wr_obj =sli_config_cmd_init (sli4, buf, +SLI4_RQST_CMDSZ (cmn_write_object) +sizeof (*bde),NULL ); +if (!wr_obj) +return EFC_FAIL ; + +sli_cmd_fill_hdr (&wr_obj->hdr,SLI4_CMN_WRITE_OBJECT , +SLI4_SUBSYSTEM_COMMON ,CMD_V0 , +SLI4_RQST_PYLD_LEN_VAR (cmn_write_object,sizeof (*bde))); + +if (noc) + dwflags |=SLI4_RQ_DES_WRITE_LEN_NOC ; +if (eof) + dwflags |=SLI4_RQ_DES_WRITE_LEN_EOF ; + dwflags |= (desired_write_length &SLI4_RQ_DES_WRITE_LEN ); + + wr_obj->desired_write_len_dword =cpu_to_le32 (dwflags); + + wr_obj->write_offset =cpu_to_le32 (offset); +strncpy (wr_obj->object_name, obj_name,sizeof (wr_obj->object_name) -1 ); + wr_obj->host_buffer_descriptor_count =cpu_to_le32 (1 ); + + bde = (struct sli4_bde *)wr_obj->host_buffer_descriptor; + +/* Setup to transfer xfer_size bytes to device */ + bde->bde_type_buflen = +cpu_to_le32 ((SLI4_BDE_TYPE_VAL (64 )) | + (desired_write_length &SLI4_BDE_LEN_MASK )); + bde->u.data.low =cpu_to_le32 (lower_32_bits (dma->phys)); + bde->u.data.high =cpu_to_le32 (upper_32_bits (dma->phys)); + +return EFC_SUCCESS ; +} + +int +sli_cmd_common_delete_object (struct sli4 *sli4,void *buf,char *obj_name) +{ +struct sli4_rqst_cmn_delete_object *req =NULL ; + + req =sli_config_cmd_init (sli4, buf, +SLI4_RQST_CMDSZ (cmn_delete_object),NULL ); +if (!req) +return EFC_FAIL ; + +sli_cmd_fill_hdr (&req->hdr,SLI4_CMN_DELETE_OBJECT , +SLI4_SUBSYSTEM_COMMON ,CMD_V0 , +SLI4_RQST_PYLD_LEN (cmn_delete_object)); + +strncpy (req->object_name, obj_name,sizeof (req->object_name) -1 ); +return EFC_SUCCESS ; +} + +int +sli_cmd_common_read_object (struct sli4 *sli4,void *buf,u32 desired_read_len, +u32 offset,char *obj_name,struct efc_dma *dma) +{ +struct sli4_rqst_cmn_read_object *rd_obj =NULL ; +struct sli4_bde *bde; + + rd_obj =sli_config_cmd_init (sli4, buf, +SLI4_RQST_CMDSZ (cmn_read_object) +sizeof (*bde),NULL ); +if (!rd_obj) +return EFC_FAIL ; + +sli_cmd_fill_hdr (&rd_obj->hdr,SLI4_CMN_READ_OBJECT , +SLI4_SUBSYSTEM_COMMON ,CMD_V0 , +SLI4_RQST_PYLD_LEN_VAR (cmn_read_object,sizeof (*bde))); + rd_obj->desired_read_length_dword = +cpu_to_le32 (desired_read_len &SLI4_REQ_DESIRE_READLEN ); + + rd_obj->read_offset =cpu_to_le32 (offset); +strncpy (rd_obj->object_name, obj_name,sizeof (rd_obj->object_name) -1 ); + rd_obj->host_buffer_descriptor_count =cpu_to_le32 (1 ); + + bde = (struct sli4_bde *)rd_obj->host_buffer_descriptor; + +/* Setup to transfer xfer_size bytes to device */ + bde->bde_type_buflen = +cpu_to_le32 ((SLI4_BDE_TYPE_VAL (64 )) | + (desired_read_len &SLI4_BDE_LEN_MASK )); +if (dma) { + bde->u.data.low =cpu_to_le32 (lower_32_bits (dma->phys)); + bde->u.data.high =cpu_to_le32 (upper_32_bits (dma->phys)); + }else { + bde->u.data.low =0 ; + bde->u.data.high =0 ; + } + +return EFC_SUCCESS ; +} + +int +sli_cmd_dmtf_exec_clp_cmd (struct sli4 *sli4,void *buf,struct efc_dma *cmd, +struct efc_dma *resp) +{ +struct sli4_rqst_dmtf_exec_clp_cmd *clp_cmd =NULL ; + + clp_cmd =sli_config_cmd_init (sli4, buf, +SLI4_RQST_CMDSZ (dmtf_exec_clp_cmd),NULL ); +if (!clp_cmd) +return EFC_FAIL ; + +sli_cmd_fill_hdr (&clp_cmd->hdr,DMTF_EXEC_CLP_CMD ,SLI4_SUBSYSTEM_DMTF , +CMD_V0 ,SLI4_RQST_PYLD_LEN (dmtf_exec_clp_cmd)); + + clp_cmd->cmd_buf_length =cpu_to_le32 (cmd->size); + clp_cmd->cmd_buf_addr_low =cpu_to_le32 (lower_32_bits (cmd->phys)); + clp_cmd->cmd_buf_addr_high =cpu_to_le32 (upper_32_bits (cmd->phys)); + clp_cmd->resp_buf_length =cpu_to_le32 (resp->size); + clp_cmd->resp_buf_addr_low =cpu_to_le32 (lower_32_bits (resp->phys)); + clp_cmd->resp_buf_addr_high =cpu_to_le32 (upper_32_bits (resp->phys)); +return EFC_SUCCESS ; +} + +int +sli_cmd_common_set_dump_location (struct sli4 *sli4,void *buf,bool query, +bool is_buffer_list, +struct efc_dma *buffer,u8 fdb) +{ +struct sli4_rqst_cmn_set_dump_location *set_dump_loc =NULL ; +u32 buffer_length_flag =0 ; + + set_dump_loc =sli_config_cmd_init (sli4, buf, +SLI4_RQST_CMDSZ (cmn_set_dump_location),NULL ); +if (!set_dump_loc) +return EFC_FAIL ; + +sli_cmd_fill_hdr (&set_dump_loc->hdr,SLI4_CMN_SET_DUMP_LOCATION , +SLI4_SUBSYSTEM_COMMON ,CMD_V0 , +SLI4_RQST_PYLD_LEN (cmn_set_dump_location)); + +if (is_buffer_list) + buffer_length_flag |=SLI4_CMN_SET_DUMP_BLP ; + +if (query) + buffer_length_flag |=SLI4_CMN_SET_DUMP_QRY ; + +if (fdb) + buffer_length_flag |=SLI4_CMN_SET_DUMP_FDB ; + +if (buffer) { + set_dump_loc->buf_addr_low = +cpu_to_le32 (lower_32_bits (buffer->phys)); + set_dump_loc->buf_addr_high = +cpu_to_le32 (upper_32_bits (buffer->phys)); + + buffer_length_flag |= + buffer->len &SLI4_CMN_SET_DUMP_BUFFER_LEN ; + }else { + set_dump_loc->buf_addr_low =0 ; + set_dump_loc->buf_addr_high =0 ; + set_dump_loc->buffer_length_dword =0 ; + } + set_dump_loc->buffer_length_dword =cpu_to_le32 (buffer_length_flag); +return EFC_SUCCESS ; +} + +int +sli_cmd_common_set_features (struct sli4 *sli4,void *buf,u32 feature, +u32 param_len,void *parameter) +{ +struct sli4_rqst_cmn_set_features *cmd =NULL ; + + cmd =sli_config_cmd_init (sli4, buf, +SLI4_RQST_CMDSZ (cmn_set_features),NULL ); +if (!cmd) +return EFC_FAIL ; + +sli_cmd_fill_hdr (&cmd->hdr,SLI4_CMN_SET_FEATURES , +SLI4_SUBSYSTEM_COMMON ,CMD_V0 , +SLI4_RQST_PYLD_LEN (cmn_set_features)); + + cmd->feature =cpu_to_le32 (feature); + cmd->param_len =cpu_to_le32 (param_len); +memcpy (cmd->params, parameter, param_len); + +return EFC_SUCCESS ; +} + +int +sli_cqe_mq (struct sli4 *sli4,void *buf) +{ +struct sli4_mcqe *mcqe = buf; +u32 dwflags =le32_to_cpu (mcqe->dw3_flags); +/* +* Firmware can split mbx completions into two MCQEs: first with only +* the "consumed" bit set and a second with the "complete" bit set. +* Thus, ignore MCQE unless "complete" is set. +*/ +if (!(dwflags &SLI4_MCQE_COMPLETED )) +return SLI4_MCQE_STATUS_NOT_COMPLETED ; + +if (le16_to_cpu (mcqe->completion_status)) { +efc_log_info (sli4,"status(st=%#x ext=%#x con=%d cmp=%d ae=%d val=%d)\n" , +le16_to_cpu (mcqe->completion_status), +le16_to_cpu (mcqe->extended_status), + (dwflags &SLI4_MCQE_CONSUMED ), + (dwflags &SLI4_MCQE_COMPLETED ), + (dwflags &SLI4_MCQE_AE ), + (dwflags &SLI4_MCQE_VALID )); + } + +return le16_to_cpu (mcqe->completion_status); +} + +int +sli_cqe_async (struct sli4 *sli4,void *buf) +{ +struct sli4_acqe *acqe = buf; +int rc =EFC_FAIL ; + +if (!buf) { +efc_log_err (sli4,"bad parameter sli4=%p buf=%p\n" , sli4, buf); +return EFC_FAIL ; + } + +switch (acqe->event_code) { +case SLI4_ACQE_EVENT_CODE_LINK_STATE : +efc_log_info (sli4,"Unsupported by FC link, evt code:%#x\n" , + acqe->event_code); +break ; +case SLI4_ACQE_EVENT_CODE_GRP_5 : +efc_log_info (sli4,"ACQE GRP5\n" ); +break ; +case SLI4_ACQE_EVENT_CODE_SLI_PORT_EVENT : +efc_log_info (sli4,"ACQE SLI Port, type=0x%x, data1,2=0x%08x,0x%08x\n" , + acqe->event_type, +le32_to_cpu (acqe->event_data[0 ]), +le32_to_cpu (acqe->event_data[1 ])); +break ; +case SLI4_ACQE_EVENT_CODE_FC_LINK_EVENT : + rc =sli_fc_process_link_attention (sli4, buf); +break ; +default : +efc_log_info (sli4,"ACQE unknown=%#x\n" , + acqe->event_code); + } + +return rc; +}
Signature · 1 line
2.26.2
PATCH v8 7/31 elx: libefc_sli: APIs to setup SLI library
In reply to James SmartThis patch continues the libefc_sli SLI-4 library population.
This patch adds APIS to initialize the library, initialize the SLI Port, reset firmware, terminate the SLI Port, and terminate the library.
---
v8:
Added sli_get_lmt helper function
--- drivers/scsi/elx/libefc_sli/sli4.c | 1135 ++++++++++++++++++++++++++++ drivers/scsi/elx/libefc_sli/sli4.h | 402 ++++++++++ 2 files changed, 1537 insertions(+)
drivers/scsi/elx/libefc_sli/sli4.c +1135 -0
@@ -4033,3 +4033,1138 @@ sli_cqe_async(struct sli4 *sli4, void *buf)return rc; } + +bool +sli_fw_ready (struct sli4 *sli4) +{ +u32 val; + +/* Determine if the chip FW is in a ready state */ + val =sli_reg_read_status (sli4); +return (val &SLI4_PORT_STATUS_RDY ) ?1 :0 ; +} + +static bool +sli_wait_for_fw_ready (struct sli4 *sli4,u32 timeout_ms) +{ +unsigned long end; + + end = jiffies +msecs_to_jiffies (timeout_ms); + +do { +if (sli_fw_ready (sli4)) +return true; + +usleep_range (1000 ,2000 ); + }while (time_before (jiffies, end)); + +return false; +} + +static bool +sli_sliport_reset (struct sli4 *sli4) +{ +bool rc; +u32 val; + + val =SLI4_PORT_CTRL_IP ; +/* Initialize port, endian */ +writel (val, (sli4->reg[0 ] +SLI4_PORT_CTRL_REG )); + + rc =sli_wait_for_fw_ready (sli4,SLI4_FW_READY_TIMEOUT_MSEC ); +if (!rc) +efc_log_crit (sli4,"port failed to become ready after initialization\n" ); + +return rc; +} + +static bool +sli_fw_init (struct sli4 *sli4) +{ +/* +* Is firmware ready for operation? +*/ +if (!sli_wait_for_fw_ready (sli4,SLI4_FW_READY_TIMEOUT_MSEC )) { +efc_log_crit (sli4,"FW status is NOT ready\n" ); +return false; + } + +/* +* Reset port to a known state +*/ +return sli_sliport_reset (sli4); +} + +static int +sli_request_features (struct sli4 *sli4,u32 *features,bool query) +{ +struct sli4_cmd_request_features *req_features = sli4->bmbx.virt; + +if (sli_cmd_request_features (sli4, sli4->bmbx.virt, *features, query)) { +efc_log_err (sli4,"bad REQUEST_FEATURES write\n" ); +return EFC_FAIL ; + } + +if (sli_bmbx_command (sli4)) { +efc_log_crit (sli4,"%s: bootstrap mailbox write fail\n" , + __func__); +return EFC_FAIL ; + } + +if (le16_to_cpu (req_features->hdr.status)) { +efc_log_err (sli4,"REQUEST_FEATURES bad status %#x\n" , +le16_to_cpu (req_features->hdr.status)); +return EFC_FAIL ; + } + + *features =le32_to_cpu (req_features->resp); +return EFC_SUCCESS ; +} + +void +sli_calc_max_qentries (struct sli4 *sli4) +{ +enum sli4_qtype q; +u32 qentries; + +for (q =SLI4_QTYPE_EQ ; q <SLI4_QTYPE_MAX ; q++) { + sli4->qinfo.max_qentries[q] = +sli_convert_mask_to_count (sli4->qinfo.count_method[q], + sli4->qinfo.count_mask[q]); + } + +/* single, continguous DMA allocations will be called for each queue +* of size (max_qentries * queue entry size); since these can be large, +* check against the OS max DMA allocation size +*/ +for (q =SLI4_QTYPE_EQ ; q <SLI4_QTYPE_MAX ; q++) { + qentries = sli4->qinfo.max_qentries[q]; + +efc_log_info (sli4,"[%s]: max_qentries from %d to %d\n" , +SLI4_QNAME [q], + sli4->qinfo.max_qentries[q], qentries); + sli4->qinfo.max_qentries[q] = qentries; + } +} + +static int +sli_get_read_config (struct sli4 *sli4) +{ +struct sli4_rsp_read_config *conf = sli4->bmbx.virt; +u32 i, total, total_size; +u32 *base; + +if (sli_cmd_read_config (sli4, sli4->bmbx.virt)) { +efc_log_err (sli4,"bad READ_CONFIG write\n" ); +return EFC_FAIL ; + } + +if (sli_bmbx_command (sli4)) { +efc_log_crit (sli4,"bootstrap mailbox fail (READ_CONFIG)\n" ); +return EFC_FAIL ; + } + +if (le16_to_cpu (conf->hdr.status)) { +efc_log_err (sli4,"READ_CONFIG bad status %#x\n" , +le16_to_cpu (conf->hdr.status)); +return EFC_FAIL ; + } + + sli4->params.has_extents = +le32_to_cpu (conf->ext_dword) &SLI4_READ_CFG_RESP_RESOURCE_EXT ; +if (sli4->params.has_extents) { +efc_log_err (sli4,"extents not supported\n" ); +return EFC_FAIL ; + } + + base = sli4->ext[0 ].base; +if (!base) { +int size =SLI4_RSRC_MAX *sizeof (u32); + + base =kzalloc (size,GFP_KERNEL ); +if (!base) +return EFC_FAIL ; + } + +for (i =0 ; i <SLI4_RSRC_MAX ; i++) { + sli4->ext[i].number =1 ; + sli4->ext[i].n_alloc =0 ; + sli4->ext[i].base = &base[i]; + } + + sli4->ext[SLI4_RSRC_VFI ].base[0 ] =le16_to_cpu (conf->vfi_base); + sli4->ext[SLI4_RSRC_VFI ].size =le16_to_cpu (conf->vfi_count); + + sli4->ext[SLI4_RSRC_VPI ].base[0 ] =le16_to_cpu (conf->vpi_base); + sli4->ext[SLI4_RSRC_VPI ].size =le16_to_cpu (conf->vpi_count); + + sli4->ext[SLI4_RSRC_RPI ].base[0 ] =le16_to_cpu (conf->rpi_base); + sli4->ext[SLI4_RSRC_RPI ].size =le16_to_cpu (conf->rpi_count); + + sli4->ext[SLI4_RSRC_XRI ].base[0 ] =le16_to_cpu (conf->xri_base); + sli4->ext[SLI4_RSRC_XRI ].size =le16_to_cpu (conf->xri_count); + + sli4->ext[SLI4_RSRC_FCFI ].base[0 ] =0 ; + sli4->ext[SLI4_RSRC_FCFI ].size =le16_to_cpu (conf->fcfi_count); + +for (i =0 ; i <SLI4_RSRC_MAX ; i++) { + total = sli4->ext[i].number * sli4->ext[i].size; + total_size =BITS_TO_LONGS (total) *sizeof (long ); + sli4->ext[i].use_map =kzalloc (total_size,GFP_KERNEL ); +if (!sli4->ext[i].use_map) { +efc_log_err (sli4,"bitmap memory allocation failed %d\n" , + i); +return EFC_FAIL ; + } + sli4->ext[i].map_size = total; + } + + sli4->topology = (le32_to_cpu (conf->topology_dword) & +SLI4_READ_CFG_RESP_TOPOLOGY ) >>24 ; +switch (sli4->topology) { +case SLI4_READ_CFG_TOPO_FC : +efc_log_info (sli4,"FC (unknown)\n" ); +break ; +case SLI4_READ_CFG_TOPO_NON_FC_AL : +efc_log_info (sli4,"FC (direct attach)\n" ); +break ; +case SLI4_READ_CFG_TOPO_FC_AL : +efc_log_info (sli4,"FC (arbitrated loop)\n" ); +break ; +default : +efc_log_info (sli4,"bad topology %#x\n" , + sli4->topology); + } + + sli4->e_d_tov =le16_to_cpu (conf->e_d_tov); + sli4->r_a_tov =le16_to_cpu (conf->r_a_tov); + + sli4->link_module_type =le16_to_cpu (conf->lmt); + + sli4->qinfo.max_qcount[SLI4_QTYPE_EQ ] =le16_to_cpu (conf->eq_count); + sli4->qinfo.max_qcount[SLI4_QTYPE_CQ ] =le16_to_cpu (conf->cq_count); + sli4->qinfo.max_qcount[SLI4_QTYPE_WQ ] =le16_to_cpu (conf->wq_count); + sli4->qinfo.max_qcount[SLI4_QTYPE_RQ ] =le16_to_cpu (conf->rq_count); + +/* +* READ_CONFIG doesn't give the max number of MQ. Applications +* will typically want 1, but we may need another at some future +* date. Dummy up a "max" MQ count here. +*/ + sli4->qinfo.max_qcount[SLI4_QTYPE_MQ ] =SLI4_USER_MQ_COUNT ; +return EFC_SUCCESS ; +} + +static int +sli_get_sli4_parameters (struct sli4 *sli4) +{ +struct sli4_rsp_cmn_get_sli4_params *parms; +u32 dw_loopback; +u32 dw_eq_pg_cnt; +u32 dw_cq_pg_cnt; +u32 dw_mq_pg_cnt; +u32 dw_wq_pg_cnt; +u32 dw_rq_pg_cnt; +u32 dw_sgl_pg_cnt; + +if (sli_cmd_common_get_sli4_parameters (sli4, sli4->bmbx.virt)) +return EFC_FAIL ; + + parms = (struct sli4_rsp_cmn_get_sli4_params *) + (((u8 *)sli4->bmbx.virt) + + offsetof(struct sli4_cmd_sli_config, payload.embed)); + +if (sli_bmbx_command (sli4)) { +efc_log_crit (sli4,"%s: bootstrap mailbox write fail\n" , + __func__); +return EFC_FAIL ; + } + +if (parms->hdr.status) { +efc_log_err (sli4,"COMMON_GET_SLI4_PARAMETERS bad status %#x" , + parms->hdr.status); +efc_log_err (sli4,"additional status %#x\n" , + parms->hdr.additional_status); +return EFC_FAIL ; + } + + dw_loopback =le32_to_cpu (parms->dw16_loopback_scope); + dw_eq_pg_cnt =le32_to_cpu (parms->dw6_eq_page_cnt); + dw_cq_pg_cnt =le32_to_cpu (parms->dw8_cq_page_cnt); + dw_mq_pg_cnt =le32_to_cpu (parms->dw10_mq_page_cnt); + dw_wq_pg_cnt =le32_to_cpu (parms->dw12_wq_page_cnt); + dw_rq_pg_cnt =le32_to_cpu (parms->dw14_rq_page_cnt); + + sli4->params.auto_reg = (dw_loopback &SLI4_PARAM_AREG ); + sli4->params.auto_xfer_rdy = (dw_loopback &SLI4_PARAM_AGXF ); + sli4->params.hdr_template_req = (dw_loopback &SLI4_PARAM_HDRR ); + sli4->params.t10_dif_inline_capable = (dw_loopback &SLI4_PARAM_TIMM ); + sli4->params.t10_dif_separate_capable = (dw_loopback &SLI4_PARAM_TSMM ); + + sli4->params.mq_create_version =GET_Q_CREATE_VERSION (dw_mq_pg_cnt); + sli4->params.cq_create_version =GET_Q_CREATE_VERSION (dw_cq_pg_cnt); + + sli4->rq_min_buf_size =le16_to_cpu (parms->min_rq_buffer_size); + sli4->rq_max_buf_size =le32_to_cpu (parms->max_rq_buffer_size); + + sli4->qinfo.qpage_count[SLI4_QTYPE_EQ ] = + (dw_eq_pg_cnt &SLI4_PARAM_EQ_PAGE_CNT_MASK ); + sli4->qinfo.qpage_count[SLI4_QTYPE_CQ ] = + (dw_cq_pg_cnt &SLI4_PARAM_CQ_PAGE_CNT_MASK ); + sli4->qinfo.qpage_count[SLI4_QTYPE_MQ ] = + (dw_mq_pg_cnt &SLI4_PARAM_MQ_PAGE_CNT_MASK ); + sli4->qinfo.qpage_count[SLI4_QTYPE_WQ ] = + (dw_wq_pg_cnt &SLI4_PARAM_WQ_PAGE_CNT_MASK ); + sli4->qinfo.qpage_count[SLI4_QTYPE_RQ ] = + (dw_rq_pg_cnt &SLI4_PARAM_RQ_PAGE_CNT_MASK ); + +/* save count methods and masks for each queue type */ + + sli4->qinfo.count_mask[SLI4_QTYPE_EQ ] = +le16_to_cpu (parms->eqe_count_mask); + sli4->qinfo.count_method[SLI4_QTYPE_EQ ] = +GET_Q_CNT_METHOD (dw_eq_pg_cnt); + + sli4->qinfo.count_mask[SLI4_QTYPE_CQ ] = +le16_to_cpu (parms->cqe_count_mask); + sli4->qinfo.count_method[SLI4_QTYPE_CQ ] = +GET_Q_CNT_METHOD (dw_cq_pg_cnt); + + sli4->qinfo.count_mask[SLI4_QTYPE_MQ ] = +le16_to_cpu (parms->mqe_count_mask); + sli4->qinfo.count_method[SLI4_QTYPE_MQ ] = +GET_Q_CNT_METHOD (dw_mq_pg_cnt); + + sli4->qinfo.count_mask[SLI4_QTYPE_WQ ] = +le16_to_cpu (parms->wqe_count_mask); + sli4->qinfo.count_method[SLI4_QTYPE_WQ ] = +GET_Q_CNT_METHOD (dw_wq_pg_cnt); + + sli4->qinfo.count_mask[SLI4_QTYPE_RQ ] = +le16_to_cpu (parms->rqe_count_mask); + sli4->qinfo.count_method[SLI4_QTYPE_RQ ] = +GET_Q_CNT_METHOD (dw_rq_pg_cnt); + +/* now calculate max queue entries */ +sli_calc_max_qentries (sli4); + + dw_sgl_pg_cnt =le32_to_cpu (parms->dw18_sgl_page_cnt); + +/* max # of pages */ + sli4->max_sgl_pages = (dw_sgl_pg_cnt &SLI4_PARAM_SGL_PAGE_CNT_MASK ); + +/* bit map of available sizes */ + sli4->sgl_page_sizes = (dw_sgl_pg_cnt & +SLI4_PARAM_SGL_PAGE_SZS_MASK ) >>8 ; +/* ignore HLM here. Use value from REQUEST_FEATURES */ + sli4->sge_supported_length =le32_to_cpu (parms->sge_supported_length); + sli4->params.sgl_pre_reg_required = (dw_loopback &SLI4_PARAM_SGLR ); +/* default to using pre-registered SGL's */ + sli4->params.sgl_pre_registered = true; + + sli4->params.perf_hint = dw_loopback &SLI4_PARAM_PHON ; + sli4->params.perf_wq_id_association = (dw_loopback &SLI4_PARAM_PHWQ ); + + sli4->rq_batch = (le16_to_cpu (parms->dw15w1_rq_db_window) & +SLI4_PARAM_RQ_DB_WINDOW_MASK ) >>12 ; + +/* Use the highest available WQE size. */ +if (((dw_wq_pg_cnt &SLI4_PARAM_WQE_SZS_MASK ) >>8 ) & +SLI4_128BYTE_WQE_SUPPORT ) + sli4->wqe_size =SLI4_WQE_EXT_BYTES ; +else + sli4->wqe_size =SLI4_WQE_BYTES ; + +return EFC_SUCCESS ; +} + +static int +sli_get_ctrl_attributes (struct sli4 *sli4) +{ +struct sli4_rsp_cmn_get_cntl_attributes *attr; +struct sli4_rsp_cmn_get_cntl_addl_attributes *add_attr; +struct efc_dma data; +u32 psize; + +/* +* Issue COMMON_GET_CNTL_ATTRIBUTES to get port_number. Temporarily +* uses VPD DMA buffer as the response won't fit in the embedded +* buffer. +*/ +memset (sli4->vpd_data.virt,0 , sli4->vpd_data.size); +if (sli_cmd_common_get_cntl_attributes (sli4, sli4->bmbx.virt, + &sli4->vpd_data)) { +efc_log_err (sli4,"bad COMMON_GET_CNTL_ATTRIBUTES write\n" ); +return EFC_FAIL ; + } + + attr = sli4->vpd_data.virt; + +if (sli_bmbx_command (sli4)) { +efc_log_crit (sli4,"%s: bootstrap mailbox write fail\n" , + __func__); +return EFC_FAIL ; + } + +if (attr->hdr.status) { +efc_log_err (sli4,"COMMON_GET_CNTL_ATTRIBUTES bad status %#x" , + attr->hdr.status); +efc_log_err (sli4,"additional status %#x\n" , + attr->hdr.additional_status); +return EFC_FAIL ; + } + + sli4->port_number = attr->port_num_type_flags &SLI4_CNTL_ATTR_PORTNUM ; + +memcpy (sli4->bios_version_string, attr->bios_version_str, +sizeof (sli4->bios_version_string)); + +/* get additional attributes */ + psize =sizeof (struct sli4_rsp_cmn_get_cntl_addl_attributes ); + data.size = psize; + data.virt =dma_alloc_coherent (&sli4->pci->dev, data.size, + &data.phys,GFP_DMA ); +if (!data.virt) { +memset (&data,0 ,sizeof (struct efc_dma )); +efc_log_err (sli4,"Failed to allocate memory for GET_CNTL_ADDL_ATTR\n" ); +return EFC_FAIL ; + } + +if (sli_cmd_common_get_cntl_addl_attributes (sli4, sli4->bmbx.virt, + &data)) { +efc_log_err (sli4,"bad GET_CNTL_ADDL_ATTR write\n" ); +dma_free_coherent (&sli4->pci->dev, data.size, + data.virt, data.phys); +return EFC_FAIL ; + } + +if (sli_bmbx_command (sli4)) { +efc_log_crit (sli4,"mailbox fail (GET_CNTL_ADDL_ATTR)\n" ); +dma_free_coherent (&sli4->pci->dev, data.size, + data.virt, data.phys); +return EFC_FAIL ; + } + + add_attr = data.virt; +if (add_attr->hdr.status) { +efc_log_err (sli4,"GET_CNTL_ADDL_ATTR bad status %#x\n" , + add_attr->hdr.status); +dma_free_coherent (&sli4->pci->dev, data.size, + data.virt, data.phys); +return EFC_FAIL ; + } + +memcpy (sli4->ipl_name, add_attr->ipl_file_name,sizeof (sli4->ipl_name)); + +efc_log_info (sli4,"IPL:%s\n" , (char *)sli4->ipl_name); + +dma_free_coherent (&sli4->pci->dev, data.size, data.virt, + data.phys); +memset (&data,0 ,sizeof (struct efc_dma )); +return EFC_SUCCESS ; +} + +static int +sli_get_fw_rev (struct sli4 *sli4) +{ +struct sli4_cmd_read_rev *read_rev = sli4->bmbx.virt; + +if (sli_cmd_read_rev (sli4, sli4->bmbx.virt, &sli4->vpd_data)) +return EFC_FAIL ; + +if (sli_bmbx_command (sli4)) { +efc_log_crit (sli4,"bootstrap mailbox write fail (READ_REV)\n" ); +return EFC_FAIL ; + } + +if (le16_to_cpu (read_rev->hdr.status)) { +efc_log_err (sli4,"READ_REV bad status %#x\n" , +le16_to_cpu (read_rev->hdr.status)); +return EFC_FAIL ; + } + + sli4->fw_rev[0 ] =le32_to_cpu (read_rev->first_fw_id); +memcpy (sli4->fw_name[0 ], read_rev->first_fw_name, +sizeof (sli4->fw_name[0 ])); + + sli4->fw_rev[1 ] =le32_to_cpu (read_rev->second_fw_id); +memcpy (sli4->fw_name[1 ], read_rev->second_fw_name, +sizeof (sli4->fw_name[1 ])); + + sli4->hw_rev[0 ] =le32_to_cpu (read_rev->first_hw_rev); + sli4->hw_rev[1 ] =le32_to_cpu (read_rev->second_hw_rev); + sli4->hw_rev[2 ] =le32_to_cpu (read_rev->third_hw_rev); + +efc_log_info (sli4,"FW1:%s (%08x) / FW2:%s (%08x)\n" , + read_rev->first_fw_name,le32_to_cpu (read_rev->first_fw_id), + read_rev->second_fw_name,le32_to_cpu (read_rev->second_fw_id)); + +efc_log_info (sli4,"HW1: %08x / HW2: %08x\n" , +le32_to_cpu (read_rev->first_hw_rev), +le32_to_cpu (read_rev->second_hw_rev)); + +/* Check that all VPD data was returned */ +if (le32_to_cpu (read_rev->returned_vpd_length) != +le32_to_cpu (read_rev->actual_vpd_length)) { +efc_log_info (sli4,"VPD length: avail=%d return=%d actual=%d\n" , +le32_to_cpu (read_rev->available_length_dword) & +SLI4_READ_REV_AVAILABLE_LENGTH , +le32_to_cpu (read_rev->returned_vpd_length), +le32_to_cpu (read_rev->actual_vpd_length)); + } + sli4->vpd_length =le32_to_cpu (read_rev->returned_vpd_length); +return EFC_SUCCESS ; +} + +static int +sli_get_config (struct sli4 *sli4) +{ +struct sli4_rsp_cmn_get_port_name *port_name; +struct sli4_cmd_read_nvparms *read_nvparms; + +/* +* Read the device configuration +*/ +if (sli_get_read_config (sli4)) +return EFC_FAIL ; + +if (sli_get_sli4_parameters (sli4)) +return EFC_FAIL ; + +if (sli_get_ctrl_attributes (sli4)) +return EFC_FAIL ; + +if (sli_cmd_common_get_port_name (sli4, sli4->bmbx.virt)) +return EFC_FAIL ; + + port_name = (struct sli4_rsp_cmn_get_port_name *) + (((u8 *)sli4->bmbx.virt) + + offsetof(struct sli4_cmd_sli_config, payload.embed)); + +if (sli_bmbx_command (sli4)) { +efc_log_crit (sli4,"bootstrap mailbox fail (GET_PORT_NAME)\n" ); +return EFC_FAIL ; + } + + sli4->port_name[0 ] = port_name->port_name[sli4->port_number]; + sli4->port_name[1 ] ='\0' ; + +if (sli_get_fw_rev (sli4)) +return EFC_FAIL ; + +if (sli_cmd_read_nvparms (sli4, sli4->bmbx.virt)) { +efc_log_err (sli4,"bad READ_NVPARMS write\n" ); +return EFC_FAIL ; + } + +if (sli_bmbx_command (sli4)) { +efc_log_crit (sli4,"bootstrap mailbox fail (READ_NVPARMS)\n" ); +return EFC_FAIL ; + } + + read_nvparms = sli4->bmbx.virt; +if (le16_to_cpu (read_nvparms->hdr.status)) { +efc_log_err (sli4,"READ_NVPARMS bad status %#x\n" , +le16_to_cpu (read_nvparms->hdr.status)); +return EFC_FAIL ; + } + +memcpy (sli4->wwpn, read_nvparms->wwpn,sizeof (sli4->wwpn)); +memcpy (sli4->wwnn, read_nvparms->wwnn,sizeof (sli4->wwnn)); + +efc_log_info (sli4,"WWPN %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n" , + sli4->wwpn[0 ], sli4->wwpn[1 ], sli4->wwpn[2 ], sli4->wwpn[3 ], + sli4->wwpn[4 ], sli4->wwpn[5 ], sli4->wwpn[6 ], sli4->wwpn[7 ]); +efc_log_info (sli4,"WWNN %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n" , + sli4->wwnn[0 ], sli4->wwnn[1 ], sli4->wwnn[2 ], sli4->wwnn[3 ], + sli4->wwnn[4 ], sli4->wwnn[5 ], sli4->wwnn[6 ], sli4->wwnn[7 ]); + +return EFC_SUCCESS ; +} + +int +sli_setup (struct sli4 *sli4,void *os,struct pci_dev *pdev, +void __iomem *reg[]) +{ +u32 intf =U32_MAX ; +u32 pci_class_rev =0 ; +u32 rev_id =0 ; +u32 family =0 ; +u32 asic_id =0 ; +u32 i; +struct sli4_asic_entry_t *asic; + +memset (sli4,0 ,sizeof (struct sli4 )); + + sli4->os = os; + sli4->pci = pdev; + +for (i =0 ; i <6 ; i++) + sli4->reg[i] = reg[i]; +/* +* Read the SLI_INTF register to discover the register layout +* and other capability information +*/ +if (pci_read_config_dword (pdev,SLI4_INTF_REG , &intf)) +return EFC_FAIL ; + +if ((intf &SLI4_INTF_VALID_MASK ) != (u32 )SLI4_INTF_VALID_VALUE ) { +efc_log_err (sli4,"SLI_INTF is not valid\n" ); +return EFC_FAIL ; + } + +/* driver only support SLI-4 */ +if ((intf &SLI4_INTF_REV_MASK ) !=SLI4_INTF_REV_S4 ) { +efc_log_err (sli4,"Unsupported SLI revision (intf=%#x)\n" , + intf); +return EFC_FAIL ; + } + + sli4->sli_family = intf &SLI4_INTF_FAMILY_MASK ; + + sli4->if_type = intf &SLI4_INTF_IF_TYPE_MASK ; +efc_log_info (sli4,"status=%#x error1=%#x error2=%#x\n" , +sli_reg_read_status (sli4), +sli_reg_read_err1 (sli4), +sli_reg_read_err2 (sli4)); + +/* +* set the ASIC type and revision +*/ +if (pci_read_config_dword (pdev,PCI_CLASS_REVISION , &pci_class_rev)) +return EFC_FAIL ; + + rev_id = pci_class_rev &0xff ; + family = sli4->sli_family; +if (family ==SLI4_FAMILY_CHECK_ASIC_TYPE ) { +if (!pci_read_config_dword (pdev,SLI4_ASIC_ID_REG , &asic_id)) + family = asic_id &SLI4_ASIC_GEN_MASK ; + } + +for (i =0 , asic = sli4_asic_table; i <ARRAY_SIZE (sli4_asic_table); + i++, asic++) { +if (rev_id == asic->rev_id && family == asic->family) { + sli4->asic_type = family; + sli4->asic_rev = rev_id; +break ; + } + } +/* Fail if no matching asic type/rev was found */ +if (!sli4->asic_type) { +efc_log_err (sli4,"no matching asic family/rev found: %02x/%02x\n" , + family, rev_id); +return EFC_FAIL ; + } + +/* +* The bootstrap mailbox is equivalent to a MQ with a single 256 byte +* entry, a CQ with a single 16 byte entry, and no event queue. +* Alignment must be 16 bytes as the low order address bits in the +* address register are also control / status. +*/ + sli4->bmbx.size =SLI4_BMBX_SIZE +sizeof (struct sli4_mcqe ); + sli4->bmbx.virt =dma_alloc_coherent (&pdev->dev, sli4->bmbx.size, + &sli4->bmbx.phys,GFP_DMA ); +if (!sli4->bmbx.virt) { +memset (&sli4->bmbx,0 ,sizeof (struct efc_dma )); +efc_log_err (sli4,"bootstrap mailbox allocation failed\n" ); +return EFC_FAIL ; + } + +if (sli4->bmbx.phys &SLI4_BMBX_MASK_LO ) { +efc_log_err (sli4,"bad alignment for bootstrap mailbox\n" ); +return EFC_FAIL ; + } + +efc_log_info (sli4,"bmbx v=%p p=0x%x %08x s=%zd\n" , sli4->bmbx.virt, +upper_32_bits (sli4->bmbx.phys), +lower_32_bits (sli4->bmbx.phys), sli4->bmbx.size); + +/* 4096 is arbitrary. What should this value actually be? */ + sli4->vpd_data.size =4096 ; + sli4->vpd_data.virt =dma_alloc_coherent (&pdev->dev, + sli4->vpd_data.size, + &sli4->vpd_data.phys, +GFP_DMA ); +if (!sli4->vpd_data.virt) { +memset (&sli4->vpd_data,0 ,sizeof (struct efc_dma )); +/* Note that failure isn't fatal in this specific case */ +efc_log_info (sli4,"VPD buffer allocation failed\n" ); + } + +if (!sli_fw_init (sli4)) { +efc_log_err (sli4,"FW initialization failed\n" ); +return EFC_FAIL ; + } + +/* +* Set one of fcpi(initiator), fcpt(target), fcpc(combined) to true +* in addition to any other desired features +*/ + sli4->features = (SLI4_REQFEAT_IAAB |SLI4_REQFEAT_NPIV | +SLI4_REQFEAT_DIF |SLI4_REQFEAT_VF | +SLI4_REQFEAT_FCPC |SLI4_REQFEAT_IAAR | +SLI4_REQFEAT_HLM |SLI4_REQFEAT_PERFH | +SLI4_REQFEAT_RXSEQ |SLI4_REQFEAT_RXRI | +SLI4_REQFEAT_MRQP ); + +/* use performance hints if available */ +if (sli4->params.perf_hint) + sli4->features |=SLI4_REQFEAT_PERFH ; + +if (sli_request_features (sli4, &sli4->features, true)) +return EFC_FAIL ; + +if (sli_get_config (sli4)) +return EFC_FAIL ; + +return EFC_SUCCESS ; +} + +int +sli_init (struct sli4 *sli4) +{ +if (sli4->params.has_extents) { +efc_log_info (sli4,"extend allocation not supported\n" ); +return EFC_FAIL ; + } + + sli4->features &= (~SLI4_REQFEAT_HLM ); + sli4->features &= (~SLI4_REQFEAT_RXSEQ ); + sli4->features &= (~SLI4_REQFEAT_RXRI ); + +if (sli_request_features (sli4, &sli4->features, false)) +return EFC_FAIL ; + +return EFC_SUCCESS ; +} + +int +sli_reset (struct sli4 *sli4) +{ +u32 i; + +if (!sli_fw_init (sli4)) { +efc_log_crit (sli4,"FW initialization failed\n" ); +return EFC_FAIL ; + } + +kfree (sli4->ext[0 ].base); + sli4->ext[0 ].base =NULL ; + +for (i =0 ; i <SLI4_RSRC_MAX ; i++) { +kfree (sli4->ext[i].use_map); + sli4->ext[i].use_map =NULL ; + sli4->ext[i].base =NULL ; + } + +return sli_get_config (sli4); +} + +int +sli_fw_reset (struct sli4 *sli4) +{ +/* +* Firmware must be ready before issuing the reset. +*/ +if (!sli_wait_for_fw_ready (sli4,SLI4_FW_READY_TIMEOUT_MSEC )) { +efc_log_crit (sli4,"FW status is NOT ready\n" ); +return EFC_FAIL ; + } + +/* Lancer uses PHYDEV_CONTROL */ +writel (SLI4_PHYDEV_CTRL_FRST , (sli4->reg[0 ] +SLI4_PHYDEV_CTRL_REG )); + +/* wait for the FW to become ready after the reset */ +if (!sli_wait_for_fw_ready (sli4,SLI4_FW_READY_TIMEOUT_MSEC )) { +efc_log_crit (sli4,"Failed to be ready after firmware reset\n" ); +return EFC_FAIL ; + } +return EFC_SUCCESS ; +} + +void +sli_teardown (struct sli4 *sli4) +{ +u32 i; + +kfree (sli4->ext[0 ].base); + sli4->ext[0 ].base =NULL ; + +for (i =0 ; i <SLI4_RSRC_MAX ; i++) { + sli4->ext[i].base =NULL ; + +kfree (sli4->ext[i].use_map); + sli4->ext[i].use_map =NULL ; + } + +if (!sli_sliport_reset (sli4)) +efc_log_err (sli4,"FW deinitialization failed\n" ); + +dma_free_coherent (&sli4->pci->dev, sli4->vpd_data.size, + sli4->vpd_data.virt, sli4->vpd_data.phys); +memset (&sli4->vpd_data,0 ,sizeof (struct efc_dma )); + +dma_free_coherent (&sli4->pci->dev, sli4->bmbx.size, + sli4->bmbx.virt, sli4->bmbx.phys); +memset (&sli4->bmbx,0 ,sizeof (struct efc_dma )); +} + +int +sli_callback (struct sli4 *sli4,enum sli4_callback which, +void *func,void *arg) +{ +if (!func) { +efc_log_err (sli4,"bad parameter sli4=%p which=%#x func=%p\n" , + sli4, which, func); +return EFC_FAIL ; + } + +switch (which) { +case SLI4_CB_LINK : + sli4->link = func; + sli4->link_arg = arg; +break ; +default : +efc_log_info (sli4,"unknown callback %#x\n" , which); +return EFC_FAIL ; + } + +return EFC_SUCCESS ; +} + +int +sli_eq_modify_delay (struct sli4 *sli4,struct sli4_queue *eq, +u32 num_eq,u32 shift,u32 delay_mult) +{ +sli_cmd_common_modify_eq_delay (sli4, sli4->bmbx.virt, eq, num_eq, + shift, delay_mult); + +if (sli_bmbx_command (sli4)) { +efc_log_crit (sli4,"bootstrap mailbox write fail (MODIFY EQ DELAY)\n" ); +return EFC_FAIL ; + } +if (sli_res_sli_config (sli4, sli4->bmbx.virt)) { +efc_log_err (sli4,"bad status MODIFY EQ DELAY\n" ); +return EFC_FAIL ; + } + +return EFC_SUCCESS ; +} + +int +sli_resource_alloc (struct sli4 *sli4,enum sli4_resource rtype, +u32 *rid,u32 *index) +{ +int rc =EFC_SUCCESS ; +u32 size; +u32 ext_idx; +u32 item_idx; +u32 position; + + *rid =U32_MAX ; + *index =U32_MAX ; + +switch (rtype) { +case SLI4_RSRC_VFI : +case SLI4_RSRC_VPI : +case SLI4_RSRC_RPI : +case SLI4_RSRC_XRI : + position = +find_first_zero_bit (sli4->ext[rtype].use_map, + sli4->ext[rtype].map_size); +if (position >= sli4->ext[rtype].map_size) { +efc_log_err (sli4,"out of resource %d (alloc=%d)\n" , + rtype, sli4->ext[rtype].n_alloc); + rc =EFC_FAIL ; +break ; + } +set_bit (position, sli4->ext[rtype].use_map); + *index = position; + + size = sli4->ext[rtype].size; + + ext_idx = *index / size; + item_idx = *index % size; + + *rid = sli4->ext[rtype].base[ext_idx] + item_idx; + + sli4->ext[rtype].n_alloc++; +break ; +default : + rc =EFC_FAIL ; + } + +return rc; +} + +int +sli_resource_free (struct sli4 *sli4,enum sli4_resource rtype,u32 rid) +{ +int rc =EFC_FAIL ; +u32 x; +u32 size, *base; + +switch (rtype) { +case SLI4_RSRC_VFI : +case SLI4_RSRC_VPI : +case SLI4_RSRC_RPI : +case SLI4_RSRC_XRI : +/* +* Figure out which extent contains the resource ID. I.e. find +* the extent such that +* extent->base <= resource ID < extent->base + extent->size +*/ + base = sli4->ext[rtype].base; + size = sli4->ext[rtype].size; + +/* +* In the case of FW reset, this may be cleared +* but the force_free path will still attempt to +* free the resource. Prevent a NULL pointer access. +*/ +if (!base) +break ; + +for (x =0 ; x < sli4->ext[rtype].number; x++) { +if ((rid < base[x] || (rid >= (base[x] + size)))) +continue ; + + rid -= base[x]; +clear_bit ((x * size) + rid, sli4->ext[rtype].use_map); + rc =EFC_SUCCESS ; +break ; + } +break ; +default : +break ; + } + +return rc; +} + +int +sli_resource_reset (struct sli4 *sli4,enum sli4_resource rtype) +{ +int rc =EFC_FAIL ; +u32 i; + +switch (rtype) { +case SLI4_RSRC_VFI : +case SLI4_RSRC_VPI : +case SLI4_RSRC_RPI : +case SLI4_RSRC_XRI : +for (i =0 ; i < sli4->ext[rtype].map_size; i++) +clear_bit (i, sli4->ext[rtype].use_map); + rc =EFC_SUCCESS ; +break ; +default : +break ; + } + +return rc; +} + +int sli_raise_ue (struct sli4 *sli4,u8 dump) +{ +u32 val =0 ; + +if (dump ==SLI4_FUNC_DESC_DUMP ) { + val =SLI4_PORT_CTRL_FDD |SLI4_PORT_CTRL_IP ; +writel (val, (sli4->reg[0 ] +SLI4_PORT_CTRL_REG )); + }else { + val =SLI4_PHYDEV_CTRL_FRST ; + +if (dump ==SLI4_CHIP_LEVEL_DUMP ) + val |=SLI4_PHYDEV_CTRL_DD ; +writel (val, (sli4->reg[0 ] +SLI4_PHYDEV_CTRL_REG )); + } + +return EFC_SUCCESS ; +} + +int sli_dump_is_ready (struct sli4 *sli4) +{ +int rc =SLI4_DUMP_READY_STATUS_NOT_READY ; +u32 port_val; +u32 bmbx_val; + +/* +* Ensure that the port is ready AND the mailbox is +* ready before signaling that the dump is ready to go. +*/ + port_val =sli_reg_read_status (sli4); + bmbx_val =readl (sli4->reg[0 ] +SLI4_BMBX_REG ); + +if ((bmbx_val &SLI4_BMBX_RDY ) && + (port_val &SLI4_PORT_STATUS_RDY )) { +if (port_val &SLI4_PORT_STATUS_DIP ) + rc =SLI4_DUMP_READY_STATUS_DD_PRESENT ; +else if (port_val &SLI4_PORT_STATUS_FDP ) + rc =SLI4_DUMP_READY_STATUS_FDB_PRESENT ; + } + +return rc; +} + +bool sli_reset_required (struct sli4 *sli4) +{ +u32 val; + + val =sli_reg_read_status (sli4); +return (val &SLI4_PORT_STATUS_RN ); +} + +int +sli_cmd_post_sgl_pages (struct sli4 *sli4,void *buf,u16 xri, +u32 xri_count,struct efc_dma *page0[], +struct efc_dma *page1[],struct efc_dma *dma) +{ +struct sli4_rqst_post_sgl_pages *post =NULL ; +u32 i; +__le32 req_len; + + post =sli_config_cmd_init (sli4, buf, +SLI4_CFG_PYLD_LENGTH (post_sgl_pages), dma); +if (!post) +return EFC_FAIL ; + +/* payload size calculation */ +/* 4 = xri_start + xri_count */ +/* xri_count = # of XRI's registered */ +/* sizeof(uint64_t) = physical address size */ +/* 2 = # of physical addresses per page set */ + req_len =cpu_to_le32 (4 + (xri_count * (sizeof (uint64_t ) *2 ))); +sli_cmd_fill_hdr (&post->hdr,SLI4_OPC_POST_SGL_PAGES ,SLI4_SUBSYSTEM_FC , +CMD_V0 , req_len); + post->xri_start =cpu_to_le16 (xri); + post->xri_count =cpu_to_le16 (xri_count); + +for (i =0 ; i < xri_count; i++) { + post->page_set[i].page0_low = +cpu_to_le32 (lower_32_bits (page0[i]->phys)); + post->page_set[i].page0_high = +cpu_to_le32 (upper_32_bits (page0[i]->phys)); + } + +if (page1) { +for (i =0 ; i < xri_count; i++) { + post->page_set[i].page1_low = +cpu_to_le32 (lower_32_bits (page1[i]->phys)); + post->page_set[i].page1_high = +cpu_to_le32 (upper_32_bits (page1[i]->phys)); + } + } + +return EFC_SUCCESS ; +} + +int +sli_cmd_post_hdr_templates (struct sli4 *sli4,void *buf,struct efc_dma *dma, +u16 rpi,struct efc_dma *payload_dma) +{ +struct sli4_rqst_post_hdr_templates *req =NULL ; +uintptr_t phys =0 ; +u32 i =0 ; +u32 page_count, payload_size; + + page_count =sli_page_count (dma->size,SLI_PAGE_SIZE ); + + payload_size = ((sizeof (struct sli4_rqst_post_hdr_templates ) + + (page_count *SZ_DMAADDR )) -sizeof (struct sli4_rqst_hdr )); + +if (page_count >16 ) { +/* +* We can't fit more than 16 descriptors into an embedded mbox +* command, it has to be non-embedded +*/ + payload_dma->size = payload_size; + payload_dma->virt =dma_alloc_coherent (&sli4->pci->dev, + payload_dma->size, + &payload_dma->phys,GFP_DMA ); +if (!payload_dma->virt) { +memset (payload_dma,0 ,sizeof (struct efc_dma )); +efc_log_err (sli4,"mbox payload memory allocation fail\n" ); +return EFC_FAIL ; + } + req =sli_config_cmd_init (sli4, buf, payload_size, payload_dma); + }else { + req =sli_config_cmd_init (sli4, buf, payload_size,NULL ); + } + +if (!req) +return EFC_FAIL ; + +if (rpi ==U16_MAX ) + rpi = sli4->ext[SLI4_RSRC_RPI ].base[0 ]; + +sli_cmd_fill_hdr (&req->hdr,SLI4_OPC_POST_HDR_TEMPLATES , +SLI4_SUBSYSTEM_FC ,CMD_V0 , +SLI4_RQST_PYLD_LEN (post_hdr_templates)); + + req->rpi_offset =cpu_to_le16 (rpi); + req->page_count =cpu_to_le16 (page_count); + phys = dma->phys; +for (i =0 ; i < page_count; i++) { + req->page_descriptor[i].low =cpu_to_le32 (lower_32_bits (phys)); + req->page_descriptor[i].high =cpu_to_le32 (upper_32_bits (phys)); + + phys +=SLI_PAGE_SIZE ; + } + +return EFC_SUCCESS ; +} + +u32 +sli_fc_get_rpi_requirements (struct sli4 *sli4,u32 n_rpi) +{ +u32 bytes =0 ; + +/* Check if header templates needed */ +if (sli4->params.hdr_template_req) +/* round up to a page */ + bytes =round_up (n_rpi *SLI4_HDR_TEMPLATE_SIZE ,SLI_PAGE_SIZE ); + +return bytes; +} + +const char * +sli_fc_get_status_string (u32 status) +{ +static struct { +u32 code; +const char *label; + } lookup[] = { + {SLI4_FC_WCQE_STATUS_SUCCESS ,"SUCCESS" }, + {SLI4_FC_WCQE_STATUS_FCP_RSP_FAILURE ,"FCP_RSP_FAILURE" }, + {SLI4_FC_WCQE_STATUS_REMOTE_STOP ,"REMOTE_STOP" }, + {SLI4_FC_WCQE_STATUS_LOCAL_REJECT ,"LOCAL_REJECT" }, + {SLI4_FC_WCQE_STATUS_NPORT_RJT ,"NPORT_RJT" }, + {SLI4_FC_WCQE_STATUS_FABRIC_RJT ,"FABRIC_RJT" }, + {SLI4_FC_WCQE_STATUS_NPORT_BSY ,"NPORT_BSY" }, + {SLI4_FC_WCQE_STATUS_FABRIC_BSY ,"FABRIC_BSY" }, + {SLI4_FC_WCQE_STATUS_LS_RJT ,"LS_RJT" }, + {SLI4_FC_WCQE_STATUS_CMD_REJECT ,"CMD_REJECT" }, + {SLI4_FC_WCQE_STATUS_FCP_TGT_LENCHECK ,"FCP_TGT_LENCHECK" }, + {SLI4_FC_WCQE_STATUS_RQ_BUF_LEN_EXCEEDED ,"BUF_LEN_EXCEEDED" }, + {SLI4_FC_WCQE_STATUS_RQ_INSUFF_BUF_NEEDED , +"RQ_INSUFF_BUF_NEEDED" }, + {SLI4_FC_WCQE_STATUS_RQ_INSUFF_FRM_DISC ,"RQ_INSUFF_FRM_DESC" }, + {SLI4_FC_WCQE_STATUS_RQ_DMA_FAILURE ,"RQ_DMA_FAILURE" }, + {SLI4_FC_WCQE_STATUS_FCP_RSP_TRUNCATE ,"FCP_RSP_TRUNCATE" }, + {SLI4_FC_WCQE_STATUS_DI_ERROR ,"DI_ERROR" }, + {SLI4_FC_WCQE_STATUS_BA_RJT ,"BA_RJT" }, + {SLI4_FC_WCQE_STATUS_RQ_INSUFF_XRI_NEEDED , +"RQ_INSUFF_XRI_NEEDED" }, + {SLI4_FC_WCQE_STATUS_RQ_INSUFF_XRI_DISC ,"INSUFF_XRI_DISC" }, + {SLI4_FC_WCQE_STATUS_RX_ERROR_DETECT ,"RX_ERROR_DETECT" }, + {SLI4_FC_WCQE_STATUS_RX_ABORT_REQUEST ,"RX_ABORT_REQUEST" }, + }; +u32 i; + +for (i =0 ; i <ARRAY_SIZE (lookup); i++) { +if (status == lookup[i].code) +return lookup[i].label; + } +return "unknown" ; +}
drivers/scsi/elx/libefc_sli/sli4.h +402 -0
406 lines not on this page · raw message
Signature · 1 line
2.26.2
PATCH v8 8/31 elx: libefc: Generic state machine framework
In reply to James SmartThis patch starts the population of the libefc library. The library will contain common tasks usable by a target or initiator driver. The library will also contain a FC discovery state machine interface.
This patch creates the library directory and adds definitions for the discovery state machine interface.
--- drivers/scsi/elx/libefc/efc_sm.c | 54 +++++++++ drivers/scsi/elx/libefc/efc_sm.h | 197 +++++++++++++++++++++++++++++++ 2 files changed, 251 insertions(+) create mode 100644 drivers/scsi/elx/libefc/efc_sm.c create mode 100644 drivers/scsi/elx/libefc/efc_sm.h
drivers/scsi/elx/libefc/efc_sm.c new file +54 -0
@@ -0,0 +1,54 @@ +// SPDX-License-Identifier: GPL-2.0 +/* +* Copyright (C) 2021 Broadcom. All Rights Reserved. The term +* “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. +*/ + +/* +* Generic state machine framework. +*/ +#include "efc.h" +#include "efc_sm.h" + +/** +* efc_sm_post_event() - Post an event to a context. +* +* @ctx: State machine context +* @evt: Event to post +* @data: Event-specific data (if any) +*/ +int +efc_sm_post_event (struct efc_sm_ctx *ctx, +enum efc_sm_event evt,void *data) +{ +if (!ctx->current_state) +return EFC_FAIL ; + + ctx->current_state (ctx, evt, data); +return EFC_SUCCESS ; +} + +void +efc_sm_transition (struct efc_sm_ctx *ctx, +void (*state)(struct efc_sm_ctx *, +enum efc_sm_event ,void *),void *data) + +{ +if (ctx->current_state == state) { +efc_sm_post_event (ctx,EFC_EVT_REENTER , data); + }else { +efc_sm_post_event (ctx,EFC_EVT_EXIT , data); + ctx->current_state = state; +efc_sm_post_event (ctx,EFC_EVT_ENTER , data); + } +} + +static char *event_name[] =EFC_SM_EVENT_NAME ; + +const char *efc_sm_event_name (enum efc_sm_event evt) +{ +if (evt >EFC_EVT_LAST ) +return "unknown" ; + +return event_name[evt]; +}
drivers/scsi/elx/libefc/efc_sm.h new file +197 -0
197 lines not on this page · raw message
Signature · 1 line
2.26.2
PATCH v8 9/31 elx: libefc: Emulex FC discovery library APIs and definitions
In reply to James SmartThis patch continues the libefc library population.
This patch adds library interface definitions for:
- SLI/Local FC port objects
- efc_domain_s: FC domain (aka fabric) objects
- efc_node_s: FC node (aka remote ports) objects
---
v8:
Rename struct efc_vport_spec to efc_vport.
--- drivers/scsi/elx/libefc/efc.h | 69 ++++ drivers/scsi/elx/libefc/efclib.c | 81 +++++ drivers/scsi/elx/libefc/efclib.h | 601 +++++++++++++++++++++++++++++++ 3 files changed, 751 insertions(+) create mode 100644 drivers/scsi/elx/libefc/efc.h create mode 100644 drivers/scsi/elx/libefc/efclib.c create mode 100644 drivers/scsi/elx/libefc/efclib.h
drivers/scsi/elx/libefc/efc.h new file +69 -0
@@ -0,0 +1,69 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* +* Copyright (C) 2021 Broadcom. All Rights Reserved. The term +* “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. +*/ + +#ifndef __EFC_H__ +#define __EFC_H__ + +#include "../include/efc_common.h" +#include "efclib.h" +#include "efc_sm.h" +#include "efc_cmds.h" +#include "efc_domain.h" +#include "efc_nport.h" +#include "efc_node.h" +#include "efc_fabric.h" +#include "efc_device.h" +#include "efc_els.h" + +#define EFC_MAX_REMOTE_NODES 2048 +#define NODE_SPARAMS_SIZE 256 + +enum efc_hw_rtn { +EFC_HW_RTN_SUCCESS =0 , +EFC_HW_RTN_SUCCESS_SYNC =1 , +EFC_HW_RTN_ERROR =-1 , +EFC_HW_RTN_NO_RESOURCES =-2 , +EFC_HW_RTN_NO_MEMORY =-3 , +EFC_HW_RTN_IO_NOT_ACTIVE =-4 , +EFC_HW_RTN_IO_ABORT_IN_PROGRESS =-5 , +EFC_HW_RTN_IO_PORT_OWNED_ALREADY_ABORTED =-6 , +EFC_HW_RTN_INVALID_ARG =-7 , +}; + +#define EFC_HW_RTN_IS_ERROR (e) ((e) < 0) + +enum efc_scsi_del_initiator_reason { +EFC_SCSI_INITIATOR_DELETED , +EFC_SCSI_INITIATOR_MISSING , +}; + +enum efc_scsi_del_target_reason { +EFC_SCSI_TARGET_DELETED , +EFC_SCSI_TARGET_MISSING , +}; + +#define EFC_SCSI_CALL_COMPLETE 0 +#define EFC_SCSI_CALL_ASYNC 1 + +#define EFC_FC_ELS_DEFAULT_RETRIES 3 + +#define domain_sm_trace (domain) \ + efc_log_debug(domain->efc, "[domain:%s] %-20s %-20s\n", \ + domain->display_name, __func__, efc_sm_event_name(evt)) \ + +#define domain_trace (domain, fmt, ...) \ + efc_log_debug(domain->efc, \ + "[%s]" fmt, domain->display_name, ##__VA_ARGS__) \ + +#define node_sm_trace () \ + efc_log_debug(node->efc, "[%s] %-20s %-20s\n", \ + node->display_name, __func__, efc_sm_event_name(evt)) \ + +#define nport_sm_trace (nport) \ + efc_log_debug(nport->efc, \ + "[%s] %-20s\n", nport->display_name, efc_sm_event_name(evt)) \ + +#endif /* __EFC_H__ */
drivers/scsi/elx/libefc/efclib.c new file +81 -0
81 lines not on this page · raw message
drivers/scsi/elx/libefc/efclib.h new file +601 -0
601 lines not on this page · raw message
Signature · 1 line
2.26.2
Re: [PATCH v8 09/31] elx: libefc: Emulex FC discovery library APIs and definitions
Quoted 318 lines · James Smart
This patch continues the libefc library population.
This patch adds library interface definitions for:
- SLI/Local FC port objects
-efc_domain_s: FC domain (aka fabric) objects
-efc_node_s: FC node (aka remote ports) objectsCo-developed-by Ram Vegesna <[email protected]>Signed-off-by Ram Vegesna <[email protected]>Signed-off-by James Smart <[email protected]>Reviewed-by Daniel Wagner <[email protected]>---
v8:
Rename structefc_vport_spectoefc_vport.--- drivers/scsi/elx/libefc/efc.h | 69 ++++ drivers/scsi/elx/libefc/efclib.c | 81 +++++ drivers/scsi/elx/libefc/efclib.h | 601 +++++++++++++++++++++++++++++++ 3 files changed, 751 insertions(+) create mode 100644 drivers/scsi/elx/libefc/efc.h create mode 100644 drivers/scsi/elx/libefc/efclib.c create mode 100644 drivers/scsi/elx/libefc/efclib.hdrivers/scsi/elx/libefc/efc.h new file +69
-0@@ -0,0 +1,69 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* +* Copyright (C) 2021 Broadcom. All Rights Reserved. The term +* “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. +*/ + +#ifndef __EFC_H__ +#define __EFC_H__ + +#include "../include/efc_common.h" +#include "efclib.h" +#include "efc_sm.h" +#include "efc_cmds.h" +#include "efc_domain.h" +#include "efc_nport.h" +#include "efc_node.h" +#include "efc_fabric.h" +#include "efc_device.h" +#include "efc_els.h" + +#define EFC_MAX_REMOTE_NODES 2048 +#define NODE_SPARAMS_SIZE 256 + +enum efc_hw_rtn { +EFC_HW_RTN_SUCCESS =0 , +EFC_HW_RTN_SUCCESS_SYNC =1 , +EFC_HW_RTN_ERROR =-1 , +EFC_HW_RTN_NO_RESOURCES =-2 , +EFC_HW_RTN_NO_MEMORY =-3 , +EFC_HW_RTN_IO_NOT_ACTIVE =-4 , +EFC_HW_RTN_IO_ABORT_IN_PROGRESS =-5 , +EFC_HW_RTN_IO_PORT_OWNED_ALREADY_ABORTED =-6 , +EFC_HW_RTN_INVALID_ARG =-7 , +}; + +#define EFC_HW_RTN_IS_ERROR (e) ((e) < 0) + +enum efc_scsi_del_initiator_reason { +EFC_SCSI_INITIATOR_DELETED , +EFC_SCSI_INITIATOR_MISSING , +}; + +enum efc_scsi_del_target_reason { +EFC_SCSI_TARGET_DELETED , +EFC_SCSI_TARGET_MISSING , +}; + +#define EFC_SCSI_CALL_COMPLETE 0 +#define EFC_SCSI_CALL_ASYNC 1 + +#define EFC_FC_ELS_DEFAULT_RETRIES 3 + +#define domain_sm_trace (domain) \ + efc_log_debug(domain->efc, "[domain:%s] %-20s %-20s\n", \ + domain->display_name, __func__, efc_sm_event_name(evt)) \ + +#define domain_trace (domain, fmt, ...) \ + efc_log_debug(domain->efc, \ + "[%s]" fmt, domain->display_name, ##__VA_ARGS__) \ + +#define node_sm_trace () \ + efc_log_debug(node->efc, "[%s] %-20s %-20s\n", \ + node->display_name, __func__, efc_sm_event_name(evt)) \ + +#define nport_sm_trace (nport) \ + efc_log_debug(nport->efc, \ + "[%s] %-20s\n", nport->display_name, efc_sm_event_name(evt)) \ + +#endif /* __EFC_H__ */ drivers/scsi/elx/libefc/efclib.c new file +81
-0@@ -0,0 +1,81 @@ +// SPDX-License-Identifier: GPL-2.0 +/* +* Copyright (C) 2021 Broadcom. All Rights Reserved. The term +* “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. +*/ + +/* +* LIBEFC LOCKING +* +* The critical sections protected by the efc's spinlock are quite broad and +* may be improved upon in the future. The libefc code and its locking doesn't +* influence the I/O path, so excessive locking doesn't impact I/O performance. +* +* The strategy is to lock whenever processing a request from user driver. This +* means that the entry points into the libefc library are protected by efc +* lock. So all the state machine transitions are protected. +*/ + +#include <linux/module.h> +#include <linux/kernel.h> +#include "efc.h" + +int efcport_init (struct efc *efc) +{ +u32 rc =EFC_SUCCESS ; + +spin_lock_init (&efc->lock); +INIT_LIST_HEAD (&efc->vport_list); + efc->hold_frames = false; +spin_lock_init (&efc->pend_frames_lock); +INIT_LIST_HEAD (&efc->pend_frames); + +/* Create Node pool */ + efc->node_pool =mempool_create_kmalloc_pool (EFC_MAX_REMOTE_NODES , +sizeof (struct efc_node )); +if (!efc->node_pool) { +efc_log_err (efc,"Can't allocate node pool\n" ); +return EFC_FAIL ; + } + + efc->node_dma_pool =dma_pool_create ("node_dma_pool" , &efc->pci->dev, +NODE_SPARAMS_SIZE ,0 ,0 ); +if (!efc->node_dma_pool) { +efc_log_err (efc,"Can't allocate node dma pool\n" ); +mempool_destroy (efc->node_pool); +return EFC_FAIL ; + } + + efc->els_io_pool =mempool_create_kmalloc_pool (EFC_ELS_IO_POOL_SZ , +sizeof (struct efc_els_io_req )); +if (!efc->els_io_pool) { +efc_log_err (efc,"Can't allocate els io pool\n" ); +return EFC_FAIL ; + } + +return rc; +} + +static void +efc_purge_pending (struct efc *efc) +{ +struct efc_hw_sequence *frame, *next; +unsigned long flags =0 ; + +spin_lock_irqsave (&efc->pend_frames_lock, flags); + +list_for_each_entry_safe (frame, next, &efc->pend_frames, list_entry) { +list_del (&frame->list_entry); + efc->tt.hw_seq_free (efc, frame); + } + +spin_unlock_irqrestore (&efc->pend_frames_lock, flags); +} + +void efcport_destroy (struct efc *efc) +{ +efc_purge_pending (efc); +mempool_destroy (efc->els_io_pool); +mempool_destroy (efc->node_pool); +dma_pool_destroy (efc->node_dma_pool); +}drivers/scsi/elx/libefc/efclib.h new file +126
-0@@ -0,0 +1,601 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* +* Copyright (C) 2021 Broadcom. All Rights Reserved. The term +* “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. +*/ + +#ifndef __EFCLIB_H__ +#define __EFCLIB_H__ + +#include "scsi/fc/fc_els.h" +#include "scsi/fc/fc_fs.h" +#include "scsi/fc/fc_ns.h" +#include "scsi/fc/fc_gs.h" +#include "scsi/fc_frame.h" +#include "../include/efc_common.h" +#include "../libefc_sli/sli4.h" + +#define EFC_SERVICE_PARMS_LENGTH 120 +#define EFC_NAME_LENGTH 32 +#define EFC_SM_NAME_LENGTH 64 +#define EFC_DISPLAY_BUS_INFO_LENGTH 16 + +#define EFC_WWN_LENGTH 32 + +#define EFC_FC_ELS_DEFAULT_RETRIES 3 + +/* Timeouts */ +#define EFC_FC_ELS_SEND_DEFAULT_TIMEOUT 0 +#define EFC_FC_FLOGI_TIMEOUT_SEC 5 +#define EFC_SHUTDOWN_TIMEOUT_USEC 30000000 + +/* Local port topology */ +enum efc_nport_topology { + EFC_NPORT_TOPO_UNKNOWN = 0, + EFC_NPORT_TOPO_FABRIC, + EFC_NPORT_TOPO_P2P, + EFC_NPORT_TOPO_FC_AL, +}; + +#define enable_target_rscn(efc) 1 + +enum efc_node_shutd_rsn { + EFC_NODE_SHUTDOWN_DEFAULT = 0, + EFC_NODE_SHUTDOWN_EXPLICIT_LOGO, + EFC_NODE_SHUTDOWN_IMPLICIT_LOGO, +}; + +enum efc_node_send_ls_acc { + EFC_NODE_SEND_LS_ACC_NONE = 0, + EFC_NODE_SEND_LS_ACC_PLOGI, + EFC_NODE_SEND_LS_ACC_PRLI, +}; + +#define EFC_LINK_STATUS_UP 0 +#define EFC_LINK_STATUS_DOWN 1 + +/* State machine context header */ +struct efc_sm_ctx { + void (*current_state)(struct efc_sm_ctx *ctx, + u32 evt, void *arg); + + const char *description; + void *app; +}; + +/* Description of discovered Fabric Domain */ +struct efc_domain_record { + u32 index; + u32 priority; + u8 address[6]; + u8 wwn[8]; + union { + u8 vlan[512]; + u8 loop[128]; + } map; + u32 speed; + u32 fc_id; + bool is_loop; + bool is_nport; +}; + +/* Domain events */ +enum efc_hw_domain_event { + EFC_HW_DOMAIN_ALLOC_OK, + EFC_HW_DOMAIN_ALLOC_FAIL, + EFC_HW_DOMAIN_ATTACH_OK, + EFC_HW_DOMAIN_ATTACH_FAIL, + EFC_HW_DOMAIN_FREE_OK, + EFC_HW_DOMAIN_FREE_FAIL, + EFC_HW_DOMAIN_LOST, + EFC_HW_DOMAIN_FOUND, + EFC_HW_DOMAIN_CHANGED, +}; + +struct efc_nport { + struct list_head list_entry; + struct kref ref; + void (*release)(struct kref *arg); + struct efc *efc; + u32 tgt_id; + u32 index; + u32 instance_index; + char display_name[EFC_NAME_LENGTH]; + bool is_vport; + bool free_req_pending; + bool attached; + bool p2p_winner; + struct efc_domain *domain; + u64 wwpn; + u64 wwnn; + void *ini_nport; + void *tgt_nport; + void *tgt_data; + void *ini_data; + + /* Members private to HW/SLI */ + void *hw; + u32 indicator; + u32 fc_id; + struct efc_dma dma; + + u8 wwnn_str[EFC_WWN_LENGTH]; + __be64 sli_wwpn; + __be64 sli_wwnn; + + struct efc_sm_ctx sm;
drivers/scsi/elx/libefc/efclib.h line 136
Quoted 10 lines
drivers/scsi/elx/libefc/efclib.h new file +10
-0+struct xarray lookup; +bool enable_ini; +bool enable_tgt; +bool enable_rscn; +bool shutting_down; +u32 p2p_port_id; +enum efc_nport_topology topology; +u8 service_params[EFC_SERVICE_PARMS_LENGTH ]; +u32 p2p_remote_port_id; +};
Why is 'struct efc_nport' not documented?
Everything below is ...
Quoted 275 lines
drivers/scsi/elx/libefc/efclib.h new file +275
-0+ +/** +* Fibre Channel domain object +* +* This object is a container for the various SLI components needed +* to connect to the domain of a FC or FCoE switch +* @efc: pointer back to efc +* @instance_index: unique instance index value +* @display_name: Node display name +* @nport_list: linked list of nports associated with this domain +* @ref: Reference count, each nport takes a reference +* @release: Function to free domain object +* @ini_domain: initiator backend private domain data +* @tgt_domain: target backend private domain data +* @hw: pointer to HW +* @sm: state machine context +* @fcf: FC Forwarder table index +* @fcf_indicator: FCFI +* @indicator: VFI +* @nport_count: Number of nports allocated +* @dma: memory for Service Parameters +* @fcf_wwn: WWN for FCF/switch +* @drvsm: driver domain sm context +* @attached: set true after attach completes +* @is_fc: is FC +* @is_loop: is loop topology +* @is_nlport: is public loop +* @domain_found_pending:A domain found is pending, drec is updated +* @req_domain_free: True if domain object should be free'd +* @req_accept_frames: set in domain state machine to enable frames +* @domain_notify_pend: Set in domain SM to avoid duplicate node event post +* @pending_drec: Pending drec if a domain found is pending +* @service_params: any nports service parameters +* @flogi_service_params:Fabric/P2p service parameters from FLOGI +* @lookup: d_id to node lookup object +* @nport: Pointer to first (physical) SLI port +*/ +struct efc_domain { +struct efc *efc; +char display_name[EFC_NAME_LENGTH ]; +struct list_head nport_list; +struct kref ref; +void (*release)(struct kref *arg); +void *ini_domain; +void *tgt_domain; + +/* Declarations private to HW/SLI */ +void *hw; +u32 fcf; +u32 fcf_indicator; +u32 indicator; +u32 nport_count; +struct efc_dma dma; + +/* Declarations private to FC trannport */ +u64 fcf_wwn; +struct efc_sm_ctx drvsm; +bool attached; +bool is_fc; +bool is_loop; +bool is_nlport; +bool domain_found_pending; +bool req_domain_free; +bool req_accept_frames; +bool domain_notify_pend; + +struct efc_domain_record pending_drec; +u8 service_params[EFC_SERVICE_PARMS_LENGTH ]; +u8 flogi_service_params[EFC_SERVICE_PARMS_LENGTH ]; + +struct xarray lookup; + +struct efc_nport *nport; +}; + +/** +* Remote Node object +* +* This object represents a connection between the SLI port and another +* Nx_Port on the fabric. Note this can be either a well known port such +* as a F_Port (i.e. ff:ff:fe) or another N_Port. +* @indicator: RPI +* @fc_id: FC address +* @attached: true if attached +* @nport: associated SLI port +* @node: associated node +*/ +struct efc_remote_node { +u32 indicator; +u32 index; +u32 fc_id; + +bool attached; + +struct efc_nport *nport; +void *node; +}; + +/** +* FC Node object +* @efc: pointer back to efc structure +* @display_name: Node display name +* @nort: Assosiated nport pointer. +* @hold_frames: hold incoming frames if true +* @els_io_enabled: Enable allocating els ios for this node +* @els_ios_lock: lock to protect the els ios list +* @els_ios_list: ELS I/O's for this node +* @ini_node: backend initiator private node data +* @tgt_node: backend target private node data +* @rnode: Remote node +* @sm: state machine context +* @evtdepth: current event posting nesting depth +* @req_free: this node is to be free'd +* @attached: node is attached (REGLOGIN complete) +* @fcp_enabled: node is enabled to handle FCP +* @rscn_pending: for name server node RSCN is pending +* @send_plogi: send PLOGI accept, upon completion of node attach +* @send_plogi_acc: TRUE if io_alloc() is enabled. +* @send_ls_acc: type of LS acc to send +* @ls_acc_io: SCSI IO for LS acc +* @ls_acc_oxid: OX_ID for pending accept +* @ls_acc_did: D_ID for pending accept +* @shutdown_reason: reason for node shutdown +* @sparm_dma_buf: service parameters buffer +* @service_params: plogi/acc frame from remote device +* @pend_frames_lock: lock for inbound pending frames list +* @pend_frames: inbound pending frames list +* @pend_frames_processed:count of frames processed in hold frames interval +* @ox_id_in_use: used to verify one at a time us of ox_id +* @els_retries_remaining:for ELS, number of retries remaining +* @els_req_cnt: number of outstanding ELS requests +* @els_cmpl_cnt: number of outstanding ELS completions +* @abort_cnt: Abort counter for debugging purpos +* @current_state_name: current node state +* @prev_state_name: previous node state +* @current_evt: current event +* @prev_evt: previous event +* @targ: node is target capable +* @init: node is init capable +* @refound: Handle node refound case when node is being deleted +* @els_io_pend_list: list of pending (not yet processed) ELS IOs +* @els_io_active_list: list of active (processed) ELS IOs +* @nodedb_state: Node debugging, saved state +* @gidpt_delay_timer: GIDPT delay timer +* @time_last_gidpt_msec:Start time of last target RSCN GIDPT +* @wwnn: remote port WWNN +* @wwpn: remote port WWPN +*/ +struct efc_node { +struct efc *efc; +char display_name[EFC_NAME_LENGTH ]; +struct efc_nport *nport; +struct kref ref; +void (*release)(struct kref *arg); +bool hold_frames; +bool els_io_enabled; +bool send_plogi_acc; +bool send_plogi; +bool rscn_pending; +bool fcp_enabled; +bool attached; +bool req_free; + +spinlock_t els_ios_lock; +struct list_head els_ios_list; +void *ini_node; +void *tgt_node; + +struct efc_remote_node rnode; +/* Declarations private to FC trannport */ +struct efc_sm_ctx sm; +u32 evtdepth; + +enum efc_node_send_ls_acc send_ls_acc; +void *ls_acc_io; +u32 ls_acc_oxid; +u32 ls_acc_did; +enum efc_node_shutd_rsn shutdown_reason; +bool targ; +bool init; +bool refound; +struct efc_dma sparm_dma_buf; +u8 service_params[EFC_SERVICE_PARMS_LENGTH ]; +spinlock_t pend_frames_lock; +struct list_head pend_frames; +u32 pend_frames_processed; +u32 ox_id_in_use; +u32 els_retries_remaining; +u32 els_req_cnt; +u32 els_cmpl_cnt; +u32 abort_cnt; + +char current_state_name[EFC_SM_NAME_LENGTH ]; +char prev_state_name[EFC_SM_NAME_LENGTH ]; +int current_evt; +int prev_evt; + +void (*nodedb_state)(struct efc_sm_ctx *ctx, +u32 evt,void *arg); +struct timer_list gidpt_delay_timer; +u64 time_last_gidpt_msec; + +char wwnn[EFC_WWN_LENGTH ]; +char wwpn[EFC_WWN_LENGTH ]; +}; + +/** +* NPIV port +* +* Collection of the information required to restore a virtual port across +* link events +* @wwnn: node name +* @wwpn: port name +* @fc_id: port id +* @tgt_data: target backend pointer +* @ini_data: initiator backend pointe +* @nport: Used to match record after attaching for update +* +*/ + +struct efc_vport { +struct list_head list_entry; +u64 wwnn; +u64 wwpn; +u32 fc_id; +bool enable_tgt; +bool enable_ini; +void *tgt_data; +void *ini_data; +struct efc_nport *nport; +}; + +#define node_printf(node, fmt, args...) \ + efc_log_info(node->efc, "[%s] " fmt, node->display_name, ##args) + +/* Node SM IO Context Callback structure */ +struct efc_node_cb { +int status; +int ext_status; +struct efc_hw_rq_buffer *header; +struct efc_hw_rq_buffer *payload; +struct efc_dma els_rsp; + +/* Actual length of data received */ +int rsp_len; +}; + +/* HW unsolicited callback status */ +enum efc_hw_unsol_status { +EFC_HW_UNSOL_SUCCESS , +EFC_HW_UNSOL_ERROR , +EFC_HW_UNSOL_ABTS_RCVD , +EFC_HW_UNSOL_MAX ,/**< must be last */ +}; + +enum efc_hw_rq_buffer_type { +EFC_HW_RQ_BUFFER_TYPE_HDR , +EFC_HW_RQ_BUFFER_TYPE_PAYLOAD , +EFC_HW_RQ_BUFFER_TYPE_MAX , +}; + +struct efc_hw_rq_buffer { +u16 rqindex; +struct efc_dma dma; +}; + +/* +* Defines a general FC sequence object, +* consisting of a header, payload buffers +* and a HW IO in the case of port owned XRI +*/ +struct efc_hw_sequence { +struct list_head list_entry; +void *hw; +u8 fcfi;
drivers/scsi/elx/libefc/efclib.h line 421
Quoted 10 lines
drivers/scsi/elx/libefc/efclib.h new file +10
-0+u8 auto_xrdy; +u8 out_of_xris; +enum efc_hw_unsol_status status; + +struct efc_hw_rq_buffer *header; +struct efc_hw_rq_buffer *payload; + +void *hw_priv; +}; +
Shouldn't the comment be in kernel-doc format?
Cheers,
Hannes
Signature · 4 lines
Dr. Hannes Reinecke Kernel Storage Architect [email protected] +49 911 74053 688 SUSE Software Solutions Germany GmbH, 90409 Nürnberg GF: F. Imendörffer, HRB 36809 (AG Nürnberg)
PATCH v8 10/31 elx: libefc: FC Domain state machine interfaces
In reply to James SmartThis patch continues the libefc library population.
This patch adds library interface definitions for:
- FC Domain registration, allocation and deallocation sequence
---
v8:efc_vport naming changes
--- drivers/scsi/elx/libefc/efc_domain.c | 1093 ++++++++++++++++++++++++++ drivers/scsi/elx/libefc/efc_domain.h | 54 ++ 2 files changed, 1147 insertions(+) create mode 100644 drivers/scsi/elx/libefc/efc_domain.c create mode 100644 drivers/scsi/elx/libefc/efc_domain.h
drivers/scsi/elx/libefc/efc_domain.c new file +1093 -0
@@ -0,0 +1,1093 @@ +// SPDX-License-Identifier: GPL-2.0 +/* +* Copyright (C) 2021 Broadcom. All Rights Reserved. The term +* “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. +*/ + +/* +* domain_sm Domain State Machine: States +*/ + +#include "efc.h" + +int +efc_domain_cb (void *arg,int event,void *data) +{ +struct efc *efc = arg; +struct efc_domain *domain =NULL ; +int rc =0 ; +unsigned long flags =0 ; + +if (event !=EFC_HW_DOMAIN_FOUND ) + domain = data; + +/* Accept domain callback events from the user driver */ +spin_lock_irqsave (&efc->lock, flags); +switch (event) { +case EFC_HW_DOMAIN_FOUND : { +u64 fcf_wwn =0 ; +struct efc_domain_record *drec = data; + +/* extract the fcf_wwn */ + fcf_wwn =be64_to_cpu (*((__be64 *)drec->wwn)); + +efc_log_debug (efc,"Domain found: wwn %016llX\n" , fcf_wwn); + +/* lookup domain, or allocate a new one */ + domain = efc->domain; +if (!domain) { + domain =efc_domain_alloc (efc, fcf_wwn); +if (!domain) { +efc_log_err (efc,"efc_domain_alloc() failed\n" ); + rc =-1 ; +break ; + } +efc_sm_transition (&domain->drvsm, __efc_domain_init, +NULL ); + } +efc_domain_post_event (domain,EFC_EVT_DOMAIN_FOUND , drec); +break ; + } + +case EFC_HW_DOMAIN_LOST : +domain_trace (domain,"EFC_HW_DOMAIN_LOST:\n" ); + efc->hold_frames = true; +efc_domain_post_event (domain,EFC_EVT_DOMAIN_LOST ,NULL ); +break ; + +case EFC_HW_DOMAIN_ALLOC_OK : +domain_trace (domain,"EFC_HW_DOMAIN_ALLOC_OK:\n" ); +efc_domain_post_event (domain,EFC_EVT_DOMAIN_ALLOC_OK ,NULL ); +break ; + +case EFC_HW_DOMAIN_ALLOC_FAIL : +domain_trace (domain,"EFC_HW_DOMAIN_ALLOC_FAIL:\n" ); +efc_domain_post_event (domain,EFC_EVT_DOMAIN_ALLOC_FAIL , +NULL ); +break ; + +case EFC_HW_DOMAIN_ATTACH_OK : +domain_trace (domain,"EFC_HW_DOMAIN_ATTACH_OK:\n" ); +efc_domain_post_event (domain,EFC_EVT_DOMAIN_ATTACH_OK ,NULL ); +break ; + +case EFC_HW_DOMAIN_ATTACH_FAIL : +domain_trace (domain,"EFC_HW_DOMAIN_ATTACH_FAIL:\n" ); +efc_domain_post_event (domain, +EFC_EVT_DOMAIN_ATTACH_FAIL ,NULL ); +break ; + +case EFC_HW_DOMAIN_FREE_OK : +domain_trace (domain,"EFC_HW_DOMAIN_FREE_OK:\n" ); +efc_domain_post_event (domain,EFC_EVT_DOMAIN_FREE_OK ,NULL ); +break ; + +case EFC_HW_DOMAIN_FREE_FAIL : +domain_trace (domain,"EFC_HW_DOMAIN_FREE_FAIL:\n" ); +efc_domain_post_event (domain,EFC_EVT_DOMAIN_FREE_FAIL ,NULL ); +break ; + +default : +efc_log_warn (efc,"unsupported event %#x\n" , event); + } +spin_unlock_irqrestore (&efc->lock, flags); + +if (efc->domain && domain->req_accept_frames) { + domain->req_accept_frames = false; + efc->hold_frames = false; + } + +return rc; +} + +static void +_efc_domain_free (struct kref *arg) +{ + struct efc_domain *domain = container_of(arg, struct efc_domain, ref); +struct efc *efc = domain->efc; + +if (efc->domain_free_cb) + (*efc->domain_free_cb)(efc, efc->domain_free_cb_arg); + +kfree (domain); +} + +void +efc_domain_free (struct efc_domain *domain) +{ +struct efc *efc; + + efc = domain->efc; + +/* Hold frames to clear the domain pointer from the xport lookup */ + efc->hold_frames = false; + +efc_log_debug (efc,"Domain free: wwn %016llX\n" , domain->fcf_wwn); + +xa_destroy (&domain->lookup); + efc->domain =NULL ; +kref_put (&domain->ref, domain->release); +} + +struct efc_domain * +efc_domain_alloc (struct efc *efc,uint64_t fcf_wwn) +{ +struct efc_domain *domain; + + domain =kzalloc (sizeof (*domain),GFP_ATOMIC ); +if (!domain) +return NULL ; + + domain->efc = efc; + domain->drvsm.app = domain; + +/* initialize refcount */ +kref_init (&domain->ref); + domain->release = _efc_domain_free; + +xa_init (&domain->lookup); + +INIT_LIST_HEAD (&domain->nport_list); + efc->domain = domain; + domain->fcf_wwn = fcf_wwn; +efc_log_debug (efc,"Domain allocated: wwn %016llX\n" , domain->fcf_wwn); + +return domain; +} + +void +efc_register_domain_free_cb (struct efc *efc, +void (*callback)(struct efc *efc,void *arg), +void *arg) +{ +/* Register a callback to be called when the domain is freed */ + efc->domain_free_cb = callback; + efc->domain_free_cb_arg = arg; +if (!efc->domain && callback) + (*callback)(efc, arg); +} + +static void +__efc_domain_common (const char *funcname,struct efc_sm_ctx *ctx, +enum efc_sm_event evt,void *arg) +{ +struct efc_domain *domain = ctx->app; + +switch (evt) { +case EFC_EVT_ENTER : +case EFC_EVT_REENTER : +case EFC_EVT_EXIT : +case EFC_EVT_ALL_CHILD_NODES_FREE : +/* +* this can arise if an FLOGI fails on the NPORT, +* and the NPORT is shutdown +*/ +break ; +default : +efc_log_warn (domain->efc,"%-20s %-20s not handled\n" , + funcname,efc_sm_event_name (evt)); + } +} + +static void +__efc_domain_common_shutdown (const char *funcname,struct efc_sm_ctx *ctx, +enum efc_sm_event evt,void *arg) +{ +struct efc_domain *domain = ctx->app; + +switch (evt) { +case EFC_EVT_ENTER : +case EFC_EVT_REENTER : +case EFC_EVT_EXIT : +break ; +case EFC_EVT_DOMAIN_FOUND : +/* save drec, mark domain_found_pending */ +memcpy (&domain->pending_drec, arg, +sizeof (domain->pending_drec)); + domain->domain_found_pending = true; +break ; +case EFC_EVT_DOMAIN_LOST : +/* unmark domain_found_pending */ + domain->domain_found_pending = false; +break ; + +default : +efc_log_warn (domain->efc,"%-20s %-20s not handled\n" , + funcname,efc_sm_event_name (evt)); + } +} + +#define std_domain_state_decl (...)\ + struct efc_domain *domain = NULL;\ + struct efc *efc = NULL;\ + \ + WARN_ON(!ctx || !ctx->app);\ + domain = ctx->app;\ + WARN_ON(!domain->efc);\ + efc = domain->efc + +void +__efc_domain_init (struct efc_sm_ctx *ctx,enum efc_sm_event evt, +void *arg) +{ +std_domain_state_decl (); + +domain_sm_trace (domain); + +switch (evt) { +case EFC_EVT_ENTER : + domain->attached = false; +break ; + +case EFC_EVT_DOMAIN_FOUND : { +u32 i; +struct efc_domain_record *drec = arg; +struct efc_nport *nport; + +u64 my_wwnn = efc->req_wwnn; +u64 my_wwpn = efc->req_wwpn; +__be64 bewwpn; + +if (my_wwpn ==0 || my_wwnn ==0 ) { +efc_log_debug (efc, +"using default hardware WWN configuration\n" ); + my_wwpn = efc->def_wwpn; + my_wwnn = efc->def_wwnn; + } + +efc_log_debug (efc, +"Creating base nport using WWPN %016llX WWNN %016llX\n" , + my_wwpn, my_wwnn); + +/* Allocate a nport and transition to __efc_nport_allocated */ + nport =efc_nport_alloc (domain, my_wwpn, my_wwnn,U32_MAX , + efc->enable_ini, efc->enable_tgt); + +if (!nport) { +efc_log_err (efc,"efc_nport_alloc() failed\n" ); +break ; + } +efc_sm_transition (&nport->sm, __efc_nport_allocated,NULL ); + + bewwpn =cpu_to_be64 (nport->wwpn); + +/* allocate struct efc_nport object for local port +* Note: drec->fc_id is ALPA from read_topology only if loop +*/ +if (efc_cmd_nport_alloc (efc, nport,NULL , (uint8_t *)&bewwpn)) { +efc_log_err (efc,"Can't allocate port\n" ); +efc_nport_free (nport); +break ; + } + + domain->is_loop = drec->is_loop; + +/* +* If the loop position map includes ALPA == 0, +* then we are in a public loop (NL_PORT) +* Note that the first element of the loopmap[] +* contains the count of elements, and if +* ALPA == 0 is present, it will occupy the first +* location after the count. +*/ + domain->is_nlport = drec->map.loop[1 ] ==0x00 ; + +if (!domain->is_loop) { +/* Initiate HW domain alloc */ +if (efc_cmd_domain_alloc (efc, domain, drec->index)) { +efc_log_err (efc, +"Failed to initiate HW domain allocation\n" ); +break ; + } +efc_sm_transition (ctx, __efc_domain_wait_alloc, arg); +break ; + } + +efc_log_debug (efc,"%s fc_id=%#x speed=%d\n" , + drec->is_loop ? + (domain->is_nlport ? +"public-loop" :"loop" ) :"other" , + drec->fc_id, drec->speed); + + nport->fc_id = drec->fc_id; + nport->topology =EFC_NPORT_TOPO_FC_AL ; +snprintf (nport->display_name,sizeof (nport->display_name), +"s%06x" , drec->fc_id); + +if (efc->enable_ini) { +u32 count = drec->map.loop[0 ]; + +efc_log_debug (efc,"%d position map entries\n" , + count); +for (i =1 ; i <= count; i++) { +if (drec->map.loop[i] != drec->fc_id) { +struct efc_node *node; + +efc_log_debug (efc,"%#x -> %#x\n" , + drec->fc_id, + drec->map.loop[i]); + node =efc_node_alloc (nport, + drec->map.loop[i], + false, true); +if (!node) { +efc_log_err (efc, +"efc_node_alloc() failed\n" ); +break ; + } +efc_node_transition (node, + __efc_d_wait_loop, +NULL ); + } + } + } + +/* Initiate HW domain alloc */ +if (efc_cmd_domain_alloc (efc, domain, drec->index)) { +efc_log_err (efc, +"Failed to initiate HW domain allocation\n" ); +break ; + } +efc_sm_transition (ctx, __efc_domain_wait_alloc, arg); +break ; + } +default : +__efc_domain_common (__func__, ctx, evt, arg); + } +} + +void +__efc_domain_wait_alloc (struct efc_sm_ctx *ctx, +enum efc_sm_event evt,void *arg) +{ +std_domain_state_decl (); + +domain_sm_trace (domain); + +switch (evt) { +case EFC_EVT_DOMAIN_ALLOC_OK : { +struct fc_els_flogi *sp; +struct efc_nport *nport; + + nport = domain->nport; +if (WARN_ON (!nport)) +return ; + + sp = (struct fc_els_flogi *)nport->service_params; + +/* Save the domain service parameters */ +memcpy (domain->service_params +4 , domain->dma.virt, +sizeof (struct fc_els_flogi ) -4 ); +memcpy (nport->service_params +4 , domain->dma.virt, +sizeof (struct fc_els_flogi ) -4 ); + +/* +* Update the nport's service parameters, +* user might have specified non-default names +*/ + sp->fl_wwpn =cpu_to_be64 (nport->wwpn); + sp->fl_wwnn =cpu_to_be64 (nport->wwnn); + +/* +* Take the loop topology path, +* unless we are an NL_PORT (public loop) +*/ +if (domain->is_loop && !domain->is_nlport) { +/* +* For loop, we already have our FC ID +* and don't need fabric login. +* Transition to the allocated state and +* post an event to attach to +* the domain. Note that this breaks the +* normal action/transition +* pattern here to avoid a race with the +* domain attach callback. +*/ +/* sm: is_loop / domain_attach */ +efc_sm_transition (ctx, __efc_domain_allocated,NULL ); +__efc_domain_attach_internal (domain, nport->fc_id); +break ; + } + { +struct efc_node *node; + +/* alloc fabric node, send FLOGI */ + node =efc_node_find (nport,FC_FID_FLOGI ); +if (node) { +efc_log_err (efc, +"Fabric Controller node already exists\n" ); +break ; + } + node =efc_node_alloc (nport,FC_FID_FLOGI , + false, false); +if (!node) { +efc_log_err (efc, +"Error: efc_node_alloc() failed\n" ); + }else { +efc_node_transition (node, + __efc_fabric_init,NULL ); + } +/* Accept frames */ + domain->req_accept_frames = true; + } +/* sm: / start fabric logins */ +efc_sm_transition (ctx, __efc_domain_allocated,NULL ); +break ; + } + +case EFC_EVT_DOMAIN_ALLOC_FAIL : +efc_log_err (efc,"%s recv'd waiting for DOMAIN_ALLOC_OK;" , +efc_sm_event_name (evt)); +efc_log_err (efc,"shutting down domain\n" ); + domain->req_domain_free = true; +break ; + +case EFC_EVT_DOMAIN_FOUND : +/* Should not happen */ +break ; + +case EFC_EVT_DOMAIN_LOST : +efc_log_debug (efc, +"%s received while waiting for hw_domain_alloc()\n" , +efc_sm_event_name (evt)); +efc_sm_transition (ctx, __efc_domain_wait_domain_lost,NULL ); +break ; + +default : +__efc_domain_common (__func__, ctx, evt, arg); + } +} + +void +__efc_domain_allocated (struct efc_sm_ctx *ctx, +enum efc_sm_event evt,void *arg) +{ +std_domain_state_decl (); + +domain_sm_trace (domain); + +switch (evt) { +case EFC_EVT_DOMAIN_REQ_ATTACH : { +int rc =0 ; +u32 fc_id; + +if (WARN_ON (!arg)) +return ; + + fc_id = *((u32 *)arg); +efc_log_debug (efc,"Requesting hw domain attach fc_id x%x\n" , + fc_id); +/* Update nport lookup */ + rc =xa_err (xa_store (&domain->lookup, fc_id, domain->nport, +GFP_ATOMIC )); +if (rc) { +efc_log_err (efc,"Sport lookup store failed: %d\n" , rc); +return ; + } + +/* Update display name for the nport */ +efc_node_fcid_display (fc_id, domain->nport->display_name, +sizeof (domain->nport->display_name)); + +/* Issue domain attach call */ + rc =efc_cmd_domain_attach (efc, domain, fc_id); +if (rc) { +efc_log_err (efc,"efc_hw_domain_attach failed: %d\n" , + rc); +return ; + } +/* sm: / domain_attach */ +efc_sm_transition (ctx, __efc_domain_wait_attach,NULL ); +break ; + } + +case EFC_EVT_DOMAIN_FOUND : +/* Should not happen */ +efc_log_err (efc,"%s: evt: %d should not happen\n" , + __func__, evt); +break ; + +case EFC_EVT_DOMAIN_LOST : { +efc_log_debug (efc, +"%s received while in EFC_EVT_DOMAIN_REQ_ATTACH\n" , +efc_sm_event_name (evt)); +if (!list_empty (&domain->nport_list)) { +/* +* if there are nports, transition to +* wait state and send shutdown to each +* nport +*/ +struct efc_nport *nport =NULL , *nport_next =NULL ; + +efc_sm_transition (ctx, __efc_domain_wait_nports_free, +NULL ); +list_for_each_entry_safe (nport, nport_next, + &domain->nport_list, + list_entry) { +efc_sm_post_event (&nport->sm, +EFC_EVT_SHUTDOWN ,NULL ); + } + }else { +/* no nports exist, free domain */ +efc_sm_transition (ctx, __efc_domain_wait_shutdown, +NULL ); +if (efc_cmd_domain_free (efc, domain)) +efc_log_err (efc,"hw_domain_free failed\n" ); + } + +break ; + } + +default : +__efc_domain_common (__func__, ctx, evt, arg); + } +} + +void +__efc_domain_wait_attach (struct efc_sm_ctx *ctx, +enum efc_sm_event evt,void *arg) +{ +std_domain_state_decl (); + +domain_sm_trace (domain); + +switch (evt) { +case EFC_EVT_DOMAIN_ATTACH_OK : { +struct efc_node *node =NULL ; +struct efc_nport *nport, *next_nport; +unsigned long index; + +/* +* Set domain notify pending state to avoid +* duplicate domain event post +*/ + domain->domain_notify_pend = true; + +/* Mark as attached */ + domain->attached = true; + +/* Transition to ready */ +/* sm: / forward event to all nports and nodes */ +efc_sm_transition (ctx, __efc_domain_ready,NULL ); + +/* We have an FCFI, so we can accept frames */ + domain->req_accept_frames = true; + +/* +* Notify all nodes that the domain attach request +* has completed +* Note: nport will have already received notification +* of nport attached as a result of the HW's port attach. +*/ +list_for_each_entry_safe (nport, next_nport, + &domain->nport_list, list_entry) { +xa_for_each (&nport->lookup, index, node) { +efc_node_post_event (node, +EFC_EVT_DOMAIN_ATTACH_OK , +NULL ); + } + } + domain->domain_notify_pend = false; +break ; + } + +case EFC_EVT_DOMAIN_ATTACH_FAIL : +efc_log_debug (efc, +"%s received while waiting for hw attach\n" , +efc_sm_event_name (evt)); +break ; + +case EFC_EVT_DOMAIN_FOUND : +/* Should not happen */ +efc_log_err (efc,"%s: evt: %d should not happen\n" , + __func__, evt); +break ; + +case EFC_EVT_DOMAIN_LOST : +/* +* Domain lost while waiting for an attach to complete, +* go to a state that waits for the domain attach to +* complete, then handle domain lost +*/ +efc_sm_transition (ctx, __efc_domain_wait_domain_lost,NULL ); +break ; + +case EFC_EVT_DOMAIN_REQ_ATTACH : +/* +* In P2P we can get an attach request from +* the other FLOGI path, so drop this one +*/ +break ; + +default : +__efc_domain_common (__func__, ctx, evt, arg); + } +} + +void +__efc_domain_ready (struct efc_sm_ctx *ctx,enum efc_sm_event evt,void *arg) +{ +std_domain_state_decl (); + +domain_sm_trace (domain); + +switch (evt) { +case EFC_EVT_ENTER : { +/* start any pending vports */ +if (efc_vport_start (domain)) { +efc_log_debug (domain->efc, +"efc_vport_start didn't start vports\n" ); + } +break ; + } +case EFC_EVT_DOMAIN_LOST : { +if (!list_empty (&domain->nport_list)) { +/* +* if there are nports, transition to wait state +* and send shutdown to each nport +*/ +struct efc_nport *nport =NULL , *nport_next =NULL ; + +efc_sm_transition (ctx, __efc_domain_wait_nports_free, +NULL ); +list_for_each_entry_safe (nport, nport_next, + &domain->nport_list, + list_entry) { +efc_sm_post_event (&nport->sm, +EFC_EVT_SHUTDOWN ,NULL ); + } + }else { +/* no nports exist, free domain */ +efc_sm_transition (ctx, __efc_domain_wait_shutdown, +NULL ); +if (efc_cmd_domain_free (efc, domain)) +efc_log_err (efc,"hw_domain_free failed\n" ); + } +break ; + } + +case EFC_EVT_DOMAIN_FOUND : +/* Should not happen */ +efc_log_err (efc,"%s: evt: %d should not happen\n" , + __func__, evt); +break ; + +case EFC_EVT_DOMAIN_REQ_ATTACH : { +/* can happen during p2p */ +u32 fc_id; + + fc_id = *((u32 *)arg); + +/* Assume that the domain is attached */ +WARN_ON (!domain->attached); + +/* +* Verify that the requested FC_ID +* is the same as the one we're working with +*/ +WARN_ON (domain->nport->fc_id != fc_id); +break ; + } + +default : +__efc_domain_common (__func__, ctx, evt, arg); + } +} + +void +__efc_domain_wait_nports_free (struct efc_sm_ctx *ctx,enum efc_sm_event evt, +void *arg) +{ +std_domain_state_decl (); + +domain_sm_trace (domain); + +/* Wait for nodes to free prior to the domain shutdown */ +switch (evt) { +case EFC_EVT_ALL_CHILD_NODES_FREE : { +int rc; + +/* sm: / efc_hw_domain_free */ +efc_sm_transition (ctx, __efc_domain_wait_shutdown,NULL ); + +/* Request efc_hw_domain_free and wait for completion */ + rc =efc_cmd_domain_free (efc, domain); +if (rc) { +efc_log_err (efc,"efc_hw_domain_free() failed: %d\n" , + rc); + } +break ; + } +default : +__efc_domain_common_shutdown (__func__, ctx, evt, arg); + } +} + +void +__efc_domain_wait_shutdown (struct efc_sm_ctx *ctx, +enum efc_sm_event evt,void *arg) +{ +std_domain_state_decl (); + +domain_sm_trace (domain); + +switch (evt) { +case EFC_EVT_DOMAIN_FREE_OK : +/* sm: / domain_free */ +if (domain->domain_found_pending) { +/* +* save fcf_wwn and drec from this domain, +* free current domain and allocate +* a new one with the same fcf_wwn +* could use a SLI-4 "re-register VPI" +* operation here? +*/ +u64 fcf_wwn = domain->fcf_wwn; +struct efc_domain_record drec = domain->pending_drec; + +efc_log_debug (efc,"Reallocating domain\n" ); + domain->req_domain_free = true; + domain =efc_domain_alloc (efc, fcf_wwn); + +if (!domain) { +efc_log_err (efc, +"efc_domain_alloc() failed\n" ); +return ; + } +/* +* got a new domain; at this point, +* there are at least two domains +* once the req_domain_free flag is processed, +* the associated domain will be removed. +*/ +efc_sm_transition (&domain->drvsm, __efc_domain_init, +NULL ); +efc_sm_post_event (&domain->drvsm, +EFC_EVT_DOMAIN_FOUND , &drec); + }else { + domain->req_domain_free = true; + } +break ; +default : +__efc_domain_common_shutdown (__func__, ctx, evt, arg); + } +} + +void +__efc_domain_wait_domain_lost (struct efc_sm_ctx *ctx, +enum efc_sm_event evt,void *arg) +{ +std_domain_state_decl (); + +domain_sm_trace (domain); + +/* +* Wait for the domain alloc/attach completion +* after receiving a domain lost. +*/ +switch (evt) { +case EFC_EVT_DOMAIN_ALLOC_OK : +case EFC_EVT_DOMAIN_ATTACH_OK : { +if (!list_empty (&domain->nport_list)) { +/* +* if there are nports, transition to +* wait state and send shutdown to each nport +*/ +struct efc_nport *nport =NULL , *nport_next =NULL ; + +efc_sm_transition (ctx, __efc_domain_wait_nports_free, +NULL ); +list_for_each_entry_safe (nport, nport_next, + &domain->nport_list, + list_entry) { +efc_sm_post_event (&nport->sm, +EFC_EVT_SHUTDOWN ,NULL ); + } + }else { +/* no nports exist, free domain */ +efc_sm_transition (ctx, __efc_domain_wait_shutdown, +NULL ); +if (efc_cmd_domain_free (efc, domain)) +efc_log_err (efc,"hw_domain_free() failed\n" ); + } +break ; + } +case EFC_EVT_DOMAIN_ALLOC_FAIL : +case EFC_EVT_DOMAIN_ATTACH_FAIL : +efc_log_err (efc,"[domain] %-20s: failed\n" , +efc_sm_event_name (evt)); +break ; + +default : +__efc_domain_common_shutdown (__func__, ctx, evt, arg); + } +} + +void +__efc_domain_attach_internal (struct efc_domain *domain,u32 s_id) +{ +memcpy (domain->dma.virt, + ((uint8_t *)domain->flogi_service_params) +4 , +sizeof (struct fc_els_flogi ) -4 ); + (void )efc_sm_post_event (&domain->drvsm,EFC_EVT_DOMAIN_REQ_ATTACH , + &s_id); +} + +void +efc_domain_attach (struct efc_domain *domain,u32 s_id) +{ +__efc_domain_attach_internal (domain, s_id); +} + +int +efc_domain_post_event (struct efc_domain *domain, +enum efc_sm_event event,void *arg) +{ +int rc; +bool req_domain_free; + + rc =efc_sm_post_event (&domain->drvsm, event, arg); + + req_domain_free = domain->req_domain_free; + domain->req_domain_free = false; + +if (req_domain_free) +efc_domain_free (domain); + +return rc; +} + +static void +efct_domain_process_pending (struct efc_domain *domain) +{ +struct efc *efc = domain->efc; +struct efc_hw_sequence *seq =NULL ; +u32 processed =0 ; +unsigned long flags =0 ; + +for (;;) { +/* need to check for hold frames condition after each frame +* processed because any given frame could cause a transition +* to a state that holds frames +*/ +if (efc->hold_frames) +break ; + +/* Get next frame/sequence */ +spin_lock_irqsave (&efc->pend_frames_lock, flags); + +if (!list_empty (&efc->pend_frames)) { + seq =list_first_entry (&efc->pend_frames, + struct efc_hw_sequence, list_entry); +list_del (&seq->list_entry); + } + +if (!seq) { + processed = efc->pend_frames_processed; + efc->pend_frames_processed =0 ; +spin_unlock_irqrestore (&efc->pend_frames_lock, flags); +break ; + } + efc->pend_frames_processed++; + +spin_unlock_irqrestore (&efc->pend_frames_lock, flags); + +/* now dispatch frame(s) to dispatch function */ +if (efc_domain_dispatch_frame (domain, seq)) + efc->tt.hw_seq_free (efc, seq); + + seq =NULL ; + } + +if (processed !=0 ) +efc_log_debug (efc,"%u domain frames held and processed\n" , + processed); +} + +void +efc_dispatch_frame (struct efc *efc,struct efc_hw_sequence *seq) +{ +struct efc_domain *domain = efc->domain; + +/* +* If we are holding frames or the domain is not yet registered or +* there's already frames on the pending list, +* then add the new frame to pending list +*/ +if (!domain || efc->hold_frames || !list_empty (&efc->pend_frames)) { +unsigned long flags =0 ; + +spin_lock_irqsave (&efc->pend_frames_lock, flags); +INIT_LIST_HEAD (&seq->list_entry); +list_add_tail (&seq->list_entry, &efc->pend_frames); +spin_unlock_irqrestore (&efc->pend_frames_lock, flags); + +if (domain) { +/* immediately process pending frames */ +efct_domain_process_pending (domain); + } + }else { +/* +* We are not holding frames and pending list is empty, +* just process frame. A non-zero return means the frame +* was not handled - so cleanup +*/ +if (efc_domain_dispatch_frame (domain, seq)) + efc->tt.hw_seq_free (efc, seq); + } +} + +int +efc_domain_dispatch_frame (void *arg,struct efc_hw_sequence *seq) +{ +struct efc_domain *domain = (struct efc_domain *)arg; +struct efc *efc = domain->efc; +struct fc_frame_header *hdr; +struct efc_node *node =NULL ; +struct efc_nport *nport =NULL ; +unsigned long flags =0 ; +u32 s_id, d_id, rc =EFC_HW_SEQ_FREE ; + +if (!seq->header || !seq->header->dma.virt || !seq->payload->dma.virt) { +efc_log_err (efc,"Sequence header or payload is null\n" ); +return rc; + } + + hdr = seq->header->dma.virt; + +/* extract the s_id and d_id */ + s_id =ntoh24 (hdr->fh_s_id); + d_id =ntoh24 (hdr->fh_d_id); + +spin_lock_irqsave (&efc->lock, flags); + + nport =efc_nport_find (domain, d_id); +if (!nport) { +if (hdr->fh_type ==FC_TYPE_FCP ) { +/* Drop frame */ +efc_log_warn (efc,"FCP frame with invalid d_id x%x\n" , + d_id); + goto out; + } + +/* p2p will use this case */ + nport = domain->nport; +if (!nport || !kref_get_unless_zero (&nport->ref)) { +efc_log_err (efc,"Physical nport is NULL\n" ); + goto out; + } + } + +/* Lookup the node given the remote s_id */ + node =efc_node_find (nport, s_id); + +/* If not found, then create a new node */ +if (!node) { +/* +* If this is solicited data or control based on R_CTL and +* there is no node context, then we can drop the frame +*/ +if ((hdr->fh_r_ctl ==FC_RCTL_DD_SOL_DATA ) || + (hdr->fh_r_ctl ==FC_RCTL_DD_SOL_CTL )) { +efc_log_debug (efc, +"solicited data/ctrl frame without node,drop\n" ); + goto out_release; + } + + node =efc_node_alloc (nport, s_id, false, false); +if (!node) { +efc_log_err (efc,"efc_node_alloc() failed\n" ); + goto out_release; + } +/* don't send PLOGI on efc_d_init entry */ +efc_node_init_device (node, false); + } + +if (node->hold_frames || !list_empty (&node->pend_frames)) { + +/* add frame to node's pending list */ +spin_lock_irqsave (&node->pend_frames_lock, flags); +INIT_LIST_HEAD (&seq->list_entry); +list_add_tail (&seq->list_entry, &node->pend_frames); +spin_unlock_irqrestore (&node->pend_frames_lock, flags); + rc =EFC_HW_SEQ_HOLD ; + goto out_release; + } + +/* now dispatch frame to the node frame handler */ +efc_node_dispatch_frame (node, seq); + +out_release: +kref_put (&nport->ref, nport->release); +out: +spin_unlock_irqrestore (&efc->lock, flags); +return rc; +} + +void +efc_node_dispatch_frame (void *arg,struct efc_hw_sequence *seq) +{ +struct fc_frame_header *hdr = seq->header->dma.virt; +u32 port_id; +struct efc_node *node = (struct efc_node *)arg; +struct efc *efc = node->efc; + + port_id =ntoh24 (hdr->fh_s_id); + +if (WARN_ON (port_id != node->rnode.fc_id)) +return ; + +if ((!(ntoh24 (hdr->fh_f_ctl) &FC_FC_END_SEQ )) || + !(ntoh24 (hdr->fh_f_ctl) &FC_FC_SEQ_INIT )) { +node_printf (node, +"Dropping frame hdr = %08x %08x %08x %08x %08x %08x\n" , +cpu_to_be32 (((u32 *)hdr)[0 ]), +cpu_to_be32 (((u32 *)hdr)[1 ]), +cpu_to_be32 (((u32 *)hdr)[2 ]), +cpu_to_be32 (((u32 *)hdr)[3 ]), +cpu_to_be32 (((u32 *)hdr)[4 ]), +cpu_to_be32 (((u32 *)hdr)[5 ])); +return ; + } + +switch (hdr->fh_r_ctl) { +case FC_RCTL_ELS_REQ : +case FC_RCTL_ELS_REP : +efc_node_recv_els_frame (node, seq); +break ; + +case FC_RCTL_BA_ABTS : +case FC_RCTL_BA_ACC : +case FC_RCTL_BA_RJT : +case FC_RCTL_BA_NOP : +efc_log_err (efc,"Received ABTS:\n" ); +break ; + +case FC_RCTL_DD_UNSOL_CMD : +case FC_RCTL_DD_UNSOL_CTL : +switch (hdr->fh_type) { +case FC_TYPE_FCP : +if ((hdr->fh_r_ctl &0xf ) ==FC_RCTL_DD_UNSOL_CMD ) { +if (!node->fcp_enabled) { +efc_node_recv_fcp_cmd (node, seq); +break ; + } +efc_log_err (efc, +"Received FCP CMD. Dropping IO\n" ); + }else if ((hdr->fh_r_ctl &0xf ) == +FC_RCTL_DD_SOL_DATA ) { +node_printf (node, +"solicited data received.Dropping IO\n" ); + } +break ; + +case FC_TYPE_CT : +efc_node_recv_ct_frame (node, seq); +break ; +default : +break ; + } +break ; +default : +efc_log_err (efc,"Unhandled frame rctl: %02x\n" , hdr->fh_r_ctl); + } +}
drivers/scsi/elx/libefc/efc_domain.h new file +54 -0
54 lines not on this page · raw message
Signature · 1 line
2.26.2
PATCH v8 11/31 elx: libefc: SLI and FC PORT state machine interfaces
In reply to James SmartThis patch continues the libefc library population.
This patch adds library interface definitions for:
- SLI and FC port (aka n_port_id) registration, allocation and deallocation.
--- drivers/scsi/elx/libefc/efc_nport.c | 792 ++++++++++++++++++++++++++++ drivers/scsi/elx/libefc/efc_nport.h | 50 ++ 2 files changed, 842 insertions(+) create mode 100644 drivers/scsi/elx/libefc/efc_nport.c create mode 100644 drivers/scsi/elx/libefc/efc_nport.h
drivers/scsi/elx/libefc/efc_nport.c new file +792 -0
@@ -0,0 +1,792 @@ +// SPDX-License-Identifier: GPL-2.0 +/* +* Copyright (C) 2021 Broadcom. All Rights Reserved. The term +* “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. +*/ + +/* +* NPORT +* +* Port object for physical port and NPIV ports. +*/ + +/* +* NPORT REFERENCE COUNTING +* +* A nport reference should be taken when: +* - an nport is allocated +* - a vport populates associated nport +* - a remote node is allocated +* - a unsolicited frame is processed +* The reference should be dropped when: +* - the unsolicited frame processesing is done +* - the remote node is removed +* - the vport is removed +* - the nport is removed +*/ + +#include "efc.h" + +void +efc_nport_cb (void *arg,int event,void *data) +{ +struct efc *efc = arg; +struct efc_nport *nport = data; +unsigned long flags =0 ; + +efc_log_debug (efc,"nport event: %s\n" ,efc_sm_event_name (event)); + +spin_lock_irqsave (&efc->lock, flags); +efc_sm_post_event (&nport->sm, event,NULL ); +spin_unlock_irqrestore (&efc->lock, flags); +} + +static struct efc_nport * +efc_nport_find_wwn (struct efc_domain *domain,uint64_t wwnn,uint64_t wwpn) +{ +struct efc_nport *nport =NULL ; + +/* Find a nport, given the WWNN and WWPN */ +list_for_each_entry (nport, &domain->nport_list, list_entry) { +if (nport->wwnn == wwnn && nport->wwpn == wwpn) +return nport; + } +return NULL ; +} + +static void +_efc_nport_free (struct kref *arg) +{ + struct efc_nport *nport = container_of(arg, struct efc_nport, ref); + +kfree (nport); +} + +struct efc_nport * +efc_nport_alloc (struct efc_domain *domain,uint64_t wwpn,uint64_t wwnn, +u32 fc_id,bool enable_ini,bool enable_tgt) +{ +struct efc_nport *nport; + +if (domain->efc->enable_ini) + enable_ini =0 ; + +/* Return a failure if this nport has already been allocated */ +if ((wwpn !=0 ) || (wwnn !=0 )) { + nport =efc_nport_find_wwn (domain, wwnn, wwpn); +if (nport) { +efc_log_err (domain->efc, +"Err: NPORT %016llX %016llX already allocated\n" , + wwnn, wwpn); +return NULL ; + } + } + + nport =kzalloc (sizeof (*nport),GFP_ATOMIC ); +if (!nport) +return nport; + +/* initialize refcount */ +kref_init (&nport->ref); + nport->release = _efc_nport_free; + + nport->efc = domain->efc; +snprintf (nport->display_name,sizeof (nport->display_name),"------" ); + nport->domain = domain; +xa_init (&nport->lookup); + nport->instance_index = domain->nport_count++; + nport->sm.app = nport; + nport->enable_ini = enable_ini; + nport->enable_tgt = enable_tgt; + nport->enable_rscn = (nport->enable_ini || + (nport->enable_tgt &&enable_target_rscn (nport->efc))); + +/* Copy service parameters from domain */ +memcpy (nport->service_params, domain->service_params, +sizeof (struct fc_els_flogi )); + +/* Update requested fc_id */ + nport->fc_id = fc_id; + +/* Update the nport's service parameters for the new wwn's */ + nport->wwpn = wwpn; + nport->wwnn = wwnn; +snprintf (nport->wwnn_str,sizeof (nport->wwnn_str),"%016llX" , + (unsigned long long )wwnn); + +/* +* if this is the "first" nport of the domain, +* then make it the "phys" nport +*/ +if (list_empty (&domain->nport_list)) + domain->nport = nport; + +INIT_LIST_HEAD (&nport->list_entry); +list_add_tail (&nport->list_entry, &domain->nport_list); + +kref_get (&domain->ref); + +efc_log_debug (domain->efc,"New Nport [%s]\n" , nport->display_name); + +return nport; +} + +void +efc_nport_free (struct efc_nport *nport) +{ +struct efc_domain *domain; + +if (!nport) +return ; + + domain = nport->domain; +efc_log_debug (domain->efc,"[%s] free nport\n" , nport->display_name); +list_del (&nport->list_entry); +/* +* if this is the physical nport, +* then clear it out of the domain +*/ +if (nport == domain->nport) + domain->nport =NULL ; + +xa_destroy (&nport->lookup); +xa_erase (&domain->lookup, nport->fc_id); + +if (list_empty (&domain->nport_list)) +efc_domain_post_event (domain,EFC_EVT_ALL_CHILD_NODES_FREE , +NULL ); + +kref_put (&domain->ref, domain->release); +kref_put (&nport->ref, nport->release); + +} + +struct efc_nport * +efc_nport_find (struct efc_domain *domain,u32 d_id) +{ +struct efc_nport *nport; + +/* Find a nport object, given an FC_ID */ + nport =xa_load (&domain->lookup, d_id); +if (!nport || !kref_get_unless_zero (&nport->ref)) +return NULL ; + +return nport; +} + +int +efc_nport_attach (struct efc_nport *nport,u32 fc_id) +{ +int rc; +struct efc_node *node; +struct efc *efc = nport->efc; +unsigned long index; + +/* Set our lookup */ + rc =xa_err (xa_store (&nport->domain->lookup, fc_id, nport,GFP_ATOMIC )); +if (rc) { +efc_log_err (efc,"Sport lookup store failed: %d\n" , rc); +return rc; + } + +/* Update our display_name */ +efc_node_fcid_display (fc_id, nport->display_name, +sizeof (nport->display_name)); + +xa_for_each (&nport->lookup, index, node) { +efc_node_update_display_name (node); + } + +efc_log_debug (nport->efc,"[%s] attach nport: fc_id x%06x\n" , + nport->display_name, fc_id); + +/* Register a nport, given an FC_ID */ + rc =efc_cmd_nport_attach (efc, nport, fc_id); +if (rc !=EFC_HW_RTN_SUCCESS ) { +efc_log_err (nport->efc, +"efc_hw_port_attach failed: %d\n" , rc); +return EFC_FAIL ; + } +return EFC_SUCCESS ; +} + +static void +efc_nport_shutdown (struct efc_nport *nport) +{ +struct efc *efc = nport->efc; +struct efc_node *node; +unsigned long index; + +xa_for_each (&nport->lookup, index, node) { +if (!(node->rnode.fc_id ==FC_FID_FLOGI && nport->is_vport)) { +efc_node_post_event (node,EFC_EVT_SHUTDOWN ,NULL ); +continue ; + } + +/* +* If this is a vport, logout of the fabric +* controller so that it deletes the vport +* on the switch. +*/ +/* if link is down, don't send logo */ +if (efc->link_status ==EFC_LINK_STATUS_DOWN ) { +efc_node_post_event (node,EFC_EVT_SHUTDOWN ,NULL ); +continue ; + } + +efc_log_debug (efc,"[%s] nport shutdown vport, send logo\n" , + node->display_name); + +if (!efc_send_logo (node)) { +/* sent LOGO, wait for response */ +efc_node_transition (node, __efc_d_wait_logo_rsp,NULL ); +continue ; + } + +/* +* failed to send LOGO, +* go ahead and cleanup node anyways +*/ +node_printf (node,"Failed to send LOGO\n" ); +efc_node_post_event (node,EFC_EVT_SHUTDOWN_EXPLICIT_LOGO ,NULL ); + } +} + +static void +efc_vport_link_down (struct efc_nport *nport) +{ +struct efc *efc = nport->efc; +struct efc_vport *vport; + +/* Clear the nport reference in the vport specification */ +list_for_each_entry (vport, &efc->vport_list, list_entry) { +if (vport->nport == nport) { +kref_put (&nport->ref, nport->release); + vport->nport =NULL ; +break ; + } + } +} + +static void +__efc_nport_common (const char *funcname,struct efc_sm_ctx *ctx, +enum efc_sm_event evt,void *arg) +{ +struct efc_nport *nport = ctx->app; +struct efc_domain *domain = nport->domain; +struct efc *efc = nport->efc; + +switch (evt) { +case EFC_EVT_ENTER : +case EFC_EVT_REENTER : +case EFC_EVT_EXIT : +case EFC_EVT_ALL_CHILD_NODES_FREE : +break ; +case EFC_EVT_NPORT_ATTACH_OK : +efc_sm_transition (ctx, __efc_nport_attached,NULL ); +break ; +case EFC_EVT_SHUTDOWN : +/* Flag this nport as shutting down */ + nport->shutting_down = true; + +if (nport->is_vport) +efc_vport_link_down (nport); + +if (xa_empty (&nport->lookup)) { +/* Remove the nport from the domain's lookup table */ +xa_erase (&domain->lookup, nport->fc_id); +efc_sm_transition (ctx, __efc_nport_wait_port_free, +NULL ); +if (efc_cmd_nport_free (efc, nport)) { +efc_log_debug (nport->efc, +"efc_hw_port_free failed\n" ); +/* Not much we can do, free the nport anyways */ +efc_nport_free (nport); + } + }else { +/* sm: node list is not empty / shutdown nodes */ +efc_sm_transition (ctx, + __efc_nport_wait_shutdown,NULL ); +efc_nport_shutdown (nport); + } +break ; +default : +efc_log_debug (nport->efc,"[%s] %-20s %-20s not handled\n" , + nport->display_name, funcname, +efc_sm_event_name (evt)); + } +} + +void +__efc_nport_allocated (struct efc_sm_ctx *ctx, +enum efc_sm_event evt,void *arg) +{ +struct efc_nport *nport = ctx->app; +struct efc_domain *domain = nport->domain; + +nport_sm_trace (nport); + +switch (evt) { +/* the physical nport is attached */ +case EFC_EVT_NPORT_ATTACH_OK : +WARN_ON (nport != domain->nport); +efc_sm_transition (ctx, __efc_nport_attached,NULL ); +break ; + +case EFC_EVT_NPORT_ALLOC_OK : +/* ignore */ +break ; +default : +__efc_nport_common (__func__, ctx, evt, arg); + } +} + +void +__efc_nport_vport_init (struct efc_sm_ctx *ctx, +enum efc_sm_event evt,void *arg) +{ +struct efc_nport *nport = ctx->app; +struct efc *efc = nport->efc; + +nport_sm_trace (nport); + +switch (evt) { +case EFC_EVT_ENTER : { +__be64 be_wwpn =cpu_to_be64 (nport->wwpn); + +if (nport->wwpn ==0 ) +efc_log_debug (efc,"vport: letting f/w select WWN\n" ); + +if (nport->fc_id !=U32_MAX ) { +efc_log_debug (efc,"vport: hard coding port id: %x\n" , + nport->fc_id); + } + +efc_sm_transition (ctx, __efc_nport_vport_wait_alloc,NULL ); +/* If wwpn is zero, then we'll let the f/w */ +if (efc_cmd_nport_alloc (efc, nport, nport->domain, + nport->wwpn ==0 ?NULL : + (uint8_t *)&be_wwpn)) { +efc_log_err (efc,"Can't allocate port\n" ); +break ; + } + +break ; + } +default : +__efc_nport_common (__func__, ctx, evt, arg); + } +} + +void +__efc_nport_vport_wait_alloc (struct efc_sm_ctx *ctx, +enum efc_sm_event evt,void *arg) +{ +struct efc_nport *nport = ctx->app; +struct efc *efc = nport->efc; + +nport_sm_trace (nport); + +switch (evt) { +case EFC_EVT_NPORT_ALLOC_OK : { +struct fc_els_flogi *sp; + + sp = (struct fc_els_flogi *)nport->service_params; +/* +* If we let f/w assign wwn's, +* then nport wwn's with those returned by hw +*/ +if (nport->wwnn ==0 ) { + nport->wwnn =be64_to_cpu (nport->sli_wwnn); + nport->wwpn =be64_to_cpu (nport->sli_wwpn); +snprintf (nport->wwnn_str,sizeof (nport->wwnn_str), +"%016llX" , nport->wwpn); + } + +/* Update the nport's service parameters */ + sp->fl_wwpn =cpu_to_be64 (nport->wwpn); + sp->fl_wwnn =cpu_to_be64 (nport->wwnn); + +/* +* if nport->fc_id is uninitialized, +* then request that the fabric node use FDISC +* to find an fc_id. +* Otherwise we're restoring vports, or we're in +* fabric emulation mode, so attach the fc_id +*/ +if (nport->fc_id ==U32_MAX ) { +struct efc_node *fabric; + + fabric =efc_node_alloc (nport,FC_FID_FLOGI , false, + false); +if (!fabric) { +efc_log_err (efc,"efc_node_alloc() failed\n" ); +return ; + } +efc_node_transition (fabric, __efc_vport_fabric_init, +NULL ); + }else { +snprintf (nport->wwnn_str,sizeof (nport->wwnn_str), +"%016llX" , nport->wwpn); +efc_nport_attach (nport, nport->fc_id); + } +efc_sm_transition (ctx, __efc_nport_vport_allocated,NULL ); +break ; + } +default : +__efc_nport_common (__func__, ctx, evt, arg); + } +} + +void +__efc_nport_vport_allocated (struct efc_sm_ctx *ctx, +enum efc_sm_event evt,void *arg) +{ +struct efc_nport *nport = ctx->app; +struct efc *efc = nport->efc; + +nport_sm_trace (nport); + +/* +* This state is entered after the nport is allocated; +* it then waits for a fabric node +* FDISC to complete, which requests a nport attach. +* The nport attach complete is handled in this state. +*/ +switch (evt) { +case EFC_EVT_NPORT_ATTACH_OK : { +struct efc_node *node; + +/* Find our fabric node, and forward this event */ + node =efc_node_find (nport,FC_FID_FLOGI ); +if (!node) { +efc_log_debug (efc,"can't find node %06x\n" , +FC_FID_FLOGI ); +break ; + } +/* sm: / forward nport attach to fabric node */ +efc_node_post_event (node, evt,NULL ); +efc_sm_transition (ctx, __efc_nport_attached,NULL ); +break ; + } +default : +__efc_nport_common (__func__, ctx, evt, arg); + } +} + +static void +efc_vport_update_spec (struct efc_nport *nport) +{ +struct efc *efc = nport->efc; +struct efc_vport *vport; +unsigned long flags =0 ; + +spin_lock_irqsave (&efc->vport_lock, flags); +list_for_each_entry (vport, &efc->vport_list, list_entry) { +if (vport->nport == nport) { + vport->wwnn = nport->wwnn; + vport->wwpn = nport->wwpn; + vport->tgt_data = nport->tgt_data; + vport->ini_data = nport->ini_data; +break ; + } + } +spin_unlock_irqrestore (&efc->vport_lock, flags); +} + +void +__efc_nport_attached (struct efc_sm_ctx *ctx, +enum efc_sm_event evt,void *arg) +{ +struct efc_nport *nport = ctx->app; +struct efc *efc = nport->efc; + +nport_sm_trace (nport); + +switch (evt) { +case EFC_EVT_ENTER : { +struct efc_node *node; +unsigned long index; + +efc_log_debug (efc, +"[%s] NPORT attached WWPN %016llX WWNN %016llX\n" , + nport->display_name, + nport->wwpn, nport->wwnn); + +xa_for_each (&nport->lookup, index, node) { +efc_node_update_display_name (node); + } + + nport->tgt_id = nport->fc_id; + + efc->tt.new_nport (efc, nport); + +/* +* Update the vport (if its not the physical nport) +* parameters +*/ +if (nport->is_vport) +efc_vport_update_spec (nport); +break ; + } + +case EFC_EVT_EXIT : +efc_log_debug (efc, +"[%s] NPORT deattached WWPN %016llX WWNN %016llX\n" , + nport->display_name, + nport->wwpn, nport->wwnn); + + efc->tt.del_nport (efc, nport); +break ; +default : +__efc_nport_common (__func__, ctx, evt, arg); + } +} + + +void +__efc_nport_wait_shutdown (struct efc_sm_ctx *ctx, +enum efc_sm_event evt,void *arg) +{ +struct efc_nport *nport = ctx->app; +struct efc_domain *domain = nport->domain; +struct efc *efc = nport->efc; + +nport_sm_trace (nport); + +switch (evt) { +case EFC_EVT_NPORT_ALLOC_OK : +case EFC_EVT_NPORT_ALLOC_FAIL : +case EFC_EVT_NPORT_ATTACH_OK : +case EFC_EVT_NPORT_ATTACH_FAIL : +/* ignore these events - just wait for the all free event */ +break ; + +case EFC_EVT_ALL_CHILD_NODES_FREE : { +/* +* Remove the nport from the domain's +* sparse vector lookup table +*/ +xa_erase (&domain->lookup, nport->fc_id); +efc_sm_transition (ctx, __efc_nport_wait_port_free,NULL ); +if (efc_cmd_nport_free (efc, nport)) { +efc_log_err (nport->efc,"efc_hw_port_free failed\n" ); +/* Not much we can do, free the nport anyways */ +efc_nport_free (nport); + } +break ; + } +default : +__efc_nport_common (__func__, ctx, evt, arg); + } +} + +void +__efc_nport_wait_port_free (struct efc_sm_ctx *ctx, +enum efc_sm_event evt,void *arg) +{ +struct efc_nport *nport = ctx->app; + +nport_sm_trace (nport); + +switch (evt) { +case EFC_EVT_NPORT_ATTACH_OK : +/* Ignore as we are waiting for the free CB */ +break ; +case EFC_EVT_NPORT_FREE_OK : { +/* All done, free myself */ +efc_nport_free (nport); +break ; + } +default : +__efc_nport_common (__func__, ctx, evt, arg); + } +} + +static int +efc_vport_nport_alloc (struct efc_domain *domain,struct efc_vport *vport) +{ +struct efc_nport *nport; + +lockdep_assert_held (&domain->efc->lock); + + nport =efc_nport_alloc (domain, vport->wwpn, vport->wwnn, vport->fc_id, + vport->enable_ini, vport->enable_tgt); + vport->nport = nport; +if (!nport) +return EFC_FAIL ; + +kref_get (&nport->ref); + nport->is_vport = true; + nport->tgt_data = vport->tgt_data; + nport->ini_data = vport->ini_data; + +efc_sm_transition (&nport->sm, __efc_nport_vport_init,NULL ); + +return EFC_SUCCESS ; +} + +int +efc_vport_start (struct efc_domain *domain) +{ +struct efc *efc = domain->efc; +struct efc_vport *vport; +struct efc_vport *next; +int rc =EFC_SUCCESS ; +unsigned long flags =0 ; + +/* Use the vport spec to find the associated vports and start them */ +spin_lock_irqsave (&efc->vport_lock, flags); +list_for_each_entry_safe (vport, next, &efc->vport_list, list_entry) { +if (!vport->nport) { +if (efc_vport_nport_alloc (domain, vport)) + rc =EFC_FAIL ; + } + } +spin_unlock_irqrestore (&efc->vport_lock, flags); + +return rc; +} + +int +efc_nport_vport_new (struct efc_domain *domain,uint64_t wwpn,uint64_t wwnn, +u32 fc_id,bool ini,bool tgt,void *tgt_data, +void *ini_data) +{ +struct efc *efc = domain->efc; +struct efc_vport *vport; +int rc =EFC_SUCCESS ; +unsigned long flags =0 ; + +if (ini && domain->efc->enable_ini ==0 ) { +efc_log_debug (efc, +"driver initiator functionality not enabled\n" ); +return EFC_FAIL ; + } + +if (tgt && domain->efc->enable_tgt ==0 ) { +efc_log_debug (efc, +"driver target functionality not enabled\n" ); +return EFC_FAIL ; + } + +/* +* Create a vport spec if we need to recreate +* this vport after a link up event +*/ + vport =efc_vport_create_spec (domain->efc, wwnn, wwpn, fc_id, ini, tgt, + tgt_data, ini_data); +if (!vport) { +efc_log_err (efc,"failed to create vport object entry\n" ); +return EFC_FAIL ; + } + +spin_lock_irqsave (&efc->lock, flags); + rc =efc_vport_nport_alloc (domain, vport); +spin_unlock_irqrestore (&efc->lock, flags); + +return rc; +} + +int +efc_nport_vport_del (struct efc *efc,struct efc_domain *domain, +u64 wwpn,uint64_t wwnn) +{ +struct efc_nport *nport; +int found =0 ; +struct efc_vport *vport; +struct efc_vport *next; +unsigned long flags =0 ; + +spin_lock_irqsave (&efc->vport_lock, flags); +/* walk the efc_vport_list and remove from there */ +list_for_each_entry_safe (vport, next, &efc->vport_list, list_entry) { +if (vport->wwpn == wwpn && vport->wwnn == wwnn) { +list_del (&vport->list_entry); +kfree (vport); +break ; + } + } +spin_unlock_irqrestore (&efc->vport_lock, flags); + +if (!domain) { +/* No domain means no nport to look for */ +return EFC_SUCCESS ; + } + +spin_lock_irqsave (&efc->lock, flags); +list_for_each_entry (nport, &domain->nport_list, list_entry) { +if (nport->wwpn == wwpn && nport->wwnn == wwnn) { + found =1 ; +break ; + } + } + +if (found) { +kref_put (&nport->ref, nport->release); +/* Shutdown this NPORT */ +efc_sm_post_event (&nport->sm,EFC_EVT_SHUTDOWN ,NULL ); + } +spin_unlock_irqrestore (&efc->lock, flags); +return EFC_SUCCESS ; +} + +void +efc_vport_del_all (struct efc *efc) +{ +struct efc_vport *vport; +struct efc_vport *next; +unsigned long flags =0 ; + +spin_lock_irqsave (&efc->vport_lock, flags); +list_for_each_entry_safe (vport, next, &efc->vport_list, list_entry) { +list_del (&vport->list_entry); +kfree (vport); + } +spin_unlock_irqrestore (&efc->vport_lock, flags); +} + +struct efc_vport * +efc_vport_create_spec (struct efc *efc,uint64_t wwnn,uint64_t wwpn, +u32 fc_id,bool enable_ini, +bool enable_tgt,void *tgt_data,void *ini_data) +{ +struct efc_vport *vport; +unsigned long flags =0 ; + +/* +* walk the efc_vport_list and return failure +* if a valid(vport with non zero WWPN and WWNN) vport entry +* is already created +*/ +spin_lock_irqsave (&efc->vport_lock, flags); +list_for_each_entry (vport, &efc->vport_list, list_entry) { +if ((wwpn && vport->wwpn == wwpn) && + (wwnn && vport->wwnn == wwnn)) { +efc_log_err (efc, +"Failed: VPORT %016llX %016llX already allocated\n" , + wwnn, wwpn); +spin_unlock_irqrestore (&efc->vport_lock, flags); +return NULL ; + } + } + + vport =kzalloc (sizeof (*vport),GFP_ATOMIC ); +if (!vport) { +spin_unlock_irqrestore (&efc->vport_lock, flags); +return NULL ; + } + + vport->wwnn = wwnn; + vport->wwpn = wwpn; + vport->fc_id = fc_id; + vport->enable_tgt = enable_tgt; + vport->enable_ini = enable_ini; + vport->tgt_data = tgt_data; + vport->ini_data = ini_data; + +INIT_LIST_HEAD (&vport->list_entry); +list_add_tail (&vport->list_entry, &efc->vport_list); +spin_unlock_irqrestore (&efc->vport_lock, flags); +return vport; +}
drivers/scsi/elx/libefc/efc_nport.h new file +50 -0
50 lines not on this page · raw message
Signature · 1 line
2.26.2
Re: [PATCH v8 11/31] elx: libefc: SLI and FC PORT state machine interfaces
Quoted 379 lines · James Smart
This patch continues the libefc library population.
This patch adds library interface definitions for:
- SLI and FC port (akan_port_id) registration, allocation and deallocation.Co-developed-by Ram Vegesna <[email protected]>Signed-off-by Ram Vegesna <[email protected]>Signed-off-by James Smart <[email protected]>Reviewed-by Daniel Wagner <[email protected]>--- drivers/scsi/elx/libefc/efc_nport.c | 792 ++++++++++++++++++++++++++++ drivers/scsi/elx/libefc/efc_nport.h | 50 ++ 2 files changed, 842 insertions(+) create mode 100644 drivers/scsi/elx/libefc/efc_nport.c create mode 100644 drivers/scsi/elx/libefc/efc_nport.hdrivers/scsi/elx/libefc/efc_nport.c new file +356
-0@@ -0,0 +1,792 @@ +// SPDX-License-Identifier: GPL-2.0 +/* +* Copyright (C) 2021 Broadcom. All Rights Reserved. The term +* “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. +*/ + +/* +* NPORT +* +* Port object for physical port and NPIV ports. +*/ + +/* +* NPORT REFERENCE COUNTING +* +* A nport reference should be taken when: +* - an nport is allocated +* - a vport populates associated nport +* - a remote node is allocated +* - a unsolicited frame is processed +* The reference should be dropped when: +* - the unsolicited frame processesing is done +* - the remote node is removed +* - the vport is removed +* - the nport is removed +*/ + +#include "efc.h" + +void +efc_nport_cb (void *arg,int event,void *data) +{ +struct efc *efc = arg; +struct efc_nport *nport = data; +unsigned long flags =0 ; + +efc_log_debug (efc,"nport event: %s\n" ,efc_sm_event_name (event)); + +spin_lock_irqsave (&efc->lock, flags); +efc_sm_post_event (&nport->sm, event,NULL ); +spin_unlock_irqrestore (&efc->lock, flags); +} + +static struct efc_nport * +efc_nport_find_wwn (struct efc_domain *domain,uint64_t wwnn,uint64_t wwpn) +{ +struct efc_nport *nport =NULL ; + +/* Find a nport, given the WWNN and WWPN */ +list_for_each_entry (nport, &domain->nport_list, list_entry) { +if (nport->wwnn == wwnn && nport->wwpn == wwpn) +return nport; + } +return NULL ; +} + +static void +_efc_nport_free (struct kref *arg) +{ + struct efc_nport *nport = container_of(arg, struct efc_nport, ref); + +kfree (nport); +} + +struct efc_nport * +efc_nport_alloc (struct efc_domain *domain,uint64_t wwpn,uint64_t wwnn, +u32 fc_id,bool enable_ini,bool enable_tgt) +{ +struct efc_nport *nport; + +if (domain->efc->enable_ini) + enable_ini =0 ; + +/* Return a failure if this nport has already been allocated */ +if ((wwpn !=0 ) || (wwnn !=0 )) { + nport =efc_nport_find_wwn (domain, wwnn, wwpn); +if (nport) { +efc_log_err (domain->efc, +"Err: NPORT %016llX %016llX already allocated\n" , + wwnn, wwpn); +return NULL ; + } + } + + nport =kzalloc (sizeof (*nport),GFP_ATOMIC ); +if (!nport) +return nport; + +/* initialize refcount */ +kref_init (&nport->ref); + nport->release = _efc_nport_free; + + nport->efc = domain->efc; +snprintf (nport->display_name,sizeof (nport->display_name),"------" ); + nport->domain = domain; +xa_init (&nport->lookup); + nport->instance_index = domain->nport_count++; + nport->sm.app = nport; + nport->enable_ini = enable_ini; + nport->enable_tgt = enable_tgt; + nport->enable_rscn = (nport->enable_ini || + (nport->enable_tgt &&enable_target_rscn (nport->efc))); + +/* Copy service parameters from domain */ +memcpy (nport->service_params, domain->service_params, +sizeof (struct fc_els_flogi )); + +/* Update requested fc_id */ + nport->fc_id = fc_id; + +/* Update the nport's service parameters for the new wwn's */ + nport->wwpn = wwpn; + nport->wwnn = wwnn; +snprintf (nport->wwnn_str,sizeof (nport->wwnn_str),"%016llX" , + (unsigned long long )wwnn); + +/* +* if this is the "first" nport of the domain, +* then make it the "phys" nport +*/ +if (list_empty (&domain->nport_list)) + domain->nport = nport; + +INIT_LIST_HEAD (&nport->list_entry); +list_add_tail (&nport->list_entry, &domain->nport_list); + +kref_get (&domain->ref); + +efc_log_debug (domain->efc,"New Nport [%s]\n" , nport->display_name); + +return nport; +} + +void +efc_nport_free (struct efc_nport *nport) +{ +struct efc_domain *domain; + +if (!nport) +return ; + + domain = nport->domain; +efc_log_debug (domain->efc,"[%s] free nport\n" , nport->display_name); +list_del (&nport->list_entry); +/* +* if this is the physical nport, +* then clear it out of the domain +*/ +if (nport == domain->nport) + domain->nport =NULL ; + +xa_destroy (&nport->lookup); +xa_erase (&domain->lookup, nport->fc_id); + +if (list_empty (&domain->nport_list)) +efc_domain_post_event (domain,EFC_EVT_ALL_CHILD_NODES_FREE , +NULL ); + +kref_put (&domain->ref, domain->release); +kref_put (&nport->ref, nport->release); + +} + +struct efc_nport * +efc_nport_find (struct efc_domain *domain,u32 d_id) +{ +struct efc_nport *nport; + +/* Find a nport object, given an FC_ID */ + nport =xa_load (&domain->lookup, d_id); +if (!nport || !kref_get_unless_zero (&nport->ref)) +return NULL ; + +return nport; +} + +int +efc_nport_attach (struct efc_nport *nport,u32 fc_id) +{ +int rc; +struct efc_node *node; +struct efc *efc = nport->efc; +unsigned long index; + +/* Set our lookup */ + rc =xa_err (xa_store (&nport->domain->lookup, fc_id, nport,GFP_ATOMIC )); +if (rc) { +efc_log_err (efc,"Sport lookup store failed: %d\n" , rc); +return rc; + } + +/* Update our display_name */ +efc_node_fcid_display (fc_id, nport->display_name, +sizeof (nport->display_name)); + +xa_for_each (&nport->lookup, index, node) { +efc_node_update_display_name (node); + } + +efc_log_debug (nport->efc,"[%s] attach nport: fc_id x%06x\n" , + nport->display_name, fc_id); + +/* Register a nport, given an FC_ID */ + rc =efc_cmd_nport_attach (efc, nport, fc_id); +if (rc !=EFC_HW_RTN_SUCCESS ) { +efc_log_err (nport->efc, +"efc_hw_port_attach failed: %d\n" , rc); +return EFC_FAIL ; + } +return EFC_SUCCESS ; +} + +static void +efc_nport_shutdown (struct efc_nport *nport) +{ +struct efc *efc = nport->efc; +struct efc_node *node; +unsigned long index; + +xa_for_each (&nport->lookup, index, node) { +if (!(node->rnode.fc_id ==FC_FID_FLOGI && nport->is_vport)) { +efc_node_post_event (node,EFC_EVT_SHUTDOWN ,NULL ); +continue ; + } + +/* +* If this is a vport, logout of the fabric +* controller so that it deletes the vport +* on the switch. +*/ +/* if link is down, don't send logo */ +if (efc->link_status ==EFC_LINK_STATUS_DOWN ) { +efc_node_post_event (node,EFC_EVT_SHUTDOWN ,NULL ); +continue ; + } + +efc_log_debug (efc,"[%s] nport shutdown vport, send logo\n" , + node->display_name); + +if (!efc_send_logo (node)) { +/* sent LOGO, wait for response */ +efc_node_transition (node, __efc_d_wait_logo_rsp,NULL ); +continue ; + } + +/* +* failed to send LOGO, +* go ahead and cleanup node anyways +*/ +node_printf (node,"Failed to send LOGO\n" ); +efc_node_post_event (node,EFC_EVT_SHUTDOWN_EXPLICIT_LOGO ,NULL ); + } +} + +static void +efc_vport_link_down (struct efc_nport *nport) +{ +struct efc *efc = nport->efc; +struct efc_vport *vport; + +/* Clear the nport reference in the vport specification */ +list_for_each_entry (vport, &efc->vport_list, list_entry) { +if (vport->nport == nport) { +kref_put (&nport->ref, nport->release); + vport->nport =NULL ; +break ; + } + } +} + +static void +__efc_nport_common (const char *funcname,struct efc_sm_ctx *ctx, +enum efc_sm_event evt,void *arg) +{ +struct efc_nport *nport = ctx->app; +struct efc_domain *domain = nport->domain; +struct efc *efc = nport->efc; + +switch (evt) { +case EFC_EVT_ENTER : +case EFC_EVT_REENTER : +case EFC_EVT_EXIT : +case EFC_EVT_ALL_CHILD_NODES_FREE : +break ; +case EFC_EVT_NPORT_ATTACH_OK : +efc_sm_transition (ctx, __efc_nport_attached,NULL ); +break ; +case EFC_EVT_SHUTDOWN : +/* Flag this nport as shutting down */ + nport->shutting_down = true; + +if (nport->is_vport) +efc_vport_link_down (nport); + +if (xa_empty (&nport->lookup)) { +/* Remove the nport from the domain's lookup table */ +xa_erase (&domain->lookup, nport->fc_id); +efc_sm_transition (ctx, __efc_nport_wait_port_free, +NULL ); +if (efc_cmd_nport_free (efc, nport)) { +efc_log_debug (nport->efc, +"efc_hw_port_free failed\n" ); +/* Not much we can do, free the nport anyways */ +efc_nport_free (nport); + } + }else { +/* sm: node list is not empty / shutdown nodes */ +efc_sm_transition (ctx, + __efc_nport_wait_shutdown,NULL ); +efc_nport_shutdown (nport); + } +break ; +default : +efc_log_debug (nport->efc,"[%s] %-20s %-20s not handled\n" , + nport->display_name, funcname, +efc_sm_event_name (evt)); + } +} + +void +__efc_nport_allocated (struct efc_sm_ctx *ctx, +enum efc_sm_event evt,void *arg) +{ +struct efc_nport *nport = ctx->app; +struct efc_domain *domain = nport->domain; + +nport_sm_trace (nport); + +switch (evt) { +/* the physical nport is attached */ +case EFC_EVT_NPORT_ATTACH_OK : +WARN_ON (nport != domain->nport); +efc_sm_transition (ctx, __efc_nport_attached,NULL ); +break ; + +case EFC_EVT_NPORT_ALLOC_OK : +/* ignore */ +break ; +default : +__efc_nport_common (__func__, ctx, evt, arg); + } +} + +void +__efc_nport_vport_init (struct efc_sm_ctx *ctx, +enum efc_sm_event evt,void *arg) +{ +struct efc_nport *nport = ctx->app; +struct efc *efc = nport->efc; + +nport_sm_trace (nport); + +switch (evt) { +case EFC_EVT_ENTER : { +__be64 be_wwpn =cpu_to_be64 (nport->wwpn); +
drivers/scsi/elx/libefc/efc_nport.c line 366
Quoted 10 lines
drivers/scsi/elx/libefc/efc_nport.c new file +10
-0+if (nport->wwpn ==0 ) +efc_log_debug (efc,"vport: letting f/w select WWN\n" ); + +if (nport->fc_id !=U32_MAX ) { +efc_log_debug (efc,"vport: hard coding port id: %x\n" , + nport->fc_id); + } + +efc_sm_transition (ctx, __efc_nport_vport_wait_alloc,NULL ); +/* If wwpn is zero, then we'll let the f/w */
We'll let the f/w _what_?
Quoted 21 lines
drivers/scsi/elx/libefc/efc_nport.c new file +21
-0+if (efc_cmd_nport_alloc (efc, nport, nport->domain, + nport->wwpn ==0 ?NULL : + (uint8_t *)&be_wwpn)) { +efc_log_err (efc,"Can't allocate port\n" ); +break ; + } + +break ; + } +default : +__efc_nport_common (__func__, ctx, evt, arg); + } +} + +void +__efc_nport_vport_wait_alloc (struct efc_sm_ctx *ctx, +enum efc_sm_event evt,void *arg) +{ +struct efc_nport *nport = ctx->app; +struct efc *efc = nport->efc; +
drivers/scsi/elx/libefc/efc_nport.c line 397
Quoted 10 lines
drivers/scsi/elx/libefc/efc_nport.c new file +10
-0+nport_sm_trace (nport); + +switch (evt) { +case EFC_EVT_NPORT_ALLOC_OK : { +struct fc_els_flogi *sp; + + sp = (struct fc_els_flogi *)nport->service_params; +/* +* If we let f/w assign wwn's, +* then nport wwn's with those returned by hw
this sentence no verb ...
Quoted 112 lines
drivers/scsi/elx/libefc/efc_nport.c new file +112
-0+*/ +if (nport->wwnn ==0 ) { + nport->wwnn =be64_to_cpu (nport->sli_wwnn); + nport->wwpn =be64_to_cpu (nport->sli_wwpn); +snprintf (nport->wwnn_str,sizeof (nport->wwnn_str), +"%016llX" , nport->wwpn); + } + +/* Update the nport's service parameters */ + sp->fl_wwpn =cpu_to_be64 (nport->wwpn); + sp->fl_wwnn =cpu_to_be64 (nport->wwnn); + +/* +* if nport->fc_id is uninitialized, +* then request that the fabric node use FDISC +* to find an fc_id. +* Otherwise we're restoring vports, or we're in +* fabric emulation mode, so attach the fc_id +*/ +if (nport->fc_id ==U32_MAX ) { +struct efc_node *fabric; + + fabric =efc_node_alloc (nport,FC_FID_FLOGI , false, + false); +if (!fabric) { +efc_log_err (efc,"efc_node_alloc() failed\n" ); +return ; + } +efc_node_transition (fabric, __efc_vport_fabric_init, +NULL ); + }else { +snprintf (nport->wwnn_str,sizeof (nport->wwnn_str), +"%016llX" , nport->wwpn); +efc_nport_attach (nport, nport->fc_id); + } +efc_sm_transition (ctx, __efc_nport_vport_allocated,NULL ); +break ; + } +default : +__efc_nport_common (__func__, ctx, evt, arg); + } +} + +void +__efc_nport_vport_allocated (struct efc_sm_ctx *ctx, +enum efc_sm_event evt,void *arg) +{ +struct efc_nport *nport = ctx->app; +struct efc *efc = nport->efc; + +nport_sm_trace (nport); + +/* +* This state is entered after the nport is allocated; +* it then waits for a fabric node +* FDISC to complete, which requests a nport attach. +* The nport attach complete is handled in this state. +*/ +switch (evt) { +case EFC_EVT_NPORT_ATTACH_OK : { +struct efc_node *node; + +/* Find our fabric node, and forward this event */ + node =efc_node_find (nport,FC_FID_FLOGI ); +if (!node) { +efc_log_debug (efc,"can't find node %06x\n" , +FC_FID_FLOGI ); +break ; + } +/* sm: / forward nport attach to fabric node */ +efc_node_post_event (node, evt,NULL ); +efc_sm_transition (ctx, __efc_nport_attached,NULL ); +break ; + } +default : +__efc_nport_common (__func__, ctx, evt, arg); + } +} + +static void +efc_vport_update_spec (struct efc_nport *nport) +{ +struct efc *efc = nport->efc; +struct efc_vport *vport; +unsigned long flags =0 ; + +spin_lock_irqsave (&efc->vport_lock, flags); +list_for_each_entry (vport, &efc->vport_list, list_entry) { +if (vport->nport == nport) { + vport->wwnn = nport->wwnn; + vport->wwpn = nport->wwpn; + vport->tgt_data = nport->tgt_data; + vport->ini_data = nport->ini_data; +break ; + } + } +spin_unlock_irqrestore (&efc->vport_lock, flags); +} + +void +__efc_nport_attached (struct efc_sm_ctx *ctx, +enum efc_sm_event evt,void *arg) +{ +struct efc_nport *nport = ctx->app; +struct efc *efc = nport->efc; + +nport_sm_trace (nport); + +switch (evt) { +case EFC_EVT_ENTER : { +struct efc_node *node; +unsigned long index;
drivers/scsi/elx/libefc/efc_nport.c line 519
Quoted 10 lines
drivers/scsi/elx/libefc/efc_nport.c new file +10
-0+ +efc_log_debug (efc, +"[%s] NPORT attached WWPN %016llX WWNN %016llX\n" , + nport->display_name, + nport->wwpn, nport->wwnn); + +xa_for_each (&nport->lookup, index, node) { +efc_node_update_display_name (node); + } +
Superfluous braces
Quoted 70 lines
drivers/scsi/elx/libefc/efc_nport.c new file +70
-0+ nport->tgt_id = nport->fc_id; + + efc->tt.new_nport (efc, nport); + +/* +* Update the vport (if its not the physical nport) +* parameters +*/ +if (nport->is_vport) +efc_vport_update_spec (nport); +break ; + } + +case EFC_EVT_EXIT : +efc_log_debug (efc, +"[%s] NPORT deattached WWPN %016llX WWNN %016llX\n" , + nport->display_name, + nport->wwpn, nport->wwnn); + + efc->tt.del_nport (efc, nport); +break ; +default : +__efc_nport_common (__func__, ctx, evt, arg); + } +} + + +void +__efc_nport_wait_shutdown (struct efc_sm_ctx *ctx, +enum efc_sm_event evt,void *arg) +{ +struct efc_nport *nport = ctx->app; +struct efc_domain *domain = nport->domain; +struct efc *efc = nport->efc; + +nport_sm_trace (nport); + +switch (evt) { +case EFC_EVT_NPORT_ALLOC_OK : +case EFC_EVT_NPORT_ALLOC_FAIL : +case EFC_EVT_NPORT_ATTACH_OK : +case EFC_EVT_NPORT_ATTACH_FAIL : +/* ignore these events - just wait for the all free event */ +break ; + +case EFC_EVT_ALL_CHILD_NODES_FREE : { +/* +* Remove the nport from the domain's +* sparse vector lookup table +*/ +xa_erase (&domain->lookup, nport->fc_id); +efc_sm_transition (ctx, __efc_nport_wait_port_free,NULL ); +if (efc_cmd_nport_free (efc, nport)) { +efc_log_err (nport->efc,"efc_hw_port_free failed\n" ); +/* Not much we can do, free the nport anyways */ +efc_nport_free (nport); + } +break ; + } +default : +__efc_nport_common (__func__, ctx, evt, arg); + } +} + +void +__efc_nport_wait_port_free (struct efc_sm_ctx *ctx, +enum efc_sm_event evt,void *arg) +{ +struct efc_nport *nport = ctx->app; +
drivers/scsi/elx/libefc/efc_nport.c line 599
Quoted 10 lines
drivers/scsi/elx/libefc/efc_nport.c new file +10
-0+nport_sm_trace (nport); + +switch (evt) { +case EFC_EVT_NPORT_ATTACH_OK : +/* Ignore as we are waiting for the free CB */ +break ; +case EFC_EVT_NPORT_FREE_OK : { +/* All done, free myself */ +efc_nport_free (nport); +break ;
Set ctx->app to NULL?
Quoted 120 lines
drivers/scsi/elx/libefc/efc_nport.c new file +120
-0+ } +default : +__efc_nport_common (__func__, ctx, evt, arg); + } +} + +static int +efc_vport_nport_alloc (struct efc_domain *domain,struct efc_vport *vport) +{ +struct efc_nport *nport; + +lockdep_assert_held (&domain->efc->lock); + + nport =efc_nport_alloc (domain, vport->wwpn, vport->wwnn, vport->fc_id, + vport->enable_ini, vport->enable_tgt); + vport->nport = nport; +if (!nport) +return EFC_FAIL ; + +kref_get (&nport->ref); + nport->is_vport = true; + nport->tgt_data = vport->tgt_data; + nport->ini_data = vport->ini_data; + +efc_sm_transition (&nport->sm, __efc_nport_vport_init,NULL ); + +return EFC_SUCCESS ; +} + +int +efc_vport_start (struct efc_domain *domain) +{ +struct efc *efc = domain->efc; +struct efc_vport *vport; +struct efc_vport *next; +int rc =EFC_SUCCESS ; +unsigned long flags =0 ; + +/* Use the vport spec to find the associated vports and start them */ +spin_lock_irqsave (&efc->vport_lock, flags); +list_for_each_entry_safe (vport, next, &efc->vport_list, list_entry) { +if (!vport->nport) { +if (efc_vport_nport_alloc (domain, vport)) + rc =EFC_FAIL ; + } + } +spin_unlock_irqrestore (&efc->vport_lock, flags); + +return rc; +} + +int +efc_nport_vport_new (struct efc_domain *domain,uint64_t wwpn,uint64_t wwnn, +u32 fc_id,bool ini,bool tgt,void *tgt_data, +void *ini_data) +{ +struct efc *efc = domain->efc; +struct efc_vport *vport; +int rc =EFC_SUCCESS ; +unsigned long flags =0 ; + +if (ini && domain->efc->enable_ini ==0 ) { +efc_log_debug (efc, +"driver initiator functionality not enabled\n" ); +return EFC_FAIL ; + } + +if (tgt && domain->efc->enable_tgt ==0 ) { +efc_log_debug (efc, +"driver target functionality not enabled\n" ); +return EFC_FAIL ; + } + +/* +* Create a vport spec if we need to recreate +* this vport after a link up event +*/ + vport =efc_vport_create_spec (domain->efc, wwnn, wwpn, fc_id, ini, tgt, + tgt_data, ini_data); +if (!vport) { +efc_log_err (efc,"failed to create vport object entry\n" ); +return EFC_FAIL ; + } + +spin_lock_irqsave (&efc->lock, flags); + rc =efc_vport_nport_alloc (domain, vport); +spin_unlock_irqrestore (&efc->lock, flags); + +return rc; +} + +int +efc_nport_vport_del (struct efc *efc,struct efc_domain *domain, +u64 wwpn,uint64_t wwnn) +{ +struct efc_nport *nport; +int found =0 ; +struct efc_vport *vport; +struct efc_vport *next; +unsigned long flags =0 ; + +spin_lock_irqsave (&efc->vport_lock, flags); +/* walk the efc_vport_list and remove from there */ +list_for_each_entry_safe (vport, next, &efc->vport_list, list_entry) { +if (vport->wwpn == wwpn && vport->wwnn == wwnn) { +list_del (&vport->list_entry); +kfree (vport); +break ; + } + } +spin_unlock_irqrestore (&efc->vport_lock, flags); + +if (!domain) { +/* No domain means no nport to look for */ +return EFC_SUCCESS ; + } + +spin_lock_irqsave (&efc->lock, flags); +list_for_each_entry (nport, &domain->nport_list, list_entry) { +if (nport->wwpn == wwpn && nport->wwnn == wwnn) {
drivers/scsi/elx/libefc/efc_nport.c line 729
Quoted 10 lines
drivers/scsi/elx/libefc/efc_nport.c new file +10
-0+ found =1 ; +break ; + } + } + +if (found) { +kref_put (&nport->ref, nport->release); +/* Shutdown this NPORT */ +efc_sm_post_event (&nport->sm,EFC_EVT_SHUTDOWN ,NULL ); + }
Bah. Using the loop variable outside of the loop is bad style. Why not moving this directly within the loop and drop the 'found' variable?
Quoted 110 lines
drivers/scsi/elx/libefc/efc_nport.c new file +63
-0+spin_unlock_irqrestore (&efc->lock, flags); +return EFC_SUCCESS ; +} + +void +efc_vport_del_all (struct efc *efc) +{ +struct efc_vport *vport; +struct efc_vport *next; +unsigned long flags =0 ; + +spin_lock_irqsave (&efc->vport_lock, flags); +list_for_each_entry_safe (vport, next, &efc->vport_list, list_entry) { +list_del (&vport->list_entry); +kfree (vport); + } +spin_unlock_irqrestore (&efc->vport_lock, flags); +} + +struct efc_vport * +efc_vport_create_spec (struct efc *efc,uint64_t wwnn,uint64_t wwpn, +u32 fc_id,bool enable_ini, +bool enable_tgt,void *tgt_data,void *ini_data) +{ +struct efc_vport *vport; +unsigned long flags =0 ; + +/* +* walk the efc_vport_list and return failure +* if a valid(vport with non zero WWPN and WWNN) vport entry +* is already created +*/ +spin_lock_irqsave (&efc->vport_lock, flags); +list_for_each_entry (vport, &efc->vport_list, list_entry) { +if ((wwpn && vport->wwpn == wwpn) && + (wwnn && vport->wwnn == wwnn)) { +efc_log_err (efc, +"Failed: VPORT %016llX %016llX already allocated\n" , + wwnn, wwpn); +spin_unlock_irqrestore (&efc->vport_lock, flags); +return NULL ; + } + } + + vport =kzalloc (sizeof (*vport),GFP_ATOMIC ); +if (!vport) { +spin_unlock_irqrestore (&efc->vport_lock, flags); +return NULL ; + } + + vport->wwnn = wwnn; + vport->wwpn = wwpn; + vport->fc_id = fc_id; + vport->enable_tgt = enable_tgt; + vport->enable_ini = enable_ini; + vport->tgt_data = tgt_data; + vport->ini_data = ini_data; + +INIT_LIST_HEAD (&vport->list_entry); +list_add_tail (&vport->list_entry, &efc->vport_list); +spin_unlock_irqrestore (&efc->vport_lock, flags); +return vport; +}drivers/scsi/elx/libefc/efc_nport.h new file +40
-0@@ -0,0 +1,50 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* +* Copyright (C) 2021 Broadcom. All Rights Reserved. The term +* “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. +*/ + +/** +* EFC FC port (NPORT) exported declarations +* +*/ + +#ifndef __EFC_NPORT_H__ +#define __EFC_NPORT_H__ + +struct efc_nport * +efc_nport_find (struct efc_domain *domain,u32 d_id); +struct efc_nport * +efc_nport_alloc (struct efc_domain *domain,uint64_t wwpn,uint64_t wwnn, +u32 fc_id,bool enable_ini,bool enable_tgt); +void +efc_nport_free (struct efc_nport *nport); +int +efc_nport_attach (struct efc_nport *nport,u32 fc_id); + +void +__efc_nport_allocated (struct efc_sm_ctx *ctx, +enum efc_sm_event evt,void *arg); +void +__efc_nport_wait_shutdown (struct efc_sm_ctx *ctx, +enum efc_sm_event evt,void *arg); +void +__efc_nport_wait_port_free (struct efc_sm_ctx *ctx, +enum efc_sm_event evt,void *arg); +void +__efc_nport_vport_init (struct efc_sm_ctx *ctx, +enum efc_sm_event evt,void *arg); +void +__efc_nport_vport_wait_alloc (struct efc_sm_ctx *ctx, +enum efc_sm_event evt,void *arg); +void
drivers/scsi/elx/libefc/efc_nport.h line 50
Quoted 10 lines
drivers/scsi/elx/libefc/efc_nport.h new file +10
-0+__efc_nport_vport_allocated(struct efc_sm_ctx *ctx, + enum efc_sm_event evt, void *arg); +void +__efc_nport_attached (struct efc_sm_ctx *ctx, +enum efc_sm_event evt,void *arg); + +int +efc_vport_start (struct efc_domain *domain); + +#endif /* __EFC_NPORT_H__ */
Cheers,
Hannes
Signature · 4 lines
Dr. Hannes Reinecke Kernel Storage Architect [email protected] +49 911 74053 688 SUSE Software Solutions Germany GmbH, 90409 Nürnberg GF: F. Imendörffer, HRB 36809 (AG Nürnberg)
PATCH v8 12/31 elx: libefc: Remote node state machine interfaces
In reply to James SmartThis patch continues the libefc library population.
This patch adds library interface definitions for:
- Remote node (aka remote port) allocation, initializaion and destroy routines.
---
v8:
Mark els_io_enabled to true, when re-authenticating the node
--- drivers/scsi/elx/libefc/efc_node.c | 1104 ++++++++++++++++++++++++++++ drivers/scsi/elx/libefc/efc_node.h | 191 +++++ 2 files changed, 1295 insertions(+) create mode 100644 drivers/scsi/elx/libefc/efc_node.c create mode 100644 drivers/scsi/elx/libefc/efc_node.h
drivers/scsi/elx/libefc/efc_node.c new file +1104 -0
@@ -0,0 +1,1104 @@ +// SPDX-License-Identifier: GPL-2.0 +/* +* Copyright (C) 2021 Broadcom. All Rights Reserved. The term +* “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. +*/ + +#include "efc.h" + +int +efc_remote_node_cb (void *arg,int event,void *data) +{ +struct efc *efc = arg; +struct efc_remote_node *rnode = data; +struct efc_node *node = rnode->node; +unsigned long flags =0 ; + +spin_lock_irqsave (&efc->lock, flags); +efc_node_post_event (node, event,NULL ); +spin_unlock_irqrestore (&efc->lock, flags); + +return EFC_SUCCESS ; +} + +struct efc_node * +efc_node_find (struct efc_nport *nport,u32 port_id) +{ +/* Find an FC node structure given the FC port ID */ +return xa_load (&nport->lookup, port_id); +} + +static void +_efc_node_free (struct kref *arg) +{ + struct efc_node *node = container_of(arg, struct efc_node, ref); +struct efc *efc = node->efc; +struct efc_dma *dma; + + dma = &node->sparm_dma_buf; +dma_pool_free (efc->node_dma_pool, dma->virt, dma->phys); +memset (dma,0 ,sizeof (struct efc_dma )); +mempool_free (node, efc->node_pool); +} + +struct efc_node *efc_node_alloc (struct efc_nport *nport, +u32 port_id,bool init,bool targ) +{ +int rc; +struct efc_node *node =NULL ; +struct efc *efc = nport->efc; +struct efc_dma *dma; + +if (nport->shutting_down) { +efc_log_debug (efc,"node allocation when shutting down %06x" , + port_id); +return NULL ; + } + + node =mempool_alloc (efc->node_pool,GFP_ATOMIC ); +if (!node) { +efc_log_err (efc,"node allocation failed %06x" , port_id); +return NULL ; + } +memset (node,0 ,sizeof (*node)); + + dma = &node->sparm_dma_buf; + dma->size =NODE_SPARAMS_SIZE ; + dma->virt =dma_pool_zalloc (efc->node_dma_pool,GFP_ATOMIC , &dma->phys); +if (!dma->virt) { +efc_log_err (efc,"node dma alloc failed\n" ); + goto dma_fail; + } + node->rnode.indicator =U32_MAX ; + node->nport = nport; + + node->efc = efc; + node->init = init; + node->targ = targ; + +spin_lock_init (&node->pend_frames_lock); +INIT_LIST_HEAD (&node->pend_frames); +spin_lock_init (&node->els_ios_lock); +INIT_LIST_HEAD (&node->els_ios_list); +WRITE_ONCE (node->els_io_enabled, true); + + rc =efc_cmd_node_alloc (efc, &node->rnode, port_id, nport); +if (rc) { +efc_log_err (efc,"efc_hw_node_alloc failed: %d\n" , rc); + goto hw_alloc_fail; + } + + node->rnode.node = node; + node->sm.app = node; + node->evtdepth =0 ; + +efc_node_update_display_name (node); + + rc =xa_err (xa_store (&nport->lookup, port_id, node,GFP_ATOMIC )); +if (rc) { +efc_log_err (efc,"Node lookup store failed: %d\n" , rc); + goto xa_fail; + } + +/* initialize refcount */ +kref_init (&node->ref); + node->release = _efc_node_free; +kref_get (&nport->ref); + +return node; + +xa_fail: +efc_node_free_resources (efc, &node->rnode); +hw_alloc_fail: +dma_pool_free (efc->node_dma_pool, dma->virt, dma->phys); +dma_fail: +mempool_free (node, efc->node_pool); +return NULL ; +} + +void +efc_node_free (struct efc_node *node) +{ +struct efc_nport *nport; +struct efc *efc; +int rc =0 ; +struct efc_node *ns =NULL ; + + nport = node->nport; + efc = node->efc; + +node_printf (node,"Free'd\n" ); + +if (node->refound) { +/* +* Save the name server node. We will send fake RSCN event at +* the end to handle ignored RSCN event during node deletion +*/ + ns =efc_node_find (node->nport,FC_FID_DIR_SERV ); + } + +if (!node->nport) { +efc_log_err (efc,"Node already Freed\n" ); +return ; + } + +/* Free HW resources */ + rc =efc_node_free_resources (efc, &node->rnode); +if (EFC_HW_RTN_IS_ERROR (rc)) +efc_log_err (efc,"efc_hw_node_free failed: %d\n" , rc); + +/* if the gidpt_delay_timer is still running, then delete it */ +if (timer_pending (&node->gidpt_delay_timer)) +del_timer (&node->gidpt_delay_timer); + +xa_erase (&nport->lookup, node->rnode.fc_id); + +/* +* If the node_list is empty, +* then post a ALL_CHILD_NODES_FREE event to the nport, +* after the lock is released. +* The nport may be free'd as a result of the event. +*/ +if (xa_empty (&nport->lookup)) +efc_sm_post_event (&nport->sm,EFC_EVT_ALL_CHILD_NODES_FREE , +NULL ); + + node->nport =NULL ; + node->sm.current_state =NULL ; + +kref_put (&nport->ref, nport->release); +kref_put (&node->ref, node->release); + +if (ns) { +/* sending fake RSCN event to name server node */ +efc_node_post_event (ns,EFC_EVT_RSCN_RCVD ,NULL ); + } +} + +static void +efc_dma_copy_in (struct efc_dma *dma,void *buffer,u32 buffer_length) +{ +if (!dma || !buffer || !buffer_length) +return ; + +if (buffer_length > dma->size) + buffer_length = dma->size; + +memcpy (dma->virt, buffer, buffer_length); + dma->len = buffer_length; +} + +int +efc_node_attach (struct efc_node *node) +{ +int rc =0 ; +struct efc_nport *nport = node->nport; +struct efc_domain *domain = nport->domain; +struct efc *efc = node->efc; + +if (!domain->attached) { +efc_log_err (efc,"Warning: unattached domain\n" ); +return EFC_FAIL ; + } +/* Update node->wwpn/wwnn */ + +efc_node_build_eui_name (node->wwpn,sizeof (node->wwpn), +efc_node_get_wwpn (node)); +efc_node_build_eui_name (node->wwnn,sizeof (node->wwnn), +efc_node_get_wwnn (node)); + +efc_dma_copy_in (&node->sparm_dma_buf, node->service_params +4 , +sizeof (node->service_params) -4 ); + +/* take lock to protect node->rnode.attached */ + rc =efc_cmd_node_attach (efc, &node->rnode, &node->sparm_dma_buf); +if (EFC_HW_RTN_IS_ERROR (rc)) +efc_log_debug (efc,"efc_hw_node_attach failed: %d\n" , rc); + +return rc; +} + +void +efc_node_fcid_display (u32 fc_id,char *buffer,u32 buffer_length) +{ +switch (fc_id) { +case FC_FID_FLOGI : +snprintf (buffer, buffer_length,"fabric" ); +break ; +case FC_FID_FCTRL : +snprintf (buffer, buffer_length,"fabctl" ); +break ; +case FC_FID_DIR_SERV : +snprintf (buffer, buffer_length,"nserve" ); +break ; +default : +if (fc_id ==FC_FID_DOM_MGR ) { +snprintf (buffer, buffer_length,"dctl%02x" , + (fc_id &0x0000ff )); + }else { +snprintf (buffer, buffer_length,"%06x" , fc_id); + } +break ; + } +} + +void +efc_node_update_display_name (struct efc_node *node) +{ +u32 port_id = node->rnode.fc_id; +struct efc_nport *nport = node->nport; +char portid_display[16 ]; + +efc_node_fcid_display (port_id, portid_display,sizeof (portid_display)); + +snprintf (node->display_name,sizeof (node->display_name),"%s.%s" , + nport->display_name, portid_display); +} + +void +efc_node_send_ls_io_cleanup (struct efc_node *node) +{ +if (node->send_ls_acc !=EFC_NODE_SEND_LS_ACC_NONE ) { +efc_log_debug (node->efc,"[%s] cleaning up LS_ACC oxid=0x%x\n" , + node->display_name, node->ls_acc_oxid); + + node->send_ls_acc =EFC_NODE_SEND_LS_ACC_NONE ; + node->ls_acc_io =NULL ; + } +} + +static void efc_node_handle_implicit_logo (struct efc_node *node) +{ +int rc; + +/* +* currently, only case for implicit logo is PLOGI +* recvd. Thus, node's ELS IO pending list won't be +* empty (PLOGI will be on it) +*/ +WARN_ON (node->send_ls_acc !=EFC_NODE_SEND_LS_ACC_PLOGI ); +node_printf (node,"Reason: implicit logout, re-authenticate\n" ); + +/* Re-attach node with the same HW node resources */ + node->req_free = false; + rc =efc_node_attach (node); +efc_node_transition (node, __efc_d_wait_node_attach,NULL ); +WRITE_ONCE (node->els_io_enabled, true); + +if (rc ==EFC_HW_RTN_SUCCESS_SYNC ) +efc_node_post_event (node,EFC_EVT_NODE_ATTACH_OK ,NULL ); + +} + +static void efc_node_handle_explicit_logo (struct efc_node *node) +{ +s8 pend_frames_empty; +unsigned long flags =0 ; + +/* cleanup any pending LS_ACC ELSs */ +efc_node_send_ls_io_cleanup (node); + +spin_lock_irqsave (&node->pend_frames_lock, flags); + pend_frames_empty =list_empty (&node->pend_frames); +spin_unlock_irqrestore (&node->pend_frames_lock, flags); + +/* +* there are two scenarios where we want to keep +* this node alive: +* 1. there are pending frames that need to be +* processed or +* 2. we're an initiator and the remote node is +* a target and we need to re-authenticate +*/ +node_printf (node,"Shutdown: explicit logo pend=%d " , + !pend_frames_empty); +node_printf (node,"nport.ini=%d node.tgt=%d\n" , + node->nport->enable_ini, node->targ); +if (!pend_frames_empty || (node->nport->enable_ini && node->targ)) { +u8 send_plogi = false; + +if (node->nport->enable_ini && node->targ) { +/* +* we're an initiator and +* node shutting down is a target; +* we'll need to re-authenticate in +* initial state +*/ + send_plogi = true; + } + +/* +* transition to __efc_d_init +* (will retain HW node resources) +*/ +WRITE_ONCE (node->els_io_enabled, true); + node->req_free = false; + +/* +* either pending frames exist or we are re-authenticating +* with PLOGI (or both); in either case, return to initial +* state +*/ +efc_node_init_device (node, send_plogi); + } +/* else: let node shutdown occur */ +} + +static void +efc_node_purge_pending (struct efc_node *node) +{ +struct efc *efc = node->efc; +struct efc_hw_sequence *frame, *next; +unsigned long flags =0 ; + +spin_lock_irqsave (&node->pend_frames_lock, flags); + +list_for_each_entry_safe (frame, next, &node->pend_frames, list_entry) { +list_del (&frame->list_entry); + efc->tt.hw_seq_free (efc, frame); + } + +spin_unlock_irqrestore (&node->pend_frames_lock, flags); +} + +void +__efc_node_shutdown (struct efc_sm_ctx *ctx, +enum efc_sm_event evt,void *arg) +{ +struct efc_node *node = ctx->app; + +efc_node_evt_set (ctx, evt, __func__); + +node_sm_trace (); + +switch (evt) { +case EFC_EVT_ENTER : { +efc_node_hold_frames (node); +WARN_ON (!efc_els_io_list_empty (node, &node->els_ios_list)); +/* by default, we will be freeing node after we unwind */ + node->req_free = true; + +switch (node->shutdown_reason) { +case EFC_NODE_SHUTDOWN_IMPLICIT_LOGO : +/* Node shutdown b/c of PLOGI received when node +* already logged in. We have PLOGI service +* parameters, so submit node attach; we won't be +* freeing this node +*/ + +efc_node_handle_implicit_logo (node); +break ; + +case EFC_NODE_SHUTDOWN_EXPLICIT_LOGO : +efc_node_handle_explicit_logo (node); +break ; + +case EFC_NODE_SHUTDOWN_DEFAULT : +default : { +/* +* shutdown due to link down, +* node going away (xport event) or +* nport shutdown, purge pending and +* proceed to cleanup node +*/ + +/* cleanup any pending LS_ACC ELSs */ +efc_node_send_ls_io_cleanup (node); + +node_printf (node, +"Shutdown reason: default, purge pending\n" ); +efc_node_purge_pending (node); +break ; + } + } + +break ; + } +case EFC_EVT_EXIT : +efc_node_accept_frames (node); +break ; + +default : +__efc_node_common (__func__, ctx, evt, arg); + } +} + +static bool +efc_node_check_els_quiesced (struct efc_node *node) +{ +/* check to see if ELS requests, completions are quiesced */ +if (node->els_req_cnt ==0 && node->els_cmpl_cnt ==0 && +efc_els_io_list_empty (node, &node->els_ios_list)) { +if (!node->attached) { +/* hw node detach already completed, proceed */ +node_printf (node,"HW node not attached\n" ); +efc_node_transition (node, + __efc_node_wait_ios_shutdown, +NULL ); + }else { +/* +* hw node detach hasn't completed, +* transition and wait +*/ +node_printf (node,"HW node still attached\n" ); +efc_node_transition (node, __efc_node_wait_node_free, +NULL ); + } +return true; + } +return false; +} + +void +efc_node_initiate_cleanup (struct efc_node *node) +{ +/* +* if ELS's have already been quiesced, will move to next state +* if ELS's have not been quiesced, abort them +*/ +if (!efc_node_check_els_quiesced (node)) { +efc_node_hold_frames (node); +efc_node_transition (node, __efc_node_wait_els_shutdown,NULL ); + } +} + +void +__efc_node_wait_els_shutdown (struct efc_sm_ctx *ctx, +enum efc_sm_event evt,void *arg) +{ +bool check_quiesce = false; +struct efc_node *node = ctx->app; + +efc_node_evt_set (ctx, evt, __func__); + +node_sm_trace (); +/* Node state machine: Wait for all ELSs to complete */ +switch (evt) { +case EFC_EVT_ENTER : +efc_node_hold_frames (node); +if (efc_els_io_list_empty (node, &node->els_ios_list)) { +node_printf (node,"All ELS IOs complete\n" ); + check_quiesce = true; + } +break ; +case EFC_EVT_EXIT : +efc_node_accept_frames (node); +break ; + +case EFC_EVT_SRRS_ELS_REQ_OK : +case EFC_EVT_SRRS_ELS_REQ_FAIL : +case EFC_EVT_SRRS_ELS_REQ_RJT : +case EFC_EVT_ELS_REQ_ABORTED : +if (WARN_ON (!node->els_req_cnt)) +break ; + node->els_req_cnt--; + check_quiesce = true; +break ; + +case EFC_EVT_SRRS_ELS_CMPL_OK : +case EFC_EVT_SRRS_ELS_CMPL_FAIL : +if (WARN_ON (!node->els_cmpl_cnt)) +break ; + node->els_cmpl_cnt--; + check_quiesce = true; +break ; + +case EFC_EVT_ALL_CHILD_NODES_FREE : +/* all ELS IO's complete */ +node_printf (node,"All ELS IOs complete\n" ); +WARN_ON (!efc_els_io_list_empty (node, &node->els_ios_list)); + check_quiesce = true; +break ; + +case EFC_EVT_NODE_ACTIVE_IO_LIST_EMPTY : + check_quiesce = true; +break ; + +case EFC_EVT_DOMAIN_ATTACH_OK : +/* don't care about domain_attach_ok */ +break ; + +/* ignore shutdown events as we're already in shutdown path */ +case EFC_EVT_SHUTDOWN : +/* have default shutdown event take precedence */ + node->shutdown_reason =EFC_NODE_SHUTDOWN_DEFAULT ; + fallthrough; + +case EFC_EVT_SHUTDOWN_EXPLICIT_LOGO : +case EFC_EVT_SHUTDOWN_IMPLICIT_LOGO : +node_printf (node,"%s received\n" ,efc_sm_event_name (evt)); +break ; + +default : +__efc_node_common (__func__, ctx, evt, arg); + } + +if (check_quiesce) +efc_node_check_els_quiesced (node); +} + +void +__efc_node_wait_node_free (struct efc_sm_ctx *ctx, +enum efc_sm_event evt,void *arg) +{ +struct efc_node *node = ctx->app; + +efc_node_evt_set (ctx, evt, __func__); + +node_sm_trace (); + +switch (evt) { +case EFC_EVT_ENTER : +efc_node_hold_frames (node); +break ; + +case EFC_EVT_EXIT : +efc_node_accept_frames (node); +break ; + +case EFC_EVT_NODE_FREE_OK : +/* node is officially no longer attached */ + node->attached = false; +efc_node_transition (node, __efc_node_wait_ios_shutdown,NULL ); +break ; + +case EFC_EVT_ALL_CHILD_NODES_FREE : +case EFC_EVT_NODE_ACTIVE_IO_LIST_EMPTY : +/* As IOs and ELS IO's complete we expect to get these events */ +break ; + +case EFC_EVT_DOMAIN_ATTACH_OK : +/* don't care about domain_attach_ok */ +break ; + +/* ignore shutdown events as we're already in shutdown path */ +case EFC_EVT_SHUTDOWN : +/* have default shutdown event take precedence */ + node->shutdown_reason =EFC_NODE_SHUTDOWN_DEFAULT ; + fallthrough; + +case EFC_EVT_SHUTDOWN_EXPLICIT_LOGO : +case EFC_EVT_SHUTDOWN_IMPLICIT_LOGO : +node_printf (node,"%s received\n" ,efc_sm_event_name (evt)); +break ; +default : +__efc_node_common (__func__, ctx, evt, arg); + } +} + +void +__efc_node_wait_ios_shutdown (struct efc_sm_ctx *ctx, +enum efc_sm_event evt,void *arg) +{ +struct efc_node *node = ctx->app; +struct efc *efc = node->efc; + +efc_node_evt_set (ctx, evt, __func__); + +node_sm_trace (); + +switch (evt) { +case EFC_EVT_ENTER : +efc_node_hold_frames (node); + +/* first check to see if no ELS IOs are outstanding */ +if (efc_els_io_list_empty (node, &node->els_ios_list)) +/* If there are any active IOS, Free them. */ +efc_node_transition (node, __efc_node_shutdown,NULL ); +break ; + +case EFC_EVT_NODE_ACTIVE_IO_LIST_EMPTY : +case EFC_EVT_ALL_CHILD_NODES_FREE : +if (efc_els_io_list_empty (node, &node->els_ios_list)) +efc_node_transition (node, __efc_node_shutdown,NULL ); +break ; + +case EFC_EVT_EXIT : +efc_node_accept_frames (node); +break ; + +case EFC_EVT_SRRS_ELS_REQ_FAIL : +/* Can happen as ELS IO IO's complete */ +if (WARN_ON (!node->els_req_cnt)) +break ; + node->els_req_cnt--; +break ; + +/* ignore shutdown events as we're already in shutdown path */ +case EFC_EVT_SHUTDOWN : +/* have default shutdown event take precedence */ + node->shutdown_reason =EFC_NODE_SHUTDOWN_DEFAULT ; + fallthrough; + +case EFC_EVT_SHUTDOWN_EXPLICIT_LOGO : +case EFC_EVT_SHUTDOWN_IMPLICIT_LOGO : +efc_log_debug (efc,"[%s] %-20s\n" , node->display_name, +efc_sm_event_name (evt)); +break ; +case EFC_EVT_DOMAIN_ATTACH_OK : +/* don't care about domain_attach_ok */ +break ; +default : +__efc_node_common (__func__, ctx, evt, arg); + } +} + +void +__efc_node_common (const char *funcname,struct efc_sm_ctx *ctx, +enum efc_sm_event evt,void *arg) +{ +struct efc_node *node =NULL ; +struct efc *efc =NULL ; +struct efc_node_cb *cbdata = arg; + + node = ctx->app; + efc = node->efc; + +switch (evt) { +case EFC_EVT_ENTER : +case EFC_EVT_REENTER : +case EFC_EVT_EXIT : +case EFC_EVT_NPORT_TOPOLOGY_NOTIFY : +case EFC_EVT_NODE_MISSING : +case EFC_EVT_FCP_CMD_RCVD : +break ; + +case EFC_EVT_NODE_REFOUND : + node->refound = true; +break ; + +/* +* node->attached must be set appropriately +* for all node attach/detach events +*/ +case EFC_EVT_NODE_ATTACH_OK : + node->attached = true; +break ; + +case EFC_EVT_NODE_FREE_OK : +case EFC_EVT_NODE_ATTACH_FAIL : + node->attached = false; +break ; + +/* +* handle any ELS completions that +* other states either didn't care about +* or forgot about +*/ +case EFC_EVT_SRRS_ELS_CMPL_OK : +case EFC_EVT_SRRS_ELS_CMPL_FAIL : +if (WARN_ON (!node->els_cmpl_cnt)) +break ; + node->els_cmpl_cnt--; +break ; + +/* +* handle any ELS request completions that +* other states either didn't care about +* or forgot about +*/ +case EFC_EVT_SRRS_ELS_REQ_OK : +case EFC_EVT_SRRS_ELS_REQ_FAIL : +case EFC_EVT_SRRS_ELS_REQ_RJT : +case EFC_EVT_ELS_REQ_ABORTED : +if (WARN_ON (!node->els_req_cnt)) +break ; + node->els_req_cnt--; +break ; + +case EFC_EVT_ELS_RCVD : { +struct fc_frame_header *hdr = cbdata->header->dma.virt; + +/* +* Unsupported ELS was received, +* send LS_RJT, command not supported +*/ +efc_log_debug (efc, +"[%s] (%s) ELS x%02x, LS_RJT not supported\n" , + node->display_name, funcname, + ((uint8_t *)cbdata->payload->dma.virt)[0 ]); + +efc_send_ls_rjt (node,be16_to_cpu (hdr->fh_ox_id), +ELS_RJT_UNSUP ,ELS_EXPL_NONE ,0 ); +break ; + } + +case EFC_EVT_PLOGI_RCVD : +case EFC_EVT_FLOGI_RCVD : +case EFC_EVT_LOGO_RCVD : +case EFC_EVT_PRLI_RCVD : +case EFC_EVT_PRLO_RCVD : +case EFC_EVT_PDISC_RCVD : +case EFC_EVT_FDISC_RCVD : +case EFC_EVT_ADISC_RCVD : +case EFC_EVT_RSCN_RCVD : +case EFC_EVT_SCR_RCVD : { +struct fc_frame_header *hdr = cbdata->header->dma.virt; + +/* sm: / send ELS_RJT */ +efc_log_debug (efc,"[%s] (%s) %s sending ELS_RJT\n" , + node->display_name, funcname, +efc_sm_event_name (evt)); +/* if we didn't catch this in a state, send generic LS_RJT */ +efc_send_ls_rjt (node,be16_to_cpu (hdr->fh_ox_id), +ELS_RJT_UNAB ,ELS_EXPL_NONE ,0 ); +break ; + } +case EFC_EVT_ABTS_RCVD : { +efc_log_debug (efc,"[%s] (%s) %s sending BA_ACC\n" , + node->display_name, funcname, +efc_sm_event_name (evt)); + +/* sm: / send BA_ACC */ +efc_send_bls_acc (node, cbdata->header->dma.virt); +break ; + } + +default : +efc_log_debug (node->efc,"[%s] %-20s %-20s not handled\n" , + node->display_name, funcname, +efc_sm_event_name (evt)); + } +} + +void +efc_node_save_sparms (struct efc_node *node,void *payload) +{ +memcpy (node->service_params, payload,sizeof (node->service_params)); +} + +void +efc_node_post_event (struct efc_node *node, +enum efc_sm_event evt,void *arg) +{ +bool free_node = false; + + node->evtdepth++; + +efc_sm_post_event (&node->sm, evt, arg); + +/* If our event call depth is one and +* we're not holding frames +* then we can dispatch any pending frames. +* We don't want to allow the efc_process_node_pending() +* call to recurse. +*/ +if (!node->hold_frames && node->evtdepth ==1 ) +efc_process_node_pending (node); + + node->evtdepth--; + +/* +* Free the node object if so requested, +* and we're at an event call depth of zero +*/ +if (node->evtdepth ==0 && node->req_free) + free_node = true; + +if (free_node) +efc_node_free (node); +} + +void +efc_node_transition (struct efc_node *node, +void (*state)(struct efc_sm_ctx *, +enum efc_sm_event ,void *),void *data) +{ +struct efc_sm_ctx *ctx = &node->sm; + +if (ctx->current_state == state) { +efc_node_post_event (node,EFC_EVT_REENTER , data); + }else { +efc_node_post_event (node,EFC_EVT_EXIT , data); + ctx->current_state = state; +efc_node_post_event (node,EFC_EVT_ENTER , data); + } +} + +void +efc_node_build_eui_name (char *buf,u32 buf_len,uint64_t eui_name) +{ +memset (buf,0 , buf_len); + +snprintf (buf, buf_len,"eui.%016llX" , (unsigned long long )eui_name); +} + +u64 +efc_node_get_wwpn (struct efc_node *node) +{ +struct fc_els_flogi *sp = + (struct fc_els_flogi *)node->service_params; + +return be64_to_cpu (sp->fl_wwpn); +} + +u64 +efc_node_get_wwnn (struct efc_node *node) +{ +struct fc_els_flogi *sp = + (struct fc_els_flogi *)node->service_params; + +return be64_to_cpu (sp->fl_wwnn); +} + +int +efc_node_check_els_req (struct efc_sm_ctx *ctx,enum efc_sm_event evt,void *arg, +uint8_t cmd,void (*efc_node_common_func)(const char *, +struct efc_sm_ctx *,enum efc_sm_event ,void *), +const char *funcname) +{ +return 0 ; +} + +int +efc_node_check_ns_req (struct efc_sm_ctx *ctx,enum efc_sm_event evt,void *arg, +uint16_t cmd,void (*efc_node_common_func)(const char *, +struct efc_sm_ctx *,enum efc_sm_event ,void *), +const char *funcname) +{ +return 0 ; +} + +int +efc_els_io_list_empty (struct efc_node *node,struct list_head *list) +{ +int empty; +unsigned long flags =0 ; + +spin_lock_irqsave (&node->els_ios_lock, flags); + empty =list_empty (list); +spin_unlock_irqrestore (&node->els_ios_lock, flags); +return empty; +} + +void +efc_node_pause (struct efc_node *node, +void (*state)(struct efc_sm_ctx *, +enum efc_sm_event ,void *)) + +{ + node->nodedb_state = state; +efc_node_transition (node, __efc_node_paused,NULL ); +} + +void +__efc_node_paused (struct efc_sm_ctx *ctx, +enum efc_sm_event evt,void *arg) +{ +struct efc_node *node = ctx->app; + +efc_node_evt_set (ctx, evt, __func__); + +node_sm_trace (); + +/* +* This state is entered when a state is "paused". When resumed, the +* node is transitioned to a previously saved state (node->ndoedb_state) +*/ +switch (evt) { +case EFC_EVT_ENTER : +node_printf (node,"Paused\n" ); +break ; + +case EFC_EVT_RESUME : { +void (*pf)(struct efc_sm_ctx *ctx, +enum efc_sm_event evt,void *arg); + + pf = node->nodedb_state; + + node->nodedb_state =NULL ; +efc_node_transition (node, pf,NULL ); +break ; + } + +case EFC_EVT_DOMAIN_ATTACH_OK : +break ; + +case EFC_EVT_SHUTDOWN : + node->req_free = true; +break ; + +default : +__efc_node_common (__func__, ctx, evt, arg); + } +} + +void +efc_node_recv_els_frame (struct efc_node *node, +struct efc_hw_sequence *seq) +{ +u32 prli_size =sizeof (struct fc_els_prli ) +sizeof (struct fc_els_spp ); +struct { +u32 cmd; +enum efc_sm_event evt; +u32 payload_size; + } els_cmd_list[] = { + {ELS_PLOGI ,EFC_EVT_PLOGI_RCVD ,sizeof (struct fc_els_flogi )}, + {ELS_FLOGI ,EFC_EVT_FLOGI_RCVD ,sizeof (struct fc_els_flogi )}, + {ELS_LOGO ,EFC_EVT_LOGO_RCVD ,sizeof (struct fc_els_ls_acc )}, + {ELS_PRLI ,EFC_EVT_PRLI_RCVD , prli_size}, + {ELS_PRLO ,EFC_EVT_PRLO_RCVD , prli_size}, + {ELS_PDISC ,EFC_EVT_PDISC_RCVD ,MAX_ACC_REJECT_PAYLOAD }, + {ELS_FDISC ,EFC_EVT_FDISC_RCVD ,MAX_ACC_REJECT_PAYLOAD }, + {ELS_ADISC ,EFC_EVT_ADISC_RCVD ,sizeof (struct fc_els_adisc )}, + {ELS_RSCN ,EFC_EVT_RSCN_RCVD ,MAX_ACC_REJECT_PAYLOAD }, + {ELS_SCR ,EFC_EVT_SCR_RCVD ,MAX_ACC_REJECT_PAYLOAD }, + }; +struct efc_node_cb cbdata; +u8 *buf = seq->payload->dma.virt; +enum efc_sm_event evt =EFC_EVT_ELS_RCVD ; +u32 i; + +memset (&cbdata,0 ,sizeof (cbdata)); + cbdata.header = seq->header; + cbdata.payload = seq->payload; + +/* find a matching event for the ELS command */ +for (i =0 ; i <ARRAY_SIZE (els_cmd_list); i++) { +if (els_cmd_list[i].cmd == buf[0 ]) { + evt = els_cmd_list[i].evt; +break ; + } + } + +efc_node_post_event (node, evt, &cbdata); +} + +void +efc_node_recv_ct_frame (struct efc_node *node, +struct efc_hw_sequence *seq) +{ +struct fc_ct_hdr *iu = seq->payload->dma.virt; +struct fc_frame_header *hdr = seq->header->dma.virt; +struct efc *efc = node->efc; +u16 gscmd =be16_to_cpu (iu->ct_cmd); + +efc_log_err (efc,"[%s] Received cmd :%x sending CT_REJECT\n" , + node->display_name, gscmd); +efc_send_ct_rsp (efc, node,be16_to_cpu (hdr->fh_ox_id), iu, +FC_FS_RJT ,FC_FS_RJT_UNSUP ,0 ); +} + +void +efc_node_recv_fcp_cmd (struct efc_node *node,struct efc_hw_sequence *seq) +{ +struct efc_node_cb cbdata; + +memset (&cbdata,0 ,sizeof (cbdata)); + cbdata.header = seq->header; + cbdata.payload = seq->payload; + +efc_node_post_event (node,EFC_EVT_FCP_CMD_RCVD , &cbdata); +} + +void +efc_process_node_pending (struct efc_node *node) +{ +struct efc *efc = node->efc; +struct efc_hw_sequence *seq =NULL ; +u32 pend_frames_processed =0 ; +unsigned long flags =0 ; + +for (;;) { +/* need to check for hold frames condition after each frame +* processed because any given frame could cause a transition +* to a state that holds frames +*/ +if (node->hold_frames) +break ; + + seq =NULL ; +/* Get next frame/sequence */ +spin_lock_irqsave (&node->pend_frames_lock, flags); + +if (!list_empty (&node->pend_frames)) { + seq =list_first_entry (&node->pend_frames, + struct efc_hw_sequence, list_entry); +list_del (&seq->list_entry); + } +spin_unlock_irqrestore (&node->pend_frames_lock, flags); + +if (!seq) { + pend_frames_processed = node->pend_frames_processed; + node->pend_frames_processed =0 ; +break ; + } + node->pend_frames_processed++; + +/* now dispatch frame(s) to dispatch function */ +efc_node_dispatch_frame (node, seq); + efc->tt.hw_seq_free (efc, seq); + } + +if (pend_frames_processed !=0 ) +efc_log_debug (efc,"%u node frames held and processed\n" , + pend_frames_processed); +} + +void +efc_scsi_sess_reg_complete (struct efc_node *node,u32 status) +{ +unsigned long flags =0 ; +enum efc_sm_event evt =EFC_EVT_NODE_SESS_REG_OK ; +struct efc *efc = node->efc; + +if (status) + evt =EFC_EVT_NODE_SESS_REG_FAIL ; + +spin_lock_irqsave (&efc->lock, flags); +/* Notify the node to resume */ +efc_node_post_event (node, evt,NULL ); +spin_unlock_irqrestore (&efc->lock, flags); +} + +void +efc_scsi_del_initiator_complete (struct efc *efc,struct efc_node *node) +{ +unsigned long flags =0 ; + +spin_lock_irqsave (&efc->lock, flags); +/* Notify the node to resume */ +efc_node_post_event (node,EFC_EVT_NODE_DEL_INI_COMPLETE ,NULL ); +spin_unlock_irqrestore (&efc->lock, flags); +} + +void +efc_scsi_del_target_complete (struct efc *efc,struct efc_node *node) +{ +unsigned long flags =0 ; + +spin_lock_irqsave (&efc->lock, flags); +/* Notify the node to resume */ +efc_node_post_event (node,EFC_EVT_NODE_DEL_TGT_COMPLETE ,NULL ); +spin_unlock_irqrestore (&efc->lock, flags); +} + +void +efc_scsi_io_list_empty (struct efc *efc,struct efc_node *node) +{ +unsigned long flags =0 ; + +spin_lock_irqsave (&efc->lock, flags); +efc_node_post_event (node,EFC_EVT_NODE_ACTIVE_IO_LIST_EMPTY ,NULL ); +spin_unlock_irqrestore (&efc->lock, flags); +} + +void efc_node_post_els_resp (struct efc_node *node,u32 evt,void *arg) +{ +struct efc *efc = node->efc; +unsigned long flags =0 ; + +spin_lock_irqsave (&efc->lock, flags); +efc_node_post_event (node, evt, arg); +spin_unlock_irqrestore (&efc->lock, flags); +} + +void efc_node_post_shutdown (struct efc_node *node,u32 evt,void *arg) +{ +unsigned long flags =0 ; +struct efc *efc = node->efc; + +spin_lock_irqsave (&efc->lock, flags); +efc_node_post_event (node,EFC_EVT_SHUTDOWN , arg); +spin_unlock_irqrestore (&efc->lock, flags); +}
drivers/scsi/elx/libefc/efc_node.h new file +191 -0
191 lines not on this page · raw message
Signature · 1 line
2.26.2
Re: [PATCH v8 12/31] elx: libefc: Remote node state machine interfaces
Quoted 11 lines · James Smart
This patch continues the libefc library population.
This patch adds library interface definitions for:
- Remote node (aka remote port) allocation, initializaion and destroy routines.Co-developed-by Ram Vegesna <[email protected]>Signed-off-by Ram Vegesna <[email protected]>Signed-off-by James Smart <[email protected]>Reviewed-by Daniel Wagner <[email protected]>
Cheers,
Hannes
Signature · 4 lines
Dr. Hannes Reinecke Kernel Storage Architect [email protected] +49 911 74053 688 SUSE Software Solutions Germany GmbH, 90409 Nürnberg GF: F. Imendörffer, HRB 36809 (AG Nürnberg)
PATCH v8 13/31 elx: libefc: Fabric node state machine interfaces
In reply to James SmartThis patch continues the libefc library population.
This patch adds library interface definitions for:
- Fabric node initialization and logins.
- Name/Directory Services node.
- Fabric Controller node to process rscn events.
These are all interactions with remote ports that correspond to well-known fabric entities
--- drivers/scsi/elx/libefc/efc_fabric.c | 1565 ++++++++++++++++++++++++++ drivers/scsi/elx/libefc/efc_fabric.h | 116 ++ 2 files changed, 1681 insertions(+) create mode 100644 drivers/scsi/elx/libefc/efc_fabric.c create mode 100644 drivers/scsi/elx/libefc/efc_fabric.h
drivers/scsi/elx/libefc/efc_fabric.c new file +1565 -0
@@ -0,0 +1,1565 @@ +// SPDX-License-Identifier: GPL-2.0 +/* +* Copyright (C) 2021 Broadcom. All Rights Reserved. The term +* “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. +*/ + +/* +* This file implements remote node state machines for: +* - Fabric logins. +* - Fabric controller events. +* - Name/directory services interaction. +* - Point-to-point logins. +*/ + +/* +* fabric_sm Node State Machine: Fabric States +* ns_sm Node State Machine: Name/Directory Services States +* p2p_sm Node State Machine: Point-to-Point Node States +*/ + +#include "efc.h" + +static void +efc_fabric_initiate_shutdown (struct efc_node *node) +{ +struct efc *efc = node->efc; + +WRITE_ONCE (node->els_io_enabled, false); + +if (node->attached) { +int rc; + +/* issue hw node free; don't care if succeeds right away +* or sometime later, will check node->attached later in +* shutdown process +*/ + rc =efc_cmd_node_detach (efc, &node->rnode); +if (rc !=EFC_HW_RTN_SUCCESS && + rc !=EFC_HW_RTN_SUCCESS_SYNC ) { +node_printf (node,"Failed freeing HW node, rc=%d\n" , + rc); + } + } +/* +* node has either been detached or is in the process of being detached, +* call common node's initiate cleanup function +*/ +efc_node_initiate_cleanup (node); +} + +static void +__efc_fabric_common (const char *funcname,struct efc_sm_ctx *ctx, +enum efc_sm_event evt,void *arg) +{ +struct efc_node *node =NULL ; + + node = ctx->app; + +switch (evt) { +case EFC_EVT_DOMAIN_ATTACH_OK : +break ; +case EFC_EVT_SHUTDOWN : + node->shutdown_reason =EFC_NODE_SHUTDOWN_DEFAULT ; +efc_fabric_initiate_shutdown (node); +break ; + +default : +/* call default event handler common to all nodes */ +__efc_node_common (funcname, ctx, evt, arg); + } +} + +void +__efc_fabric_init (struct efc_sm_ctx *ctx,enum efc_sm_event evt, +void *arg) +{ +struct efc_node *node = ctx->app; +struct efc *efc = node->efc; + +efc_node_evt_set (ctx, evt, __func__); + +node_sm_trace (); + +switch (evt) { +case EFC_EVT_REENTER : +efc_log_debug (efc,">>> reenter !!\n" ); + fallthrough; + +case EFC_EVT_ENTER : +/* send FLOGI */ +efc_send_flogi (node); +efc_node_transition (node, __efc_fabric_flogi_wait_rsp,NULL ); +break ; + +default : +__efc_fabric_common (__func__, ctx, evt, arg); + } +} + +void +efc_fabric_set_topology (struct efc_node *node, +enum efc_nport_topology topology) +{ + node->nport->topology = topology; +} + +void +efc_fabric_notify_topology (struct efc_node *node) +{ +struct efc_node *tmp_node; +enum efc_nport_topology topology = node->nport->topology; +unsigned long index; + +/* +* now loop through the nodes in the nport +* and send topology notification +*/ +xa_for_each (&node->nport->lookup, index, tmp_node) { +if (tmp_node != node) { +efc_node_post_event (tmp_node, +EFC_EVT_NPORT_TOPOLOGY_NOTIFY , + (void *)topology); + } + } +} + +static bool efc_rnode_is_nport (struct fc_els_flogi *rsp) +{ +return !(ntohs (rsp->fl_csp.sp_features) &FC_SP_FT_FPORT ); +} + +void +__efc_fabric_flogi_wait_rsp (struct efc_sm_ctx *ctx, +enum efc_sm_event evt,void *arg) +{ +struct efc_node_cb *cbdata = arg; +struct efc_node *node = ctx->app; + +efc_node_evt_set (ctx, evt, __func__); + +node_sm_trace (); + +switch (evt) { +case EFC_EVT_SRRS_ELS_REQ_OK : { +if (efc_node_check_els_req (ctx, evt, arg,ELS_FLOGI , + __efc_fabric_common, __func__)) { +return ; + } +WARN_ON (!node->els_req_cnt); + node->els_req_cnt--; + +memcpy (node->nport->domain->flogi_service_params, + cbdata->els_rsp.virt, +sizeof (struct fc_els_flogi )); + +/* Check to see if the fabric is an F_PORT or and N_PORT */ +if (!efc_rnode_is_nport (cbdata->els_rsp.virt)) { +/* sm: if not nport / efc_domain_attach */ +/* ext_status has the fc_id, attach domain */ +efc_fabric_set_topology (node,EFC_NPORT_TOPO_FABRIC ); +efc_fabric_notify_topology (node); +WARN_ON (node->nport->domain->attached); +efc_domain_attach (node->nport->domain, + cbdata->ext_status); +efc_node_transition (node, + __efc_fabric_wait_domain_attach, +NULL ); +break ; + } + +/* sm: if nport and p2p_winner / efc_domain_attach */ +efc_fabric_set_topology (node,EFC_NPORT_TOPO_P2P ); +if (efc_p2p_setup (node->nport)) { +node_printf (node, +"p2p setup failed, shutting down node\n" ); + node->shutdown_reason =EFC_NODE_SHUTDOWN_DEFAULT ; +efc_fabric_initiate_shutdown (node); +break ; + } + +if (node->nport->p2p_winner) { +efc_node_transition (node, + __efc_p2p_wait_domain_attach, +NULL ); +if (node->nport->domain->attached && + !node->nport->domain->domain_notify_pend) { +/* +* already attached, +* just send ATTACH_OK +*/ +node_printf (node, +"p2p winner, domain already attached\n" ); +efc_node_post_event (node, +EFC_EVT_DOMAIN_ATTACH_OK , +NULL ); + } + }else { +/* +* peer is p2p winner; +* PLOGI will be received on the +* remote SID=1 node; +* this node has served its purpose +*/ + node->shutdown_reason =EFC_NODE_SHUTDOWN_DEFAULT ; +efc_fabric_initiate_shutdown (node); + } + +break ; + } + +case EFC_EVT_ELS_REQ_ABORTED : +case EFC_EVT_SRRS_ELS_REQ_RJT : +case EFC_EVT_SRRS_ELS_REQ_FAIL : { +struct efc_nport *nport = node->nport; +/* +* with these errors, we have no recovery, +* so shutdown the nport, leave the link +* up and the domain ready +*/ +if (efc_node_check_els_req (ctx, evt, arg,ELS_FLOGI , + __efc_fabric_common, __func__)) { +return ; + } +node_printf (node, +"FLOGI failed evt=%s, shutting down nport [%s]\n" , +efc_sm_event_name (evt), nport->display_name); +WARN_ON (!node->els_req_cnt); + node->els_req_cnt--; +efc_sm_post_event (&nport->sm,EFC_EVT_SHUTDOWN ,NULL ); +break ; + } + +default : +__efc_fabric_common (__func__, ctx, evt, arg); + } +} + +void +__efc_vport_fabric_init (struct efc_sm_ctx *ctx, +enum efc_sm_event evt,void *arg) +{ +struct efc_node *node = ctx->app; + +efc_node_evt_set (ctx, evt, __func__); + +node_sm_trace (); + +switch (evt) { +case EFC_EVT_ENTER : +/* sm: / send FDISC */ +efc_send_fdisc (node); +efc_node_transition (node, __efc_fabric_fdisc_wait_rsp,NULL ); +break ; + +default : +__efc_fabric_common (__func__, ctx, evt, arg); + } +} + +void +__efc_fabric_fdisc_wait_rsp (struct efc_sm_ctx *ctx, +enum efc_sm_event evt,void *arg) +{ +struct efc_node_cb *cbdata = arg; +struct efc_node *node = ctx->app; + +efc_node_evt_set (ctx, evt, __func__); + +node_sm_trace (); + +switch (evt) { +case EFC_EVT_SRRS_ELS_REQ_OK : { +/* fc_id is in ext_status */ +if (efc_node_check_els_req (ctx, evt, arg,ELS_FDISC , + __efc_fabric_common, __func__)) { +return ; + } + +WARN_ON (!node->els_req_cnt); + node->els_req_cnt--; +/* sm: / efc_nport_attach */ +efc_nport_attach (node->nport, cbdata->ext_status); +efc_node_transition (node, __efc_fabric_wait_domain_attach, +NULL ); +break ; + } + +case EFC_EVT_SRRS_ELS_REQ_RJT : +case EFC_EVT_SRRS_ELS_REQ_FAIL : { +if (efc_node_check_els_req (ctx, evt, arg,ELS_FDISC , + __efc_fabric_common, __func__)) { +return ; + } +WARN_ON (!node->els_req_cnt); + node->els_req_cnt--; +efc_log_err (node->efc,"FDISC failed, shutting down nport\n" ); +/* sm: / shutdown nport */ +efc_sm_post_event (&node->nport->sm,EFC_EVT_SHUTDOWN ,NULL ); +break ; + } + +default : +__efc_fabric_common (__func__, ctx, evt, arg); + } +} + +static int +efc_start_ns_node (struct efc_nport *nport) +{ +struct efc_node *ns; + +/* Instantiate a name services node */ + ns =efc_node_find (nport,FC_FID_DIR_SERV ); +if (!ns) { + ns =efc_node_alloc (nport,FC_FID_DIR_SERV , false, false); +if (!ns) +return EFC_FAIL ; + } +/* +* for found ns, should we be transitioning from here? +* breaks transition only +* 1. from within state machine or +* 2. if after alloc +*/ +if (ns->efc->nodedb_mask &EFC_NODEDB_PAUSE_NAMESERVER ) +efc_node_pause (ns, __efc_ns_init); +else +efc_node_transition (ns, __efc_ns_init,NULL ); +return EFC_SUCCESS ; +} + +static int +efc_start_fabctl_node (struct efc_nport *nport) +{ +struct efc_node *fabctl; + + fabctl =efc_node_find (nport,FC_FID_FCTRL ); +if (!fabctl) { + fabctl =efc_node_alloc (nport,FC_FID_FCTRL , + false, false); +if (!fabctl) +return EFC_FAIL ; + } +/* +* for found ns, should we be transitioning from here? +* breaks transition only +* 1. from within state machine or +* 2. if after alloc +*/ +efc_node_transition (fabctl, __efc_fabctl_init,NULL ); +return EFC_SUCCESS ; +} + +void +__efc_fabric_wait_domain_attach (struct efc_sm_ctx *ctx, +enum efc_sm_event evt,void *arg) +{ +struct efc_node *node = ctx->app; + +efc_node_evt_set (ctx, evt, __func__); + +node_sm_trace (); + +switch (evt) { +case EFC_EVT_ENTER : +efc_node_hold_frames (node); +break ; + +case EFC_EVT_EXIT : +efc_node_accept_frames (node); +break ; +case EFC_EVT_DOMAIN_ATTACH_OK : +case EFC_EVT_NPORT_ATTACH_OK : { +int rc; + + rc =efc_start_ns_node (node->nport); +if (rc) +return ; + +/* sm: if enable_ini / start fabctl node */ +/* Instantiate the fabric controller (sends SCR) */ +if (node->nport->enable_rscn) { + rc =efc_start_fabctl_node (node->nport); +if (rc) +return ; + } +efc_node_transition (node, __efc_fabric_idle,NULL ); +break ; + } +default : +__efc_fabric_common (__func__, ctx, evt, arg); + } +} + +void +__efc_fabric_idle (struct efc_sm_ctx *ctx,enum efc_sm_event evt, +void *arg) +{ +struct efc_node *node = ctx->app; + +efc_node_evt_set (ctx, evt, __func__); + +node_sm_trace (); + +switch (evt) { +case EFC_EVT_DOMAIN_ATTACH_OK : +break ; +default : +__efc_fabric_common (__func__, ctx, evt, arg); + } +} + +void +__efc_ns_init (struct efc_sm_ctx *ctx,enum efc_sm_event evt,void *arg) +{ +struct efc_node *node = ctx->app; + +efc_node_evt_set (ctx, evt, __func__); + +node_sm_trace (); + +switch (evt) { +case EFC_EVT_ENTER : +/* sm: / send PLOGI */ +efc_send_plogi (node); +efc_node_transition (node, __efc_ns_plogi_wait_rsp,NULL ); +break ; +default : +__efc_fabric_common (__func__, ctx, evt, arg); + } +} + +void +__efc_ns_plogi_wait_rsp (struct efc_sm_ctx *ctx, +enum efc_sm_event evt,void *arg) +{ +struct efc_node_cb *cbdata = arg; +struct efc_node *node = ctx->app; + +efc_node_evt_set (ctx, evt, __func__); + +node_sm_trace (); + +switch (evt) { +case EFC_EVT_SRRS_ELS_REQ_OK : { +int rc; + +/* Save service parameters */ +if (efc_node_check_els_req (ctx, evt, arg,ELS_PLOGI , + __efc_fabric_common, __func__)) { +return ; + } +WARN_ON (!node->els_req_cnt); + node->els_req_cnt--; +/* sm: / save sparams, efc_node_attach */ +efc_node_save_sparms (node, cbdata->els_rsp.virt); + rc =efc_node_attach (node); +efc_node_transition (node, __efc_ns_wait_node_attach,NULL ); +if (rc ==EFC_HW_RTN_SUCCESS_SYNC ) +efc_node_post_event (node,EFC_EVT_NODE_ATTACH_OK , +NULL ); +break ; + } +default : +__efc_fabric_common (__func__, ctx, evt, arg); + } +} + +void +__efc_ns_wait_node_attach (struct efc_sm_ctx *ctx, +enum efc_sm_event evt,void *arg) +{ +struct efc_node *node = ctx->app; + +efc_node_evt_set (ctx, evt, __func__); + +node_sm_trace (); + +switch (evt) { +case EFC_EVT_ENTER : +efc_node_hold_frames (node); +break ; + +case EFC_EVT_EXIT : +efc_node_accept_frames (node); +break ; + +case EFC_EVT_NODE_ATTACH_OK : + node->attached = true; +/* sm: / send RFTID */ +efc_ns_send_rftid (node); +efc_node_transition (node, __efc_ns_rftid_wait_rsp,NULL ); +break ; + +case EFC_EVT_NODE_ATTACH_FAIL : +/* node attach failed, shutdown the node */ + node->attached = false; +node_printf (node,"Node attach failed\n" ); + node->shutdown_reason =EFC_NODE_SHUTDOWN_DEFAULT ; +efc_fabric_initiate_shutdown (node); +break ; + +case EFC_EVT_SHUTDOWN : +node_printf (node,"Shutdown event received\n" ); + node->shutdown_reason =EFC_NODE_SHUTDOWN_DEFAULT ; +efc_node_transition (node, + __efc_fabric_wait_attach_evt_shutdown, +NULL ); +break ; + +/* +* if receive RSCN just ignore, +* we haven't sent GID_PT yet (ACC sent by fabctl node) +*/ +case EFC_EVT_RSCN_RCVD : +break ; + +default : +__efc_fabric_common (__func__, ctx, evt, arg); + } +} + +void +__efc_fabric_wait_attach_evt_shutdown (struct efc_sm_ctx *ctx, +enum efc_sm_event evt,void *arg) +{ +struct efc_node *node = ctx->app; + +efc_node_evt_set (ctx, evt, __func__); + +node_sm_trace (); + +switch (evt) { +case EFC_EVT_ENTER : +efc_node_hold_frames (node); +break ; + +case EFC_EVT_EXIT : +efc_node_accept_frames (node); +break ; + +/* wait for any of these attach events and then shutdown */ +case EFC_EVT_NODE_ATTACH_OK : + node->attached = true; +node_printf (node,"Attach evt=%s, proceed to shutdown\n" , +efc_sm_event_name (evt)); +efc_fabric_initiate_shutdown (node); +break ; + +case EFC_EVT_NODE_ATTACH_FAIL : + node->attached = false; +node_printf (node,"Attach evt=%s, proceed to shutdown\n" , +efc_sm_event_name (evt)); +efc_fabric_initiate_shutdown (node); +break ; + +/* ignore shutdown event as we're already in shutdown path */ +case EFC_EVT_SHUTDOWN : +node_printf (node,"Shutdown event received\n" ); +break ; + +default : +__efc_fabric_common (__func__, ctx, evt, arg); + } +} + +void +__efc_ns_rftid_wait_rsp (struct efc_sm_ctx *ctx, +enum efc_sm_event evt,void *arg) +{ +struct efc_node *node = ctx->app; + +efc_node_evt_set (ctx, evt, __func__); + +node_sm_trace (); + +switch (evt) { +case EFC_EVT_SRRS_ELS_REQ_OK : +if (efc_node_check_ns_req (ctx, evt, arg,FC_NS_RFT_ID , + __efc_fabric_common, __func__)) { +return ; + } +WARN_ON (!node->els_req_cnt); + node->els_req_cnt--; +/* sm: / send RFFID */ +efc_ns_send_rffid (node); +efc_node_transition (node, __efc_ns_rffid_wait_rsp,NULL ); +break ; + +/* +* if receive RSCN just ignore, +* we haven't sent GID_PT yet (ACC sent by fabctl node) +*/ +case EFC_EVT_RSCN_RCVD : +break ; + +default : +__efc_fabric_common (__func__, ctx, evt, arg); + } +} + +void +__efc_ns_rffid_wait_rsp (struct efc_sm_ctx *ctx, +enum efc_sm_event evt,void *arg) +{ +struct efc_node *node = ctx->app; + +efc_node_evt_set (ctx, evt, __func__); + +node_sm_trace (); + +/* +* Waits for an RFFID response event; +* if rscn enabled, a GIDPT name services request is issued. +*/ +switch (evt) { +case EFC_EVT_SRRS_ELS_REQ_OK : { +if (efc_node_check_ns_req (ctx, evt, arg,FC_NS_RFF_ID , + __efc_fabric_common, __func__)) { +return ; + } +WARN_ON (!node->els_req_cnt); + node->els_req_cnt--; +if (node->nport->enable_rscn) { +/* sm: if enable_rscn / send GIDPT */ +efc_ns_send_gidpt (node); + +efc_node_transition (node, __efc_ns_gidpt_wait_rsp, +NULL ); + }else { +/* if 'T' only, we're done, go to idle */ +efc_node_transition (node, __efc_ns_idle,NULL ); + } +break ; + } +/* +* if receive RSCN just ignore, +* we haven't sent GID_PT yet (ACC sent by fabctl node) +*/ +case EFC_EVT_RSCN_RCVD : +break ; + +default : +__efc_fabric_common (__func__, ctx, evt, arg); + } +} + +static int +efc_process_gidpt_payload (struct efc_node *node, +void *data,u32 gidpt_len) +{ +u32 i, j; +struct efc_node *newnode; +struct efc_nport *nport = node->nport; +struct efc *efc = node->efc; +u32 port_id =0 , port_count, plist_count; +struct efc_node *n; +struct efc_node **active_nodes; +int residual; +struct { +struct fc_ct_hdr hdr; +struct fc_gid_pn_resp pn_rsp; + } *rsp; +struct fc_gid_pn_resp *gidpt; +unsigned long index; + + rsp = data; + gidpt = &rsp->pn_rsp; + residual =be16_to_cpu (rsp->hdr.ct_mr_size); + +if (residual !=0 ) +efc_log_debug (node->efc,"residual is %u words\n" , residual); + +if (be16_to_cpu (rsp->hdr.ct_cmd) ==FC_FS_RJT ) { +node_printf (node, +"GIDPT request failed: rsn x%x rsn_expl x%x\n" , + rsp->hdr.ct_reason, rsp->hdr.ct_explan); +return EFC_FAIL ; + } + + plist_count = (gidpt_len -sizeof (struct fc_ct_hdr )) /sizeof (*gidpt); + +/* Count the number of nodes */ + port_count =0 ; +xa_for_each (&nport->lookup, index, n) { + port_count++; + } + +/* Allocate a buffer for all nodes */ + active_nodes =kzalloc (port_count *sizeof (*active_nodes),GFP_ATOMIC ); +if (!active_nodes) { +node_printf (node,"efc_malloc failed\n" ); +return EFC_FAIL ; + } + +/* Fill buffer with fc_id of active nodes */ + i =0 ; +xa_for_each (&nport->lookup, index, n) { + port_id = n->rnode.fc_id; +switch (port_id) { +case FC_FID_FLOGI : +case FC_FID_FCTRL : +case FC_FID_DIR_SERV : +break ; +default : +if (port_id !=FC_FID_DOM_MGR ) + active_nodes[i++] = n; +break ; + } + } + +/* update the active nodes buffer */ +for (i =0 ; i < plist_count; i++) { +hton24 (gidpt[i].fp_fid, port_id); + +for (j =0 ; j < port_count; j++) { +if (active_nodes[j] && + port_id == active_nodes[j]->rnode.fc_id) { + active_nodes[j] =NULL ; + } + } + +if (gidpt[i].fp_resvd &FC_NS_FID_LAST ) +break ; + } + +/* Those remaining in the active_nodes[] are now gone ! */ +for (i =0 ; i < port_count; i++) { +/* +* if we're an initiator and the remote node +* is a target, then post the node missing event. +* if we're target and we have enabled +* target RSCN, then post the node missing event. +*/ +if (!active_nodes[i]) +continue ; + +if ((node->nport->enable_ini && active_nodes[i]->targ) || + (node->nport->enable_tgt &&enable_target_rscn (efc))) { +efc_node_post_event (active_nodes[i], +EFC_EVT_NODE_MISSING ,NULL ); + }else { +node_printf (node, +"GID_PT: skipping non-tgt port_id x%06x\n" , + active_nodes[i]->rnode.fc_id); + } + } +kfree (active_nodes); + +for (i =0 ; i < plist_count; i++) { +hton24 (gidpt[i].fp_fid, port_id); + +/* Don't create node for ourselves */ +if (port_id == node->rnode.nport->fc_id) { +if (gidpt[i].fp_resvd &FC_NS_FID_LAST ) +break ; +continue ; + } + + newnode =efc_node_find (nport, port_id); +if (!newnode) { +if (!node->nport->enable_ini) +continue ; + + newnode =efc_node_alloc (nport, port_id, false, false); +if (!newnode) { +efc_log_err (efc,"efc_node_alloc() failed\n" ); +return EFC_FAIL ; + } +/* +* send PLOGI automatically +* if initiator +*/ +efc_node_init_device (newnode, true); + } + +if (node->nport->enable_ini && newnode->targ) { +efc_node_post_event (newnode,EFC_EVT_NODE_REFOUND , +NULL ); + } + +if (gidpt[i].fp_resvd &FC_NS_FID_LAST ) +break ; + } +return EFC_SUCCESS ; +} + +void +__efc_ns_gidpt_wait_rsp (struct efc_sm_ctx *ctx, +enum efc_sm_event evt,void *arg) +{ +struct efc_node_cb *cbdata = arg; +struct efc_node *node = ctx->app; + +efc_node_evt_set (ctx, evt, __func__); + +node_sm_trace (); +/* +* Wait for a GIDPT response from the name server. Process the FC_IDs +* that are reported by creating new remote ports, as needed. +*/ + +switch (evt) { +case EFC_EVT_SRRS_ELS_REQ_OK : { +if (efc_node_check_ns_req (ctx, evt, arg,FC_NS_GID_PT , + __efc_fabric_common, __func__)) { +return ; + } +WARN_ON (!node->els_req_cnt); + node->els_req_cnt--; +/* sm: / process GIDPT payload */ +efc_process_gidpt_payload (node, cbdata->els_rsp.virt, + cbdata->els_rsp.len); +efc_node_transition (node, __efc_ns_idle,NULL ); +break ; + } + +case EFC_EVT_SRRS_ELS_REQ_FAIL : { +/* not much we can do; will retry with the next RSCN */ +node_printf (node,"GID_PT failed to complete\n" ); +WARN_ON (!node->els_req_cnt); + node->els_req_cnt--; +efc_node_transition (node, __efc_ns_idle,NULL ); +break ; + } + +/* if receive RSCN here, queue up another discovery processing */ +case EFC_EVT_RSCN_RCVD : { +node_printf (node,"RSCN received during GID_PT processing\n" ); + node->rscn_pending = true; +break ; + } + +default : +__efc_fabric_common (__func__, ctx, evt, arg); + } +} + +void +__efc_ns_idle (struct efc_sm_ctx *ctx,enum efc_sm_event evt,void *arg) +{ +struct efc_node *node = ctx->app; +struct efc *efc = node->efc; + +efc_node_evt_set (ctx, evt, __func__); + +node_sm_trace (); + +/* +* Wait for RSCN received events (posted from the fabric controller) +* and restart the GIDPT name services query and processing. +*/ + +switch (evt) { +case EFC_EVT_ENTER : +if (!node->rscn_pending) +break ; + +node_printf (node,"RSCN pending, restart discovery\n" ); + node->rscn_pending = false; + fallthrough; + +case EFC_EVT_RSCN_RCVD : { +/* sm: / send GIDPT */ +/* +* If target RSCN processing is enabled, +* and this is target only (not initiator), +* and tgt_rscn_delay is non-zero, +* then we delay issuing the GID_PT +*/ +if (efc->tgt_rscn_delay_msec !=0 && + !node->nport->enable_ini && node->nport->enable_tgt && +enable_target_rscn (efc)) { +efc_node_transition (node, __efc_ns_gidpt_delay,NULL ); + }else { +efc_ns_send_gidpt (node); +efc_node_transition (node, __efc_ns_gidpt_wait_rsp, +NULL ); + } +break ; + } + +default : +__efc_fabric_common (__func__, ctx, evt, arg); + } +} + +static void +gidpt_delay_timer_cb (struct timer_list *t) +{ +struct efc_node *node =from_timer (node, t, gidpt_delay_timer); + +del_timer (&node->gidpt_delay_timer); + +efc_node_post_event (node,EFC_EVT_GIDPT_DELAY_EXPIRED ,NULL ); +} + +void +__efc_ns_gidpt_delay (struct efc_sm_ctx *ctx, +enum efc_sm_event evt,void *arg) +{ +struct efc_node *node = ctx->app; +struct efc *efc = node->efc; + +efc_node_evt_set (ctx, evt, __func__); + +node_sm_trace (); + +switch (evt) { +case EFC_EVT_ENTER : { +u64 delay_msec, tmp; + +/* +* Compute the delay time. +* Set to tgt_rscn_delay, if the time since last GIDPT +* is less than tgt_rscn_period, then use tgt_rscn_period. +*/ + delay_msec = efc->tgt_rscn_delay_msec; + tmp =jiffies_to_msecs (jiffies) - node->time_last_gidpt_msec; +if (tmp < efc->tgt_rscn_period_msec) + delay_msec = efc->tgt_rscn_period_msec; + +timer_setup (&node->gidpt_delay_timer, &gidpt_delay_timer_cb, +0 ); +mod_timer (&node->gidpt_delay_timer, + jiffies +msecs_to_jiffies (delay_msec)); + +break ; + } + +case EFC_EVT_GIDPT_DELAY_EXPIRED : + node->time_last_gidpt_msec =jiffies_to_msecs (jiffies); + +efc_ns_send_gidpt (node); +efc_node_transition (node, __efc_ns_gidpt_wait_rsp,NULL ); +break ; + +case EFC_EVT_RSCN_RCVD : { +efc_log_debug (efc, +"RSCN received while in GIDPT delay - no action\n" ); +break ; + } + +default : +__efc_fabric_common (__func__, ctx, evt, arg); + } +} + +void +__efc_fabctl_init (struct efc_sm_ctx *ctx, +enum efc_sm_event evt,void *arg) +{ +struct efc_node *node = ctx->app; + +node_sm_trace (); + +switch (evt) { +case EFC_EVT_ENTER : +/* no need to login to fabric controller, just send SCR */ +efc_send_scr (node); +efc_node_transition (node, __efc_fabctl_wait_scr_rsp,NULL ); +break ; + +case EFC_EVT_NODE_ATTACH_OK : + node->attached = true; +break ; + +default : +__efc_fabric_common (__func__, ctx, evt, arg); + } +} + +void +__efc_fabctl_wait_scr_rsp (struct efc_sm_ctx *ctx, +enum efc_sm_event evt,void *arg) +{ +struct efc_node *node = ctx->app; + +efc_node_evt_set (ctx, evt, __func__); + +node_sm_trace (); + +/* +* Fabric controller node state machine: +* Wait for an SCR response from the fabric controller. +*/ +switch (evt) { +case EFC_EVT_SRRS_ELS_REQ_OK : +if (efc_node_check_els_req (ctx, evt, arg,ELS_SCR , + __efc_fabric_common, __func__)) { +return ; + } +WARN_ON (!node->els_req_cnt); + node->els_req_cnt--; +efc_node_transition (node, __efc_fabctl_ready,NULL ); +break ; + +default : +__efc_fabric_common (__func__, ctx, evt, arg); + } +} + +static void +efc_process_rscn (struct efc_node *node,struct efc_node_cb *cbdata) +{ +struct efc *efc = node->efc; +struct efc_nport *nport = node->nport; +struct efc_node *ns; + +/* Forward this event to the name-services node */ + ns =efc_node_find (nport,FC_FID_DIR_SERV ); +if (ns) +efc_node_post_event (ns,EFC_EVT_RSCN_RCVD , cbdata); +else +efc_log_warn (efc,"can't find name server node\n" ); +} + +void +__efc_fabctl_ready (struct efc_sm_ctx *ctx, +enum efc_sm_event evt,void *arg) +{ +struct efc_node_cb *cbdata = arg; +struct efc_node *node = ctx->app; + +efc_node_evt_set (ctx, evt, __func__); + +node_sm_trace (); + +/* +* Fabric controller node state machine: Ready. +* In this state, the fabric controller sends a RSCN, which is received +* by this node and is forwarded to the name services node object; and +* the RSCN LS_ACC is sent. +*/ +switch (evt) { +case EFC_EVT_RSCN_RCVD : { +struct fc_frame_header *hdr = cbdata->header->dma.virt; + +/* +* sm: / process RSCN (forward to name services node), +* send LS_ACC +*/ +efc_process_rscn (node, cbdata); +efc_send_ls_acc (node,be16_to_cpu (hdr->fh_ox_id)); +efc_node_transition (node, __efc_fabctl_wait_ls_acc_cmpl, +NULL ); +break ; + } + +default : +__efc_fabric_common (__func__, ctx, evt, arg); + } +} + +void +__efc_fabctl_wait_ls_acc_cmpl (struct efc_sm_ctx *ctx, +enum efc_sm_event evt,void *arg) +{ +struct efc_node *node = ctx->app; + +efc_node_evt_set (ctx, evt, __func__); + +node_sm_trace (); + +switch (evt) { +case EFC_EVT_ENTER : +efc_node_hold_frames (node); +break ; + +case EFC_EVT_EXIT : +efc_node_accept_frames (node); +break ; + +case EFC_EVT_SRRS_ELS_CMPL_OK : +WARN_ON (!node->els_cmpl_cnt); + node->els_cmpl_cnt--; +efc_node_transition (node, __efc_fabctl_ready,NULL ); +break ; + +default : +__efc_fabric_common (__func__, ctx, evt, arg); + } +} + +static uint64_t +efc_get_wwpn (struct fc_els_flogi *sp) +{ +return be64_to_cpu (sp->fl_wwnn); +} + +static int +efc_rnode_is_winner (struct efc_nport *nport) +{ +struct fc_els_flogi *remote_sp; +u64 remote_wwpn; +u64 local_wwpn = nport->wwpn; +u64 wwn_bump =0 ; + + remote_sp = (struct fc_els_flogi *)nport->domain->flogi_service_params; + remote_wwpn =efc_get_wwpn (remote_sp); + + local_wwpn ^= wwn_bump; + +efc_log_debug (nport->efc,"r: %llx\n" , +be64_to_cpu (remote_sp->fl_wwpn)); +efc_log_debug (nport->efc,"l: %llx\n" , local_wwpn); + +if (remote_wwpn == local_wwpn) { +efc_log_warn (nport->efc, +"WWPN of remote node [%08x %08x] matches local WWPN\n" , + (u32)(local_wwpn >>32ll ), + (u32 )local_wwpn); +return -1 ; + } + +return (remote_wwpn > local_wwpn); +} + +void +__efc_p2p_wait_domain_attach (struct efc_sm_ctx *ctx, +enum efc_sm_event evt,void *arg) +{ +struct efc_node *node = ctx->app; +struct efc *efc = node->efc; + +efc_node_evt_set (ctx, evt, __func__); + +node_sm_trace (); + +switch (evt) { +case EFC_EVT_ENTER : +efc_node_hold_frames (node); +break ; + +case EFC_EVT_EXIT : +efc_node_accept_frames (node); +break ; + +case EFC_EVT_DOMAIN_ATTACH_OK : { +struct efc_nport *nport = node->nport; +struct efc_node *rnode; + +/* +* this transient node (SID=0 (recv'd FLOGI) +* or DID=fabric (sent FLOGI)) +* is the p2p winner, will use a separate node +* to send PLOGI to peer +*/ +WARN_ON (!node->nport->p2p_winner); + + rnode =efc_node_find (nport, node->nport->p2p_remote_port_id); +if (rnode) { +/* +* the "other" transient p2p node has +* already kicked off the +* new node from which PLOGI is sent +*/ +node_printf (node, +"Node with fc_id x%x already exists\n" , + rnode->rnode.fc_id); + }else { +/* +* create new node (SID=1, DID=2) +* from which to send PLOGI +*/ + rnode =efc_node_alloc (nport, + nport->p2p_remote_port_id, + false, false); +if (!rnode) { +efc_log_err (efc,"node alloc failed\n" ); +return ; + } + +efc_fabric_notify_topology (node); +/* sm: / allocate p2p remote node */ +efc_node_transition (rnode, __efc_p2p_rnode_init, +NULL ); + } + +/* +* the transient node (SID=0 or DID=fabric) +* has served its purpose +*/ +if (node->rnode.fc_id ==0 ) { +/* +* if this is the SID=0 node, +* move to the init state in case peer +* has restarted FLOGI discovery and FLOGI is pending +*/ +/* don't send PLOGI on efc_d_init entry */ +efc_node_init_device (node, false); + }else { +/* +* if this is the DID=fabric node +* (we initiated FLOGI), shut it down +*/ + node->shutdown_reason =EFC_NODE_SHUTDOWN_DEFAULT ; +efc_fabric_initiate_shutdown (node); + } +break ; + } + +default : +__efc_fabric_common (__func__, ctx, evt, arg); + } +} + +void +__efc_p2p_rnode_init (struct efc_sm_ctx *ctx, +enum efc_sm_event evt,void *arg) +{ +struct efc_node_cb *cbdata = arg; +struct efc_node *node = ctx->app; + +efc_node_evt_set (ctx, evt, __func__); + +node_sm_trace (); + +switch (evt) { +case EFC_EVT_ENTER : +/* sm: / send PLOGI */ +efc_send_plogi (node); +efc_node_transition (node, __efc_p2p_wait_plogi_rsp,NULL ); +break ; + +case EFC_EVT_ABTS_RCVD : +/* sm: send BA_ACC */ +efc_send_bls_acc (node, cbdata->header->dma.virt); + +break ; + +default : +__efc_fabric_common (__func__, ctx, evt, arg); + } +} + +void +__efc_p2p_wait_flogi_acc_cmpl (struct efc_sm_ctx *ctx, +enum efc_sm_event evt,void *arg) +{ +struct efc_node_cb *cbdata = arg; +struct efc_node *node = ctx->app; + +efc_node_evt_set (ctx, evt, __func__); + +node_sm_trace (); + +switch (evt) { +case EFC_EVT_ENTER : +efc_node_hold_frames (node); +break ; + +case EFC_EVT_EXIT : +efc_node_accept_frames (node); +break ; + +case EFC_EVT_SRRS_ELS_CMPL_OK : +WARN_ON (!node->els_cmpl_cnt); + node->els_cmpl_cnt--; + +/* sm: if p2p_winner / domain_attach */ +if (node->nport->p2p_winner) { +efc_node_transition (node, + __efc_p2p_wait_domain_attach, +NULL ); +if (!node->nport->domain->attached) { +node_printf (node,"Domain not attached\n" ); +efc_domain_attach (node->nport->domain, + node->nport->p2p_port_id); + }else { +node_printf (node,"Domain already attached\n" ); +efc_node_post_event (node, +EFC_EVT_DOMAIN_ATTACH_OK , +NULL ); + } + }else { +/* this node has served its purpose; +* we'll expect a PLOGI on a separate +* node (remote SID=0x1); return this node +* to init state in case peer +* restarts discovery -- it may already +* have (pending frames may exist). +*/ +/* don't send PLOGI on efc_d_init entry */ +efc_node_init_device (node, false); + } +break ; + +case EFC_EVT_SRRS_ELS_CMPL_FAIL : +/* +* LS_ACC failed, possibly due to link down; +* shutdown node and wait +* for FLOGI discovery to restart +*/ +node_printf (node,"FLOGI LS_ACC failed, shutting down\n" ); +WARN_ON (!node->els_cmpl_cnt); + node->els_cmpl_cnt--; + node->shutdown_reason =EFC_NODE_SHUTDOWN_DEFAULT ; +efc_fabric_initiate_shutdown (node); +break ; + +case EFC_EVT_ABTS_RCVD : { +/* sm: / send BA_ACC */ +efc_send_bls_acc (node, cbdata->header->dma.virt); +break ; + } + +default : +__efc_fabric_common (__func__, ctx, evt, arg); + } +} + +void +__efc_p2p_wait_plogi_rsp (struct efc_sm_ctx *ctx, +enum efc_sm_event evt,void *arg) +{ +struct efc_node_cb *cbdata = arg; +struct efc_node *node = ctx->app; + +efc_node_evt_set (ctx, evt, __func__); + +node_sm_trace (); + +switch (evt) { +case EFC_EVT_SRRS_ELS_REQ_OK : { +int rc; + +if (efc_node_check_els_req (ctx, evt, arg,ELS_PLOGI , + __efc_fabric_common, __func__)) { +return ; + } +WARN_ON (!node->els_req_cnt); + node->els_req_cnt--; +/* sm: / save sparams, efc_node_attach */ +efc_node_save_sparms (node, cbdata->els_rsp.virt); + rc =efc_node_attach (node); +efc_node_transition (node, __efc_p2p_wait_node_attach,NULL ); +if (rc ==EFC_HW_RTN_SUCCESS_SYNC ) +efc_node_post_event (node,EFC_EVT_NODE_ATTACH_OK , +NULL ); +break ; + } +case EFC_EVT_SRRS_ELS_REQ_FAIL : { +if (efc_node_check_els_req (ctx, evt, arg,ELS_PLOGI , + __efc_fabric_common, __func__)) { +return ; + } +node_printf (node,"PLOGI failed, shutting down\n" ); +WARN_ON (!node->els_req_cnt); + node->els_req_cnt--; + node->shutdown_reason =EFC_NODE_SHUTDOWN_DEFAULT ; +efc_fabric_initiate_shutdown (node); +break ; + } + +case EFC_EVT_PLOGI_RCVD : { +struct fc_frame_header *hdr = cbdata->header->dma.virt; +/* if we're in external loopback mode, just send LS_ACC */ +if (node->efc->external_loopback) { +efc_send_plogi_acc (node,be16_to_cpu (hdr->fh_ox_id)); + }else { +/* +* if this isn't external loopback, +* pass to default handler +*/ +__efc_fabric_common (__func__, ctx, evt, arg); + } +break ; + } +case EFC_EVT_PRLI_RCVD : +/* I, or I+T */ +/* sent PLOGI and before completion was seen, received the +* PRLI from the remote node (WCQEs and RCQEs come in on +* different queues and order of processing cannot be assumed) +* Save OXID so PRLI can be sent after the attach and continue +* to wait for PLOGI response +*/ +efc_process_prli_payload (node, cbdata->payload->dma.virt); +efc_send_ls_acc_after_attach (node, + cbdata->header->dma.virt, +EFC_NODE_SEND_LS_ACC_PRLI ); +efc_node_transition (node, __efc_p2p_wait_plogi_rsp_recvd_prli, +NULL ); +break ; +default : +__efc_fabric_common (__func__, ctx, evt, arg); + } +} + +void +__efc_p2p_wait_plogi_rsp_recvd_prli (struct efc_sm_ctx *ctx, +enum efc_sm_event evt,void *arg) +{ +struct efc_node_cb *cbdata = arg; +struct efc_node *node = ctx->app; + +efc_node_evt_set (ctx, evt, __func__); + +node_sm_trace (); + +switch (evt) { +case EFC_EVT_ENTER : +/* +* Since we've received a PRLI, we have a port login and will +* just need to wait for the PLOGI response to do the node +* attach and then we can send the LS_ACC for the PRLI. If, +* during this time, we receive FCP_CMNDs (which is possible +* since we've already sent a PRLI and our peer may have +* accepted). +* At this time, we are not waiting on any other unsolicited +* frames to continue with the login process. Thus, it will not +* hurt to hold frames here. +*/ +efc_node_hold_frames (node); +break ; + +case EFC_EVT_EXIT : +efc_node_accept_frames (node); +break ; + +case EFC_EVT_SRRS_ELS_REQ_OK : {/* PLOGI response received */ +int rc; + +/* Completion from PLOGI sent */ +if (efc_node_check_els_req (ctx, evt, arg,ELS_PLOGI , + __efc_fabric_common, __func__)) { +return ; + } +WARN_ON (!node->els_req_cnt); + node->els_req_cnt--; +/* sm: / save sparams, efc_node_attach */ +efc_node_save_sparms (node, cbdata->els_rsp.virt); + rc =efc_node_attach (node); +efc_node_transition (node, __efc_p2p_wait_node_attach,NULL ); +if (rc ==EFC_HW_RTN_SUCCESS_SYNC ) +efc_node_post_event (node,EFC_EVT_NODE_ATTACH_OK , +NULL ); +break ; + } +case EFC_EVT_SRRS_ELS_REQ_FAIL :/* PLOGI response received */ +case EFC_EVT_SRRS_ELS_REQ_RJT : +/* PLOGI failed, shutdown the node */ +if (efc_node_check_els_req (ctx, evt, arg,ELS_PLOGI , + __efc_fabric_common, __func__)) { +return ; + } +WARN_ON (!node->els_req_cnt); + node->els_req_cnt--; + node->shutdown_reason =EFC_NODE_SHUTDOWN_DEFAULT ; +efc_fabric_initiate_shutdown (node); +break ; + +default : +__efc_fabric_common (__func__, ctx, evt, arg); + } +} + +void +__efc_p2p_wait_node_attach (struct efc_sm_ctx *ctx, +enum efc_sm_event evt,void *arg) +{ +struct efc_node_cb *cbdata = arg; +struct efc_node *node = ctx->app; + +efc_node_evt_set (ctx, evt, __func__); + +node_sm_trace (); + +switch (evt) { +case EFC_EVT_ENTER : +efc_node_hold_frames (node); +break ; + +case EFC_EVT_EXIT : +efc_node_accept_frames (node); +break ; + +case EFC_EVT_NODE_ATTACH_OK : + node->attached = true; +switch (node->send_ls_acc) { +case EFC_NODE_SEND_LS_ACC_PRLI : { +efc_d_send_prli_rsp (node->ls_acc_io, + node->ls_acc_oxid); + node->send_ls_acc =EFC_NODE_SEND_LS_ACC_NONE ; + node->ls_acc_io =NULL ; +break ; + } +case EFC_NODE_SEND_LS_ACC_PLOGI :/* Can't happen in P2P */ +case EFC_NODE_SEND_LS_ACC_NONE : +default : +/* Normal case for I */ +/* sm: send_plogi_acc is not set / send PLOGI acc */ +efc_node_transition (node, __efc_d_port_logged_in, +NULL ); +break ; + } +break ; + +case EFC_EVT_NODE_ATTACH_FAIL : +/* node attach failed, shutdown the node */ + node->attached = false; +node_printf (node,"Node attach failed\n" ); + node->shutdown_reason =EFC_NODE_SHUTDOWN_DEFAULT ; +efc_fabric_initiate_shutdown (node); +break ; + +case EFC_EVT_SHUTDOWN : +node_printf (node,"%s received\n" ,efc_sm_event_name (evt)); + node->shutdown_reason =EFC_NODE_SHUTDOWN_DEFAULT ; +efc_node_transition (node, + __efc_fabric_wait_attach_evt_shutdown, +NULL ); +break ; +case EFC_EVT_PRLI_RCVD : +node_printf (node,"%s: PRLI received before node is attached\n" , +efc_sm_event_name (evt)); +efc_process_prli_payload (node, cbdata->payload->dma.virt); +efc_send_ls_acc_after_attach (node, + cbdata->header->dma.virt, +EFC_NODE_SEND_LS_ACC_PRLI ); +break ; + +default : +__efc_fabric_common (__func__, ctx, evt, arg); + } +} + +int +efc_p2p_setup (struct efc_nport *nport) +{ +struct efc *efc = nport->efc; +int rnode_winner; + + rnode_winner =efc_rnode_is_winner (nport); + +/* set nport flags to indicate p2p "winner" */ +if (rnode_winner ==1 ) { + nport->p2p_remote_port_id =0 ; + nport->p2p_port_id =0 ; + nport->p2p_winner = false; + }else if (rnode_winner ==0 ) { + nport->p2p_remote_port_id =2 ; + nport->p2p_port_id =1 ; + nport->p2p_winner = true; + }else { +/* no winner; only okay if external loopback enabled */ +if (nport->efc->external_loopback) { +/* +* External loopback mode enabled; +* local nport and remote node +* will be registered with an NPortID = 1; +*/ +efc_log_debug (efc, +"External loopback mode enabled\n" ); + nport->p2p_remote_port_id =1 ; + nport->p2p_port_id =1 ; + nport->p2p_winner = true; + }else { +efc_log_warn (efc, +"failed to determine p2p winner\n" ); +return rnode_winner; + } + } +return EFC_SUCCESS ; +}
drivers/scsi/elx/libefc/efc_fabric.h new file +116 -0
116 lines not on this page · raw message
Signature · 1 line
2.26.2
PATCH v8 14/31 elx: libefc: FC node ELS and state handling
In reply to James SmartThis patch continues the libefc library population.
This patch adds library interface definitions for:
- FC node PRLI handling and state management
--- drivers/scsi/elx/libefc/efc_device.c | 1601 ++++++++++++++++++++++++++ drivers/scsi/elx/libefc/efc_device.h | 72 ++ 2 files changed, 1673 insertions(+) create mode 100644 drivers/scsi/elx/libefc/efc_device.c create mode 100644 drivers/scsi/elx/libefc/efc_device.h
drivers/scsi/elx/libefc/efc_device.c new file +1601 -0
@@ -0,0 +1,1601 @@ +// SPDX-License-Identifier: GPL-2.0 +/* +* Copyright (C) 2021 Broadcom. All Rights Reserved. The term +* “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. +*/ + +/* +* device_sm Node State Machine: Remote Device States +*/ + +#include "efc.h" +#include "efc_device.h" +#include "efc_fabric.h" + +void +efc_d_send_prli_rsp (struct efc_node *node,uint16_t ox_id) +{ +u32 rc =EFC_SCSI_CALL_COMPLETE ; +struct efc *efc = node->efc; + + node->ls_acc_oxid = ox_id; + node->send_ls_acc =EFC_NODE_SEND_LS_ACC_PRLI ; + +/* +* Wait for backend session registration +* to complete before sending PRLI resp +*/ + +if (node->init) { +efc_log_info (efc,"[%s] found(initiator) WWPN:%s WWNN:%s\n" , + node->display_name, node->wwpn, node->wwnn); +if (node->nport->enable_tgt) + rc = efc->tt.scsi_new_node (efc, node); + } + +if (rc ==EFC_SCSI_CALL_COMPLETE ) +efc_node_post_event (node,EFC_EVT_NODE_SESS_REG_OK ,NULL ); +} + +static void +__efc_d_common (const char *funcname,struct efc_sm_ctx *ctx, +enum efc_sm_event evt,void *arg) +{ +struct efc_node *node =NULL ; +struct efc *efc =NULL ; + + node = ctx->app; + efc = node->efc; + +switch (evt) { +/* Handle shutdown events */ +case EFC_EVT_SHUTDOWN : +efc_log_debug (efc,"[%s] %-20s %-20s\n" , node->display_name, + funcname,efc_sm_event_name (evt)); + node->shutdown_reason =EFC_NODE_SHUTDOWN_DEFAULT ; +efc_node_transition (node, __efc_d_initiate_shutdown,NULL ); +break ; +case EFC_EVT_SHUTDOWN_EXPLICIT_LOGO : +efc_log_debug (efc,"[%s] %-20s %-20s\n" , + node->display_name, funcname, +efc_sm_event_name (evt)); + node->shutdown_reason =EFC_NODE_SHUTDOWN_EXPLICIT_LOGO ; +efc_node_transition (node, __efc_d_initiate_shutdown,NULL ); +break ; +case EFC_EVT_SHUTDOWN_IMPLICIT_LOGO : +efc_log_debug (efc,"[%s] %-20s %-20s\n" , node->display_name, + funcname,efc_sm_event_name (evt)); + node->shutdown_reason =EFC_NODE_SHUTDOWN_IMPLICIT_LOGO ; +efc_node_transition (node, __efc_d_initiate_shutdown,NULL ); +break ; + +default : +/* call default event handler common to all nodes */ +__efc_node_common (funcname, ctx, evt, arg); + } +} + +static void +__efc_d_wait_del_node (struct efc_sm_ctx *ctx, +enum efc_sm_event evt,void *arg) +{ +struct efc_node *node = ctx->app; + +efc_node_evt_set (ctx, evt, __func__); + +/* +* State is entered when a node sends a delete initiator/target call +* to the target-server/initiator-client and needs to wait for that +* work to complete. +*/ +node_sm_trace (); + +switch (evt) { +case EFC_EVT_ENTER : +efc_node_hold_frames (node); + fallthrough; + +case EFC_EVT_NODE_ACTIVE_IO_LIST_EMPTY : +case EFC_EVT_ALL_CHILD_NODES_FREE : +/* These are expected events. */ +break ; + +case EFC_EVT_NODE_DEL_INI_COMPLETE : +case EFC_EVT_NODE_DEL_TGT_COMPLETE : +/* +* node has either been detached or is in the process +* of being detached, +* call common node's initiate cleanup function +*/ +efc_node_initiate_cleanup (node); +break ; + +case EFC_EVT_EXIT : +efc_node_accept_frames (node); +break ; + +case EFC_EVT_SRRS_ELS_REQ_FAIL : +/* Can happen as ELS IO IO's complete */ +WARN_ON (!node->els_req_cnt); + node->els_req_cnt--; +break ; + +/* ignore shutdown events as we're already in shutdown path */ +case EFC_EVT_SHUTDOWN : +/* have default shutdown event take precedence */ + node->shutdown_reason =EFC_NODE_SHUTDOWN_DEFAULT ; + fallthrough; + +case EFC_EVT_SHUTDOWN_EXPLICIT_LOGO : +case EFC_EVT_SHUTDOWN_IMPLICIT_LOGO : +node_printf (node,"%s received\n" ,efc_sm_event_name (evt)); +break ; +case EFC_EVT_DOMAIN_ATTACH_OK : +/* don't care about domain_attach_ok */ +break ; +default : +__efc_d_common (__func__, ctx, evt, arg); + } +} + +static void +__efc_d_wait_del_ini_tgt (struct efc_sm_ctx *ctx, +enum efc_sm_event evt,void *arg) +{ +struct efc_node *node = ctx->app; + +efc_node_evt_set (ctx, evt, __func__); + +node_sm_trace (); + +switch (evt) { +case EFC_EVT_ENTER : +efc_node_hold_frames (node); + fallthrough; + +case EFC_EVT_NODE_ACTIVE_IO_LIST_EMPTY : +case EFC_EVT_ALL_CHILD_NODES_FREE : +/* These are expected events. */ +break ; + +case EFC_EVT_NODE_DEL_INI_COMPLETE : +case EFC_EVT_NODE_DEL_TGT_COMPLETE : +efc_node_transition (node, __efc_d_wait_del_node,NULL ); +break ; + +case EFC_EVT_EXIT : +efc_node_accept_frames (node); +break ; + +case EFC_EVT_SRRS_ELS_REQ_FAIL : +/* Can happen as ELS IO IO's complete */ +WARN_ON (!node->els_req_cnt); + node->els_req_cnt--; +break ; + +/* ignore shutdown events as we're already in shutdown path */ +case EFC_EVT_SHUTDOWN : +/* have default shutdown event take precedence */ + node->shutdown_reason =EFC_NODE_SHUTDOWN_DEFAULT ; + fallthrough; + +case EFC_EVT_SHUTDOWN_EXPLICIT_LOGO : +case EFC_EVT_SHUTDOWN_IMPLICIT_LOGO : +node_printf (node,"%s received\n" ,efc_sm_event_name (evt)); +break ; +case EFC_EVT_DOMAIN_ATTACH_OK : +/* don't care about domain_attach_ok */ +break ; +default : +__efc_d_common (__func__, ctx, evt, arg); + } +} + +void +__efc_d_initiate_shutdown (struct efc_sm_ctx *ctx, +enum efc_sm_event evt,void *arg) +{ +struct efc_node *node = ctx->app; +struct efc *efc = node->efc; + +efc_node_evt_set (ctx, evt, __func__); + +node_sm_trace (); + +switch (evt) { +case EFC_EVT_ENTER : { +int rc =EFC_SCSI_CALL_COMPLETE ; + +/* assume no wait needed */ +WRITE_ONCE (node->els_io_enabled, false); + +/* make necessary delete upcall(s) */ +if (node->init && !node->targ) { +efc_log_info (node->efc, +"[%s] delete (initiator) WWPN %s WWNN %s\n" , + node->display_name, + node->wwpn, node->wwnn); +efc_node_transition (node, + __efc_d_wait_del_node, +NULL ); +if (node->nport->enable_tgt) + rc = efc->tt.scsi_del_node (efc, node, +EFC_SCSI_INITIATOR_DELETED ); + +if (rc ==EFC_SCSI_CALL_COMPLETE ) +efc_node_post_event (node, +EFC_EVT_NODE_DEL_INI_COMPLETE ,NULL ); + + }else if (node->targ && !node->init) { +efc_log_info (node->efc, +"[%s] delete (target) WWPN %s WWNN %s\n" , + node->display_name, + node->wwpn, node->wwnn); +efc_node_transition (node, + __efc_d_wait_del_node, +NULL ); +if (node->nport->enable_ini) + rc = efc->tt.scsi_del_node (efc, node, +EFC_SCSI_TARGET_DELETED ); + +if (rc ==EFC_SCSI_CALL_COMPLETE ) +efc_node_post_event (node, +EFC_EVT_NODE_DEL_TGT_COMPLETE ,NULL ); + + }else if (node->init && node->targ) { +efc_log_info (node->efc, +"[%s] delete (I+T) WWPN %s WWNN %s\n" , + node->display_name, node->wwpn, node->wwnn); +efc_node_transition (node, __efc_d_wait_del_ini_tgt, +NULL ); +if (node->nport->enable_tgt) + rc = efc->tt.scsi_del_node (efc, node, +EFC_SCSI_INITIATOR_DELETED ); + +if (rc ==EFC_SCSI_CALL_COMPLETE ) +efc_node_post_event (node, +EFC_EVT_NODE_DEL_INI_COMPLETE ,NULL ); +/* assume no wait needed */ + rc =EFC_SCSI_CALL_COMPLETE ; +if (node->nport->enable_ini) + rc = efc->tt.scsi_del_node (efc, node, +EFC_SCSI_TARGET_DELETED ); + +if (rc ==EFC_SCSI_CALL_COMPLETE ) +efc_node_post_event (node, +EFC_EVT_NODE_DEL_TGT_COMPLETE ,NULL ); + } + +/* we've initiated the upcalls as needed, now kick off the node +* detach to precipitate the aborting of outstanding exchanges +* associated with said node +* +* Beware: if we've made upcall(s), we've already transitioned +* to a new state by the time we execute this. +* consider doing this before the upcalls? +*/ +if (node->attached) { +/* issue hw node free; don't care if succeeds right +* away or sometime later, will check node->attached +* later in shutdown process +*/ + rc =efc_cmd_node_detach (efc, &node->rnode); +if (rc !=EFC_HW_RTN_SUCCESS && + rc !=EFC_HW_RTN_SUCCESS_SYNC ) +node_printf (node, +"Failed freeing HW node, rc=%d\n" , + rc); + } + +/* if neither initiator nor target, proceed to cleanup */ +if (!node->init && !node->targ) { +/* +* node has either been detached or is in +* the process of being detached, +* call common node's initiate cleanup function +*/ +efc_node_initiate_cleanup (node); + } +break ; + } +case EFC_EVT_ALL_CHILD_NODES_FREE : +/* Ignore, this can happen if an ELS is +* aborted while in a delay/retry state +*/ +break ; +default : +__efc_d_common (__func__, ctx, evt, arg); + } +} + +void +__efc_d_wait_loop (struct efc_sm_ctx *ctx, +enum efc_sm_event evt,void *arg) +{ +struct efc_node *node = ctx->app; + +efc_node_evt_set (ctx, evt, __func__); + +node_sm_trace (); + +switch (evt) { +case EFC_EVT_ENTER : +efc_node_hold_frames (node); +break ; + +case EFC_EVT_EXIT : +efc_node_accept_frames (node); +break ; + +case EFC_EVT_DOMAIN_ATTACH_OK : { +/* send PLOGI automatically if initiator */ +efc_node_init_device (node, true); +break ; + } +default : +__efc_d_common (__func__, ctx, evt, arg); + } +} + +void +efc_send_ls_acc_after_attach (struct efc_node *node, +struct fc_frame_header *hdr, +enum efc_node_send_ls_acc ls) +{ +u16 ox_id =be16_to_cpu (hdr->fh_ox_id); + +/* Save the OX_ID for sending LS_ACC sometime later */ +WARN_ON (node->send_ls_acc !=EFC_NODE_SEND_LS_ACC_NONE ); + + node->ls_acc_oxid = ox_id; + node->send_ls_acc = ls; + node->ls_acc_did =ntoh24 (hdr->fh_d_id); +} + +void +efc_process_prli_payload (struct efc_node *node,void *prli) +{ +struct { +struct fc_els_prli prli; +struct fc_els_spp sp; + } *pp; + + pp = prli; + node->init = (pp->sp.spp_flags &FCP_SPPF_INIT_FCN ) !=0 ; + node->targ = (pp->sp.spp_flags &FCP_SPPF_TARG_FCN ) !=0 ; +} + +void +__efc_d_wait_plogi_acc_cmpl (struct efc_sm_ctx *ctx, +enum efc_sm_event evt,void *arg) +{ +struct efc_node *node = ctx->app; + +efc_node_evt_set (ctx, evt, __func__); + +node_sm_trace (); + +switch (evt) { +case EFC_EVT_ENTER : +efc_node_hold_frames (node); +break ; + +case EFC_EVT_EXIT : +efc_node_accept_frames (node); +break ; + +case EFC_EVT_SRRS_ELS_CMPL_FAIL : +WARN_ON (!node->els_cmpl_cnt); + node->els_cmpl_cnt--; + node->shutdown_reason =EFC_NODE_SHUTDOWN_DEFAULT ; +efc_node_transition (node, __efc_d_initiate_shutdown,NULL ); +break ; + +case EFC_EVT_SRRS_ELS_CMPL_OK :/* PLOGI ACC completions */ +WARN_ON (!node->els_cmpl_cnt); + node->els_cmpl_cnt--; +efc_node_transition (node, __efc_d_port_logged_in,NULL ); +break ; + +default : +__efc_d_common (__func__, ctx, evt, arg); + } +} + +void +__efc_d_wait_logo_rsp (struct efc_sm_ctx *ctx, +enum efc_sm_event evt,void *arg) +{ +struct efc_node *node = ctx->app; + +efc_node_evt_set (ctx, evt, __func__); + +node_sm_trace (); + +switch (evt) { +case EFC_EVT_ENTER : +efc_node_hold_frames (node); +break ; + +case EFC_EVT_EXIT : +efc_node_accept_frames (node); +break ; + +case EFC_EVT_SRRS_ELS_REQ_OK : +case EFC_EVT_SRRS_ELS_REQ_RJT : +case EFC_EVT_SRRS_ELS_REQ_FAIL : +/* LOGO response received, sent shutdown */ +if (efc_node_check_els_req (ctx, evt, arg,ELS_LOGO , + __efc_d_common, __func__)) +return ; + +WARN_ON (!node->els_req_cnt); + node->els_req_cnt--; +node_printf (node, +"LOGO sent (evt=%s), shutdown node\n" , +efc_sm_event_name (evt)); +/* sm: / post explicit logout */ +efc_node_post_event (node,EFC_EVT_SHUTDOWN_EXPLICIT_LOGO , +NULL ); +break ; + +default : +__efc_d_common (__func__, ctx, evt, arg); + } +} + +void +efc_node_init_device (struct efc_node *node,bool send_plogi) +{ + node->send_plogi = send_plogi; +if ((node->efc->nodedb_mask &EFC_NODEDB_PAUSE_NEW_NODES ) && + (node->rnode.fc_id !=FC_FID_DOM_MGR )) { + node->nodedb_state = __efc_d_init; +efc_node_transition (node, __efc_node_paused,NULL ); + }else { +efc_node_transition (node, __efc_d_init,NULL ); + } +} + +static void +efc_d_check_plogi_topology (struct efc_node *node,u32 d_id) +{ +switch (node->nport->topology) { +case EFC_NPORT_TOPO_P2P : +/* we're not attached and nport is p2p, +* need to attach +*/ +efc_domain_attach (node->nport->domain, d_id); +efc_node_transition (node, __efc_d_wait_domain_attach,NULL ); +break ; +case EFC_NPORT_TOPO_FABRIC : +/* we're not attached and nport is fabric, domain +* attach should have already been requested as part +* of the fabric state machine, wait for it +*/ +efc_node_transition (node, __efc_d_wait_domain_attach,NULL ); +break ; +case EFC_NPORT_TOPO_UNKNOWN : +/* Two possibilities: +* 1. received a PLOGI before our FLOGI has completed +* (possible since completion comes in on another +* CQ), thus we don't know what we're connected to +* yet; transition to a state to wait for the +* fabric node to tell us; +* 2. PLOGI received before link went down and we +* haven't performed domain attach yet. +* Note: we cannot distinguish between 1. and 2. +* so have to assume PLOGI +* was received after link back up. +*/ +node_printf (node,"received PLOGI, unknown topology did=0x%x\n" , + d_id); +efc_node_transition (node, __efc_d_wait_topology_notify,NULL ); +break ; +default : +node_printf (node,"received PLOGI, unexpected topology %d\n" , + node->nport->topology); + } +} + +void +__efc_d_init (struct efc_sm_ctx *ctx,enum efc_sm_event evt,void *arg) +{ +struct efc_node_cb *cbdata = arg; +struct efc_node *node = ctx->app; + +efc_node_evt_set (ctx, evt, __func__); + +node_sm_trace (); + +/* +* This state is entered when a node is instantiated, +* either having been discovered from a name services query, +* or having received a PLOGI/FLOGI. +*/ +switch (evt) { +case EFC_EVT_ENTER : +if (!node->send_plogi) +break ; +/* only send if we have initiator capability, +* and domain is attached +*/ +if (node->nport->enable_ini && + node->nport->domain->attached) { +efc_send_plogi (node); + +efc_node_transition (node, __efc_d_wait_plogi_rsp,NULL ); + }else { +node_printf (node,"not sending plogi nport.ini=%d," , + node->nport->enable_ini); +node_printf (node,"domain attached=%d\n" , + node->nport->domain->attached); + } +break ; +case EFC_EVT_PLOGI_RCVD : { +/* T, or I+T */ +struct fc_frame_header *hdr = cbdata->header->dma.virt; +int rc; + +efc_node_save_sparms (node, cbdata->payload->dma.virt); +efc_send_ls_acc_after_attach (node, + cbdata->header->dma.virt, +EFC_NODE_SEND_LS_ACC_PLOGI ); + +/* domain not attached; several possibilities: */ +if (!node->nport->domain->attached) { +efc_d_check_plogi_topology (node,ntoh24 (hdr->fh_d_id)); +break ; + } + +/* domain already attached */ + rc =efc_node_attach (node); +efc_node_transition (node, __efc_d_wait_node_attach,NULL ); +if (rc ==EFC_HW_RTN_SUCCESS_SYNC ) +efc_node_post_event (node,EFC_EVT_NODE_ATTACH_OK ,NULL ); + +break ; + } + +case EFC_EVT_FDISC_RCVD : { +__efc_d_common (__func__, ctx, evt, arg); +break ; + } + +case EFC_EVT_FLOGI_RCVD : { +struct fc_frame_header *hdr = cbdata->header->dma.virt; +u32 d_id =ntoh24 (hdr->fh_d_id); + +/* sm: / save sparams, send FLOGI acc */ +memcpy (node->nport->domain->flogi_service_params, + cbdata->payload->dma.virt, +sizeof (struct fc_els_flogi )); + +/* send FC LS_ACC response, override s_id */ +efc_fabric_set_topology (node,EFC_NPORT_TOPO_P2P ); + +efc_send_flogi_p2p_acc (node,be16_to_cpu (hdr->fh_ox_id), d_id); + +if (efc_p2p_setup (node->nport)) { +node_printf (node,"p2p failed, shutting down node\n" ); +efc_node_post_event (node,EFC_EVT_SHUTDOWN ,NULL ); +break ; + } + +efc_node_transition (node, __efc_p2p_wait_flogi_acc_cmpl,NULL ); +break ; + } + +case EFC_EVT_LOGO_RCVD : { +struct fc_frame_header *hdr = cbdata->header->dma.virt; + +if (!node->nport->domain->attached) { +/* most likely a frame left over from before a link +* down; drop and +* shut node down w/ "explicit logout" so pending +* frames are processed +*/ +node_printf (node,"%s domain not attached, dropping\n" , +efc_sm_event_name (evt)); +efc_node_post_event (node, +EFC_EVT_SHUTDOWN_EXPLICIT_LOGO ,NULL ); +break ; + } + +efc_send_logo_acc (node,be16_to_cpu (hdr->fh_ox_id)); +efc_node_transition (node, __efc_d_wait_logo_acc_cmpl,NULL ); +break ; + } + +case EFC_EVT_PRLI_RCVD : +case EFC_EVT_PRLO_RCVD : +case EFC_EVT_PDISC_RCVD : +case EFC_EVT_ADISC_RCVD : +case EFC_EVT_RSCN_RCVD : { +struct fc_frame_header *hdr = cbdata->header->dma.virt; + +if (!node->nport->domain->attached) { +/* most likely a frame left over from before a link +* down; drop and shut node down w/ "explicit logout" +* so pending frames are processed +*/ +node_printf (node,"%s domain not attached, dropping\n" , +efc_sm_event_name (evt)); + +efc_node_post_event (node, +EFC_EVT_SHUTDOWN_EXPLICIT_LOGO , +NULL ); +break ; + } +node_printf (node,"%s received, sending reject\n" , +efc_sm_event_name (evt)); + +efc_send_ls_rjt (node,be16_to_cpu (hdr->fh_ox_id), +ELS_RJT_UNAB ,ELS_EXPL_PLOGI_REQD ,0 ); + +break ; + } + +case EFC_EVT_FCP_CMD_RCVD : { +/* note: problem, we're now expecting an ELS REQ completion +* from both the LOGO and PLOGI +*/ +if (!node->nport->domain->attached) { +/* most likely a frame left over from before a +* link down; drop and +* shut node down w/ "explicit logout" so pending +* frames are processed +*/ +node_printf (node,"%s domain not attached, dropping\n" , +efc_sm_event_name (evt)); +efc_node_post_event (node, +EFC_EVT_SHUTDOWN_EXPLICIT_LOGO , +NULL ); +break ; + } + +/* Send LOGO */ +node_printf (node,"FCP_CMND received, send LOGO\n" ); +if (efc_send_logo (node)) { +/* +* failed to send LOGO, go ahead and cleanup node +* anyways +*/ +node_printf (node,"Failed to send LOGO\n" ); +efc_node_post_event (node, +EFC_EVT_SHUTDOWN_EXPLICIT_LOGO , +NULL ); + }else { +/* sent LOGO, wait for response */ +efc_node_transition (node, + __efc_d_wait_logo_rsp,NULL ); + } +break ; + } +case EFC_EVT_DOMAIN_ATTACH_OK : +/* don't care about domain_attach_ok */ +break ; + +default : +__efc_d_common (__func__, ctx, evt, arg); + } +} + +void +__efc_d_wait_plogi_rsp (struct efc_sm_ctx *ctx, +enum efc_sm_event evt,void *arg) +{ +int rc; +struct efc_node_cb *cbdata = arg; +struct efc_node *node = ctx->app; + +efc_node_evt_set (ctx, evt, __func__); + +node_sm_trace (); + +switch (evt) { +case EFC_EVT_PLOGI_RCVD : { +/* T, or I+T */ +/* received PLOGI with svc parms, go ahead and attach node +* when PLOGI that was sent ultimately completes, it'll be a +* no-op +* +* If there is an outstanding PLOGI sent, can we set a flag +* to indicate that we don't want to retry it if it times out? +*/ +efc_node_save_sparms (node, cbdata->payload->dma.virt); +efc_send_ls_acc_after_attach (node, + cbdata->header->dma.virt, +EFC_NODE_SEND_LS_ACC_PLOGI ); +/* sm: domain->attached / efc_node_attach */ + rc =efc_node_attach (node); +efc_node_transition (node, __efc_d_wait_node_attach,NULL ); +if (rc ==EFC_HW_RTN_SUCCESS_SYNC ) +efc_node_post_event (node, +EFC_EVT_NODE_ATTACH_OK ,NULL ); + +break ; + } + +case EFC_EVT_PRLI_RCVD : +/* I, or I+T */ +/* sent PLOGI and before completion was seen, received the +* PRLI from the remote node (WCQEs and RCQEs come in on +* different queues and order of processing cannot be assumed) +* Save OXID so PRLI can be sent after the attach and continue +* to wait for PLOGI response +*/ +efc_process_prli_payload (node, cbdata->payload->dma.virt); +efc_send_ls_acc_after_attach (node, + cbdata->header->dma.virt, +EFC_NODE_SEND_LS_ACC_PRLI ); +efc_node_transition (node, __efc_d_wait_plogi_rsp_recvd_prli, +NULL ); +break ; + +case EFC_EVT_LOGO_RCVD :/* why don't we do a shutdown here?? */ +case EFC_EVT_PRLO_RCVD : +case EFC_EVT_PDISC_RCVD : +case EFC_EVT_FDISC_RCVD : +case EFC_EVT_ADISC_RCVD : +case EFC_EVT_RSCN_RCVD : +case EFC_EVT_SCR_RCVD : { +struct fc_frame_header *hdr = cbdata->header->dma.virt; + +node_printf (node,"%s received, sending reject\n" , +efc_sm_event_name (evt)); + +efc_send_ls_rjt (node,be16_to_cpu (hdr->fh_ox_id), +ELS_RJT_UNAB ,ELS_EXPL_PLOGI_REQD ,0 ); + +break ; + } + +case EFC_EVT_SRRS_ELS_REQ_OK :/* PLOGI response received */ +/* Completion from PLOGI sent */ +if (efc_node_check_els_req (ctx, evt, arg,ELS_PLOGI , + __efc_d_common, __func__)) +return ; + +WARN_ON (!node->els_req_cnt); + node->els_req_cnt--; +/* sm: / save sparams, efc_node_attach */ +efc_node_save_sparms (node, cbdata->els_rsp.virt); + rc =efc_node_attach (node); +efc_node_transition (node, __efc_d_wait_node_attach,NULL ); +if (rc ==EFC_HW_RTN_SUCCESS_SYNC ) +efc_node_post_event (node, +EFC_EVT_NODE_ATTACH_OK ,NULL ); + +break ; + +case EFC_EVT_SRRS_ELS_REQ_FAIL :/* PLOGI response received */ +/* PLOGI failed, shutdown the node */ +if (efc_node_check_els_req (ctx, evt, arg,ELS_PLOGI , + __efc_d_common, __func__)) +return ; + +WARN_ON (!node->els_req_cnt); + node->els_req_cnt--; +efc_node_post_event (node,EFC_EVT_SHUTDOWN ,NULL ); +break ; + +case EFC_EVT_SRRS_ELS_REQ_RJT : +/* Our PLOGI was rejected, this is ok in some cases */ +if (efc_node_check_els_req (ctx, evt, arg,ELS_PLOGI , + __efc_d_common, __func__)) +return ; + +WARN_ON (!node->els_req_cnt); + node->els_req_cnt--; +break ; + +case EFC_EVT_FCP_CMD_RCVD : { +/* not logged in yet and outstanding PLOGI so don't send LOGO, +* just drop +*/ +node_printf (node,"FCP_CMND received, drop\n" ); +break ; + } + +default : +__efc_d_common (__func__, ctx, evt, arg); + } +} + +void +__efc_d_wait_plogi_rsp_recvd_prli (struct efc_sm_ctx *ctx, +enum efc_sm_event evt,void *arg) +{ +int rc; +struct efc_node_cb *cbdata = arg; +struct efc_node *node = ctx->app; + +efc_node_evt_set (ctx, evt, __func__); + +node_sm_trace (); + +switch (evt) { +case EFC_EVT_ENTER : +/* +* Since we've received a PRLI, we have a port login and will +* just need to wait for the PLOGI response to do the node +* attach and then we can send the LS_ACC for the PRLI. If, +* during this time, we receive FCP_CMNDs (which is possible +* since we've already sent a PRLI and our peer may have +* accepted). At this time, we are not waiting on any other +* unsolicited frames to continue with the login process. Thus, +* it will not hurt to hold frames here. +*/ +efc_node_hold_frames (node); +break ; + +case EFC_EVT_EXIT : +efc_node_accept_frames (node); +break ; + +case EFC_EVT_SRRS_ELS_REQ_OK :/* PLOGI response received */ +/* Completion from PLOGI sent */ +if (efc_node_check_els_req (ctx, evt, arg,ELS_PLOGI , + __efc_d_common, __func__)) +return ; + +WARN_ON (!node->els_req_cnt); + node->els_req_cnt--; +/* sm: / save sparams, efc_node_attach */ +efc_node_save_sparms (node, cbdata->els_rsp.virt); + rc =efc_node_attach (node); +efc_node_transition (node, __efc_d_wait_node_attach,NULL ); +if (rc ==EFC_HW_RTN_SUCCESS_SYNC ) +efc_node_post_event (node,EFC_EVT_NODE_ATTACH_OK , +NULL ); + +break ; + +case EFC_EVT_SRRS_ELS_REQ_FAIL :/* PLOGI response received */ +case EFC_EVT_SRRS_ELS_REQ_RJT : +/* PLOGI failed, shutdown the node */ +if (efc_node_check_els_req (ctx, evt, arg,ELS_PLOGI , + __efc_d_common, __func__)) +return ; + +WARN_ON (!node->els_req_cnt); + node->els_req_cnt--; +efc_node_post_event (node,EFC_EVT_SHUTDOWN ,NULL ); +break ; + +default : +__efc_d_common (__func__, ctx, evt, arg); + } +} + +void +__efc_d_wait_domain_attach (struct efc_sm_ctx *ctx, +enum efc_sm_event evt,void *arg) +{ +int rc; +struct efc_node *node = ctx->app; + +efc_node_evt_set (ctx, evt, __func__); + +node_sm_trace (); + +switch (evt) { +case EFC_EVT_ENTER : +efc_node_hold_frames (node); +break ; + +case EFC_EVT_EXIT : +efc_node_accept_frames (node); +break ; + +case EFC_EVT_DOMAIN_ATTACH_OK : +WARN_ON (!node->nport->domain->attached); +/* sm: / efc_node_attach */ + rc =efc_node_attach (node); +efc_node_transition (node, __efc_d_wait_node_attach,NULL ); +if (rc ==EFC_HW_RTN_SUCCESS_SYNC ) +efc_node_post_event (node,EFC_EVT_NODE_ATTACH_OK , +NULL ); + +break ; + +default : +__efc_d_common (__func__, ctx, evt, arg); + } +} + +void +__efc_d_wait_topology_notify (struct efc_sm_ctx *ctx, +enum efc_sm_event evt,void *arg) +{ +int rc; +struct efc_node *node = ctx->app; + +efc_node_evt_set (ctx, evt, __func__); + +node_sm_trace (); + +switch (evt) { +case EFC_EVT_ENTER : +efc_node_hold_frames (node); +break ; + +case EFC_EVT_EXIT : +efc_node_accept_frames (node); +break ; + +case EFC_EVT_NPORT_TOPOLOGY_NOTIFY : { +enum efc_nport_topology topology = + (enum efc_nport_topology )arg; + +WARN_ON (node->nport->domain->attached); + +WARN_ON (node->send_ls_acc !=EFC_NODE_SEND_LS_ACC_PLOGI ); + +node_printf (node,"topology notification, topology=%d\n" , + topology); + +/* At the time the PLOGI was received, the topology was unknown, +* so we didn't know which node would perform the domain attach: +* 1. The node from which the PLOGI was sent (p2p) or +* 2. The node to which the FLOGI was sent (fabric). +*/ +if (topology ==EFC_NPORT_TOPO_P2P ) { +/* if this is p2p, need to attach to the domain using +* the d_id from the PLOGI received +*/ +efc_domain_attach (node->nport->domain, + node->ls_acc_did); + } +/* else, if this is fabric, the domain attach +* should be performed by the fabric node (node sending FLOGI); +* just wait for attach to complete +*/ + +efc_node_transition (node, __efc_d_wait_domain_attach,NULL ); +break ; + } +case EFC_EVT_DOMAIN_ATTACH_OK : +WARN_ON (!node->nport->domain->attached); +node_printf (node,"domain attach ok\n" ); +/* sm: / efc_node_attach */ + rc =efc_node_attach (node); +efc_node_transition (node, __efc_d_wait_node_attach,NULL ); +if (rc ==EFC_HW_RTN_SUCCESS_SYNC ) +efc_node_post_event (node, +EFC_EVT_NODE_ATTACH_OK ,NULL ); + +break ; + +default : +__efc_d_common (__func__, ctx, evt, arg); + } +} + +void +__efc_d_wait_node_attach (struct efc_sm_ctx *ctx, +enum efc_sm_event evt,void *arg) +{ +struct efc_node *node = ctx->app; + +efc_node_evt_set (ctx, evt, __func__); + +node_sm_trace (); + +switch (evt) { +case EFC_EVT_ENTER : +efc_node_hold_frames (node); +break ; + +case EFC_EVT_EXIT : +efc_node_accept_frames (node); +break ; + +case EFC_EVT_NODE_ATTACH_OK : + node->attached = true; +switch (node->send_ls_acc) { +case EFC_NODE_SEND_LS_ACC_PLOGI : { +/* sm: send_plogi_acc is set / send PLOGI acc */ +/* Normal case for T, or I+T */ +efc_send_plogi_acc (node, node->ls_acc_oxid); +efc_node_transition (node, __efc_d_wait_plogi_acc_cmpl, +NULL ); + node->send_ls_acc =EFC_NODE_SEND_LS_ACC_NONE ; + node->ls_acc_io =NULL ; +break ; + } +case EFC_NODE_SEND_LS_ACC_PRLI : { +efc_d_send_prli_rsp (node, node->ls_acc_oxid); + node->send_ls_acc =EFC_NODE_SEND_LS_ACC_NONE ; + node->ls_acc_io =NULL ; +break ; + } +case EFC_NODE_SEND_LS_ACC_NONE : +default : +/* Normal case for I */ +/* sm: send_plogi_acc is not set / send PLOGI acc */ +efc_node_transition (node, + __efc_d_port_logged_in,NULL ); +break ; + } +break ; + +case EFC_EVT_NODE_ATTACH_FAIL : +/* node attach failed, shutdown the node */ + node->attached = false; +node_printf (node,"node attach failed\n" ); + node->shutdown_reason =EFC_NODE_SHUTDOWN_DEFAULT ; +efc_node_transition (node, __efc_d_initiate_shutdown,NULL ); +break ; + +/* Handle shutdown events */ +case EFC_EVT_SHUTDOWN : +node_printf (node,"%s received\n" ,efc_sm_event_name (evt)); + node->shutdown_reason =EFC_NODE_SHUTDOWN_DEFAULT ; +efc_node_transition (node, __efc_d_wait_attach_evt_shutdown, +NULL ); +break ; +case EFC_EVT_SHUTDOWN_EXPLICIT_LOGO : +node_printf (node,"%s received\n" ,efc_sm_event_name (evt)); + node->shutdown_reason =EFC_NODE_SHUTDOWN_EXPLICIT_LOGO ; +efc_node_transition (node, __efc_d_wait_attach_evt_shutdown, +NULL ); +break ; +case EFC_EVT_SHUTDOWN_IMPLICIT_LOGO : +node_printf (node,"%s received\n" ,efc_sm_event_name (evt)); + node->shutdown_reason =EFC_NODE_SHUTDOWN_IMPLICIT_LOGO ; +efc_node_transition (node, + __efc_d_wait_attach_evt_shutdown,NULL ); +break ; +default : +__efc_d_common (__func__, ctx, evt, arg); + } +} + +void +__efc_d_wait_attach_evt_shutdown (struct efc_sm_ctx *ctx, +enum efc_sm_event evt,void *arg) +{ +struct efc_node *node = ctx->app; + +efc_node_evt_set (ctx, evt, __func__); + +node_sm_trace (); + +switch (evt) { +case EFC_EVT_ENTER : +efc_node_hold_frames (node); +break ; + +case EFC_EVT_EXIT : +efc_node_accept_frames (node); +break ; + +/* wait for any of these attach events and then shutdown */ +case EFC_EVT_NODE_ATTACH_OK : + node->attached = true; +node_printf (node,"Attach evt=%s, proceed to shutdown\n" , +efc_sm_event_name (evt)); +efc_node_transition (node, __efc_d_initiate_shutdown,NULL ); +break ; + +case EFC_EVT_NODE_ATTACH_FAIL : +/* node attach failed, shutdown the node */ + node->attached = false; +node_printf (node,"Attach evt=%s, proceed to shutdown\n" , +efc_sm_event_name (evt)); +efc_node_transition (node, __efc_d_initiate_shutdown,NULL ); +break ; + +/* ignore shutdown events as we're already in shutdown path */ +case EFC_EVT_SHUTDOWN : +/* have default shutdown event take precedence */ + node->shutdown_reason =EFC_NODE_SHUTDOWN_DEFAULT ; + fallthrough; + +case EFC_EVT_SHUTDOWN_EXPLICIT_LOGO : +case EFC_EVT_SHUTDOWN_IMPLICIT_LOGO : +node_printf (node,"%s received\n" ,efc_sm_event_name (evt)); +break ; + +default : +__efc_d_common (__func__, ctx, evt, arg); + } +} + +void +__efc_d_port_logged_in (struct efc_sm_ctx *ctx, +enum efc_sm_event evt,void *arg) +{ +struct efc_node_cb *cbdata = arg; +struct efc_node *node = ctx->app; + +efc_node_evt_set (ctx, evt, __func__); + +node_sm_trace (); + +switch (evt) { +case EFC_EVT_ENTER : +/* Normal case for I or I+T */ +if (node->nport->enable_ini && + !(node->rnode.fc_id !=FC_FID_DOM_MGR )) { +/* sm: if enable_ini / send PRLI */ +efc_send_prli (node); +/* can now expect ELS_REQ_OK/FAIL/RJT */ + } +break ; + +case EFC_EVT_FCP_CMD_RCVD : { +break ; + } + +case EFC_EVT_PRLI_RCVD : { +/* Normal case for T or I+T */ +struct fc_frame_header *hdr = cbdata->header->dma.virt; +struct { +struct fc_els_prli prli; +struct fc_els_spp sp; + } *pp; + + pp = cbdata->payload->dma.virt; +if (pp->sp.spp_type !=FC_TYPE_FCP ) { +/*Only FCP is supported*/ +efc_send_ls_rjt (node,be16_to_cpu (hdr->fh_ox_id), +ELS_RJT_UNAB ,ELS_EXPL_UNSUPR ,0 ); +break ; + } + +efc_process_prli_payload (node, cbdata->payload->dma.virt); +efc_d_send_prli_rsp (node,be16_to_cpu (hdr->fh_ox_id)); +break ; + } + +case EFC_EVT_NODE_SESS_REG_OK : +if (node->send_ls_acc ==EFC_NODE_SEND_LS_ACC_PRLI ) +efc_send_prli_acc (node, node->ls_acc_oxid); + + node->send_ls_acc =EFC_NODE_SEND_LS_ACC_NONE ; +efc_node_transition (node, __efc_d_device_ready,NULL ); +break ; + +case EFC_EVT_NODE_SESS_REG_FAIL : +efc_send_ls_rjt (node, node->ls_acc_oxid,ELS_RJT_UNAB , +ELS_EXPL_UNSUPR ,0 ); + node->send_ls_acc =EFC_NODE_SEND_LS_ACC_NONE ; +break ; + +case EFC_EVT_SRRS_ELS_REQ_OK : {/* PRLI response */ +/* Normal case for I or I+T */ +if (efc_node_check_els_req (ctx, evt, arg,ELS_PRLI , + __efc_d_common, __func__)) +return ; + +WARN_ON (!node->els_req_cnt); + node->els_req_cnt--; +/* sm: / process PRLI payload */ +efc_process_prli_payload (node, cbdata->els_rsp.virt); +efc_node_transition (node, __efc_d_device_ready,NULL ); +break ; + } + +case EFC_EVT_SRRS_ELS_REQ_FAIL : {/* PRLI response failed */ +/* I, I+T, assume some link failure, shutdown node */ +if (efc_node_check_els_req (ctx, evt, arg,ELS_PRLI , + __efc_d_common, __func__)) +return ; + +WARN_ON (!node->els_req_cnt); + node->els_req_cnt--; +efc_node_post_event (node,EFC_EVT_SHUTDOWN ,NULL ); +break ; + } + +case EFC_EVT_SRRS_ELS_REQ_RJT : { +/* PRLI rejected by remote +* Normal for I, I+T (connected to an I) +* Node doesn't want to be a target, stay here and wait for a +* PRLI from the remote node +* if it really wants to connect to us as target +*/ +if (efc_node_check_els_req (ctx, evt, arg,ELS_PRLI , + __efc_d_common, __func__)) +return ; + +WARN_ON (!node->els_req_cnt); + node->els_req_cnt--; +break ; + } + +case EFC_EVT_SRRS_ELS_CMPL_OK : { +/* Normal T, I+T, target-server rejected the process login */ +/* This would be received only in the case where we sent +* LS_RJT for the PRLI, so +* do nothing. (note: as T only we could shutdown the node) +*/ +WARN_ON (!node->els_cmpl_cnt); + node->els_cmpl_cnt--; +break ; + } + +case EFC_EVT_PLOGI_RCVD : { +/*sm: / save sparams, set send_plogi_acc, +*post implicit logout +* Save plogi parameters +*/ +efc_node_save_sparms (node, cbdata->payload->dma.virt); +efc_send_ls_acc_after_attach (node, + cbdata->header->dma.virt, +EFC_NODE_SEND_LS_ACC_PLOGI ); + +/* Restart node attach with new service parameters, +* and send ACC +*/ +efc_node_post_event (node,EFC_EVT_SHUTDOWN_IMPLICIT_LOGO , +NULL ); +break ; + } + +case EFC_EVT_LOGO_RCVD : { +/* I, T, I+T */ +struct fc_frame_header *hdr = cbdata->header->dma.virt; + +node_printf (node,"%s received attached=%d\n" , +efc_sm_event_name (evt), + node->attached); +/* sm: / send LOGO acc */ +efc_send_logo_acc (node,be16_to_cpu (hdr->fh_ox_id)); +efc_node_transition (node, __efc_d_wait_logo_acc_cmpl,NULL ); +break ; + } + +default : +__efc_d_common (__func__, ctx, evt, arg); + } +} + +void +__efc_d_wait_logo_acc_cmpl (struct efc_sm_ctx *ctx, +enum efc_sm_event evt,void *arg) +{ +struct efc_node *node = ctx->app; + +efc_node_evt_set (ctx, evt, __func__); + +node_sm_trace (); + +switch (evt) { +case EFC_EVT_ENTER : +efc_node_hold_frames (node); +break ; + +case EFC_EVT_EXIT : +efc_node_accept_frames (node); +break ; + +case EFC_EVT_SRRS_ELS_CMPL_OK : +case EFC_EVT_SRRS_ELS_CMPL_FAIL : +/* sm: / post explicit logout */ +WARN_ON (!node->els_cmpl_cnt); + node->els_cmpl_cnt--; +efc_node_post_event (node, +EFC_EVT_SHUTDOWN_EXPLICIT_LOGO ,NULL ); +break ; +default : +__efc_d_common (__func__, ctx, evt, arg); + } +} + +void +__efc_d_device_ready (struct efc_sm_ctx *ctx, +enum efc_sm_event evt,void *arg) +{ +struct efc_node_cb *cbdata = arg; +struct efc_node *node = ctx->app; +struct efc *efc = node->efc; + +efc_node_evt_set (ctx, evt, __func__); + +if (evt !=EFC_EVT_FCP_CMD_RCVD ) +node_sm_trace (); + +switch (evt) { +case EFC_EVT_ENTER : + node->fcp_enabled = true; +if (node->targ) { +efc_log_info (efc, +"[%s] found (target) WWPN %s WWNN %s\n" , + node->display_name, + node->wwpn, node->wwnn); +if (node->nport->enable_ini) + efc->tt.scsi_new_node (efc, node); + } +break ; + +case EFC_EVT_EXIT : + node->fcp_enabled = false; +break ; + +case EFC_EVT_PLOGI_RCVD : { +/* sm: / save sparams, set send_plogi_acc, post implicit +* logout +* Save plogi parameters +*/ +efc_node_save_sparms (node, cbdata->payload->dma.virt); +efc_send_ls_acc_after_attach (node, + cbdata->header->dma.virt, +EFC_NODE_SEND_LS_ACC_PLOGI ); + +/* +* Restart node attach with new service parameters, +* and send ACC +*/ +efc_node_post_event (node, +EFC_EVT_SHUTDOWN_IMPLICIT_LOGO ,NULL ); +break ; + } + +case EFC_EVT_PRLI_RCVD : { +/* T, I+T: remote initiator is slow to get started */ +struct fc_frame_header *hdr = cbdata->header->dma.virt; +struct { +struct fc_els_prli prli; +struct fc_els_spp sp; + } *pp; + + pp = cbdata->payload->dma.virt; +if (pp->sp.spp_type !=FC_TYPE_FCP ) { +/*Only FCP is supported*/ +efc_send_ls_rjt (node,be16_to_cpu (hdr->fh_ox_id), +ELS_RJT_UNAB ,ELS_EXPL_UNSUPR ,0 ); +break ; + } + +efc_process_prli_payload (node, cbdata->payload->dma.virt); +efc_send_prli_acc (node,be16_to_cpu (hdr->fh_ox_id)); +break ; + } + +case EFC_EVT_PRLO_RCVD : { +struct fc_frame_header *hdr = cbdata->header->dma.virt; +/* sm: / send PRLO acc */ +efc_send_prlo_acc (node,be16_to_cpu (hdr->fh_ox_id)); +/* need implicit logout? */ +break ; + } + +case EFC_EVT_LOGO_RCVD : { +struct fc_frame_header *hdr = cbdata->header->dma.virt; + +node_printf (node,"%s received attached=%d\n" , +efc_sm_event_name (evt), node->attached); +/* sm: / send LOGO acc */ +efc_send_logo_acc (node,be16_to_cpu (hdr->fh_ox_id)); +efc_node_transition (node, __efc_d_wait_logo_acc_cmpl,NULL ); +break ; + } + +case EFC_EVT_ADISC_RCVD : { +struct fc_frame_header *hdr = cbdata->header->dma.virt; +/* sm: / send ADISC acc */ +efc_send_adisc_acc (node,be16_to_cpu (hdr->fh_ox_id)); +break ; + } + +case EFC_EVT_ABTS_RCVD : +/* sm: / process ABTS */ +efc_log_err (efc,"Unexpected event:%s\n" , +efc_sm_event_name (evt)); +break ; + +case EFC_EVT_NODE_ACTIVE_IO_LIST_EMPTY : +break ; + +case EFC_EVT_NODE_REFOUND : +break ; + +case EFC_EVT_NODE_MISSING : +if (node->nport->enable_rscn) +efc_node_transition (node, __efc_d_device_gone,NULL ); + +break ; + +case EFC_EVT_SRRS_ELS_CMPL_OK : +/* T, or I+T, PRLI accept completed ok */ +WARN_ON (!node->els_cmpl_cnt); + node->els_cmpl_cnt--; +break ; + +case EFC_EVT_SRRS_ELS_CMPL_FAIL : +/* T, or I+T, PRLI accept failed to complete */ +WARN_ON (!node->els_cmpl_cnt); + node->els_cmpl_cnt--; +node_printf (node,"Failed to send PRLI LS_ACC\n" ); +break ; + +default : +__efc_d_common (__func__, ctx, evt, arg); + } +} + +void +__efc_d_device_gone (struct efc_sm_ctx *ctx, +enum efc_sm_event evt,void *arg) +{ +struct efc_node_cb *cbdata = arg; +struct efc_node *node = ctx->app; +struct efc *efc = node->efc; + +efc_node_evt_set (ctx, evt, __func__); + +node_sm_trace (); + +switch (evt) { +case EFC_EVT_ENTER : { +int rc =EFC_SCSI_CALL_COMPLETE ; +int rc_2 =EFC_SCSI_CALL_COMPLETE ; +static const char *const labels[] = { +"none" ,"initiator" ,"target" ,"initiator+target" + }; + +efc_log_info (efc,"[%s] missing (%s) WWPN %s WWNN %s\n" , + node->display_name, + labels[(node->targ <<1 ) | (node->init)], + node->wwpn, node->wwnn); + +switch (efc_node_get_enable (node)) { +case EFC_NODE_ENABLE_T_TO_T : +case EFC_NODE_ENABLE_I_TO_T : +case EFC_NODE_ENABLE_IT_TO_T : + rc = efc->tt.scsi_del_node (efc, node, +EFC_SCSI_TARGET_MISSING ); +break ; + +case EFC_NODE_ENABLE_T_TO_I : +case EFC_NODE_ENABLE_I_TO_I : +case EFC_NODE_ENABLE_IT_TO_I : + rc = efc->tt.scsi_del_node (efc, node, +EFC_SCSI_INITIATOR_MISSING ); +break ; + +case EFC_NODE_ENABLE_T_TO_IT : + rc = efc->tt.scsi_del_node (efc, node, +EFC_SCSI_INITIATOR_MISSING ); +break ; + +case EFC_NODE_ENABLE_I_TO_IT : + rc = efc->tt.scsi_del_node (efc, node, +EFC_SCSI_TARGET_MISSING ); +break ; + +case EFC_NODE_ENABLE_IT_TO_IT : + rc = efc->tt.scsi_del_node (efc, node, +EFC_SCSI_INITIATOR_MISSING ); + rc_2 = efc->tt.scsi_del_node (efc, node, +EFC_SCSI_TARGET_MISSING ); +break ; + +default : + rc =EFC_SCSI_CALL_COMPLETE ; +break ; + } + +if (rc ==EFC_SCSI_CALL_COMPLETE && + rc_2 ==EFC_SCSI_CALL_COMPLETE ) +efc_node_post_event (node,EFC_EVT_SHUTDOWN ,NULL ); + +break ; + } +case EFC_EVT_NODE_REFOUND : +/* two approaches, reauthenticate with PLOGI/PRLI, or ADISC */ + +/* reauthenticate with PLOGI/PRLI */ +/* efc_node_transition(node, __efc_d_discovered, NULL); */ + +/* reauthenticate with ADISC */ +/* sm: / send ADISC */ +efc_send_adisc (node); +efc_node_transition (node, __efc_d_wait_adisc_rsp,NULL ); +break ; + +case EFC_EVT_PLOGI_RCVD : { +/* sm: / save sparams, set send_plogi_acc, post implicit +* logout +* Save plogi parameters +*/ +efc_node_save_sparms (node, cbdata->payload->dma.virt); +efc_send_ls_acc_after_attach (node, + cbdata->header->dma.virt, +EFC_NODE_SEND_LS_ACC_PLOGI ); + +/* +* Restart node attach with new service parameters, and send +* ACC +*/ +efc_node_post_event (node,EFC_EVT_SHUTDOWN_IMPLICIT_LOGO , +NULL ); +break ; + } + +case EFC_EVT_FCP_CMD_RCVD : { +/* most likely a stale frame (received prior to link down), +* if attempt to send LOGO, will probably timeout and eat +* up 20s; thus, drop FCP_CMND +*/ +node_printf (node,"FCP_CMND received, drop\n" ); +break ; + } +case EFC_EVT_LOGO_RCVD : { +/* I, T, I+T */ +struct fc_frame_header *hdr = cbdata->header->dma.virt; + +node_printf (node,"%s received attached=%d\n" , +efc_sm_event_name (evt), node->attached); +/* sm: / send LOGO acc */ +efc_send_logo_acc (node,be16_to_cpu (hdr->fh_ox_id)); +efc_node_transition (node, __efc_d_wait_logo_acc_cmpl,NULL ); +break ; + } +default : +__efc_d_common (__func__, ctx, evt, arg); + } +} + +void +__efc_d_wait_adisc_rsp (struct efc_sm_ctx *ctx, +enum efc_sm_event evt,void *arg) +{ +struct efc_node_cb *cbdata = arg; +struct efc_node *node = ctx->app; + +efc_node_evt_set (ctx, evt, __func__); + +node_sm_trace (); + +switch (evt) { +case EFC_EVT_SRRS_ELS_REQ_OK : +if (efc_node_check_els_req (ctx, evt, arg,ELS_ADISC , + __efc_d_common, __func__)) +return ; + +WARN_ON (!node->els_req_cnt); + node->els_req_cnt--; +efc_node_transition (node, __efc_d_device_ready,NULL ); +break ; + +case EFC_EVT_SRRS_ELS_REQ_RJT : +/* received an LS_RJT, in this case, send shutdown +* (explicit logo) event which will unregister the node, +* and start over with PLOGI +*/ +if (efc_node_check_els_req (ctx, evt, arg,ELS_ADISC , + __efc_d_common, __func__)) +return ; + +WARN_ON (!node->els_req_cnt); + node->els_req_cnt--; +/* sm: / post explicit logout */ +efc_node_post_event (node, +EFC_EVT_SHUTDOWN_EXPLICIT_LOGO , +NULL ); +break ; + +case EFC_EVT_LOGO_RCVD : { +/* In this case, we have the equivalent of an LS_RJT for +* the ADISC, so we need to abort the ADISC, and re-login +* with PLOGI +*/ +/* sm: / request abort, send LOGO acc */ +struct fc_frame_header *hdr = cbdata->header->dma.virt; + +node_printf (node,"%s received attached=%d\n" , +efc_sm_event_name (evt), node->attached); + +efc_send_logo_acc (node,be16_to_cpu (hdr->fh_ox_id)); +efc_node_transition (node, __efc_d_wait_logo_acc_cmpl,NULL ); +break ; + } +default : +__efc_d_common (__func__, ctx, evt, arg); + } +}
drivers/scsi/elx/libefc/efc_device.h new file +72 -0
72 lines not on this page · raw message
Signature · 1 line
2.26.2
PATCH v8 15/31 elx: libefc: Extended link Service IO handling
In reply to James SmartThis patch continues the libefc library population.
This patch adds library interface definitions for:
Functions to build and send ELS/CT/BLS commands and responses.
--- drivers/scsi/elx/libefc/efc_els.c | 1099 +++++++++++++++++++++++++++++ drivers/scsi/elx/libefc/efc_els.h | 107 +++ 2 files changed, 1206 insertions(+) create mode 100644 drivers/scsi/elx/libefc/efc_els.c create mode 100644 drivers/scsi/elx/libefc/efc_els.h
drivers/scsi/elx/libefc/efc_els.c new file +1099 -0
@@ -0,0 +1,1099 @@ +// SPDX-License-Identifier: GPL-2.0 +/* +* Copyright (C) 2021 Broadcom. All Rights Reserved. The term +* “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. +*/ + +/* +* Functions to build and send ELS/CT/BLS commands and responses. +*/ + +#include "efc.h" +#include "efc_els.h" +#include "../libefc_sli/sli4.h" + +#define EFC_LOG_ENABLE_ELS_TRACE (efc) \ + (((efc) != NULL) ? (((efc)->logmask & (1U << 1)) != 0) : 0) + +#define node_els_trace () \ + do { \ + if (EFC_LOG_ENABLE_ELS_TRACE(efc)) \ + efc_log_info(efc, "[%s] %-20s\n", \ + node->display_name, __func__); \ + } while (0) + +#define els_io_printf (els, fmt, ...) \ + efc_log_err((struct efc *)els->node->efc,\ + "[%s] %-8s " fmt, \ + els->node->display_name,\ + els->display_name, ##__VA_ARGS__) + +#define EFC_ELS_RSP_LEN 1024 +#define EFC_ELS_GID_PT_RSP_LEN 8096 + +struct efc_els_io_req * +efc_els_io_alloc (struct efc_node *node,u32 reqlen) +{ +return efc_els_io_alloc_size (node, reqlen,EFC_ELS_RSP_LEN ); +} + +struct efc_els_io_req * +efc_els_io_alloc_size (struct efc_node *node,u32 reqlen,u32 rsplen) +{ +struct efc *efc; +struct efc_els_io_req *els; +unsigned long flags =0 ; + + efc = node->efc; + +spin_lock_irqsave (&node->els_ios_lock, flags); + +if (!READ_ONCE (node->els_io_enabled)) { +efc_log_err (efc,"els io alloc disabled\n" ); +spin_unlock_irqrestore (&node->els_ios_lock, flags); +return NULL ; + } + + els =mempool_alloc (efc->els_io_pool,GFP_ATOMIC ); +if (!els) { +atomic_add_return (1 , &efc->els_io_alloc_failed_count); +spin_unlock_irqrestore (&node->els_ios_lock, flags); +return NULL ; + } + +/* initialize refcount */ +kref_init (&els->ref); + els->release = _efc_els_io_free; + +/* populate generic io fields */ + els->node = node; + +/* now allocate DMA for request and response */ + els->io.req.size = reqlen; + els->io.req.virt =dma_alloc_coherent (&efc->pci->dev, els->io.req.size, + &els->io.req.phys,GFP_DMA ); +if (!els->io.req.virt) { +mempool_free (els, efc->els_io_pool); +spin_unlock_irqrestore (&node->els_ios_lock, flags); +return NULL ; + } + + els->io.rsp.size = rsplen; + els->io.rsp.virt =dma_alloc_coherent (&efc->pci->dev, els->io.rsp.size, + &els->io.rsp.phys,GFP_DMA ); +if (!els->io.rsp.virt) { +dma_free_coherent (&efc->pci->dev, els->io.req.size, + els->io.req.virt, els->io.req.phys); +mempool_free (els, efc->els_io_pool); + els =NULL ; + } + +if (els) { +/* initialize fields */ + els->els_retries_remaining =EFC_FC_ELS_DEFAULT_RETRIES ; + +/* add els structure to ELS IO list */ +INIT_LIST_HEAD (&els->list_entry); +list_add_tail (&els->list_entry, &node->els_ios_list); + } + +spin_unlock_irqrestore (&node->els_ios_lock, flags); +return els; +} + +void +efc_els_io_free (struct efc_els_io_req *els) +{ +kref_put (&els->ref, els->release); +} + +void +_efc_els_io_free (struct kref *arg) +{ +struct efc_els_io_req *els = + container_of(arg, struct efc_els_io_req, ref); +struct efc *efc; +struct efc_node *node; +int send_empty_event = false; +unsigned long flags =0 ; + + node = els->node; + efc = node->efc; + +spin_lock_irqsave (&node->els_ios_lock, flags); + +list_del (&els->list_entry); +/* Send list empty event if the IO allocator +* is disabled, and the list is empty +* If node->els_io_enabled was not checked, +* the event would be posted continually +*/ + send_empty_event = (!READ_ONCE (node->els_io_enabled)) && +list_empty (&node->els_ios_list); + +spin_unlock_irqrestore (&node->els_ios_lock, flags); + +/* free ELS request and response buffers */ +dma_free_coherent (&efc->pci->dev, els->io.rsp.size, + els->io.rsp.virt, els->io.rsp.phys); +dma_free_coherent (&efc->pci->dev, els->io.req.size, + els->io.req.virt, els->io.req.phys); + +mempool_free (els, efc->els_io_pool); + +if (send_empty_event) +efc_scsi_io_list_empty (node->efc, node); +} + +static void +efc_els_retry (struct efc_els_io_req *els); + +static void +efc_els_delay_timer_cb (struct timer_list *t) +{ +struct efc_els_io_req *els =from_timer (els, t, delay_timer); + +/* Retry delay timer expired, retry the ELS request */ +efc_els_retry (els); +} + +static int +efc_els_req_cb (void *arg,u32 length,int status,u32 ext_status) +{ +struct efc_els_io_req *els; +struct efc_node *node; +struct efc *efc; +struct efc_node_cb cbdata; +u32 reason_code; + + els = arg; + node = els->node; + efc = node->efc; + +if (status) +els_io_printf (els,"status x%x ext x%x\n" , status, ext_status); + +/* set the response len element of els->rsp */ + els->io.rsp.len = length; + + cbdata.status = status; + cbdata.ext_status = ext_status; + cbdata.header =NULL ; + cbdata.els_rsp = els->io.rsp; + +/* set the response len element of els->rsp */ + cbdata.rsp_len = length; + +/* FW returns the number of bytes received on the link in +* the WCQE, not the amount placed in the buffer; use this info to +* check if there was an overrun. +*/ +if (length > els->io.rsp.size) { +efc_log_warn (efc, +"ELS response returned len=%d > buflen=%zu\n" , + length, els->io.rsp.size); +efc_els_io_cleanup (els,EFC_EVT_SRRS_ELS_REQ_FAIL , &cbdata); +return EFC_SUCCESS ; + } + +/* Post event to ELS IO object */ +switch (status) { +case SLI4_FC_WCQE_STATUS_SUCCESS : +efc_els_io_cleanup (els,EFC_EVT_SRRS_ELS_REQ_OK , &cbdata); +break ; + +case SLI4_FC_WCQE_STATUS_LS_RJT : + reason_code = (ext_status >>16 ) &0xff ; + +/* delay and retry if reason code is Logical Busy */ +switch (reason_code) { +case ELS_RJT_BUSY : + els->node->els_req_cnt--; +els_io_printf (els, +"LS_RJT Logical Busy, delay and retry\n" ); +timer_setup (&els->delay_timer, + efc_els_delay_timer_cb,0 ); +mod_timer (&els->delay_timer, + jiffies +msecs_to_jiffies (5000 )); +break ; +default : +efc_els_io_cleanup (els,EFC_EVT_SRRS_ELS_REQ_RJT , + &cbdata); +break ; + } +break ; + +case SLI4_FC_WCQE_STATUS_LOCAL_REJECT : +switch (ext_status) { +case SLI4_FC_LOCAL_REJECT_SEQUENCE_TIMEOUT : +efc_els_retry (els); +break ; +default : +efc_log_err (efc,"LOCAL_REJECT with ext status:%x\n" , + ext_status); +efc_els_io_cleanup (els,EFC_EVT_SRRS_ELS_REQ_FAIL , + &cbdata); +break ; + } +break ; +default :/* Other error */ +efc_log_warn (efc,"els req failed status x%x, ext_status x%x\n" , + status, ext_status); +efc_els_io_cleanup (els,EFC_EVT_SRRS_ELS_REQ_FAIL , &cbdata); +break ; + } + +return EFC_SUCCESS ; +} + +void efc_disc_io_complete (struct efc_disc_io *io,u32 len,u32 status, +u32 ext_status) +{ +struct efc_els_io_req *els = + container_of(io, struct efc_els_io_req, io); + +WARN_ON_ONCE (!els->cb); + + ((efc_hw_srrs_cb_t ) els->cb) (els, len, status, ext_status); +} + +static int efc_els_send_req (struct efc_node *node,struct efc_els_io_req *els, +enum efc_disc_io_type io_type) +{ +int rc =EFC_SUCCESS ; +struct efc *efc = node->efc; +struct efc_node_cb cbdata; + +/* update ELS request counter */ + els->node->els_req_cnt++; + +/* Prepare the IO request details */ + els->io.io_type = io_type; + els->io.xmit_len = els->io.req.size; + els->io.rsp_len = els->io.rsp.size; + els->io.rpi = node->rnode.indicator; + els->io.vpi = node->nport->indicator; + els->io.s_id = node->nport->fc_id; + els->io.d_id = node->rnode.fc_id; + +if (node->rnode.attached) + els->io.rpi_registered = true; + + els->cb = efc_els_req_cb; + + rc = efc->tt.send_els (efc, &els->io); +if (!rc) +return rc; + + cbdata.status =EFC_STATUS_INVALID ; + cbdata.ext_status =EFC_STATUS_INVALID ; + cbdata.els_rsp = els->io.rsp; +efc_log_err (efc,"efc_els_send failed: %d\n" , rc); +efc_els_io_cleanup (els,EFC_EVT_SRRS_ELS_REQ_FAIL , &cbdata); + +return rc; +} + +static void +efc_els_retry (struct efc_els_io_req *els) +{ +struct efc *efc; +struct efc_node_cb cbdata; +u32 rc; + + efc = els->node->efc; + cbdata.status =EFC_STATUS_INVALID ; + cbdata.ext_status =EFC_STATUS_INVALID ; + cbdata.els_rsp = els->io.rsp; + + +if (els->els_retries_remaining) { + els->els_retries_remaining--; + rc = efc->tt.send_els (efc, &els->io); + }else { + rc =EFC_FAIL ; + } + +if (rc) { +efc_log_err (efc,"ELS retries exhausted\n" ); +efc_els_io_cleanup (els,EFC_EVT_SRRS_ELS_REQ_FAIL , &cbdata); + } +} + +static int +efc_els_acc_cb (void *arg,u32 length,int status,u32 ext_status) +{ +struct efc_els_io_req *els; +struct efc_node *node; +struct efc *efc; +struct efc_node_cb cbdata; + + els = arg; + node = els->node; + efc = node->efc; + + cbdata.status = status; + cbdata.ext_status = ext_status; + cbdata.header =NULL ; + cbdata.els_rsp = els->io.rsp; + +/* Post node event */ +switch (status) { +case SLI4_FC_WCQE_STATUS_SUCCESS : +efc_els_io_cleanup (els,EFC_EVT_SRRS_ELS_CMPL_OK , &cbdata); +break ; + +default :/* Other error */ +efc_log_warn (efc,"[%s] %-8s failed status x%x, ext x%x\n" , + node->display_name, els->display_name, + status, ext_status); +efc_els_io_cleanup (els,EFC_EVT_SRRS_ELS_CMPL_FAIL , &cbdata); +break ; + } + +return EFC_SUCCESS ; +} + +static int +efc_els_send_rsp (struct efc_els_io_req *els,u32 rsplen) +{ +int rc =EFC_SUCCESS ; +struct efc_node_cb cbdata; +struct efc_node *node = els->node; +struct efc *efc = node->efc; + +/* increment ELS completion counter */ + node->els_cmpl_cnt++; + + els->io.io_type =EFC_DISC_IO_ELS_RESP ; + els->cb = efc_els_acc_cb; + +/* Prepare the IO request details */ + els->io.xmit_len = rsplen; + els->io.rsp_len = els->io.rsp.size; + els->io.rpi = node->rnode.indicator; + els->io.vpi = node->nport->indicator; +if (node->nport->fc_id !=U32_MAX ) + els->io.s_id = node->nport->fc_id; +else + els->io.s_id = els->io.iparam.els.s_id; + els->io.d_id = node->rnode.fc_id; + +if (node->attached) + els->io.rpi_registered = true; + + rc = efc->tt.send_els (efc, &els->io); +if (!rc) +return rc; + + cbdata.status =EFC_STATUS_INVALID ; + cbdata.ext_status =EFC_STATUS_INVALID ; + cbdata.els_rsp = els->io.rsp; +efc_els_io_cleanup (els,EFC_EVT_SRRS_ELS_CMPL_FAIL , &cbdata); + +return rc; +} + +int +efc_send_plogi (struct efc_node *node) +{ +struct efc_els_io_req *els; +struct efc *efc = node->efc; +struct fc_els_flogi *plogi; + +node_els_trace (); + + els =efc_els_io_alloc (node,sizeof (*plogi)); +if (!els) { +efc_log_err (efc,"IO alloc failed\n" ); +return EFC_FAIL ; + } + els->display_name ="plogi" ; + +/* Build PLOGI request */ + plogi = els->io.req.virt; + +memcpy (plogi, node->nport->service_params,sizeof (*plogi)); + + plogi->fl_cmd =ELS_PLOGI ; +memset (plogi->_fl_resvd,0 ,sizeof (plogi->_fl_resvd)); + +return efc_els_send_req (node, els,EFC_DISC_IO_ELS_REQ ); +} + +int +efc_send_flogi (struct efc_node *node) +{ +struct efc_els_io_req *els; +struct efc *efc; +struct fc_els_flogi *flogi; + + efc = node->efc; + +node_els_trace (); + + els =efc_els_io_alloc (node,sizeof (*flogi)); +if (!els) { +efc_log_err (efc,"IO alloc failed\n" ); +return EFC_FAIL ; + } + + els->display_name ="flogi" ; + +/* Build FLOGI request */ + flogi = els->io.req.virt; + +memcpy (flogi, node->nport->service_params,sizeof (*flogi)); + flogi->fl_cmd =ELS_FLOGI ; +memset (flogi->_fl_resvd,0 ,sizeof (flogi->_fl_resvd)); + +return efc_els_send_req (node, els,EFC_DISC_IO_ELS_REQ ); +} + +int +efc_send_fdisc (struct efc_node *node) +{ +struct efc_els_io_req *els; +struct efc *efc; +struct fc_els_flogi *fdisc; + + efc = node->efc; + +node_els_trace (); + + els =efc_els_io_alloc (node,sizeof (*fdisc)); +if (!els) { +efc_log_err (efc,"IO alloc failed\n" ); +return EFC_FAIL ; + } + + els->display_name ="fdisc" ; + +/* Build FDISC request */ + fdisc = els->io.req.virt; + +memcpy (fdisc, node->nport->service_params,sizeof (*fdisc)); + fdisc->fl_cmd =ELS_FDISC ; +memset (fdisc->_fl_resvd,0 ,sizeof (fdisc->_fl_resvd)); + +return efc_els_send_req (node, els,EFC_DISC_IO_ELS_REQ ); +} + +int +efc_send_prli (struct efc_node *node) +{ +struct efc *efc = node->efc; +struct efc_els_io_req *els; +struct { +struct fc_els_prli prli; +struct fc_els_spp spp; + } *pp; + +node_els_trace (); + + els =efc_els_io_alloc (node,sizeof (*pp)); +if (!els) { +efc_log_err (efc,"IO alloc failed\n" ); +return EFC_FAIL ; + } + + els->display_name ="prli" ; + +/* Build PRLI request */ + pp = els->io.req.virt; + +memset (pp,0 ,sizeof (*pp)); + + pp->prli.prli_cmd =ELS_PRLI ; + pp->prli.prli_spp_len =16 ; + pp->prli.prli_len =cpu_to_be16 (sizeof (*pp)); + pp->spp.spp_type =FC_TYPE_FCP ; + pp->spp.spp_type_ext =0 ; + pp->spp.spp_flags =FC_SPP_EST_IMG_PAIR ; + pp->spp.spp_params =cpu_to_be32 (FCP_SPPF_RD_XRDY_DIS | + (node->nport->enable_ini ? +FCP_SPPF_INIT_FCN :0 ) | + (node->nport->enable_tgt ? +FCP_SPPF_TARG_FCN :0 )); + +return efc_els_send_req (node, els,EFC_DISC_IO_ELS_REQ ); +} + +int +efc_send_logo (struct efc_node *node) +{ +struct efc *efc = node->efc; +struct efc_els_io_req *els; +struct fc_els_logo *logo; +struct fc_els_flogi *sparams; + +node_els_trace (); + + sparams = (struct fc_els_flogi *)node->nport->service_params; + + els =efc_els_io_alloc (node,sizeof (*logo)); +if (!els) { +efc_log_err (efc,"IO alloc failed\n" ); +return EFC_FAIL ; + } + + els->display_name ="logo" ; + +/* Build LOGO request */ + + logo = els->io.req.virt; + +memset (logo,0 ,sizeof (*logo)); + logo->fl_cmd =ELS_LOGO ; +hton24 (logo->fl_n_port_id, node->rnode.nport->fc_id); + logo->fl_n_port_wwn = sparams->fl_wwpn; + +return efc_els_send_req (node, els,EFC_DISC_IO_ELS_REQ ); +} + +int +efc_send_adisc (struct efc_node *node) +{ +struct efc *efc = node->efc; +struct efc_els_io_req *els; +struct fc_els_adisc *adisc; +struct fc_els_flogi *sparams; +struct efc_nport *nport = node->nport; + +node_els_trace (); + + sparams = (struct fc_els_flogi *)node->nport->service_params; + + els =efc_els_io_alloc (node,sizeof (*adisc)); +if (!els) { +efc_log_err (efc,"IO alloc failed\n" ); +return EFC_FAIL ; + } + + els->display_name ="adisc" ; + +/* Build ADISC request */ + + adisc = els->io.req.virt; + +memset (adisc,0 ,sizeof (*adisc)); + adisc->adisc_cmd =ELS_ADISC ; +hton24 (adisc->adisc_hard_addr, nport->fc_id); + adisc->adisc_wwpn = sparams->fl_wwpn; + adisc->adisc_wwnn = sparams->fl_wwnn; +hton24 (adisc->adisc_port_id, node->rnode.nport->fc_id); + +return efc_els_send_req (node, els,EFC_DISC_IO_ELS_REQ ); +} + +int +efc_send_scr (struct efc_node *node) +{ +struct efc_els_io_req *els; +struct efc *efc = node->efc; +struct fc_els_scr *req; + +node_els_trace (); + + els =efc_els_io_alloc (node,sizeof (*req)); +if (!els) { +efc_log_err (efc,"IO alloc failed\n" ); +return EFC_FAIL ; + } + + els->display_name ="scr" ; + + req = els->io.req.virt; + +memset (req,0 ,sizeof (*req)); + req->scr_cmd =ELS_SCR ; + req->scr_reg_func =ELS_SCRF_FULL ; + +return efc_els_send_req (node, els,EFC_DISC_IO_ELS_REQ ); +} + +int +efc_send_ls_rjt (struct efc_node *node,u32 ox_id,u32 reason_code, +u32 reason_code_expl,u32 vendor_unique) +{ +struct efc *efc = node->efc; +struct efc_els_io_req *els =NULL ; +struct fc_els_ls_rjt *rjt; + + els =efc_els_io_alloc (node,sizeof (*rjt)); +if (!els) { +efc_log_err (efc,"els IO alloc failed\n" ); +return EFC_FAIL ; + } + +node_els_trace (); + + els->display_name ="ls_rjt" ; + +memset (&els->io.iparam,0 ,sizeof (els->io.iparam)); + els->io.iparam.els.ox_id = ox_id; + + rjt = els->io.req.virt; +memset (rjt,0 ,sizeof (*rjt)); + + rjt->er_cmd =ELS_LS_RJT ; + rjt->er_reason = reason_code; + rjt->er_explan = reason_code_expl; + +return efc_els_send_rsp (els,sizeof (*rjt)); +} + +int +efc_send_plogi_acc (struct efc_node *node,u32 ox_id) +{ +struct efc *efc = node->efc; +struct efc_els_io_req *els =NULL ; +struct fc_els_flogi *plogi; +struct fc_els_flogi *req = (struct fc_els_flogi *)node->service_params; + +node_els_trace (); + + els =efc_els_io_alloc (node,sizeof (*plogi)); +if (!els) { +efc_log_err (efc,"els IO alloc failed\n" ); +return EFC_FAIL ; + } + + els->display_name ="plogi_acc" ; + +memset (&els->io.iparam,0 ,sizeof (els->io.iparam)); + els->io.iparam.els.ox_id = ox_id; + + plogi = els->io.req.virt; + +/* copy our port's service parameters to payload */ +memcpy (plogi, node->nport->service_params,sizeof (*plogi)); + plogi->fl_cmd =ELS_LS_ACC ; +memset (plogi->_fl_resvd,0 ,sizeof (plogi->_fl_resvd)); + +/* Set Application header support bit if requested */ +if (req->fl_csp.sp_features &cpu_to_be16 (FC_SP_FT_BCAST )) + plogi->fl_csp.sp_features |=cpu_to_be16 (FC_SP_FT_BCAST ); + +return efc_els_send_rsp (els,sizeof (*plogi)); +} + +int +efc_send_flogi_p2p_acc (struct efc_node *node,u32 ox_id,u32 s_id) +{ +struct efc *efc = node->efc; +struct efc_els_io_req *els =NULL ; +struct fc_els_flogi *flogi; + +node_els_trace (); + + els =efc_els_io_alloc (node,sizeof (*flogi)); +if (!els) { +efc_log_err (efc,"els IO alloc failed\n" ); +return EFC_FAIL ; + } + + els->display_name ="flogi_p2p_acc" ; + +memset (&els->io.iparam,0 ,sizeof (els->io.iparam)); + els->io.iparam.els.ox_id = ox_id; + els->io.iparam.els.s_id = s_id; + + flogi = els->io.req.virt; + +/* copy our port's service parameters to payload */ +memcpy (flogi, node->nport->service_params,sizeof (*flogi)); + flogi->fl_cmd =ELS_LS_ACC ; +memset (flogi->_fl_resvd,0 ,sizeof (flogi->_fl_resvd)); + +memset (flogi->fl_cssp,0 ,sizeof (flogi->fl_cssp)); + +return efc_els_send_rsp (els,sizeof (*flogi)); +} + +int +efc_send_prli_acc (struct efc_node *node,u32 ox_id) +{ +struct efc *efc = node->efc; +struct efc_els_io_req *els =NULL ; +struct { +struct fc_els_prli prli; +struct fc_els_spp spp; + } *pp; + +node_els_trace (); + + els =efc_els_io_alloc (node,sizeof (*pp)); +if (!els) { +efc_log_err (efc,"els IO alloc failed\n" ); +return EFC_FAIL ; + } + + els->display_name ="prli_acc" ; + +memset (&els->io.iparam,0 ,sizeof (els->io.iparam)); + els->io.iparam.els.ox_id = ox_id; + + pp = els->io.req.virt; +memset (pp,0 ,sizeof (*pp)); + + pp->prli.prli_cmd =ELS_LS_ACC ; + pp->prli.prli_spp_len =0x10 ; + pp->prli.prli_len =cpu_to_be16 (sizeof (*pp)); + pp->spp.spp_type =FC_TYPE_FCP ; + pp->spp.spp_type_ext =0 ; + pp->spp.spp_flags =FC_SPP_EST_IMG_PAIR |FC_SPP_RESP_ACK ; + + pp->spp.spp_params =cpu_to_be32 (FCP_SPPF_RD_XRDY_DIS | + (node->nport->enable_ini ? +FCP_SPPF_INIT_FCN :0 ) | + (node->nport->enable_tgt ? +FCP_SPPF_TARG_FCN :0 )); + +return efc_els_send_rsp (els,sizeof (*pp)); +} + +int +efc_send_prlo_acc (struct efc_node *node,u32 ox_id) +{ +struct efc *efc = node->efc; +struct efc_els_io_req *els =NULL ; +struct { +struct fc_els_prlo prlo; +struct fc_els_spp spp; + } *pp; + +node_els_trace (); + + els =efc_els_io_alloc (node,sizeof (*pp)); +if (!els) { +efc_log_err (efc,"els IO alloc failed\n" ); +return EFC_FAIL ; + } + + els->display_name ="prlo_acc" ; + +memset (&els->io.iparam,0 ,sizeof (els->io.iparam)); + els->io.iparam.els.ox_id = ox_id; + + pp = els->io.req.virt; +memset (pp,0 ,sizeof (*pp)); + pp->prlo.prlo_cmd =ELS_LS_ACC ; + pp->prlo.prlo_obs =0x10 ; + pp->prlo.prlo_len =cpu_to_be16 (sizeof (*pp)); + + pp->spp.spp_type =FC_TYPE_FCP ; + pp->spp.spp_type_ext =0 ; + pp->spp.spp_flags =FC_SPP_RESP_ACK ; + +return efc_els_send_rsp (els,sizeof (*pp)); +} + +int +efc_send_ls_acc (struct efc_node *node,u32 ox_id) +{ +struct efc *efc = node->efc; +struct efc_els_io_req *els =NULL ; +struct fc_els_ls_acc *acc; + +node_els_trace (); + + els =efc_els_io_alloc (node,sizeof (*acc)); +if (!els) { +efc_log_err (efc,"els IO alloc failed\n" ); +return EFC_FAIL ; + } + + els->display_name ="ls_acc" ; + +memset (&els->io.iparam,0 ,sizeof (els->io.iparam)); + els->io.iparam.els.ox_id = ox_id; + + acc = els->io.req.virt; +memset (acc,0 ,sizeof (*acc)); + + acc->la_cmd =ELS_LS_ACC ; + +return efc_els_send_rsp (els,sizeof (*acc)); +} + +int +efc_send_logo_acc (struct efc_node *node,u32 ox_id) +{ +struct efc_els_io_req *els =NULL ; +struct efc *efc = node->efc; +struct fc_els_ls_acc *logo; + +node_els_trace (); + + els =efc_els_io_alloc (node,sizeof (*logo)); +if (!els) { +efc_log_err (efc,"els IO alloc failed\n" ); +return EFC_FAIL ; + } + + els->display_name ="logo_acc" ; + +memset (&els->io.iparam,0 ,sizeof (els->io.iparam)); + els->io.iparam.els.ox_id = ox_id; + + logo = els->io.req.virt; +memset (logo,0 ,sizeof (*logo)); + + logo->la_cmd =ELS_LS_ACC ; + +return efc_els_send_rsp (els,sizeof (*logo)); +} + +int +efc_send_adisc_acc (struct efc_node *node,u32 ox_id) +{ +struct efc *efc = node->efc; +struct efc_els_io_req *els =NULL ; +struct fc_els_adisc *adisc; +struct fc_els_flogi *sparams; + +node_els_trace (); + + els =efc_els_io_alloc (node,sizeof (*adisc)); +if (!els) { +efc_log_err (efc,"els IO alloc failed\n" ); +return EFC_FAIL ; + } + + els->display_name ="adisc_acc" ; + +/* Go ahead and send the ELS_ACC */ +memset (&els->io.iparam,0 ,sizeof (els->io.iparam)); + els->io.iparam.els.ox_id = ox_id; + + sparams = (struct fc_els_flogi *)node->nport->service_params; + adisc = els->io.req.virt; +memset (adisc,0 ,sizeof (*adisc)); + adisc->adisc_cmd =ELS_LS_ACC ; + adisc->adisc_wwpn = sparams->fl_wwpn; + adisc->adisc_wwnn = sparams->fl_wwnn; +hton24 (adisc->adisc_port_id, node->rnode.nport->fc_id); + +return efc_els_send_rsp (els,sizeof (*adisc)); +} + +static inline void +fcct_build_req_header (struct fc_ct_hdr *hdr,u16 cmd,u16 max_size) +{ + hdr->ct_rev =FC_CT_REV ; + hdr->ct_fs_type =FC_FST_DIR ; + hdr->ct_fs_subtype =FC_NS_SUBTYPE ; + hdr->ct_options =0 ; + hdr->ct_cmd =cpu_to_be16 (cmd); +/* words */ + hdr->ct_mr_size =cpu_to_be16 (max_size / (sizeof (u32))); + hdr->ct_reason =0 ; + hdr->ct_explan =0 ; + hdr->ct_vendor =0 ; +} + +int +efc_ns_send_rftid (struct efc_node *node) +{ +struct efc *efc = node->efc; +struct efc_els_io_req *els; +struct { +struct fc_ct_hdr hdr; +struct fc_ns_rft_id rftid; + } *ct; + +node_els_trace (); + + els =efc_els_io_alloc (node,sizeof (*ct)); +if (!els) { +efc_log_err (efc,"IO alloc failed\n" ); +return EFC_FAIL ; + } + + els->io.iparam.ct.r_ctl =FC_RCTL_ELS_REQ ; + els->io.iparam.ct.type =FC_TYPE_CT ; + els->io.iparam.ct.df_ctl =0 ; + els->io.iparam.ct.timeout =EFC_FC_ELS_SEND_DEFAULT_TIMEOUT ; + + els->display_name ="rftid" ; + + ct = els->io.req.virt; +memset (ct,0 ,sizeof (*ct)); +fcct_build_req_header (&ct->hdr,FC_NS_RFT_ID , +sizeof (struct fc_ns_rft_id )); + +hton24 (ct->rftid.fr_fid.fp_fid, node->rnode.nport->fc_id); + ct->rftid.fr_fts.ff_type_map[FC_TYPE_FCP /FC_NS_BPW ] = +cpu_to_be32 (1 << (FC_TYPE_FCP %FC_NS_BPW )); + +return efc_els_send_req (node, els,EFC_DISC_IO_CT_REQ ); +} + +int +efc_ns_send_rffid (struct efc_node *node) +{ +struct efc *efc = node->efc; +struct efc_els_io_req *els; +struct { +struct fc_ct_hdr hdr; +struct fc_ns_rff_id rffid; + } *ct; + +node_els_trace (); + + els =efc_els_io_alloc (node,sizeof (*ct)); +if (!els) { +efc_log_err (efc,"IO alloc failed\n" ); +return EFC_FAIL ; + } + + els->io.iparam.ct.r_ctl =FC_RCTL_ELS_REQ ; + els->io.iparam.ct.type =FC_TYPE_CT ; + els->io.iparam.ct.df_ctl =0 ; + els->io.iparam.ct.timeout =EFC_FC_ELS_SEND_DEFAULT_TIMEOUT ; + + els->display_name ="rffid" ; + ct = els->io.req.virt; + +memset (ct,0 ,sizeof (*ct)); +fcct_build_req_header (&ct->hdr,FC_NS_RFF_ID , +sizeof (struct fc_ns_rff_id )); + +hton24 (ct->rffid.fr_fid.fp_fid, node->rnode.nport->fc_id); +if (node->nport->enable_ini) + ct->rffid.fr_feat |=FCP_FEAT_INIT ; +if (node->nport->enable_tgt) + ct->rffid.fr_feat |=FCP_FEAT_TARG ; + ct->rffid.fr_type =FC_TYPE_FCP ; + +return efc_els_send_req (node, els,EFC_DISC_IO_CT_REQ ); +} + +int +efc_ns_send_gidpt (struct efc_node *node) +{ +struct efc_els_io_req *els =NULL ; +struct efc *efc = node->efc; +struct { +struct fc_ct_hdr hdr; +struct fc_ns_gid_pt gidpt; + } *ct; + +node_els_trace (); + + els =efc_els_io_alloc_size (node,sizeof (*ct),EFC_ELS_GID_PT_RSP_LEN ); +if (!els) { +efc_log_err (efc,"IO alloc failed\n" ); +return EFC_FAIL ; + } + + els->io.iparam.ct.r_ctl =FC_RCTL_ELS_REQ ; + els->io.iparam.ct.type =FC_TYPE_CT ; + els->io.iparam.ct.df_ctl =0 ; + els->io.iparam.ct.timeout =EFC_FC_ELS_SEND_DEFAULT_TIMEOUT ; + + els->display_name ="gidpt" ; + + ct = els->io.req.virt; + +memset (ct,0 ,sizeof (*ct)); +fcct_build_req_header (&ct->hdr,FC_NS_GID_PT , +sizeof (struct fc_ns_gid_pt )); + + ct->gidpt.fn_pt_type =FC_TYPE_FCP ; + +return efc_els_send_req (node, els,EFC_DISC_IO_CT_REQ ); +} + +void +efc_els_io_cleanup (struct efc_els_io_req *els,int evt,void *arg) +{ +/* don't want further events that could come; e.g. abort requests +* from the node state machine; thus, disable state machine +*/ + els->els_req_free = true; +efc_node_post_els_resp (els->node, evt, arg); + +efc_els_io_free (els); +} + +static int +efc_ct_acc_cb (void *arg,u32 length,int status,u32 ext_status) +{ +struct efc_els_io_req *els = arg; + +efc_els_io_free (els); + +return EFC_SUCCESS ; +} + +int +efc_send_ct_rsp (struct efc *efc,struct efc_node *node,u16 ox_id, +struct fc_ct_hdr *ct_hdr,u32 cmd_rsp_code, +u32 reason_code,u32 reason_code_explanation) +{ +struct efc_els_io_req *els =NULL ; +struct fc_ct_hdr *rsp =NULL ; + + els =efc_els_io_alloc (node,256 ); +if (!els) { +efc_log_err (efc,"IO alloc failed\n" ); +return EFC_FAIL ; + } + + rsp = els->io.rsp.virt; + + *rsp = *ct_hdr; + +fcct_build_req_header (rsp, cmd_rsp_code,0 ); + rsp->ct_reason = reason_code; + rsp->ct_explan = reason_code_explanation; + + els->display_name ="ct_rsp" ; + els->cb = efc_ct_acc_cb; + +/* Prepare the IO request details */ + els->io.io_type =EFC_DISC_IO_CT_RESP ; + els->io.xmit_len =sizeof (*rsp); + + els->io.rpi = node->rnode.indicator; + els->io.d_id = node->rnode.fc_id; + +memset (&els->io.iparam,0 ,sizeof (els->io.iparam)); + + els->io.iparam.ct.ox_id = ox_id; + els->io.iparam.ct.r_ctl =3 ; + els->io.iparam.ct.type =FC_TYPE_CT ; + els->io.iparam.ct.df_ctl =0 ; + els->io.iparam.ct.timeout =5 ; + +if (efc->tt.send_els (efc, &els->io)) { +efc_els_io_free (els); +return EFC_FAIL ; + } +return EFC_SUCCESS ; +} + +int +efc_send_bls_acc (struct efc_node *node,struct fc_frame_header *hdr) +{ +struct sli_bls_params bls; +struct fc_ba_acc *acc; +struct efc *efc = node->efc; + +memset (&bls,0 ,sizeof (bls)); + bls.ox_id =be16_to_cpu (hdr->fh_ox_id); + bls.rx_id =be16_to_cpu (hdr->fh_rx_id); + bls.s_id =ntoh24 (hdr->fh_d_id); + bls.d_id = node->rnode.fc_id; + bls.rpi = node->rnode.indicator; + bls.vpi = node->nport->indicator; + + acc = (void *)bls.payload; + acc->ba_ox_id =cpu_to_be16 (bls.ox_id); + acc->ba_rx_id =cpu_to_be16 (bls.rx_id); + acc->ba_high_seq_cnt =cpu_to_be16 (U16_MAX ); + +return efc->tt.send_bls (efc,FC_RCTL_BA_ACC , &bls); +}
drivers/scsi/elx/libefc/efc_els.h new file +107 -0
107 lines not on this page · raw message
Signature · 1 line
2.26.2
Re: [PATCH v8 15/31] elx: libefc: Extended link Service IO handling
Quoted 9 lines · James Smart
This patch continues the libefc library population.
This patch adds library interface definitions for:
Functions to build and send ELS/CT/BLS commands and responses.Co-developed-by Ram Vegesna <[email protected]>Signed-off-by Ram Vegesna <[email protected]>Signed-off-by James Smart <[email protected]>Reviewed-by Daniel Wagner <[email protected]>
Quoted 7 lines
--- drivers/scsi/elx/libefc/efc_els.c | 1099 +++++++++++++++++++++++++++++ drivers/scsi/elx/libefc/efc_els.h | 107 +++ 2 files changed, 1206 insertions(+) create mode 100644 drivers/scsi/elx/libefc/efc_els.c create mode 100644 drivers/scsi/elx/libefc/efc_els.h
Cheers,
Hannes
Signature · 4 lines
Dr. Hannes Reinecke Kernel Storage Architect [email protected] +49 911 74053 688 SUSE Software Solutions Germany GmbH, 90409 Nürnberg GF: F. Imendörffer, HRB 36809 (AG Nürnberg)