efct: Broadcom (Emulex) FC Target driver
Subsystems (2)
v2 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 12/18/2018. 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.6/scsi-queue branch.
Thank you to those that have contributed to the driver in the past.
Review comments welcome!
-- james
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 (32):
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: 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: Extended link Service IO handling
elx: efct: SCSI IO handling routines
elx: efct: LIO backend interface routines
elx: efct: Hardware IO submission routines
elx: efct: link statistics and SFP data
elx: efct: xport and hardware teardown routines
elx: efct: IO timeout handling routines
elx: efct: Firmware update, async link processing
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 | 8 + drivers/scsi/Kconfig | 2 + drivers/scsi/Makefile | 1 + drivers/scsi/elx/Kconfig | 9 + drivers/scsi/elx/Makefile | 30 + drivers/scsi/elx/efct/efct_driver.c | 1031 +++++ drivers/scsi/elx/efct/efct_driver.h | 150 + drivers/scsi/elx/efct/efct_els.c | 1953 +++++++++ drivers/scsi/elx/efct/efct_els.h | 136 + drivers/scsi/elx/efct/efct_hw.c | 6742 ++++++++++++++++++++++++++++++++ drivers/scsi/elx/efct/efct_hw.h | 1099 ++++++ drivers/scsi/elx/efct/efct_hw_queues.c | 1648 ++++++++ drivers/scsi/elx/efct/efct_hw_queues.h | 67 + drivers/scsi/elx/efct/efct_io.c | 203 + drivers/scsi/elx/efct/efct_io.h | 196 + drivers/scsi/elx/efct/efct_lio.c | 1921 +++++++++ drivers/scsi/elx/efct/efct_lio.h | 192 + drivers/scsi/elx/efct/efct_scsi.c | 1572 ++++++++ drivers/scsi/elx/efct/efct_scsi.h | 313 ++ drivers/scsi/elx/efct/efct_unsol.c | 835 ++++ drivers/scsi/elx/efct/efct_unsol.h | 49 + drivers/scsi/elx/efct/efct_utils.c | 446 +++ drivers/scsi/elx/efct/efct_utils.h | 83 + drivers/scsi/elx/efct/efct_xport.c | 1472 +++++++ drivers/scsi/elx/efct/efct_xport.h | 205 + drivers/scsi/elx/include/efc_common.h | 52 + drivers/scsi/elx/libefc/efc.h | 99 + drivers/scsi/elx/libefc/efc_device.c | 1658 ++++++++ drivers/scsi/elx/libefc/efc_device.h | 72 + drivers/scsi/elx/libefc/efc_domain.c | 1126 ++++++ drivers/scsi/elx/libefc/efc_domain.h | 52 + drivers/scsi/elx/libefc/efc_fabric.c | 1762 +++++++++ drivers/scsi/elx/libefc/efc_fabric.h | 116 + drivers/scsi/elx/libefc/efc_lib.c | 131 + drivers/scsi/elx/libefc/efc_node.c | 1343 +++++++ drivers/scsi/elx/libefc/efc_node.h | 188 + drivers/scsi/elx/libefc/efc_sm.c | 213 + drivers/scsi/elx/libefc/efc_sm.h | 140 + drivers/scsi/elx/libefc/efc_sport.c | 843 ++++ drivers/scsi/elx/libefc/efc_sport.h | 52 + drivers/scsi/elx/libefc/efclib.h | 637 +++ drivers/scsi/elx/libefc_sli/sli4.c | 5748 +++++++++++++++++++++++++++ drivers/scsi/elx/libefc_sli/sli4.h | 4296 ++++++++++++++++++++ 43 files changed, 38891 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_els.c create mode 100644 drivers/scsi/elx/efct/efct_els.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_hw_queues.h 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_utils.c create mode 100644 drivers/scsi/elx/efct/efct_utils.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_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_fabric.c create mode 100644 drivers/scsi/elx/libefc/efc_fabric.h create mode 100644 drivers/scsi/elx/libefc/efc_lib.c 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_sm.c create mode 100644 drivers/scsi/elx/libefc/efc_sm.h create mode 100644 drivers/scsi/elx/libefc/efc_sport.c create mode 100644 drivers/scsi/elx/libefc/efc_sport.h 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.13.7
PATCH v2 1/32 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 | 8 ++ drivers/scsi/elx/libefc_sli/sli4.c | 26 ++++ drivers/scsi/elx/libefc_sli/sli4.h | 239 +++++++++++++++++++++++++++++++++++++ 3 files changed, 273 insertions(+) create mode 100644 drivers/scsi/elx/libefc_sli/sli4.c create mode 100644 drivers/scsi/elx/libefc_sli/sli4.h
MAINTAINERS +8 -0
@@ -6139,6 +6139,14 @@ W: http://www.broadcom.com S: Supported 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] +W: http://www.broadcom.com +S: Supported +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 +26 -0
@@ -0,0 +1,26 @@ +// SPDX-License-Identifier: GPL-2.0 +/* +* Copyright (C) 2019 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" + +struct sli4_asic_entry_t { +u32 rev_id; +u32 family; +}; + +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 }, +};
drivers/scsi/elx/libefc_sli/sli4.h new file +239 -0
239 lines not on this page · raw message
Signature · 1 line
2.13.7
Re: [PATCH v2 01/32] elx: libefc_sli: SLI-4 register offsets and field definitions
Quoted 181 lines · James Smart
This is the initial patch for the new Emulex target mode SCSI driver sources.
This patch:
- Creates the new Emulex source level directorydrivers/scsi/elxand adds the directory to theMAINTAINERSfile.
- Creates the first library subdirectorydrivers/scsi/elx/libefc_sli. This library is a SLI-4 interface library.
- Starts the population of thelibefc_slilibrary with definitions of SLI-4 hardware register offsets and definitions.Signed-off-by Ram Vegesna <[email protected]>Signed-off-by James Smart <[email protected]>--- MAINTAINERS | 8 ++ drivers/scsi/elx/libefc_sli/sli4.c | 26 ++++ drivers/scsi/elx/libefc_sli/sli4.h | 239 +++++++++++++++++++++++++++++++++++++ 3 files changed, 273 insertions(+) create mode 100644 drivers/scsi/elx/libefc_sli/sli4.c create mode 100644 drivers/scsi/elx/libefc_sli/sli4.hMAINTAINERS +8
-0@@ -6139,6 +6139,14 @@ W: http://www.broadcom.com S: Supported 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] +W: http://www.broadcom.com +S: Supported +F: drivers/scsi/elx/ + ENE CB710 FLASH CARD READER DRIVER M: Michał Mirosław <[email protected]> S: Maintaineddrivers/scsi/elx/libefc_sli/sli4.c new file +26
-0@@ -0,0 +1,26 @@ +// SPDX-License-Identifier: GPL-2.0 +/* +* Copyright (C) 2019 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" + +struct sli4_asic_entry_t { +u32 rev_id; +u32 family; +}; + +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 }, +};drivers/scsi/elx/libefc_sli/sli4.h new file +103
-0@@ -0,0 +1,239 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* +* Copyright (C) 2019 Broadcom. All Rights Reserved. The term +* “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. +* +*/ + +/* +* All common SLI-4 structures and function prototypes. +*/ + +#ifndef _SLI4_H +#define _SLI4_H + +/************************************************************************* +* Common SLI-4 register offsets and field definitions +*/ + +/* SLI_INTF - SLI Interface Definition Register */ +#define SLI4_INTF_REG 0x0058 +enum { +SLI4_INTF_REV_SHIFT =4 , +SLI4_INTF_REV_MASK =0x0F <<SLI4_INTF_REV_SHIFT , + +SLI4_INTF_REV_S3 =3 <<SLI4_INTF_REV_SHIFT , +SLI4_INTF_REV_S4 =4 <<SLI4_INTF_REV_SHIFT , + +SLI4_INTF_FAMILY_SHIFT =8 , +SLI4_INTF_FAMILY_MASK =0x0F <<SLI4_INTF_FAMILY_SHIFT , + +SLI4_FAMILY_CHECK_ASIC_TYPE =0xf <<SLI4_INTF_FAMILY_SHIFT , + +SLI4_INTF_IF_TYPE_SHIFT =12 , +SLI4_INTF_IF_TYPE_MASK =0x0F <<SLI4_INTF_IF_TYPE_SHIFT , + +SLI4_INTF_IF_TYPE_2 =2 <<SLI4_INTF_IF_TYPE_SHIFT , +SLI4_INTF_IF_TYPE_6 =6 <<SLI4_INTF_IF_TYPE_SHIFT , + +SLI4_INTF_VALID_SHIFT =29 , +SLI4_INTF_VALID_MASK =7 <<SLI4_INTF_VALID_SHIFT , + +SLI4_INTF_VALID_VALUE =6 <<SLI4_INTF_VALID_SHIFT , +}; + +/* ASIC_ID - SLI ASIC Type and Revision Register */ +#define SLI4_ASIC_ID_REG 0x009c +enum { +SLI4_ASIC_GEN_SHIFT =8 , +SLI4_ASIC_GEN_MASK =0xFF <<SLI4_ASIC_GEN_SHIFT , +SLI4_ASIC_GEN_5 =0x0b <<SLI4_ASIC_GEN_SHIFT , +SLI4_ASIC_GEN_6 =0x0c <<SLI4_ASIC_GEN_SHIFT , +SLI4_ASIC_GEN_7 =0x0d <<SLI4_ASIC_GEN_SHIFT , +}; + +enum { +SLI4_ASIC_REV_A0 =0x00 , +SLI4_ASIC_REV_A1 =0x01 , +SLI4_ASIC_REV_A2 =0x02 , +SLI4_ASIC_REV_A3 =0x03 , +SLI4_ASIC_REV_B0 =0x10 , +SLI4_ASIC_REV_B1 =0x11 , +SLI4_ASIC_REV_B2 =0x12 , +SLI4_ASIC_REV_C0 =0x20 , +SLI4_ASIC_REV_C1 =0x21 , +SLI4_ASIC_REV_C2 =0x22 , +SLI4_ASIC_REV_D0 =0x30 , +}; + +/* BMBX - Bootstrap Mailbox Register */ +#define SLI4_BMBX_REG 0x0160 +#define SLI4_BMBX_MASK_HI 0x3 +#define SLI4_BMBX_MASK_LO 0xf +#define SLI4_BMBX_RDY (1 << 0) +#define SLI4_BMBX_HI (1 << 1) +#define SLI4_BMBX_WRITE_HI (r) \ + ((upper_32_bits(r) & ~SLI4_BMBX_MASK_HI) | SLI4_BMBX_HI) +#define SLI4_BMBX_WRITE_LO (r) \ + (((upper_32_bits(r) & SLI4_BMBX_MASK_HI) << 30) | \ + (((r) & ~SLI4_BMBX_MASK_LO) >> 2)) +#define SLI4_BMBX_SIZE 256 + +/* SLIPORT_CONTROL - SLI Port Control Register */ +#define SLI4_PORT_CTRL_REG 0x0408 +#define SLI4_PORT_CTRL_IP (1 << 27) +#define SLI4_PORT_CTRL_IDIS (1 << 22) +#define SLI4_PORT_CTRL_FDD (1 << 31) + +/* SLI4_SLIPORT_ERROR - SLI Port Error Register */ +#define SLI4_PORT_ERROR1 0x040c +#define SLI4_PORT_ERROR2 0x0410 + +/* EQCQ_DOORBELL - EQ and CQ Doorbell Register */ +#define SLI4_EQCQ_DB_REG 0x120 +enum { +SLI4_EQ_ID_LO_MASK =0x01FF , + +SLI4_CQ_ID_LO_MASK =0x03FF , + +SLI4_EQCQ_CI_EQ =0x0200 , + +SLI4_EQCQ_QT_EQ =0x00000400 , + SLI4_EQCQ_QT_CQ = 0x00000000, +
drivers/scsi/elx/libefc_sli/sli4.h line 113
Quoted 10 lines
drivers/scsi/elx/libefc_sli/sli4.h new file +10
-0+SLI4_EQCQ_ID_HI_SHIFT =11 , +SLI4_EQCQ_ID_HI_MASK =0xF800 , + +SLI4_EQCQ_NUM_SHIFT =16 , +SLI4_EQCQ_NUM_MASK =0x1FFF0000 , + +SLI4_EQCQ_ARM =0x20000000 , + SLI4_EQCQ_UNARM = 0x00000000, +}; +
Please be consistent here wrt _SHIFT and _MASK statements. Either have them spelled out (as you do in this case), but then please change the first hunk to avoid an explicit shift.
Or keep the style in the first hunk, and change the _MASK values here to use the _SHIFT values
(ie SLI4_EQCQ_ID_HI_MASK = 0x1F << SLI4_EQCQ_ID_HI_SHIFT). I don't mind either way, but keep it consistent.
Cheers,
Hannes
Signature · 4 lines
Dr. Hannes Reinecke Teamlead Storage & Networking [email protected] +49 911 74053 688 SUSE Software Solutions Germany GmbH, Maxfeldstr. 5, 90409 Nürnberg HRB 36809 (AG Nürnberg), GF: Felix Imendörffer
Re: [PATCH v2 01/32] elx: libefc_sli: SLI-4 register offsets and field definitions
Quoted 8 lines · Hannes Reinecke
Please be consistent here wrt
_SHIFTand_MASKstatements. Either have them spelled out (as you do in this case), but then please change the first hunk to avoid an explicit shift.
Or keep the style in the first hunk, and change the_MASKvalues here to use the_SHIFTvalues
(ieSLI4_EQCQ_ID_HI_MASK=0x1F<<SLI4_EQCQ_ID_HI_SHIFT). I don't mind either way, but keep it consistent.
Quoted 4 lines
Cheers,
Hannes
We will do the change to spell out the _MASK directly.
Thanks
-- james
PATCH v2 2/32 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 | 1768 +++++++++++++++++++++++++++++++++ 2 files changed, 1793 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) 2019 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 +1768 -0
1,778 lines not on this page · raw message
Signature · 1 line
2.13.7
Re: [PATCH v2 02/32] elx: libefc_sli: SLI Descriptors and Queue entries
Quoted 128 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).Signed-off-by Ram Vegesna <[email protected]>Signed-off-by James Smart <[email protected]>--- drivers/scsi/elx/include/efc_common.h | 25 + drivers/scsi/elx/libefc_sli/sli4.h | 1768 +++++++++++++++++++++++++++++++++ 2 files changed, 1793 insertions(+) create mode 100644 drivers/scsi/elx/include/efc_common.hdrivers/scsi/elx/include/efc_common.h new file +25
-0@@ -0,0 +1,25 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* +* Copyright (C) 2019 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 +65
-0@@ -12,6 +12,8 @@#ifndef _SLI4_H#define _SLI4_H +#include "../include/efc_common.h" +/************************************************************************* * Common SLI-4 register offsets and field definitions */ @@ -236,4 +238,1770 @@ struct sli4_reg {u32 off; }; +struct sli4_dmaaddr { +__le32 low; +__le32 high; +}; + +/* a 3-word BDE with address 1st 2 words, length last word */ +struct sli4_bufptr { +struct sli4_dmaaddr addr; +__le32 length; +}; + +/* a 3-word BDE with length as first word, address last 2 words */ +struct sli4_bufptr_len1st { +__le32 length0; +struct sli4_dmaaddr addr; +}; + +/* Buffer Descriptor Entry (BDE) */ +enum { +SLI4_BDE_MASK_BUFFER_LEN =0x00ffffff , +SLI4_BDE_MASK_BDE_TYPE =0xff000000 , +}; + +struct sli4_bde { +__le32 bde_type_buflen; +union { +struct sli4_dmaaddr data; +struct { +__le32 offset; +__le32 rsvd2; + } imm; +struct sli4_dmaaddr blp; + } u; +}; + +/* Buffer Descriptors */ +enum { +BDE_TYPE_SHIFT =24 , +BDE_TYPE_BDE_64 =0x00 ,/* Generic 64-bit data */ +BDE_TYPE_BDE_IMM =0x01 ,/* Immediate data */ +BDE_TYPE_BLP =0x40 ,/* Buffer List Pointer */ +}; + +/* Scatter-Gather Entry (SGE) */ +#define SLI4_SGE_MAX_RESERVED 3 + +enum { +/* DW2 */ +SLI4_SGE_DATA_OFFSET_MASK =0x07FFFFFF , +/*DW2W1*/ +SLI4_SGE_TYPE_SHIFT =27 , +SLI4_SGE_TYPE_MASK =0xf <<SLI4_SGE_TYPE_SHIFT , +/*SGE Types*/ +SLI4_SGE_TYPE_DATA =0x00 , +SLI4_SGE_TYPE_DIF =0x04 ,/* Data Integrity Field */ +SLI4_SGE_TYPE_LSP =0x05 ,/* List Segment Pointer */ +SLI4_SGE_TYPE_PEDIF =0x06 ,/* Post Encryption Engine DIF */ +SLI4_SGE_TYPE_PESEED =0x07 ,/* Post Encryption DIF Seed */ +SLI4_SGE_TYPE_DISEED =0x08 ,/* DIF Seed */ +SLI4_SGE_TYPE_ENC =0x09 ,/* Encryption */ +SLI4_SGE_TYPE_ATM =0x0a ,/* DIF Application Tag Mask */ +SLI4_SGE_TYPE_SKIP =0x0c ,/* SKIP */ +
drivers/scsi/elx/libefc_sli/sli4.h struct sli4_reg { · line 313
Quoted 10 lines
drivers/scsi/elx/libefc_sli/sli4.h +10
-0+ SLI4_SGE_LAST = (1 << 31), +}; + +struct sli4_sge { +__le32 buffer_address_high; +__le32 buffer_address_low; +__le32 dw2_flags; +__le32 buffer_length; +}; +
I am really not a big fan of anonymous enums, especially not if they are scoped for specific structures.
Can you please avoid the use of anonymous enums, and name them according to the structure where they are indended to be used?
Ideally the structure should reference named enums directly, but I do agree that this it not always possible or desired.
But we should at least name them accordingly to give the developer a hint where these values are expected to occur.
Eg in the above case
enum sli4_sge_flags {
or similar would make the intended usage clearer.
Quoted 37 lines
drivers/scsi/elx/libefc_sli/sli4.h +37
-0+/* T10 DIF Scatter-Gather Entry (SGE) */ +struct sli4_dif_sge { +__le32 buffer_address_high; +__le32 buffer_address_low; +__le32 dw2_flags; +__le32 rsvd12; +}; + +/* Data Integrity Seed (DISEED) SGE */ +enum { +/* DW2W1 */ +DISEED_SGE_HS = (1 <<2 ), +DISEED_SGE_WS = (1 <<3 ), +DISEED_SGE_IC = (1 <<4 ), +DISEED_SGE_ICS = (1 <<5 ), +DISEED_SGE_ATRT = (1 <<6 ), +DISEED_SGE_AT = (1 <<7 ), +DISEED_SGE_FAT = (1 <<8 ), +DISEED_SGE_NA = (1 <<9 ), +DISEED_SGE_HI = (1 <<10 ), + +/* DW3W1 */ +DISEED_SGE_BS_MASK =0x0007 , +DISEED_SGE_AI = (1 <<3 ), +DISEED_SGE_ME = (1 <<4 ), +DISEED_SGE_RE = (1 <<5 ), +DISEED_SGE_CE = (1 <<6 ), +DISEED_SGE_NR = (1 <<7 ), + +DISEED_SGE_OP_RX_SHIFT =8 , +DISEED_SGE_OP_RX_MASK = (0xf <<DISEED_SGE_OP_RX_SHIFT ), +DISEED_SGE_OP_TX_SHIFT =12 , +DISEED_SGE_OP_TX_MASK = (0xf <<DISEED_SGE_OP_TX_SHIFT ), + +/* Opcode values */ +DISEED_SGE_OP_IN_NODIF_OUT_CRC =0x00 , +DISEED_SGE_OP_IN_CRC_OUT_NODIF =0x01 ,
drivers/scsi/elx/libefc_sli/sli4.h struct sli4_reg { · line 360
Quoted 10 lines
drivers/scsi/elx/libefc_sli/sli4.h +10
-0+DISEED_SGE_OP_IN_NODIF_OUT_CSUM =0x02 , +DISEED_SGE_OP_IN_CSUM_OUT_NODIF =0x03 , +DISEED_SGE_OP_IN_CRC_OUT_CRC =0x04 , +DISEED_SGE_OP_IN_CSUM_OUT_CSUM =0x05 , +DISEED_SGE_OP_IN_CRC_OUT_CSUM =0x06 , +DISEED_SGE_OP_IN_CSUM_OUT_CRC =0x07 , + DISEED_SGE_OP_IN_RAW_OUT_RAW = 0x08, + +}; +
Similar here: please use individual named enums, not one giant anonymous enum containing different value for different use-cases.
Cheers,
Hannes
Signature · 4 lines
Dr. Hannes Reinecke Teamlead Storage & Networking [email protected] +49 911 74053 688 SUSE Software Solutions Germany GmbH, Maxfeldstr. 5, 90409 Nürnberg HRB 36809 (AG Nürnberg), GF: Felix Imendörffer
Re: [PATCH v2 02/32] elx: libefc_sli: SLI Descriptors and Queue entries
Quoted 9 lines · Hannes Reinecke
I am really not a big fan of anonymous enums, especially not if they are scoped for specific structures.
Can you please avoid the use of anonymous enums, and name them according to the structure where they are indended to be used?
Ideally the structure should reference named enums directly, but I do agree that this it not always possible or desired.
But we should at least name them accordingly to give the developer a hint where these values are expected to occur.
Quoted 6 lines
Eg in the above case
enum
sli4_sge_flags{or similar would make the intended usage clearer.
We will add names to the enums as suggested.
Thanks
-- james
PATCH v2 3/32 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.
--- drivers/scsi/elx/libefc_sli/sli4.h | 1728 +++++++++++++++++++++++++++++++++++- 1 file changed, 1727 insertions(+), 1 deletion(-)
drivers/scsi/elx/libefc_sli/sli4.h +1727 -1
@@ -1995,7 +1995,7 @@ struct sli4_fc_xri_aborted_cqe {#define SLI4_ELS_REQUEST64_DIR_READ 0x1#define SLI4_ELS_REQUEST64_OTHER 0x0 -#define SLI4_ELS_REQUEST64_LOGO 0x1 +#define SLI4_ELS_REQUEST64_LOGO 0x1#define SLI4_ELS_REQUEST64_FDISC 0x2#define SLI4_ELS_REQUEST64_FLOGIN 0x3#define SLI4_ELS_REQUEST64_PLOGI 0x4
@@ -2004,4 +2004,1730 @@ struct sli4_fc_xri_aborted_cqe {#define SLI4_ELS_REQUEST64_CMD_NON_FABRIC 0x0c#define SLI4_ELS_REQUEST64_CMD_FABRIC 0x0d +#define SLI_PAGE_SIZE (1 << 12)/* 4096 */ +#define SLI_SUB_PAGE_MASK (SLI_PAGE_SIZE - 1) +#define SLI_ROUND_PAGE (b) (((b) + SLI_SUB_PAGE_MASK) & ~SLI_SUB_PAGE_MASK) + +#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 { +MBX_CMD_CONFIG_LINK =0x07 , +MBX_CMD_DUMP =0x17 , +MBX_CMD_DOWN_LINK =0x06 , +MBX_CMD_INIT_LINK =0x05 , +MBX_CMD_INIT_VFI =0xa3 , +MBX_CMD_INIT_VPI =0xa4 , +MBX_CMD_POST_XRI =0xa7 , +MBX_CMD_RELEASE_XRI =0xac , +MBX_CMD_READ_CONFIG =0x0b , +MBX_CMD_READ_STATUS =0x0e , +MBX_CMD_READ_NVPARMS =0x02 , +MBX_CMD_READ_REV =0x11 , +MBX_CMD_READ_LNK_STAT =0x12 , +MBX_CMD_READ_SPARM64 =0x8d , +MBX_CMD_READ_TOPOLOGY =0x95 , +MBX_CMD_REG_FCFI =0xa0 , +MBX_CMD_REG_FCFI_MRQ =0xaf , +MBX_CMD_REG_RPI =0x93 , +MBX_CMD_REG_RX_RQ =0xa6 , +MBX_CMD_REG_VFI =0x9f , +MBX_CMD_REG_VPI =0x96 , +MBX_CMD_RQST_FEATURES =0x9d , +MBX_CMD_SLI_CONFIG =0x9b , +MBX_CMD_UNREG_FCFI =0xa2 , +MBX_CMD_UNREG_RPI =0x14 , +MBX_CMD_UNREG_VFI =0xa1 , +MBX_CMD_UNREG_VPI =0x97 , +MBX_CMD_WRITE_NVPARMS =0x03 , +MBX_CMD_CFG_AUTO_XFER_RDY =0xAD , + +MBX_STATUS_SUCCESS =0x0000 , +MBX_STATUS_FAILURE =0x0001 , +MBX_STATUS_RPI_NOT_REG =0x1400 , +}; + +/* CONFIG_LINK */ +enum { +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; +}; + +enum { +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 */ +#define FC_TOPOLOGY_FCAL 0 +#define FC_TOPOLOGY_P2P 1 + +#define SLI4_INIT_LINK_F_LOOP_BACK (1 << 0) +#define SLI4_INIT_LINK_F_UNFAIR (1 << 6) +#define SLI4_INIT_LINK_F_NO_LIRP (1 << 7) +#define SLI4_INIT_LINK_F_LOOP_VALID_CHK (1 << 8) +#define SLI4_INIT_LINK_F_NO_LISA (1 << 9) +#define SLI4_INIT_LINK_F_FAIL_OVER (1 << 10) +#define SLI4_INIT_LINK_F_NO_AUTOSPEED (1 << 11) +#define SLI4_INIT_LINK_F_PICK_HI_ALPA (1 << 15) + +#define SLI4_INIT_LINK_F_P2P_ONLY 1 +#define SLI4_INIT_LINK_F_FCAL_ONLY 2 + +#define SLI4_INIT_LINK_F_FCAL_FAIL_OVER 0 +#define SLI4_INIT_LINK_F_P2P_FAIL_OVER 1 + +enum { +SLI4_INIT_LINK_SEL_RESET_AL_PA =0xff , +SLI4_INIT_LINK_FLAG_LOOPBACK =0x1 , +SLI4_INIT_LINK_FLAG_TOPOLOGY =0x6 , +SLI4_INIT_LINK_FLAG_UNFAIR =0x40 , +SLI4_INIT_LINK_FLAG_SKIP_LIRP_LILP =0x80 , +SLI4_INIT_LINK_FLAG_LOOP_VALIDITY =0x100 , +SLI4_INIT_LINK_FLAG_SKIP_LISA =0x200 , +SLI4_INIT_LINK_FLAG_EN_TOPO_FAILOVER =0x400 , +SLI4_INIT_LINK_FLAG_FIXED_SPEED =0x800 , +SLI4_INIT_LINK_FLAG_SEL_HIGHTEST_AL_PA =0x8000 , +}; + +#define FC_LINK_SPEED_1G 1 +#define FC_LINK_SPEED_2G 2 +#define FC_LINK_SPEED_AUTO_1_2 3 +#define FC_LINK_SPEED_4G 4 +#define FC_LINK_SPEED_AUTO_4_1 5 +#define FC_LINK_SPEED_AUTO_4_2 6 +#define FC_LINK_SPEED_AUTO_4_2_1 7 +#define FC_LINK_SPEED_8G 8 +#define FC_LINK_SPEED_AUTO_8_1 9 +#define FC_LINK_SPEED_AUTO_8_2 10 +#define FC_LINK_SPEED_AUTO_8_2_1 11 +#define FC_LINK_SPEED_AUTO_8_4 12 +#define FC_LINK_SPEED_AUTO_8_4_1 13 +#define FC_LINK_SPEED_AUTO_8_4_2 14 +#define FC_LINK_SPEED_10G 16 +#define FC_LINK_SPEED_16G 17 +#define FC_LINK_SPEED_AUTO_16_8_4 18 +#define FC_LINK_SPEED_AUTO_16_8 19 +#define FC_LINK_SPEED_32G 20 +#define FC_LINK_SPEED_AUTO_32_16_8 21 +#define FC_LINK_SPEED_AUTO_32_16 22 + +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_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_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_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_RESOURCE_EXT =0x80000000 ,/* DW1 */ +SLI4_READ_CFG_RESP_TOPOLOGY =0xff000000 ,/* DW2 */ +}; + +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 ]; +}; + +#define SLI4_READ_CFG_TOPO_FC 0x1/* FC topology unknown */ +#define SLI4_READ_CFG_TOPO_FC_DA 0x2/* FC Direct Attach */ +#define SLI4_READ_CFG_TOPO_FC_AL 0x3/* FC-AL topology */ + +/* READ_NVPARMS - read SLI port configuration parameters */ +enum { +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 */ +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; +}; + +#define SLI4_READ_SPARM64_VPI_DEFAULT 0 +#define SLI4_READ_SPARM64_VPI_SPECIAL U16_MAX + +#define SLI4_READ_SPARM64_WWPN_OFFSET (4 * sizeof(u32)) +#define SLI4_READ_SPARM64_WWNN_OFFSET (SLI4_READ_SPARM64_WWPN_OFFSET \ + + sizeof(uint64_t)) +/* READ_TOPOLOGY - read the link event information */ +enum { +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 , +}; + +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; +}; + +#define SLI4_MIN_LOOP_MAP_BYTES 128 + +#define SLI4_READ_TOPOLOGY_LINK_UP 0x1 +#define SLI4_READ_TOPOLOGY_LINK_DOWN 0x2 +#define SLI4_READ_TOPOLOGY_LINK_NO_ALPA 0x3 + +#define SLI4_READ_TOPOLOGY_UNKNOWN 0x0 +#define SLI4_READ_TOPOLOGY_NPORT 0x1 +#define SLI4_READ_TOPOLOGY_FC_AL 0x2 + +#define SLI4_READ_TOPOLOGY_SPEED_NONE 0x00 +#define SLI4_READ_TOPOLOGY_SPEED_1G 0x04 +#define SLI4_READ_TOPOLOGY_SPEED_2G 0x08 +#define SLI4_READ_TOPOLOGY_SPEED_4G 0x10 +#define SLI4_READ_TOPOLOGY_SPEED_8G 0x20 +#define SLI4_READ_TOPOLOGY_SPEED_10G 0x40 +#define SLI4_READ_TOPOLOGY_SPEED_16G 0x80 +#define SLI4_READ_TOPOLOGY_SPEED_32G 0x90 + +/* 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_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_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; +}; + +/* REG_RPI - register a Remote Port Indicator */ +enum { +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 { +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_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_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_SLICONF_EMB =0x1 ,/* DW1 */ +SLI4_SLICONF_PMDCMD_SHIFT =3 , +SLI4_SLICONF_PMDCMD_MASK =0x1F <<SLI4_SLICONF_PMDCMD_SHIFT , +SLI4_SLICONF_PMDCMD_VAL_1 =1 <<SLI4_SLICONF_PMDCMD_SHIFT , +SLI4_SLICONF_PMDCNT =0xf8 , + +SLI4_SLICONFIG_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 */ +enum { +SLI4_READSTATUS_CLEAR_COUNTERS =0x1 ,/* DW1 */ +}; + +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_LNKSTAT_REC = (1 <<0 ), +SLI4_READ_LNKSTAT_GEC = (1 <<1 ), +SLI4_READ_LNKSTAT_W02OF = (1 <<2 ), +SLI4_READ_LNKSTAT_W03OF = (1 <<3 ), +SLI4_READ_LNKSTAT_W04OF = (1 <<4 ), +SLI4_READ_LNKSTAT_W05OF = (1 <<5 ), +SLI4_READ_LNKSTAT_W06OF = (1 <<6 ), +SLI4_READ_LNKSTAT_W07OF = (1 <<7 ), +SLI4_READ_LNKSTAT_W08OF = (1 <<8 ), +SLI4_READ_LNKSTAT_W09OF = (1 <<9 ), +SLI4_READ_LNKSTAT_W10OF = (1 <<10 ), +SLI4_READ_LNKSTAT_W11OF = (1 <<11 ), +SLI4_READ_LNKSTAT_W12OF = (1 <<12 ), +SLI4_READ_LNKSTAT_W13OF = (1 <<13 ), +SLI4_READ_LNKSTAT_W14OF = (1 <<14 ), +SLI4_READ_LNKSTAT_W15OF = (1 <<15 ), +SLI4_READ_LNKSTAT_W16OF = (1 <<16 ), +SLI4_READ_LNKSTAT_W17OF = (1 <<17 ), +SLI4_READ_LNKSTAT_W18OF = (1 <<18 ), +SLI4_READ_LNKSTAT_W19OF = (1 <<19 ), +SLI4_READ_LNKSTAT_W20OF = (1 <<20 ), +SLI4_READ_LNKSTAT_W21OF = (1 <<21 ), +SLI4_READ_LNKSTAT_CLRC = (1 <<30 ), +SLI4_READ_LNKSTAT_CLOF = (1 <<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 { +UNREG_RPI_DP =0x2000 , +UNREG_RPI_II_SHIFT =14 , +UNREG_RPI_II_MASK =0x03 <<UNREG_RPI_II_SHIFT , +UNREG_RPI_II_RPI =0x00 <<UNREG_RPI_II_SHIFT , +UNREG_RPI_II_VPI =0x01 <<UNREG_RPI_II_SHIFT , +UNREG_RPI_II_VFI =0x02 <<UNREG_RPI_II_SHIFT , +UNREG_RPI_II_FCFI =0x03 <<UNREG_RPI_II_SHIFT , + +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 { +UNREG_VFI_II_SHIFT =14 , +UNREG_VFI_II_MASK =0x03 <<UNREG_VFI_II_SHIFT , +UNREG_VFI_II_VFI =0x00 <<UNREG_VFI_II_SHIFT , +UNREG_VFI_II_FCFI =0x03 <<UNREG_VFI_II_SHIFT , +}; + +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 { +UNREG_VPI_II_SHIFT =14 , +UNREG_VPI_II_MASK =0x03 <<UNREG_VPI_II_SHIFT , +UNREG_VPI_II_VPI =0x00 <<UNREG_VPI_II_SHIFT , +UNREG_VPI_II_VFI =0x02 <<UNREG_VPI_II_SHIFT , +UNREG_VPI_II_FCFI =0x03 <<UNREG_VPI_II_SHIFT , +}; + +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 +*/ + +#define SLI4_CFG_STATUS_SUCCESS 0x00 +#define SLI4_CFG_STATUS_FAILED 0x01 +#define SLI4_CFG_STATUS_ILLEGAL_REQUEST 0x02 +#define SLI4_CFG_STATUS_ILLEGAL_FIELD 0x03 + +#define SLI4_MGMT_STATUS_FLASHROM_READ_FAILED 0xcb + +#define SLI4_CFG_ADD_STATUS_NO_STATUS 0x00 +#define SLI4_CFG_ADD_STATUS_INVALID_OPCODE 0x1e + +/* +* Subsystem values. +*/ +#define SLI4_SUBSYSTEM_COMMON 0x01 +#define SLI4_SUBSYSTEM_LOWLEVEL 0x0B +#define SLI4_SUBSYSTEM_FC 0x0c +#define SLI4_SUBSYSTEM_DMTF 0x11 + +#define SLI4_OPC_LOWLEVEL_SET_WATCHDOG 0X36 + +/* +* Common opcode (OPC) values. +*/ +enum { +CMN_FUNCTION_RESET =0x3d , +CMN_CREATE_CQ =0x0c , +CMN_CREATE_CQ_SET =0x1d , +CMN_DESTROY_CQ =0x36 , +CMN_MODIFY_EQ_DELAY =0x29 , +CMN_CREATE_EQ =0x0d , +CMN_DESTROY_EQ =0x37 , +CMN_CREATE_MQ_EXT =0x5a , +CMN_DESTROY_MQ =0x35 , +CMN_GET_CNTL_ATTRIBUTES =0x20 , +CMN_NOP =0x21 , +CMN_GET_RSC_EXTENT_INFO =0x9a , +CMN_GET_SLI4_PARAMS =0xb5 , +CMN_QUERY_FW_CONFIG =0x3a , +CMN_GET_PORT_NAME =0x4d , + +CMN_WRITE_FLASHROM =0x07 , +/* TRANSCEIVER Data */ +CMN_READ_TRANS_DATA =0x49 , +CMN_GET_CNTL_ADDL_ATTRS =0x79 , +CMN_GET_FUNCTION_CFG =0xa0 , +CMN_GET_PROFILE_CFG =0xa4 , +CMN_SET_PROFILE_CFG =0xa5 , +CMN_GET_PROFILE_LIST =0xa6 , +CMN_GET_ACTIVE_PROFILE =0xa7 , +CMN_SET_ACTIVE_PROFILE =0xa8 , +CMN_READ_OBJECT =0xab , +CMN_WRITE_OBJECT =0xac , +CMN_DELETE_OBJECT =0xae , +CMN_READ_OBJECT_LIST =0xad , +CMN_SET_DUMP_LOCATION =0xb8 , +CMN_SET_FEATURES =0xbf , +CMN_GET_RECFG_LINK_INFO =0xc9 , +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_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; +}; + +#define SLI4_RSC_TYPE_ISCSI_INI_XRI 0x0c +#define SLI4_RSC_TYPE_VFI 0x20 +#define SLI4_RSC_TYPE_VPI 0x21 +#define SLI4_RSC_TYPE_RPI 0x22 +#define 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) & RSP_GET_PARAM_Q_CNT_MTHD_MASK) >> RSP_GET_PARAM_Q_CNT_MTHD_SHFT) +#define GET_Q_CREATE_VERSION (v) \ + (((v) & RSP_GET_PARAM_QV_MASK) >> RSP_GET_PARAM_QV_SHIFT) + +enum { +/*GENERIC*/ +RSP_GET_PARAM_Q_CNT_MTHD_SHFT =24 , +RSP_GET_PARAM_Q_CNT_MTHD_MASK = (0xF <<24 ), +RSP_GET_PARAM_QV_SHIFT =14 , +RSP_GET_PARAM_QV_MASK = (3 <<14 ), + +/* DW4 */ +RSP_GET_PARAM_PROTO_TYPE_MASK =0xFF , +/* DW5 */ +RSP_GET_PARAM_FT = (1 <<0 ), +RSP_GET_PARAM_SLI_REV_MASK = (0xF <<4 ), +RSP_GET_PARAM_SLI_FAM_MASK = (0xF <<8 ), +RSP_GET_PARAM_IF_TYPE_MASK = (0xF <<12 ), +RSP_GET_PARAM_SLI_HINT1_MASK = (0xFF <<16 ), +RSP_GET_PARAM_SLI_HINT2_MASK = (0x1F <<24 ), +/* DW6 */ +RSP_GET_PARAM_EQ_PAGE_CNT_MASK = (0xF <<0 ), +RSP_GET_PARAM_EQE_SZS_MASK = (0xF <<8 ), +RSP_GET_PARAM_EQ_PAGE_SZS_MASK = (0xFF <<16 ), +/* DW8 */ +RSP_GET_PARAM_CQ_PAGE_CNT_MASK = (0xF <<0 ), +RSP_GET_PARAM_CQE_SZS_MASK = (0xF <<8 ), +RSP_GET_PARAM_CQ_PAGE_SZS_MASK = (0xFF <<16 ), +/* DW10 */ +RSP_GET_PARAM_MQ_PAGE_CNT_MASK = (0xF <<0 ), +RSP_GET_PARAM_MQ_PAGE_SZS_MASK = (0xFF <<16 ), +/* DW12 */ +RSP_GET_PARAM_WQ_PAGE_CNT_MASK = (0xF <<0 ), +RSP_GET_PARAM_WQE_SZS_MASK = (0xF <<8 ), +RSP_GET_PARAM_WQ_PAGE_SZS_MASK = (0xFF <<16 ), +/* DW14 */ +RSP_GET_PARAM_RQ_PAGE_CNT_MASK = (0xF <<0 ), +RSP_GET_PARAM_RQE_SZS_MASK = (0xF <<8 ), +RSP_GET_PARAM_RQ_PAGE_SZS_MASK = (0xFF <<16 ), +/* DW15W1*/ +RSP_GET_PARAM_RQ_DB_WINDOW_MASK =0xF000 , +/* DW16 */ +RSP_GET_PARAM_FC = (1 <<0 ), +RSP_GET_PARAM_EXT = (1 <<1 ), +RSP_GET_PARAM_HDRR = (1 <<2 ), +RSP_GET_PARAM_SGLR = (1 <<3 ), +RSP_GET_PARAM_FBRR = (1 <<4 ), +RSP_GET_PARAM_AREG = (1 <<5 ), +RSP_GET_PARAM_TGT = (1 <<6 ), +RSP_GET_PARAM_TERP = (1 <<7 ), +RSP_GET_PARAM_ASSI = (1 <<8 ), +RSP_GET_PARAM_WCHN = (1 <<9 ), +RSP_GET_PARAM_TCCA = (1 <<10 ), +RSP_GET_PARAM_TRTY = (1 <<11 ), +RSP_GET_PARAM_TRIR = (1 <<12 ), +RSP_GET_PARAM_PHOFF = (1 <<13 ), +RSP_GET_PARAM_PHON = (1 <<14 ), +RSP_GET_PARAM_PHWQ = (1 <<15 ), +RSP_GET_PARAM_BOUND_4GA = (1 <<16 ), +RSP_GET_PARAM_RXC = (1 <<17 ), +RSP_GET_PARAM_HLM = (1 <<18 ), +RSP_GET_PARAM_IPR = (1 <<19 ), +RSP_GET_PARAM_RXRI = (1 <<20 ), +RSP_GET_PARAM_SGLC = (1 <<21 ), +RSP_GET_PARAM_TIMM = (1 <<22 ), +RSP_GET_PARAM_TSMM = (1 <<23 ), +RSP_GET_PARAM_OAS = (1 <<25 ), +RSP_GET_PARAM_LC = (1 <<26 ), +RSP_GET_PARAM_AGXF = (1 <<27 ), +RSP_GET_PARAM_LOOPBACK_MASK = (0xF <<28 ), +/* DW18 */ +RSP_GET_PARAM_SGL_PAGE_CNT_MASK = (0xF <<0 ), +RSP_GET_PARAM_SGL_PAGE_SZS_MASK = (0xFF <<8 ), +RSP_GET_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; +}; + +/* +* COMMON_QUERY_FW_CONFIG +* +* This command retrieves firmware configuration parameters and adapter +* resources available to the driver. +*/ +struct sli4_rqst_cmn_query_fw_config { +struct sli4_rqst_hdr hdr; +}; + +#define SLI4_FUNCTION_MODE_INI_MODE 0x40 +#define SLI4_FUNCTION_MODE_TGT_MODE 0x80 +#define SLI4_FUNCTION_MODE_DUA_MODE 0x800 + +#define SLI4_ULP_MODE_INI 0x40 +#define SLI4_ULP_MODE_TGT 0x80 + +struct sli4_rsp_cmn_query_fw_config { +struct sli4_rsp_hdr hdr; +__le32 config_number; +__le32 asic_rev; +__le32 physical_port; +__le32 function_mode; +__le32 ulp0_mode; +__le32 ulp0_nic_wqid_base; +__le32 ulp0_nic_wq_total;/* DW10 */ +__le32 ulp0_toe_wqid_base; +__le32 ulp0_toe_wq_total; +__le32 ulp0_toe_rqid_base; +__le32 ulp0_toe_rq_total; +__le32 ulp0_toe_defrqid_base; +__le32 ulp0_toe_defrq_total; +__le32 ulp0_lro_rqid_base; +__le32 ulp0_lro_rq_total; +__le32 ulp0_iscsi_icd_base; +__le32 ulp0_iscsi_icd_total;/* DW20 */ +__le32 ulp1_mode; +__le32 ulp1_nic_wqid_base; +__le32 ulp1_nic_wq_total; +__le32 ulp1_toe_wqid_base; +__le32 ulp1_toe_wq_total; +__le32 ulp1_toe_rqid_base; +__le32 ulp1_toe_rq_total; +__le32 ulp1_toe_defrqid_base; +__le32 ulp1_toe_defrq_total; +__le32 ulp1_lro_rqid_base;/* DW30 */ +__le32 ulp1_lro_rq_total; +__le32 ulp1_iscsi_icd_base; +__le32 ulp1_iscsi_icd_total; +__le32 function_capabilities; +__le32 ulp0_cq_base; +__le32 ulp0_cq_total; +__le32 ulp0_eq_base; +__le32 ulp0_eq_total; +__le32 ulp0_iscsi_chain_icd_base; +__le32 ulp0_iscsi_chain_icd_total;/* DW40 */ +__le32 ulp1_iscsi_chain_icd_base; +__le32 ulp1_iscsi_chain_icd_total; +}; + +/*Port Types*/ +enum { +PORT_TYPE_ETH =0 , +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 ]; +}; + +#define SLI4_MGMT_FLASHROM_OPCODE_FLASH 0x01 +#define SLI4_MGMT_FLASHROM_OPCODE_SAVE 0x02 +#define SLI4_MGMT_FLASHROM_OPCODE_CLEAR 0x03 +#define SLI4_MGMT_FLASHROM_OPCODE_REPORT 0x04 +#define SLI4_MGMT_FLASHROM_OPCODE_IMAGE_INFO 0x05 +#define SLI4_MGMT_FLASHROM_OPCODE_IMAGE_CRC 0x06 +#define SLI4_MGMT_FLASHROM_OPCODE_OFFSET_BASED_FLASH 0x07 +#define SLI4_MGMT_FLASHROM_OPCODE_OFFSET_BASED_SAVE 0x08 +#define SLI4_MGMT_PHY_FLASHROM_OPCODE_FLASH 0x09 +#define SLI4_MGMT_PHY_FLASHROM_OPCODE_SAVE 0x0a + +#define SLI4_FLASH_ROM_ACCESS_OP_TYPE_ISCSI 0x00 +#define SLI4_FLASH_ROM_ACCESS_OP_TYPE_REDBOOT 0x01 +#define SLI4_FLASH_ROM_ACCESS_OP_TYPE_BIOS 0x02 +#define SLI4_FLASH_ROM_ACCESS_OP_TYPE_PXE_BIOS 0x03 +#define SLI4_FLASH_ROM_ACCESS_OP_TYPE_CODE_CONTROL 0x04 +#define SLI4_FLASH_ROM_ACCESS_OP_TYPE_IPSEC_CFG 0x05 +#define SLI4_FLASH_ROM_ACCESS_OP_TYPE_INIT_DATA 0x06 +#define SLI4_FLASH_ROM_ACCESS_OP_TYPE_ROM_OFFSET 0x07 +#define SLI4_FLASH_ROM_ACCESS_OP_TYPE_FC_BIOS 0x08 +#define SLI4_FLASH_ROM_ACCESS_OP_TYPE_ISCSI_BAK 0x09 +#define SLI4_FLASH_ROM_ACCESS_OP_TYPE_FC_ACT 0x0a +#define SLI4_FLASH_ROM_ACCESS_OP_TYPE_FC_BAK 0x0b +#define SLI4_FLASH_ROM_ACCESS_OP_TYPE_CODE_CTRL_P 0x0c +#define SLI4_FLASH_ROM_ACCESS_OP_TYPE_NCSI 0x0d +#define SLI4_FLASH_ROM_ACCESS_OP_TYPE_NIC 0x0e +#define SLI4_FLASH_ROM_ACCESS_OP_TYPE_DCBX 0x0f +#define SLI4_FLASH_ROM_ACCESS_OP_TYPE_PXE_BIOS_CFG 0x10 +#define SLI4_FLASH_ROM_ACCESS_OP_TYPE_ALL_CFG_DATA 0x11 + +/* +* 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 ]; +}; + +enum { +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 ]; +}; + +enum { +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_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 ]; +}; + +enum { +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 ]; +}; + +enum { +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_RQ_COM_SET_DUMP_BUFFER_LEN =0xFFFFFF , +SLI4_RQ_COM_SET_DUMP_FDB =0x20000000 , +SLI4_RQ_COM_SET_DUMP_BLP =0x40000000 , +SLI4_RQ_COM_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; +}; + +enum { +RSP_SET_DUMP_BUFFER_LEN =0xFFFFFF , +}; + +struct sli4_rsp_cmn_set_dump_location { +struct sli4_rsp_hdr hdr; +__le32 buffer_length_dword; +}; + +#define SLI4_SET_FEATURES_DIF_SEED 0x01 +#define SLI4_SET_FEATURES_XRI_TIMER 0x03 +#define SLI4_SET_FEATURES_MAX_PCIE_SPEED 0x04 +#define SLI4_SET_FEATURES_FCTL_CHECK 0x05 +#define SLI4_SET_FEATURES_FEC 0x06 +#define SLI4_SET_FEATURES_PCIE_RECV_DETECT 0x07 +#define SLI4_SET_FEATURES_DIF_MEMORY_MODE 0x08 +#define SLI4_SET_FEATURES_DISABLE_SLI_PORT_PAUSE_STATE 0x09 +#define SLI4_SET_FEATURES_ENABLE_PCIE_OPTIONS 0x0A +#define SLI4_SET_FEAT_CFG_AUTO_XFER_RDY_T10PI 0x0C +#define SLI4_SET_FEATURES_ENABLE_MULTI_RECEIVE_QUEUE 0x0D +#define SLI4_SET_FEATURES_SET_FTD_XFER_HINT 0x0F +#define 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_RQ_COM_SET_T10_PI_MEM_MODEL =0x1 , +}; + +struct sli4_rqst_cmn_set_features_t10_pi_mem_model { +__le32 tmm_dword; +}; + +enum { +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_SETFEAT_XFERRDY_T10PI_RTC = (1 <<0 ), +SLI4_SETFEAT_XFERRDY_T10PI_ATV = (1 <<1 ), +SLI4_SETFEAT_XFERRDY_T10PI_TMM = (1 <<2 ), +SLI4_SETFEAT_XFERRDY_T10PI_PTYPE = (0x7 <<4 ), +SLI4_SETFEAT_XFERRDY_T10PI_BLKSIZ = (0x7 <<7 ), +}; + +struct sli4_rqst_cmn_set_features_xfer_rdy_t10pi { +__le32 dw0_flags; +__le16 app_tag; +__le16 rsvd6; +}; + +enum { +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_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_LINKID_NEXT =0xff , +SLI4_SET_RECONFIG_LINKID_FD = (1 <<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 */ +#define SLI4_OPC_WQ_CREATE 0x1 +#define SLI4_OPC_WQ_DESTROY 0x2 +#define SLI4_OPC_POST_SGL_PAGES 0x3 +#define SLI4_OPC_RQ_CREATE 0x5 +#define SLI4_OPC_RQ_DESTROY 0x6 +#define SLI4_OPC_READ_FCF_TABLE 0x8 +#define SLI4_OPC_POST_HDR_TEMPLATES 0xb +#define 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 + +/* The XRI associated with this IO is already active */ +#define SLI4_IO_CONTINUATION (1 << 0) +/* Automatically generate a good RSP frame */ +#define SLI4_IO_AUTO_GOOD_RESPONSE (1 << 1) +#define SLI4_IO_NO_ABORT (1 << 2) +/* Set the DNRX bit because no auto xref rdy buffer is posted */ +#define SLI4_IO_DNRX (1 << 3) + + + +enum sli4_callback { +SLI4_CB_LINK , +SLI4_CB_MAX , +}; + +enum sli4_link_status { +SLI_LINK_STATUS_UP , +SLI_LINK_STATUS_DOWN , +SLI_LINK_STATUS_NO_ALPA , +SLI_LINK_STATUS_MAX , +}; + +enum sli4_link_topology { +SLI_LINK_TOPO_NPORT =1 , +SLI_LINK_TOPO_LOOP , +SLI_LINK_TOPO_LOOPBACK_INTERNAL , +SLI_LINK_TOPO_LOOPBACK_EXTERNAL , +SLI_LINK_TOPO_NONE , +SLI_LINK_TOPO_MAX , +}; + +enum sli4_link_medium { +SLI_LINK_MEDIUM_ETHERNET , +SLI_LINK_MEDIUM_FC , +SLI_LINK_MEDIUM_MAX , +}; + +/*Driver specific structures*/ + +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 { +SLI_RSRC_VFI , +SLI_RSRC_VPI , +SLI_RSRC_RPI , +SLI_RSRC_XRI , +SLI_RSRC_FCFI , +SLI_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[SLI_QTYPE_MAX ]; +u32 max_qentries[SLI_QTYPE_MAX ]; +u16 count_mask[SLI_QTYPE_MAX ]; +u16 count_method[SLI_QTYPE_MAX ]; +u32 qpage_count[SLI_QTYPE_MAX ]; +}; + +#define SLI_PCI_MAX_REGS 6 +struct sli4 { +void *os; +struct pci_dev *pcidev; +void __iomem *reg[SLI_PCI_MAX_REGS ]; + +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; +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 ]; +u8 port_number; +char port_name[2 ]; +char modeldesc[64 ]; +char bios_version_string[32 ]; +/* +* 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 extent[SLI_RSRC_MAX ]; +u32 features; +u32 has_extents:1 , + auto_reg:1 , + auto_xfer_rdy:1 , + hdr_template_req:1 , + perf_hint:1 , + perf_wq_id_association:1 , + cq_create_version:2 , + mq_create_version:2 , + high_login_mode:1 , + sgl_pre_registered:1 , + sgl_pre_registration_required:1 , + t10_dif_inline_capable:1 , + t10_dif_separate_capable:1 ; +u32 sge_supported_length; +u32 sgl_page_sizes; +u32 max_sgl_pages; +u32 wqe_size; + +/* +* 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; +u32 vpd_length; +}; +#endif /* !_SLI4_H */
Signature · 1 line
2.13.7
Re: [PATCH v2 03/32] elx: libefc_sli: Data structures and defines for mbox commands
Quoted 16 lines · James Smart
This patch continues the
libefc_sliSLI-4 library population.This patch adds definitions for SLI-4 mailbox commands and responses.
Signed-off-by Ram Vegesna <[email protected]>Signed-off-by James Smart <[email protected]>--- drivers/scsi/elx/libefc_sli/sli4.h | 1728 +++++++++++++++++++++++++++++++++++- 1 file changed, 1727 insertions(+), 1 deletion(-)drivers/scsi/elx/libefc_sli/sli4.h +0
-0
drivers/scsi/elx/libefc_sli/sli4.h struct sli4_fc_xri_aborted_cqe { · line 2001
Quoted 8 lines
drivers/scsi/elx/libefc_sli/sli4.h +1
-1@@ -1995,7 +1995,7 @@ struct sli4_fc_xri_aborted_cqe {#define SLI4_ELS_REQUEST64_DIR_READ 0x1#define SLI4_ELS_REQUEST64_OTHER 0x0 -#define SLI4_ELS_REQUEST64_LOGO 0x1 +#define SLI4_ELS_REQUEST64_LOGO 0x1#define SLI4_ELS_REQUEST64_FDISC 0x2#define SLI4_ELS_REQUEST64_FLOGIN 0x3#define SLI4_ELS_REQUEST64_PLOGI 0x4
Shouldn't this rather be merged with the previous patch?
Quoted 59 lines
drivers/scsi/elx/libefc_sli/sli4.h +55
-0@@ -2004,4 +2004,1730 @@ struct sli4_fc_xri_aborted_cqe {#define SLI4_ELS_REQUEST64_CMD_NON_FABRIC 0x0c#define SLI4_ELS_REQUEST64_CMD_FABRIC 0x0d +#define SLI_PAGE_SIZE (1 << 12)/* 4096 */ +#define SLI_SUB_PAGE_MASK (SLI_PAGE_SIZE - 1) +#define SLI_ROUND_PAGE (b) (((b) + SLI_SUB_PAGE_MASK) & ~SLI_SUB_PAGE_MASK) + +#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 { +MBX_CMD_CONFIG_LINK =0x07 , +MBX_CMD_DUMP =0x17 , +MBX_CMD_DOWN_LINK =0x06 , +MBX_CMD_INIT_LINK =0x05 , +MBX_CMD_INIT_VFI =0xa3 , +MBX_CMD_INIT_VPI =0xa4 , +MBX_CMD_POST_XRI =0xa7 , +MBX_CMD_RELEASE_XRI =0xac , +MBX_CMD_READ_CONFIG =0x0b , +MBX_CMD_READ_STATUS =0x0e , +MBX_CMD_READ_NVPARMS =0x02 , +MBX_CMD_READ_REV =0x11 , +MBX_CMD_READ_LNK_STAT =0x12 , +MBX_CMD_READ_SPARM64 =0x8d , +MBX_CMD_READ_TOPOLOGY =0x95 , +MBX_CMD_REG_FCFI =0xa0 , +MBX_CMD_REG_FCFI_MRQ =0xaf , +MBX_CMD_REG_RPI =0x93 , +MBX_CMD_REG_RX_RQ =0xa6 , +MBX_CMD_REG_VFI =0x9f , +MBX_CMD_REG_VPI =0x96 , +MBX_CMD_RQST_FEATURES =0x9d , +MBX_CMD_SLI_CONFIG =0x9b , +MBX_CMD_UNREG_FCFI =0xa2 , +MBX_CMD_UNREG_RPI =0x14 ,
drivers/scsi/elx/libefc_sli/sli4.h struct sli4_fc_xri_aborted_cqe { · line 2071
Quoted 10 lines
drivers/scsi/elx/libefc_sli/sli4.h +10
-0+MBX_CMD_UNREG_VFI =0xa1 , +MBX_CMD_UNREG_VPI =0x97 , +MBX_CMD_WRITE_NVPARMS =0x03 , +MBX_CMD_CFG_AUTO_XFER_RDY =0xAD , + +MBX_STATUS_SUCCESS =0x0000 , +MBX_STATUS_FAILURE =0x0001 , + MBX_STATUS_RPI_NOT_REG = 0x1400, +}; +
Make this two enums, one 'enum sli4_mbx_cmd' and one 'enum sli4_mbx_status'.
Quoted 18 lines
drivers/scsi/elx/libefc_sli/sli4.h +18
-0+/* CONFIG_LINK */ +enum { +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;
drivers/scsi/elx/libefc_sli/sli4.h struct sli4_fc_xri_aborted_cqe { · line 2099
Quoted 10 lines
drivers/scsi/elx/libefc_sli/sli4.h +10
-0+__le32 r_a_tov; +__le32 r_t_tov; +__le32 al_tov; +__le32 rsvd36; +__le32 bbscn_dword; +}; + +enum { +SLI4_DUMP4_TYPE =0xf , +};
Single enum should rather be converted into a #define ..
Quoted 35 lines
drivers/scsi/elx/libefc_sli/sli4.h +35
-0+ +#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 */ +#define FC_TOPOLOGY_FCAL 0 +#define FC_TOPOLOGY_P2P 1 + +#define SLI4_INIT_LINK_F_LOOP_BACK (1 << 0) +#define SLI4_INIT_LINK_F_UNFAIR (1 << 6) +#define SLI4_INIT_LINK_F_NO_LIRP (1 << 7) +#define SLI4_INIT_LINK_F_LOOP_VALID_CHK (1 << 8) +#define SLI4_INIT_LINK_F_NO_LISA (1 << 9) +#define SLI4_INIT_LINK_F_FAIL_OVER (1 << 10) +#define SLI4_INIT_LINK_F_NO_AUTOSPEED (1 << 11) +#define SLI4_INIT_LINK_F_PICK_HI_ALPA (1 << 15) + +#define SLI4_INIT_LINK_F_P2P_ONLY 1 +#define SLI4_INIT_LINK_F_FCAL_ONLY 2 + +#define SLI4_INIT_LINK_F_FCAL_FAIL_OVER 0 +#define SLI4_INIT_LINK_F_P2P_FAIL_OVER 1 + +enum { +SLI4_INIT_LINK_SEL_RESET_AL_PA =0xff , +SLI4_INIT_LINK_FLAG_LOOPBACK =0x1 ,
drivers/scsi/elx/libefc_sli/sli4.h struct sli4_fc_xri_aborted_cqe { · line 2144
Quoted 10 lines
drivers/scsi/elx/libefc_sli/sli4.h +10
-0+SLI4_INIT_LINK_FLAG_TOPOLOGY =0x6 , +SLI4_INIT_LINK_FLAG_UNFAIR =0x40 , +SLI4_INIT_LINK_FLAG_SKIP_LIRP_LILP =0x80 , +SLI4_INIT_LINK_FLAG_LOOP_VALIDITY =0x100 , +SLI4_INIT_LINK_FLAG_SKIP_LISA =0x200 , +SLI4_INIT_LINK_FLAG_EN_TOPO_FAILOVER =0x400 , +SLI4_INIT_LINK_FLAG_FIXED_SPEED =0x800 , + SLI4_INIT_LINK_FLAG_SEL_HIGHTEST_AL_PA = 0x8000, +}; +
Why is this an enum, and the above SLI4_INIT_LINK_F_XXX value are defines? Please be consistent.
And this applies throughout the remainder of the patch.
Cheers,
Hannes
Signature · 4 lines
Dr. Hannes Reinecke Teamlead Storage & Networking [email protected] +49 911 74053 688 SUSE Software Solutions Germany GmbH, Maxfeldstr. 5, 90409 Nürnberg HRB 36809 (AG Nürnberg), GF: Felix Imendörffer
Re: [PATCH v2 03/32] elx: libefc_sli: Data structures and defines for mbox commands
Quoted 11 lines · Hannes Reinecke
drivers/scsi/elx/libefc_sli/sli4.h struct sli4_fc_xri_aborted_cqe { · line 2001
Quoted 9 lines · James Smart
drivers/scsi/elx/libefc_sli/sli4.h +1
-1@@ -1995,7 +1995,7 @@ struct sli4_fc_xri_aborted_cqe {#define SLI4_ELS_REQUEST64_DIR_READ 0x1#define SLI4_ELS_REQUEST64_OTHER 0x0 -#define SLI4_ELS_REQUEST64_LOGO 0x1 +#define SLI4_ELS_REQUEST64_LOGO 0x1#define SLI4_ELS_REQUEST64_FDISC 0x2#define SLI4_ELS_REQUEST64_FLOGIN 0x3#define SLI4_ELS_REQUEST64_PLOGI 0x4Shouldn't this rather be merged with the previous patch?
yes - will do so
Quoted 2 lines
Make this two enums, one 'enum
sli4_mbx_cmd' and one 'enumsli4_mbx_status'.
...
Quoted 3 lines
Single enum should rather be converted into a #define ..
...
Quoted 9 lines
Why is this an enum, and the above
SLI4_INIT_LINK_F_XXXvalue are defines? Please be consistent.And this applies throughout the remainder of the patch.
Cheers,
Hannes
We will convert to multiple enums.
Thanks
-- james
PATCH v2 4/32 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 | 27 + drivers/scsi/elx/libefc_sli/sli4.c | 1556 +++++++++++++++++++++++++++++++++ drivers/scsi/elx/libefc_sli/sli4.h | 9 + 3 files changed, 1592 insertions(+)
drivers/scsi/elx/include/efc_common.h +27 -0
@@ -22,4 +22,31 @@ struct efc_dma {struct pci_dev *pdev; }; +#define efc_log_crit(efc, fmt, args...) \ + dev_crit(&((efc)->pcidev)->dev, fmt, ##args) + +#define efc_log_err(efc, fmt, args...) \ + dev_err(&((efc)->pcidev)->dev, fmt, ##args) + +#define efc_log_warn(efc, fmt, args...) \ + dev_warn(&((efc)->pcidev)->dev, fmt, ##args) + +#define efc_log_info(efc, fmt, args...) \ + dev_info(&((efc)->pcidev)->dev, fmt, ##args) + +#define efc_log_test(efc, fmt, args...) \ + dev_dbg(&((efc)->pcidev)->dev, fmt, ##args) + +#define efc_log_debug(efc, fmt, args...) \ + dev_dbg(&((efc)->pcidev)->dev, fmt, ##args) + +#define efc_assert (cond, ...) \ + do { \ + if (!(cond)) { \ + pr_err("%s(%d) assertion (%s) failed\n", \ + __FILE__, __LINE__, #cond); \ + dump_stack(); \ + } \ + } while (0) +#endif /* __EFC_COMMON_H__ */
drivers/scsi/elx/libefc_sli/sli4.c +1556 -0
1,559 lines not on this page · raw message
drivers/scsi/elx/libefc_sli/sli4.h +9 -0
@@ -3730,4 +3730,13 @@ struct sli4 { u32 vpd_length; }; +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.13.7
Re: [PATCH v2 04/32] elx: libefc_sli: queue create/destroy/parse routines
Quoted 187 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.
Signed-off-by Ram Vegesna <[email protected]>Signed-off-by James Smart <[email protected]>--- drivers/scsi/elx/include/efc_common.h | 27 + drivers/scsi/elx/libefc_sli/sli4.c | 1556 +++++++++++++++++++++++++++++++++ drivers/scsi/elx/libefc_sli/sli4.h | 9 + 3 files changed, 1592 insertions(+)drivers/scsi/elx/include/efc_common.h +27
-0@@ -22,4 +22,31 @@ struct efc_dma {struct pci_dev *pdev; }; +#define efc_log_crit(efc, fmt, args...) \ + dev_crit(&((efc)->pcidev)->dev, fmt, ##args) + +#define efc_log_err(efc, fmt, args...) \ + dev_err(&((efc)->pcidev)->dev, fmt, ##args) + +#define efc_log_warn(efc, fmt, args...) \ + dev_warn(&((efc)->pcidev)->dev, fmt, ##args) + +#define efc_log_info(efc, fmt, args...) \ + dev_info(&((efc)->pcidev)->dev, fmt, ##args) + +#define efc_log_test(efc, fmt, args...) \ + dev_dbg(&((efc)->pcidev)->dev, fmt, ##args) + +#define efc_log_debug(efc, fmt, args...) \ + dev_dbg(&((efc)->pcidev)->dev, fmt, ##args) + +#define efc_assert (cond, ...) \ + do { \ + if (!(cond)) { \ + pr_err("%s(%d) assertion (%s) failed\n", \ + __FILE__, __LINE__, #cond); \ + dump_stack(); \ + } \ + } while (0) +#endif /* __EFC_COMMON_H__ */ drivers/scsi/elx/libefc_sli/sli4.c +130
-0@@ -24,3 +24,1559 @@ static struct sli4_asic_entry_t sli4_asic_table[] = { { SLI4_ASIC_REV_A3, SLI4_ASIC_GEN_6}, { SLI4_ASIC_REV_A1, SLI4_ASIC_GEN_7}, }; + +/* Convert queue type enum (SLI_QTYPE_*) into a string */ +static char *SLI_QNAME [] = { +"Event Queue" , +"Completion Queue" , +"Mailbox Queue" , +"Work Queue" , +"Receive Queue" , +"Undefined" +}; + +/* +* Write a SLI_CONFIG command to the provided buffer. +* +* @sli4 SLI context pointer. +* @buf Destination buffer for the command. +* @size size of the destination buffer(buf). +* @length Length in bytes of attached command. +* @dma DMA buffer for non-embedded commands. +* +*/ +static void * +sli_config_cmd_init (struct sli4 *sli4,void *buf, +size_t size,u32 length, +struct efc_dma *dma) +{ +struct sli4_cmd_sli_config *config =NULL ; +u32 flags =0 ; + +if (length >sizeof (config->payload.embed) && !dma) { +efc_log_err (sli4,"Too big for an embedded cmd with len(%d)\n" , + length); +return NULL ; + } + + config = buf; + +memset (buf,0 , size); + + config->hdr.command =MBX_CMD_SLI_CONFIG ; +if (!dma) { + flags |=SLI4_SLICONF_EMB ; + config->dw1_flags =cpu_to_le32 (flags); + config->payload_len =cpu_to_le32 (length); + buf += offsetof(struct sli4_cmd_sli_config, payload.embed); +return buf; + } + + flags =SLI4_SLICONF_PMDCMD_VAL_1 ; + flags &= ~SLI4_SLICONF_EMB ; + config->dw1_flags =cpu_to_le32 (flags); + + config->payload.mem.addr.low =cpu_to_le32 (lower_32_bits (dma->phys)); + config->payload.mem.addr.high =cpu_to_le32 (upper_32_bits (dma->phys)); + config->payload.mem.length = +cpu_to_le32 (dma->size &SLI4_SLICONFIG_PMD_LEN ); + config->payload_len =cpu_to_le32 (dma->size); +/* save pointer to DMA for BMBX dumping purposes */ + sli4->bmbx_non_emb_pmd = dma; +return dma->virt; +} + +/* +* Write a COMMON_CREATE_CQ command. +* +* This creates a Version 2 message. +* +* Returns 0 on success, or non-zero otherwise. +*/ +static int +sli_cmd_common_create_cq (struct sli4 *sli4,void *buf,size_t size, +struct efc_dma *qmem, +u16 eq_id) +{ +struct sli4_rqst_cmn_create_cq_v2 *cqv2 =NULL ; +u32 p; +uintptr_t addr; +u32 page_bytes =0 ; +u32 num_pages =0 ; +size_t cmd_size =0 ; +u32 page_size =0 ; +u32 n_cqe =0 ; +u32 dw5_flags =0 ; +u16 dw6w1_arm =0 ; +__le32 len; + +/* First calculate number of pages and the mailbox cmd length */ + n_cqe = qmem->size /SLI4_CQE_BYTES ; +switch (n_cqe) { +case 256 : +case 512 : +case 1024 : +case 2048 : + page_size =1 ; +break ; +case 4096 : + page_size =2 ; +break ; +default : +return EFC_FAIL ; + } + page_bytes = page_size *SLI_PAGE_SIZE ; + num_pages =sli_page_count (qmem->size, page_bytes); + + cmd_size =CFG_RQST_CMDSZ (cmn_create_cq_v2) +SZ_DMAADDR * num_pages; + + cqv2 =sli_config_cmd_init (sli4, buf, size, cmd_size,NULL ); +if (!cqv2) +return EFC_FAIL ; + + len =CFG_RQST_PYLD_LEN_VAR (cmn_create_cq_v2, +SZ_DMAADDR * num_pages); +sli_cmd_fill_hdr (&cqv2->hdr,CMN_CREATE_CQ ,SLI4_SUBSYSTEM_COMMON , +CMD_V2 , len); + cqv2->page_size = page_size; + +/* valid values for number of pages: 1, 2, 4, 8 (sec 4.4.3) */ + cqv2->num_pages =cpu_to_le16 (num_pages); +if (!num_pages || num_pages >SLI4_CMN_CREATE_CQ_V2_MAX_PAGES ) +return EFC_FAIL ; + +switch (num_pages) { +case 1 : + dw5_flags |=CQ_CNT_VAL (256 ); +break ; +case 2 : + dw5_flags |=CQ_CNT_VAL (512 ); +break ; +case 4 : + dw5_flags |=CQ_CNT_VAL (1024 );
drivers/scsi/elx/libefc_sli/sli4.c static struct sli4_asic_entry_t sli4_asic_table[] = { · line 166
Quoted 10 lines
drivers/scsi/elx/libefc_sli/sli4.c +10
-0+break ; +case 8 : + dw5_flags |=CQ_CNT_VAL (LARGE ); + cqv2->cqe_count =cpu_to_le16 (n_cqe); +break ; +default : +efc_log_info (sli4,"num_pages %d not valid\n" , num_pages); +return -EFC_FAIL ; + } +
Hmm. Why do you return -EFC_FAIL here, and EFC_FAIL in the two cases above? Do you differentiate between EFC_FAIL and -EFC_FAIL?
If so you should probably use different #defines ...
Quoted 228 lines
drivers/scsi/elx/libefc_sli/sli4.c +228
-0+if (sli4->if_type ==SLI4_INTF_IF_TYPE_6 ) + dw5_flags |=CREATE_CQV2_AUTOVALID ; + + dw5_flags |=CREATE_CQV2_EVT ; + dw5_flags |=CREATE_CQV2_VALID ; + + cqv2->dw5_flags =cpu_to_le32 (dw5_flags); + cqv2->dw6w1_arm =cpu_to_le16 (dw6w1_arm); + cqv2->eq_id =cpu_to_le16 (eq_id); + +for (p =0 , addr = qmem->phys; p < num_pages; p++, addr += page_bytes) { + cqv2->page_phys_addr[p].low =cpu_to_le32 (lower_32_bits (addr)); + cqv2->page_phys_addr[p].high =cpu_to_le32 (upper_32_bits (addr)); + } + +return EFC_SUCCESS ; +} + +/* Write a COMMON_CREATE_EQ command */ +static int +sli_cmd_common_create_eq (struct sli4 *sli4,void *buf,size_t size, +struct efc_dma *qmem) +{ +struct sli4_rqst_cmn_create_eq *eq; +u32 p; +uintptr_t addr; +u16 num_pages; +u32 dw5_flags =0 ; +u32 dw6_flags =0 , ver; + + eq =sli_config_cmd_init (sli4, buf, size, +SLI_CONFIG_PYLD_LENGTH (cmn_create_eq),NULL ); +if (!eq) +return EFC_FAIL ; + +if (sli4->if_type ==SLI4_INTF_IF_TYPE_6 ) + ver =CMD_V2 ; + +sli_cmd_fill_hdr (&eq->hdr,CMN_CREATE_EQ ,SLI4_SUBSYSTEM_COMMON , + ver,CFG_RQST_PYLD_LEN (cmn_create_eq)); + +/* valid values for number of pages: 1, 2, 4 (sec 4.4.3) */ + num_pages = qmem->size /SLI_PAGE_SIZE ; + eq->num_pages =cpu_to_le16 (num_pages); + +switch (num_pages) { +case 1 : + dw5_flags |=SLI4_EQE_SIZE_4 ; + dw6_flags |=EQ_CNT_VAL (1024 ); +break ; +case 2 : + dw5_flags |=SLI4_EQE_SIZE_4 ; + dw6_flags |=EQ_CNT_VAL (2048 ); +break ; +case 4 : + dw5_flags |=SLI4_EQE_SIZE_4 ; + dw6_flags |=EQ_CNT_VAL (4096 ); +break ; +default : +efc_log_err (sli4,"num_pages %d not valid\n" , num_pages); +return EFC_FAIL ; + } + +if (sli4->if_type ==SLI4_INTF_IF_TYPE_6 ) + dw5_flags |=CREATE_EQ_AUTOVALID ; + + dw5_flags |=CREATE_EQ_VALID ; + dw6_flags &= (~CREATE_EQ_ARM ); + eq->dw5_flags =cpu_to_le32 (dw5_flags); + eq->dw6_flags =cpu_to_le32 (dw6_flags); + eq->dw7_delaymulti =cpu_to_le32 (CREATE_EQ_DELAYMULTI ); + +for (p =0 , addr = qmem->phys; p < num_pages; + p++, addr +=SLI_PAGE_SIZE ) { + eq->page_address[p].low =cpu_to_le32 (lower_32_bits (addr)); + eq->page_address[p].high =cpu_to_le32 (upper_32_bits (addr)); + } + +return EFC_SUCCESS ; +} + +static int +sli_cmd_common_create_mq_ext (struct sli4 *sli4,void *buf,size_t size, +struct efc_dma *qmem, +u16 cq_id) +{ +struct sli4_rqst_cmn_create_mq_ext *mq; +u32 p; +uintptr_t addr; +u32 num_pages; +u16 dw6w1_flags =0 ; + + mq =sli_config_cmd_init (sli4, buf, size, +SLI_CONFIG_PYLD_LENGTH (cmn_create_mq_ext), +NULL ); +if (!mq) +return EFC_FAIL ; + +sli_cmd_fill_hdr (&mq->hdr,CMN_CREATE_MQ_EXT ,SLI4_SUBSYSTEM_COMMON , +CMD_V0 ,CFG_RQST_PYLD_LEN (cmn_create_mq_ext)); + +/* valid values for number of pages: 1, 2, 4, 8 (sec 4.4.12) */ + num_pages = qmem->size /SLI_PAGE_SIZE ; + mq->num_pages =cpu_to_le16 (num_pages); +switch (num_pages) { +case 1 : + dw6w1_flags |=SLI4_MQE_SIZE_16 ; +break ; +case 2 : + dw6w1_flags |=SLI4_MQE_SIZE_32 ; +break ; +case 4 : + dw6w1_flags |=SLI4_MQE_SIZE_64 ; +break ; +case 8 : + dw6w1_flags |=SLI4_MQE_SIZE_128 ; +break ; +default : +efc_log_info (sli4,"num_pages %d not valid\n" , num_pages); +return EFC_FAIL ; + } + + mq->async_event_bitmap =cpu_to_le32 (SLI4_ASYNC_EVT_FC_ALL ); + +if (sli4->mq_create_version) { + mq->cq_id_v1 =cpu_to_le16 (cq_id); + mq->hdr.dw3_version =cpu_to_le32 (CMD_V1 ); + }else { + dw6w1_flags |= (cq_id <<CREATE_MQEXT_CQID_SHIFT ); + } + mq->dw7_val =cpu_to_le32 (CREATE_MQEXT_VAL ); + + mq->dw6w1_flags =cpu_to_le16 (dw6w1_flags); +for (p =0 , addr = qmem->phys; p < num_pages; + p++, addr +=SLI_PAGE_SIZE ) { + mq->page_phys_addr[p].low =cpu_to_le32 (lower_32_bits (addr)); + mq->page_phys_addr[p].high =cpu_to_le32 (upper_32_bits (addr)); + } + +return EFC_SUCCESS ; +} + +int +sli_cmd_wq_create (struct sli4 *sli4,void *buf,size_t size, +struct efc_dma *qmem,u16 cq_id) +{ +struct sli4_rqst_wq_create *wq; +u32 p; +uintptr_t addr; +u32 page_size =0 ; +u32 page_bytes =0 ; +u32 n_wqe =0 ; +u16 num_pages; + + wq =sli_config_cmd_init (sli4, buf, size, +SLI_CONFIG_PYLD_LENGTH (wq_create),NULL ); +if (!wq) +return EFC_FAIL ; + +sli_cmd_fill_hdr (&wq->hdr,SLI4_OPC_WQ_CREATE ,SLI4_SUBSYSTEM_FC , +CMD_V1 ,CFG_RQST_PYLD_LEN (wq_create)); + n_wqe = qmem->size / sli4->wqe_size; + +switch (qmem->size) { +case 4096 : +case 8192 : +case 16384 : +case 32768 : + page_size =1 ; +break ; +case 65536 : + page_size =2 ; +break ; +case 131072 : + page_size =4 ; +break ; +case 262144 : + page_size =8 ; +break ; +case 524288 : + page_size =10 ; +break ; +default : +return EFC_FAIL ; + } + page_bytes = page_size *SLI_PAGE_SIZE ; + +/* valid values for number of pages(num_pages): 1-8 */ + num_pages =sli_page_count (qmem->size, page_bytes); + wq->num_pages =cpu_to_le16 (num_pages); +if (!num_pages || num_pages >SLI4_WQ_CREATE_MAX_PAGES ) +return EFC_FAIL ; + + wq->cq_id =cpu_to_le16 (cq_id); + + wq->page_size = page_size; + +if (sli4->wqe_size ==SLI4_WQE_EXT_BYTES ) + wq->wqe_size_byte |=SLI4_WQE_EXT_SIZE ; +else + wq->wqe_size_byte |=SLI4_WQE_SIZE ; + + wq->wqe_count =cpu_to_le16 (n_wqe); + +for (p =0 , addr = qmem->phys; p < num_pages; p++, addr += page_bytes) { + wq->page_phys_addr[p].low =cpu_to_le32 (lower_32_bits (addr)); + wq->page_phys_addr[p].high =cpu_to_le32 (upper_32_bits (addr)); + } + +return EFC_SUCCESS ; +} + +int +sli_cmd_rq_create (struct sli4 *sli4,void *buf,size_t size, +struct efc_dma *qmem, +u16 cq_id,u16 buffer_size) +{ +struct sli4_rqst_rq_create *rq; +u32 p; +uintptr_t addr; +u16 num_pages; + + rq =sli_config_cmd_init (sli4, buf, size, +SLI_CONFIG_PYLD_LENGTH (rq_create),NULL ); +if (!rq) +return EFC_FAIL ; + + sli_cmd_fill_hdr(&rq->hdr, SLI4_OPC_RQ_CREATE, SLI4_SUBSYSTEM_FC,
drivers/scsi/elx/libefc_sli/sli4.c static struct sli4_asic_entry_t sli4_asic_table[] = { · line 404
Quoted 10 lines
drivers/scsi/elx/libefc_sli/sli4.c +10
-0+ CMD_V0, CFG_RQST_PYLD_LEN(rq_create)); +/* valid values for number of pages: 1-8 (sec 4.5.6) */ + num_pages =sli_page_count (qmem->size,SLI_PAGE_SIZE ); + rq->num_pages =cpu_to_le16 (num_pages); +if (!num_pages || + num_pages >SLI4_RQ_CREATE_V0_MAX_PAGES ) { +efc_log_info (sli4,"num_pages %d not valid\n" , num_pages); +return 0 ; + } +
'0'? Why not EFC_FAIL/EFC_SUCCESS?
drivers/scsi/elx/libefc_sli/sli4.c static struct sli4_asic_entry_t sli4_asic_table[] = { · line 417
Quoted 13 lines
drivers/scsi/elx/libefc_sli/sli4.c +13
-0+/* +* RQE count is the log base 2 of the total number of entries +*/ + rq->rqe_count_byte |=31 -__builtin_clz (qmem->size /SLI4_RQE_SIZE ); + +if (buffer_size <SLI4_RQ_CREATE_V0_MIN_BUF_SIZE || + buffer_size >SLI4_RQ_CREATE_V0_MAX_BUF_SIZE ) { +efc_log_err (sli4,"buffer_size %d out of range (%d-%d)\n" , + buffer_size, +SLI4_RQ_CREATE_V0_MIN_BUF_SIZE , +SLI4_RQ_CREATE_V0_MAX_BUF_SIZE ); +return -1 ; + }
'-1'? Not EFC_FAIL?
[ .. ]
Quoted 11 lines
drivers/scsi/elx/libefc_sli/sli4.c +11
-0+int +__sli_queue_init (struct sli4 *sli4,struct sli4_queue *q, +u32 qtype,size_t size,u32 n_entries, +u32 align) +{ +if (!q->dma.virt || size != q->size || + n_entries != q->length) { +if (q->dma.size) +__sli_queue_destroy (sli4, q); + +memset (q,0 ,sizeof (struct sli4_queue ));
drivers/scsi/elx/libefc_sli/sli4.c static struct sli4_asic_entry_t sli4_asic_table[] = { · line 586
Quoted 10 lines
drivers/scsi/elx/libefc_sli/sli4.c +10
-0+ + q->dma.size = size * n_entries; + q->dma.virt =dma_alloc_coherent (&sli4->pcidev->dev, + q->dma.size, &q->dma.phys, + GFP_DMA);> + if (!q->dma.virt) { +memset (&q->dma,0 ,sizeof (struct efc_dma )); +efc_log_err (sli4,"%s allocation failed\n" , +SLI_QNAME [qtype]); +return -1 ; + }
EFC_FAIL?
Cheers,
Hannes
Signature · 4 lines
Dr. Hannes Reinecke Teamlead Storage & Networking [email protected] +49 911 74053 688 SUSE Software Solutions Germany GmbH, Maxfeldstr. 5, 90409 Nürnberg HRB 36809 (AG Nürnberg), GF: Felix Imendörffer
Re: [PATCH v2 04/32] elx: libefc_sli: queue create/destroy/parse routines
Quoted 4 lines · Hannes Reinecke
Hmm. Why do you return -EFC_FAIL here, and
EFC_FAILin the two cases above? Do you differentiate betweenEFC_FAILand -EFC_FAIL?
If so you should probably use different #defines ...
...
Quoted 3 lines
'0'? Why not EFC_FAIL/EFC_SUCCESS?
...
Quoted 6 lines
EFC_FAIL?Cheers,
Hannes
We will remove all -1, -EFC_FAIL and return only EFC_SUCCESS/EFC_FAIL.
Thanks
-- james
PATCH v2 5/32 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 | 1717 ++++++++++++++++++++++++++++++++++++ drivers/scsi/elx/libefc_sli/sli4.h | 2 + 2 files changed, 1719 insertions(+)
drivers/scsi/elx/libefc_sli/sli4.c +1717 -0
@@ -1580,3 +1580,1720 @@ sli_cq_parse(struct sli4 *sli4, struct sli4_queue *cq, u8 *cqe,return rc; } + +/* Write an ABORT_WQE work queue entry */ +int +sli_abort_wqe (struct sli4 *sli4,void *buf,size_t size, +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 , size); + +switch (type) { +case SLI_ABORT_XRI : + abort->criteria =SLI4_ABORT_CRITERIA_XRI_TAG ; +if (mask) { +efc_log_warn (sli4,"%#x aborting XRI %#x warning non-zero mask" , + mask, ids); + mask =0 ; + } +break ; +case SLI_ABORT_ABORT_ID : + abort->criteria =SLI4_ABORT_CRITERIA_ABORT_TAG ; +break ; +case SLI_ABORT_REQUEST_ID : + abort->criteria =SLI4_ABORT_CRITERIA_REQUEST_TAG ; +break ; +default : +efc_log_info (sli4,"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 ; +} + +/* Write an ELS_REQUEST64_WQE work queue entry */ +int +sli_els_request64_wqe (struct sli4 *sli4,void *buf,size_t size, +struct efc_dma *sgl, +u8 req_type,u32 req_len,u32 max_rsp_len, +u8 timeout,u16 xri,u16 tag, +u16 cq_id,u16 rnodeindicator,u16 sportindicator, +bool hlm,bool rnodeattached,u32 rnode_fcid, +u32 sport_fcid) +{ +struct sli4_els_request64_wqe *els = buf; +struct sli4_sge *sge = sgl->virt; +bool is_fabric = false; +struct sli4_bde *bptr; + +memset (buf,0 , size); + + bptr = &els->els_request_payload; +if (sli4->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 ((BDE_TYPE_BDE_64 <<BDE_TYPE_SHIFT ) | + (req_len &SLI4_BDE_MASK_BUFFER_LEN )); + + 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 ((BDE_TYPE_BLP <<BDE_TYPE_SHIFT ) | + ((2 *sizeof (struct sli4_sge )) & +SLI4_BDE_MASK_BUFFER_LEN )); + 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 (req_len); + els->max_response_payload_length =cpu_to_le32 (max_rsp_len); + + els->xri_tag =cpu_to_le16 (xri); + els->timer = timeout; + els->class_byte |=SLI4_GENERIC_CLASS_CLASS_3 ; + + els->command =SLI4_WQE_ELS_REQUEST64 ; + + els->request_tag =cpu_to_le16 (tag); + +if (hlm) { + els->qosd_xbl_hlm_iod_dbde_wqes |=SLI4_REQ_WQE_HLM ; + els->remote_id_dword =cpu_to_le32 (rnode_fcid &0x00ffffff ); + } + + 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 (req_type) { +case ELS_LOGO : + els->cmdtype_elsid_byte |= +SLI4_ELS_REQUEST64_LOGO <<SLI4_REQ_WQE_ELSID_SHFT ; +if (rnodeattached) { + els->ct_byte |= (SLI4_GENERIC_CONTEXT_RPI << +SLI4_REQ_WQE_CT_SHFT ); + els->context_tag =cpu_to_le16 (rnodeindicator); + }else { + els->ct_byte |= +SLI4_GENERIC_CONTEXT_VPI <<SLI4_REQ_WQE_CT_SHFT ; + els->context_tag = +cpu_to_le16 (sportindicator); + } +if (rnode_fcid ==FC_FID_FLOGI ) + is_fabric = true; +break ; +case ELS_FDISC : +if (rnode_fcid ==FC_FID_FLOGI ) + is_fabric = true; +if (sport_fcid ==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 (sportindicator); + 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 (sportindicator); +/* +* 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 (sport_fcid !=U32_MAX ) + els->sid_sp_dword |=cpu_to_le32 (sport_fcid); +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 (sportindicator); +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 (sportindicator); +break ; +default : + els->cmdtype_elsid_byte |= +SLI4_ELS_REQUEST64_OTHER <<SLI4_REQ_WQE_ELSID_SHFT ; +if (rnodeattached) { + els->ct_byte |= (SLI4_GENERIC_CONTEXT_RPI << +SLI4_REQ_WQE_CT_SHFT ); + els->context_tag =cpu_to_le16 (sportindicator); + }else { + els->ct_byte |= +SLI4_GENERIC_CONTEXT_VPI <<SLI4_REQ_WQE_CT_SHFT ; + els->context_tag = +cpu_to_le16 (sportindicator); + } +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 (cq_id); + +if (((els->ct_byte &SLI4_REQ_WQE_CT ) >>SLI4_REQ_WQE_CT_SHFT ) != +SLI4_GENERIC_CONTEXT_RPI ) + els->remote_id_dword =cpu_to_le32 (rnode_fcid); + +if (((els->ct_byte &SLI4_REQ_WQE_CT ) >>SLI4_REQ_WQE_CT_SHFT ) == +SLI4_GENERIC_CONTEXT_VPI ) + els->temporary_rpi =cpu_to_le16 (rnodeindicator); + +return EFC_SUCCESS ; +} + +/* Write an FCP_ICMND64_WQE work queue entry */ +int +sli_fcp_icmnd64_wqe (struct sli4 *sli4,void *buf,size_t size, +struct efc_dma *sgl,u16 xri,u16 tag, +u16 cq_id,u32 rpi,bool hlm, +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 , size); + +if (!sgl || !sgl->virt) { +efc_log_err (sli4,"bad parameter sgl=%p virt=%p\n" , + sgl, sgl ? sgl->virt :NULL ); +return -1 ; + } + sge = sgl->virt; + bptr = &icmnd->bde; +if (sli4->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 ((BDE_TYPE_BDE_64 <<BDE_TYPE_SHIFT ) | + (le32_to_cpu (sge[0 ].buffer_length) & +SLI4_BDE_MASK_BUFFER_LEN )); + + 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 ((BDE_TYPE_BLP <<BDE_TYPE_SHIFT ) | + (sgl->size &SLI4_BDE_MASK_BUFFER_LEN )); + + 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 ; +if (hlm) { + icmnd->qosd_xbl_hlm_iod_dbde_wqes |=SLI4_ICMD_WQE_HLM ; + icmnd->remote_n_port_id_dword = +cpu_to_le32 (rnode_fcid &0x00ffffff ); + } + icmnd->cmd_type_byte |=SLI4_CMD_FCP_ICMND64_WQE ; + icmnd->cq_id =cpu_to_le16 (cq_id); + +return 0 ; +} + +/* Write an FCP_IREAD64_WQE work queue entry */ +int +sli_fcp_iread64_wqe (struct sli4 *sli4,void *buf,size_t size, +struct efc_dma *sgl,u32 first_data_sge, +u32 xfer_len,u16 xri,u16 tag, +u16 cq_id,u32 rpi,bool hlm,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 , size); + +if (!sgl || !sgl->virt) { +efc_log_err (sli4,"bad parameter sgl=%p virt=%p\n" , + sgl, sgl ? sgl->virt :NULL ); +return -1 ; + } + sge = sgl->virt; + bptr = &iread->bde; +if (sli4->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 ((BDE_TYPE_BDE_64 <<BDE_TYPE_SHIFT ) | + (le32_to_cpu (sge[0 ].buffer_length) & +SLI4_BDE_MASK_BUFFER_LEN )); + + 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 ((BDE_TYPE_BLP <<BDE_TYPE_SHIFT ) | + (sgl->size &SLI4_BDE_MASK_BUFFER_LEN )); + + 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 ; +if (hlm) { + iread->qosd_xbl_hlm_iod_dbde_wqes |=SLI4_IR_WQE_HLM ; + iread->remote_n_port_id_dword = +cpu_to_le32 (rnode_fcid &0x00ffffff ); + } + 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 (sli4->perf_hint) { + bptr = &iread->first_data_bde; + bptr->bde_type_buflen = +cpu_to_le32 ((BDE_TYPE_BDE_64 <<BDE_TYPE_SHIFT ) | + (le32_to_cpu (sge[first_data_sge].buffer_length) & +SLI4_BDE_MASK_BUFFER_LEN )); + bptr->u.data.low = + sge[first_data_sge].buffer_address_low; + bptr->u.data.high = + sge[first_data_sge].buffer_address_high; + } + +return 0 ; +} + +/* Write an FCP_IWRITE64_WQE work queue entry */ +int +sli_fcp_iwrite64_wqe (struct sli4 *sli4,void *buf,size_t size, +struct efc_dma *sgl, +u32 first_data_sge,u32 xfer_len, +u32 first_burst,u16 xri,u16 tag, +u16 cq_id,u32 rpi, +bool hlm,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 , size); + +if (!sgl || !sgl->virt) { +efc_log_err (sli4,"bad parameter sgl=%p virt=%p\n" , + sgl, sgl ? sgl->virt :NULL ); +return -1 ; + } + sge = sgl->virt; + bptr = &iwrite->bde; +if (sli4->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 ((BDE_TYPE_BDE_64 <<BDE_TYPE_SHIFT ) | + (le32_to_cpu (sge[0 ].buffer_length) & +SLI4_BDE_MASK_BUFFER_LEN )); + 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 ((BDE_TYPE_BDE_64 <<BDE_TYPE_SHIFT ) | + (sgl->size &SLI4_BDE_MASK_BUFFER_LEN )); + + 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 ; +if (hlm) { + iwrite->qosd_xbl_hlm_iod_dbde_wqes |=SLI4_IWR_WQE_HLM ; + iwrite->remote_n_port_id_dword = +cpu_to_le32 (rnode_fcid &0x00ffffff ); + } + iwrite->cmd_type_byte |=SLI4_CMD_FCP_IWRITE64_WQE ; + iwrite->cq_id =cpu_to_le16 (cq_id); + +if (sli4->perf_hint) { + bptr = &iwrite->first_data_bde; + + bptr->bde_type_buflen = +cpu_to_le32 ((BDE_TYPE_BDE_64 <<BDE_TYPE_SHIFT ) | + (le32_to_cpu (sge[first_data_sge].buffer_length) & +SLI4_BDE_MASK_BUFFER_LEN )); + + bptr->u.data.low = + sge[first_data_sge].buffer_address_low; + bptr->u.data.high = + sge[first_data_sge].buffer_address_high; + } + +return 0 ; +} + +/* Write an FCP_TRECEIVE64_WQE work queue entry */ +int +sli_fcp_treceive64_wqe (struct sli4 *sli4,void *buf,size_t size, +struct efc_dma *sgl, +u32 first_data_sge,u32 relative_off, +u32 xfer_len,u16 xri,u16 tag, +u16 cq_id,u16 xid,u32 rpi,bool hlm, +u32 rnode_fcid,u32 flags,u8 dif, +u8 bs,u8 csctl,u32 app_id) +{ +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 , size); + +if (!sgl || !sgl->virt) { +efc_log_err (sli4,"bad parameter sgl=%p virt=%p\n" , + sgl, sgl ? sgl->virt :NULL ); +return -1 ; + } + sge = sgl->virt; + bptr = &trecv->bde; +if (sli4->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 ((BDE_TYPE_BDE_64 <<BDE_TYPE_SHIFT ) | + (le32_to_cpu (sge[0 ].buffer_length) + &SLI4_BDE_MASK_BUFFER_LEN )); + + 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 && xfer_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 ((BDE_TYPE_BDE_64 <<BDE_TYPE_SHIFT ) | + (le32_to_cpu (sge[2 ].buffer_length) + &SLI4_BDE_MASK_BUFFER_LEN )); + + 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 ((BDE_TYPE_BLP <<BDE_TYPE_SHIFT ) | + (sgl->size &SLI4_BDE_MASK_BUFFER_LEN )); + 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 (relative_off); + +if (flags &SLI4_IO_CONTINUATION ) + trecv->eat_xc_ccpe |=SLI4_TRCV_WQE_XC ; + + trecv->xri_tag =cpu_to_le16 (xri); + + trecv->context_tag =cpu_to_le16 (rpi); + +/* WQE uses relative offset */ + trecv->class_ar_pu_byte |=1 <<SLI4_TRCV_WQE_PU_SHFT ; + +if (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 (xid); + + trecv->request_tag =cpu_to_le16 (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 ; + +if (hlm) { + trecv->qosd_xbl_hlm_iod_dbde_wqes |=SLI4_TRCV_WQE_HLM ; + trecv->dword5.dword =cpu_to_le32 (rnode_fcid &0x00ffffff ); + } + + 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 (xfer_len); + +if (sli4->perf_hint) { + bptr = &trecv->first_data_bde; + + bptr->bde_type_buflen = +cpu_to_le32 ((BDE_TYPE_BDE_64 <<BDE_TYPE_SHIFT ) | + (le32_to_cpu (sge[first_data_sge].buffer_length) & +SLI4_BDE_MASK_BUFFER_LEN )); + 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 (csctl &SLI4_MASK_CCP ) { + trecv->eat_xc_ccpe |=SLI4_TRCV_WQE_CCPE ; + trecv->ccp = (csctl &SLI4_MASK_CCP ); + } + +if (app_id && sli4->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 ] = app_id; + } +return 0 ; +} + +/* Write an FCP_CONT_TRECEIVE64_WQE work queue entry */ +int +sli_fcp_cont_treceive64_wqe (struct sli4 *sli4,void *buf,size_t size, +struct efc_dma *sgl,u32 first_data_sge, +u32 relative_off,u32 xfer_len, +u16 xri,u16 sec_xri,u16 tag, +u16 cq_id,u16 xid,u32 rpi, +bool hlm,u32 rnode_fcid,u32 flags, +u8 dif,u8 bs,u8 csctl, +u32 app_id) +{ +int rc; + + rc =sli_fcp_treceive64_wqe (sli4, buf, size, sgl, first_data_sge, + relative_off, xfer_len, xri, tag, cq_id, + xid, rpi, hlm, rnode_fcid, flags, dif, bs, + csctl, app_id); +if (rc ==0 ) { +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; +} + +/* Write an FCP_TRSP64_WQE work queue entry */ +int +sli_fcp_trsp64_wqe (struct sli4 *sli4,void *buf,size_t size, +struct efc_dma *sgl, +u32 rsp_len,u16 xri,u16 tag,u16 cq_id, +u16 xid,u32 rpi,bool hlm,u32 rnode_fcid, +u32 flags,u8 csctl,u8 port_owned, +u32 app_id) +{ +struct sli4_fcp_trsp64_wqe *trsp = buf; +struct sli4_fcp_128byte_wqe *trsp_128 = buf; +struct sli4_bde *bptr; + +memset (buf,0 , size); + +if (flags &SLI4_IO_AUTO_GOOD_RESPONSE ) { + trsp->class_ag_byte |=SLI4_TRSP_WQE_AG ; + }else { +struct sli4_sge *sge = sgl->virt; + +if (sli4->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 ((BDE_TYPE_BDE_64 <<BDE_TYPE_SHIFT ) | + (le32_to_cpu (sge[0 ].buffer_length) & +SLI4_BDE_MASK_BUFFER_LEN )); + 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 (rsp_len); + } + +if (flags &SLI4_IO_CONTINUATION ) + trsp->eat_xc_ccpe |=SLI4_TRSP_WQE_XC ; + +if (hlm) { + trsp->qosd_xbl_hlm_dbde_wqes |=SLI4_TRSP_WQE_HLM ; + trsp->dword5 =cpu_to_le32 (rnode_fcid &0x00ffffff ); + } + + trsp->xri_tag =cpu_to_le16 (xri); + trsp->rpi =cpu_to_le16 (rpi); + + trsp->command =SLI4_WQE_FCP_TRSP64 ; + trsp->class_ag_byte |=SLI4_GENERIC_CLASS_CLASS_3 ; + + trsp->remote_xid =cpu_to_le16 (xid); + trsp->request_tag =cpu_to_le16 (tag); +if (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 (csctl &SLI4_MASK_CCP ) { + trsp->eat_xc_ccpe |=SLI4_TRSP_WQE_CCPE ; + trsp->ccp = (csctl &SLI4_MASK_CCP ); + } + +if (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 ] = app_id; + } +return 0 ; +} + +/* Write an FCP_TSEND64_WQE work queue entry */ +int +sli_fcp_tsend64_wqe (struct sli4 *sli4,void *buf,size_t size, +struct efc_dma *sgl, +u32 first_data_sge,u32 relative_off, +u32 xfer_len,u16 xri,u16 tag, +u16 cq_id,u16 xid,u32 rpi, +bool hlm,u32 rnode_fcid,u32 flags,u8 dif, +u8 bs,u8 csctl,u32 app_id) +{ +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 , size); + +if (!sgl || !sgl->virt) { +efc_log_err (sli4,"bad parameter sgl=%p virt=%p\n" , + sgl, sgl ? sgl->virt :NULL ); +return -1 ; + } + sge = sgl->virt; + + bptr = &tsend->bde; +if (sli4->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 ((BDE_TYPE_BDE_64 <<BDE_TYPE_SHIFT ) | + (le32_to_cpu (sge[2 ].buffer_length) & +SLI4_BDE_MASK_BUFFER_LEN )); + +/* 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 && xfer_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 ((BDE_TYPE_BDE_64 <<BDE_TYPE_SHIFT ) | + (le32_to_cpu (sge[2 ].buffer_length) & +SLI4_BDE_MASK_BUFFER_LEN )); +/* +* 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 ((BDE_TYPE_BLP <<BDE_TYPE_SHIFT ) | + (sgl->size & +SLI4_BDE_MASK_BUFFER_LEN )); + 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 (relative_off); + +if (flags &SLI4_IO_CONTINUATION ) + tsend->dw10byte2 |=SLI4_TSEND_XC ; + + tsend->xri_tag =cpu_to_le16 (xri); + + tsend->rpi =cpu_to_le16 (rpi); +/* WQE uses relative offset */ + tsend->class_pu_ar_byte |=1 <<SLI4_TSEND_WQE_PU_SHFT ; + +if (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 (xid); + + tsend->request_tag =cpu_to_le16 (tag); + + tsend->ll_qd_xbl_hlm_iod_dbde |=SLI4_TSEND_LEN_LOC_BIT2 ; + +if (hlm) { + tsend->ll_qd_xbl_hlm_iod_dbde |=SLI4_TSEND_WQE_HLM ; + tsend->dword5 =cpu_to_le32 (rnode_fcid &0x00ffffff ); + } + + 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 (xfer_len); + +if (sli4->perf_hint) { + bptr = &tsend->first_data_bde; + bptr->bde_type_buflen = +cpu_to_le32 ((BDE_TYPE_BDE_64 <<BDE_TYPE_SHIFT ) | + (le32_to_cpu (sge[first_data_sge].buffer_length) & +SLI4_BDE_MASK_BUFFER_LEN )); + 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 (csctl &SLI4_MASK_CCP ) { + tsend->dw10byte2 |=SLI4_TSEND_CCPE ; + tsend->ccp = (csctl &SLI4_MASK_CCP ); + } + +if (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 ] = app_id; + } +return 0 ; +} + +/* Write a GEN_REQUEST64 work queue entry */ +int +sli_gen_request64_wqe (struct sli4 *sli4,void *buf,size_t size, +struct efc_dma *sgl,u32 req_len, +u32 max_rsp_len,u8 timeout,u16 xri, +u16 tag,u16 cq_id,bool hlm,u32 rnode_fcid, +u16 rnodeindicator,u8 r_ctl, +u8 type,u8 df_ctl) +{ +struct sli4_gen_request64_wqe *gen = buf; +struct sli4_sge *sge =NULL ; +struct sli4_bde *bptr; + +memset (buf,0 , size); + +if (!sgl || !sgl->virt) { +efc_log_err (sli4,"bad parameter sgl=%p virt=%p\n" , + sgl, sgl ? sgl->virt :NULL ); +return -1 ; + } + sge = sgl->virt; + bptr = &gen->bde; + +if (sli4->sgl_pre_registered) { + gen->dw10flags1 &= ~SLI4_GEN_REQ64_WQE_XBL ; + + gen->dw10flags1 |=SLI4_GEN_REQ64_WQE_DBDE ; + bptr->bde_type_buflen = +cpu_to_le32 ((BDE_TYPE_BDE_64 <<BDE_TYPE_SHIFT ) | + (req_len &SLI4_BDE_MASK_BUFFER_LEN )); + + 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 ((BDE_TYPE_BLP <<BDE_TYPE_SHIFT ) | + ((2 *sizeof (struct sli4_sge )) & +SLI4_BDE_MASK_BUFFER_LEN )); + + 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 (req_len); + gen->max_response_payload_length =cpu_to_le32 (max_rsp_len); + + gen->df_ctl = df_ctl; + gen->type = type; + gen->r_ctl = r_ctl; + + gen->xri_tag =cpu_to_le16 (xri); + + gen->ct_byte =SLI4_GENERIC_CONTEXT_RPI <<SLI4_GEN_REQ64_CT_SHFT ; + gen->context_tag =cpu_to_le16 (rnodeindicator); + + gen->class_byte =SLI4_GENERIC_CLASS_CLASS_3 ; + + gen->command =SLI4_WQE_GEN_REQUEST64 ; + + gen->timer = timeout; + + gen->request_tag =cpu_to_le16 (tag); + + gen->dw10flags1 |=SLI4_GEN_REQ64_WQE_IOD ; + + gen->dw10flags0 |=SLI4_GEN_REQ64_WQE_QOSD ; + +if (hlm) { + gen->dw10flags1 |=SLI4_GEN_REQ64_WQE_HLM ; + gen->remote_n_port_id_dword = +cpu_to_le32 (rnode_fcid &0x00ffffff ); + } + + gen->cmd_type_byte =SLI4_CMD_GEN_REQUEST64_WQE ; + + gen->cq_id =cpu_to_le16 (cq_id); + +return 0 ; +} + +/* Write a SEND_FRAME work queue entry */ +int +sli_send_frame_wqe (struct sli4 *sli4,void *buf,size_t size, +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 , size); + + sf->dw10flags1 |=SLI4_SF_WQE_DBDE ; + sf->bde.bde_type_buflen =cpu_to_le32 (req_len & +SLI4_BDE_MASK_BUFFER_LEN ); + 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 0 ; +} + +/* Write an XMIT_BLS_RSP64_WQE work queue entry */ +int +sli_xmit_bls_rsp64_wqe (struct sli4 *sli4,void *buf,size_t size, +struct sli_bls_payload *payload,u16 xri, +u16 tag,u16 cq_id, +bool rnodeattached,bool hlm,u16 rnodeindicator, +u16 sportindicator,u32 rnode_fcid, +u32 sport_fcid,u32 s_id) +{ +struct sli4_xmit_bls_rsp_wqe *bls = buf; +u32 dw_ridflags =0 ; + +/* +* Callers can either specify RPI or S_ID, but not both +*/ +if (rnodeattached && s_id !=U32_MAX ) { +efc_log_info (sli4,"S_ID specified for attached remote node %d\n" , + rnodeindicator); +return -1 ; + } + +memset (buf,0 , 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 (sli4,"bad BLS type %#x\n" , payload->type); +return -1 ; + } + + bls->ox_id = payload->ox_id; + bls->rx_id = payload->rx_id; + +if (rnodeattached) { + bls->dw8flags0 |= +SLI4_GENERIC_CONTEXT_RPI <<SLI4_BLS_RSP_WQE_CT_SHFT ; + bls->context_tag =cpu_to_le16 (rnodeindicator); + }else { + bls->dw8flags0 |= +SLI4_GENERIC_CONTEXT_VPI <<SLI4_BLS_RSP_WQE_CT_SHFT ; + bls->context_tag =cpu_to_le16 (sportindicator); + +if (s_id !=U32_MAX ) + bls->local_n_port_id_dword |= +cpu_to_le32 (s_id &0x00ffffff ); +else + bls->local_n_port_id_dword |= +cpu_to_le32 (sport_fcid &0x00ffffff ); + + dw_ridflags = (dw_ridflags & ~SLI4_BLS_RSP_RID ) | + (rnode_fcid &SLI4_BLS_RSP_RID ); + + bls->temporary_rpi =cpu_to_le16 (rnodeindicator); + } + + bls->xri_tag =cpu_to_le16 (xri); + + bls->dw8flags1 |=SLI4_GENERIC_CLASS_CLASS_3 ; + + bls->command =SLI4_WQE_XMIT_BLS_RSP ; + + bls->request_tag =cpu_to_le16 (tag); + + bls->dw11flags1 |=SLI4_BLS_RSP_WQE_QOSD ; + +if (hlm) { + bls->dw11flags1 |=SLI4_BLS_RSP_WQE_HLM ; + dw_ridflags = (dw_ridflags & ~SLI4_BLS_RSP_RID ) | + (rnode_fcid &SLI4_BLS_RSP_RID ); + } + + bls->remote_id_dword =cpu_to_le32 (dw_ridflags); + bls->cq_id =cpu_to_le16 (cq_id); + + bls->dw12flags0 |=SLI4_CMD_XMIT_BLS_RSP64_WQE ; + +return 0 ; +} + +/* Write a XMIT_ELS_RSP64_WQE work queue entry */ +int +sli_xmit_els_rsp64_wqe (struct sli4 *sli4,void *buf,size_t size, +struct efc_dma *rsp,u32 rsp_len, +u16 xri,u16 tag,u16 cq_id, +u16 ox_id,u16 rnodeindicator, +u16 sportindicator,bool hlm, +bool rnodeattached,u32 rnode_fcid, +u32 flags,u32 s_id) +{ +struct sli4_xmit_els_rsp64_wqe *els = buf; + +memset (buf,0 , size); + +if (sli4->sgl_pre_registered) + els->flags2 |=SLI4_ELS_DBDE ; +else + els->flags2 |=SLI4_ELS_XBL ; + + els->els_response_payload.bde_type_buflen = +cpu_to_le32 ((BDE_TYPE_BDE_64 <<BDE_TYPE_SHIFT ) | + (rsp_len &SLI4_BDE_MASK_BUFFER_LEN )); + 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 (rsp_len); + + els->xri_tag =cpu_to_le16 (xri); + + els->class_byte |=SLI4_GENERIC_CLASS_CLASS_3 ; + + els->command =SLI4_WQE_ELS_RSP64 ; + + els->request_tag =cpu_to_le16 (tag); + + els->ox_id =cpu_to_le16 (ox_id); + + els->flags2 |= (SLI4_ELS_IOD &SLI4_ELS_REQUEST64_DIR_WRITE ); + + els->flags2 |=SLI4_ELS_QOSD ; + +if (flags &SLI4_IO_CONTINUATION ) + els->flags3 |=SLI4_ELS_XC ; + +if (rnodeattached) { + els->ct_byte |= +SLI4_GENERIC_CONTEXT_RPI <<SLI4_ELS_CT_OFFSET ; + els->context_tag =cpu_to_le16 (rnodeindicator); + }else { + els->ct_byte |= +SLI4_GENERIC_CONTEXT_VPI <<SLI4_ELS_CT_OFFSET ; + els->context_tag =cpu_to_le16 (sportindicator); + els->rid_dw =cpu_to_le32 (rnode_fcid &SLI4_ELS_RID ); + els->temporary_rpi =cpu_to_le16 (rnodeindicator); +if (s_id !=U32_MAX ) { + els->sid_dw |=cpu_to_le32 (SLI4_ELS_SP | + (s_id &SLI4_ELS_SID )); + } + } + +if (hlm) { + els->flags2 |=SLI4_ELS_HLM ; + els->rid_dw =cpu_to_le32 (rnode_fcid &SLI4_ELS_RID ); + } + + els->cmd_type_wqec =SLI4_ELS_REQUEST64_CMD_GEN ; + + els->cq_id =cpu_to_le16 (cq_id); + +return 0 ; +} + +/* Write a XMIT_SEQUENCE64 work queue entry */ +int +sli_xmit_sequence64_wqe (struct sli4 *sli4,void *buf,size_t size, +struct efc_dma *payload,u32 payload_len, +u8 timeout,u16 ox_id,u16 xri, +u16 tag,bool hlm,u32 rnode_fcid, +u16 rnodeindicator,u8 r_ctl, +u8 type,u8 df_ctl) +{ +struct sli4_xmit_sequence64_wqe *xmit = buf; + +memset (buf,0 , size); + +if (!payload || !payload->virt) { +efc_log_err (sli4,"bad parameter sgl=%p virt=%p\n" , + payload, payload ? payload->virt :NULL ); +return -1 ; + } + +if (sli4->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 ((BDE_TYPE_BDE_64 <<BDE_TYPE_SHIFT ) | + (payload_len &SLI4_BDE_MASK_BUFFER_LEN )); + 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 (payload_len); + + xmit->remote_n_port_id_dword |=cpu_to_le32 (rnode_fcid &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 = df_ctl; + xmit->type = type; + xmit->r_ctl = r_ctl; + + xmit->xri_tag =cpu_to_le16 (xri); + xmit->context_tag =cpu_to_le16 (rnodeindicator); + + 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 = timeout; + + xmit->abort_tag =0 ; + xmit->request_tag =cpu_to_le16 (tag); + xmit->remote_xid =cpu_to_le16 (ox_id); + + xmit->dw10w0 |= +cpu_to_le16 (SLI4_ELS_REQUEST64_DIR_READ <<SLI4_SEQ_WQE_IOD_SHIFT ); + +if (hlm) { + xmit->dw10w0 |=cpu_to_le16 (SLI4_SEQ_WQE_HLM ); + xmit->remote_n_port_id_dword |= +cpu_to_le32 (rnode_fcid &0x00ffffff ); + } + + 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 0 ; +} + +/* Write a REQUEUE_XRI_WQE work queue entry */ +int +sli_requeue_xri_wqe (struct sli4 *sli4,void *buf,size_t size, +u16 xri,u16 tag,u16 cq_id) +{ +struct sli4_requeue_xri_wqe *requeue = buf; + +memset (buf,0 , 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 0 ; +} + +/* Process an asynchronous Link State event entry */ +int +sli_fc_process_link_state (struct sli4 *sli4,void *acqe) +{ +struct sli4_link_state *link_state = acqe; +struct sli4_link_event event = {0 }; +int rc =0 ; +u8 link_type = (link_state->link_num_type &LINK_TYPE_MASK ); + +if (!sli4->link) { +/* bail if there is no callback */ +return 0 ; + } + +if (link_type ==LINK_TYPE_ETHERNET ) { + event.topology =SLI_LINK_TOPO_NPORT ; + event.medium =SLI_LINK_MEDIUM_ETHERNET ; + }else { +efc_log_info (sli4,"unsupported link type %#x\n" , + link_type); + event.topology =SLI_LINK_TOPO_MAX ; + event.medium =SLI_LINK_MEDIUM_MAX ; + rc =-1 ; + } + +switch (link_state->port_link_status) { +case PORT_LINK_STATUS_PHYSICAL_DOWN : +case PORT_LINK_STATUS_LOGICAL_DOWN : + event.status =SLI_LINK_STATUS_DOWN ; +break ; +case PORT_LINK_STATUS_PHYSICAL_UP : +case PORT_LINK_STATUS_LOGICAL_UP : + event.status =SLI_LINK_STATUS_UP ; +break ; +default : +efc_log_info (sli4,"unsupported link status %#x\n" , + link_state->port_link_status); + event.status =SLI_LINK_STATUS_MAX ; + rc =-1 ; + } + +switch (link_state->port_speed) { +case PORT_SPEED_NO_LINK : + event.speed =0 ; +break ; +case PORT_SPEED_10_MBPS : + event.speed =10 ; +break ; +case PORT_SPEED_100_MBP : + event.speed =100 ; +break ; +case PORT_SPEED_1_GBPS : + event.speed =1000 ; +break ; +case PORT_SPEED_10_GBPS : + event.speed =10000 ; +break ; +case PORT_SPEED_20_GBPS : + event.speed =20000 ; +break ; +case PORT_SPEED_25_GBPS : + event.speed =25000 ; +break ; +case PORT_SPEED_40_GBPS : + event.speed =40000 ; +break ; +case PORT_SPEED_100_GBPS : + event.speed =100000 ; +break ; +default : +efc_log_info (sli4,"unsupported port_speed %#x\n" , + link_state->port_speed); + rc =-1 ; + } + + sli4->link (sli4->link_arg, (void *)&event); + +return rc; +} + +/* Process an asynchronous Link Attention event entry */ +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 evnttag=%#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 0 ; + + event.medium =SLI_LINK_MEDIUM_FC ; + +switch (link_attn->attn_type) { +case LINK_ATTN_TYPE_LINK_UP : + event.status =SLI_LINK_STATUS_UP ; +break ; +case LINK_ATTN_TYPE_LINK_DOWN : + event.status =SLI_LINK_STATUS_DOWN ; +break ; +case LINK_ATTN_TYPE_NO_HARD_ALPA : +efc_log_info (sli4,"attn_type: no hard alpa\n" ); + event.status =SLI_LINK_STATUS_NO_ALPA ; +break ; +default : +efc_log_info (sli4,"attn_type: unknown\n" ); +break ; + } + +switch (link_attn->event_type) { +case FC_EVENT_LINK_ATTENTION : +break ; +case FC_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 LINK_ATTN_P2P : + event.topology =SLI_LINK_TOPO_NPORT ; +break ; +case LINK_ATTN_FC_AL : + event.topology =SLI_LINK_TOPO_LOOP ; +break ; +case LINK_ATTN_INTERNAL_LOOPBACK : +efc_log_info (sli4,"topology Internal loopback\n" ); + event.topology =SLI_LINK_TOPO_LOOPBACK_INTERNAL ; +break ; +case LINK_ATTN_SERDES_LOOPBACK : +efc_log_info (sli4,"topology serdes loopback\n" ); + event.topology =SLI_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 0 ; +} + +/* Parse an FC work queue CQ entry */ +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 =-1 ; + +switch (code) { +case SLI4_CQE_CODE_WORK_REQUEST_COMPLETION : + { +struct sli4_fc_wcqe *wcqe = (void *)cqe; + + *etype =SLI_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 =SLI_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 =SLI_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 =SLI_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 =SLI_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 =SLI_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 =SLI_QENTRY_XABT ; + *r_id =le16_to_cpu (xa->xri); + rc =0 ; +break ; + } +case SLI4_CQE_CODE_RELEASE_WQE : { +struct sli4_fc_wqec *wqec = (void *)cqe; + + *etype =SLI_QENTRY_WQ_RELEASE ; + *r_id =le16_to_cpu (wqec->wq_id); + rc =0 ; +break ; + } +default : +efc_log_info (sli4,"CQE completion code %d not handled\n" , + code); + *etype =SLI_QENTRY_MAX ; + *r_id =U16_MAX ; + } + +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 -1 ; + *d_id =le32_to_cpu (wcqe->wqe_specific_2) &0x00ffffff ; +return 0 ; +} + +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; +} + +/* Retrieve the RQ index from the completion */ +int +sli_fc_rqe_rqid_and_index (struct sli4 *sli4,u8 *cqe, +u16 *rq_id,u32 *index) +{ +struct sli4_fc_async_rcqe *rcqe = (void *)cqe; +struct sli4_fc_async_rcqe_v1 *rcqe_v1 = (void *)cqe; +int rc =-1 ; +u8 code =0 ; +u16 rq_element_index; + + *rq_id =0 ; + *index =U32_MAX ; + + code = cqe[SLI4_CQE_CODE_OFFSET ]; + +if (code ==SLI4_CQE_CODE_RQ_ASYNC ) { + *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 =0 ; + }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 ) { + *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 =0 ; + }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 =0 ; + }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; +u16 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 =0 ; + }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 { + *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; +}
drivers/scsi/elx/libefc_sli/sli4.h +2 -0
@@ -12,6 +12,8 @@#ifndef _SLI4_H#define _SLI4_H +#include "scsi/fc/fc_els.h" +#include "scsi/fc/fc_fs.h" #include "../include/efc_common.h" /*************************************************************************
Signature · 1 line
2.13.7
Re: [PATCH v2 05/32] elx: libefc_sli: Populate and post different WQEs
Quoted 218 lines · James Smart
This patch continues the
libefc_sliSLI-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.
Signed-off-by Ram Vegesna <[email protected]>Signed-off-by James Smart <[email protected]>--- drivers/scsi/elx/libefc_sli/sli4.c | 1717 ++++++++++++++++++++++++++++++++++++ drivers/scsi/elx/libefc_sli/sli4.h | 2 + 2 files changed, 1719 insertions(+)drivers/scsi/elx/libefc_sli/sli4.c +197
-0@@ -1580,3 +1580,1720 @@ sli_cq_parse(struct sli4 *sli4, struct sli4_queue *cq, u8 *cqe,return rc; } + +/* Write an ABORT_WQE work queue entry */ +int +sli_abort_wqe (struct sli4 *sli4,void *buf,size_t size, +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 , size); + +switch (type) { +case SLI_ABORT_XRI : + abort->criteria =SLI4_ABORT_CRITERIA_XRI_TAG ; +if (mask) { +efc_log_warn (sli4,"%#x aborting XRI %#x warning non-zero mask" , + mask, ids); + mask =0 ; + } +break ; +case SLI_ABORT_ABORT_ID : + abort->criteria =SLI4_ABORT_CRITERIA_ABORT_TAG ; +break ; +case SLI_ABORT_REQUEST_ID : + abort->criteria =SLI4_ABORT_CRITERIA_REQUEST_TAG ; +break ; +default : +efc_log_info (sli4,"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 ; +} + +/* Write an ELS_REQUEST64_WQE work queue entry */ +int +sli_els_request64_wqe (struct sli4 *sli4,void *buf,size_t size, +struct efc_dma *sgl, +u8 req_type,u32 req_len,u32 max_rsp_len, +u8 timeout,u16 xri,u16 tag, +u16 cq_id,u16 rnodeindicator,u16 sportindicator, +bool hlm,bool rnodeattached,u32 rnode_fcid, +u32 sport_fcid) +{ +struct sli4_els_request64_wqe *els = buf; +struct sli4_sge *sge = sgl->virt; +bool is_fabric = false; +struct sli4_bde *bptr; + +memset (buf,0 , size); + + bptr = &els->els_request_payload; +if (sli4->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 ((BDE_TYPE_BDE_64 <<BDE_TYPE_SHIFT ) | + (req_len &SLI4_BDE_MASK_BUFFER_LEN )); + + 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 ((BDE_TYPE_BLP <<BDE_TYPE_SHIFT ) | + ((2 *sizeof (struct sli4_sge )) & +SLI4_BDE_MASK_BUFFER_LEN )); + 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 (req_len); + els->max_response_payload_length =cpu_to_le32 (max_rsp_len); + + els->xri_tag =cpu_to_le16 (xri); + els->timer = timeout; + els->class_byte |=SLI4_GENERIC_CLASS_CLASS_3 ; + + els->command =SLI4_WQE_ELS_REQUEST64 ; + + els->request_tag =cpu_to_le16 (tag); + +if (hlm) { + els->qosd_xbl_hlm_iod_dbde_wqes |=SLI4_REQ_WQE_HLM ; + els->remote_id_dword =cpu_to_le32 (rnode_fcid &0x00ffffff ); + } + + 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 (req_type) { +case ELS_LOGO : + els->cmdtype_elsid_byte |= +SLI4_ELS_REQUEST64_LOGO <<SLI4_REQ_WQE_ELSID_SHFT ; +if (rnodeattached) { + els->ct_byte |= (SLI4_GENERIC_CONTEXT_RPI << +SLI4_REQ_WQE_CT_SHFT ); + els->context_tag =cpu_to_le16 (rnodeindicator); + }else { + els->ct_byte |= +SLI4_GENERIC_CONTEXT_VPI <<SLI4_REQ_WQE_CT_SHFT ; + els->context_tag = +cpu_to_le16 (sportindicator); + } +if (rnode_fcid ==FC_FID_FLOGI ) + is_fabric = true; +break ; +case ELS_FDISC : +if (rnode_fcid ==FC_FID_FLOGI ) + is_fabric = true; +if (sport_fcid ==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 (sportindicator); + 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 (sportindicator); +/* +* 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 (sport_fcid !=U32_MAX ) + els->sid_sp_dword |=cpu_to_le32 (sport_fcid); +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 (sportindicator); +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 (sportindicator); +break ; +default : + els->cmdtype_elsid_byte |= +SLI4_ELS_REQUEST64_OTHER <<SLI4_REQ_WQE_ELSID_SHFT ; +if (rnodeattached) { + els->ct_byte |= (SLI4_GENERIC_CONTEXT_RPI << +SLI4_REQ_WQE_CT_SHFT ); + els->context_tag =cpu_to_le16 (sportindicator); + }else { + els->ct_byte |= +SLI4_GENERIC_CONTEXT_VPI <<SLI4_REQ_WQE_CT_SHFT ; + els->context_tag = +cpu_to_le16 (sportindicator); + } +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 (cq_id); + + if (((els->ct_byte & SLI4_REQ_WQE_CT) >> SLI4_REQ_WQE_CT_SHFT) !=
drivers/scsi/elx/libefc_sli/sli4.c sli_cq_parse(struct sli4 *sli4, struct sli4_queue *cq, u8 *cqe, · line 1789
Quoted 10 lines
drivers/scsi/elx/libefc_sli/sli4.c +10
-0+ SLI4_GENERIC_CONTEXT_RPI) + els->remote_id_dword = cpu_to_le32(rnode_fcid); + +if (((els->ct_byte &SLI4_REQ_WQE_CT ) >>SLI4_REQ_WQE_CT_SHFT ) == +SLI4_GENERIC_CONTEXT_VPI ) + els->temporary_rpi =cpu_to_le16 (rnodeindicator); + +return EFC_SUCCESS ; +} +
You seem to have given up using EFC_SUCCESS / EFC_FAIL for the next few functions.
Please be consistent here.
Cheers,
Hannes
Signature · 4 lines
Dr. Hannes Reinecke Teamlead Storage & Networking [email protected] +49 911 74053 688 SUSE Software Solutions Germany GmbH, Maxfeldstr. 5, 90409 Nürnberg HRB 36809 (AG Nürnberg), GF: Felix Imendörffer
Re: [PATCH v2 05/32] elx: libefc_sli: Populate and post different WQEs
Quoted 8 lines · Hannes Reinecke
You seem to have given up using
EFC_SUCCESS/EFC_FAILfor the next few functions.
Please be consistent here.Cheers,
Hannes
We will covert over to EFC_xxx status's
Thanks
-- james
PATCH v2 6/32 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 | 1229 +++++++++++++++++++++++++++++++++++- drivers/scsi/elx/libefc_sli/sli4.h | 2 + 2 files changed, 1230 insertions(+), 1 deletion(-)
drivers/scsi/elx/libefc_sli/sli4.c +1228 -1
@@ -942,7 +942,6 @@ static int sli_cmd_cq_set_create(struct sli4 *sli4,u16 dw6w1_flags =0 ;__le32 req_len; - n_cqe = qs[0 ]->dma.size /SLI4_CQE_BYTES ;switch (n_cqe) {case 256 :
@@ -3297,3 +3296,1231 @@ sli_fc_rqe_rqid_and_index(struct sli4 *sli4, u8 *cqe,return rc; } + +/* Wait for the bootstrap mailbox to report "ready" */ +static int +sli_bmbx_wait (struct sli4 *sli4,u32 msec) +{ +u32 val =0 ; + +do { +mdelay (1 );/* 1 ms */ + val =readl (sli4->reg[0 ] +SLI4_BMBX_REG ); + msec--; + }while (msec && !(val &SLI4_BMBX_RDY )); + + val = (!(val &SLI4_BMBX_RDY )); +return val; +} + +/* Write bootstrap mailbox */ +static int +sli_bmbx_write (struct sli4 *sli4) +{ +u32 val =0 ; + +/* write buffer location to bootstrap mailbox register */ + val =SLI4_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 -1 ; + } + val =SLI4_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 ); +} + +/* Submit a command to the bootstrap mailbox and check the status */ +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 -1 ; + } + +if (sli_bmbx_write (sli4)) { +efc_log_crit (sli4,"bootstrap mailbox write fail phys=%p reg=%#x\n" , + (void *)sli4->bmbx.phys, +readl (sli4->reg[0 ] +SLI4_BMBX_REG )); +return -1 ; + } + +/* 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 -1 ; +} + +/* Write a CONFIG_LINK command to the provided buffer */ +int +sli_cmd_config_link (struct sli4 *sli4,void *buf,size_t size) +{ +struct sli4_cmd_config_link *config_link = buf; + +memset (buf,0 , size); + + config_link->hdr.command =MBX_CMD_CONFIG_LINK ; + +/* Port interprets zero in a field as "use default value" */ + +return EFC_SUCCESS ; +} + +/* Write a DOWN_LINK command to the provided buffer */ +int +sli_cmd_down_link (struct sli4 *sli4,void *buf,size_t size) +{ +struct sli4_mbox_command_header *hdr = buf; + +memset (buf,0 , size); + + hdr->command =MBX_CMD_DOWN_LINK ; + +/* Port interprets zero in a field as "use default value" */ + +return EFC_SUCCESS ; +} + +/* Write a DUMP Type 4 command to the provided buffer */ +int +sli_cmd_dump_type4 (struct sli4 *sli4,void *buf, +size_t size,u16 wki) +{ +struct sli4_cmd_dump4 *cmd = buf; + +memset (buf,0 , size); + + cmd->hdr.command =MBX_CMD_DUMP ; + cmd->type_dword =cpu_to_le32 (0x4 ); + cmd->wki_selection =cpu_to_le16 (wki); +return EFC_SUCCESS ; +} + +/* Write a COMMON_READ_TRANSCEIVER_DATA command */ +int +sli_cmd_common_read_transceiver_data (struct sli4 *sli4,void *buf, +size_t size,u32 page_num, +struct efc_dma *dma) +{ +struct sli4_rqst_cmn_read_transceiver_data *req =NULL ; +u32 psize; + +if (!dma) + psize =SLI_CONFIG_PYLD_LENGTH (cmn_read_transceiver_data); +else + psize = dma->size; + + req =sli_config_cmd_init (sli4, buf, size, + psize, dma); +if (!req) +return EFC_FAIL ; + +sli_cmd_fill_hdr (&req->hdr,CMN_READ_TRANS_DATA ,SLI4_SUBSYSTEM_COMMON , +CMD_V0 ,CFG_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 ; +} + +/* Write a READ_LINK_STAT command to the provided buffer */ +int +sli_cmd_read_link_stats (struct sli4 *sli4,void *buf,size_t size, +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 , size); + + cmd->hdr.command =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 ; +} + +/* Write a READ_STATUS command to the provided buffer */ +int +sli_cmd_read_status (struct sli4 *sli4,void *buf,size_t size, +u8 clear_counters) +{ +struct sli4_cmd_read_status *cmd = buf; +u32 flags =0 ; + +memset (buf,0 , size); + + cmd->hdr.command =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 ; +} + +/* Write an INIT_LINK command to the provided buffer */ +int +sli_cmd_init_link (struct sli4 *sli4,void *buf,size_t size, +u32 speed,u8 reset_alpa) +{ +struct sli4_cmd_init_link *init_link = buf; +u32 flags =0 ; + +memset (buf,0 , size); + + init_link->hdr.command =MBX_CMD_INIT_LINK ; + + init_link->sel_reset_al_pa_dword = +cpu_to_le32 (reset_alpa); + flags &= ~SLI4_INIT_LINK_FLAG_LOOPBACK ; + + init_link->link_speed_sel_code =cpu_to_le32 (speed); +switch (speed) { +case FC_LINK_SPEED_1G : +case FC_LINK_SPEED_2G : +case FC_LINK_SPEED_4G : +case FC_LINK_SPEED_8G : +case FC_LINK_SPEED_16G : +case FC_LINK_SPEED_32G : + flags |=SLI4_INIT_LINK_FLAG_FIXED_SPEED ; +break ; +case FC_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_FLAG_EN_TOPO_FAILOVER ; + + flags &= ~SLI4_INIT_LINK_FLAG_TOPOLOGY ; + flags |= (SLI4_INIT_LINK_F_P2P_FAIL_OVER <<1 ); +break ; +case SLI4_READ_CFG_TOPO_FC_AL : + flags &= ~SLI4_INIT_LINK_FLAG_TOPOLOGY ; + flags |= (SLI4_INIT_LINK_F_FCAL_ONLY <<1 ); +if (speed ==FC_LINK_SPEED_16G || + speed ==FC_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_FC_DA : + flags &= ~SLI4_INIT_LINK_FLAG_TOPOLOGY ; + flags |= (FC_TOPOLOGY_P2P <<1 ); +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_FLAG_UNFAIR ); + flags &= (~SLI4_INIT_LINK_FLAG_SKIP_LIRP_LILP ); + flags &= (~SLI4_INIT_LINK_FLAG_LOOP_VALIDITY ); + flags &= (~SLI4_INIT_LINK_FLAG_SKIP_LISA ); + flags &= (~SLI4_INIT_LINK_FLAG_SEL_HIGHTEST_AL_PA ); + init_link->flags0 =cpu_to_le32 (flags); + +return EFC_SUCCESS ; +} + +/* Write an INIT_VFI command to the provided buffer */ +int +sli_cmd_init_vfi (struct sli4 *sli4,void *buf,size_t size, +u16 vfi,u16 fcfi,u16 vpi) +{ +struct sli4_cmd_init_vfi *init_vfi = buf; +u16 flags =0 ; + +memset (buf,0 , size); + + init_vfi->hdr.command =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 ; +} + +/* Write an INIT_VPI command to the provided buffer */ +int +sli_cmd_init_vpi (struct sli4 *sli4,void *buf,size_t size, +u16 vpi,u16 vfi) +{ +struct sli4_cmd_init_vpi *init_vpi = buf; + +memset (buf,0 , size); + + init_vpi->hdr.command =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,size_t size, +u16 xri_base,u16 xri_count) +{ +struct sli4_cmd_post_xri *post_xri = buf; +u16 xri_count_flags =0 ; + +memset (buf,0 , size); + + post_xri->hdr.command =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,size_t size, +u8 num_xri) +{ +struct sli4_cmd_release_xri *release_xri = buf; + +memset (buf,0 , size); + + release_xri->hdr.command =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,size_t size) +{ +struct sli4_cmd_read_config *read_config = buf; + +memset (buf,0 , size); + + read_config->hdr.command =MBX_CMD_READ_CONFIG ; + +return EFC_SUCCESS ; +} + +int +sli_cmd_read_nvparms (struct sli4 *sli4,void *buf,size_t size) +{ +struct sli4_cmd_read_nvparms *read_nvparms = buf; + +memset (buf,0 , size); + + read_nvparms->hdr.command =MBX_CMD_READ_NVPARMS ; + +return EFC_SUCCESS ; +} + +int +sli_cmd_write_nvparms (struct sli4 *sli4,void *buf,size_t size, +u8 *wwpn,u8 *wwnn,u8 hard_alpa, +u32 preferred_d_id) +{ +struct sli4_cmd_write_nvparms *write_nvparms = buf; + +memset (buf,0 , size); + + write_nvparms->hdr.command =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,size_t size, +struct efc_dma *vpd) +{ +struct sli4_cmd_read_rev *read_rev = buf; + +memset (buf,0 , size); + + read_rev->hdr.command =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,size_t size, +struct efc_dma *dma, +u16 vpi) +{ +struct sli4_cmd_read_sparm64 *read_sparm64 = buf; + +memset (buf,0 , size); + +if (vpi ==SLI4_READ_SPARM64_VPI_SPECIAL ) { +efc_log_info (sli4,"special VPI not supported!!!\n" ); +return -1 ; + } + +if (!dma || !dma->phys) { +efc_log_info (sli4,"bad DMA buffer\n" ); +return -1 ; + } + + read_sparm64->hdr.command =MBX_CMD_READ_SPARM64 ; + + read_sparm64->bde_64.bde_type_buflen = +cpu_to_le32 ((BDE_TYPE_BDE_64 <<BDE_TYPE_SHIFT ) | + (dma->size &SLI4_BDE_MASK_BUFFER_LEN )); + 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,size_t size, +struct efc_dma *dma) +{ +struct sli4_cmd_read_topology *read_topo = buf; + +memset (buf,0 , size); + + read_topo->hdr.command =MBX_CMD_READ_TOPOLOGY ; + +if (dma && dma->size) { +if (dma->size <SLI4_MIN_LOOP_MAP_BYTES ) { +efc_log_info (sli4,"loop map buffer too small %jd\n" , + dma->size); +return 0 ; + } + +memset (dma->virt,0 , dma->size); + + read_topo->bde_loop_map.bde_type_buflen = +cpu_to_le32 ((BDE_TYPE_BDE_64 <<BDE_TYPE_SHIFT ) | + (dma->size &SLI4_BDE_MASK_BUFFER_LEN )); + 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,size_t size, +u16 index, +struct sli4_cmd_rq_cfg rq_cfg[SLI4_CMD_REG_FCFI_NUM_RQ_CFG ]) +{ +struct sli4_cmd_reg_fcfi *reg_fcfi = buf; +u32 i; + +memset (buf,0 , size); + + reg_fcfi->hdr.command =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,size_t size, +u8 mode,u16 fcf_index, +u8 rq_selection_policy,u8 mrq_bit_mask, +u16 num_mrqs, +struct sli4_cmd_rq_cfg rq_cfg[SLI4_CMD_REG_FCFI_NUM_RQ_CFG ]) +{ +struct sli4_cmd_reg_fcfi_mrq *reg_fcfi_mrq = buf; +u32 i; +u32 mrq_flags =0 ; + +memset (buf,0 , size); + + reg_fcfi_mrq->hdr.command =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; + } + +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,size_t size, +u32 nport_id,u16 rpi,u16 vpi, +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 , size); + + reg_rpi->hdr.command =MBX_CMD_REG_RPI ; + + reg_rpi->rpi =cpu_to_le16 (rpi); + + rportid_flags = nport_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 ((BDE_TYPE_BDE_64 <<BDE_TYPE_SHIFT ) | + (SLI4_REG_RPI_BUF_LEN &SLI4_BDE_MASK_BUFFER_LEN )); + 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; + +if (!sli4 || !buf) +return 0 ; + +memset (buf,0 , size); + + reg_vfi->hdr.command =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 ((BDE_TYPE_BDE_64 <<BDE_TYPE_SHIFT ) | + (SLI4_REG_RPI_BUF_LEN &SLI4_BDE_MASK_BUFFER_LEN )); + 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,size_t size, +u32 fc_id,__be64 sli_wwpn,u16 vpi,u16 vfi, +bool update) +{ +struct sli4_cmd_reg_vpi *reg_vpi = buf; +u32 flags =0 ; + +if (!sli4 || !buf) +return 0 ; + +memset (buf,0 , size); + + reg_vpi->hdr.command =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,size_t size, +u32 features_mask,bool query) +{ +struct sli4_cmd_request_features *req_features = buf; + +memset (buf,0 , size); + + req_features->hdr.command =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,size_t size, +u16 indicator) +{ +struct sli4_cmd_unreg_fcfi *unreg_fcfi = buf; + +if (!sli4 || !buf) +return 0 ; + +memset (buf,0 , size); + + unreg_fcfi->hdr.command =MBX_CMD_UNREG_FCFI ; + + unreg_fcfi->fcfi =cpu_to_le16 (indicator); + +return EFC_SUCCESS ; +} + +int +sli_cmd_unreg_rpi (struct sli4 *sli4,void *buf,size_t size, +u16 indicator, +enum sli4_resource which,u32 fc_id) +{ +struct sli4_cmd_unreg_rpi *unreg_rpi = buf; +u32 flags =0 ; + +memset (buf,0 , size); + + unreg_rpi->hdr.command =MBX_CMD_UNREG_RPI ; + +switch (which) { +case SLI_RSRC_RPI : + flags |=UNREG_RPI_II_RPI ; +if (fc_id ==U32_MAX ) +break ; + + flags |=UNREG_RPI_DP ; + unreg_rpi->dw2_dest_n_portid = +cpu_to_le32 (fc_id &UNREG_RPI_DEST_N_PORTID_MASK ); +break ; +case SLI_RSRC_VPI : + flags |=UNREG_RPI_II_VPI ; +break ; +case SLI_RSRC_VFI : + flags |=UNREG_RPI_II_VFI ; +break ; +case SLI_RSRC_FCFI : + flags |=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,size_t size, +u16 index,u32 which) +{ +struct sli4_cmd_unreg_vfi *unreg_vfi = buf; + +memset (buf,0 , size); + + unreg_vfi->hdr.command =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 0 ; + } + +if (which !=SLI4_UNREG_TYPE_DOMAIN ) + unreg_vfi->dw2_flags = +cpu_to_le16 (UNREG_VFI_II_FCFI ); + +return EFC_SUCCESS ; +} + +int +sli_cmd_unreg_vpi (struct sli4 *sli4,void *buf,size_t size, +u16 indicator,u32 which) +{ +struct sli4_cmd_unreg_vpi *unreg_vpi = buf; +u32 flags =0 ; + +memset (buf,0 , size); + + unreg_vpi->hdr.command =MBX_CMD_UNREG_VPI ; + unreg_vpi->index =cpu_to_le16 (indicator); +switch (which) { +case SLI4_UNREG_TYPE_PORT : + flags |=UNREG_VPI_II_VPI ; +break ; +case SLI4_UNREG_TYPE_DOMAIN : + flags |=UNREG_VPI_II_VFI ; +break ; +case SLI4_UNREG_TYPE_FCF : + flags |=UNREG_VPI_II_FCFI ; +break ; +case SLI4_UNREG_TYPE_ALL : +/* override indicator */ + unreg_vpi->index =cpu_to_le16 (U32_MAX ); + flags |=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,size_t size, +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, size, +SLI_CONFIG_PYLD_LENGTH (cmn_modify_eq_delay), +NULL ); +if (!req) +return EFC_FAIL ; + +sli_cmd_fill_hdr (&req->hdr,CMN_MODIFY_EQ_DELAY ,SLI4_SUBSYSTEM_COMMON , +CMD_V0 ,CFG_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, size, +SLI_CONFIG_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 , +CFG_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,size_t size, +struct efc_dma *dma) +{ +struct sli4_rqst_hdr *hdr =NULL ; + + hdr =sli_config_cmd_init (sli4, buf, size,CFG_RQST_CMDSZ (hdr), dma); +if (!hdr) +return EFC_FAIL ; + + hdr->opcode =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, +size_t size,struct efc_dma *dma) +{ +struct sli4_rqst_hdr *hdr =NULL ; + + hdr =sli_config_cmd_init (sli4, buf, size,CFG_RQST_CMDSZ (hdr), dma); +if (!hdr) +return EFC_FAIL ; + + hdr->opcode =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, +size_t size,uint64_t context) +{ +struct sli4_rqst_cmn_nop *nop =NULL ; + + nop =sli_config_cmd_init (sli4, buf, size, +SLI_CONFIG_PYLD_LENGTH (cmn_nop),NULL ); +if (!nop) +return EFC_FAIL ; + +sli_cmd_fill_hdr (&nop->hdr,CMN_NOP ,SLI4_SUBSYSTEM_COMMON , +CMD_V0 ,CFG_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, +size_t size,u16 rtype) +{ +struct sli4_rqst_cmn_get_resource_extent_info *extent =NULL ; + + extent =sli_config_cmd_init (sli4, buf, size, +CFG_RQST_CMDSZ (cmn_get_resource_extent_info), +NULL ); +if (extent) +return EFC_FAIL ; + +sli_cmd_fill_hdr (&extent->hdr,CMN_GET_RSC_EXTENT_INFO , +SLI4_SUBSYSTEM_COMMON ,CMD_V0 , +CFG_RQST_PYLD_LEN (cmn_get_resource_extent_info)); + + extent->resource_type =cpu_to_le16 (rtype); + +return EFC_SUCCESS ; +} + +int +sli_cmd_common_get_sli4_parameters (struct sli4 *sli4,void *buf, +size_t size) +{ +struct sli4_rqst_hdr *hdr =NULL ; + + hdr =sli_config_cmd_init (sli4, buf, size, +SLI_CONFIG_PYLD_LENGTH (cmn_get_sli4_params), +NULL ); +if (!hdr) +return EFC_FAIL ; + + hdr->opcode =CMN_GET_SLI4_PARAMS ; + hdr->subsystem =SLI4_SUBSYSTEM_COMMON ; + hdr->request_length =CFG_RQST_PYLD_LEN (cmn_get_sli4_params); + +return EFC_SUCCESS ; +} + +static int +sli_cmd_common_get_port_name (struct sli4 *sli4,void *buf,size_t size) +{ +struct sli4_rqst_cmn_get_port_name *pname; + + pname =sli_config_cmd_init (sli4, buf, size, +SLI_CONFIG_PYLD_LENGTH (cmn_get_port_name), +NULL ); +if (!pname) +return EFC_FAIL ; + +sli_cmd_fill_hdr (&pname->hdr,CMN_GET_PORT_NAME ,SLI4_SUBSYSTEM_COMMON , +CMD_V1 ,CFG_RQST_PYLD_LEN (cmn_get_port_name)); + +/* Set the port type value (ethernet=0, FC=1) for V1 commands */ + pname->port_type =PORT_TYPE_FC ; + +return EFC_SUCCESS ; +} + +int +sli_cmd_common_write_object (struct sli4 *sli4,void *buf,size_t size, +u16 noc, +u16 eof,u32 desired_write_length, +u32 offset,char *object_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, size, +CFG_RQST_CMDSZ (cmn_write_object) + +sizeof (*bde),NULL ); +if (!wr_obj) +return EFC_FAIL ; + +sli_cmd_fill_hdr (&wr_obj->hdr,CMN_WRITE_OBJECT ,SLI4_SUBSYSTEM_COMMON , +CMD_V0 , +CFG_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, object_name, +sizeof (wr_obj->object_name)); + 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 ((BDE_TYPE_BDE_64 <<BDE_TYPE_SHIFT ) | + (desired_write_length &SLI4_BDE_MASK_BUFFER_LEN )); + 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,size_t size, +char *object_name) +{ +struct sli4_rqst_cmn_delete_object *req =NULL ; + + req =sli_config_cmd_init (sli4, buf, size, +CFG_RQST_CMDSZ (cmn_delete_object),NULL ); +if (!req) +return EFC_FAIL ; + +sli_cmd_fill_hdr (&req->hdr,CMN_DELETE_OBJECT ,SLI4_SUBSYSTEM_COMMON , +CMD_V0 ,CFG_RQST_PYLD_LEN (cmn_delete_object)); + +strncpy (req->object_name, object_name,sizeof (req->object_name)); +return EFC_SUCCESS ; +} + +int +sli_cmd_common_read_object (struct sli4 *sli4,void *buf,size_t size, +u32 desired_read_length,u32 offset, +char *object_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, size, +CFG_RQST_CMDSZ (cmn_read_object) + +sizeof (*bde),NULL ); +if (!rd_obj) +return EFC_FAIL ; + +sli_cmd_fill_hdr (&rd_obj->hdr,CMN_READ_OBJECT ,SLI4_SUBSYSTEM_COMMON , +CMD_V0 , +CFG_RQST_PYLD_LEN_VAR (cmn_read_object,sizeof (*bde))); + rd_obj->desired_read_length_dword = +cpu_to_le32 (desired_read_length &SLI4_REQ_DESIRE_READLEN ); + + rd_obj->read_offset =cpu_to_le32 (offset); +strncpy (rd_obj->object_name, object_name, +sizeof (rd_obj->object_name)); + 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 ((BDE_TYPE_BDE_64 <<BDE_TYPE_SHIFT ) | + (desired_read_length &SLI4_BDE_MASK_BUFFER_LEN )); +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,size_t size, +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, size, +CFG_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 ,CFG_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, +size_t size,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, size, +CFG_RQST_CMDSZ (cmn_set_dump_location), +NULL ); +if (!set_dump_loc) +return EFC_FAIL ; + +sli_cmd_fill_hdr (&set_dump_loc->hdr,CMN_SET_DUMP_LOCATION , +SLI4_SUBSYSTEM_COMMON ,CMD_V0 , +CFG_RQST_PYLD_LEN (cmn_set_dump_location)); + +if (is_buffer_list) + buffer_length_flag |=SLI4_RQ_COM_SET_DUMP_BLP ; + +if (query) + buffer_length_flag |=SLI4_RQ_COM_SET_DUMP_QRY ; + +if (fdb) + buffer_length_flag |=SLI4_RQ_COM_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_RQ_COM_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,size_t size, +u32 feature, +u32 param_len, +void *parameter) +{ +struct sli4_rqst_cmn_set_features *cmd =NULL ; + + cmd =sli_config_cmd_init (sli4, buf, size, +CFG_RQST_CMDSZ (cmn_set_features),NULL ); +if (!cmd) +return EFC_FAIL ; + +sli_cmd_fill_hdr (&cmd->hdr,CMN_SET_FEATURES ,SLI4_SUBSYSTEM_COMMON , +CMD_V0 ,CFG_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 -2 ; + +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 =-1 ; + +if (!buf) { +efc_log_err (sli4,"bad parameter sli4=%p buf=%p\n" , sli4, buf); +return -1 ; + } + +switch (acqe->event_code) { +case SLI4_ACQE_EVENT_CODE_LINK_STATE : + rc =sli_fc_process_link_state (sli4, buf); +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; +}
drivers/scsi/elx/libefc_sli/sli4.h +2 -0
@@ -12,6 +12,8 @@#ifndef _SLI4_H#define _SLI4_H +#include <linux/pci.h> +#include <linux/delay.h> #include "scsi/fc/fc_els.h" #include "scsi/fc/fc_fs.h" #include "../include/efc_common.h"
Signature · 1 line
2.13.7
Re: [PATCH v2 06/32] elx: libefc_sli: bmbx routines and SLI config commands
Quoted 50 lines · James Smart
This patch continues the
libefc_sliSLI-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.
Signed-off-by Ram Vegesna <[email protected]>Signed-off-by James Smart <[email protected]>--- drivers/scsi/elx/libefc_sli/sli4.c | 1229 +++++++++++++++++++++++++++++++++++- drivers/scsi/elx/libefc_sli/sli4.h | 2 + 2 files changed, 1230 insertions(+), 1 deletion(-)drivers/scsi/elx/libefc_sli/sli4.c +21
-1@@ -942,7 +942,6 @@ static int sli_cmd_cq_set_create(struct sli4 *sli4,u16 dw6w1_flags =0 ;__le32 req_len; - n_cqe = qs[0 ]->dma.size /SLI4_CQE_BYTES ;switch (n_cqe) {case 256 :@@ -3297,3 +3296,1231 @@ sli_fc_rqe_rqid_and_index(struct sli4 *sli4, u8 *cqe,return rc; } + +/* Wait for the bootstrap mailbox to report "ready" */ +static int +sli_bmbx_wait (struct sli4 *sli4,u32 msec) +{ +u32 val =0 ; + +do { +mdelay (1 );/* 1 ms */ + val =readl (sli4->reg[0 ] +SLI4_BMBX_REG ); + msec--; + }while (msec && !(val &SLI4_BMBX_RDY )); + + val = (!(val &SLI4_BMBX_RDY )); +return val; +} + +/* Write bootstrap mailbox */ +static int +sli_bmbx_write (struct sli4 *sli4) +{
drivers/scsi/elx/libefc_sli/sli4.c sli_fc_rqe_rqid_and_index(struct sli4 *sli4, u8 *cqe, · line 3329
Quoted 10 lines
drivers/scsi/elx/libefc_sli/sli4.c +10
-0+u32 val =0 ; + +/* write buffer location to bootstrap mailbox register */ + val =SLI4_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 -1 ; + }
EFC_FAIL?
Quoted 12 lines
drivers/scsi/elx/libefc_sli/sli4.c +12
-0+ val =SLI4_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 ); +} + +/* Submit a command to the bootstrap mailbox and check the status */ +int +sli_bmbx_command (struct sli4 *sli4) +{ +void *cqe = (u8 *)sli4->bmbx.virt +SLI4_BMBX_SIZE ;
drivers/scsi/elx/libefc_sli/sli4.c sli_fc_rqe_rqid_and_index(struct sli4 *sli4, u8 *cqe, · line 3351
Quoted 10 lines
drivers/scsi/elx/libefc_sli/sli4.c +10
-0+ +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 -1 ; + } +
Same here.
drivers/scsi/elx/libefc_sli/sli4.c sli_fc_rqe_rqid_and_index(struct sli4 *sli4, u8 *cqe, · line 3358
Quoted 7 lines
drivers/scsi/elx/libefc_sli/sli4.c +7
-0+if (sli_bmbx_write (sli4)) { +efc_log_crit (sli4,"bootstrap mailbox write fail phys=%p reg=%#x\n" , + (void *)sli4->bmbx.phys, +readl (sli4->reg[0 ] +SLI4_BMBX_REG )); +return -1 ; + } +
And here.
Quoted 144 lines
drivers/scsi/elx/libefc_sli/sli4.c +144
-0+/* 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 -1 ; +} + +/* Write a CONFIG_LINK command to the provided buffer */ +int +sli_cmd_config_link (struct sli4 *sli4,void *buf,size_t size) +{ +struct sli4_cmd_config_link *config_link = buf; + +memset (buf,0 , size); + + config_link->hdr.command =MBX_CMD_CONFIG_LINK ; + +/* Port interprets zero in a field as "use default value" */ + +return EFC_SUCCESS ; +} + +/* Write a DOWN_LINK command to the provided buffer */ +int +sli_cmd_down_link (struct sli4 *sli4,void *buf,size_t size) +{ +struct sli4_mbox_command_header *hdr = buf; + +memset (buf,0 , size); + + hdr->command =MBX_CMD_DOWN_LINK ; + +/* Port interprets zero in a field as "use default value" */ + +return EFC_SUCCESS ; +} + +/* Write a DUMP Type 4 command to the provided buffer */ +int +sli_cmd_dump_type4 (struct sli4 *sli4,void *buf, +size_t size,u16 wki) +{ +struct sli4_cmd_dump4 *cmd = buf; + +memset (buf,0 , size); + + cmd->hdr.command =MBX_CMD_DUMP ; + cmd->type_dword =cpu_to_le32 (0x4 ); + cmd->wki_selection =cpu_to_le16 (wki); +return EFC_SUCCESS ; +} + +/* Write a COMMON_READ_TRANSCEIVER_DATA command */ +int +sli_cmd_common_read_transceiver_data (struct sli4 *sli4,void *buf, +size_t size,u32 page_num, +struct efc_dma *dma) +{ +struct sli4_rqst_cmn_read_transceiver_data *req =NULL ; +u32 psize; + +if (!dma) + psize =SLI_CONFIG_PYLD_LENGTH (cmn_read_transceiver_data); +else + psize = dma->size; + + req =sli_config_cmd_init (sli4, buf, size, + psize, dma); +if (!req) +return EFC_FAIL ; + +sli_cmd_fill_hdr (&req->hdr,CMN_READ_TRANS_DATA ,SLI4_SUBSYSTEM_COMMON , +CMD_V0 ,CFG_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 ; +} + +/* Write a READ_LINK_STAT command to the provided buffer */ +int +sli_cmd_read_link_stats (struct sli4 *sli4,void *buf,size_t size, +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 , size); + + cmd->hdr.command =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 ; +} + +/* Write a READ_STATUS command to the provided buffer */ +int +sli_cmd_read_status (struct sli4 *sli4,void *buf,size_t size, +u8 clear_counters) +{ +struct sli4_cmd_read_status *cmd = buf; +u32 flags =0 ; + +memset (buf,0 , size); + + cmd->hdr.command =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 ; +} + +/* Write an INIT_LINK command to the provided buffer */ +int +sli_cmd_init_link (struct sli4 *sli4,void *buf,size_t size, +u32 speed,u8 reset_alpa) +{ +struct sli4_cmd_init_link *init_link = buf; +u32 flags =0 ; + +memset (buf,0 , size); + + init_link->hdr.command =MBX_CMD_INIT_LINK ; + + init_link->sel_reset_al_pa_dword = +cpu_to_le32 (reset_alpa); + flags &= ~SLI4_INIT_LINK_FLAG_LOOPBACK ; +
drivers/scsi/elx/libefc_sli/sli4.c sli_fc_rqe_rqid_and_index(struct sli4 *sli4, u8 *cqe, · line 3512
Quoted 10 lines
drivers/scsi/elx/libefc_sli/sli4.c +10
-0+ init_link->link_speed_sel_code =cpu_to_le32 (speed); +switch (speed) { +case FC_LINK_SPEED_1G : +case FC_LINK_SPEED_2G : +case FC_LINK_SPEED_4G : +case FC_LINK_SPEED_8G : +case FC_LINK_SPEED_16G : +case FC_LINK_SPEED_32G : + flags |=SLI4_INIT_LINK_FLAG_FIXED_SPEED ; +break ;
I was under the impression that 64G FC is already underway, is it not?
Quoted 197 lines
drivers/scsi/elx/libefc_sli/sli4.c +197
-0+case FC_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_FLAG_EN_TOPO_FAILOVER ; + + flags &= ~SLI4_INIT_LINK_FLAG_TOPOLOGY ; + flags |= (SLI4_INIT_LINK_F_P2P_FAIL_OVER <<1 ); +break ; +case SLI4_READ_CFG_TOPO_FC_AL : + flags &= ~SLI4_INIT_LINK_FLAG_TOPOLOGY ; + flags |= (SLI4_INIT_LINK_F_FCAL_ONLY <<1 ); +if (speed ==FC_LINK_SPEED_16G || + speed ==FC_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_FC_DA : + flags &= ~SLI4_INIT_LINK_FLAG_TOPOLOGY ; + flags |= (FC_TOPOLOGY_P2P <<1 ); +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_FLAG_UNFAIR ); + flags &= (~SLI4_INIT_LINK_FLAG_SKIP_LIRP_LILP ); + flags &= (~SLI4_INIT_LINK_FLAG_LOOP_VALIDITY ); + flags &= (~SLI4_INIT_LINK_FLAG_SKIP_LISA ); + flags &= (~SLI4_INIT_LINK_FLAG_SEL_HIGHTEST_AL_PA ); + init_link->flags0 =cpu_to_le32 (flags); + +return EFC_SUCCESS ; +} + +/* Write an INIT_VFI command to the provided buffer */ +int +sli_cmd_init_vfi (struct sli4 *sli4,void *buf,size_t size, +u16 vfi,u16 fcfi,u16 vpi) +{ +struct sli4_cmd_init_vfi *init_vfi = buf; +u16 flags =0 ; + +memset (buf,0 , size); + + init_vfi->hdr.command =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 ; +} + +/* Write an INIT_VPI command to the provided buffer */ +int +sli_cmd_init_vpi (struct sli4 *sli4,void *buf,size_t size, +u16 vpi,u16 vfi) +{ +struct sli4_cmd_init_vpi *init_vpi = buf; + +memset (buf,0 , size); + + init_vpi->hdr.command =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,size_t size, +u16 xri_base,u16 xri_count) +{ +struct sli4_cmd_post_xri *post_xri = buf; +u16 xri_count_flags =0 ; + +memset (buf,0 , size); + + post_xri->hdr.command =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,size_t size, +u8 num_xri) +{ +struct sli4_cmd_release_xri *release_xri = buf; + +memset (buf,0 , size); + + release_xri->hdr.command =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,size_t size) +{ +struct sli4_cmd_read_config *read_config = buf; + +memset (buf,0 , size); + + read_config->hdr.command =MBX_CMD_READ_CONFIG ; + +return EFC_SUCCESS ; +} + +int +sli_cmd_read_nvparms (struct sli4 *sli4,void *buf,size_t size) +{ +struct sli4_cmd_read_nvparms *read_nvparms = buf; + +memset (buf,0 , size); + + read_nvparms->hdr.command =MBX_CMD_READ_NVPARMS ; + +return EFC_SUCCESS ; +} + +int +sli_cmd_write_nvparms (struct sli4 *sli4,void *buf,size_t size, +u8 *wwpn,u8 *wwnn,u8 hard_alpa, +u32 preferred_d_id) +{ +struct sli4_cmd_write_nvparms *write_nvparms = buf; + +memset (buf,0 , size); + + write_nvparms->hdr.command =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,size_t size, +struct efc_dma *vpd) +{ +struct sli4_cmd_read_rev *read_rev = buf; + +memset (buf,0 , size); + + read_rev->hdr.command =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, size_t size, + struct efc_dma *dma,
drivers/scsi/elx/libefc_sli/sli4.c sli_fc_rqe_rqid_and_index(struct sli4 *sli4, u8 *cqe, · line 3719
Quoted 10 lines
drivers/scsi/elx/libefc_sli/sli4.c +10
-0+ u16 vpi) +{ +struct sli4_cmd_read_sparm64 *read_sparm64 = buf; + +memset (buf,0 , size); + +if (vpi ==SLI4_READ_SPARM64_VPI_SPECIAL ) { +efc_log_info (sli4,"special VPI not supported!!!\n" ); +return -1 ; + }
EFC_FAIL
drivers/scsi/elx/libefc_sli/sli4.c sli_fc_rqe_rqid_and_index(struct sli4 *sli4, u8 *cqe, · line 3725
Quoted 6 lines
drivers/scsi/elx/libefc_sli/sli4.c +6
-0+ +if (!dma || !dma->phys) { +efc_log_info (sli4,"bad DMA buffer\n" ); +return -1 ; + } +
Same here.
Quoted 21 lines
drivers/scsi/elx/libefc_sli/sli4.c +21
-0+ read_sparm64->hdr.command =MBX_CMD_READ_SPARM64 ; + + read_sparm64->bde_64.bde_type_buflen = +cpu_to_le32 ((BDE_TYPE_BDE_64 <<BDE_TYPE_SHIFT ) | + (dma->size &SLI4_BDE_MASK_BUFFER_LEN )); + 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,size_t size, +struct efc_dma *dma) +{ +struct sli4_cmd_read_topology *read_topo = buf; +
drivers/scsi/elx/libefc_sli/sli4.c sli_fc_rqe_rqid_and_index(struct sli4 *sli4, u8 *cqe, · line 3756
Quoted 10 lines
drivers/scsi/elx/libefc_sli/sli4.c +10
-0+memset (buf,0 , size); + + read_topo->hdr.command =MBX_CMD_READ_TOPOLOGY ; + +if (dma && dma->size) { +if (dma->size <SLI4_MIN_LOOP_MAP_BYTES ) { +efc_log_info (sli4,"loop map buffer too small %jd\n" , + dma->size); +return 0 ; + }
Ah. So this is not an error?
And if this function can't fail, why not make it a void function?
Quoted 144 lines
drivers/scsi/elx/libefc_sli/sli4.c +144
-0+ +memset (dma->virt,0 , dma->size); + + read_topo->bde_loop_map.bde_type_buflen = +cpu_to_le32 ((BDE_TYPE_BDE_64 <<BDE_TYPE_SHIFT ) | + (dma->size &SLI4_BDE_MASK_BUFFER_LEN )); + 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,size_t size, +u16 index, +struct sli4_cmd_rq_cfg rq_cfg[SLI4_CMD_REG_FCFI_NUM_RQ_CFG ]) +{ +struct sli4_cmd_reg_fcfi *reg_fcfi = buf; +u32 i; + +memset (buf,0 , size); + + reg_fcfi->hdr.command =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,size_t size, +u8 mode,u16 fcf_index, +u8 rq_selection_policy,u8 mrq_bit_mask, +u16 num_mrqs, +struct sli4_cmd_rq_cfg rq_cfg[SLI4_CMD_REG_FCFI_NUM_RQ_CFG ]) +{ +struct sli4_cmd_reg_fcfi_mrq *reg_fcfi_mrq = buf; +u32 i; +u32 mrq_flags =0 ; + +memset (buf,0 , size); + + reg_fcfi_mrq->hdr.command =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; + } + +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,size_t size, +u32 nport_id,u16 rpi,u16 vpi, +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 , size); + + reg_rpi->hdr.command =MBX_CMD_REG_RPI ; + + reg_rpi->rpi =cpu_to_le16 (rpi); + + rportid_flags = nport_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 ((BDE_TYPE_BDE_64 <<BDE_TYPE_SHIFT ) | + (SLI4_REG_RPI_BUF_LEN &SLI4_BDE_MASK_BUFFER_LEN )); + 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 ; +} +
drivers/scsi/elx/libefc_sli/sli4.c sli_fc_rqe_rqid_and_index(struct sli4 *sli4, u8 *cqe, · line 3910
Quoted 10 lines
drivers/scsi/elx/libefc_sli/sli4.c +10
-0+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; + +if (!sli4 || !buf) +return 0 ; +
EFC_SUCCESS?
And why is this not an error?
Quoted 28 lines
drivers/scsi/elx/libefc_sli/sli4.c +28
-0+memset (buf,0 , size); + + reg_vfi->hdr.command =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 ((BDE_TYPE_BDE_64 <<BDE_TYPE_SHIFT ) | + (SLI4_REG_RPI_BUF_LEN &SLI4_BDE_MASK_BUFFER_LEN )); + 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
drivers/scsi/elx/libefc_sli/sli4.c sli_fc_rqe_rqid_and_index(struct sli4 *sli4, u8 *cqe, · line 3948
Quoted 10 lines
drivers/scsi/elx/libefc_sli/sli4.c +10
-0+sli_cmd_reg_vpi(struct sli4 *sli4, void *buf, size_t size, + u32 fc_id, __be64 sli_wwpn, u16 vpi, u16 vfi, + bool update) +{ + struct sli4_cmd_reg_vpi *reg_vpi = buf; +u32 flags =0 ; + +if (!sli4 || !buf) +return 0 ; +
Same here. Why is this not returning EFC_SUCCESS?
And why is it not an error?
Quoted 14 lines
drivers/scsi/elx/libefc_sli/sli4.c +14
-0+memset (buf,0 , size); + + reg_vpi->hdr.command =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);
drivers/scsi/elx/libefc_sli/sli4.c sli_fc_rqe_rqid_and_index(struct sli4 *sli4, u8 *cqe, · line 3972
Quoted 10 lines
drivers/scsi/elx/libefc_sli/sli4.c +10
-0+ +return EFC_SUCCESS ; +} + +static int +sli_cmd_request_features (struct sli4 *sli4,void *buf,size_t size, +u32 features_mask,bool query) +{ +struct sli4_cmd_request_features *req_features = buf; +
And why does this function _not_ have the check?
Quoted 28 lines
drivers/scsi/elx/libefc_sli/sli4.c +28
-0+memset (buf,0 , size); + + req_features->hdr.command =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,size_t size, +u16 indicator) +{ +struct sli4_cmd_unreg_fcfi *unreg_fcfi = buf; + +if (!sli4 || !buf) +return 0 ; + +memset (buf,0 , size); + + unreg_fcfi->hdr.command =MBX_CMD_UNREG_FCFI ; + + unreg_fcfi->fcfi =cpu_to_le16 (indicator); + +return EFC_SUCCESS ;
drivers/scsi/elx/libefc_sli/sli4.c sli_fc_rqe_rqid_and_index(struct sli4 *sli4, u8 *cqe, · line 4010
Quoted 10 lines
drivers/scsi/elx/libefc_sli/sli4.c +10
-0+} + +int +sli_cmd_unreg_rpi (struct sli4 *sli4,void *buf,size_t size, +u16 indicator, +enum sli4_resource which,u32 fc_id) +{ +struct sli4_cmd_unreg_rpi *unreg_rpi = buf; +u32 flags =0 ; +
Same here.
Why is there no check?
[ .. ]
Quoted 4 lines
drivers/scsi/elx/libefc_sli/sli4.c +4
-0+ +int +sli_cqe_mq (struct sli4 *sli4,void *buf) +{
drivers/scsi/elx/libefc_sli/sli4.c sli_fc_rqe_rqid_and_index(struct sli4 *sli4, u8 *cqe, · line 4479
Quoted 10 lines
drivers/scsi/elx/libefc_sli/sli4.c +10
-0+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 -2 ; +
Now you're getting creative.
-2 ?
What happened to EFC_SUCCESS/EFC_FAIL?
If this is deliberate please add another EFC_XXX define and document it why this is not the standard return value.
Quoted 14 lines
drivers/scsi/elx/libefc_sli/sli4.c +14
-0+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
drivers/scsi/elx/libefc_sli/sli4.c sli_fc_rqe_rqid_and_index(struct sli4 *sli4, u8 *cqe, · line 4503
Quoted 10 lines
drivers/scsi/elx/libefc_sli/sli4.c +10
-0+sli_cqe_async(struct sli4 *sli4, void *buf) +{ + struct sli4_acqe *acqe = buf; +int rc =-1 ; + +if (!buf) { +efc_log_err (sli4,"bad parameter sli4=%p buf=%p\n" , sli4, buf); +return -1 ; + } +
EFC_FAIL...
Cheers,
Hannes
Signature · 4 lines
Dr. Hannes Reinecke Teamlead Storage & Networking [email protected] +49 911 74053 688 SUSE Software Solutions Germany GmbH, Maxfeldstr. 5, 90409 Nürnberg HRB 36809 (AG Nürnberg), GF: Felix Imendörffer
PATCH v2 7/32 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.
--- drivers/scsi/elx/libefc_sli/sli4.c | 1222 ++++++++++++++++++++++++++++++++++++ drivers/scsi/elx/libefc_sli/sli4.h | 552 +++++++++++++++- 2 files changed, 1773 insertions(+), 1 deletion(-)
drivers/scsi/elx/libefc_sli/sli4.c +1222 -0
@@ -4524,3 +4524,1225 @@ sli_cqe_async(struct sli4 *sli4, void *buf)return rc; } + +/* Determine if the chip FW is in a ready state */ +int +sli_fw_ready (struct sli4 *sli4) +{ +u32 val; +/* +* Is firmware ready for operation? Check needed depends on IF_TYPE +*/ + val =sli_reg_read_status (sli4); +return (val &SLI4_PORT_STATUS_RDY ) ?1 :0 ; +} + +static int +sli_sliport_reset (struct sli4 *sli4) +{ +u32 iter, val; +int rc =-1 ; + + val =SLI4_PORT_CTRL_IP ; +/* Initialize port, endian */ +writel (val, (sli4->reg[0 ] +SLI4_PORT_CTRL_REG )); + +for (iter =0 ; iter <3000 ; iter++) { +mdelay (10 );/* 10 ms */ +if (sli_fw_ready (sli4) ==1 ) { + rc =0 ; +break ; + } + } + +if (rc !=0 ) +efc_log_crit (sli4,"port failed to become ready after initialization\n" ); + +return rc; +} + +static bool +sli_wait_for_fw_ready (struct sli4 *sli4,u32 timeout_ms) +{ +u32 iter = timeout_ms / (SLI4_INIT_PORT_DELAY_US /1000 ); +bool ready = false; + +do { + iter--; +mdelay (10 );/* 10 ms */ +if (sli_fw_ready (sli4) ==1 ) + ready = true; + }while (!ready && (iter >0 )); + +return ready; +} + +static int +sli_fw_init (struct sli4 *sli4) +{ +bool ready; + +/* +* Is firmware ready for operation? +*/ + ready =sli_wait_for_fw_ready (sli4,SLI4_FW_READY_TIMEOUT_MSEC ); +if (!ready) { +efc_log_crit (sli4,"FW status is NOT ready\n" ); +return -1 ; + } + +/* +* Reset port to a known state +*/ +if (sli_sliport_reset (sli4)) +return -1 ; + +return 0 ; +} + +static int +sli_fw_term (struct sli4 *sli4) +{ +/* type 2 etc. use SLIPORT_CONTROL to initialize port */ +sli_sliport_reset (sli4); +return 0 ; +} + +static int +sli_request_features (struct sli4 *sli4,u32 *features,bool query) +{ +if (!sli_cmd_request_features (sli4, sli4->bmbx.virt,SLI4_BMBX_SIZE , + *features, query)) { +struct sli4_cmd_request_features *req_features = + sli4->bmbx.virt; + +if (sli_bmbx_command (sli4)) { +efc_log_crit (sli4,"%s: bootstrap mailbox write fail\n" , + __func__); +return -1 ; + } +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 -1 ; + } + *features =le32_to_cpu (req_features->resp); + }else { +efc_log_err (sli4,"bad REQUEST_FEATURES write\n" ); +return -1 ; + } + +return 0 ; +} + +void +sli_calc_max_qentries (struct sli4 *sli4) +{ +enum sli4_qtype q; +u32 qentries; + +for (q =SLI_QTYPE_EQ ; q <SLI_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 =SLI_QTYPE_EQ ; q <SLI_QTYPE_MAX ; q++) { + qentries = sli4->qinfo.max_qentries[q]; + +efc_log_info (sli4,"[%s]: max_qentries from %d to %d\n" , +SLI_QNAME [q], + sli4->qinfo.max_qentries[q], qentries); + sli4->qinfo.max_qentries[q] = qentries; + } +} + +static int +sli_get_config (struct sli4 *sli4) +{ +struct efc_dma data; +u32 psize; + +/* +* Read the device configuration +*/ +if (!sli_cmd_read_config (sli4, sli4->bmbx.virt,SLI4_BMBX_SIZE )) { +struct sli4_rsp_read_config *read_config = sli4->bmbx.virt; +u32 i; +u32 total, total_size; + +if (sli_bmbx_command (sli4)) { +efc_log_crit (sli4,"bootstrap mailbox fail (READ_CONFIG)\n" ); +return -1 ; + } +if (le16_to_cpu (read_config->hdr.status)) { +efc_log_err (sli4,"READ_CONFIG bad status %#x\n" , +le16_to_cpu (read_config->hdr.status)); +return -1 ; + } + + sli4->has_extents = +le32_to_cpu (read_config->ext_dword) & +SLI4_READ_CFG_RESP_RESOURCE_EXT ; +if (!sli4->has_extents) { +u32 i =0 , size =0 ; +u32 *base = sli4->extent[0 ].base; + +if (!base) { + size =SLI_RSRC_MAX *sizeof (u32); + base =kzalloc (size,GFP_ATOMIC ); +if (!base) +return -1 ; + +memset (base,0 , +SLI_RSRC_MAX *sizeof (u32)); + } + +for (i =0 ; i <SLI_RSRC_MAX ; i++) { + sli4->extent[i].number =1 ; + sli4->extent[i].n_alloc =0 ; + sli4->extent[i].base = &base[i]; + } + + sli4->extent[SLI_RSRC_VFI ].base[0 ] = +le16_to_cpu (read_config->vfi_base); + sli4->extent[SLI_RSRC_VFI ].size = +le16_to_cpu (read_config->vfi_count); + + sli4->extent[SLI_RSRC_VPI ].base[0 ] = +le16_to_cpu (read_config->vpi_base); + sli4->extent[SLI_RSRC_VPI ].size = +le16_to_cpu (read_config->vpi_count); + + sli4->extent[SLI_RSRC_RPI ].base[0 ] = +le16_to_cpu (read_config->rpi_base); + sli4->extent[SLI_RSRC_RPI ].size = +le16_to_cpu (read_config->rpi_count); + + sli4->extent[SLI_RSRC_XRI ].base[0 ] = +le16_to_cpu (read_config->xri_base); + sli4->extent[SLI_RSRC_XRI ].size = +le16_to_cpu (read_config->xri_count); + + sli4->extent[SLI_RSRC_FCFI ].base[0 ] =0 ; + sli4->extent[SLI_RSRC_FCFI ].size = +le16_to_cpu (read_config->fcfi_count); + } + +for (i =0 ; i <SLI_RSRC_MAX ; i++) { + total = sli4->extent[i].number * + sli4->extent[i].size; + total_size =BITS_TO_LONGS (total) *sizeof (long ); + sli4->extent[i].use_map = +kzalloc (total_size,GFP_ATOMIC ); +if (!sli4->extent[i].use_map) { +efc_log_err (sli4,"bitmap memory allocation failed %d\n" , + i); +return -1 ; + } + sli4->extent[i].map_size = total; + } + + sli4->topology = + (le32_to_cpu (read_config->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_FC_DA : +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 (read_config->e_d_tov); + sli4->r_a_tov =le16_to_cpu (read_config->r_a_tov); + + sli4->link_module_type =le16_to_cpu (read_config->lmt); + + sli4->qinfo.max_qcount[SLI_QTYPE_EQ ] = +le16_to_cpu (read_config->eq_count); + sli4->qinfo.max_qcount[SLI_QTYPE_CQ ] = +le16_to_cpu (read_config->cq_count); + sli4->qinfo.max_qcount[SLI_QTYPE_WQ ] = +le16_to_cpu (read_config->wq_count); + sli4->qinfo.max_qcount[SLI_QTYPE_RQ ] = +le16_to_cpu (read_config->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[SLI_QTYPE_MQ ] =SLI_USER_MQ_COUNT ; + }else { +efc_log_err (sli4,"bad READ_CONFIG write\n" ); +return -1 ; + } + +if (!sli_cmd_common_get_sli4_parameters (sli4, sli4->bmbx.virt, +SLI4_BMBX_SIZE )) { +struct sli4_rsp_cmn_get_sli4_params *parms = + (struct sli4_rsp_cmn_get_sli4_params *) + (((u8 *)sli4->bmbx.virt) + + offsetof(struct sli4_cmd_sli_config, payload.embed)); +u32 dwflags_loopback; +u32 dwflags_eq_page_cnt; +u32 dwflags_cq_page_cnt; +u32 dwflags_mq_page_cnt; +u32 dwflags_wq_page_cnt; +u32 dwflags_rq_page_cnt; +u32 dwflags_sgl_page_cnt; + +if (sli_bmbx_command (sli4)) { +efc_log_crit (sli4,"%s: bootstrap mailbox write fail\n" , + __func__); +return -1 ; + }else 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 -1 ; + } + + dwflags_loopback =le32_to_cpu (parms->dw16_loopback_scope); + dwflags_eq_page_cnt =le32_to_cpu (parms->dw6_eq_page_cnt); + dwflags_cq_page_cnt =le32_to_cpu (parms->dw8_cq_page_cnt); + dwflags_mq_page_cnt =le32_to_cpu (parms->dw10_mq_page_cnt); + dwflags_wq_page_cnt =le32_to_cpu (parms->dw12_wq_page_cnt); + dwflags_rq_page_cnt =le32_to_cpu (parms->dw14_rq_page_cnt); + + sli4->auto_reg = + (dwflags_loopback &RSP_GET_PARAM_AREG ); + sli4->auto_xfer_rdy = + (dwflags_loopback &RSP_GET_PARAM_AGXF ); + sli4->hdr_template_req = + (dwflags_loopback &RSP_GET_PARAM_HDRR ); + sli4->t10_dif_inline_capable = + (dwflags_loopback &RSP_GET_PARAM_TIMM ); + sli4->t10_dif_separate_capable = + (dwflags_loopback &RSP_GET_PARAM_TSMM ); + + sli4->mq_create_version = +GET_Q_CREATE_VERSION (dwflags_mq_page_cnt); + sli4->cq_create_version = +GET_Q_CREATE_VERSION (dwflags_cq_page_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[SLI_QTYPE_EQ ] = + (dwflags_eq_page_cnt &RSP_GET_PARAM_EQ_PAGE_CNT_MASK ); + sli4->qinfo.qpage_count[SLI_QTYPE_CQ ] = + (dwflags_cq_page_cnt &RSP_GET_PARAM_CQ_PAGE_CNT_MASK ); + sli4->qinfo.qpage_count[SLI_QTYPE_MQ ] = + (dwflags_mq_page_cnt &RSP_GET_PARAM_MQ_PAGE_CNT_MASK ); + sli4->qinfo.qpage_count[SLI_QTYPE_WQ ] = + (dwflags_wq_page_cnt &RSP_GET_PARAM_WQ_PAGE_CNT_MASK ); + sli4->qinfo.qpage_count[SLI_QTYPE_RQ ] = + (dwflags_rq_page_cnt &RSP_GET_PARAM_RQ_PAGE_CNT_MASK ); + +/* save count methods and masks for each queue type */ + + sli4->qinfo.count_mask[SLI_QTYPE_EQ ] = +le16_to_cpu (parms->eqe_count_mask); + sli4->qinfo.count_method[SLI_QTYPE_EQ ] = +GET_Q_CNT_METHOD (dwflags_eq_page_cnt); + + sli4->qinfo.count_mask[SLI_QTYPE_CQ ] = +le16_to_cpu (parms->cqe_count_mask); + sli4->qinfo.count_method[SLI_QTYPE_CQ ] = +GET_Q_CNT_METHOD (dwflags_cq_page_cnt); + + sli4->qinfo.count_mask[SLI_QTYPE_MQ ] = +le16_to_cpu (parms->mqe_count_mask); + sli4->qinfo.count_method[SLI_QTYPE_MQ ] = +GET_Q_CNT_METHOD (dwflags_mq_page_cnt); + + sli4->qinfo.count_mask[SLI_QTYPE_WQ ] = +le16_to_cpu (parms->wqe_count_mask); + sli4->qinfo.count_method[SLI_QTYPE_WQ ] = +GET_Q_CNT_METHOD (dwflags_wq_page_cnt); + + sli4->qinfo.count_mask[SLI_QTYPE_RQ ] = +le16_to_cpu (parms->rqe_count_mask); + sli4->qinfo.count_method[SLI_QTYPE_RQ ] = +GET_Q_CNT_METHOD (dwflags_rq_page_cnt); + +/* now calculate max queue entries */ +sli_calc_max_qentries (sli4); + + dwflags_sgl_page_cnt =le32_to_cpu (parms->dw18_sgl_page_cnt); + +/* max # of pages */ + sli4->max_sgl_pages = + (dwflags_sgl_page_cnt & +RSP_GET_PARAM_SGL_PAGE_CNT_MASK ); + +/* bit map of available sizes */ + sli4->sgl_page_sizes = + (dwflags_sgl_page_cnt & +RSP_GET_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->sgl_pre_registration_required = + (dwflags_loopback &RSP_GET_PARAM_SGLR ); +/* default to using pre-registered SGL's */ + sli4->sgl_pre_registered = true; + + sli4->perf_hint = + (dwflags_loopback &RSP_GET_PARAM_PHON ); + sli4->perf_wq_id_association = + (dwflags_loopback &RSP_GET_PARAM_PHWQ ); + + sli4->rq_batch = + (le16_to_cpu (parms->dw15w1_rq_db_window) & +RSP_GET_PARAM_RQ_DB_WINDOW_MASK ) >>12 ; + +/* Use the highest available WQE size. */ +if (((dwflags_wq_page_cnt & +RSP_GET_PARAM_WQE_SZS_MASK ) >>8 ) & +SLI4_128BYTE_WQE_SUPPORT ) + sli4->wqe_size =SLI4_WQE_EXT_BYTES ; +else + sli4->wqe_size =SLI4_WQE_BYTES ; + } + + sli4->port_number =0 ; + +/* +* Issue COMMON_GET_CNTL_ATTRIBUTES to get port_number. Temporarily +* uses VPD DMA buffer as the response won't fit in the embedded +* buffer. +*/ +if (!sli_cmd_common_get_cntl_attributes (sli4, sli4->bmbx.virt, +SLI4_BMBX_SIZE , + &sli4->vpd_data)) { +struct sli4_rsp_cmn_get_cntl_attributes *attr = + sli4->vpd_data.virt; + +if (sli_bmbx_command (sli4)) { +efc_log_crit (sli4,"%s: bootstrap mailbox write fail\n" , + __func__); +return -1 ; + }else 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 -1 ; + } + + 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)); + }else { +efc_log_err (sli4,"bad COMMON_GET_CNTL_ATTRIBUTES write\n" ); +return -1 ; + } + + psize =sizeof (struct sli4_rsp_cmn_get_cntl_addl_attributes ); + data.size = psize; + data.virt =dma_alloc_coherent (&sli4->pcidev->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" ); + }else { +if (!sli_cmd_common_get_cntl_addl_attributes (sli4, + sli4->bmbx.virt, +SLI4_BMBX_SIZE , + &data)) { +struct sli4_rsp_cmn_get_cntl_addl_attributes *attr; + + attr = data.virt; +if (sli_bmbx_command (sli4)) { +efc_log_crit (sli4,"mailbox fail (GET_CNTL_ADDL_ATTR)\n" ); +dma_free_coherent (&sli4->pcidev->dev, data.size, + data.virt, data.phys); +return -1 ; + } +if (attr->hdr.status) { +efc_log_err (sli4,"GET_CNTL_ADDL_ATTR bad status %#x\n" , + attr->hdr.status); +dma_free_coherent (&sli4->pcidev->dev, data.size, + data.virt, data.phys); +return -1 ; + } + +memcpy (sli4->ipl_name, attr->ipl_file_name, +sizeof (sli4->ipl_name)); + +efc_log_info (sli4,"IPL:%s\n" , + (char *)sli4->ipl_name); + }else { +efc_log_err (sli4,"bad GET_CNTL_ADDL_ATTR write\n" ); +dma_free_coherent (&sli4->pcidev->dev, data.size, + data.virt, data.phys); +return -1 ; + } + +dma_free_coherent (&sli4->pcidev->dev, data.size, data.virt, + data.phys); +memset (&data,0 ,sizeof (struct efc_dma )); + } + +if (!sli_cmd_common_get_port_name (sli4, sli4->bmbx.virt, +SLI4_BMBX_SIZE )) { +struct sli4_rsp_cmn_get_port_name *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,"%s: bootstrap mailbox write fail\n" , + __func__); +return -1 ; + } + + sli4->port_name[0 ] = + port_name->port_name[sli4->port_number]; + } + sli4->port_name[1 ] ='\0' ; + +if (!sli_cmd_read_rev (sli4, sli4->bmbx.virt,SLI4_BMBX_SIZE , + &sli4->vpd_data)) { +struct sli4_cmd_read_rev *read_rev = sli4->bmbx.virt; + +if (sli_bmbx_command (sli4)) { +efc_log_crit (sli4,"bootstrap mailbox write fail (READ_REV)\n" ); +return -1 ; + } +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 -1 ; + } + + 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 returned=%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); + }else { +efc_log_err (sli4,"bad READ_REV write\n" ); +return -1 ; + } + +if (!sli_cmd_read_nvparms (sli4, sli4->bmbx.virt,SLI4_BMBX_SIZE )) { +struct sli4_cmd_read_nvparms *read_nvparms = sli4->bmbx.virt; + +if (sli_bmbx_command (sli4)) { +efc_log_crit (sli4,"bootstrap mailbox fail (READ_NVPARMS)\n" ); +return -1 ; + } +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 -1 ; + } + +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 ]); + }else { +efc_log_err (sli4,"bad READ_NVPARMS write\n" ); +return -1 ; + } + +return 0 ; +} + +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->pcidev = 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 +*/ +pci_read_config_dword (pdev,SLI4_INTF_REG , &intf); + +if ((intf &SLI4_INTF_VALID_MASK ) != (u32 )SLI4_INTF_VALID_VALUE ) { +efc_log_err (sli4,"SLI_INTF is not valid\n" ); +return -1 ; + } + +/* 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 -1 ; + } + + 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 +*/ +pci_read_config_dword (pdev,PCI_CLASS_REVISION , &pci_class_rev); + rev_id = pci_class_rev &0xff ; + family = sli4->sli_family; +if (family ==SLI4_FAMILY_CHECK_ASIC_TYPE ) { +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 || !sli4->asic_rev) { +efc_log_err (sli4,"no matching asic family/rev found: %02x/%02x\n" , + family, rev_id); +return -1 ; + } + +/* +* 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 -1 ; + } + +if (sli4->bmbx.phys &SLI4_BMBX_MASK_LO ) { +efc_log_err (sli4,"bad alignment for bootstrap mailbox\n" ); +return -1 ; + } + +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 -1 ; + } + +/* +* 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->perf_hint) + sli4->features |=SLI4_REQFEAT_PERFH ; + +if (sli_request_features (sli4, &sli4->features, true)) +return -1 ; + +if (sli_get_config (sli4)) +return -1 ; + +return 0 ; +} + +int +sli_init (struct sli4 *sli4) +{ +if (sli4->has_extents) { +efc_log_info (sli4,"XXX need to implement extent allocation\n" ); +return -1 ; + } + +if (sli4->high_login_mode) + sli4->features |=SLI4_REQFEAT_HLM ; +else + sli4->features &= (~SLI4_REQFEAT_HLM ); + sli4->features &= (~SLI4_REQFEAT_RXSEQ ); + sli4->features &= (~SLI4_REQFEAT_RXRI ); + +if (sli_request_features (sli4, &sli4->features, false)) +return -1 ; + +return 0 ; +} + +int +sli_reset (struct sli4 *sli4) +{ +u32 i; + +if (sli_fw_init (sli4)) { +efc_log_crit (sli4,"FW initialization failed\n" ); +return -1 ; + } + +kfree (sli4->extent[0 ].base); + sli4->extent[0 ].base =NULL ; + +for (i =0 ; i <SLI_RSRC_MAX ; i++) { +kfree (sli4->extent[i].use_map); + sli4->extent[i].use_map =NULL ; + sli4->extent[i].base =NULL ; + } + +if (sli_get_config (sli4)) +return -1 ; + +return 0 ; +} + +int +sli_fw_reset (struct sli4 *sli4) +{ +u32 val; +bool ready; + +/* +* Firmware must be ready before issuing the reset. +*/ + ready =sli_wait_for_fw_ready (sli4,SLI4_FW_READY_TIMEOUT_MSEC ); +if (!ready) { +efc_log_crit (sli4,"FW status is NOT ready\n" ); +return -1 ; + } +/* Lancer uses PHYDEV_CONTROL */ + + val =SLI4_PHYDEV_CTRL_FRST ; +writel (val, (sli4->reg[0 ] +SLI4_PHYDEV_CTRL_REG )); + +/* wait for the FW to become ready after the reset */ + ready =sli_wait_for_fw_ready (sli4,SLI4_FW_READY_TIMEOUT_MSEC ); +if (!ready) { +efc_log_crit (sli4,"Failed to become ready after firmware reset\n" ); +return -1 ; + } +return 0 ; +} + +int +sli_teardown (struct sli4 *sli4) +{ +u32 i; + +kfree (sli4->extent[0 ].base); + sli4->extent[0 ].base =NULL ; + +for (i =0 ; i <SLI_RSRC_MAX ; i++) { + sli4->extent[i].base =NULL ; + +kfree (sli4->extent[i].use_map); + sli4->extent[i].use_map =NULL ; + } + +if (sli_fw_term (sli4)) +efc_log_err (sli4,"FW deinitialization failed\n" ); + +dma_free_coherent (&sli4->pcidev->dev, sli4->vpd_data.size, + sli4->vpd_data.virt, sli4->vpd_data.phys); +dma_free_coherent (&sli4->pcidev->dev, sli4->bmbx.size, + sli4->bmbx.virt, sli4->bmbx.phys); + +return 0 ; +} + +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 -1 ; + } + +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 -1 ; + } + +return 0 ; +} + +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,SLI4_BMBX_SIZE , + eq, num_eq, shift, delay_mult); + +if (sli_bmbx_command (sli4)) { +efc_log_crit (sli4,"bootstrap mailbox write fail (MODIFY EQ DELAY)\n" ); +return -1 ; + } +if (sli_res_sli_config (sli4, sli4->bmbx.virt)) { +efc_log_err (sli4,"bad status MODIFY EQ DELAY\n" ); +return -1 ; + } + +return 0 ; +} + +int +sli_resource_alloc (struct sli4 *sli4,enum sli4_resource rtype, +u32 *rid,u32 *index) +{ +int rc =0 ; +u32 size; +u32 extent_idx; +u32 item_idx; +u32 position; + + *rid =U32_MAX ; + *index =U32_MAX ; + +switch (rtype) { +case SLI_RSRC_VFI : +case SLI_RSRC_VPI : +case SLI_RSRC_RPI : +case SLI_RSRC_XRI : + position = +find_first_zero_bit (sli4->extent[rtype].use_map, + sli4->extent[rtype].map_size); +if (position >= sli4->extent[rtype].map_size) { +efc_log_err (sli4,"out of resource %d (alloc=%d)\n" , + rtype, sli4->extent[rtype].n_alloc); + rc =-1 ; +break ; + } +set_bit (position, sli4->extent[rtype].use_map); + *index = position; + + size = sli4->extent[rtype].size; + + extent_idx = *index / size; + item_idx = *index % size; + + *rid = sli4->extent[rtype].base[extent_idx] + item_idx; + + sli4->extent[rtype].n_alloc++; +break ; +default : + rc =-1 ; + } + +return rc; +} + +int +sli_resource_free (struct sli4 *sli4, +enum sli4_resource rtype,u32 rid) +{ +int rc =-1 ; +u32 x; +u32 size, *base; + +switch (rtype) { +case SLI_RSRC_VFI : +case SLI_RSRC_VPI : +case SLI_RSRC_RPI : +case SLI_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->extent[rtype].base; + size = sli4->extent[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) { +for (x =0 ; x < sli4->extent[rtype].number; + x++) { +if (rid >= base[x] && + (rid < (base[x] + size))) { + rid -= base[x]; +clear_bit ((x * size) + rid, + sli4->extent[rtype].use_map); + rc =0 ; +break ; + } + } + } +break ; +default : +break ; + } + +return rc; +} + +int +sli_resource_reset (struct sli4 *sli4,enum sli4_resource rtype) +{ +int rc =-1 ; +u32 i; + +switch (rtype) { +case SLI_RSRC_VFI : +case SLI_RSRC_VPI : +case SLI_RSRC_RPI : +case SLI_RSRC_XRI : +for (i =0 ; i < sli4->extent[rtype].map_size; i++) +clear_bit (i, sli4->extent[rtype].use_map); + rc =0 ; +break ; +default : +break ; + } + +return rc; +} + +int sli_raise_ue (struct sli4 *sli4,u8 dump) +{ +u32 val =0 ; +#define FDD 2 +if (dump ==FDD ) { + 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 ==1 ) + val |=SLI4_PHYDEV_CTRL_DD ; +writel (val, (sli4->reg[0 ] +SLI4_PHYDEV_CTRL_REG )); + } + +return 0 ; +} + +int sli_dump_is_ready (struct sli4 *sli4) +{ +int rc =0 ; +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 =1 ; +else if (port_val &SLI4_PORT_STATUS_FDP ) + rc =2 ; + } + +return rc; +} + +int sli_dump_is_present (struct sli4 *sli4) +{ +u32 val; +bool ready; + +/* If the chip is not ready, then there cannot be a dump */ + ready =sli_wait_for_fw_ready (sli4,SLI4_INIT_PORT_DELAY_US ); +if (!ready) +return 0 ; + + val =sli_reg_read_status (sli4); +if (val ==U32_MAX ) { +efc_log_err (sli4,"error reading SLIPORT_STATUS\n" ); +return -1 ; + }else { +return (val &SLI4_PORT_STATUS_DIP ) ?1 :0 ; + } +} + +int sli_reset_required (struct sli4 *sli4) +{ +u32 val; + + val =sli_reg_read_status (sli4); +if (val ==U32_MAX ) { +efc_log_err (sli4,"error reading SLIPORT_STATUS\n" ); +return -1 ; + }else { +return (val &SLI4_PORT_STATUS_RN ) ?1 :0 ; + } +} + +int +sli_cmd_post_sgl_pages (struct sli4 *sli4,void *buf,size_t size, +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, size, +SLI_CONFIG_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, +size_t size,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->pcidev->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, size, + payload_size, payload_dma); + }else { + req =sli_config_cmd_init (sli4, buf, size, + payload_size,NULL ); + } + +if (!req) +return EFC_FAIL ; + +if (rpi ==U16_MAX ) + rpi = sli4->extent[SLI_RSRC_RPI ].base[0 ]; + +sli_cmd_fill_hdr (&req->hdr,SLI4_OPC_POST_HDR_TEMPLATES , +SLI4_SUBSYSTEM_FC ,CMD_V0 , +CFG_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->hdr_template_req) +/* round up to a page */ + bytes =SLI_ROUND_PAGE (n_rpi *SLI4_HDR_TEMPLATE_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 +551 -1
562 lines not on this page · raw message
Signature · 1 line
2.13.7
Re: [PATCH v2 07/32] elx: libefc_sli: APIs to setup SLI library
Quoted 24 lines · James Smart
This patch continues the
libefc_sliSLI-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.
Signed-off-by Ram Vegesna <[email protected]>Signed-off-by James Smart <[email protected]>--- drivers/scsi/elx/libefc_sli/sli4.c | 1222 ++++++++++++++++++++++++++++++++++++ drivers/scsi/elx/libefc_sli/sli4.h | 552 +++++++++++++++- 2 files changed, 1773 insertions(+), 1 deletion(-)drivers/scsi/elx/libefc_sli/sli4.c +3
-0@@ -4524,3 +4524,1225 @@ sli_cqe_async(struct sli4 *sli4, void *buf)return rc; } + +/* Determine if the chip FW is in a ready state */ +int
drivers/scsi/elx/libefc_sli/sli4.c sli_cqe_async(struct sli4 *sli4, void *buf) · line 4539
Quoted 10 lines
drivers/scsi/elx/libefc_sli/sli4.c +10
-0+sli_fw_ready(struct sli4 *sli4) +{ +u32 val; +/* +* Is firmware ready for operation? Check needed depends on IF_TYPE +*/ + val =sli_reg_read_status (sli4); +return (val &SLI4_PORT_STATUS_RDY ) ?1 :0 ; +} +
boolean?
Quoted 14 lines
drivers/scsi/elx/libefc_sli/sli4.c +14
-0+static int +sli_sliport_reset (struct sli4 *sli4) +{ +u32 iter, val; +int rc =-1 ; + + val =SLI4_PORT_CTRL_IP ; +/* Initialize port, endian */ +writel (val, (sli4->reg[0 ] +SLI4_PORT_CTRL_REG )); + +for (iter =0 ; iter <3000 ; iter++) { +mdelay (10 );/* 10 ms */ +if (sli_fw_ready (sli4) ==1 ) { + rc =0 ;
drivers/scsi/elx/libefc_sli/sli4.c sli_cqe_async(struct sli4 *sli4, void *buf) · line 4563
Quoted 10 lines
drivers/scsi/elx/libefc_sli/sli4.c +10
-0+break ; + } + } + +if (rc !=0 ) +efc_log_crit (sli4,"port failed to become ready after initialization\n" ); + +return rc; +} +
Same here?
Quoted 6 lines
drivers/scsi/elx/libefc_sli/sli4.c +6
-0+static bool +sli_wait_for_fw_ready (struct sli4 *sli4,u32 timeout_ms) +{ +u32 iter = timeout_ms / (SLI4_INIT_PORT_DELAY_US /1000 ); +bool ready = false; +
drivers/scsi/elx/libefc_sli/sli4.c sli_cqe_async(struct sli4 *sli4, void *buf) · line 4579
Quoted 10 lines
drivers/scsi/elx/libefc_sli/sli4.c +10
-0+do { + iter--; +mdelay (10 );/* 10 ms */ +if (sli_fw_ready (sli4) ==1 ) + ready = true; + }while (!ready && (iter >0 )); + +return ready; +} +
See? It doesn't even hurt ...
Quoted 13 lines
drivers/scsi/elx/libefc_sli/sli4.c +13
-0+static int +sli_fw_init (struct sli4 *sli4) +{ +bool ready; + +/* +* Is firmware ready for operation? +*/ + ready =sli_wait_for_fw_ready (sli4,SLI4_FW_READY_TIMEOUT_MSEC ); +if (!ready) { +efc_log_crit (sli4,"FW status is NOT ready\n" ); +return -1 ; + }
drivers/scsi/elx/libefc_sli/sli4.c sli_cqe_async(struct sli4 *sli4, void *buf) · line 4602
Quoted 10 lines
drivers/scsi/elx/libefc_sli/sli4.c +10
-0+ +/* +* Reset port to a known state +*/ +if (sli_sliport_reset (sli4)) +return -1 ; + +return 0 ; +} +
boolean?
[ .. ]
drivers/scsi/elx/libefc_sli/sli4.c sli_cqe_async(struct sli4 *sli4, void *buf) · line 5266
Quoted 8 lines
drivers/scsi/elx/libefc_sli/sli4.c +8
-0+int +sli_init (struct sli4 *sli4) +{ +if (sli4->has_extents) { +efc_log_info (sli4,"XXX need to implement extent allocation\n" ); +return -1 ; + } +
Ho-hum.
Maybe 'extend allocation not implemented' ?
[ .. ]
Quoted 36 lines
drivers/scsi/elx/libefc_sli/sli4.c +36
-0+int +sli_resource_alloc (struct sli4 *sli4,enum sli4_resource rtype, +u32 *rid,u32 *index) +{ +int rc =0 ; +u32 size; +u32 extent_idx; +u32 item_idx; +u32 position; + + *rid =U32_MAX ; + *index =U32_MAX ; + +switch (rtype) { +case SLI_RSRC_VFI : +case SLI_RSRC_VPI : +case SLI_RSRC_RPI : +case SLI_RSRC_XRI : + position = +find_first_zero_bit (sli4->extent[rtype].use_map, + sli4->extent[rtype].map_size); +if (position >= sli4->extent[rtype].map_size) { +efc_log_err (sli4,"out of resource %d (alloc=%d)\n" , + rtype, sli4->extent[rtype].n_alloc); + rc =-1 ; +break ; + } +set_bit (position, sli4->extent[rtype].use_map); + *index = position; + + size = sli4->extent[rtype].size; + + extent_idx = *index / size; + item_idx = *index % size; + + *rid = sli4->extent[rtype].base[extent_idx] + item_idx;
drivers/scsi/elx/libefc_sli/sli4.c sli_cqe_async(struct sli4 *sli4, void *buf) · line 5446
Quoted 10 lines
drivers/scsi/elx/libefc_sli/sli4.c +10
-0+ + sli4->extent[rtype].n_alloc++; +break ; +default : + rc =-1 ; + } + +return rc; +} +
Didn't you mention extent allocation is not implemented? So is this a different type of extent?
Quoted 63 lines
drivers/scsi/elx/libefc_sli/sli4.c +63
-0+int +sli_resource_free (struct sli4 *sli4, +enum sli4_resource rtype,u32 rid) +{ +int rc =-1 ; +u32 x; +u32 size, *base; + +switch (rtype) { +case SLI_RSRC_VFI : +case SLI_RSRC_VPI : +case SLI_RSRC_RPI : +case SLI_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->extent[rtype].base; + size = sli4->extent[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) { +for (x =0 ; x < sli4->extent[rtype].number; + x++) { +if (rid >= base[x] && + (rid < (base[x] + size))) { + rid -= base[x]; +clear_bit ((x * size) + rid, + sli4->extent[rtype].use_map); + rc =0 ; +break ; + } + } + } +break ; +default : +break ; + } + +return rc; +} + +int +sli_resource_reset (struct sli4 *sli4,enum sli4_resource rtype) +{ +int rc =-1 ; +u32 i; + +switch (rtype) { +case SLI_RSRC_VFI : +case SLI_RSRC_VPI : +case SLI_RSRC_RPI : +case SLI_RSRC_XRI : +for (i =0 ; i < sli4->extent[rtype].map_size; i++) +clear_bit (i, sli4->extent[rtype].use_map); + rc =0 ; +break ; +default :
drivers/scsi/elx/libefc_sli/sli4.c sli_cqe_async(struct sli4 *sli4, void *buf) · line 5519
Quoted 10 lines
drivers/scsi/elx/libefc_sli/sli4.c +10
-0+break ; + } + +return rc; +} + +int sli_raise_ue (struct sli4 *sli4,u8 dump) +{ +u32 val =0 ; +#define FDD 2
Oh, come on.
You have defines for everything but the kitchen sink. So why do you have to define this one inline?
Quoted 28 lines
drivers/scsi/elx/libefc_sli/sli4.c +28
-0+if (dump ==FDD ) { + 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 ==1 ) + val |=SLI4_PHYDEV_CTRL_DD ; +writel (val, (sli4->reg[0 ] +SLI4_PHYDEV_CTRL_REG )); + } + +return 0 ; +} + +int sli_dump_is_ready (struct sli4 *sli4) +{ +int rc =0 ; +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) &&
drivers/scsi/elx/libefc_sli/sli4.c sli_cqe_async(struct sli4 *sli4, void *buf) · line 5557
Quoted 10 lines
drivers/scsi/elx/libefc_sli/sli4.c +10
-0+ (port_val & SLI4_PORT_STATUS_RDY)) { +if (port_val &SLI4_PORT_STATUS_DIP ) + rc =1 ; +else if (port_val &SLI4_PORT_STATUS_FDP ) + rc =2 ; + } + +return rc; +} +
Please use defines for the return values here.
One has no idea why '1' or '2' is returned here.
At the very least some documentation.
Quoted 68 lines
drivers/scsi/elx/libefc_sli/sli4.c +68
-0+int sli_dump_is_present (struct sli4 *sli4) +{ +u32 val; +bool ready; + +/* If the chip is not ready, then there cannot be a dump */ + ready =sli_wait_for_fw_ready (sli4,SLI4_INIT_PORT_DELAY_US ); +if (!ready) +return 0 ; + + val =sli_reg_read_status (sli4); +if (val ==U32_MAX ) { +efc_log_err (sli4,"error reading SLIPORT_STATUS\n" ); +return -1 ; + }else { +return (val &SLI4_PORT_STATUS_DIP ) ?1 :0 ; + } +} + +int sli_reset_required (struct sli4 *sli4) +{ +u32 val; + + val =sli_reg_read_status (sli4); +if (val ==U32_MAX ) { +efc_log_err (sli4,"error reading SLIPORT_STATUS\n" ); +return -1 ; + }else { +return (val &SLI4_PORT_STATUS_RN ) ?1 :0 ; + } +} + +int +sli_cmd_post_sgl_pages (struct sli4 *sli4,void *buf,size_t size, +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, size, +SLI_CONFIG_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++) {
drivers/scsi/elx/libefc_sli/sli4.c sli_cqe_async(struct sli4 *sli4, void *buf) · line 5635
Quoted 10 lines
drivers/scsi/elx/libefc_sli/sli4.c +10
-0+ 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 ; +} +
EFC_SUCCESS is back!
I've already missed them; none of the previous functions in this patch use them.
Please fix.
[ .. ]
Quoted 108 lines
drivers/scsi/elx/libefc_sli/sli4.c +108
-0+extern int +sli_cmd_unreg_vfi (struct sli4 *sli4,void *buf,size_t size, +u16 index,u32 which); +extern int +sli_cmd_common_nop (struct sli4 *sli4,void *buf,size_t size, +uint64_t context); +extern int +sli_cmd_common_get_resource_extent_info (struct sli4 *sli4,void *buf, +size_t size,u16 rtype); +extern int +sli_cmd_common_get_sli4_parameters (struct sli4 *sli4, +void *buf,size_t size); +extern int +sli_cmd_common_write_object (struct sli4 *sli4,void *buf,size_t size, +u16 noc,u16 eof,u32 desired_write_length, +u32 offset,char *object_name,struct efc_dma *dma); +extern int +sli_cmd_common_delete_object (struct sli4 *sli4,void *buf,size_t size, +char *object_name); +extern int +sli_cmd_common_read_object (struct sli4 *sli4,void *buf,size_t size, +u32 desired_read_length,u32 offset, +char *object_name,struct efc_dma *dma); +extern int +sli_cmd_dmtf_exec_clp_cmd (struct sli4 *sli4,void *buf,size_t size, +struct efc_dma *cmd,struct efc_dma *resp); +extern int +sli_cmd_common_set_dump_location (struct sli4 *sli4, +void *buf,size_t size,bool query, +bool is_buffer_list, +struct efc_dma *buffer,u8 fdb); +extern int +sli_cmd_common_set_features (struct sli4 *sli4,void *buf,size_t size, +u32 feature,u32 param_len, +void *parameter); + +int sli_cqe_mq (struct sli4 *sli4,void *buf); +int sli_cqe_async (struct sli4 *sli4,void *buf); + +extern int +sli_setup (struct sli4 *sli4,void *os,struct pci_dev *pdev, +void __iomem *reg[]); +void sli_calc_max_qentries (struct sli4 *sli4); +int sli_init (struct sli4 *sli4); +int sli_reset (struct sli4 *sli4); +int sli_fw_reset (struct sli4 *sli4); +int sli_teardown (struct sli4 *sli4); +extern int +sli_callback (struct sli4 *sli4,enum sli4_callback which, +void *func,void *arg); +extern int +sli_bmbx_command (struct sli4 *sli4); +extern int +__sli_queue_init (struct sli4 *sli4,struct sli4_queue *q, +u32 qtype,size_t size,u32 n_entries, +u32 align); +extern int +__sli_create_queue (struct sli4 *sli4,struct sli4_queue *q); +extern int +sli_eq_modify_delay (struct sli4 *sli4,struct sli4_queue *eq, +u32 num_eq,u32 shift,u32 delay_mult); +extern int +sli_queue_alloc (struct sli4 *sli4,u32 qtype, +struct sli4_queue *q,u32 n_entries, +struct sli4_queue *assoc); +extern int +sli_cq_alloc_set (struct sli4 *sli4,struct sli4_queue *qs[], +u32 num_cqs,u32 n_entries,struct sli4_queue *eqs[]); +extern int +sli_get_queue_entry_size (struct sli4 *sli4,u32 qtype); +extern int +sli_queue_free (struct sli4 *sli4,struct sli4_queue *q, +u32 destroy_queues,u32 free_memory); +extern int +sli_queue_eq_arm (struct sli4 *sli4,struct sli4_queue *q,bool arm); +extern int +sli_queue_arm (struct sli4 *sli4,struct sli4_queue *q,bool arm); + +extern int +sli_wq_write (struct sli4 *sli4,struct sli4_queue *q, +u8 *entry); +extern int +sli_mq_write (struct sli4 *sli4,struct sli4_queue *q, +u8 *entry); +extern int +sli_rq_write (struct sli4 *sli4,struct sli4_queue *q, +u8 *entry); +extern int +sli_eq_read (struct sli4 *sli4,struct sli4_queue *q, +u8 *entry); +extern int +sli_cq_read (struct sli4 *sli4,struct sli4_queue *q, +u8 *entry); +extern int +sli_mq_read (struct sli4 *sli4,struct sli4_queue *q, +u8 *entry); +extern int +sli_queue_index (struct sli4 *sli4,struct sli4_queue *q); +extern int +_sli_queue_poke (struct sli4 *sli4,struct sli4_queue *q, +u32 index,u8 *entry); +extern int +sli_queue_poke (struct sli4 *sli4,struct sli4_queue *q,u32 index, +u8 *entry); +extern int +sli_resource_alloc (struct sli4 *sli4,enum sli4_resource rtype, +u32 *rid,u32 *index); +extern int
drivers/scsi/elx/libefc_sli/sli4.c sli_cqe_async(struct sli4 *sli4, void *buf) · line 4963
Quoted 10 lines
drivers/scsi/elx/libefc_sli/sli4.c +10
-0+sli_resource_free(struct sli4 *sli4, enum sli4_resource rtype, + u32 rid); +extern int +sli_resource_reset (struct sli4 *sli4,enum sli4_resource rtype); +extern int +sli_eq_parse (struct sli4 *sli4,u8 *buf,u16 *cq_id); +extern int +sli_cq_parse (struct sli4 *sli4,struct sli4_queue *cq,u8 *cqe, +enum sli4_qentry *etype,u16 *q_id); +
I guess you can reformat those; the linux line length is 80 characters, and one really should use them ...
Cheers,
Hannes
Signature · 4 lines
Dr. Hannes Reinecke Teamlead Storage & Networking [email protected] +49 911 74053 688 SUSE Software Solutions Germany GmbH, Maxfeldstr. 5, 90409 Nürnberg HRB 36809 (AG Nürnberg), GF: Felix Imendörffer
Re: [PATCH v2 07/32] elx: libefc_sli: APIs to setup SLI library
Quoted 3 lines · Hannes Reinecke
boolean?
...
Quoted 3 lines
Same here?
...
Quoted 1 line
See? It doesn't even hurt ...
:)
...
Quoted 3 lines
boolean?
yep - we'll convert them to boolean's
Quoted 2 lines
Ho-hum.
Maybe 'extend allocation not implemented' ?
ok
Quoted 3 lines
Didn't you mention extent allocation is not implemented? So is this a different type of extent?
kinda - there was a comment header that tried to clarify this:
/* * 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.
*/
regardless - we'll clarify what's going on.
Quoted 5 lines
Quoted 1 line
+#define FDD 2
Oh, come on.
You have defines for everything but the kitchen sink. So why do you have to define this one inline?
yeah - there are a lot.
Agree - the define will be moved to a header. It's a dump-type selection (function scope or adapter scope; only newer things do function only).
Quoted 5 lines
Please use defines for the return values here.
One has no idea why '1' or '2' is returned here.
At the very least some documentation.
yep - will do.
Quoted 4 lines
EFC_SUCCESSis back!
I've already missed them; none of the previous functions in this patch use them.
Please fix.
yep.
Quoted 7 lines
I guess you can reformat those; the linux line length is 80 characters, and one really should use them ...
Cheers,
Hannes
We'll fix the line lengths.
-- james
PATCH v2 8/32 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 | 213 +++++++++++++++++++++++++++++++++++++++ drivers/scsi/elx/libefc/efc_sm.h | 140 +++++++++++++++++++++++++ 2 files changed, 353 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 +213 -0
@@ -0,0 +1,213 @@ +// SPDX-License-Identifier: GPL-2.0 +/* +* Copyright (C) 2019 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" + +const char *efc_sm_id[] = { +"common" , +"domain" , +"login" +}; + +/** +* 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) { + ctx->current_state (ctx, evt, data); +return 0 ; + }else { +return -1 ; + } +} + +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); + } +} + +void +efc_sm_disable (struct efc_sm_ctx *ctx) +{ + ctx->current_state =NULL ; +} + +const char *efc_sm_event_name (enum efc_sm_event evt) +{ +switch (evt) { +case EFC_EVT_ENTER : +return "EFC_EVT_ENTER" ; +case EFC_EVT_REENTER : +return "EFC_EVT_REENTER" ; +case EFC_EVT_EXIT : +return "EFC_EVT_EXIT" ; +case EFC_EVT_SHUTDOWN : +return "EFC_EVT_SHUTDOWN" ; +case EFC_EVT_RESPONSE : +return "EFC_EVT_RESPONSE" ; +case EFC_EVT_RESUME : +return "EFC_EVT_RESUME" ; +case EFC_EVT_TIMER_EXPIRED : +return "EFC_EVT_TIMER_EXPIRED" ; +case EFC_EVT_ERROR : +return "EFC_EVT_ERROR" ; +case EFC_EVT_SRRS_ELS_REQ_OK : +return "EFC_EVT_SRRS_ELS_REQ_OK" ; +case EFC_EVT_SRRS_ELS_CMPL_OK : +return "EFC_EVT_SRRS_ELS_CMPL_OK" ; +case EFC_EVT_SRRS_ELS_REQ_FAIL : +return "EFC_EVT_SRRS_ELS_REQ_FAIL" ; +case EFC_EVT_SRRS_ELS_CMPL_FAIL : +return "EFC_EVT_SRRS_ELS_CMPL_FAIL" ; +case EFC_EVT_SRRS_ELS_REQ_RJT : +return "EFC_EVT_SRRS_ELS_REQ_RJT" ; +case EFC_EVT_NODE_ATTACH_OK : +return "EFC_EVT_NODE_ATTACH_OK" ; +case EFC_EVT_NODE_ATTACH_FAIL : +return "EFC_EVT_NODE_ATTACH_FAIL" ; +case EFC_EVT_NODE_FREE_OK : +return "EFC_EVT_NODE_FREE_OK" ; +case EFC_EVT_ELS_REQ_TIMEOUT : +return "EFC_EVT_ELS_REQ_TIMEOUT" ; +case EFC_EVT_ELS_REQ_ABORTED : +return "EFC_EVT_ELS_REQ_ABORTED" ; +case EFC_EVT_ABORT_ELS : +return "EFC_EVT_ABORT_ELS" ; +case EFC_EVT_ELS_ABORT_CMPL : +return "EFC_EVT_ELS_ABORT_CMPL" ; + +case EFC_EVT_DOMAIN_FOUND : +return "EFC_EVT_DOMAIN_FOUND" ; +case EFC_EVT_DOMAIN_ALLOC_OK : +return "EFC_EVT_DOMAIN_ALLOC_OK" ; +case EFC_EVT_DOMAIN_ALLOC_FAIL : +return "EFC_EVT_DOMAIN_ALLOC_FAIL" ; +case EFC_EVT_DOMAIN_REQ_ATTACH : +return "EFC_EVT_DOMAIN_REQ_ATTACH" ; +case EFC_EVT_DOMAIN_ATTACH_OK : +return "EFC_EVT_DOMAIN_ATTACH_OK" ; +case EFC_EVT_DOMAIN_ATTACH_FAIL : +return "EFC_EVT_DOMAIN_ATTACH_FAIL" ; +case EFC_EVT_DOMAIN_LOST : +return "EFC_EVT_DOMAIN_LOST" ; +case EFC_EVT_DOMAIN_FREE_OK : +return "EFC_EVT_DOMAIN_FREE_OK" ; +case EFC_EVT_DOMAIN_FREE_FAIL : +return "EFC_EVT_DOMAIN_FREE_FAIL" ; +case EFC_EVT_HW_DOMAIN_REQ_ATTACH : +return "EFC_EVT_HW_DOMAIN_REQ_ATTACH" ; +case EFC_EVT_HW_DOMAIN_REQ_FREE : +return "EFC_EVT_HW_DOMAIN_REQ_FREE" ; +case EFC_EVT_ALL_CHILD_NODES_FREE : +return "EFC_EVT_ALL_CHILD_NODES_FREE" ; + +case EFC_EVT_SPORT_ALLOC_OK : +return "EFC_EVT_SPORT_ALLOC_OK" ; +case EFC_EVT_SPORT_ALLOC_FAIL : +return "EFC_EVT_SPORT_ALLOC_FAIL" ; +case EFC_EVT_SPORT_ATTACH_OK : +return "EFC_EVT_SPORT_ATTACH_OK" ; +case EFC_EVT_SPORT_ATTACH_FAIL : +return "EFC_EVT_SPORT_ATTACH_FAIL" ; +case EFC_EVT_SPORT_FREE_OK : +return "EFC_EVT_SPORT_FREE_OK" ; +case EFC_EVT_SPORT_FREE_FAIL : +return "EFC_EVT_SPORT_FREE_FAIL" ; +case EFC_EVT_SPORT_TOPOLOGY_NOTIFY : +return "EFC_EVT_SPORT_TOPOLOGY_NOTIFY" ; +case EFC_EVT_HW_PORT_ALLOC_OK : +return "EFC_EVT_HW_PORT_ALLOC_OK" ; +case EFC_EVT_HW_PORT_ALLOC_FAIL : +return "EFC_EVT_HW_PORT_ALLOC_FAIL" ; +case EFC_EVT_HW_PORT_ATTACH_OK : +return "EFC_EVT_HW_PORT_ATTACH_OK" ; +case EFC_EVT_HW_PORT_REQ_ATTACH : +return "EFC_EVT_HW_PORT_REQ_ATTACH" ; +case EFC_EVT_HW_PORT_REQ_FREE : +return "EFC_EVT_HW_PORT_REQ_FREE" ; +case EFC_EVT_HW_PORT_FREE_OK : +return "EFC_EVT_HW_PORT_FREE_OK" ; + +case EFC_EVT_NODE_FREE_FAIL : +return "EFC_EVT_NODE_FREE_FAIL" ; + +case EFC_EVT_ABTS_RCVD : +return "EFC_EVT_ABTS_RCVD" ; + +case EFC_EVT_NODE_MISSING : +return "EFC_EVT_NODE_MISSING" ; +case EFC_EVT_NODE_REFOUND : +return "EFC_EVT_NODE_REFOUND" ; +case EFC_EVT_SHUTDOWN_IMPLICIT_LOGO : +return "EFC_EVT_SHUTDOWN_IMPLICIT_LOGO" ; +case EFC_EVT_SHUTDOWN_EXPLICIT_LOGO : +return "EFC_EVT_SHUTDOWN_EXPLICIT_LOGO" ; + +case EFC_EVT_ELS_FRAME : +return "EFC_EVT_ELS_FRAME" ; +case EFC_EVT_PLOGI_RCVD : +return "EFC_EVT_PLOGI_RCVD" ; +case EFC_EVT_FLOGI_RCVD : +return "EFC_EVT_FLOGI_RCVD" ; +case EFC_EVT_LOGO_RCVD : +return "EFC_EVT_LOGO_RCVD" ; +case EFC_EVT_PRLI_RCVD : +return "EFC_EVT_PRLI_RCVD" ; +case EFC_EVT_PRLO_RCVD : +return "EFC_EVT_PRLO_RCVD" ; +case EFC_EVT_PDISC_RCVD : +return "EFC_EVT_PDISC_RCVD" ; +case EFC_EVT_FDISC_RCVD : +return "EFC_EVT_FDISC_RCVD" ; +case EFC_EVT_ADISC_RCVD : +return "EFC_EVT_ADISC_RCVD" ; +case EFC_EVT_RSCN_RCVD : +return "EFC_EVT_RSCN_RCVD" ; +case EFC_EVT_SCR_RCVD : +return "EFC_EVT_SCR_RCVD" ; +case EFC_EVT_ELS_RCVD : +return "EFC_EVT_ELS_RCVD" ; +case EFC_EVT_LAST : +return "EFC_EVT_LAST" ; +case EFC_EVT_FCP_CMD_RCVD : +return "EFC_EVT_FCP_CMD_RCVD" ; + +case EFC_EVT_GIDPT_DELAY_EXPIRED : +return "EFC_EVT_GIDPT_DELAY_EXPIRED" ; + +case EFC_EVT_NODE_ACTIVE_IO_LIST_EMPTY : +return "EFC_EVT_NODE_ACTIVE_IO_LIST_EMPTY" ; +case EFC_EVT_NODE_DEL_INI_COMPLETE : +return "EFC_EVT_NODE_DEL_INI_COMPLETE" ; +case EFC_EVT_NODE_DEL_TGT_COMPLETE : +return "EFC_EVT_NODE_DEL_TGT_COMPLETE" ; + +default : +break ; + } +return "unknown" ; +}
drivers/scsi/elx/libefc/efc_sm.h new file +140 -0
140 lines not on this page · raw message
Signature · 1 line
2.13.7
Re: [PATCH v2 08/32] elx: libefc: Generic state machine framework
Quoted 226 lines · James Smart
This 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.
Signed-off-by Ram Vegesna <[email protected]>Signed-off-by James Smart <[email protected]>--- drivers/scsi/elx/libefc/efc_sm.c | 213 +++++++++++++++++++++++++++++++++++++++ drivers/scsi/elx/libefc/efc_sm.h | 140 +++++++++++++++++++++++++ 2 files changed, 353 insertions(+) create mode 100644 drivers/scsi/elx/libefc/efc_sm.c create mode 100644 drivers/scsi/elx/libefc/efc_sm.hdrivers/scsi/elx/libefc/efc_sm.c new file +203
-0@@ -0,0 +1,213 @@ +// SPDX-License-Identifier: GPL-2.0 +/* +* Copyright (C) 2019 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" + +const char *efc_sm_id[] = { +"common" , +"domain" , +"login" +}; + +/** +* 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) { + ctx->current_state (ctx, evt, data); +return 0 ; + }else { +return -1 ; + } +} + +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); + } +} + +void +efc_sm_disable (struct efc_sm_ctx *ctx) +{ + ctx->current_state =NULL ; +} + +const char *efc_sm_event_name (enum efc_sm_event evt) +{ +switch (evt) { +case EFC_EVT_ENTER : +return "EFC_EVT_ENTER" ; +case EFC_EVT_REENTER : +return "EFC_EVT_REENTER" ; +case EFC_EVT_EXIT : +return "EFC_EVT_EXIT" ; +case EFC_EVT_SHUTDOWN : +return "EFC_EVT_SHUTDOWN" ; +case EFC_EVT_RESPONSE : +return "EFC_EVT_RESPONSE" ; +case EFC_EVT_RESUME : +return "EFC_EVT_RESUME" ; +case EFC_EVT_TIMER_EXPIRED : +return "EFC_EVT_TIMER_EXPIRED" ; +case EFC_EVT_ERROR : +return "EFC_EVT_ERROR" ; +case EFC_EVT_SRRS_ELS_REQ_OK : +return "EFC_EVT_SRRS_ELS_REQ_OK" ; +case EFC_EVT_SRRS_ELS_CMPL_OK : +return "EFC_EVT_SRRS_ELS_CMPL_OK" ; +case EFC_EVT_SRRS_ELS_REQ_FAIL : +return "EFC_EVT_SRRS_ELS_REQ_FAIL" ; +case EFC_EVT_SRRS_ELS_CMPL_FAIL : +return "EFC_EVT_SRRS_ELS_CMPL_FAIL" ; +case EFC_EVT_SRRS_ELS_REQ_RJT : +return "EFC_EVT_SRRS_ELS_REQ_RJT" ; +case EFC_EVT_NODE_ATTACH_OK : +return "EFC_EVT_NODE_ATTACH_OK" ; +case EFC_EVT_NODE_ATTACH_FAIL : +return "EFC_EVT_NODE_ATTACH_FAIL" ; +case EFC_EVT_NODE_FREE_OK : +return "EFC_EVT_NODE_FREE_OK" ; +case EFC_EVT_ELS_REQ_TIMEOUT : +return "EFC_EVT_ELS_REQ_TIMEOUT" ; +case EFC_EVT_ELS_REQ_ABORTED : +return "EFC_EVT_ELS_REQ_ABORTED" ; +case EFC_EVT_ABORT_ELS : +return "EFC_EVT_ABORT_ELS" ; +case EFC_EVT_ELS_ABORT_CMPL : +return "EFC_EVT_ELS_ABORT_CMPL" ; + +case EFC_EVT_DOMAIN_FOUND : +return "EFC_EVT_DOMAIN_FOUND" ; +case EFC_EVT_DOMAIN_ALLOC_OK : +return "EFC_EVT_DOMAIN_ALLOC_OK" ; +case EFC_EVT_DOMAIN_ALLOC_FAIL : +return "EFC_EVT_DOMAIN_ALLOC_FAIL" ; +case EFC_EVT_DOMAIN_REQ_ATTACH : +return "EFC_EVT_DOMAIN_REQ_ATTACH" ; +case EFC_EVT_DOMAIN_ATTACH_OK : +return "EFC_EVT_DOMAIN_ATTACH_OK" ; +case EFC_EVT_DOMAIN_ATTACH_FAIL : +return "EFC_EVT_DOMAIN_ATTACH_FAIL" ; +case EFC_EVT_DOMAIN_LOST : +return "EFC_EVT_DOMAIN_LOST" ; +case EFC_EVT_DOMAIN_FREE_OK : +return "EFC_EVT_DOMAIN_FREE_OK" ; +case EFC_EVT_DOMAIN_FREE_FAIL : +return "EFC_EVT_DOMAIN_FREE_FAIL" ; +case EFC_EVT_HW_DOMAIN_REQ_ATTACH : +return "EFC_EVT_HW_DOMAIN_REQ_ATTACH" ; +case EFC_EVT_HW_DOMAIN_REQ_FREE : +return "EFC_EVT_HW_DOMAIN_REQ_FREE" ; +case EFC_EVT_ALL_CHILD_NODES_FREE : +return "EFC_EVT_ALL_CHILD_NODES_FREE" ; + +case EFC_EVT_SPORT_ALLOC_OK : +return "EFC_EVT_SPORT_ALLOC_OK" ; +case EFC_EVT_SPORT_ALLOC_FAIL : +return "EFC_EVT_SPORT_ALLOC_FAIL" ; +case EFC_EVT_SPORT_ATTACH_OK : +return "EFC_EVT_SPORT_ATTACH_OK" ; +case EFC_EVT_SPORT_ATTACH_FAIL : +return "EFC_EVT_SPORT_ATTACH_FAIL" ; +case EFC_EVT_SPORT_FREE_OK : +return "EFC_EVT_SPORT_FREE_OK" ; +case EFC_EVT_SPORT_FREE_FAIL : +return "EFC_EVT_SPORT_FREE_FAIL" ; +case EFC_EVT_SPORT_TOPOLOGY_NOTIFY : +return "EFC_EVT_SPORT_TOPOLOGY_NOTIFY" ; +case EFC_EVT_HW_PORT_ALLOC_OK : +return "EFC_EVT_HW_PORT_ALLOC_OK" ; +case EFC_EVT_HW_PORT_ALLOC_FAIL : +return "EFC_EVT_HW_PORT_ALLOC_FAIL" ; +case EFC_EVT_HW_PORT_ATTACH_OK : +return "EFC_EVT_HW_PORT_ATTACH_OK" ; +case EFC_EVT_HW_PORT_REQ_ATTACH : +return "EFC_EVT_HW_PORT_REQ_ATTACH" ; +case EFC_EVT_HW_PORT_REQ_FREE : +return "EFC_EVT_HW_PORT_REQ_FREE" ; +case EFC_EVT_HW_PORT_FREE_OK : +return "EFC_EVT_HW_PORT_FREE_OK" ; + +case EFC_EVT_NODE_FREE_FAIL : +return "EFC_EVT_NODE_FREE_FAIL" ; + +case EFC_EVT_ABTS_RCVD : +return "EFC_EVT_ABTS_RCVD" ; + +case EFC_EVT_NODE_MISSING : +return "EFC_EVT_NODE_MISSING" ; +case EFC_EVT_NODE_REFOUND : +return "EFC_EVT_NODE_REFOUND" ; +case EFC_EVT_SHUTDOWN_IMPLICIT_LOGO : +return "EFC_EVT_SHUTDOWN_IMPLICIT_LOGO" ; +case EFC_EVT_SHUTDOWN_EXPLICIT_LOGO : +return "EFC_EVT_SHUTDOWN_EXPLICIT_LOGO" ; + +case EFC_EVT_ELS_FRAME : +return "EFC_EVT_ELS_FRAME" ; +case EFC_EVT_PLOGI_RCVD : +return "EFC_EVT_PLOGI_RCVD" ; +case EFC_EVT_FLOGI_RCVD : +return "EFC_EVT_FLOGI_RCVD" ; +case EFC_EVT_LOGO_RCVD : +return "EFC_EVT_LOGO_RCVD" ; +case EFC_EVT_PRLI_RCVD : +return "EFC_EVT_PRLI_RCVD" ; +case EFC_EVT_PRLO_RCVD : +return "EFC_EVT_PRLO_RCVD" ; +case EFC_EVT_PDISC_RCVD : +return "EFC_EVT_PDISC_RCVD" ; +case EFC_EVT_FDISC_RCVD : +return "EFC_EVT_FDISC_RCVD" ; +case EFC_EVT_ADISC_RCVD : +return "EFC_EVT_ADISC_RCVD" ; +case EFC_EVT_RSCN_RCVD : +return "EFC_EVT_RSCN_RCVD" ; +case EFC_EVT_SCR_RCVD : +return "EFC_EVT_SCR_RCVD" ; +case EFC_EVT_ELS_RCVD : +return "EFC_EVT_ELS_RCVD" ; +case EFC_EVT_LAST : +return "EFC_EVT_LAST" ; +case EFC_EVT_FCP_CMD_RCVD : +return "EFC_EVT_FCP_CMD_RCVD" ; + +case EFC_EVT_GIDPT_DELAY_EXPIRED : +return "EFC_EVT_GIDPT_DELAY_EXPIRED" ; + +case EFC_EVT_NODE_ACTIVE_IO_LIST_EMPTY : +return "EFC_EVT_NODE_ACTIVE_IO_LIST_EMPTY" ;
drivers/scsi/elx/libefc/efc_sm.c line 213
Quoted 10 lines
drivers/scsi/elx/libefc/efc_sm.c new file +10
-0+case EFC_EVT_NODE_DEL_INI_COMPLETE : +return "EFC_EVT_NODE_DEL_INI_COMPLETE" ; +case EFC_EVT_NODE_DEL_TGT_COMPLETE : +return "EFC_EVT_NODE_DEL_TGT_COMPLETE" ; + +default : +break ; + } +return "unknown" ; +}
Please convert into a lookup array.
Quoted 26 lines
drivers/scsi/elx/libefc/efc_sm.h new file +20
-0@@ -0,0 +1,140 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* +* Copyright (C) 2019 Broadcom. All Rights Reserved. The term +* “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. +* +*/ + +/** +* Generic state machine framework declarations. +*/ + +#ifndef _EFC_SM_H +#define _EFC_SM_H + +/** +* State Machine (SM) IDs. +*/ +enum { +EFC_SM_COMMON =0 , + EFC_SM_DOMAIN,
drivers/scsi/elx/libefc/efc_sm.h line 30
Quoted 10 lines
drivers/scsi/elx/libefc/efc_sm.h new file +10
-0+EFC_SM_PORT , +EFC_SM_LOGIN , + EFC_SM_LAST +}; + +#define EFC_SM_EVENT_SHIFT 24 +#define EFC_SM_EVENT_START (id) ((id) << EFC_SM_EVENT_SHIFT) + +extern const char *efc_sm_id[]; +
Curious.
You define 4 state machine IDs, yet declare names for only 3 of them. Omission?
And I would probably use a lookup function for the state machines; this 'const char *efc_sm_id[]' looks a bit lonely. Plus I'm always wary of variable sized global const ...
Cheers,
Hannes
Signature · 4 lines
Dr. Hannes Reinecke Teamlead Storage & Networking [email protected] +49 911 74053 688 SUSE Software Solutions Germany GmbH, Maxfeldstr. 5, 90409 Nürnberg HRB 36809 (AG Nürnberg), GF: Felix Imendörffer
PATCH v2 9/32 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
- A sparse vector interface that manages lookup tables for the objects.
--- drivers/scsi/elx/libefc/efc.h | 99 ++++++ drivers/scsi/elx/libefc/efc_lib.c | 131 ++++++++ drivers/scsi/elx/libefc/efclib.h | 637 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 867 insertions(+) create mode 100644 drivers/scsi/elx/libefc/efc.h create mode 100644 drivers/scsi/elx/libefc/efc_lib.c create mode 100644 drivers/scsi/elx/libefc/efclib.h
drivers/scsi/elx/libefc/efc.h new file +99 -0
@@ -0,0 +1,99 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* +* Copyright (C) 2019 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_domain.h" +#include "efc_sport.h" +#include "efc_node.h" +#include "efc_fabric.h" +#include "efc_device.h" + +#define EFC_MAX_REMOTE_NODES 2048 + +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 + +/* Timeouts */ +#define EFC_FC_ELS_SEND_DEFAULT_TIMEOUT 0 +#define EFC_FC_FLOGI_TIMEOUT_SEC 5 +#define EFC_FC_DOMAIN_SHUTDOWN_TIMEOUT_USEC 30000000 + +#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\n", node->display_name, efc_sm_event_name(evt)) \ + +#define sport_sm_trace (sport) \ + efc_log_debug(sport->efc, \ + "[%s] %-20s\n", sport->display_name, efc_sm_event_name(evt)) \ + +/** +* Sparse Vector API +* +* This is a trimmed down sparse vector implementation tuned to the problem of +* 24-bit FC_IDs. In this case, the 24-bit index value is broken down in three +* 8-bit values. These values are used to index up to three 256 element arrays. +* Arrays are allocated, only when needed. @n @n +* The lookup can complete in constant time (3 indexed array references). @n @n +* A typical use case would be that the fabric/directory FC_IDs would cause two +* rows to be allocated, and the fabric assigned remote nodes would cause two +* rows to be allocated, with the root row always allocated. This gives five +* rows of 256 x sizeof(void*), resulting in 10k. +*/ + +struct sparse_vector { +struct efc *efc; +u32 max_idx; +void **array; +}; + +#define SPV_ROWLEN 256 +#define SPV_DIM 3 + +void efc_spv_del (struct sparse_vector *spv); +struct sparse_vector *efc_spv_new (struct efc *efc); +void efc_spv_set (struct sparse_vector *sv,u32 idx,void *value); +void *efc_spv_get (struct sparse_vector *sv,u32 idx); + +#endif /* __EFC_H__ */
drivers/scsi/elx/libefc/efc_lib.c new file +131 -0
131 lines not on this page · raw message
drivers/scsi/elx/libefc/efclib.h new file +637 -0
637 lines not on this page · raw message
Signature · 1 line
2.13.7
Re: [PATCH v2 09/32] elx: libefc: Emulex FC discovery library APIs and definitions
Quoted 48 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) objects
- A sparse vector interface that manages lookup tables for the objects.Signed-off-by Ram Vegesna <[email protected]>Signed-off-by James Smart <[email protected]>--- drivers/scsi/elx/libefc/efc.h | 99 ++++++ drivers/scsi/elx/libefc/efc_lib.c | 131 ++++++++ drivers/scsi/elx/libefc/efclib.h | 637 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 867 insertions(+) create mode 100644 drivers/scsi/elx/libefc/efc.h create mode 100644 drivers/scsi/elx/libefc/efc_lib.c create mode 100644 drivers/scsi/elx/libefc/efclib.hdrivers/scsi/elx/libefc/efc.h new file +22
-0@@ -0,0 +1,99 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* +* Copyright (C) 2019 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_domain.h" +#include "efc_sport.h" +#include "efc_node.h" +#include "efc_fabric.h" +#include "efc_device.h" + +#define EFC_MAX_REMOTE_NODES 2048 + +enum efc_hw_rtn { + EFC_HW_RTN_SUCCESS = 0,
drivers/scsi/elx/libefc/efc.h line 32
Quoted 10 lines
drivers/scsi/elx/libefc/efc.h new file +10
-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, +}; +
(Silent applause for the named enum :-)
Quoted 35 lines
drivers/scsi/elx/libefc/efc.h new file +35
-0+#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 + +/* Timeouts */ +#define EFC_FC_ELS_SEND_DEFAULT_TIMEOUT 0 +#define EFC_FC_FLOGI_TIMEOUT_SEC 5 +#define EFC_FC_DOMAIN_SHUTDOWN_TIMEOUT_USEC 30000000 + +#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\n", node->display_name, efc_sm_event_name(evt)) \ + +#define sport_sm_trace (sport) \
drivers/scsi/elx/libefc/efc.h line 77
Quoted 10 lines
drivers/scsi/elx/libefc/efc.h new file +10
-0+efc_log_debug (sport->efc, \ +"[%s] %-20s\n" , sport->display_name,efc_sm_event_name (evt)) \ + +/** +* Sparse Vector API +* +* This is a trimmed down sparse vector implementation tuned to the problem of +* 24-bit FC_IDs. In this case, the 24-bit index value is broken down in three +* 8-bit values. These values are used to index up to three 256 element arrays. +* Arrays are allocated, only when needed. @n @n
@n @n ?
Quoted 6 lines
drivers/scsi/elx/libefc/efc.h new file +6
-0+* The lookup can complete in constant time (3 indexed array references). @n @n +* A typical use case would be that the fabric/directory FC_IDs would cause two +* rows to be allocated, and the fabric assigned remote nodes would cause two +* rows to be allocated, with the root row always allocated. This gives five +* rows of 256 x sizeof(void*), resulting in 10k. +*/
drivers/scsi/elx/libefc/efc.h line 93
Quoted 10 lines
drivers/scsi/elx/libefc/efc.h new file +10
-0+ +struct sparse_vector { +struct efc *efc; +u32 max_idx; +void **array; +}; + +#define SPV_ROWLEN 256 +#define SPV_DIM 3 +
Hmm. One wonders if xarrays wouldn't work better (and simpler to implement).
Have you looked at that?
Quoted 133 lines
drivers/scsi/elx/libefc/efc.h new file +6
-0+void efc_spv_del (struct sparse_vector *spv); +struct sparse_vector *efc_spv_new (struct efc *efc); +void efc_spv_set (struct sparse_vector *sv,u32 idx,void *value); +void *efc_spv_get (struct sparse_vector *sv,u32 idx); + +#endif /* __EFC_H__ */ drivers/scsi/elx/libefc/efc_lib.c new file +121
-0@@ -0,0 +1,131 @@ +// SPDX-License-Identifier: GPL-2.0 +/* +* Copyright (C) 2019 Broadcom. All Rights Reserved. The term +* “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. +*/ + +#include <linux/module.h> +#include <linux/kernel.h> +#include "efc.h" + +int efcport_init (struct efc *efc) +{ +u32 rc =0 ; + +spin_lock_init (&efc->lock); +INIT_LIST_HEAD (&efc->vport_list); + +/* Create Node pool */ + rc =efc_node_create_pool (efc,EFC_MAX_REMOTE_NODES ); +if (rc) +efc_log_err (efc,"Can't allocate node pool\n" ); + +return rc; +} + +void efcport_destroy (struct efc *efc) +{ +efc_node_free_pool (efc); +} + +static void **efc_spv_new_row (u32 rowcount) +{ +return kzalloc (sizeof (void *) * rowcount,GFP_ATOMIC ); +} + +/* Recursively delete the rows in this sparse vector */ +static void +_efc_spv_del (struct efc *efc,void **a,u32 n,u32 depth) +{ +if (a) { +if (depth) { +u32 i; + +for (i =0 ; i < n; i++) +_efc_spv_del (efc, a[i], n, depth -1 ); + +kfree (a); + } + } +} + +void +efc_spv_del (struct sparse_vector *spv) +{ +if (spv) { +_efc_spv_del (spv->efc, spv->array,SPV_ROWLEN ,SPV_DIM ); +kfree (spv); + } +} + +struct sparse_vector +*efc_spv_new (struct efc *efc) +{ +struct sparse_vector *spv; +u32 i; + + spv =kzalloc (sizeof (*spv),GFP_ATOMIC ); +if (!spv) +return NULL ; + + spv->efc = efc; + spv->max_idx =1 ; +for (i =0 ; i <SPV_DIM ; i++) + spv->max_idx *=SPV_ROWLEN ; + +return spv; +} + +static void +*efc_spv_new_cell (struct sparse_vector *sv,u32 idx,bool alloc_new_rows) +{ +void **p; +u32 a = (idx >>16 ) &0xff ; +u32 b = (idx >>8 ) &0xff ; +u32 c = (idx >>0 ) &0xff ; + +if (idx >= sv->max_idx) +return NULL ; + +if (!sv->array) { + sv->array = (alloc_new_rows ? +efc_spv_new_row (SPV_ROWLEN ) :NULL ); +if (!sv->array) +return NULL ; + } + p = sv->array; +if (!p[a]) { + p[a] = (alloc_new_rows ?efc_spv_new_row (SPV_ROWLEN ) :NULL ); +if (!p[a]) +return NULL ; + } + p = p[a]; +if (!p[b]) { + p[b] = (alloc_new_rows ?efc_spv_new_row (SPV_ROWLEN ) :NULL ); +if (!p[b]) +return NULL ; + } + p = p[b]; + +return &p[c]; +} + +void +efc_spv_set (struct sparse_vector *sv,u32 idx,void *value) +{ +void **ref =efc_spv_new_cell (sv, idx, true); + +if (ref) + *ref = value; +} +
drivers/scsi/elx/libefc/efc_lib.c line 131
Quoted 10 lines
drivers/scsi/elx/libefc/efc_lib.c new file +10
-0+void +*efc_spv_get (struct sparse_vector *sv,u32 idx) +{ +void **ref =efc_spv_new_cell (sv, idx, false); + +if (ref) +return *ref; + +return NULL ; +}
What about locking?
But maybe it'll clarify itself with the next patches. Let's see.
Cheers,
Hannes
Signature · 4 lines
Dr. Hannes Reinecke Teamlead Storage & Networking [email protected] +49 911 74053 688 SUSE Software Solutions Germany GmbH, Maxfeldstr. 5, 90409 Nürnberg HRB 36809 (AG Nürnberg), GF: Felix Imendörffer
PATCH v2 10/32 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
--- drivers/scsi/elx/libefc/efc_domain.c | 1126 ++++++++++++++++++++++++++++++++++ drivers/scsi/elx/libefc/efc_domain.h | 52 ++ 2 files changed, 1178 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 +1126 -0
@@ -0,0 +1,1126 @@ +// SPDX-License-Identifier: GPL-2.0 +/* +* Copyright (C) 2019 Broadcom. All Rights Reserved. The term +* “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. +*/ + +/* +* domain_sm Domain State Machine: States +*/ + +#include "efc.h" + +/* Accept domain callback events from the user driver */ +int +efc_domain_cb (void *arg,int event,void *data) +{ +struct efc *efc = arg; +struct efc_domain *domain =NULL ; +int rc =0 ; + +if (event !=EFC_HW_DOMAIN_FOUND ) + domain = data; + +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 allocated: wwn %016llX\n" , fcf_wwn); +/* +* lookup domain, or allocate a new one +* if one doesn't exist already +*/ + 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 ); + } + +if (fcf_wwn != domain->fcf_wwn) { +efc_log_err (efc,"evt: FOUND for existing domain\n" ); +efc_log_err (efc,"wwn:%016llX domain wwn:%016llX\n" , + fcf_wwn, domain->fcf_wwn); + } + +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->tt.domain_hold_frames (efc, domain); +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); + } + +return rc; +} + +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) { + domain->efc = efc; + domain->drvsm.app = domain; + +/* Allocate a sparse vector for sport FC_ID's */ + domain->lookup =efc_spv_new (efc); +if (!domain->lookup) { +efc_log_err (efc,"efc_spv_new() failed\n" ); +kfree (domain); +return NULL ; + } + +INIT_LIST_HEAD (&domain->sport_list); + domain->fcf_wwn = fcf_wwn; +efc_log_debug (efc,"Domain allocated: wwn %016llX\n" , + domain->fcf_wwn); + efc->domain = domain; + }else { +efc_log_err (efc,"domain allocation failed\n" ); + } + +return 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->tt.domain_hold_frames (efc, domain); + +efc_log_debug (efc,"Domain free: wwn %016llX\n" , + domain->fcf_wwn); + +efc_spv_del (domain->lookup); + domain->lookup =NULL ; + efc->domain =NULL ; + +if (efc->domain_free_cb) + (*efc->domain_free_cb)(efc, efc->domain_free_cb_arg); + +kfree (domain); +} + +/* Free memory resources of a domain object */ +void +efc_domain_force_free (struct efc_domain *domain) +{ +struct efc_sli_port *sport; +struct efc_sli_port *next; +struct efc *efc = domain->efc; + +/* Shutdown domain sm */ +efc_sm_disable (&domain->drvsm); + +list_for_each_entry_safe (sport, next, &domain->sport_list, list_entry) { +efc_sport_force_free (sport); + } + + efc->tt.hw_domain_force_free (efc, domain); +efc_domain_free (domain); +} + +/* Register a callback to be called when the domain is freed */ +void +efc_register_domain_free_cb (struct efc *efc, +void (*callback)(struct efc *efc,void *arg), +void *arg) +{ + 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 SPORT, +* and the SPORT is shutdown +*/ +break ; +default : +efc_log_warn (domain->efc,"%-20s %-20s not handled\n" , + funcname,efc_sm_event_name (evt)); +break ; + } + +return NULL ; +} + +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)); +break ; + } + +return NULL ; +} + +#define std_domain_state_decl (...)\ + struct efc_domain *domain = NULL;\ + struct efc *efc = NULL;\ + \ + efc_assert(ctx, NULL);\ + efc_assert(ctx->app, NULL);\ + domain = ctx->app;\ + efc_assert(domain->efc, NULL);\ + 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_sli_port *sport; + +u64 my_wwnn = efc->req_wwnn; +u64 my_wwpn = efc->req_wwpn; +__be64 be_wwpn; + +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 sport using WWPN %016llX WWNN %016llX\n" , + my_wwpn, my_wwnn); + +/* Allocate a sport and transition to __efc_sport_allocated */ + sport =efc_sport_alloc (domain, my_wwpn, my_wwnn,U32_MAX , + efc->enable_ini, efc->enable_tgt); + +if (!sport) { +efc_log_err (efc,"efc_sport_alloc() failed\n" ); +break ; + } +efc_sm_transition (&sport->sm, __efc_sport_allocated,NULL ); + + be_wwpn =cpu_to_be64 (sport->wwpn); + +/* allocate struct efc_sli_port object for local port +* Note: drec->fc_id is ALPA from read_topology only if loop +*/ +if (efc->tt.hw_port_alloc (efc, sport,NULL , + (uint8_t *)&be_wwpn)) { +efc_log_err (efc,"Can't allocate port\n" ); +efc_sport_free (sport); +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->tt.hw_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); + + sport->fc_id = drec->fc_id; + sport->topology =EFC_SPORT_TOPOLOGY_LOOP ; +snprintf (sport->display_name,sizeof (sport->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 (sport, + 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->tt.hw_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); +return NULL ; + } + +return NULL ; +} + +/* Domain state machine: Wait for the domain allocation to complete */ +void * +__efc_domain_wait_alloc (struct efc_sm_ctx *ctx, +enum efc_sm_event evt,void *arg) +{ +struct efc_sli_port *sport; + +std_domain_state_decl (); + +domain_sm_trace (domain); + +switch (evt) { +case EFC_EVT_DOMAIN_ALLOC_OK : { +struct fc_els_flogi *sp; + + sport = domain->sport; +efc_assert (sport,NULL ); + sp = (struct fc_els_flogi *)sport->service_params; + +/* Save the domain service parameters */ +memcpy (domain->service_params +4 , domain->dma.virt, +sizeof (struct fc_els_flogi ) -4 ); +memcpy (sport->service_params +4 , domain->dma.virt, +sizeof (struct fc_els_flogi ) -4 ); + +/* +* Update the sport's service parameters, +* user might have specified non-default names +*/ + sp->fl_wwpn =cpu_to_be64 (sport->wwpn); + sp->fl_wwnn =cpu_to_be64 (sport->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, sport->fc_id); +break ; + } + { +struct efc_node *node; + +/* alloc fabric node, send FLOGI */ + node =efc_node_find (sport,FC_FID_FLOGI ); +if (node) { +efc_log_err (efc, +"Fabric Controller node already exists\n" ); +break ; + } + node =efc_node_alloc (sport,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); +return NULL ; + } + +return NULL ; +} + +/* Domain state machine: Wait for the domain attach request */ +void * +__efc_domain_allocated (struct efc_sm_ctx *ctx, +enum efc_sm_event evt,void *arg) +{ +int rc =0 ; + +std_domain_state_decl (); + +domain_sm_trace (domain); + +switch (evt) { +case EFC_EVT_DOMAIN_REQ_ATTACH : { +u32 fc_id; + +efc_assert (arg,NULL ); + + fc_id = *((u32 *)arg); +efc_log_debug (efc,"Requesting hw domain attach fc_id x%x\n" , + fc_id); +/* Update sport lookup */ +efc_spv_set (domain->lookup, fc_id, domain->sport); + +/* Update display name for the sport */ +efc_node_fcid_display (fc_id, domain->sport->display_name, +sizeof (domain->sport->display_name)); + +/* Issue domain attach call */ + rc = efc->tt.hw_domain_attach (efc, domain, fc_id); +if (rc) { +efc_log_err (efc,"efc_hw_domain_attach failed: %d\n" , + rc); +return NULL ; + } +/* 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 : { +int rc; + +efc_log_debug (efc, +"%s received while in EFC_EVT_DOMAIN_REQ_ATTACH\n" , +efc_sm_event_name (evt)); +if (!list_empty (&domain->sport_list)) { +/* +* if there are sports, transition to +* wait state and send shutdown to each +* sport +*/ +struct efc_sli_port *sport =NULL ; +struct efc_sli_port *sport_next =NULL ; + +efc_sm_transition (ctx, __efc_domain_wait_sports_free, +NULL ); +list_for_each_entry_safe (sport, sport_next, + &domain->sport_list, + list_entry) { +efc_sm_post_event (&sport->sm, +EFC_EVT_SHUTDOWN ,NULL ); + } + }else { +/* no sports exist, free domain */ +efc_sm_transition (ctx, __efc_domain_wait_shutdown, +NULL ); + rc = efc->tt.hw_domain_free (efc, domain); +if (rc) { +efc_log_err (efc, +"hw_domain_free failed: %d\n" , rc); + } + } + +break ; + } + +default : +__efc_domain_common (__func__, ctx, evt, arg); +return NULL ; + } + +return NULL ; +} + +/* Domain state machine: Wait for the HW domain attach to complete */ +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_node *next_node =NULL ; +struct efc_sli_port *sport; +struct efc_sli_port *next_sport; + +/* +* Set domain notify pending state to avoid +* duplicate domain event post +*/ + domain->domain_notify_pend = true; + +/* Mark as attached */ + domain->attached = true; + +/* Register with SCSI API */ + efc->tt.new_domain (efc, domain); + +/* Transition to ready */ +/* sm: / forward event to all sports 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: sport will have already received notification +* of sport attached as a result of the HW's port attach. +*/ +list_for_each_entry_safe (sport, next_sport, + &domain->sport_list, list_entry) { +list_for_each_entry_safe (node, next_node, + &sport->node_list, + list_entry) { +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); +return NULL ; + } + +return NULL ; +} + +/* Domain state machine: Ready state */ +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 : { +int rc; + +if (!list_empty (&domain->sport_list)) { +/* +* if there are sports, transition to wait state +* and send shutdown to each sport +*/ +struct efc_sli_port *sport =NULL ; +struct efc_sli_port *sport_next =NULL ; + +efc_sm_transition (ctx, __efc_domain_wait_sports_free, +NULL ); +list_for_each_entry_safe (sport, sport_next, + &domain->sport_list, + list_entry) { +efc_sm_post_event (&sport->sm, +EFC_EVT_SHUTDOWN ,NULL ); + } + }else { +/* no sports exist, free domain */ +efc_sm_transition (ctx, __efc_domain_wait_shutdown, +NULL ); + rc = efc->tt.hw_domain_free (efc, domain); +if (rc) { +efc_log_err (efc, +"hw_domain_free failed: %d\n" , rc); + } + } +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 */ +efc_assert (domain->attached,NULL ); + +/* +* Verify that the requested FC_ID +* is the same as the one we're working with +*/ +efc_assert (domain->sport->fc_id == fc_id,NULL ); +break ; + } + +default : +__efc_domain_common (__func__, ctx, evt, arg); +return NULL ; + } + +return NULL ; +} + +/* Domain state machine: Wait for nodes to free prior to the domain shutdown */ +void * +__efc_domain_wait_sports_free (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_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->tt.hw_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); +return NULL ; + } + +return NULL ; +} + +/* Domain state machine: Complete the domain shutdown */ +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 : { + efc->tt.del_domain (efc, domain); + +/* 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 NULL ; + } +/* +* 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); +return NULL ; + } + +return NULL ; +} + +/* +* Domain state machine: Wait for the domain alloc/attach completion +* after receiving a domain lost. +*/ +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); + +switch (evt) { +case EFC_EVT_DOMAIN_ALLOC_OK : +case EFC_EVT_DOMAIN_ATTACH_OK : { +int rc; + +if (!list_empty (&domain->sport_list)) { +/* +* if there are sports, transition to +* wait state and send shutdown to each sport +*/ +struct efc_sli_port *sport =NULL ; +struct efc_sli_port *sport_next =NULL ; + +efc_sm_transition (ctx, __efc_domain_wait_sports_free, +NULL ); +list_for_each_entry_safe (sport, sport_next, + &domain->sport_list, + list_entry) { +efc_sm_post_event (&sport->sm, +EFC_EVT_SHUTDOWN ,NULL ); + } + }else { +/* no sports exist, free domain */ +efc_sm_transition (ctx, __efc_domain_wait_shutdown, +NULL ); + rc = efc->tt.hw_domain_free (efc, domain); +if (rc) { +efc_log_err (efc, +"efc_hw_domain_free() failed: %d\n" , + rc); + } + } +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); +return NULL ; + } + +return NULL ; +} + +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 accept_frames; +bool req_domain_free; +struct efc *efc = domain->efc; + + rc =efc_sm_post_event (&domain->drvsm, event, arg); + + req_domain_free = domain->req_domain_free; + domain->req_domain_free = false; + + accept_frames = domain->req_accept_frames; + domain->req_accept_frames = false; + +if (accept_frames) + efc->tt.domain_accept_frames (efc, domain); + +if (req_domain_free) +efc_domain_free (domain); + +return rc; +} + +/* Dispatch unsolicited FC frame */ +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; +u32 s_id; +u32 d_id; +struct efc_node *node =NULL ; +struct efc_sli_port *sport =NULL ; +unsigned long flags =0 ; + +if (!seq->header || !seq->header->dma.virt || !seq->payload->dma.virt) { +efc_log_err (efc,"Sequence header or payload is null\n" ); +return -1 ; + } + + 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); + + sport = domain->sport; +if (!sport) { +efc_log_err (efc, +"Drop frame, sport for FC ID 0x%06x is NULL" , d_id); +return -1 ; + } + +if (sport->fc_id != d_id) { +/* Not a physical port IO lookup sport associated with the +* npiv port +*/ +/* Look up without lock */ + sport =efc_sport_find (domain, d_id); +if (!sport) { +if (hdr->fh_type ==FC_TYPE_FCP ) { +/* Drop frame */ +efc_log_warn (efc, +"unsolicited FCP frame with invalid d_id x%x\n" , + d_id); +return -1 ; + } +/* p2p will use this case */ + sport = domain->sport; + } + } + +spin_lock_irqsave (&efc->lock, flags); +/* Lookup the node given the remote s_id */ + node =efc_node_find (sport, 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" ); +spin_unlock_irqrestore (&efc->lock, flags); +return -1 ; + } + + node =efc_node_alloc (sport, s_id, false, false); +if (!node) { +efc_log_err (efc,"efc_node_alloc() failed\n" ); +spin_unlock_irqrestore (&efc->lock, flags); +return -1 ; + } +/* don't send PLOGI on efc_d_init entry */ +efc_node_init_device (node, false); + } +spin_unlock_irqrestore (&efc->lock, flags); + +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); + +return 0 ; + } + +/* now dispatch frame to the node frame handler */ +return efc_node_dispatch_frame (node, seq); +} + +int +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; +int rc =-1 ; +int sit_set =0 ; + +struct efc *efc = node->efc; + + port_id =ntoh24 (hdr->fh_s_id); +efc_assert (port_id == node->rnode.fc_id,-1 ); + +if (!(ntoh24 (hdr->fh_f_ctl) &FC_FC_END_SEQ )) { +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 rc; + } + +/*if SIT is set */ +if (ntoh24 (hdr->fh_f_ctl) &FC_FC_SEQ_INIT ) + sit_set =1 ; + +switch (hdr->fh_r_ctl) { +case FC_RCTL_ELS_REQ : +case FC_RCTL_ELS_REP : +if (sit_set) + rc =efc_node_recv_els_frame (node, seq); + +//failure status to release the seq +if (!rc) + rc =2 ; +break ; + +case FC_RCTL_BA_ABTS : +case FC_RCTL_BA_ACC : +case FC_RCTL_BA_RJT : +case FC_RCTL_BA_NOP : +if (sit_set) + rc = efc->tt.recv_abts_frame (efc, node, seq); +else + rc =efc_node_recv_bls_no_sit (node, seq); +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) { + rc =efc_node_recv_fcp_cmd (node, seq); +break ; + } + +if (sit_set) { + rc = efc->tt.dispatch_fcp_cmd (node, + seq); + }else { +node_printf (node, +"Unsol cmd received with no SIT\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 : +if (sit_set) + rc =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); + } + +return rc; +}
drivers/scsi/elx/libefc/efc_domain.h new file +52 -0
52 lines not on this page · raw message
Signature · 1 line
2.13.7
Re: [PATCH v2 10/32] elx: libefc: FC Domain state machine interfaces
Quoted 113 lines · James Smart
This patch continues the libefc library population.
This patch adds library interface definitions for:
- FC Domain registration, allocation and deallocation sequenceSigned-off-by Ram Vegesna <[email protected]>Signed-off-by James Smart <[email protected]>--- drivers/scsi/elx/libefc/efc_domain.c | 1126 ++++++++++++++++++++++++++++++++++ drivers/scsi/elx/libefc/efc_domain.h | 52 ++ 2 files changed, 1178 insertions(+) create mode 100644 drivers/scsi/elx/libefc/efc_domain.c create mode 100644 drivers/scsi/elx/libefc/efc_domain.hdrivers/scsi/elx/libefc/efc_domain.c new file +93
-0@@ -0,0 +1,1126 @@ +// SPDX-License-Identifier: GPL-2.0 +/* +* Copyright (C) 2019 Broadcom. All Rights Reserved. The term +* “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. +*/ + +/* +* domain_sm Domain State Machine: States +*/ + +#include "efc.h" + +/* Accept domain callback events from the user driver */ +int +efc_domain_cb (void *arg,int event,void *data) +{ +struct efc *efc = arg; +struct efc_domain *domain =NULL ; +int rc =0 ; + +if (event !=EFC_HW_DOMAIN_FOUND ) + domain = data; + +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 allocated: wwn %016llX\n" , fcf_wwn); +/* +* lookup domain, or allocate a new one +* if one doesn't exist already +*/ + 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 ); + } + +if (fcf_wwn != domain->fcf_wwn) { +efc_log_err (efc,"evt: FOUND for existing domain\n" ); +efc_log_err (efc,"wwn:%016llX domain wwn:%016llX\n" , + fcf_wwn, domain->fcf_wwn); + } + +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->tt.domain_hold_frames (efc, domain); +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" );
drivers/scsi/elx/libefc/efc_domain.c line 103
Quoted 10 lines
drivers/scsi/elx/libefc/efc_domain.c new file +10
-0+efc_domain_post_event (domain,EFC_EVT_DOMAIN_FREE_FAIL ,NULL ); +break ; + +default : +efc_log_warn (efc,"unsupported event %#x\n" , event); + } + +return rc; +} +
You painfully declared a mapping for all events to strings in efc_sm_event_name(), yet you spell them out here.
Wouldn't the above be a great place to use that function?
It would even simplify the code, as several cases can be collapsed into one ...
Quoted 290 lines
drivers/scsi/elx/libefc/efc_domain.c new file +290
-0+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) { + domain->efc = efc; + domain->drvsm.app = domain; + +/* Allocate a sparse vector for sport FC_ID's */ + domain->lookup =efc_spv_new (efc); +if (!domain->lookup) { +efc_log_err (efc,"efc_spv_new() failed\n" ); +kfree (domain); +return NULL ; + } + +INIT_LIST_HEAD (&domain->sport_list); + domain->fcf_wwn = fcf_wwn; +efc_log_debug (efc,"Domain allocated: wwn %016llX\n" , + domain->fcf_wwn); + efc->domain = domain; + }else { +efc_log_err (efc,"domain allocation failed\n" ); + } + +return 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->tt.domain_hold_frames (efc, domain); + +efc_log_debug (efc,"Domain free: wwn %016llX\n" , + domain->fcf_wwn); + +efc_spv_del (domain->lookup); + domain->lookup =NULL ; + efc->domain =NULL ; + +if (efc->domain_free_cb) + (*efc->domain_free_cb)(efc, efc->domain_free_cb_arg); + +kfree (domain); +} + +/* Free memory resources of a domain object */ +void +efc_domain_force_free (struct efc_domain *domain) +{ +struct efc_sli_port *sport; +struct efc_sli_port *next; +struct efc *efc = domain->efc; + +/* Shutdown domain sm */ +efc_sm_disable (&domain->drvsm); + +list_for_each_entry_safe (sport, next, &domain->sport_list, list_entry) { +efc_sport_force_free (sport); + } + + efc->tt.hw_domain_force_free (efc, domain); +efc_domain_free (domain); +} + +/* Register a callback to be called when the domain is freed */ +void +efc_register_domain_free_cb (struct efc *efc, +void (*callback)(struct efc *efc,void *arg), +void *arg) +{ + 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 SPORT, +* and the SPORT is shutdown +*/ +break ; +default : +efc_log_warn (domain->efc,"%-20s %-20s not handled\n" , + funcname,efc_sm_event_name (evt)); +break ; + } + +return NULL ; +} + +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)); +break ; + } + +return NULL ; +} + +#define std_domain_state_decl (...)\ + struct efc_domain *domain = NULL;\ + struct efc *efc = NULL;\ + \ + efc_assert(ctx, NULL);\ + efc_assert(ctx->app, NULL);\ + domain = ctx->app;\ + efc_assert(domain->efc, NULL);\ + 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_sli_port *sport; + +u64 my_wwnn = efc->req_wwnn; +u64 my_wwpn = efc->req_wwpn; +__be64 be_wwpn; + +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 sport using WWPN %016llX WWNN %016llX\n" , + my_wwpn, my_wwnn); + +/* Allocate a sport and transition to __efc_sport_allocated */ + sport =efc_sport_alloc (domain, my_wwpn, my_wwnn,U32_MAX , + efc->enable_ini, efc->enable_tgt); + +if (!sport) { +efc_log_err (efc,"efc_sport_alloc() failed\n" ); +break ; + } +efc_sm_transition (&sport->sm, __efc_sport_allocated,NULL ); + + be_wwpn =cpu_to_be64 (sport->wwpn); + +/* allocate struct efc_sli_port object for local port +* Note: drec->fc_id is ALPA from read_topology only if loop +*/ +if (efc->tt.hw_port_alloc (efc, sport,NULL , + (uint8_t *)&be_wwpn)) { +efc_log_err (efc,"Can't allocate port\n" ); +efc_sport_free (sport); +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->tt.hw_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); + + sport->fc_id = drec->fc_id; + sport->topology =EFC_SPORT_TOPOLOGY_LOOP ; +snprintf (sport->display_name,sizeof (sport->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 (sport, + 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->tt.hw_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); +return NULL ; + } + +return NULL ; +} + +/* Domain state machine: Wait for the domain allocation to complete */ +void * +__efc_domain_wait_alloc (struct efc_sm_ctx *ctx, +enum efc_sm_event evt,void *arg) +{ +struct efc_sli_port *sport; +
drivers/scsi/elx/libefc/efc_domain.c line 403
Quoted 10 lines
drivers/scsi/elx/libefc/efc_domain.c new file +10
-0+std_domain_state_decl (); + +domain_sm_trace (domain); + +switch (evt) { +case EFC_EVT_DOMAIN_ALLOC_OK : { +struct fc_els_flogi *sp; + + sport = domain->sport; +efc_assert (sport,NULL );
The assert is pretty much pointless; you'll crash anyway in the next line.
if (WARN_ON())
break;
maybe?
Quoted 25 lines
drivers/scsi/elx/libefc/efc_domain.c new file +25
-0+ sp = (struct fc_els_flogi *)sport->service_params; + +/* Save the domain service parameters */ +memcpy (domain->service_params +4 , domain->dma.virt, +sizeof (struct fc_els_flogi ) -4 ); +memcpy (sport->service_params +4 , domain->dma.virt, +sizeof (struct fc_els_flogi ) -4 ); + +/* +* Update the sport's service parameters, +* user might have specified non-default names +*/ + sp->fl_wwpn =cpu_to_be64 (sport->wwpn); + sp->fl_wwnn =cpu_to_be64 (sport->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
drivers/scsi/elx/libefc/efc_domain.c line 438
Quoted 10 lines
drivers/scsi/elx/libefc/efc_domain.c new file +10
-0+* 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, sport->fc_id); +break ; + }
Locking would help ...
Quoted 737 lines
drivers/scsi/elx/libefc/efc_domain.c new file +688
-0+ { +struct efc_node *node; + +/* alloc fabric node, send FLOGI */ + node =efc_node_find (sport,FC_FID_FLOGI ); +if (node) { +efc_log_err (efc, +"Fabric Controller node already exists\n" ); +break ; + } + node =efc_node_alloc (sport,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); +return NULL ; + } + +return NULL ; +} + +/* Domain state machine: Wait for the domain attach request */ +void * +__efc_domain_allocated (struct efc_sm_ctx *ctx, +enum efc_sm_event evt,void *arg) +{ +int rc =0 ; + +std_domain_state_decl (); + +domain_sm_trace (domain); + +switch (evt) { +case EFC_EVT_DOMAIN_REQ_ATTACH : { +u32 fc_id; + +efc_assert (arg,NULL ); + + fc_id = *((u32 *)arg); +efc_log_debug (efc,"Requesting hw domain attach fc_id x%x\n" , + fc_id); +/* Update sport lookup */ +efc_spv_set (domain->lookup, fc_id, domain->sport); + +/* Update display name for the sport */ +efc_node_fcid_display (fc_id, domain->sport->display_name, +sizeof (domain->sport->display_name)); + +/* Issue domain attach call */ + rc = efc->tt.hw_domain_attach (efc, domain, fc_id); +if (rc) { +efc_log_err (efc,"efc_hw_domain_attach failed: %d\n" , + rc); +return NULL ; + } +/* 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 : { +int rc; + +efc_log_debug (efc, +"%s received while in EFC_EVT_DOMAIN_REQ_ATTACH\n" , +efc_sm_event_name (evt)); +if (!list_empty (&domain->sport_list)) { +/* +* if there are sports, transition to +* wait state and send shutdown to each +* sport +*/ +struct efc_sli_port *sport =NULL ; +struct efc_sli_port *sport_next =NULL ; + +efc_sm_transition (ctx, __efc_domain_wait_sports_free, +NULL ); +list_for_each_entry_safe (sport, sport_next, + &domain->sport_list, + list_entry) { +efc_sm_post_event (&sport->sm, +EFC_EVT_SHUTDOWN ,NULL ); + } + }else { +/* no sports exist, free domain */ +efc_sm_transition (ctx, __efc_domain_wait_shutdown, +NULL ); + rc = efc->tt.hw_domain_free (efc, domain); +if (rc) { +efc_log_err (efc, +"hw_domain_free failed: %d\n" , rc); + } + } + +break ; + } + +default : +__efc_domain_common (__func__, ctx, evt, arg); +return NULL ; + } + +return NULL ; +} + +/* Domain state machine: Wait for the HW domain attach to complete */ +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_node *next_node =NULL ; +struct efc_sli_port *sport; +struct efc_sli_port *next_sport; + +/* +* Set domain notify pending state to avoid +* duplicate domain event post +*/ + domain->domain_notify_pend = true; + +/* Mark as attached */ + domain->attached = true; + +/* Register with SCSI API */ + efc->tt.new_domain (efc, domain); + +/* Transition to ready */ +/* sm: / forward event to all sports 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: sport will have already received notification +* of sport attached as a result of the HW's port attach. +*/ +list_for_each_entry_safe (sport, next_sport, + &domain->sport_list, list_entry) { +list_for_each_entry_safe (node, next_node, + &sport->node_list, + list_entry) { +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); +return NULL ; + } + +return NULL ; +} + +/* Domain state machine: Ready state */ +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 : { +int rc; + +if (!list_empty (&domain->sport_list)) { +/* +* if there are sports, transition to wait state +* and send shutdown to each sport +*/ +struct efc_sli_port *sport =NULL ; +struct efc_sli_port *sport_next =NULL ; + +efc_sm_transition (ctx, __efc_domain_wait_sports_free, +NULL ); +list_for_each_entry_safe (sport, sport_next, + &domain->sport_list, + list_entry) { +efc_sm_post_event (&sport->sm, +EFC_EVT_SHUTDOWN ,NULL ); + } + }else { +/* no sports exist, free domain */ +efc_sm_transition (ctx, __efc_domain_wait_shutdown, +NULL ); + rc = efc->tt.hw_domain_free (efc, domain); +if (rc) { +efc_log_err (efc, +"hw_domain_free failed: %d\n" , rc); + } + } +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 */ +efc_assert (domain->attached,NULL ); + +/* +* Verify that the requested FC_ID +* is the same as the one we're working with +*/ +efc_assert (domain->sport->fc_id == fc_id,NULL ); +break ; + } + +default : +__efc_domain_common (__func__, ctx, evt, arg); +return NULL ; + } + +return NULL ; +} + +/* Domain state machine: Wait for nodes to free prior to the domain shutdown */ +void * +__efc_domain_wait_sports_free (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_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->tt.hw_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); +return NULL ; + } + +return NULL ; +} + +/* Domain state machine: Complete the domain shutdown */ +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 : { + efc->tt.del_domain (efc, domain); + +/* 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 NULL ; + } +/* +* 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); +return NULL ; + } + +return NULL ; +} + +/* +* Domain state machine: Wait for the domain alloc/attach completion +* after receiving a domain lost. +*/ +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); + +switch (evt) { +case EFC_EVT_DOMAIN_ALLOC_OK : +case EFC_EVT_DOMAIN_ATTACH_OK : { +int rc; + +if (!list_empty (&domain->sport_list)) { +/* +* if there are sports, transition to +* wait state and send shutdown to each sport +*/ +struct efc_sli_port *sport =NULL ; +struct efc_sli_port *sport_next =NULL ; + +efc_sm_transition (ctx, __efc_domain_wait_sports_free, +NULL ); +list_for_each_entry_safe (sport, sport_next, + &domain->sport_list, + list_entry) { +efc_sm_post_event (&sport->sm, +EFC_EVT_SHUTDOWN ,NULL ); + } + }else { +/* no sports exist, free domain */ +efc_sm_transition (ctx, __efc_domain_wait_shutdown, +NULL ); + rc = efc->tt.hw_domain_free (efc, domain); +if (rc) { +efc_log_err (efc, +"efc_hw_domain_free() failed: %d\n" , + rc); + } + } +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); +return NULL ; + } + +return NULL ; +} + +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 accept_frames; +bool req_domain_free; +struct efc *efc = domain->efc; + + rc =efc_sm_post_event (&domain->drvsm, event, arg); + + req_domain_free = domain->req_domain_free; + domain->req_domain_free = false; + + accept_frames = domain->req_accept_frames; + domain->req_accept_frames = false; + +if (accept_frames) + efc->tt.domain_accept_frames (efc, domain); + +if (req_domain_free) +efc_domain_free (domain); + +return rc; +} + +/* Dispatch unsolicited FC frame */ +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; +u32 s_id; +u32 d_id; +struct efc_node *node =NULL ; +struct efc_sli_port *sport =NULL ; +unsigned long flags =0 ; + +if (!seq->header || !seq->header->dma.virt || !seq->payload->dma.virt) { +efc_log_err (efc,"Sequence header or payload is null\n" ); +return -1 ; + } + + 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); + + sport = domain->sport; +if (!sport) { +efc_log_err (efc, +"Drop frame, sport for FC ID 0x%06x is NULL" , d_id); +return -1 ; + } + +if (sport->fc_id != d_id) { +/* Not a physical port IO lookup sport associated with the +* npiv port +*/ +/* Look up without lock */ + sport =efc_sport_find (domain, d_id); +if (!sport) { +if (hdr->fh_type ==FC_TYPE_FCP ) { +/* Drop frame */ +efc_log_warn (efc, +"unsolicited FCP frame with invalid d_id x%x\n" , + d_id); +return -1 ; + } +/* p2p will use this case */ + sport = domain->sport; + } + } + +spin_lock_irqsave (&efc->lock, flags); +/* Lookup the node given the remote s_id */ + node =efc_node_find (sport, 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" ); +spin_unlock_irqrestore (&efc->lock, flags); +return -1 ; + } + + node =efc_node_alloc (sport, s_id, false, false); +if (!node) { +efc_log_err (efc,"efc_node_alloc() failed\n" ); +spin_unlock_irqrestore (&efc->lock, flags); +return -1 ; + } +/* don't send PLOGI on efc_d_init entry */ +efc_node_init_device (node, false); + } +spin_unlock_irqrestore (&efc->lock, flags); + +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); + +return 0 ; + } + +/* now dispatch frame to the node frame handler */ +return efc_node_dispatch_frame (node, seq); +} + +int +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; +int rc =-1 ; +int sit_set =0 ; + +struct efc *efc = node->efc; + + port_id =ntoh24 (hdr->fh_s_id); +efc_assert (port_id == node->rnode.fc_id,-1 ); + +if (!(ntoh24 (hdr->fh_f_ctl) &FC_FC_END_SEQ )) { +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 rc; + } + +/*if SIT is set */ +if (ntoh24 (hdr->fh_f_ctl) &FC_FC_SEQ_INIT ) + sit_set =1 ; + +switch (hdr->fh_r_ctl) { +case FC_RCTL_ELS_REQ : +case FC_RCTL_ELS_REP : +if (sit_set) + rc =efc_node_recv_els_frame (node, seq); + +//failure status to release the seq +if (!rc) + rc =2 ; +break ; + +case FC_RCTL_BA_ABTS : +case FC_RCTL_BA_ACC : +case FC_RCTL_BA_RJT : +case FC_RCTL_BA_NOP : +if (sit_set) + rc = efc->tt.recv_abts_frame (efc, node, seq); +else + rc =efc_node_recv_bls_no_sit (node, seq); +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) { + rc =efc_node_recv_fcp_cmd (node, seq); +break ; + } + +if (sit_set) { + rc = efc->tt.dispatch_fcp_cmd (node, + seq); + }else { +node_printf (node, +"Unsol cmd received with no SIT\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 : +if (sit_set) + rc =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); + } + +return rc; +}drivers/scsi/elx/libefc/efc_domain.h new file +42
-0@@ -0,0 +1,52 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* +* Copyright (C) 2019 Broadcom. All Rights Reserved. The term +* “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. +*/ + +/* +* Declare driver's domain handler exported interface +*/ + +#ifndef __EFCT_DOMAIN_H__ +#define __EFCT_DOMAIN_H__ + +extern struct efc_domain * +efc_domain_alloc (struct efc *efc,uint64_t fcf_wwn); +extern void +efc_domain_free (struct efc_domain *domain); + +extern void * +__efc_domain_init (struct efc_sm_ctx *ctx, +enum efc_sm_event evt,void *arg); +extern void * +__efc_domain_wait_alloc (struct efc_sm_ctx *ctx, +enum efc_sm_event evt,void *arg); +extern void * +__efc_domain_allocated (struct efc_sm_ctx *ctx, +enum efc_sm_event evt,void *arg); +extern void * +__efc_domain_wait_attach (struct efc_sm_ctx *ctx, +enum efc_sm_event evt,void *arg); +extern void * +__efc_domain_ready (struct efc_sm_ctx *ctx, +enum efc_sm_event evt,void *arg); +extern void * +__efc_domain_wait_sports_free (struct efc_sm_ctx *ctx, +enum efc_sm_event evt,void *arg); +extern void * +__efc_domain_wait_shutdown (struct efc_sm_ctx *ctx, +enum efc_sm_event evt,void *arg); +extern void * +__efc_domain_wait_domain_lost (struct efc_sm_ctx *ctx, +enum efc_sm_event evt,void *arg);
drivers/scsi/elx/libefc/efc_domain.h line 52
Quoted 10 lines
drivers/scsi/elx/libefc/efc_domain.h new file +10
-0+ +extern void +efc_domain_attach (struct efc_domain *domain,u32 s_id); +extern int +efc_domain_post_event (struct efc_domain *domain, +enum efc_sm_event event,void *arg); +extern void +__efc_domain_attach_internal (struct efc_domain *domain,u32 s_id); + +#endif /* __EFCT_DOMAIN_H__ */
What makes me slightly nervous is the complete lack of locking in the domain and sport structures. I could imagine that they are mostly single-threaded, but still I can't see why they wouldn't race with eg lookup sports during interrupt handling.
Can you explain the logic behind it?
Cheers,
Hannes
Signature · 4 lines
Dr. Hannes Reinecke Teamlead Storage & Networking [email protected] +49 911 74053 688 SUSE Software Solutions Germany GmbH, Maxfeldstr. 5, 90409 Nürnberg HRB 36809 (AG Nürnberg), GF: Felix Imendörffer
PATCH v2 11/32 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_sport.c | 843 ++++++++++++++++++++++++++++++++++++ drivers/scsi/elx/libefc/efc_sport.h | 52 +++ 2 files changed, 895 insertions(+) create mode 100644 drivers/scsi/elx/libefc/efc_sport.c create mode 100644 drivers/scsi/elx/libefc/efc_sport.h
drivers/scsi/elx/libefc/efc_sport.c new file +843 -0
@@ -0,0 +1,843 @@ +// SPDX-License-Identifier: GPL-2.0 +/* +* Copyright (C) 2019 Broadcom. All Rights Reserved. The term +* “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. +*/ + +/* +* Details SLI port (sport) functions. +*/ + +#include "efc.h" + +/* HW sport callback events from the user driver */ +int +efc_lport_cb (void *arg,int event,void *data) +{ +struct efc *efc = arg; +struct efc_sli_port *sport = data; + +switch (event) { +case EFC_HW_PORT_ALLOC_OK : +efc_log_debug (efc,"EFC_HW_PORT_ALLOC_OK\n" ); +efc_sm_post_event (&sport->sm,EFC_EVT_SPORT_ALLOC_OK ,NULL ); +break ; +case EFC_HW_PORT_ALLOC_FAIL : +efc_log_debug (efc,"EFC_HW_PORT_ALLOC_FAIL\n" ); +efc_sm_post_event (&sport->sm,EFC_EVT_SPORT_ALLOC_FAIL ,NULL ); +break ; +case EFC_HW_PORT_ATTACH_OK : +efc_log_debug (efc,"EFC_HW_PORT_ATTACH_OK\n" ); +efc_sm_post_event (&sport->sm,EFC_EVT_SPORT_ATTACH_OK ,NULL ); +break ; +case EFC_HW_PORT_ATTACH_FAIL : +efc_log_debug (efc,"EFC_HW_PORT_ATTACH_FAIL\n" ); +efc_sm_post_event (&sport->sm, +EFC_EVT_SPORT_ATTACH_FAIL ,NULL ); +break ; +case EFC_HW_PORT_FREE_OK : +efc_log_debug (efc,"EFC_HW_PORT_FREE_OK\n" ); +efc_sm_post_event (&sport->sm,EFC_EVT_SPORT_FREE_OK ,NULL ); +break ; +case EFC_HW_PORT_FREE_FAIL : +efc_log_debug (efc,"EFC_HW_PORT_FREE_FAIL\n" ); +efc_sm_post_event (&sport->sm,EFC_EVT_SPORT_FREE_FAIL ,NULL ); +break ; +default : +efc_log_test (efc,"unknown event %#x\n" , event); + } + +return 0 ; +} + +struct efc_sli_port * +efc_sport_alloc (struct efc_domain *domain,uint64_t wwpn,uint64_t wwnn, +u32 fc_id,bool enable_ini,bool enable_tgt) +{ +struct efc_sli_port *sport; + +if (domain->efc->enable_ini) + enable_ini =0 ; + +/* Return a failure if this sport has already been allocated */ +if (wwpn !=0 ) { + sport =efc_sport_find_wwn (domain, wwnn, wwpn); +if (sport) { +efc_log_err (domain->efc, +"Failed: SPORT %016llX %016llX already allocated\n" , + wwnn, wwpn); +return NULL ; + } + } + + sport =kzalloc (sizeof (*sport),GFP_ATOMIC ); +if (!sport) +return sport; + + sport->efc = domain->efc; +snprintf (sport->display_name,sizeof (sport->display_name),"------" ); + sport->domain = domain; + sport->lookup =efc_spv_new (domain->efc); + sport->instance_index = domain->sport_instance_count++; +INIT_LIST_HEAD (&sport->node_list); + sport->sm.app = sport; + sport->enable_ini = enable_ini; + sport->enable_tgt = enable_tgt; + sport->enable_rscn = (sport->enable_ini || + (sport->enable_tgt &&enable_target_rscn (sport->efc))); + +/* Copy service parameters from domain */ +memcpy (sport->service_params, domain->service_params, +sizeof (struct fc_els_flogi )); + +/* Update requested fc_id */ + sport->fc_id = fc_id; + +/* Update the sport's service parameters for the new wwn's */ + sport->wwpn = wwpn; + sport->wwnn = wwnn; +snprintf (sport->wwnn_str,sizeof (sport->wwnn_str),"%016llX" , wwnn); + +/* +* if this is the "first" sport of the domain, +* then make it the "phys" sport +*/ +if (list_empty (&domain->sport_list)) + domain->sport = sport; + +INIT_LIST_HEAD (&sport->list_entry); +list_add_tail (&sport->list_entry, &domain->sport_list); + +efc_log_debug (domain->efc,"[%s] allocate sport\n" , + sport->display_name); + +return sport; +} + +void +efc_sport_free (struct efc_sli_port *sport) +{ +struct efc_domain *domain; + +if (!sport) +return ; + + domain = sport->domain; +efc_log_debug (domain->efc,"[%s] free sport\n" , sport->display_name); +list_del (&sport->list_entry); +/* +* if this is the physical sport, +* then clear it out of the domain +*/ +if (sport == domain->sport) + domain->sport =NULL ; + +efc_spv_del (sport->lookup); + sport->lookup =NULL ; + +efc_spv_set (domain->lookup, sport->fc_id,NULL ); + +if (list_empty (&domain->sport_list)) +efc_domain_post_event (domain,EFC_EVT_ALL_CHILD_NODES_FREE , +NULL ); + +kfree (sport); +} + +void +efc_sport_force_free (struct efc_sli_port *sport) +{ +struct efc_node *node; +struct efc_node *next; + +/* shutdown sm processing */ +efc_sm_disable (&sport->sm); + +list_for_each_entry_safe (node, next, &sport->node_list, list_entry) { +efc_node_force_free (node); + } + +efc_sport_free (sport); +} + +/* Find a SLI port object, given an FC_ID */ +struct efc_sli_port * +efc_sport_find (struct efc_domain *domain,u32 d_id) +{ +struct efc_sli_port *sport; + +if (!domain->lookup) { +efc_log_test (domain->efc, +"assertion failed: domain->lookup is not valid\n" ); +return NULL ; + } + + sport =efc_spv_get (domain->lookup, d_id); +return sport; +} + +/* Find a SLI port, given the WWNN and WWPN */ +struct efc_sli_port * +efc_sport_find_wwn (struct efc_domain *domain,uint64_t wwnn,uint64_t wwpn) +{ +struct efc_sli_port *sport =NULL ; + +list_for_each_entry (sport, &domain->sport_list, list_entry) { +if (sport->wwnn == wwnn && sport->wwpn == wwpn) +return sport; + } +return NULL ; +} + +/* External call to request an attach for a sport, given an FC_ID */ +int +efc_sport_attach (struct efc_sli_port *sport,u32 fc_id) +{ +int rc; +struct efc_node *node; +struct efc *efc = sport->efc; + +/* Set our lookup */ +efc_spv_set (sport->domain->lookup, fc_id, sport); + +/* Update our display_name */ +efc_node_fcid_display (fc_id, sport->display_name, +sizeof (sport->display_name)); + +list_for_each_entry (node, &sport->node_list, list_entry) { +efc_node_update_display_name (node); + } + +efc_log_debug (sport->efc,"[%s] attach sport: fc_id x%06x\n" , + sport->display_name, fc_id); + + rc = efc->tt.hw_port_attach (efc, sport, fc_id); +if (rc !=EFC_HW_RTN_SUCCESS ) { +efc_log_err (sport->efc, +"efc_hw_port_attach failed: %d\n" , rc); +return -1 ; + } +return 0 ; +} + +static void +efc_sport_shutdown (struct efc_sli_port *sport) +{ +struct efc *efc = sport->efc; +struct efc_node *node; +struct efc_node *node_next; + +list_for_each_entry_safe (node, node_next, + &sport->node_list, list_entry) { +if (node->rnode.fc_id !=FC_FID_FLOGI || + !sport->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 ); + }else { +efc_log_debug (efc, +"[%s] sport shutdown vport, sending logo to node\n" , + node->display_name); + +if (efc->tt.els_send (efc, node,ELS_LOGO , +EFC_FC_FLOGI_TIMEOUT_SEC , +EFC_FC_ELS_DEFAULT_RETRIES )) { +/* 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 ); + } + } +} + +/* Clear the sport reference in the vport specification */ +static void +efc_vport_link_down (struct efc_sli_port *sport) +{ +struct efc *efc = sport->efc; +struct efc_vport_spec *vport; + +list_for_each_entry (vport, &efc->vport_list, list_entry) { +if (vport->sport == sport) { + vport->sport =NULL ; +break ; + } + } +} + +static void * +__efc_sport_common (const char *funcname,struct efc_sm_ctx *ctx, +enum efc_sm_event evt,void *arg) +{ +struct efc_sli_port *sport = ctx->app; +struct efc_domain *domain = sport->domain; +struct efc *efc = sport->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_SPORT_ATTACH_OK : +efc_sm_transition (ctx, __efc_sport_attached,NULL ); +break ; +case EFC_EVT_SHUTDOWN : { +int node_list_empty; + +/* Flag this sport as shutting down */ + sport->shutting_down = true; + +if (sport->is_vport) +efc_vport_link_down (sport); + + node_list_empty =list_empty (&sport->node_list); + +if (node_list_empty) { +/* sm: node list is empty / efc_hw_port_free */ +/* +* Remove the sport from the domain's +* sparse vector lookup table +*/ +efc_spv_set (domain->lookup, sport->fc_id,NULL ); +efc_sm_transition (ctx, __efc_sport_wait_port_free, +NULL ); +if (efc->tt.hw_port_free (efc, sport)) { +efc_log_test (sport->efc, +"efc_hw_port_free failed\n" ); +/* Not much we can do, free the sport anyways */ +efc_sport_free (sport); + } + }else { +/* sm: node list is not empty / shutdown nodes */ +efc_sm_transition (ctx, + __efc_sport_wait_shutdown,NULL ); +efc_sport_shutdown (sport); + } +break ; + } +default : +efc_log_test (sport->efc,"[%s] %-20s %-20s not handled\n" , + sport->display_name, funcname, +efc_sm_event_name (evt)); +break ; + } + +return NULL ; +} + +/* SLI port state machine: Physical sport allocated */ +void * +__efc_sport_allocated (struct efc_sm_ctx *ctx, +enum efc_sm_event evt,void *arg) +{ +struct efc_sli_port *sport = ctx->app; +struct efc_domain *domain = sport->domain; + +sport_sm_trace (sport); + +switch (evt) { +/* the physical sport is attached */ +case EFC_EVT_SPORT_ATTACH_OK : +efc_assert (sport == domain->sport,NULL ); +efc_sm_transition (ctx, __efc_sport_attached,NULL ); +break ; + +case EFC_EVT_SPORT_ALLOC_OK : +/* ignore */ +break ; +default : +__efc_sport_common (__func__, ctx, evt, arg); +return NULL ; + } +return NULL ; +} + +/* SLI port state machine: Handle initial virtual port events */ +void * +__efc_sport_vport_init (struct efc_sm_ctx *ctx, +enum efc_sm_event evt,void *arg) +{ +struct efc_sli_port *sport = ctx->app; +struct efc *efc = sport->efc; + +sport_sm_trace (sport); + +switch (evt) { +case EFC_EVT_ENTER : { +__be64 be_wwpn =cpu_to_be64 (sport->wwpn); + +if (sport->wwpn ==0 ) +efc_log_debug (efc,"vport: letting f/w select WWN\n" ); + +if (sport->fc_id !=U32_MAX ) { +efc_log_debug (efc,"vport: hard coding port id: %x\n" , + sport->fc_id); + } + +efc_sm_transition (ctx, __efc_sport_vport_wait_alloc,NULL ); +/* If wwpn is zero, then we'll let the f/w */ +if (efc->tt.hw_port_alloc (efc, sport, sport->domain, + sport->wwpn ==0 ?NULL : + (uint8_t *)&be_wwpn)) { +efc_log_err (efc,"Can't allocate port\n" ); +break ; + } + +break ; + } +default : +__efc_sport_common (__func__, ctx, evt, arg); +return NULL ; + } +return NULL ; +} + +/** +* SLI port state machine: +* Wait for the HW SLI port allocation to complete +*/ +void * +__efc_sport_vport_wait_alloc (struct efc_sm_ctx *ctx, +enum efc_sm_event evt,void *arg) +{ +struct efc_sli_port *sport = ctx->app; +struct efc *efc = sport->efc; + +sport_sm_trace (sport); + +switch (evt) { +case EFC_EVT_SPORT_ALLOC_OK : { +struct fc_els_flogi *sp; +struct efc_node *fabric; + + sp = (struct fc_els_flogi *)sport->service_params; +/* +* If we let f/w assign wwn's, +* then sport wwn's with those returned by hw +*/ +if (sport->wwnn ==0 ) { + sport->wwnn =be64_to_cpu (sport->sli_wwnn); + sport->wwpn =be64_to_cpu (sport->sli_wwpn); +snprintf (sport->wwnn_str,sizeof (sport->wwnn_str), +"%016llX" , sport->wwpn); + } + +/* Update the sport's service parameters */ + sp->fl_wwpn =cpu_to_be64 (sport->wwpn); + sp->fl_wwnn =cpu_to_be64 (sport->wwnn); + +/* +* if sport->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 (sport->fc_id ==U32_MAX ) { + fabric =efc_node_alloc (sport,FC_FID_FLOGI , false, + false); +if (!fabric) { +efc_log_err (efc,"efc_node_alloc() failed\n" ); +return NULL ; + } +efc_node_transition (fabric, __efc_vport_fabric_init, +NULL ); + }else { +snprintf (sport->wwnn_str,sizeof (sport->wwnn_str), +"%016llX" , sport->wwpn); +efc_sport_attach (sport, sport->fc_id); + } +efc_sm_transition (ctx, __efc_sport_vport_allocated,NULL ); +break ; + } +default : +__efc_sport_common (__func__, ctx, evt, arg); +return NULL ; + } +return NULL ; +} + +/** +* SLI port state machine: virtual sport allocated. +* +* This state is entered after the sport is allocated; +* it then waits for a fabric node +* FDISC to complete, which requests a sport attach. +* The sport attach complete is handled in this state. +*/ + +void * +__efc_sport_vport_allocated (struct efc_sm_ctx *ctx, +enum efc_sm_event evt,void *arg) +{ +struct efc_sli_port *sport = ctx->app; +struct efc *efc = sport->efc; + +sport_sm_trace (sport); + +switch (evt) { +case EFC_EVT_SPORT_ATTACH_OK : { +struct efc_node *node; + +/* Find our fabric node, and forward this event */ + node =efc_node_find (sport,FC_FID_FLOGI ); +if (!node) { +efc_log_test (efc,"can't find node %06x\n" , +FC_FID_FLOGI ); +break ; + } +/* sm: / forward sport attach to fabric node */ +efc_node_post_event (node, evt,NULL ); +efc_sm_transition (ctx, __efc_sport_attached,NULL ); +break ; + } +default : +__efc_sport_common (__func__, ctx, evt, arg); +return NULL ; + } +return NULL ; +} + +static void +efc_vport_update_spec (struct efc_sli_port *sport) +{ +struct efc *efc = sport->efc; +struct efc_vport_spec *vport; + +list_for_each_entry (vport, &efc->vport_list, list_entry) { +if (vport->sport == sport) { + vport->wwnn = sport->wwnn; + vport->wwpn = sport->wwpn; + vport->tgt_data = sport->tgt_data; + vport->ini_data = sport->ini_data; +break ; + } + } +} + +/* State entered after the sport attach has completed */ +void * +__efc_sport_attached (struct efc_sm_ctx *ctx, +enum efc_sm_event evt,void *arg) +{ +struct efc_sli_port *sport = ctx->app; +struct efc *efc = sport->efc; + +sport_sm_trace (sport); + +switch (evt) { +case EFC_EVT_ENTER : { +struct efc_node *node; + +efc_log_debug (efc, +"[%s] SPORT attached WWPN %016llX WWNN %016llX\n" , + sport->display_name, + sport->wwpn, sport->wwnn); + +list_for_each_entry (node, &sport->node_list, list_entry) { +efc_node_update_display_name (node); + } + + sport->tgt_id = sport->fc_id; + + efc->tt.new_sport (efc, sport); + +/* +* Update the vport (if its not the physical sport) +* parameters +*/ +if (sport->is_vport) +efc_vport_update_spec (sport); +break ; + } + +case EFC_EVT_EXIT : +efc_log_debug (efc, +"[%s] SPORT deattached WWPN %016llX WWNN %016llX\n" , + sport->display_name, + sport->wwpn, sport->wwnn); + + efc->tt.del_sport (efc, sport); +break ; +default : +__efc_sport_common (__func__, ctx, evt, arg); +return NULL ; + } +return NULL ; +} + + +/* SLI port state machine: Wait for the node shutdowns to complete */ +void * +__efc_sport_wait_shutdown (struct efc_sm_ctx *ctx, +enum efc_sm_event evt,void *arg) +{ +struct efc_sli_port *sport = ctx->app; +struct efc_domain *domain = sport->domain; +struct efc *efc = sport->efc; + +sport_sm_trace (sport); + +switch (evt) { +case EFC_EVT_SPORT_ALLOC_OK : +case EFC_EVT_SPORT_ALLOC_FAIL : +case EFC_EVT_SPORT_ATTACH_OK : +case EFC_EVT_SPORT_ATTACH_FAIL : +/* ignore these events - just wait for the all free event */ +break ; + +case EFC_EVT_ALL_CHILD_NODES_FREE : { +/* +* Remove the sport from the domain's +* sparse vector lookup table +*/ +efc_spv_set (domain->lookup, sport->fc_id,NULL ); +efc_sm_transition (ctx, __efc_sport_wait_port_free,NULL ); +if (efc->tt.hw_port_free (efc, sport)) { +efc_log_err (sport->efc,"efc_hw_port_free failed\n" ); +/* Not much we can do, free the sport anyways */ +efc_sport_free (sport); + } +break ; + } +default : +__efc_sport_common (__func__, ctx, evt, arg); +return NULL ; + } +return NULL ; +} + +/* SLI port state machine: Wait for the HW's port free to complete */ +void * +__efc_sport_wait_port_free (struct efc_sm_ctx *ctx, +enum efc_sm_event evt,void *arg) +{ +struct efc_sli_port *sport = ctx->app; + +sport_sm_trace (sport); + +switch (evt) { +case EFC_EVT_SPORT_ATTACH_OK : +/* Ignore as we are waiting for the free CB */ +break ; +case EFC_EVT_SPORT_FREE_OK : { +/* All done, free myself */ +/* sm: / efc_sport_free */ +efc_sport_free (sport); +break ; + } +default : +__efc_sport_common (__func__, ctx, evt, arg); +return NULL ; + } +return NULL ; +} + +/* Use the vport specification to find the associated vports and start them */ +int +efc_vport_start (struct efc_domain *domain) +{ +struct efc *efc = domain->efc; +struct efc_vport_spec *vport; +struct efc_vport_spec *next; +struct efc_sli_port *sport; +int rc =0 ; +u8 found = false; + +list_for_each_entry_safe (vport, next, &efc->vport_list, list_entry) { +if (!vport->sport) { + found = true; +break ; + } + } + +if (found && vport) { + sport =efc_sport_alloc (domain, vport->wwpn, + vport->wwnn, vport->fc_id, + vport->enable_ini, + vport->enable_tgt); + vport->sport = sport; +if (!sport) { + rc =-1 ; + }else { + sport->is_vport = true; + sport->tgt_data = vport->tgt_data; + sport->ini_data = vport->ini_data; + +efc_sm_transition (&sport->sm, __efc_sport_vport_init, +NULL ); + } + } + +return rc; +} + +/* Allocate a new virtual SLI port */ +int +efc_sport_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,bool restore_vport) +{ +struct efc_sli_port *sport; + +if (ini && domain->efc->enable_ini ==0 ) { +efc_log_test (domain->efc, +"driver initiator functionality not enabled\n" ); +return -1 ; + } + +if (tgt && domain->efc->enable_tgt ==0 ) { +efc_log_test (domain->efc, +"driver target functionality not enabled\n" ); +return -1 ; + } + +/* +* Create a vport spec if we need to recreate +* this vport after a link up event +*/ +if (restore_vport) { +if (efc_vport_create_spec (domain->efc, wwnn, wwpn, fc_id, + ini, tgt, tgt_data, ini_data)) { +efc_log_test (domain->efc, +"failed to create vport object entry\n" ); +return -1 ; + } +return efc_vport_start (domain); + } + +/* Allocate a sport */ + sport =efc_sport_alloc (domain, wwpn, wwnn, fc_id, ini, tgt); + +if (!sport) +return -1 ; + + sport->is_vport = true; + sport->tgt_data = tgt_data; + sport->ini_data = ini_data; + +/* Transition to vport_init */ +efc_sm_transition (&sport->sm, __efc_sport_vport_init,NULL ); + +return 0 ; +} + +/* Remove a previously-allocated virtual port */ +int +efc_sport_vport_del (struct efc *efc,struct efc_domain *domain, +u64 wwpn,uint64_t wwnn) +{ +struct efc_sli_port *sport; +int found =0 ; +struct efc_vport_spec *vport; +struct efc_vport_spec *next; + +/* 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 ; + } + } + +if (!domain) { +/* No domain means no sport to look for */ +return 0 ; + } + +list_for_each_entry (sport, &domain->sport_list, list_entry) { +if (sport->wwpn == wwpn && sport->wwnn == wwnn) { + found =1 ; +break ; + } + } + +if (found) { +/* Shutdown this SPORT */ +efc_sm_post_event (&sport->sm,EFC_EVT_SHUTDOWN ,NULL ); + } +return 0 ; +} + +/* Force free all saved vports */ +void +efc_vport_del_all (struct efc *efc) +{ +struct efc_vport_spec *vport; +struct efc_vport_spec *next; + +list_for_each_entry_safe (vport, next, &efc->vport_list, list_entry) { +list_del (&vport->list_entry); +kfree (vport); + } +} + +/** +* Create a saved vport entry. +* +* A saved vport entry is added to the vport list, +* which is restored following a link up. +* This function is used to allow vports to be created the first time +* the link comes up without having to go through the ioctl() API. +*/ + +int8_t +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_spec *vport; + +/* +* walk the efc_vport_list and return failure +* if a valid(vport with non zero WWPN and WWNN) vport entry +* is already created +*/ +list_for_each_entry (vport, &efc->vport_list, list_entry) { +if ((wwpn && vport->wwpn == wwpn) && + (wwnn && vport->wwnn == wwnn)) { +efc_log_test (efc, +"Failed: VPORT %016llX %016llX already allocated\n" , + wwnn, wwpn); +return -1 ; + } + } + + vport =kzalloc (sizeof (*vport),GFP_ATOMIC ); +if (!vport) +return -1 ; + + 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); +return 0 ; +}
drivers/scsi/elx/libefc/efc_sport.h new file +52 -0
52 lines not on this page · raw message
Signature · 1 line
2.13.7
Re: [PATCH v2 11/32] elx: libefc: SLI and FC PORT state machine interfaces
Quoted 63 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.Signed-off-by Ram Vegesna <[email protected]>Signed-off-by James Smart <[email protected]>--- drivers/scsi/elx/libefc/efc_sport.c | 843 ++++++++++++++++++++++++++++++++++++ drivers/scsi/elx/libefc/efc_sport.h | 52 +++ 2 files changed, 895 insertions(+) create mode 100644 drivers/scsi/elx/libefc/efc_sport.c create mode 100644 drivers/scsi/elx/libefc/efc_sport.hdrivers/scsi/elx/libefc/efc_sport.c new file +42
-0@@ -0,0 +1,843 @@ +// SPDX-License-Identifier: GPL-2.0 +/* +* Copyright (C) 2019 Broadcom. All Rights Reserved. The term +* “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. +*/ + +/* +* Details SLI port (sport) functions. +*/ + +#include "efc.h" + +/* HW sport callback events from the user driver */ +int +efc_lport_cb (void *arg,int event,void *data) +{ +struct efc *efc = arg; +struct efc_sli_port *sport = data; + +switch (event) { +case EFC_HW_PORT_ALLOC_OK : +efc_log_debug (efc,"EFC_HW_PORT_ALLOC_OK\n" ); +efc_sm_post_event (&sport->sm,EFC_EVT_SPORT_ALLOC_OK ,NULL ); +break ; +case EFC_HW_PORT_ALLOC_FAIL : +efc_log_debug (efc,"EFC_HW_PORT_ALLOC_FAIL\n" ); +efc_sm_post_event (&sport->sm,EFC_EVT_SPORT_ALLOC_FAIL ,NULL ); +break ; +case EFC_HW_PORT_ATTACH_OK : +efc_log_debug (efc,"EFC_HW_PORT_ATTACH_OK\n" ); +efc_sm_post_event (&sport->sm,EFC_EVT_SPORT_ATTACH_OK ,NULL ); +break ; +case EFC_HW_PORT_ATTACH_FAIL : +efc_log_debug (efc,"EFC_HW_PORT_ATTACH_FAIL\n" ); +efc_sm_post_event (&sport->sm, +EFC_EVT_SPORT_ATTACH_FAIL ,NULL ); +break ; +case EFC_HW_PORT_FREE_OK : +efc_log_debug (efc,"EFC_HW_PORT_FREE_OK\n" ); +efc_sm_post_event (&sport->sm,EFC_EVT_SPORT_FREE_OK ,NULL ); +break ; +case EFC_HW_PORT_FREE_FAIL :
drivers/scsi/elx/libefc/efc_sport.c line 52
Quoted 10 lines
drivers/scsi/elx/libefc/efc_sport.c new file +10
-0+efc_log_debug (efc,"EFC_HW_PORT_FREE_FAIL\n" ); +efc_sm_post_event (&sport->sm,EFC_EVT_SPORT_FREE_FAIL ,NULL ); +break ; +default : +efc_log_test (efc,"unknown event %#x\n" , event); + } + +return 0 ; +} +
Same here; please use the name mapping function and collapse the cases.
Quoted 53 lines
drivers/scsi/elx/libefc/efc_sport.c new file +53
-0+struct efc_sli_port * +efc_sport_alloc (struct efc_domain *domain,uint64_t wwpn,uint64_t wwnn, +u32 fc_id,bool enable_ini,bool enable_tgt) +{ +struct efc_sli_port *sport; + +if (domain->efc->enable_ini) + enable_ini =0 ; + +/* Return a failure if this sport has already been allocated */ +if (wwpn !=0 ) { + sport =efc_sport_find_wwn (domain, wwnn, wwpn); +if (sport) { +efc_log_err (domain->efc, +"Failed: SPORT %016llX %016llX already allocated\n" , + wwnn, wwpn); +return NULL ; + } + } + + sport =kzalloc (sizeof (*sport),GFP_ATOMIC ); +if (!sport) +return sport; + + sport->efc = domain->efc; +snprintf (sport->display_name,sizeof (sport->display_name),"------" ); + sport->domain = domain; + sport->lookup =efc_spv_new (domain->efc); + sport->instance_index = domain->sport_instance_count++; +INIT_LIST_HEAD (&sport->node_list); + sport->sm.app = sport; + sport->enable_ini = enable_ini; + sport->enable_tgt = enable_tgt; + sport->enable_rscn = (sport->enable_ini || + (sport->enable_tgt &&enable_target_rscn (sport->efc))); + +/* Copy service parameters from domain */ +memcpy (sport->service_params, domain->service_params, +sizeof (struct fc_els_flogi )); + +/* Update requested fc_id */ + sport->fc_id = fc_id; + +/* Update the sport's service parameters for the new wwn's */ + sport->wwpn = wwpn; + sport->wwnn = wwnn; +snprintf (sport->wwnn_str,sizeof (sport->wwnn_str),"%016llX" , wwnn); + +/* +* if this is the "first" sport of the domain, +* then make it the "phys" sport +*/ +if (list_empty (&domain->sport_list))
drivers/scsi/elx/libefc/efc_sport.c line 115
Quoted 10 lines
drivers/scsi/elx/libefc/efc_sport.c new file +10
-0+ domain->sport = sport; + +INIT_LIST_HEAD (&sport->list_entry); +list_add_tail (&sport->list_entry, &domain->sport_list); + +efc_log_debug (domain->efc,"[%s] allocate sport\n" , + sport->display_name); + +return sport; +}
And this is what I meant with missing locking; if this function is called concurrently with the same wwnn you might end up with two identical entries in the sport list.
At the very lease explain why this is safe; but still I would prefer locking here.
Quoted 162 lines
drivers/scsi/elx/libefc/efc_sport.c new file +162
-0+ +void +efc_sport_free (struct efc_sli_port *sport) +{ +struct efc_domain *domain; + +if (!sport) +return ; + + domain = sport->domain; +efc_log_debug (domain->efc,"[%s] free sport\n" , sport->display_name); +list_del (&sport->list_entry); +/* +* if this is the physical sport, +* then clear it out of the domain +*/ +if (sport == domain->sport) + domain->sport =NULL ; + +efc_spv_del (sport->lookup); + sport->lookup =NULL ; + +efc_spv_set (domain->lookup, sport->fc_id,NULL ); + +if (list_empty (&domain->sport_list)) +efc_domain_post_event (domain,EFC_EVT_ALL_CHILD_NODES_FREE , +NULL ); + +kfree (sport); +} + +void +efc_sport_force_free (struct efc_sli_port *sport) +{ +struct efc_node *node; +struct efc_node *next; + +/* shutdown sm processing */ +efc_sm_disable (&sport->sm); + +list_for_each_entry_safe (node, next, &sport->node_list, list_entry) { +efc_node_force_free (node); + } + +efc_sport_free (sport); +} + +/* Find a SLI port object, given an FC_ID */ +struct efc_sli_port * +efc_sport_find (struct efc_domain *domain,u32 d_id) +{ +struct efc_sli_port *sport; + +if (!domain->lookup) { +efc_log_test (domain->efc, +"assertion failed: domain->lookup is not valid\n" ); +return NULL ; + } + + sport =efc_spv_get (domain->lookup, d_id); +return sport; +} + +/* Find a SLI port, given the WWNN and WWPN */ +struct efc_sli_port * +efc_sport_find_wwn (struct efc_domain *domain,uint64_t wwnn,uint64_t wwpn) +{ +struct efc_sli_port *sport =NULL ; + +list_for_each_entry (sport, &domain->sport_list, list_entry) { +if (sport->wwnn == wwnn && sport->wwpn == wwpn) +return sport; + } +return NULL ; +} + +/* External call to request an attach for a sport, given an FC_ID */ +int +efc_sport_attach (struct efc_sli_port *sport,u32 fc_id) +{ +int rc; +struct efc_node *node; +struct efc *efc = sport->efc; + +/* Set our lookup */ +efc_spv_set (sport->domain->lookup, fc_id, sport); + +/* Update our display_name */ +efc_node_fcid_display (fc_id, sport->display_name, +sizeof (sport->display_name)); + +list_for_each_entry (node, &sport->node_list, list_entry) { +efc_node_update_display_name (node); + } + +efc_log_debug (sport->efc,"[%s] attach sport: fc_id x%06x\n" , + sport->display_name, fc_id); + + rc = efc->tt.hw_port_attach (efc, sport, fc_id); +if (rc !=EFC_HW_RTN_SUCCESS ) { +efc_log_err (sport->efc, +"efc_hw_port_attach failed: %d\n" , rc); +return -1 ; + } +return 0 ; +} + +static void +efc_sport_shutdown (struct efc_sli_port *sport) +{ +struct efc *efc = sport->efc; +struct efc_node *node; +struct efc_node *node_next; + +list_for_each_entry_safe (node, node_next, + &sport->node_list, list_entry) { +if (node->rnode.fc_id !=FC_FID_FLOGI || + !sport->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 ); + }else { +efc_log_debug (efc, +"[%s] sport shutdown vport, sending logo to node\n" , + node->display_name); + +if (efc->tt.els_send (efc, node,ELS_LOGO , +EFC_FC_FLOGI_TIMEOUT_SEC , +EFC_FC_ELS_DEFAULT_RETRIES )) { +/* 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 ); + } + } +} + +/* Clear the sport reference in the vport specification */ +static void +efc_vport_link_down (struct efc_sli_port *sport) +{ +struct efc *efc = sport->efc;
drivers/scsi/elx/libefc/efc_sport.c line 287
Quoted 10 lines
drivers/scsi/elx/libefc/efc_sport.c new file +10
-0+struct efc_vport_spec *vport; + +list_for_each_entry (vport, &efc->vport_list, list_entry) { +if (vport->sport == sport) { + vport->sport =NULL ; +break ; + } + } +} +
Similar here: Why is there no locking?
Or RCU lists?
Quoted 442 lines
drivers/scsi/elx/libefc/efc_sport.c new file +442
-0+static void * +__efc_sport_common (const char *funcname,struct efc_sm_ctx *ctx, +enum efc_sm_event evt,void *arg) +{ +struct efc_sli_port *sport = ctx->app; +struct efc_domain *domain = sport->domain; +struct efc *efc = sport->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_SPORT_ATTACH_OK : +efc_sm_transition (ctx, __efc_sport_attached,NULL ); +break ; +case EFC_EVT_SHUTDOWN : { +int node_list_empty; + +/* Flag this sport as shutting down */ + sport->shutting_down = true; + +if (sport->is_vport) +efc_vport_link_down (sport); + + node_list_empty =list_empty (&sport->node_list); + +if (node_list_empty) { +/* sm: node list is empty / efc_hw_port_free */ +/* +* Remove the sport from the domain's +* sparse vector lookup table +*/ +efc_spv_set (domain->lookup, sport->fc_id,NULL ); +efc_sm_transition (ctx, __efc_sport_wait_port_free, +NULL ); +if (efc->tt.hw_port_free (efc, sport)) { +efc_log_test (sport->efc, +"efc_hw_port_free failed\n" ); +/* Not much we can do, free the sport anyways */ +efc_sport_free (sport); + } + }else { +/* sm: node list is not empty / shutdown nodes */ +efc_sm_transition (ctx, + __efc_sport_wait_shutdown,NULL ); +efc_sport_shutdown (sport); + } +break ; + } +default : +efc_log_test (sport->efc,"[%s] %-20s %-20s not handled\n" , + sport->display_name, funcname, +efc_sm_event_name (evt)); +break ; + } + +return NULL ; +} + +/* SLI port state machine: Physical sport allocated */ +void * +__efc_sport_allocated (struct efc_sm_ctx *ctx, +enum efc_sm_event evt,void *arg) +{ +struct efc_sli_port *sport = ctx->app; +struct efc_domain *domain = sport->domain; + +sport_sm_trace (sport); + +switch (evt) { +/* the physical sport is attached */ +case EFC_EVT_SPORT_ATTACH_OK : +efc_assert (sport == domain->sport,NULL ); +efc_sm_transition (ctx, __efc_sport_attached,NULL ); +break ; + +case EFC_EVT_SPORT_ALLOC_OK : +/* ignore */ +break ; +default : +__efc_sport_common (__func__, ctx, evt, arg); +return NULL ; + } +return NULL ; +} + +/* SLI port state machine: Handle initial virtual port events */ +void * +__efc_sport_vport_init (struct efc_sm_ctx *ctx, +enum efc_sm_event evt,void *arg) +{ +struct efc_sli_port *sport = ctx->app; +struct efc *efc = sport->efc; + +sport_sm_trace (sport); + +switch (evt) { +case EFC_EVT_ENTER : { +__be64 be_wwpn =cpu_to_be64 (sport->wwpn); + +if (sport->wwpn ==0 ) +efc_log_debug (efc,"vport: letting f/w select WWN\n" ); + +if (sport->fc_id !=U32_MAX ) { +efc_log_debug (efc,"vport: hard coding port id: %x\n" , + sport->fc_id); + } + +efc_sm_transition (ctx, __efc_sport_vport_wait_alloc,NULL ); +/* If wwpn is zero, then we'll let the f/w */ +if (efc->tt.hw_port_alloc (efc, sport, sport->domain, + sport->wwpn ==0 ?NULL : + (uint8_t *)&be_wwpn)) { +efc_log_err (efc,"Can't allocate port\n" ); +break ; + } + +break ; + } +default : +__efc_sport_common (__func__, ctx, evt, arg); +return NULL ; + } +return NULL ; +} + +/** +* SLI port state machine: +* Wait for the HW SLI port allocation to complete +*/ +void * +__efc_sport_vport_wait_alloc (struct efc_sm_ctx *ctx, +enum efc_sm_event evt,void *arg) +{ +struct efc_sli_port *sport = ctx->app; +struct efc *efc = sport->efc; + +sport_sm_trace (sport); + +switch (evt) { +case EFC_EVT_SPORT_ALLOC_OK : { +struct fc_els_flogi *sp; +struct efc_node *fabric; + + sp = (struct fc_els_flogi *)sport->service_params; +/* +* If we let f/w assign wwn's, +* then sport wwn's with those returned by hw +*/ +if (sport->wwnn ==0 ) { + sport->wwnn =be64_to_cpu (sport->sli_wwnn); + sport->wwpn =be64_to_cpu (sport->sli_wwpn); +snprintf (sport->wwnn_str,sizeof (sport->wwnn_str), +"%016llX" , sport->wwpn); + } + +/* Update the sport's service parameters */ + sp->fl_wwpn =cpu_to_be64 (sport->wwpn); + sp->fl_wwnn =cpu_to_be64 (sport->wwnn); + +/* +* if sport->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 (sport->fc_id ==U32_MAX ) { + fabric =efc_node_alloc (sport,FC_FID_FLOGI , false, + false); +if (!fabric) { +efc_log_err (efc,"efc_node_alloc() failed\n" ); +return NULL ; + } +efc_node_transition (fabric, __efc_vport_fabric_init, +NULL ); + }else { +snprintf (sport->wwnn_str,sizeof (sport->wwnn_str), +"%016llX" , sport->wwpn); +efc_sport_attach (sport, sport->fc_id); + } +efc_sm_transition (ctx, __efc_sport_vport_allocated,NULL ); +break ; + } +default : +__efc_sport_common (__func__, ctx, evt, arg); +return NULL ; + } +return NULL ; +} + +/** +* SLI port state machine: virtual sport allocated. +* +* This state is entered after the sport is allocated; +* it then waits for a fabric node +* FDISC to complete, which requests a sport attach. +* The sport attach complete is handled in this state. +*/ + +void * +__efc_sport_vport_allocated (struct efc_sm_ctx *ctx, +enum efc_sm_event evt,void *arg) +{ +struct efc_sli_port *sport = ctx->app; +struct efc *efc = sport->efc; + +sport_sm_trace (sport); + +switch (evt) { +case EFC_EVT_SPORT_ATTACH_OK : { +struct efc_node *node; + +/* Find our fabric node, and forward this event */ + node =efc_node_find (sport,FC_FID_FLOGI ); +if (!node) { +efc_log_test (efc,"can't find node %06x\n" , +FC_FID_FLOGI ); +break ; + } +/* sm: / forward sport attach to fabric node */ +efc_node_post_event (node, evt,NULL ); +efc_sm_transition (ctx, __efc_sport_attached,NULL ); +break ; + } +default : +__efc_sport_common (__func__, ctx, evt, arg); +return NULL ; + } +return NULL ; +} + +static void +efc_vport_update_spec (struct efc_sli_port *sport) +{ +struct efc *efc = sport->efc; +struct efc_vport_spec *vport; + +list_for_each_entry (vport, &efc->vport_list, list_entry) { +if (vport->sport == sport) { + vport->wwnn = sport->wwnn; + vport->wwpn = sport->wwpn; + vport->tgt_data = sport->tgt_data; + vport->ini_data = sport->ini_data; +break ; + } + } +} + +/* State entered after the sport attach has completed */ +void * +__efc_sport_attached (struct efc_sm_ctx *ctx, +enum efc_sm_event evt,void *arg) +{ +struct efc_sli_port *sport = ctx->app; +struct efc *efc = sport->efc; + +sport_sm_trace (sport); + +switch (evt) { +case EFC_EVT_ENTER : { +struct efc_node *node; + +efc_log_debug (efc, +"[%s] SPORT attached WWPN %016llX WWNN %016llX\n" , + sport->display_name, + sport->wwpn, sport->wwnn); + +list_for_each_entry (node, &sport->node_list, list_entry) { +efc_node_update_display_name (node); + } + + sport->tgt_id = sport->fc_id; + + efc->tt.new_sport (efc, sport); + +/* +* Update the vport (if its not the physical sport) +* parameters +*/ +if (sport->is_vport) +efc_vport_update_spec (sport); +break ; + } + +case EFC_EVT_EXIT : +efc_log_debug (efc, +"[%s] SPORT deattached WWPN %016llX WWNN %016llX\n" , + sport->display_name, + sport->wwpn, sport->wwnn); + + efc->tt.del_sport (efc, sport); +break ; +default : +__efc_sport_common (__func__, ctx, evt, arg); +return NULL ; + } +return NULL ; +} + + +/* SLI port state machine: Wait for the node shutdowns to complete */ +void * +__efc_sport_wait_shutdown (struct efc_sm_ctx *ctx, +enum efc_sm_event evt,void *arg) +{ +struct efc_sli_port *sport = ctx->app; +struct efc_domain *domain = sport->domain; +struct efc *efc = sport->efc; + +sport_sm_trace (sport); + +switch (evt) { +case EFC_EVT_SPORT_ALLOC_OK : +case EFC_EVT_SPORT_ALLOC_FAIL : +case EFC_EVT_SPORT_ATTACH_OK : +case EFC_EVT_SPORT_ATTACH_FAIL : +/* ignore these events - just wait for the all free event */ +break ; + +case EFC_EVT_ALL_CHILD_NODES_FREE : { +/* +* Remove the sport from the domain's +* sparse vector lookup table +*/ +efc_spv_set (domain->lookup, sport->fc_id,NULL ); +efc_sm_transition (ctx, __efc_sport_wait_port_free,NULL ); +if (efc->tt.hw_port_free (efc, sport)) { +efc_log_err (sport->efc,"efc_hw_port_free failed\n" ); +/* Not much we can do, free the sport anyways */ +efc_sport_free (sport); + } +break ; + } +default : +__efc_sport_common (__func__, ctx, evt, arg); +return NULL ; + } +return NULL ; +} + +/* SLI port state machine: Wait for the HW's port free to complete */ +void * +__efc_sport_wait_port_free (struct efc_sm_ctx *ctx, +enum efc_sm_event evt,void *arg) +{ +struct efc_sli_port *sport = ctx->app; + +sport_sm_trace (sport); + +switch (evt) { +case EFC_EVT_SPORT_ATTACH_OK : +/* Ignore as we are waiting for the free CB */ +break ; +case EFC_EVT_SPORT_FREE_OK : { +/* All done, free myself */ +/* sm: / efc_sport_free */ +efc_sport_free (sport); +break ; + } +default : +__efc_sport_common (__func__, ctx, evt, arg); +return NULL ; + } +return NULL ; +} + +/* Use the vport specification to find the associated vports and start them */ +int +efc_vport_start (struct efc_domain *domain) +{ +struct efc *efc = domain->efc; +struct efc_vport_spec *vport; +struct efc_vport_spec *next; +struct efc_sli_port *sport; +int rc =0 ; +u8 found = false; + +list_for_each_entry_safe (vport, next, &efc->vport_list, list_entry) { +if (!vport->sport) { + found = true; +break ; + } + } + +if (found && vport) { + sport =efc_sport_alloc (domain, vport->wwpn, + vport->wwnn, vport->fc_id, + vport->enable_ini, + vport->enable_tgt); + vport->sport = sport; +if (!sport) { + rc =-1 ; + }else { + sport->is_vport = true; + sport->tgt_data = vport->tgt_data; + sport->ini_data = vport->ini_data; + +efc_sm_transition (&sport->sm, __efc_sport_vport_init, +NULL ); + } + } + +return rc; +} + +/* Allocate a new virtual SLI port */ +int +efc_sport_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,bool restore_vport) +{ +struct efc_sli_port *sport; + +if (ini && domain->efc->enable_ini ==0 ) { +efc_log_test (domain->efc, +"driver initiator functionality not enabled\n" ); +return -1 ; + } + +if (tgt && domain->efc->enable_tgt ==0 ) { +efc_log_test (domain->efc, +"driver target functionality not enabled\n" ); +return -1 ; + } + +/* +* Create a vport spec if we need to recreate +* this vport after a link up event +*/ +if (restore_vport) { +if (efc_vport_create_spec (domain->efc, wwnn, wwpn, fc_id, + ini, tgt, tgt_data, ini_data)) { +efc_log_test (domain->efc, +"failed to create vport object entry\n" ); +return -1 ; + } +return efc_vport_start (domain); + } +
drivers/scsi/elx/libefc/efc_sport.c line 739
Quoted 10 lines
drivers/scsi/elx/libefc/efc_sport.c new file +10
-0+/* Allocate a sport */ + sport =efc_sport_alloc (domain, wwpn, wwnn, fc_id, ini, tgt); + +if (!sport) +return -1 ; + + sport->is_vport = true; + sport->tgt_data = tgt_data; + sport->ini_data = ini_data; +
Isn't there a race condition?
The port is already allocated, but not fully populated. Can someone access the sport before these three lines are executed?
Quoted 15 lines
drivers/scsi/elx/libefc/efc_sport.c new file +15
-0+/* Transition to vport_init */ +efc_sm_transition (&sport->sm, __efc_sport_vport_init,NULL ); + +return 0 ; +} + +/* Remove a previously-allocated virtual port */ +int +efc_sport_vport_del (struct efc *efc,struct efc_domain *domain, +u64 wwpn,uint64_t wwnn) +{ +struct efc_sli_port *sport; +int found =0 ; +struct efc_vport_spec *vport; +struct efc_vport_spec *next;
drivers/scsi/elx/libefc/efc_sport.c line 764
Quoted 10 lines
drivers/scsi/elx/libefc/efc_sport.c new file +10
-0+ +/* 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 ; + } + } +
Locking?
Cheers,
Hannes
Signature · 4 lines
Dr. Hannes Reinecke Teamlead Storage & Networking [email protected] +49 911 74053 688 SUSE Software Solutions Germany GmbH, Maxfeldstr. 5, 90409 Nürnberg HRB 36809 (AG Nürnberg), GF: Felix Imendörffer
PATCH v2 12/32 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.
--- drivers/scsi/elx/libefc/efc_node.c | 1343 ++++++++++++++++++++++++++++++++++++ drivers/scsi/elx/libefc/efc_node.h | 188 +++++ 2 files changed, 1531 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 +1343 -0
@@ -0,0 +1,1343 @@ +// SPDX-License-Identifier: GPL-2.0 +/* +* Copyright (C) 2019 Broadcom. All Rights Reserved. The term +* “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. +*/ + +#include "efc.h" + +/* HW node callback events from the user driver */ +int +efc_remote_node_cb (void *arg,int event, +void *data) +{ +struct efc *efc = arg; +enum efc_sm_event sm_event =EFC_EVT_LAST ; +struct efc_remote_node *rnode = data; +struct efc_node *node = rnode->node; +unsigned long flags =0 ; + +switch (event) { +case EFC_HW_NODE_ATTACH_OK : + sm_event =EFC_EVT_NODE_ATTACH_OK ; +break ; + +case EFC_HW_NODE_ATTACH_FAIL : + sm_event =EFC_EVT_NODE_ATTACH_FAIL ; +break ; + +case EFC_HW_NODE_FREE_OK : + sm_event =EFC_EVT_NODE_FREE_OK ; +break ; + +case EFC_HW_NODE_FREE_FAIL : + sm_event =EFC_EVT_NODE_FREE_FAIL ; +break ; + +default : +efc_log_test (efc,"unhandled event %#x\n" , event); +return -1 ; + } + +spin_lock_irqsave (&efc->lock, flags); +efc_node_post_event (node, sm_event,NULL ); +spin_unlock_irqrestore (&efc->lock, flags); + +return 0 ; +} + +/* Find an FC node structure given the FC port ID */ +struct efc_node * +efc_node_find (struct efc_sli_port *sport,u32 port_id) +{ +struct efc_node *node; + + node =efc_spv_get (sport->lookup, port_id); +return node; +} + +int +efc_node_create_pool (struct efc *efc,u32 node_count) +{ +u32 i; +struct efc_node *node; +u64 max_xfer_size; +struct efc_dma *dma; + + efc->nodes_count = node_count; + + efc->nodes =kmalloc_array (node_count,sizeof (struct efc_node *), +GFP_ATOMIC ); +if (!efc->nodes) +return -1 ; + +memset (efc->nodes,0 , node_count *sizeof (struct efc_node *)); + +if (efc->max_xfer_size) + max_xfer_size = efc->max_xfer_size; +else + max_xfer_size =65536 ; + +INIT_LIST_HEAD (&efc->nodes_free_list); + +for (i =0 ; i < node_count; i++) { + dma =NULL ; + node =kzalloc (sizeof (*node),GFP_ATOMIC ); +if (!node) { +efc_log_err (efc,"node allocation failed" ); + goto error; + } +/* Assign any persistent field values */ + node->instance_index = i; + node->max_wr_xfer_size = max_xfer_size; + node->rnode.indicator =U32_MAX ; + + dma = &node->sparm_dma_buf; + dma->size =256 ; + dma->virt =dma_alloc_coherent (&efc->pcidev->dev, dma->size, + &dma->phys,GFP_DMA ); +if (!dma->virt) { +kfree (node); +efc_log_err (efc,"efc_dma_alloc failed" ); + goto error; + } + + efc->nodes[i] = node; +INIT_LIST_HEAD (&node->list_entry); +list_add_tail (&node->list_entry, &efc->nodes_free_list); + } +return 0 ; + +error: +efc_node_free_pool (efc); +return -1 ; +} + +void +efc_node_free_pool (struct efc *efc) +{ +struct efc_node *node; +u32 i; +struct efc_dma *dma; + +if (!efc->nodes) +return ; + +for (i =0 ; i < efc->nodes_count; i++) { + node = efc->nodes[i]; +if (node) { +/* free sparam_dma_buf */ + dma = &node->sparm_dma_buf; +dma_free_coherent (&efc->pcidev->dev, dma->size, + dma->virt, dma->phys); + +kfree (node); + } + efc->nodes[i] =NULL ; + } +} + +struct efc_node * +efc_node_get_instance (struct efc *efc,u32 index) +{ +struct efc_node *node =NULL ; + +if (index >= efc->nodes_count) { +efc_log_test (efc,"invalid index: %d\n" , index); +return NULL ; + } + node = efc->nodes[index]; +return node->attached ? node :NULL ; +} + +struct efc_node *efc_node_alloc (struct efc_sli_port *sport, +u32 port_id,bool init,bool targ) +{ +int rc; +struct efc_node *node =NULL ; +u32 instance_index; +u64 max_wr_xfer_size; +struct efc *efc = sport->efc; +struct efc_dma sparm_dma_buf; + +if (sport->shutting_down) { +efc_log_debug (efc,"node allocation when shutting down %06x" , + port_id); +return NULL ; + } + +if (!list_empty (&efc->nodes_free_list)) { + node =list_first_entry (&efc->nodes_free_list, + struct efc_node, list_entry); +list_del (&node->list_entry); + } + +if (!node) { +efc_log_err (efc,"node allocation failed %06x" , port_id); +return NULL ; + } + +/* Save persistent values across memset zero */ + instance_index = node->instance_index; + max_wr_xfer_size = node->max_wr_xfer_size; + sparm_dma_buf = node->sparm_dma_buf; + +memset (node,0 ,sizeof (*node)); + node->instance_index = instance_index; + node->max_wr_xfer_size = max_wr_xfer_size; + node->sparm_dma_buf = sparm_dma_buf; + node->rnode.indicator =U32_MAX ; + + node->sport = sport; +INIT_LIST_HEAD (&node->list_entry); +list_add_tail (&node->list_entry, &sport->node_list); + + 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->active_ios_lock); +INIT_LIST_HEAD (&node->active_ios); +INIT_LIST_HEAD (&node->els_io_pend_list); +INIT_LIST_HEAD (&node->els_io_active_list); + efc->tt.scsi_io_alloc_enable (efc, node); + + rc = efc->tt.hw_node_alloc (efc, &node->rnode, port_id, sport); +if (rc) { +efc_log_err (efc,"efc_hw_node_alloc failed: %d\n" , rc); +return NULL ; + } +/* zero the service parameters */ +memset (node->sparm_dma_buf.virt,0 , node->sparm_dma_buf.size); + + node->rnode.node = node; + node->sm.app = node; + node->evtdepth =0 ; + +efc_node_update_display_name (node); + +efc_spv_set (sport->lookup, port_id, node); + +return node; +} + +int +efc_node_free (struct efc_node *node) +{ +struct efc_sli_port *sport; +struct efc *efc; +int rc =0 ; +struct efc_node *ns =NULL ; + + sport = node->sport; + 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->sport,FC_FID_DIR_SERV ); + } + +list_del (&node->list_entry); + +/* Free HW resources */ + rc = efc->tt.hw_node_free_resources (efc, &node->rnode); +if (EFC_HW_RTN_IS_ERROR (rc)) { +efc_log_test (efc,"efc_hw_node_free failed: %d\n" , rc); + rc =-1 ; + } + +/* if the gidpt_delay_timer is still running, then delete it */ +if (timer_pending (&node->gidpt_delay_timer)) +del_timer (&node->gidpt_delay_timer); + +/* remove entry from sparse vector list */ +if (!sport->lookup) { +efc_log_test (node->efc, +"assertion failed: sport lookup is NULL\n" ); +return -1 ; + } + +efc_spv_set (sport->lookup, node->rnode.fc_id,NULL ); + +/* +* If the node_list is empty, +* then post a ALL_CHILD_NODES_FREE event to the sport, +* after the lock is released. +* The sport may be free'd as a result of the event. +*/ +if (list_empty (&sport->node_list)) +efc_sm_post_event (&sport->sm,EFC_EVT_ALL_CHILD_NODES_FREE , +NULL ); + + node->sport =NULL ; + node->sm.current_state =NULL ; + +/* return to free list */ +INIT_LIST_HEAD (&node->list_entry); +list_add_tail (&node->list_entry, &efc->nodes_free_list); + +if (ns) { +/* sending fake RSCN event to name server node */ +efc_node_post_event (ns,EFC_EVT_RSCN_RCVD ,NULL ); + } + +return rc; +} + +void +efc_node_force_free (struct efc_node *node) +{ +struct efc *efc = node->efc; +/* shutdown sm processing */ +efc_sm_disable (&node->sm); + +strncpy (node->prev_state_name, node->current_state_name, +sizeof (node->prev_state_name)); +strncpy (node->current_state_name,"disabled" , +sizeof (node->current_state_name)); + + efc->tt.node_io_cleanup (efc, node, true); + efc->tt.node_els_cleanup (efc, node, true); + +/* manually purge pending frames (if any) */ + efc->tt.node_purge_pending (efc, node); + +efc_node_free (node); +} + +static void +efc_dma_copy_in (struct efc_dma *dma,void *buffer,u32 buffer_length) +{ +if (!dma) +return ; +if (!buffer) +return ; +if (buffer_length ==0 ) +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_sli_port *sport = node->sport; +struct efc_domain *domain = sport->domain; +struct efc *efc = node->efc; + +if (!domain->attached) { +efc_log_test (efc, +"Warning: unattached domain\n" ); +return -1 ; + } +/* 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->tt.hw_node_attach (efc, &node->rnode, &node->sparm_dma_buf); +if (EFC_HW_RTN_IS_ERROR (rc)) +efc_log_test (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_sli_port *sport = node->sport; +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" , + sport->display_name, portid_display); +} + +void +efc_node_send_ls_io_cleanup (struct efc_node *node) +{ +struct efc *efc = node->efc; + +if (node->send_ls_acc !=EFC_NODE_SEND_LS_ACC_NONE ) { +efc_log_debug (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 ; + } +} + +void * +__efc_node_shutdown (struct efc_sm_ctx *ctx, +enum efc_sm_event evt,void *arg) +{ +int rc; +unsigned long flags =0 ; +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); +efc_assert (efc_node_active_ios_empty (node),NULL ); +efc_assert (efc_els_io_list_empty (node, + &node->els_io_active_list), +NULL ); + +/* by default, we will be freeing node after we unwind */ + node->req_free = true; + +switch (node->shutdown_reason) { +case EFC_NODE_SHUTDOWN_IMPLICIT_LOGO : +/* +* sm: if shutdown reason is +* implicit logout / efc_node_attach +*/ +/* 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 +*/ + +/* 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) +*/ +efc_assert (node->send_ls_acc == +EFC_NODE_SEND_LS_ACC_PLOGI ,NULL ); +node_printf (node, +"Shutdown reason: implicit logout, re-authenticate\n" ); + + efc->tt.scsi_io_alloc_enable (efc, node); + +/* 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 ); +if (rc ==EFC_HW_RTN_SUCCESS_SYNC ) { +efc_node_post_event (node, +EFC_EVT_NODE_ATTACH_OK , +NULL ); + } +break ; +case EFC_NODE_SHUTDOWN_EXPLICIT_LOGO : { +s8 pend_frames_empty; +struct list_head *list; + +/* cleanup any pending LS_ACC ELSs */ +efc_node_send_ls_io_cleanup (node); + list = &node->els_io_pend_list; +efc_assert (efc_els_io_list_empty (node, list),NULL ); + +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, +"sport.ini=%d node.tgt=%d\n" , + node->sport->enable_ini, node->targ); + +if (!pend_frames_empty || + (node->sport->enable_ini && node->targ)) { +u8 send_plogi = false; + +if (node->sport->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) +*/ + efc->tt.scsi_io_alloc_enable (efc, node); + node->req_free = false; + +/* +* either pending frames exist, +* or we're 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 */ +break ; + } +case EFC_NODE_SHUTDOWN_DEFAULT : +default : { +struct list_head *list; + +/* +* shutdown due to link down, +* node going away (xport event) or +* sport shutdown, purge pending and +* proceed to cleanup node +*/ + +/* cleanup any pending LS_ACC ELSs */ +efc_node_send_ls_io_cleanup (node); + list = &node->els_io_pend_list; +efc_assert (efc_els_io_list_empty (node, list),NULL ); + +node_printf (node, +"Shutdown reason: default, purge pending\n" ); + efc->tt.node_purge_pending (efc, node); +break ; + } + } + +break ; + } +case EFC_EVT_EXIT : +efc_node_accept_frames (node); +break ; + +default : +__efc_node_common (__func__, ctx, evt, arg); +return NULL ; + } + +return NULL ; +} + +static int +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_io_active_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 1 ; + } +return 0 ; +} + +void +efc_node_initiate_cleanup (struct efc_node *node) +{ +struct efc *efc; + + efc = node->efc; + efc->tt.node_els_cleanup (efc, node, false); + +/* +* 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) ==0 ) { +/* +* Abort all ELS's since ELS's won't be aborted by HW +* node free. +*/ +efc_node_hold_frames (node); + efc->tt.node_abort_all_els (efc, node); +efc_node_transition (node, __efc_node_wait_els_shutdown,NULL ); + } +} + +/* Node state machine: Wait for all ELSs to complete */ +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 (); + +switch (evt) { +case EFC_EVT_ENTER : +efc_node_hold_frames (node); +if (efc_els_io_list_empty (node, &node->els_io_active_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 : +efc_assert (node->els_req_cnt,NULL ); + node->els_req_cnt--; + check_quiesce = true; +break ; + +case EFC_EVT_SRRS_ELS_CMPL_OK : +case EFC_EVT_SRRS_ELS_CMPL_FAIL : +efc_assert (node->els_cmpl_cnt,NULL ); + 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" ); +efc_assert (efc_els_io_list_empty (node, + &node->els_io_active_list), +NULL ); + 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 ; +/* fall through */ +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); +return NULL ; + } + +if (check_quiesce) +efc_node_check_els_quiesced (node); + +return NULL ; +} + +/* Node state machine: Wait for a HW node free event to complete */ +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 ; +/* Fall through */ +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); +return NULL ; + } + +return NULL ; +} + +/** +* State is entered when a node receives a shutdown event, and it's waiting +* for all the active IOs and ELS IOs associated with the node to complete. +*/ +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_io_active_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_node_active_ios_empty (node) && +efc_els_io_list_empty (node, &node->els_io_active_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 */ +efc_assert (node->els_req_cnt,NULL ); + 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 ; +/* fall through */ +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); +return NULL ; + } + +return NULL ; +} + +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; + +efc_assert (ctx,NULL ); +efc_assert (ctx->app,NULL ); + node = ctx->app; +efc_assert (node->efc,NULL ); + efc = node->efc; + +switch (evt) { +case EFC_EVT_ENTER : +case EFC_EVT_REENTER : +case EFC_EVT_EXIT : +case EFC_EVT_SPORT_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 : +efc_assert (node->els_cmpl_cnt,NULL ); + 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 : +efc_assert (node->els_req_cnt,NULL ); + 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->tt.send_ls_rjt (efc, 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->tt.send_ls_rjt (efc, 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->tt.bls_send_acc_hdr (efc, node, cbdata->header->dma.virt); +break ; + } + +default : +efc_log_test (node->efc,"[%s] %-20s %-20s not handled\n" , + node->display_name, funcname, +efc_sm_event_name (evt)); +break ; + } +return NULL ; +} + +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 *buffer,u32 buffer_len,uint64_t eui_name) +{ +memset (buffer,0 , buffer_len); + +snprintf (buffer, buffer_len,"eui.%016llX" , eui_name); +} + +uint64_t +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); +} + +uint64_t +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_node_active_ios_empty (struct efc_node *node) +{ +int empty; +unsigned long flags =0 ; + +spin_lock_irqsave (&node->active_ios_lock, flags); + empty =list_empty (&node->active_ios); +spin_unlock_irqrestore (&node->active_ios_lock, flags); +return empty; +} + +int +efc_els_io_list_empty (struct efc_node *node,struct list_head *list) +{ +int empty; +unsigned long flags =0 ; + +spin_lock_irqsave (&node->active_ios_lock, flags); + empty =list_empty (list); +spin_unlock_irqrestore (&node->active_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 ); +} + +/** +* This state is entered when a state is "paused". When resumed, the node +* is transitioned to a previously saved state (node->ndoedb_state) +*/ +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 (); + +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); +break ; + } +return NULL ; +} + +/* Posts a resume event to the paused node */ +int +efc_node_resume (struct efc_node *node) +{ +efc_node_post_event (node,EFC_EVT_RESUME ,NULL ); + +return 0 ; +} + +int +efc_node_recv_els_frame (struct efc_node *node, +struct efc_hw_sequence *seq) +{ +unsigned long flags =0 ; +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 ; + } + } + +spin_lock_irqsave (&node->efc->lock, flags); +efc_node_post_event (node, evt, &cbdata); +spin_unlock_irqrestore (&node->efc->lock, flags); + +return 0 ; +} + +int +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->tt.send_ct_rsp (efc, node,be16_to_cpu (hdr->fh_ox_id), iu, +FC_FS_RJT ,FC_FS_RJT_UNSUP ,0 ); +return 0 ; +} + +int +efc_node_recv_fcp_cmd (struct efc_node *node,struct efc_hw_sequence *seq) +{ +struct efc_node_cb cbdata; +unsigned long flags =0 ; + +memset (&cbdata,0 ,sizeof (cbdata)); + cbdata.header = seq->header; + cbdata.payload = seq->payload; + +spin_lock_irqsave (&node->efc->lock, flags); +efc_node_post_event (node,EFC_EVT_FCP_CMD_RCVD , &cbdata); +spin_unlock_irqrestore (&node->efc->lock, flags); + +return 1 ; +} + +int +efc_node_recv_bls_no_sit (struct efc_node *node, +struct efc_hw_sequence *seq) +{ +struct fc_frame_header *hdr = seq->header->dma.virt; + +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 -1 ; +} + +int +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 ; + +/* 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); + } +if (!seq) { + pend_frames_processed = + node->pend_frames_processed; + node->pend_frames_processed =0 ; +spin_unlock_irqrestore (&node->pend_frames_lock, + flags); +break ; + } + node->pend_frames_processed++; +spin_unlock_irqrestore (&node->pend_frames_lock, flags); + +/* now dispatch frame(s) to dispatch function */ +efc_node_dispatch_frame (node, seq); + } + +if (pend_frames_processed !=0 ) +efc_log_debug (efc,"%u node frames held and processed\n" , + pend_frames_processed); + +return 0 ; +} + +void +efc_scsi_del_initiator_complete (struct efc *efc,struct efc_node *node) +{ +unsigned long flags =0 ; + +spin_lock_irqsave (&node->efc->lock, flags); +/* Notify the node to resume */ +efc_node_post_event (node,EFC_EVT_NODE_DEL_INI_COMPLETE ,NULL ); +spin_unlock_irqrestore (&node->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, +enum efc_hw_node_els_event evt,void *arg) +{ +enum efc_sm_event sm_event =EFC_EVT_LAST ; +struct efc *efc = node->efc; +unsigned long flags =0 ; + +switch (evt) { +case EFC_HW_SRRS_ELS_REQ_OK : + sm_event =EFC_EVT_SRRS_ELS_REQ_OK ; +break ; +case EFC_HW_SRRS_ELS_CMPL_OK : + sm_event =EFC_EVT_SRRS_ELS_CMPL_OK ; +break ; +case EFC_HW_SRRS_ELS_REQ_FAIL : + sm_event =EFC_EVT_SRRS_ELS_REQ_FAIL ; +break ; +case EFC_HW_SRRS_ELS_CMPL_FAIL : + sm_event =EFC_EVT_SRRS_ELS_CMPL_FAIL ; +break ; +case EFC_HW_SRRS_ELS_REQ_RJT : + sm_event =EFC_EVT_SRRS_ELS_REQ_RJT ; +break ; +case EFC_HW_ELS_REQ_ABORTED : + sm_event =EFC_EVT_ELS_REQ_ABORTED ; +break ; +default : +efc_log_test (efc,"unhandled event %#x\n" , evt); +return ; + } + +spin_lock_irqsave (&node->efc->lock, flags); +efc_node_post_event (node, sm_event, arg); +spin_unlock_irqrestore (&node->efc->lock, flags); +} + +void efc_node_post_shutdown (struct efc_node *node, +u32 evt,void *arg) +{ +unsigned long flags =0 ; + +spin_lock_irqsave (&node->efc->lock, flags); +efc_node_post_event (node,EFC_EVT_SHUTDOWN , arg); +spin_unlock_irqrestore (&node->efc->lock, flags); +}
drivers/scsi/elx/libefc/efc_node.h new file +188 -0
188 lines not on this page · raw message
Signature · 1 line
2.13.7
Re: [PATCH v2 12/32] elx: libefc: Remote node state machine interfaces
Quoted 123 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.Signed-off-by Ram Vegesna <[email protected]>Signed-off-by James Smart <[email protected]>--- drivers/scsi/elx/libefc/efc_node.c | 1343 ++++++++++++++++++++++++++++++++++++ drivers/scsi/elx/libefc/efc_node.h | 188 +++++ 2 files changed, 1531 insertions(+) create mode 100644 drivers/scsi/elx/libefc/efc_node.c create mode 100644 drivers/scsi/elx/libefc/efc_node.hdrivers/scsi/elx/libefc/efc_node.c new file +102
-0@@ -0,0 +1,1343 @@ +// SPDX-License-Identifier: GPL-2.0 +/* +* Copyright (C) 2019 Broadcom. All Rights Reserved. The term +* “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. +*/ + +#include "efc.h" + +/* HW node callback events from the user driver */ +int +efc_remote_node_cb (void *arg,int event, +void *data) +{ +struct efc *efc = arg; +enum efc_sm_event sm_event =EFC_EVT_LAST ; +struct efc_remote_node *rnode = data; +struct efc_node *node = rnode->node; +unsigned long flags =0 ; + +switch (event) { +case EFC_HW_NODE_ATTACH_OK : + sm_event =EFC_EVT_NODE_ATTACH_OK ; +break ; + +case EFC_HW_NODE_ATTACH_FAIL : + sm_event =EFC_EVT_NODE_ATTACH_FAIL ; +break ; + +case EFC_HW_NODE_FREE_OK : + sm_event =EFC_EVT_NODE_FREE_OK ; +break ; + +case EFC_HW_NODE_FREE_FAIL : + sm_event = EFC_EVT_NOD> + default: +efc_log_test (efc,"unhandled event %#x\n" , event); +return -1 ; + } + +spin_lock_irqsave (&efc->lock, flags); +efc_node_post_event (node, sm_event,NULL ); +spin_unlock_irqrestore (&efc->lock, flags); + +return 0 ; +} + +/* Find an FC node structure given the FC port ID */ +struct efc_node * +efc_node_find (struct efc_sli_port *sport,u32 port_id) +{ +struct efc_node *node; + + node =efc_spv_get (sport->lookup, port_id); +return node; +} + +int +efc_node_create_pool (struct efc *efc,u32 node_count) +{ +u32 i; +struct efc_node *node; +u64 max_xfer_size; +struct efc_dma *dma; + + efc->nodes_count = node_count; + + efc->nodes =kmalloc_array (node_count,sizeof (struct efc_node *), +GFP_ATOMIC ); +if (!efc->nodes) +return -1 ; + +memset (efc->nodes,0 , node_count *sizeof (struct efc_node *)); + +if (efc->max_xfer_size) + max_xfer_size = efc->max_xfer_size; +else + max_xfer_size =65536 ; + +INIT_LIST_HEAD (&efc->nodes_free_list); + +for (i =0 ; i < node_count; i++) { + dma =NULL ; + node =kzalloc (sizeof (*node),GFP_ATOMIC ); +if (!node) { +efc_log_err (efc,"node allocation failed" ); + goto error; + } +/* Assign any persistent field values */ + node->instance_index = i; + node->max_wr_xfer_size = max_xfer_size; + node->rnode.indicator =U32_MAX ; + + dma = &node->sparm_dma_buf; + dma->size =256 ; + dma->virt =dma_alloc_coherent (&efc->pcidev->dev, dma->size, + &dma->phys,GFP_DMA ); +if (!dma->virt) { +kfree (node); +efc_log_err (efc,"efc_dma_alloc failed" ); + goto error; + } + + efc->nodes[i] = node;
drivers/scsi/elx/libefc/efc_node.c line 112
Quoted 10 lines
drivers/scsi/elx/libefc/efc_node.c new file +10
-0+INIT_LIST_HEAD (&node->list_entry); +list_add_tail (&node->list_entry, &efc->nodes_free_list); + } +return 0 ; + +error: +efc_node_free_pool (efc); +return -1 ; +} +
Can't you use a normal mempool here, and allocate the dma region when required? I guess the node pool is used only infrequently, so performance shouldn't be impacted ...
But it would reduce the pressure on the IOMMU, no?
[ .. ]
Quoted 16 lines
drivers/scsi/elx/libefc/efc_node.c new file +16
-0+void efc_node_post_els_resp (struct efc_node *node, +enum efc_hw_node_els_event evt,void *arg) +{ +enum efc_sm_event sm_event =EFC_EVT_LAST ; +struct efc *efc = node->efc; +unsigned long flags =0 ; + +switch (evt) { +case EFC_HW_SRRS_ELS_REQ_OK : + sm_event =EFC_EVT_SRRS_ELS_REQ_OK ; +break ; +case EFC_HW_SRRS_ELS_CMPL_OK : + sm_event =EFC_EVT_SRRS_ELS_CMPL_OK ; +break ; +case EFC_HW_SRRS_ELS_REQ_FAIL : + sm_event =EFC_EVT_SRRS_ELS_REQ_FAIL ;
drivers/scsi/elx/libefc/efc_node.c line 1324
Quoted 10 lines
drivers/scsi/elx/libefc/efc_node.c new file +10
-0+break ; +case EFC_HW_SRRS_ELS_CMPL_FAIL : + sm_event =EFC_EVT_SRRS_ELS_CMPL_FAIL ; +break ; +case EFC_HW_SRRS_ELS_REQ_RJT : + sm_event =EFC_EVT_SRRS_ELS_REQ_RJT ; +break ; +case EFC_HW_ELS_REQ_ABORTED : + sm_event =EFC_EVT_ELS_REQ_ABORTED ; +break ;
Please collapse.
Cheers,
Hannes
Signature · 4 lines
Dr. Hannes Reinecke Teamlead Storage & Networking [email protected] +49 911 74053 688 SUSE Software Solutions Germany GmbH, Maxfeldstr. 5, 90409 Nürnberg HRB 36809 (AG Nürnberg), GF: Felix Imendörffer