efct: Broadcom (Emulex) FC Target driver
Subsystems (2)
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.5/scsi-queue branch.
Thank you to those that have contributed to the driver in the past.
Review comments welcome!
-- james
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 | 8 + drivers/scsi/elx/Makefile | 30 + drivers/scsi/elx/efct/efct_driver.c | 1243 +++++ drivers/scsi/elx/efct/efct_driver.h | 154 + drivers/scsi/elx/efct/efct_els.c | 2676 +++++++++++ drivers/scsi/elx/efct/efct_els.h | 139 + drivers/scsi/elx/efct/efct_hw.c | 7866 ++++++++++++++++++++++++++++++++ drivers/scsi/elx/efct/efct_hw.h | 1275 ++++++ drivers/scsi/elx/efct/efct_hw_queues.c | 1964 ++++++++ drivers/scsi/elx/efct/efct_hw_queues.h | 66 + drivers/scsi/elx/efct/efct_io.c | 288 ++ drivers/scsi/elx/efct/efct_io.h | 219 + drivers/scsi/elx/efct/efct_lio.c | 2643 +++++++++++ drivers/scsi/elx/efct/efct_lio.h | 371 ++ drivers/scsi/elx/efct/efct_scsi.c | 1970 ++++++++ drivers/scsi/elx/efct/efct_scsi.h | 401 ++ drivers/scsi/elx/efct/efct_unsol.c | 1156 +++++ drivers/scsi/elx/efct/efct_unsol.h | 49 + drivers/scsi/elx/efct/efct_utils.c | 662 +++ drivers/scsi/elx/efct/efct_utils.h | 113 + drivers/scsi/elx/efct/efct_xport.c | 1728 +++++++ drivers/scsi/elx/efct/efct_xport.h | 216 + drivers/scsi/elx/include/efc_common.h | 44 + drivers/scsi/elx/libefc/efc.h | 188 + drivers/scsi/elx/libefc/efc_device.c | 1977 ++++++++ drivers/scsi/elx/libefc/efc_device.h | 72 + drivers/scsi/elx/libefc/efc_domain.c | 1393 ++++++ drivers/scsi/elx/libefc/efc_domain.h | 57 + drivers/scsi/elx/libefc/efc_fabric.c | 2252 +++++++++ drivers/scsi/elx/libefc/efc_fabric.h | 116 + drivers/scsi/elx/libefc/efc_lib.c | 263 ++ drivers/scsi/elx/libefc/efc_node.c | 1878 ++++++++ drivers/scsi/elx/libefc/efc_node.h | 196 + drivers/scsi/elx/libefc/efc_sm.c | 275 ++ drivers/scsi/elx/libefc/efc_sm.h | 171 + drivers/scsi/elx/libefc/efc_sport.c | 1157 +++++ drivers/scsi/elx/libefc/efc_sport.h | 52 + drivers/scsi/elx/libefc/efclib.h | 796 ++++ drivers/scsi/elx/libefc_sli/sli4.c | 7522 ++++++++++++++++++++++++++++++ drivers/scsi/elx/libefc_sli/sli4.h | 4845 ++++++++++++++++++++ 43 files changed, 48502 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 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 | 252 +++++++++++++++++++++++++++++++++++++ 3 files changed, 286 insertions(+) create mode 100644 drivers/scsi/elx/libefc_sli/sli4.c create mode 100644 drivers/scsi/elx/libefc_sli/sli4.h
MAINTAINERS +8 -0
@@ -6088,6 +6088,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;/* generation */ +}; + +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 +252 -0
252 lines not on this page · raw message
Signature · 1 line
2.13.7
Re: [PATCH 01/32] elx: libefc_sli: SLI-4 register offsets and field definitions
Hi,
Quoted 16 lines · James Smart
drivers/scsi/elx/libefc_sli/sli4.h new file +16
-0+/************************************************************************* +* 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 , +
drivers/scsi/elx/libefc_sli/sli4.h line 40
Quoted 10 lines
drivers/scsi/elx/libefc_sli/sli4.h new file +10
-0+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 = 0x0F << SLI4_INTF_VALID_SHIFT,
Should this a 32 bit value? This overflows to 34 bits.
drivers/scsi/elx/libefc_sli/sli4.h line 43
Quoted 3 lines
drivers/scsi/elx/libefc_sli/sli4.h new file +3
-0+ + SLI4_INTF_VALID_VALUE = 6 << SLI4_INTF_VALID_SHIFT, +};
Just style question: what is the benefit using anonymous enums? The only reason I came up was that gdb could show the name of the value. Though a quick test didn't work if the value is passed into a function. Maybe I did something wrong.
I am asking because register number is a define and then the shift and mask are enums.
Quoted 25 lines
drivers/scsi/elx/libefc_sli/sli4.h new file +25
-0+ +/* 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 , +}; +
drivers/scsi/elx/libefc_sli/sli4.h line 78
Quoted 10 lines
drivers/scsi/elx/libefc_sli/sli4.h new file +10
-0+/* 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))
Could you break the line differently so that the expression is a bit simpler to read (there is a version below which does this (SLI4_EQ_DOORBELL))?
Quoted 61 lines
drivers/scsi/elx/libefc_sli/sli4.h new file +61
-0+#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 , + +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 , + +}; + +#define SLI4_EQ_DOORBELL (n, id, a)\ + ((id & SLI4_EQ_ID_LO_MASK) | SLI4_EQCQ_QT_EQ |\ + (((id >> 9) << SLI4_EQCQ_ID_HI_SHIFT) & SLI4_EQCQ_ID_HI_MASK) | \ + ((n << SLI4_EQCQ_NUM_SHIFT) & SLI4_EQCQ_NUM_MASK) | \ + a | SLI4_EQCQ_CI_EQ) + +#define SLI4_CQ_DOORBELL (n, id, a)\ + ((id & SLI4_CQ_ID_LO_MASK) | SLI4_EQCQ_QT_CQ |\ + (((id >> 10) << SLI4_EQCQ_ID_HI_SHIFT) & SLI4_EQCQ_ID_HI_MASK) | \ + ((n << SLI4_EQCQ_NUM_SHIFT) & SLI4_EQCQ_NUM_MASK) | a) + +/* EQ_DOORBELL - EQ Doorbell Register for IF_TYPE = 6*/ +#define SLI4_IF6_EQ_DB_REG 0x120 +enum { +SLI4_IF6_EQ_ID_MASK =0x0FFF , + +SLI4_IF6_EQ_NUM_SHIFT =16 , +SLI4_IF6_EQ_NUM_MASK =0x1FFF0000 , +}; + +#define SLI4_IF6_EQ_DOORBELL (n, id, a)\ + ((id & SLI4_IF6_EQ_ID_MASK) | \ + ((n << SLI4_IF6_EQ_NUM_SHIFT) & SLI4_IF6_EQ_NUM_MASK) | a) + +/* CQ_DOORBELL - CQ Doorbell Register for IF_TYPE = 6*/ +#define SLI4_IF6_CQ_DB_REG 0xC0
drivers/scsi/elx/libefc_sli/sli4.h line 149
Quoted 10 lines
drivers/scsi/elx/libefc_sli/sli4.h new file +10
-0+enum { +SLI4_IF6_CQ_ID_MASK =0xFFFF , + +SLI4_IF6_CQ_NUM_SHIFT =16 , +SLI4_IF6_CQ_NUM_MASK =0x1FFF0000 , +}; + +#define SLI4_IF6_CQ_DOORBELL (n, id, a)\ + ((id & SLI4_IF6_CQ_ID_MASK) | \ + ((n << SLI4_IF6_CQ_NUM_SHIFT) & SLI4_IF6_CQ_NUM_MASK) | a)
There is sometimes a space before '\' and sometimes not. Just my OCD, sorry...
drivers/scsi/elx/libefc_sli/sli4.h line 154
Quoted 4 lines
drivers/scsi/elx/libefc_sli/sli4.h new file +4
-0+/** +* @brief MQ_DOORBELL - MQ Doorbell Register +*/ +#define SLI4_MQ_DB_REG 0x0140/* register offset */
Are the other registers defines also all offsets? Just wondering if the comment is pointing out that these values are special or not.
Thanks,
Daniel
Re: [PATCH 01/32] elx: libefc_sli: SLI-4 register offsets and field definitions
Thanks. We mostly agree with the comment written and will work on the changes.
Exceptions or answers to questions are inline below.
-- james
Quoted 4 lines · Daniel Wagner
drivers/scsi/elx/libefc_sli/sli4.h line 40
Quoted 2 lines
drivers/scsi/elx/libefc_sli/sli4.h new file +2
-0+SLI4_INTF_VALID_SHIFT =29 , + SLI4_INTF_VALID_MASK = 0x0F << SLI4_INTF_VALID_SHIFT,Should this a 32 bit value? This overflows to 34 bits.
agreed
Quoted 10 lines
drivers/scsi/elx/libefc_sli/sli4.h line 43
Quoted 4 lines
drivers/scsi/elx/libefc_sli/sli4.h new file +3
-0+ + SLI4_INTF_VALID_VALUE = 6 << SLI4_INTF_VALID_SHIFT, +};Just style question: what is the benefit using anonymous enums? The only reason I came up was that gdb could show the name of the value. Though a quick test didn't work if the value is passed into a function. Maybe I did something wrong.
Quoted 2 lines
I am asking because register number is a define and then the shift and mask are enums.
In newer code I've seen the preference being anonymous enums. But in looking for why or when to use what, there wasn't much guidance or reasons. As in my other email, we had older defines. In newer code we used enums. So we have a mix. At this point, there's so much volume it's not worth making it one way or the other.
Quoted 7 lines
drivers/scsi/elx/libefc_sli/sli4.h line 154
Quoted 4 lines
drivers/scsi/elx/libefc_sli/sli4.h new file +4
-0+/** +* @brief MQ_DOORBELL - MQ Doorbell Register +*/ +#define SLI4_MQ_DB_REG 0x0140/* register offset */ Are the other registers defines also all offsets? Just wondering if the comment is pointing out that these values are special or not.
yes. We'll clarify them as well.
PATCH 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 | 26 + drivers/scsi/elx/libefc_sli/sli4.h | 2015 +++++++++++++++++++++++++++++++++ 2 files changed, 2041 insertions(+) create mode 100644 drivers/scsi/elx/include/efc_common.h
drivers/scsi/elx/include/efc_common.h 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. +*/ + +#if !defined(__EFC_COMMON_H__) +#define __EFC_COMMON_H__ + +#define EFC_SUCCESS 0 +#define EFC_FAIL 1 + +struct efc_dma_s { +void *virt;/* virtual address of the memory +* used by the CPU +*/ +void *alloc; +dma_addr_t phys;/* physical or bus address of the memory used +* by the hardware +*/ +size_t size;/* size in bytes of the memory */ +size_t len; +struct pci_dev *pdev; +}; + +#endif /* __EFC_COMMON_H__ */
drivers/scsi/elx/libefc_sli/sli4.h +2015 -0
2,025 lines not on this page · raw message
Signature · 1 line
2.13.7
Re: [PATCH 02/32] elx: libefc_sli: SLI Descriptors and Queue entries
Hi James,
drivers/scsi/elx/include/efc_common.h line 7
Quoted 8 lines
drivers/scsi/elx/include/efc_common.h new file +7
-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. +*/ + +#if !defined(__EFC_COMMON_H__)
What about #ifndef which is more commonly used.
drivers/scsi/elx/libefc_sli/sli4.h struct sli4_reg_s { · line 355
Quoted 11 lines
drivers/scsi/elx/libefc_sli/sli4.h +11
-0+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 ),
I noticed sometimes there are also BIT() used. Wouldn't it make sense to the whole driver to use one or the other version of bit definitions?
drivers/scsi/elx/libefc_sli/sli4.h struct sli4_reg_s { · line 580
Quoted 5 lines
drivers/scsi/elx/libefc_sli/sli4.h +5
-0+#define SLI4_QUEUE_DEFAULT_CQ U16_MAX/** Use the default CQ */ + +#define SLI4_QUEUE_RQ_BATCH 8 + +#define CFG_RQST_CMDSZ (stype) sizeof(struct sli4_rqst_##stype##_s)
The alignment of sizeof is off. Suppose it should be a tab there instead spaces.
Quoted 5 lines
drivers/scsi/elx/libefc_sli/sli4.h +5
-0+ +#define CFG_RQST_PYLD_LEN (stype) \ + cpu_to_le32(sizeof(struct sli4_rqst_##stype##_s) - \ + sizeof(struct sli4_rqst_hdr_s)) +
drivers/scsi/elx/libefc_sli/sli4.h struct sli4_reg_s { · line 595
Quoted 10 lines
drivers/scsi/elx/libefc_sli/sli4.h +10
-0+#define CFG_RQST_PYLD_LEN_VAR (stype, varpyld) \ + cpu_to_le32((sizeof(struct sli4_rqst_##stype##_s) + \ + varpyld) - sizeof(struct sli4_rqst_hdr_s)) + +#define SZ_DMAADDR sizeof(struct sli4_dmaaddr_s) + +/* Payload length must accommodate both request and response */ +#define SLI_CONFIG_PYLD_LENGTH (stype) \ + max(sizeof(struct sli4_rqst_##stype##_s), \ + sizeof(struct sli4_rsp_##stype##_s))
Here are the '\' have more indention compared to patch #1.
drivers/scsi/elx/libefc_sli/sli4.h struct sli4_reg_s { · line 673
Quoted 5 lines
drivers/scsi/elx/libefc_sli/sli4.h +5
-0+#define CQ_CNT_VAL (type) (CQ_CNT_##type << CQ_CNT_SHIFT) + +#define SLI4_CQE_BYTES (4 * sizeof(u32)) + +#define SLI4_COMMON_CREATE_CQ_V2_MAX_PAGES 8
Maybe use the same indention for the first to defines?
drivers/scsi/elx/libefc_sli/sli4.h struct sli4_reg_s { · line 686
Quoted 13 lines
drivers/scsi/elx/libefc_sli/sli4.h +13
-0+ +/** +* @brief Generic Common Create EQ/CQ/MQ/WQ/RQ Queue completion +*/ +struct sli4_rsp_cmn_create_queue_s { +struct sli4_rsp_hdr_s hdr; +__le16 q_id; +u8 rsvd18; +u8 ulp; +__le32 db_offset; +__le16 db_rs; +__le16 db_fmt; +};
Just wondering about all these definitions here: These structs describes the wire format, no? Shouldn't this marked with __packed? I keep forgetting the rules.
Quoted 6 lines
drivers/scsi/elx/libefc_sli/sli4.h +6
-0+/** +* EQ count. +*/ +enum { +EQ_CNT_SHIFT =26 , +
drivers/scsi/elx/libefc_sli/sli4.h struct sli4_reg_s { · line 775
Quoted 10 lines
drivers/scsi/elx/libefc_sli/sli4.h +10
-0+EQ_CNT_256 =0 , +EQ_CNT_512 =1 , +EQ_CNT_1024 =2 , +EQ_CNT_2048 =3 , + EQ_CNT_4096 = 3, +}; +#define EQ_CNT_VAL (type) (EQ_CNT_##type << EQ_CNT_SHIFT) + +#define SLI4_EQE_SIZE_4 0 +#define SLI4_EQE_SIZE_16 1
Picking up my question from patch #1, what's the idea about the enums and defines? Why are the last two ones not an enum?
Quoted 16 lines
drivers/scsi/elx/libefc_sli/sli4.h +16
-0+/** +* @brief WQ_CREATE +* +* Create a Work Queue for FC. +*/ +#define SLI4_WQ_CREATE_V0_MAX_PAGES 4 +struct sli4_rqst_wq_create_s { +struct sli4_rqst_hdr_s hdr; +u8 num_pages; +u8 dua_byte; +__le16 cq_id; +struct sli4_dmaaddr_s page_phys_addr[SLI4_WQ_CREATE_V0_MAX_PAGES ]; +u8 bqu_byte; +u8 ulp; +__le16 rsvd; +};
drivers/scsi/elx/libefc_sli/sli4.h struct sli4_reg_s { · line 1035
Quoted 10 lines
drivers/scsi/elx/libefc_sli/sli4.h +10
-0+ +struct sli4_rsp_wq_create_s { +struct sli4_rsp_cmn_create_queue_s q_rsp; +}; + +/** +* @brief WQ_CREATE_V1 +* +* Create a version 1 Work Queue for FC use. +*/
Why does the workqueue code encode a version? Isn't this pure driver code?
Quoted 6 lines
drivers/scsi/elx/libefc_sli/sli4.h +6
-0+#define SLI4_WQ_CREATE_V1_MAX_PAGES 8 +struct sli4_rqst_wq_create_v1_s { +struct sli4_rqst_hdr_s hdr; +__le16 num_pages; +__le16 cq_id; +u8 page_size;
drivers/scsi/elx/libefc_sli/sli4.h struct sli4_reg_s { · line 1051
Quoted 10 lines
drivers/scsi/elx/libefc_sli/sli4.h +10
-0+u8 wqe_size_byte; +__le16 wqe_count; +__le32 rsvd; +struct sli4_dmaaddr_s page_phys_addr[SLI4_WQ_CREATE_V1_MAX_PAGES ]; +}; + +struct sli4_rsp_wq_create_v1_s { +struct sli4_rsp_cmn_create_queue_s rsp; +}; +/**
Empty line missing.
Quoted 13 lines
+ * @brief
WQ_DESTROY
+ *
+ * Destroy an FC Work Queue.
+ */drivers/scsi/elx/libefc_sli/sli4.h +7
-0+enum { +LINK_ATTN_TYPE_LINK_UP =0x01 , +LINK_ATTN_TYPE_LINK_DOWN =0x02 , +LINK_ATTN_TYPE_NO_HARD_ALPA =0x03 , + +LINK_ATTN_P2P =0x01 , +LINK_ATTN_FC_AL =0x02 ,
drivers/scsi/elx/libefc_sli/sli4.h struct sli4_reg_s { · line 1133
Quoted 10 lines
drivers/scsi/elx/libefc_sli/sli4.h +10
-0+LINK_ATTN_INTERNAL_LOOPBACK =0x03 , +LINK_ATTN_SERDES_LOOPBACK =0x04 , + +LINK_ATTN_1G =0x01 , +LINK_ATTN_2G =0x02 , +LINK_ATTN_4G =0x04 , +LINK_ATTN_8G =0x08 , +LINK_ATTN_10G =0x0a , + LINK_ATTN_16G = 0x10, +
One empty line too much.
Quoted 18 lines
drivers/scsi/elx/libefc_sli/sli4.h +17
-0+}; + +/** +* @brief FC Completion Status Codes. +*/ +#define SLI4_FC_WCQE_STATUS_SUCCESS 0x00 +#define SLI4_FC_WCQE_STATUS_FCP_RSP_FAILURE 0x01 +#define SLI4_FC_WCQE_STATUS_REMOTE_STOP 0x02 +#define SLI4_FC_WCQE_STATUS_LOCAL_REJECT 0x03 +#define SLI4_FC_WCQE_STATUS_NPORT_RJT 0x04 +#define SLI4_FC_WCQE_STATUS_FABRIC_RJT 0x05 +#define SLI4_FC_WCQE_STATUS_NPORT_BSY 0x06 +#define SLI4_FC_WCQE_STATUS_FABRIC_BSY 0x07 +#define SLI4_FC_WCQE_STATUS_LS_RJT 0x09 +#define SLI4_FC_WCQE_STATUS_CMD_REJECT 0x0b +#define SLI4_FC_WCQE_STATUS_FCP_TGT_LENCHECK 0x0c +#define SLI4_FC_WCQE_STATUS_RQ_BUF_LEN_EXCEEDED 0x11
drivers/scsi/elx/libefc_sli/sli4.h struct sli4_reg_s { · line 1216
Quoted 10 lines
drivers/scsi/elx/libefc_sli/sli4.h +10
-0+#define SLI4_FC_WCQE_STATUS_RQ_INSUFF_BUF_NEEDED 0x12 +#define SLI4_FC_WCQE_STATUS_RQ_INSUFF_FRM_DISC 0x13 +#define SLI4_FC_WCQE_STATUS_RQ_DMA_FAILURE 0x14 +#define SLI4_FC_WCQE_STATUS_FCP_RSP_TRUNCATE 0x15 +#define SLI4_FC_WCQE_STATUS_DI_ERROR 0x16 +#define SLI4_FC_WCQE_STATUS_BA_RJT 0x17 +#define SLI4_FC_WCQE_STATUS_RQ_INSUFF_XRI_NEEDED 0x18 +#define SLI4_FC_WCQE_STATUS_RQ_INSUFF_XRI_DISC 0x19 +#define SLI4_FC_WCQE_STATUS_RX_ERROR_DETECT 0x1a +#define SLI4_FC_WCQE_STATUS_RX_ABORT_REQUEST 0x1b
Here are defines and no enums.
Quoted 10 lines
drivers/scsi/elx/libefc_sli/sli4.h +10
-0+/** +* @brief WQE used to create an FCP initiator write. +*/ +enum { +SLI4_IWR_WQE_DBDE =0x40 , +SLI4_IWR_WQE_XBL =0x8 , +SLI4_IWR_WQE_XC =0x20 , +SLI4_IWR_WQE_IOD =0x20 , +SLI4_IWR_WQE_HLM =0x10 , +SLI4_IWR_WQE_DNRX =0x10 ,
drivers/scsi/elx/libefc_sli/sli4.h struct sli4_reg_s { · line 1562
Quoted 10 lines
drivers/scsi/elx/libefc_sli/sli4.h +10
-0+SLI4_IWR_WQE_CCPE =0x80 , +SLI4_IWR_WQE_EAT =0x10 , +SLI4_IWR_WQE_APPID =0x10 , +SLI4_IWR_WQE_WQES =0x80 , +SLI4_IWR_WQE_PU_SHFT =4 , +SLI4_IWR_WQE_CT_SHFT =2 , +SLI4_IWR_WQE_BS_SHFT =4 , +SLI4_IWR_WQE_LEN_LOC_BIT1 =0x80 , + SLI4_IWR_WQE_LEN_LOC_BIT2 = 0x1, +};
There are a couple of the same patters above. There is still enough space for adding another level of indention so that all '=' are align.
Quoted 42 lines
drivers/scsi/elx/libefc_sli/sli4.h +42
-0+/** +* @brief Local Reject Reason Codes. +*/ +#define SLI4_FC_LOCAL_REJECT_MISSING_CONTINUE 0x01 +#define SLI4_FC_LOCAL_REJECT_SEQUENCE_TIMEOUT 0x02 +#define SLI4_FC_LOCAL_REJECT_INTERNAL_ERROR 0x03 +#define SLI4_FC_LOCAL_REJECT_INVALID_RPI 0x04 +#define SLI4_FC_LOCAL_REJECT_NO_XRI 0x05 +#define SLI4_FC_LOCAL_REJECT_ILLEGAL_COMMAND 0x06 +#define SLI4_FC_LOCAL_REJECT_XCHG_DROPPED 0x07 +#define SLI4_FC_LOCAL_REJECT_ILLEGAL_FIELD 0x08 +#define SLI4_FC_LOCAL_REJECT_NO_ABORT_MATCH 0x0c +#define SLI4_FC_LOCAL_REJECT_TX_DMA_FAILED 0x0d +#define SLI4_FC_LOCAL_REJECT_RX_DMA_FAILED 0x0e +#define SLI4_FC_LOCAL_REJECT_ILLEGAL_FRAME 0x0f +#define SLI4_FC_LOCAL_REJECT_NO_RESOURCES 0x11 +#define SLI4_FC_LOCAL_REJECT_FCP_CONF_FAILURE 0x12 +#define SLI4_FC_LOCAL_REJECT_ILLEGAL_LENGTH 0x13 +#define SLI4_FC_LOCAL_REJECT_UNSUPPORTED_FEATURE 0x14 +#define SLI4_FC_LOCAL_REJECT_ABORT_IN_PROGRESS 0x15 +#define SLI4_FC_LOCAL_REJECT_ABORT_REQUESTED 0x16 +#define SLI4_FC_LOCAL_REJECT_RCV_BUFFER_TIMEOUT 0x17 +#define SLI4_FC_LOCAL_REJECT_LOOP_OPEN_FAILURE 0x18 +#define SLI4_FC_LOCAL_REJECT_LINK_DOWN 0x1a +#define SLI4_FC_LOCAL_REJECT_CORRUPTED_DATA 0x1b +#define SLI4_FC_LOCAL_REJECT_CORRUPTED_RPI 0x1c +#define SLI4_FC_LOCAL_REJECT_OUTOFORDER_DATA 0x1d +#define SLI4_FC_LOCAL_REJECT_OUTOFORDER_ACK 0x1e +#define SLI4_FC_LOCAL_REJECT_DUP_FRAME 0x1f +#define SLI4_FC_LOCAL_REJECT_LINK_CONTROL_FRAME 0x20 +#define SLI4_FC_LOCAL_REJECT_BAD_HOST_ADDRESS 0x21 +#define SLI4_FC_LOCAL_REJECT_MISSING_HDR_BUFFER 0x23 +#define SLI4_FC_LOCAL_REJECT_MSEQ_CHAIN_CORRUPTED 0x24 +#define SLI4_FC_LOCAL_REJECT_ABORTMULT_REQUESTED 0x25 +#define SLI4_FC_LOCAL_REJECT_BUFFER_SHORTAGE 0x28 +#define SLI4_FC_LOCAL_REJECT_RCV_XRIBUF_WAITING 0x29 +#define SLI4_FC_LOCAL_REJECT_INVALID_VPI 0x2e +#define SLI4_FC_LOCAL_REJECT_MISSING_XRIBUF 0x30 +#define SLI4_FC_LOCAL_REJECT_INVALID_RELOFFSET 0x40 +#define SLI4_FC_LOCAL_REJECT_MISSING_RELOFFSET 0x41 +#define SLI4_FC_LOCAL_REJECT_INSUFF_BUFFERSPACE 0x42 +#define SLI4_FC_LOCAL_REJECT_MISSING_SI 0x43
drivers/scsi/elx/libefc_sli/sli4.h struct sli4_reg_s { · line 2131
Quoted 10 lines
drivers/scsi/elx/libefc_sli/sli4.h +10
-0+#define SLI4_FC_LOCAL_REJECT_MISSING_ES 0x44 +#define SLI4_FC_LOCAL_REJECT_INCOMPLETE_XFER 0x45 +#define SLI4_FC_LOCAL_REJECT_SLER_FAILURE 0x46 +#define SLI4_FC_LOCAL_REJECT_SLER_CMD_RCV_FAILURE 0x47 +#define SLI4_FC_LOCAL_REJECT_SLER_REC_RJT_ERR 0x48 +#define SLI4_FC_LOCAL_REJECT_SLER_REC_SRR_RETRY_ERR 0x49 +#define SLI4_FC_LOCAL_REJECT_SLER_SRR_RJT_ERR 0x4a +#define SLI4_FC_LOCAL_REJECT_SLER_RRQ_RJT_ERR 0x4c +#define SLI4_FC_LOCAL_REJECT_SLER_RRQ_RETRY_ERR 0x4d +#define SLI4_FC_LOCAL_REJECT_SLER_ABTS_ERR 0x4e
There are a bunch of not align values. Having another tab wouldn't hurt.
drivers/scsi/elx/libefc_sli/sli4.h struct sli4_reg_s { · line 2138
Quoted 7 lines
drivers/scsi/elx/libefc_sli/sli4.h +7
-0+ +enum { +SLI4_RACQE_RQ_EL_INDX =0xfff , +SLI4_RACQE_FCFI =0x3f , +SLI4_RACQE_HDPL =0x3f , +SLI4_RACQE_RQ_ID =0xffc0 , +};
And here the values are not aligned.
Thanks,
Daniel
Re: [PATCH 02/32] elx: libefc_sli: SLI Descriptors and Queue entries
Thanks. We mostly agree with the comment written and will work on the changes.
Exceptions or answers to questions are inline below.
-- james
Quoted 3 lines · Daniel Wagner
I noticed sometimes there are also
BIT()used. Wouldn't it make sense to the whole driver to use one or the other version of bit definitions?
We don't want to have BIT() used. Any references will be removed.
Quoted 9 lines
Quoted 9 lines
drivers/scsi/elx/libefc_sli/sli4.h +9
-0+ +/** +* @brief Generic Common Create EQ/CQ/MQ/WQ/RQ Queue completion +*/ +struct sli4_rsp_cmn_create_queue_s { +struct sli4_rsp_hdr_s hdr; +__le16 q_id; +u8 rsvd18; +u8 ulp;
Quoted 8 lines
drivers/scsi/elx/libefc_sli/sli4.h struct sli4_reg_s { · line 686
Quoted 4 lines
drivers/scsi/elx/libefc_sli/sli4.h +4
-0+__le32 db_offset; +__le16 db_rs; +__le16 db_fmt; +};Just wondering about all these definitions here: These structs describes the wire format, no? Shouldn't this marked with
__packed? I keep forgetting the rules.
not wire format, but rather the endianness of the adapter interface.
yes, it's probably good practice to use __packed. The existing definitions should have been ok as the layouts should never have created a condition where pad would have been added. but... better safe than sorry.
Quoted 2 lines
Picking up my question from patch #1, what's the idea about the enums and defines? Why are the last two ones not an enum?
Well, its a code volume issue. We migrated old code which was mostly defines. When close attention was made to properly code for endianness in register definitions and things at the lower interfaces, we used enums. Some things changed while others didn't. Upon conclusion, we saw a large amount of both and it is a lot of work for no technical gain and limited readability gain to make them all one way or the other.
I asked around as to whether we must be all one type or not and there's not a mandate to be one or the other or even specifically when to do what. So we've stuck with what we have.
Quoted 22 lines
Quoted 22 lines
drivers/scsi/elx/libefc_sli/sli4.h +21
-0+/** +* @brief WQ_CREATE +* +* Create a Work Queue for FC. +*/ +#define SLI4_WQ_CREATE_V0_MAX_PAGES 4 +struct sli4_rqst_wq_create_s { +struct sli4_rqst_hdr_s hdr; +u8 num_pages; +u8 dua_byte; +__le16 cq_id; +struct sli4_dmaaddr_s page_phys_addr[SLI4_WQ_CREATE_V0_MAX_PAGES ]; +u8 bqu_byte; +u8 ulp; +__le16 rsvd; +}; + +struct sli4_rsp_wq_create_s { +struct sli4_rsp_cmn_create_queue_s q_rsp; +}; +
Quoted 8 lines
Quoted 5 lines
+/**
+ * @briefWQ_CREATE_V1
+ *
+ * Create a version 1 Work Queue for FC use.
+ */Why does the workqueue code encode a version? Isn't this pure driver code?
The same command can have multiple forms. yes, there's no need to be calling out the version if they are the same between versions. We'll fix this.
PATCH 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 | 1996 ++++++++++++++++++++++++++++++++++++ 1 file changed, 1996 insertions(+)
drivers/scsi/elx/libefc_sli/sli4.h +1996 -0
@@ -2264,4 +2264,2000 @@ struct sli4_fc_xri_aborted_cqe_s {#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) +{ +u32 mask = page_size -1 ; +u32 shift =0 ; + +switch (page_size) { +case 4096 : + shift =12 ; +break ; +case 8192 : + shift =13 ; +break ; +case 16384 : + shift =14 ; +break ; +case 32768 : + shift =15 ; +break ; +case 65536 : + shift =16 ; +break ; +default : +return 0 ; + } + +return (bytes + mask) >> shift; +} + +/************************************************************************* +* SLI-4 mailbox command formats and definitions +*/ + +struct sli4_mbox_command_header_s { +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 , +}; + +/** +* @brief CONFIG_LINK +*/ +enum { +SLI4_CFG_LINK_BBSCN =0xf00 , +SLI4_CFG_LINK_CSCN =0x1000 , +}; + +struct sli4_cmd_config_link_s { +struct sli4_mbox_command_header_s hdr; +u8 maxbbc;/* Max buffer-to-buffer credit */ +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; +/* +* Buffer-to-buffer state change number +* Configure BBSCN +*/ +__le32 bbscn_dword; +}; + +/** +* @brief DUMP Type 4 +*/ +enum { +SLI4_DUMP4_TYPE =0xf , +}; + +#define SLI4_WKI_TAG_SAT_TEM 0x1040 + +struct sli4_cmd_dump4_s { +struct sli4_mbox_command_header_s 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 , +}; + +struct sli4_cmd_init_link_s { +struct sli4_mbox_command_header_s hdr; +__le32 sel_reset_al_pa_dword; +__le32 flags0; +__le32 link_speed_sel_code; +#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 +}; + +/** +* @brief INIT_VFI - initialize the VFI resource +*/ +enum { +SLI4_INIT_VFI_FLAG_VP =0x1000 ,/* DW1W1 */ +SLI4_INIT_VFI_FLAG_VF =0x2000 , +SLI4_INIT_VFI_FLAG_VT =0x4000 , +SLI4_INIT_VFI_FLAG_VR =0x8000 , + +SLI4_INIT_VFI_VFID =0x1fff ,/* DW3W0 */ +SLI4_INIT_VFI_PRI =0xe000 , + +SLI4_INIT_VFI_HOP_COUNT =0xff000000 ,/* DW4 */ +}; + +struct sli4_cmd_init_vfi_s { +struct sli4_mbox_command_header_s hdr; +__le16 vfi; +__le16 flags0_word; +__le16 fcfi; +__le16 vpi; +__le32 vf_id_pri_dword; +__le32 hop_cnt_dword; +}; + +/** +* @brief INIT_VPI - initialize the VPI resource +*/ +struct sli4_cmd_init_vpi_s { +struct sli4_mbox_command_header_s hdr; +__le16 vpi; +__le16 vfi; +}; + +/** +* @brief POST_XRI - post XRI resources to the SLI Port +*/ +enum { +SLI4_POST_XRI_COUNT =0xfff ,/* DW1W1 */ +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_s { +struct sli4_mbox_command_header_s hdr; +__le16 xri_base; +__le16 xri_count_flags; +}; + +/** +* @brief RELEASE_XRI - Release XRI resources from the SLI Port +*/ +enum { +SLI4_RELEASE_XRI_REL_XRI_CNT =0x1f ,/* DW1W0 */ +SLI4_RELEASE_XRI_COUNT =0x1f ,/* DW1W1 */ +}; + +struct sli4_cmd_release_xri_s { +struct sli4_mbox_command_header_s hdr; +__le16 rel_xri_count_word; +__le16 xri_count_word; + +struct { +__le16 xri_tag0; +__le16 xri_tag1; + } xri_tbl[62 ]; +}; + +/** +* @brief READ_CONFIG - read SLI port configuration parameters +*/ +struct sli4_cmd_read_config_s { +struct sli4_mbox_command_header_s hdr; +}; + +enum { +SLI4_READ_CFG_RESP_RESOURCE_EXT =0x80000000 ,/* DW1 */ +SLI4_READ_CFG_RESP_TOPOLOGY =0xff000000 ,/* DW2 */ +}; + +struct sli4_rsp_read_config_s { +struct sli4_mbox_command_header_s 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 (non FC-AL) */ +#define SLI4_READ_CFG_TOPO_FC_AL 0x3/** FC-AL topology */ + +/** +* @brief 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_s { +struct sli4_mbox_command_header_s hdr; +__le32 resvd0; +__le32 resvd4; +__le32 resvd8; +__le32 resvd12; +u8 wwpn[8 ]; +u8 wwnn[8 ]; +__le32 hard_alpa_d_id; +}; + +/** +* @brief WRITE_NVPARMS - write SLI port configuration parameters +*/ +struct sli4_cmd_write_nvparms_s { +struct sli4_mbox_command_header_s hdr; +__le32 resvd0; +__le32 resvd4; +__le32 resvd8; +__le32 resvd12; +u8 wwpn[8 ]; +u8 wwnn[8 ]; +__le32 hard_alpa_d_id; +}; + +/** +* @brief 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_s { +struct sli4_mbox_command_header_s 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_s hostbuf; +__le32 returned_vpd_length; +__le32 actual_vpd_length; +}; + +/** +* @brief READ_SPARM64 - read the Port service parameters +*/ +struct sli4_cmd_read_sparm64_s { +struct sli4_mbox_command_header_s hdr; +__le32 resvd0; +__le32 resvd4; +struct sli4_bde_s 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)) +/** +* @brief READ_TOPOLOGY - read the link event information +*/ +enum { +SLI4_READTOPO_ATTEN_TYPE =0xff ,/* DW2 */ +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 ,/* DW9W1B0 */ +SLI4_READTOPO_SCN_CBBSCN =0xf0 , + +SLI4_READTOPO_R_T_TOV =0x1ff ,/* DW10WO */ +SLI4_READTOPO_AL_TOV =0xf000 , + +SLI4_READTOPO_PB_FLAG =0x80 , + +SLI4_READTOPO_INIT_N_PORTID =0xffffff , +}; + +struct sli4_cmd_read_topology_s { +struct sli4_mbox_command_header_s hdr; +__le32 event_tag; +__le32 dw2_attentype; +u8 topology; +u8 lip_type; +u8 lip_al_ps; +u8 al_pa_granted; +struct sli4_bde_s 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 + +/** +* @brief 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_s { +struct sli4_mbox_command_header_s 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_s { +struct sli4_mbox_command_header_s 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; +}; + +/** +* @brief 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_s { +struct sli4_mbox_command_header_s hdr; +__le16 rpi; +__le16 rsvd2; +__le32 dw2_rportid_flags; +struct sli4_bde_s bde_64; +__le16 vpi; +__le16 rsvd26; +}; + +#define SLI4_REG_RPI_BUF_LEN 0x70 + +/** +* @brief 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_s { +struct sli4_mbox_command_header_s hdr; +__le16 vfi; +__le16 dw0w1_flags; +__le16 fcfi; +__le16 vpi;/* vp=TRUE */ +u8 wwpn[8 ]; +struct sli4_bde_s sparm; +__le32 e_d_tov; +__le32 r_a_tov; +__le32 dw10_lportid_flags; +}; + +/** +* @brief REG_VPI - register a Virtual Port Indicator +*/ +enum { +SLI4_REGVPI_LOCAL_N_PORTID =0xffffff , +SLI4_REGVPI_UPD =0x1000000 , +}; + +struct sli4_cmd_reg_vpi_s { +struct sli4_mbox_command_header_s hdr; +__le32 rsvd0; +__le32 dw2_lportid_flags; +u8 wwpn[8 ]; +__le32 rsvd12; +__le16 vpi; +__le16 vfi; +}; + +/** +* @brief 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_s { +struct sli4_mbox_command_header_s hdr; +__le32 dw1_qry; +__le32 cmd; +__le32 resp; +}; + +/** +* @brief 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 ,/* Config PMD length */ +}; + +struct sli4_cmd_sli_config_s { +struct sli4_mbox_command_header_s hdr; +__le32 dw1_flags; +__le32 payload_len; +__le32 rsvd12[3 ]; +union { +u8 embed[58 *sizeof (u32)]; +struct sli4_bufptr_s mem; + } payload; +}; + +/** +* @brief READ_STATUS - read tx/rx status of a particular port +* +*/ +enum { +SLI4_READSTATUS_CLEAR_COUNTERS =0x1 ,/* DW1 */ +}; + +struct sli4_cmd_read_status_s { +struct sli4_mbox_command_header_s 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; +}; + +/** +* @brief 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_s { +struct sli4_mbox_command_header_s 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; +}; + +/** +* @brief Format a WQE with WQ_ID Association performance hint +* +* @par Description +* PHWQ works by over-writing part of Word 10 in the WQE with the WQ ID. +* +* @param entry Pointer to the WQE. +* @param q_id Queue ID. +* +* @return None. +*/ +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 ] &=cpu_to_le32 (~0xffff ); + wqe[10 ] |=cpu_to_le16 (q_id <<1 ); +} + +/** +* @brief UNREG_FCFI - unregister a FCFI +*/ +struct sli4_cmd_unreg_fcfi_s { +struct sli4_mbox_command_header_s hdr; +__le32 rsvd0; +__le16 fcfi; +__le16 rsvd6; +}; + +/** +* @brief 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_s { +struct sli4_mbox_command_header_s hdr; +__le16 index; +__le16 dw1w1_flags; +__le32 dw2_dest_n_portid; +}; + +/** +* @brief 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_s { +struct sli4_mbox_command_header_s hdr; +__le32 rsvd0; +__le16 index; +__le16 dw2_flags; +}; + +enum sli4_unreg_type_e { +SLI4_UNREG_TYPE_PORT , +SLI4_UNREG_TYPE_DOMAIN , +SLI4_UNREG_TYPE_FCF , +SLI4_UNREG_TYPE_ALL +}; + +/** +* @brief 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_s { +struct sli4_mbox_command_header_s hdr; +__le32 rsvd0; +__le16 index; +__le16 dw2w0_flags; +}; + +/** +* @brief AUTO_XFER_RDY - Configure the auto-generate XFER-RDY feature. +*/ +struct sli4_cmd_config_auto_xfer_rdy_s { +struct sli4_mbox_command_header_s hdr; +__le32 rsvd0; +__le32 max_burst_len; +}; + +#define SLI4_CONFIG_AUTO_XFERRDY_BLKSIZE 0xffff + +struct sli4_cmd_config_auto_xfer_rdy_hp_s { +struct sli4_mbox_command_header_s 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 + +/** +* @brief 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_s { +struct sli4_rqst_hdr_s hdr; +}; + +struct sli4_rsp_cmn_function_reset_s { +struct sli4_rsp_hdr_s hdr; +}; + + +/** +* @brief COMMON_GET_CNTL_ATTRIBUTES +* +* Query for information about the SLI Port +*/ +enum { +SLI4_CNTL_ATTR_PORTNUM =0x3f ,/* Port num and type */ +SLI4_CNTL_ATTR_PORTTYPE =0xc0 , +}; + +struct sli4_rsp_cmn_get_cntl_attributes_s { +struct sli4_rsp_hdr_s 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 ]; +}; + +/** +* @brief COMMON_GET_CNTL_ATTRIBUTES +* +* This command queries the controller information from the Flash ROM. +*/ +struct sli4_rqst_cmn_get_cntl_addl_attributes_s { +struct sli4_rqst_hdr_s hdr; +}; + +struct sli4_rsp_cmn_get_cntl_addl_attributes_s { +struct sli4_rsp_hdr_s 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 ]; +}; + +/** +* @brief COMMON_NOP +* +* This command does not do anything; it only returns +* the payload in the completion. +*/ +struct sli4_rqst_cmn_nop_s { +struct sli4_rqst_hdr_s hdr; +__le32 context[2 ]; +}; + +struct sli4_rsp_cmn_nop_s { +struct sli4_rsp_hdr_s hdr; +__le32 context[2 ]; +}; + +/** +* @brief COMMON_GET_RESOURCE_EXTENT_INFO +*/ +struct sli4_rqst_cmn_get_resource_extent_info_s { +struct sli4_rqst_hdr_s 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_s { +struct sli4_rsp_hdr_s hdr; +__le16 resource_extent_count; +__le16 resource_extent_size; +}; + +#define SLI4_128BYTE_WQE_SUPPORT 0x02 +/** +* @brief COMMON_GET_SLI4_PARAMETERS +*/ + +#define GET_Q_CNT_METHOD (val)\ + ((val & RSP_GET_PARAM_Q_CNT_MTHD_MASK)\ + >> RSP_GET_PARAM_Q_CNT_MTHD_SHFT) +#define GET_Q_CREATE_VERSION (val)\ + ((val & 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_s { +struct sli4_rqst_hdr_s hdr; +}; + +struct sli4_rsp_cmn_get_sli4_params_s { +struct sli4_rsp_hdr_s 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; +}; + +/** +* @brief COMMON_QUERY_FW_CONFIG +* +* This command retrieves firmware configuration parameters and adapter +* resources available to the driver. +*/ +struct sli4_rqst_cmn_query_fw_config_s { +struct sli4_rqst_hdr_s 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_s { +struct sli4_rsp_hdr_s 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;/* Dword 10 */ +__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;/* Dword 20 */ +__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;/* Dword 30 */ +__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;/* Dword 40 */ +__le32 ulp1_iscsi_chain_icd_base; +__le32 ulp1_iscsi_chain_icd_total; +}; + +/** +* @brief COMMON_GET_PORT_NAME +*/ +/*Port Types*/ +enum { +PORT_TYPE_ETH =0 , +PORT_TYPE_FC =1 , +}; + +struct sli4_rqst_cmn_get_port_name_s { +struct sli4_rqst_hdr_s hdr; +u8 port_type; +u8 rsvd4[3 ]; +}; + +struct sli4_rsp_cmn_get_port_name_s { +struct sli4_rsp_hdr_s hdr; +char port_name[4 ]; +}; + +/** +* @brief COMMON_WRITE_FLASHROM +*/ +struct sli4_rqst_cmn_write_flashrom_s { +struct sli4_rqst_hdr_s 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 + +/** +* @brief 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_s { +struct sli4_rqst_hdr_s hdr; +__le32 page_number; +__le32 port; +}; + +struct sli4_rsp_cmn_read_transceiver_data_s { +struct sli4_rsp_hdr_s hdr; +__le32 page_number; +__le32 port; +__le32 page_data[32 ]; +__le32 page_data_2[32 ]; +}; + +/** +* @brief COMMON_READ_OBJECT +*/ + +enum { +SLI4_REQ_DESIRE_READLEN =0xFFFFFF +}; + +struct sli4_rqst_cmn_read_object_s { +struct sli4_rqst_hdr_s hdr; +__le32 desired_read_length_dword; +__le32 read_offset; +u8 object_name[104 ]; +__le32 host_buffer_descriptor_count; +struct sli4_bde_s host_buffer_descriptor[0 ]; +}; + +enum { +RSP_COM_READ_OBJ_EOF =0x80000000 + +}; + +struct sli4_rsp_cmn_read_object_s { +struct sli4_rsp_hdr_s hdr; +__le32 actual_read_length; +__le32 eof_dword; +}; + +/** +* @brief COMMON_WRITE_OBJECT +*/ + +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_s { +struct sli4_rqst_hdr_s hdr; +__le32 desired_write_len_dword; +__le32 write_offset; +u8 object_name[104 ]; +__le32 host_buffer_descriptor_count; +struct sli4_bde_s host_buffer_descriptor[0 ]; +}; + +enum { +RSP_CHANGE_STATUS =0xFF + +}; + +struct sli4_rsp_cmn_write_object_s { +struct sli4_rsp_hdr_s hdr; +__le32 actual_write_length; +__le32 change_status_dword; +}; + +/** +* @brief COMMON_DELETE_OBJECT +*/ +struct sli4_rqst_cmn_delete_object_s { +struct sli4_rqst_hdr_s hdr; +__le32 rsvd4; +__le32 rsvd5; +u8 object_name[104 ]; +}; + +/** +* @brief COMMON_READ_OBJECT_LIST +*/ + +enum { +SLI4_RQ_OBJ_LIST_READ_LEN =0xFFFFFF + +}; + +struct sli4_rqst_cmn_read_object_list_s { +struct sli4_rqst_hdr_s hdr; +__le32 desired_read_length_dword; +__le32 read_offset; +u8 object_name[104 ]; +__le32 host_buffer_descriptor_count; +struct sli4_bde_s host_buffer_descriptor[0 ]; +}; + +/** +* @brief COMMON_SET_DUMP_LOCATION +*/ + +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_s { +struct sli4_rqst_hdr_s 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_s { +struct sli4_rsp_hdr_s hdr; +__le32 buffer_length_dword; +}; + +/** +* @brief COMMON_SET_SET_FEATURES +*/ +#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_s { +struct sli4_rqst_hdr_s hdr; +__le32 feature; +__le32 param_len; +__le32 params[8 ]; +}; + +struct sli4_rqst_cmn_set_features_dif_seed_s { +__le16 seed; +__le16 rsvd16; +}; + +enum { +SLI4_RQ_COM_SET_T10_PI_MEM_MODEL =0x1 + +}; + +struct sli4_rqst_cmn_set_features_t10_pi_mem_model_s { +__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_s { +__le32 auto_gen_xfer_dword;/* Include Sequence Reporting */ +/* Auto Generate XFER-RDY Enabled */ +__le32 num_rqs_dword; +}; + +enum { +SLI4_SETFEAT_XFERRDY_T10PI_RTC = (1 <<0 ),/* DW0 */ +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_s { +__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_s { +__le32 health_check_dword; +}; + +struct sli4_rqst_cmn_set_features_set_fdt_xfer_hint_s { +__le32 fdt_xfer_hint; +}; + +/** +* @brief DMTF_EXEC_CLP_CMD +*/ +struct sli4_rqst_dmtf_exec_clp_cmd_s { +struct sli4_rqst_hdr_s 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_s { +struct sli4_rsp_hdr_s 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_s { +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_s { +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 ]; +}; + +/** +* @brief COMMON_GET_FUNCTION_CONFIG +*/ +struct sli4_rqst_cmn_get_function_config_s { +struct sli4_rqst_hdr_s hdr; +}; + +struct sli4_rsp_cmn_get_function_config_s { +struct sli4_rsp_hdr_s hdr; +__le32 desc_count; +__le32 desc[54 ]; +}; + +/** +* @brief COMMON_GET_PROFILE_CONFIG +*/ + +enum { +SLI4_RQ_GET_PROFILE_ID =0XFF , +SLI4_RQ_GET_PROFILE_TYPE =0x300 +}; + +struct sli4_rqst_cmn_get_profile_config_s { +struct sli4_rqst_hdr_s hdr; +__le32 profile_id_dword; +}; + +struct sli4_rsp_cmn_get_profile_config_s { +struct sli4_rsp_hdr_s hdr; +__le32 desc_count; +__le32 desc[0 ]; +}; + +/** +* @brief COMMON_SET_PROFILE_CONFIG +*/ + +enum { +SLI4_RQ_SET_PROFILE_ID =0XFF , +SLI4_RQ_SET_PROFILE_ISAP =0x80000000 + +}; + +struct sli4_rqst_cmn_set_profile_config_s { +struct sli4_rqst_hdr_s hdr; +__le32 profile_id_dword; +__le32 desc_count; +__le32 desc[0 ]; +}; + +struct sli4_rsp_cmn_set_profile_config_s { +struct sli4_rsp_hdr_s hdr; +}; + +/** +* @brief Profile Descriptor for profile functions +*/ +struct sli4_profile_descriptor_s { +u8 profile_id; +u8 rsvd8; +u8 profile_index; +u8 rsvd24; +__le32 profile_description[128 ]; +}; + +/* +* We don't know in advance how many descriptors there are. We have +* to pick a number that we think will be big enough and ask for that +* many. +*/ + +#define MAX_PROD_DES 40 + +/** +* @brief COMMON_GET_PROFILE_LIST +*/ + +enum { +SLI4_RQ_PROFILE_INDEX =0XFF + +}; + +struct sli4_rqst_cmn_get_profile_list_s { +struct sli4_rqst_hdr_s hdr; +__le32 start_profile_index_dword; +}; + +struct sli4_rsp_cmn_get_profile_list_s { +struct sli4_rsp_hdr_s hdr; +__le32 profile_descriptor_count; +struct sli4_profile_descriptor_s profile_descriptor[MAX_PROD_DES ]; +}; + +/** +* @brief COMMON_GET_ACTIVE_PROFILE +*/ +struct sli4_rqst_cmn_get_active_profile_s { +struct sli4_rqst_hdr_s hdr; +}; + +struct sli4_rsp_cmn_get_active_profile_s { +struct sli4_rsp_hdr_s hdr; +u8 active_profile_id; +u8 rsvd0; +u8 next_profile_id; +u8 rsvd1; +}; + +/** +* @brief COMMON_SET_ACTIVE_PROFILE +*/ + +enum { +SLI4_REQ_SETACTIVE_PROF_ID =0xFF , +SLI4_REQ_SETACTIVE_PROF_FD =0x80000000 +}; + +struct sli4_rqst_cmn_set_active_profile_s { +struct sli4_rqst_hdr_s hdr; +__le32 active_profile_id_dword; +}; + +struct sli4_rsp_cmn_set_active_profile_s { +struct sli4_rsp_hdr_s hdr; +}; + +/** +* @brief Link Config Descriptor for link config functions +*/ +struct sli4_link_config_descriptor_s { +u8 link_config_id; +u8 rsvd1[3 ]; +__le32 config_description[8 ]; +}; + +#define MAX_LINK_DES 10 + +/** +* @brief COMMON_GET_RECONFIG_LINK_INFO +*/ +struct sli4_rqst_cmn_get_reconfig_link_info_s { +struct sli4_rqst_hdr_s hdr; +}; + +struct sli4_rsp_cmn_get_reconfig_link_info_s { +struct sli4_rsp_hdr_s 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_s desc[MAX_LINK_DES ]; +}; + +/** +* @brief COMMON_SET_RECONFIG_LINK_ID +*/ +enum { +SLI4_SET_RECONFIG_LINKID_NEXT =0xff , +SLI4_SET_RECONFIG_LINKID_FD = (1 <<31 ), +}; + +struct sli4_rqst_cmn_set_reconfig_link_id_s { +struct sli4_rqst_hdr_s hdr; +__le32 dw4_flags; +}; + +struct sli4_rsp_cmn_set_reconfig_link_id_s { +struct sli4_rsp_hdr_s hdr; +}; + +struct sli4_rqst_lowlevel_set_watchdog_s { +struct sli4_rqst_hdr_s hdr; +__le16 watchdog_timeout; +__le16 rsvd18; +}; + +struct sli4_rsp_lowlevel_set_watchdog_s { +struct sli4_rsp_hdr_s hdr; +__le32 rsvd; +}; + +/* +* Maximum value for a FCFI +* +* Note that although most commands provide a 16 bit field for the FCFI, +* the FC/FCoE Asynchronous Recived CQE format only provides 6 bits for +* the returned FCFI. Then effectively, the FCFI cannot be larger than +* 1 << 6 or 64. +*/ +#define SLI4_MAX_FCFI 64 + +/** +* 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 + +/** +* @brief POST_SGL_PAGES +* +* Register the scatter gather list (SGL) memory and associate it with an XRI. +*/ +struct sli4_rqst_post_sgl_pages_s { +struct sli4_rqst_hdr_s 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_s { +struct sli4_rsp_hdr_s hdr; +}; + +/** +* @brief POST_HDR_TEMPLATES +*/ +struct sli4_rqst_post_hdr_templates_s { +struct sli4_rqst_hdr_s hdr; +__le16 rpi_offset; +__le16 page_count; +struct sli4_dmaaddr_s 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_e { +SLI4_CB_LINK , +SLI4_CB_MAX /* must be last */ +}; + +enum sli4_link_status_e { +SLI_LINK_STATUS_UP , +SLI_LINK_STATUS_DOWN , +SLI_LINK_STATUS_NO_ALPA , +SLI_LINK_STATUS_MAX , +}; + +enum sli4_link_topology_e { +SLI_LINK_TOPO_NPORT =1 ,/** fabric or point-to-point */ +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_e { +SLI_LINK_MEDIUM_ETHERNET , +SLI_LINK_MEDIUM_FC , +SLI_LINK_MEDIUM_MAX , +}; + +/*Driver specific structures*/ + +struct sli4_link_event_s { +enum sli4_link_status_e status;/* link up/down */ +enum sli4_link_topology_e topology; +enum sli4_link_medium_e medium;/* Ethernet / FC */ +u32 speed;/* Mbps */ +u8 *loop_map; +u32 fc_id; +}; + +enum sli4_resource_e { +SLI_RSRC_VFI , +SLI_RSRC_VPI , +SLI_RSRC_RPI , +SLI_RSRC_XRI , +SLI_RSRC_FCFI , +SLI_RSRC_MAX /* must be last */ +}; + +struct sli4_extent_s { +u32 number;/* number of extents */ +u32 size;/* no of element in each extent */ +u32 n_alloc;/* no of elements allocated */ +u32 *base; +unsigned long *use_map;/* shows resource in use */ +u32 map_size;/* no of bits in bitmap */ +}; + +struct sli4_queue_info_s { +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 ]; +}; + +struct sli4_s { +void *os; +struct pci_dev *pcidev; +#define SLI_PCI_MAX_REGS 6 +void __iomem *reg[SLI_PCI_MAX_REGS ]; + +u32 sli_rev;/* SLI revision number */ +u32 sli_family; +u32 if_type;/* SLI Interface type */ + +u16 asic_type; +u16 asic_rev; + +u16 e_d_tov; +u16 r_a_tov; +struct sli4_queue_info_s qinfo; +u16 link_module_type; +u8 rq_batch; +u16 rq_min_buf_size; +u32 rq_max_buf_size; +u8 topology; +u8 wwpn[8 ];/* WW Port Name */ +u8 wwnn[8 ];/* WW Node Name */ +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_s 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_s bmbx; + +/* Save pointer to physical memory descriptor for non-embedded +* SLI_CONFIG commands for BMBX dumping purposes +*/ +struct efc_dma_s *bmbx_non_emb_pmd; + +struct efc_dma_s vpd_data; +u32 vpd_length; +}; +#endif /* !_SLI4_H */
Signature · 1 line
2.13.7
Re: [PATCH 03/32] elx: libefc_sli: Data structures and defines for mbox commands
Hi James,
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 | 1996 ++++++++++++++++++++++++++++++++++++ 1 file changed, 1996 insertions(+)drivers/scsi/elx/libefc_sli/sli4.h +0
-0
drivers/scsi/elx/libefc_sli/sli4.h struct sli4_fc_xri_aborted_cqe_s { · line 2267
Quoted 4 lines
drivers/scsi/elx/libefc_sli/sli4.h +1
-0@@ -2264,4 +2264,2000 @@ struct sli4_fc_xri_aborted_cqe_s {#define SLI4_ELS_REQUEST64_CMD_NON_FABRIC 0x0c#define SLI4_ELS_REQUEST64_CMD_FABRIC 0x0d +#define SLI_PAGE_SIZE (1 << 12)/* 4096 */
So SLI_PAGE_SIZE is fixed and can't be changed...
drivers/scsi/elx/libefc_sli/sli4.h struct sli4_fc_xri_aborted_cqe_s { · line 2278
Quoted 11 lines
drivers/scsi/elx/libefc_sli/sli4.h +11
-0+#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)
... and callers of this function pass in SLI_PAGE_SIZE.
Quoted 13 lines
drivers/scsi/elx/libefc_sli/sli4.h +13
-0+{ +u32 mask = page_size -1 ; +u32 shift =0 ; + +switch (page_size) { +case 4096 : + shift =12 ; +break ; +case 8192 : + shift =13 ; +break ; +case 16384 : + shift =14 ;
drivers/scsi/elx/libefc_sli/sli4.h struct sli4_fc_xri_aborted_cqe_s { · line 2301
Quoted 10 lines
drivers/scsi/elx/libefc_sli/sli4.h +10
-0+break ; +case 32768 : + shift =15 ; +break ; +case 65536 : + shift =16 ; +break ; +default : +return 0 ; + }
What about using __ffs(page_size)? But...
drivers/scsi/elx/libefc_sli/sli4.h struct sli4_fc_xri_aborted_cqe_s { · line 2303
Quoted 2 lines
drivers/scsi/elx/libefc_sli/sli4.h +2
-0+ +return (bytes + mask) >> shift;
... mask and shift could just be defined like SLI_PAGE_SIZE and we safe a few instructions. Unless SLI_PAGE_SIZE will be dynamic in future.
Quoted 49 lines
drivers/scsi/elx/libefc_sli/sli4.h +49
-0+} + +/************************************************************************* +* SLI-4 mailbox command formats and definitions +*/ + +struct sli4_mbox_command_header_s { +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 , +}; + +/**
drivers/scsi/elx/libefc_sli/sli4.h struct sli4_fc_xri_aborted_cqe_s { · line 2362
Quoted 10 lines
drivers/scsi/elx/libefc_sli/sli4.h +10
-0+* @brief CONFIG_LINK +*/ +enum { +SLI4_CFG_LINK_BBSCN =0xf00 , +SLI4_CFG_LINK_CSCN =0x1000 , +}; + +struct sli4_cmd_config_link_s { +struct sli4_mbox_command_header_s hdr; +u8 maxbbc;/* Max buffer-to-buffer credit */
Why stopping here documention the members?
Quoted 88 lines
drivers/scsi/elx/libefc_sli/sli4.h +88
-0+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; +/* +* Buffer-to-buffer state change number +* Configure BBSCN +*/ +__le32 bbscn_dword; +}; + +/** +* @brief DUMP Type 4 +*/ +enum { +SLI4_DUMP4_TYPE =0xf , +}; + +#define SLI4_WKI_TAG_SAT_TEM 0x1040 + +struct sli4_cmd_dump4_s { +struct sli4_mbox_command_header_s 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 , +}; + +struct sli4_cmd_init_link_s { +struct sli4_mbox_command_header_s hdr; +__le32 sel_reset_al_pa_dword; +__le32 flags0; +__le32 link_speed_sel_code; +#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
drivers/scsi/elx/libefc_sli/sli4.h struct sli4_fc_xri_aborted_cqe_s { · line 2460
Quoted 10 lines
drivers/scsi/elx/libefc_sli/sli4.h +10
-0+#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 +};
I would move the defines in front of the struct.
Quoted 5 lines
drivers/scsi/elx/libefc_sli/sli4.h +5
-0+ +/** +* @brief INIT_VFI - initialize the VFI resource +*/ +enum {
drivers/scsi/elx/libefc_sli/sli4.h struct sli4_fc_xri_aborted_cqe_s { · line 2475
Quoted 10 lines
drivers/scsi/elx/libefc_sli/sli4.h +10
-0+SLI4_INIT_VFI_FLAG_VP =0x1000 ,/* DW1W1 */ +SLI4_INIT_VFI_FLAG_VF =0x2000 , +SLI4_INIT_VFI_FLAG_VT =0x4000 , +SLI4_INIT_VFI_FLAG_VR =0x8000 , + +SLI4_INIT_VFI_VFID =0x1fff ,/* DW3W0 */ +SLI4_INIT_VFI_PRI =0xe000 , + + SLI4_INIT_VFI_HOP_COUNT = 0xff000000, /* DW4 */ +};
I would align all the '='.
Quoted 94 lines
drivers/scsi/elx/libefc_sli/sli4.h +94
-0+ +struct sli4_cmd_init_vfi_s { +struct sli4_mbox_command_header_s hdr; +__le16 vfi; +__le16 flags0_word; +__le16 fcfi; +__le16 vpi; +__le32 vf_id_pri_dword; +__le32 hop_cnt_dword; +}; + +/** +* @brief INIT_VPI - initialize the VPI resource +*/ +struct sli4_cmd_init_vpi_s { +struct sli4_mbox_command_header_s hdr; +__le16 vpi; +__le16 vfi; +}; + +/** +* @brief POST_XRI - post XRI resources to the SLI Port +*/ +enum { +SLI4_POST_XRI_COUNT =0xfff ,/* DW1W1 */ +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_s { +struct sli4_mbox_command_header_s hdr; +__le16 xri_base; +__le16 xri_count_flags; +}; + +/** +* @brief RELEASE_XRI - Release XRI resources from the SLI Port +*/ +enum { +SLI4_RELEASE_XRI_REL_XRI_CNT =0x1f ,/* DW1W0 */ +SLI4_RELEASE_XRI_COUNT =0x1f ,/* DW1W1 */ +}; + +struct sli4_cmd_release_xri_s { +struct sli4_mbox_command_header_s hdr; +__le16 rel_xri_count_word; +__le16 xri_count_word; + +struct { +__le16 xri_tag0; +__le16 xri_tag1; + } xri_tbl[62 ]; +}; + +/** +* @brief READ_CONFIG - read SLI port configuration parameters +*/ +struct sli4_cmd_read_config_s { +struct sli4_mbox_command_header_s hdr; +}; + +enum { +SLI4_READ_CFG_RESP_RESOURCE_EXT =0x80000000 ,/* DW1 */ +SLI4_READ_CFG_RESP_TOPOLOGY =0xff000000 ,/* DW2 */ +}; + +struct sli4_rsp_read_config_s { +struct sli4_mbox_command_header_s 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;
drivers/scsi/elx/libefc_sli/sli4.h struct sli4_fc_xri_aborted_cqe_s { · line 2579
Quoted 10 lines
drivers/scsi/elx/libefc_sli/sli4.h +10
-0+__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 (non FC-AL) */ +#define SLI4_READ_CFG_TOPO_FC_AL 0x3/** FC-AL topology */
The comments are not aligned.
Quoted 34 lines
drivers/scsi/elx/libefc_sli/sli4.h +34
-0+* @brief 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_s { +struct sli4_mbox_command_header_s hdr; +__le32 resvd0; +__le32 resvd4; +__le32 resvd8; +__le32 resvd12; +u8 wwpn[8 ]; +u8 wwnn[8 ]; +__le32 hard_alpa_d_id; +}; + +/** +* @brief WRITE_NVPARMS - write SLI port configuration parameters +*/ +struct sli4_cmd_write_nvparms_s { +struct sli4_mbox_command_header_s hdr; +__le32 resvd0; +__le32 resvd4; +__le32 resvd8; +__le32 resvd12; +u8 wwpn[8 ]; +u8 wwnn[8 ]; +__le32 hard_alpa_d_id; +}; + +/**
drivers/scsi/elx/libefc_sli/sli4.h struct sli4_fc_xri_aborted_cqe_s { · line 2625
Quoted 10 lines
drivers/scsi/elx/libefc_sli/sli4.h +10
-0+* @brief 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 , +};
Also here I would align the '='.
Quoted 30 lines
drivers/scsi/elx/libefc_sli/sli4.h +30
-0+ +struct sli4_cmd_read_rev_s { +struct sli4_mbox_command_header_s 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_s hostbuf; +__le32 returned_vpd_length; +__le32 actual_vpd_length; +}; + +/** +* @brief READ_SPARM64 - read the Port service parameters +*/ +struct sli4_cmd_read_sparm64_s { +struct sli4_mbox_command_header_s hdr;
drivers/scsi/elx/libefc_sli/sli4.h struct sli4_fc_xri_aborted_cqe_s { · line 2665
Quoted 10 lines
drivers/scsi/elx/libefc_sli/sli4.h +10
-0+__le32 resvd0; +__le32 resvd4; +struct sli4_bde_s bde_64; +__le16 vpi; +__le16 resvd22; +__le16 port_name_start; +__le16 port_name_len; +__le16 node_name_start; +__le16 node_name_len; +};
I would also ident all members (except hdr I guess) to the same level.
Quoted 45 lines
drivers/scsi/elx/libefc_sli/sli4.h +45
-0+ +#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)) +/** +* @brief READ_TOPOLOGY - read the link event information +*/ +enum { +SLI4_READTOPO_ATTEN_TYPE =0xff ,/* DW2 */ +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 ,/* DW9W1B0 */ +SLI4_READTOPO_SCN_CBBSCN =0xf0 , + +SLI4_READTOPO_R_T_TOV =0x1ff ,/* DW10WO */ +SLI4_READTOPO_AL_TOV =0xf000 , + +SLI4_READTOPO_PB_FLAG =0x80 , + +SLI4_READTOPO_INIT_N_PORTID =0xffffff , +}; + +struct sli4_cmd_read_topology_s { +struct sli4_mbox_command_header_s hdr; +__le32 event_tag; +__le32 dw2_attentype; +u8 topology; +u8 lip_type; +u8 lip_al_ps; +u8 al_pa_granted; +struct sli4_bde_s bde_loop_map; +__le32 linkdown_state; +__le32 currlink_state; +u8 max_bbc;
drivers/scsi/elx/libefc_sli/sli4.h struct sli4_fc_xri_aborted_cqe_s { · line 2720
Quoted 10 lines
drivers/scsi/elx/libefc_sli/sli4.h +10
-0+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; +};
also here same ident level for all (except hdr, I suppose).
Quoted 35 lines
drivers/scsi/elx/libefc_sli/sli4.h +35
-0+ +#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 + +/** +* @brief 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 , +}; +
drivers/scsi/elx/libefc_sli/sli4.h struct sli4_fc_xri_aborted_cqe_s { · line 2765
Quoted 10 lines
drivers/scsi/elx/libefc_sli/sli4.h +10
-0+#define SLI4_CMD_REG_FCFI_NUM_RQ_CFG 4 +struct sli4_cmd_reg_fcfi_s { +struct sli4_mbox_command_header_s 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 ];
below in struct sli4_cmd_reg_fcfi_mrq_s the member is on a new line, maybe make it here too? Consistency :)
Quoted 42 lines
drivers/scsi/elx/libefc_sli/sli4.h +42
-0+__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_s { +struct sli4_mbox_command_header_s 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; +}; + +/** +* @brief 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 , +};
drivers/scsi/elx/libefc_sli/sli4.h struct sli4_fc_xri_aborted_cqe_s { · line 2817
Quoted 10 lines
drivers/scsi/elx/libefc_sli/sli4.h +10
-0+ +struct sli4_cmd_reg_rpi_s { +struct sli4_mbox_command_header_s hdr; +__le16 rpi; +__le16 rsvd2; +__le32 dw2_rportid_flags; +struct sli4_bde_s bde_64; +__le16 vpi; +__le16 rsvd26; +};
Again all members the same ident level?
drivers/scsi/elx/libefc_sli/sli4.h struct sli4_fc_xri_aborted_cqe_s { · line 2829
Quoted 12 lines
drivers/scsi/elx/libefc_sli/sli4.h +12
-0+ +#define SLI4_REG_RPI_BUF_LEN 0x70 + +/** +* @brief REG_VFI - register a Virtual Fabric Indicator +*/ +enum { +SLI4_REGVFI_VP =0x1000 ,/* DW1 */ +SLI4_REGVFI_UPD =0x2000 , + +SLI4_REGVFI_LOCAL_N_PORTID =0xffffff ,/* DW10 */ +};
ditto.
drivers/scsi/elx/libefc_sli/sli4.h struct sli4_fc_xri_aborted_cqe_s { · line 2842
Quoted 13 lines
drivers/scsi/elx/libefc_sli/sli4.h +13
-0+ +struct sli4_cmd_reg_vfi_s { +struct sli4_mbox_command_header_s hdr; +__le16 vfi; +__le16 dw0w1_flags; +__le16 fcfi; +__le16 vpi;/* vp=TRUE */ +u8 wwpn[8 ]; +struct sli4_bde_s sparm; +__le32 e_d_tov; +__le32 r_a_tov; +__le32 dw10_lportid_flags; +};
and here.
drivers/scsi/elx/libefc_sli/sli4.h struct sli4_fc_xri_aborted_cqe_s { · line 3357
Quoted 10 lines
drivers/scsi/elx/libefc_sli/sli4.h +10
-0+/** +* @brief COMMON_GET_SLI4_PARAMETERS +*/ + +#define GET_Q_CNT_METHOD (val)\ + ((val & RSP_GET_PARAM_Q_CNT_MTHD_MASK)\ + >> RSP_GET_PARAM_Q_CNT_MTHD_SHFT) +#define GET_Q_CREATE_VERSION (val)\ + ((val & RSP_GET_PARAM_QV_MASK)\ + >> RSP_GET_PARAM_QV_SHIFT)
This time there is no space in front of '\'. Does the expresssion not fit on one line? Would be easier to read:
#define GET_Q_CREATE_VERSION(val) \ ((val & RSP_GET_PARAM_QV_MASK) >> RSP_GET_PARAM_QV_SHIFT)
drivers/scsi/elx/libefc_sli/sli4.h struct sli4_fc_xri_aborted_cqe_s { · line 3485
Quoted 3 lines
drivers/scsi/elx/libefc_sli/sli4.h +3
-0+#define SLI4_FUNCTION_MODE_INI_MODE 0x40 +#define SLI4_FUNCTION_MODE_TGT_MODE 0x80 +#define SLI4_FUNCTION_MODE_DUA_MODE 0x800
Just one space between _MODE and 0x800
drivers/scsi/elx/libefc_sli/sli4.h struct sli4_fc_xri_aborted_cqe_s { · line 3630
Quoted 8 lines
drivers/scsi/elx/libefc_sli/sli4.h +8
-0+struct sli4_rqst_cmn_read_object_s { +struct sli4_rqst_hdr_s hdr; +__le32 desired_read_length_dword; +__le32 read_offset; +u8 object_name[104 ]; +__le32 host_buffer_descriptor_count; +struct sli4_bde_s host_buffer_descriptor[0 ]; +};
Same ident for all members?
drivers/scsi/elx/libefc_sli/sli4.h struct sli4_fc_xri_aborted_cqe_s { · line 3641
Quoted 11 lines
drivers/scsi/elx/libefc_sli/sli4.h +11
-0+ +enum { +RSP_COM_READ_OBJ_EOF =0x80000000 + +}; + +struct sli4_rsp_cmn_read_object_s { +struct sli4_rsp_hdr_s hdr; +__le32 actual_read_length; +__le32 eof_dword; +};
Also here?
drivers/scsi/elx/libefc_sli/sli4.h struct sli4_fc_xri_aborted_cqe_s { · line 3652
Quoted 10 lines
drivers/scsi/elx/libefc_sli/sli4.h +10
-0+/** +* @brief COMMON_WRITE_OBJECT +*/ + +enum { +SLI4_RQ_DES_WRITE_LEN =0xFFFFFF , +SLI4_RQ_DES_WRITE_LEN_NOC =0x40000000 , +SLI4_RQ_DES_WRITE_LEN_EOF =0x80000000 + +};
New line too much and I would also add the ',' to the last member as it was done above. Furhtermore aligment of '='?
drivers/scsi/elx/libefc_sli/sli4.h struct sli4_fc_xri_aborted_cqe_s { · line 3661
Quoted 9 lines
drivers/scsi/elx/libefc_sli/sli4.h +9
-0+ +struct sli4_rqst_cmn_write_object_s { +struct sli4_rqst_hdr_s hdr; +__le32 desired_write_len_dword; +__le32 write_offset; +u8 object_name[104 ]; +__le32 host_buffer_descriptor_count; +struct sli4_bde_s host_buffer_descriptor[0 ]; +};
Aligment of the members?
drivers/scsi/elx/libefc_sli/sli4.h struct sli4_fc_xri_aborted_cqe_s { · line 3666
Quoted 4 lines
drivers/scsi/elx/libefc_sli/sli4.h +4
-0+enum { +RSP_CHANGE_STATUS =0xFF + +};
One newline too much and ',' on the member?
drivers/scsi/elx/libefc_sli/sli4.h struct sli4_fc_xri_aborted_cqe_s { · line 3672
Quoted 6 lines
drivers/scsi/elx/libefc_sli/sli4.h +6
-0+ +struct sli4_rsp_cmn_write_object_s { +struct sli4_rsp_hdr_s hdr; +__le32 actual_write_length; +__le32 change_status_dword; +};
One more aligment thingy
Quoted 9 lines
drivers/scsi/elx/libefc_sli/sli4.h +9
-0+ +/** +* @brief COMMON_DELETE_OBJECT +*/ +struct sli4_rqst_cmn_delete_object_s { +struct sli4_rqst_hdr_s hdr; +__le32 rsvd4; +__le32 rsvd5; +u8 object_name[104 ];
drivers/scsi/elx/libefc_sli/sli4.h struct sli4_fc_xri_aborted_cqe_s { · line 3691
Quoted 10 lines
drivers/scsi/elx/libefc_sli/sli4.h +10
-0+}; + +/** +* @brief COMMON_READ_OBJECT_LIST +*/ + +enum { +SLI4_RQ_OBJ_LIST_READ_LEN =0xFFFFFF + +};
Newline too much and and missing ','
drivers/scsi/elx/libefc_sli/sli4.h struct sli4_fc_xri_aborted_cqe_s { · line 3700
Quoted 9 lines
drivers/scsi/elx/libefc_sli/sli4.h +9
-0+ +struct sli4_rqst_cmn_read_object_list_s { +struct sli4_rqst_hdr_s hdr; +__le32 desired_read_length_dword; +__le32 read_offset; +u8 object_name[104 ]; +__le32 host_buffer_descriptor_count; +struct sli4_bde_s host_buffer_descriptor[0 ]; +};
aliment of the members
drivers/scsi/elx/libefc_sli/sli4.h struct sli4_fc_xri_aborted_cqe_s { · line 3712
Quoted 12 lines
drivers/scsi/elx/libefc_sli/sli4.h +12
-0+ +/** +* @brief COMMON_SET_DUMP_LOCATION +*/ + +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 , + +};
Newline too much
drivers/scsi/elx/libefc_sli/sli4.h struct sli4_fc_xri_aborted_cqe_s { · line 3719
Quoted 7 lines
drivers/scsi/elx/libefc_sli/sli4.h +7
-0+ +struct sli4_rqst_cmn_set_dump_location_s { +struct sli4_rqst_hdr_s hdr; +__le32 buffer_length_dword; +__le32 buf_addr_low; +__le32 buf_addr_high; +};
same comment as above
drivers/scsi/elx/libefc_sli/sli4.h struct sli4_fc_xri_aborted_cqe_s { · line 3724
Quoted 5 lines
drivers/scsi/elx/libefc_sli/sli4.h +5
-0+ +enum { +RSP_SET_DUMP_BUFFER_LEN =0xFFFFFF + +};
same comment as above
drivers/scsi/elx/libefc_sli/sli4.h struct sli4_fc_xri_aborted_cqe_s { · line 3729
Quoted 5 lines
drivers/scsi/elx/libefc_sli/sli4.h +5
-0+ +struct sli4_rsp_cmn_set_dump_location_s { +struct sli4_rsp_hdr_s hdr; +__le32 buffer_length_dword; +};
same comment as above
Quoted 14 lines
drivers/scsi/elx/libefc_sli/sli4.h +14
-0+ +/** +* @brief COMMON_SET_SET_FEATURES +*/ +#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
drivers/scsi/elx/libefc_sli/sli4.h struct sli4_fc_xri_aborted_cqe_s { · line 3753
Quoted 10 lines
drivers/scsi/elx/libefc_sli/sli4.h +10
-0+#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_s { +struct sli4_rqst_hdr_s hdr; +__le32 feature; +__le32 param_len; +__le32 params[8 ]; +};
same comment as above
drivers/scsi/elx/libefc_sli/sli4.h struct sli4_fc_xri_aborted_cqe_s { · line 3763
Quoted 10 lines
drivers/scsi/elx/libefc_sli/sli4.h +10
-0+ +struct sli4_rqst_cmn_set_features_dif_seed_s { +__le16 seed; +__le16 rsvd16; +}; + +enum { +SLI4_RQ_COM_SET_T10_PI_MEM_MODEL =0x1 + +};
same comment as above
drivers/scsi/elx/libefc_sli/sli4.h struct sli4_fc_xri_aborted_cqe_s { · line 3775
Quoted 12 lines
drivers/scsi/elx/libefc_sli/sli4.h +12
-0+ +struct sli4_rqst_cmn_set_features_t10_pi_mem_model_s { +__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 +};
aligment of '='?
drivers/scsi/elx/libefc_sli/sli4.h struct sli4_fc_xri_aborted_cqe_s { · line 3781
Quoted 6 lines
drivers/scsi/elx/libefc_sli/sli4.h +6
-0+ +struct sli4_rqst_cmn_set_features_multirq_s { +__le32 auto_gen_xfer_dword;/* Include Sequence Reporting */ +/* Auto Generate XFER-RDY Enabled */ +__le32 num_rqs_dword; +};
Aligment of the comment?
drivers/scsi/elx/libefc_sli/sli4.h struct sli4_fc_xri_aborted_cqe_s { · line 3789
Quoted 8 lines
drivers/scsi/elx/libefc_sli/sli4.h +8
-0+ +enum { +SLI4_SETFEAT_XFERRDY_T10PI_RTC = (1 <<0 ),/* DW0 */ +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 ), +};
Aligment of the '='
drivers/scsi/elx/libefc_sli/sli4.h struct sli4_fc_xri_aborted_cqe_s { · line 3801
Quoted 12 lines
drivers/scsi/elx/libefc_sli/sli4.h +12
-0+ +struct sli4_rqst_cmn_set_features_xfer_rdy_t10pi_s { +__le32 dw0_flags; +__le16 app_tag; +__le16 rsvd6; +}; + +enum { +SLI4_RQ_HEALTH_CHECK_ENABLE =0x1 , +SLI4_RQ_HEALTH_CHECK_QUERY =0x2 + +};
Newline and missing ',' on the last entry.
I stop here pointing out the same issues for the rest of this patch. There are few more of those alignment issues in my opinion.q
drivers/scsi/elx/libefc_sli/sli4.h struct sli4_fc_xri_aborted_cqe_s { · line 4192
Quoted 4 lines
drivers/scsi/elx/libefc_sli/sli4.h +4
-0+struct sli4_s { +void *os; +struct pci_dev *pcidev; +#define SLI_PCI_MAX_REGS 6
I would move the define in front of the struct.
drivers/scsi/elx/libefc_sli/sli4.h struct sli4_fc_xri_aborted_cqe_s { · line 4194
Quoted 2 lines
drivers/scsi/elx/libefc_sli/sli4.h +2
-0+void __iomem *reg[SLI_PCI_MAX_REGS ]; +
Thanks,
Daniel
Re: [PATCH 03/32] elx: libefc_sli: Data structures and defines for mbox commands
Quoted 29 lines · Daniel Wagner
Quoted 14 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 | 1996 ++++++++++++++++++++++++++++++++++++ 1 file changed, 1996 insertions(+)drivers/scsi/elx/libefc_sli/sli4.h +1
-0+#define SLI_ROUND_PAGE (b) (((b) + SLI_SUB_PAGE_MASK) & ~SLI_SUB_PAGE_MASK)drivers/scsi/elx/libefc_sli/sli4.h struct sli4_fc_xri_aborted_cqe_s { · line 3357
Quoted 10 lines
drivers/scsi/elx/libefc_sli/sli4.h +10
-0+/** +* @brief COMMON_GET_SLI4_PARAMETERS +*/ + +#define GET_Q_CNT_METHOD (val)\ + ((val & RSP_GET_PARAM_Q_CNT_MTHD_MASK)\ + >> RSP_GET_PARAM_Q_CNT_MTHD_SHFT) +#define GET_Q_CREATE_VERSION (val)\ + ((val & RSP_GET_PARAM_QV_MASK)\ + >> RSP_GET_PARAM_QV_SHIFT)This time there is no space in front of '\'. Does the expresssion not fit on one line? Would be easier to read:
Quoted 2 lines
#define GET_Q_CREATE_VERSION(val) \ ((val & RSP_GET_PARAM_QV_MASK) >> RSP_GET_PARAM_QV_SHIFT)
Protect the macro argument in the expansion with parentheses to prevent unintended operator precedence during evaluation? As with (b) of SLI_ROUND_PAGE(b) above.
(((val) & ... ))
Signature · 11 lines
Mit freundlichen Gruessen / Kind regards Steffen Maier Linux on IBM Z Development https://www.ibm.com/privacy/us/en/ IBM Deutschland Research & Development GmbH Vorsitzender des Aufsichtsrats: Matthias Hartmann Geschaeftsfuehrung: Dirk Wittkopp Sitz der Gesellschaft: Boeblingen Registergericht: Amtsgericht Stuttgart, HRB 243294
Re: [PATCH 03/32] elx: libefc_sli: Data structures and defines for mbox commands
Quoted 4 lines · Steffen Maier
Protect the macro argument in the expansion with parentheses to prevent unintended operator precedence during evaluation? As with (b) of
SLI_ROUND_PAGE(b)above.(((val) & ... ))
yep, agree. Thanks
-- james
Re: [PATCH 03/32] elx: libefc_sli: Data structures and defines for mbox commands
In reply to Daniel WagnerThanks. We mostly agree with the comment written and will work on the changes. Agreed that consistency and uniformity helps.
Exceptions or answers to questions are inline below.
-- james
Quoted 3 lines · Daniel Wagner
Quoted 1 line
+#define
SLI_PAGE_SIZE(1 << 12) /* 4096 */So
SLI_PAGE_SIZEis fixed and can't be changed...
For how the driver uses the SLI interface in this current implementation, yes. The interface's page size is independent from what the OS's pagesize is.
Quoted 19 lines
... and callers of this function pass in
SLI_PAGE_SIZE.Quoted 17 lines
drivers/scsi/elx/libefc_sli/sli4.h +17
-0+{ +u32 mask = page_size -1 ; +u32 shift =0 ; + +switch (page_size) { +case 4096 : + shift =12 ; +break ; +case 8192 : + shift =13 ; +break ; +case 16384 : + shift =14 ; +break ; +case 32768 : + shift =15 ; +break ;
Quoted 8 lines
drivers/scsi/elx/libefc_sli/sli4.h struct sli4_fc_xri_aborted_cqe_s { · line 2301
Quoted 6 lines
drivers/scsi/elx/libefc_sli/sli4.h +6
-0+case 65536 : + shift =16 ; +break ; +default : +return 0 ; + }What about using
__ffs(page_size)? But...
will look into it...
Quoted 6 lines
Review
Quoted 3 lines
(quoted diff) +2
-0+ + return (bytes + mask) >> shift;... mask and shift could just be defined like
SLI_PAGE_SIZEand we safe a few instructions. UnlessSLI_PAGE_SIZEwill be dynamic in future.
desire is to keep it easily adapted. There's actually some conditions that could have us use different page sizes for different structures.
PATCH 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 | 18 + drivers/scsi/elx/libefc_sli/sli4.c | 2155 +++++++++++++++++++++++++++++++++ 2 files changed, 2173 insertions(+)
drivers/scsi/elx/include/efc_common.h +18 -0
@@ -23,4 +23,22 @@ struct efc_dma_s {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) +#endif /* __EFC_COMMON_H__ */
drivers/scsi/elx/libefc_sli/sli4.c +2155 -0
2,158 lines not on this page · raw message
Signature · 1 line
2.13.7
Re: [PATCH 04/32] elx: libefc_sli: queue create/destroy/parse routines
Hi James,
Quoted 54 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 | 18 + drivers/scsi/elx/libefc_sli/sli4.c | 2155 +++++++++++++++++++++++++++++++++ 2 files changed, 2173 insertions(+)drivers/scsi/elx/include/efc_common.h +18
-0@@ -23,4 +23,22 @@ struct efc_dma_s {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) +#endif /* __EFC_COMMON_H__ */ drivers/scsi/elx/libefc_sli/sli4.c +7
-0@@ -24,3 +24,2158 @@ 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}, }; + +/* +* @brief Convert queue type enum (SLI_QTYPE_*) into a string. +*/ +static char *SLI_QNAME [] = { +"Event Queue" , + "Completion Queue",
drivers/scsi/elx/libefc_sli/sli4.c static struct sli4_asic_entry_t sli4_asic_table[] = { · line 43
Quoted 10 lines
drivers/scsi/elx/libefc_sli/sli4.c +10
-0+"Mailbox Queue" , +"Work Queue" , +"Receive Queue" , + "Undefined" +}; + +/** +* @ingroup sli +* @brief Write a SLI_CONFIG command to the provided buffer. +*
Could add some additional comments about the size and dma parameter...
Quoted 11 lines
drivers/scsi/elx/libefc_sli/sli4.c +11
-0+* @param sli4 SLI context pointer. +* @param buf Virtual pointer to the destination buffer. +* @param size Buffer size, in bytes. +* @param length Length in bytes of attached command. +* @param dma DMA buffer for non-embedded commands. +* +* @return Returns the number of bytes written. +*/ +static void * +sli_config_cmd_init(struct sli4_s *sli4, void *buf, + size_t size, u32 length,
drivers/scsi/elx/libefc_sli/sli4.c static struct sli4_asic_entry_t sli4_asic_table[] = { · line 64
Quoted 10 lines
drivers/scsi/elx/libefc_sli/sli4.c +10
-0+ struct efc_dma_s *dma) +{ +struct sli4_cmd_sli_config_s *sli_config =NULL ; +u32 flags =0 ; + +if (length >sizeof (sli_config->payload.embed) && !dma) { +efc_log_info (sli4,"length(%d) > payload(%ld)\n" , + length,sizeof (sli_config->payload.embed)); +return NULL ; + }
...this logs something but what does it tell? I suppose it has something to do if a data are embedded or not.
drivers/scsi/elx/libefc_sli/sli4.c static struct sli4_asic_entry_t sli4_asic_table[] = { · line 74
Quoted 9 lines
drivers/scsi/elx/libefc_sli/sli4.c +9
-0+ sli_config = buf; + +memset (buf,0 , size); + + sli_config->hdr.command =MBX_CMD_SLI_CONFIG ; +if (!dma) { + flags |=SLI4_SLICONF_EMB ; + sli_config->dw1_flags =cpu_to_le32 (flags); + sli_config->payload_len =cpu_to_le32 (length);
Could you move the last return here ...
drivers/scsi/elx/libefc_sli/sli4.c static struct sli4_asic_entry_t sli4_asic_table[] = { · line 74
Quoted 1 line
drivers/scsi/elx/libefc_sli/sli4.c +1
-0+ }else {
... and get rid of this else here? Easier to read in my opinion because the control flow is not splittet over the else part.
Quoted 21 lines
drivers/scsi/elx/libefc_sli/sli4.c +21
-0+ flags =SLI4_SLICONF_PMDCMD_VAL_1 ;/* pmd_count = 1 */ + flags &= ~SLI4_SLICONF_EMB ; + sli_config->dw1_flags =cpu_to_le32 (flags); + + sli_config->payload.mem.addr.low = +cpu_to_le32 (lower_32_bits (dma->phys)); + sli_config->payload.mem.addr.high = +cpu_to_le32 (upper_32_bits (dma->phys)); + sli_config->payload.mem.length = +cpu_to_le32 (dma->size &SLI4_SLICONFIG_PMD_LEN ); + sli_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; + } + + return buf + offsetof(struct sli4_cmd_sli_config_s, payload.embed); +} + +/** +* @brief Write a COMMON_CREATE_CQ command.
drivers/scsi/elx/libefc_sli/sli4.c static struct sli4_asic_entry_t sli4_asic_table[] = { · line 106
Quoted 10 lines
drivers/scsi/elx/libefc_sli/sli4.c +10
-0+* +* @param sli4 SLI context. +* @param buf Destination buffer for the command. +* @param size Buffer size, in bytes. +* @param qmem DMA memory for the queue. +* @param eq_id Associated EQ_ID +* @param ignored This parameter carries the ULP +* which is only used for WQ and RQs +* +* @note This creates a Version 0 message.
I wonder if this should be encoded into the function name?
drivers/scsi/elx/libefc_sli/sli4.c static struct sli4_asic_entry_t sli4_asic_table[] = { · line 115
Quoted 9 lines
drivers/scsi/elx/libefc_sli/sli4.c +9
-0+* +* @return Returns 0 on success, or non-zero otherwise. +*/ +static int +sli_cmd_common_create_cq (struct sli4_s *sli4,void *buf,size_t size, +struct efc_dma_s *qmem, +u16 eq_id) +{ +struct sli4_rqst_cmn_create_cq_v2_s *cqv2 =NULL ;
too many spaces between the type and the variable name.
Quoted 14 lines
drivers/scsi/elx/libefc_sli/sli4.c +14
-0+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 ; + +/* First calculate number of pages and the mailbox cmd length */ + n_cqe = qmem->size /SLI4_CQE_BYTES ; +switch (n_cqe) { +case 256 :
drivers/scsi/elx/libefc_sli/sli4.c static struct sli4_asic_entry_t sli4_asic_table[] = { · line 139
Quoted 10 lines
drivers/scsi/elx/libefc_sli/sli4.c +10
-0+case 512 : +case 1024 : +case 2048 : + page_size =1 ; +break ; +case 4096 : + page_size =2 ; +break ; +default : +return EFC_FAIL ;
If it's an error code it should probably be an negative value.
I would also go with something like
if (n_cqe <= 2048) page_size = 1; else if (n_cqe == 4096) page_size = 2; else return -EFC_FAIL;
since this results into a smaller code and I find simpler to read. It is not completely equivalent since your version limits the values to 256, 512, 1024, 2048 and 4096. My version tolerates all values below 2048. Since the same switch pattern is repeated below (see sli_cmd_wq_create_v1) am not utterly sure if my idea is good.
drivers/scsi/elx/libefc_sli/sli4.c static struct sli4_asic_entry_t sli4_asic_table[] = { · line 152
Quoted 13 lines
drivers/scsi/elx/libefc_sli/sli4.c +13
-0+ } + 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 ; + + cqv2->hdr.opcode =CMN_CREATE_CQ ; + cqv2->hdr.subsystem =SLI4_SUBSYSTEM_COMMON ; + cqv2->hdr.dw3_version =cpu_to_le32 (CMD_V2 );
Is this now a the command version? Shouldn't it be V0 as the documentation writes?
drivers/scsi/elx/libefc_sli/sli4.c static struct sli4_asic_entry_t sli4_asic_table[] = { · line 161
Quoted 9 lines
drivers/scsi/elx/libefc_sli/sli4.c +9
-0+ cmd_size =CFG_RQST_PYLD_LEN_VAR (cmn_create_cq_v2, +SZ_DMAADDR * num_pages); + cqv2->hdr.request_length = cmd_size; + 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_COMMON_CREATE_CQ_V2_MAX_PAGES ) {
I would write the condition on one line. There is still enough space left on the line.
Quoted 10 lines
drivers/scsi/elx/libefc_sli/sli4.c +10
-0+return EFC_FAIL ; + } + +switch (num_pages) { +case 1 : + dw5_flags |=CQ_CNT_VAL (256 ); +break ; +case 2 : + dw5_flags |=CQ_CNT_VAL (512 ); +break ;
drivers/scsi/elx/libefc_sli/sli4.c static struct sli4_asic_entry_t sli4_asic_table[] = { · line 181
Quoted 10 lines
drivers/scsi/elx/libefc_sli/sli4.c +10
-0+case 4 : + dw5_flags |=CQ_CNT_VAL (1024 ); +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 -1 ;
return -EFC_FAIL; ?
Quoted 4 lines
drivers/scsi/elx/libefc_sli/sli4.c +4
-0+ } + +if (sli4->if_type ==SLI4_INTF_IF_TYPE_6 ) + dw5_flags |=CREATE_CQV2_AUTOVALID ;
drivers/scsi/elx/libefc_sli/sli4.c static struct sli4_asic_entry_t sli4_asic_table[] = { · line 195
Quoted 10 lines
drivers/scsi/elx/libefc_sli/sli4.c +10
-0+ + 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) {
This fits on one line, exact 80 chars :)
drivers/scsi/elx/libefc_sli/sli4.c static struct sli4_asic_entry_t sli4_asic_table[] = { · line 200
Quoted 5 lines
drivers/scsi/elx/libefc_sli/sli4.c +5
-0+ 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)); + }
Also these two assignment fit into 80 chars.
Quoted 13 lines
drivers/scsi/elx/libefc_sli/sli4.c +13
-0+ +return EFC_SUCCESS ; +} + +/** +* @brief Write a COMMON_DESTROY_CQ command. +* +* @param sli4 SLI context. +* @param buf Destination buffer for the command. +* @param size Buffer size, in bytes. +* @param cq_id CQ ID +* +* @note This creates a Version 0 message.
drivers/scsi/elx/libefc_sli/sli4.c static struct sli4_asic_entry_t sli4_asic_table[] = { · line 223
Quoted 10 lines
drivers/scsi/elx/libefc_sli/sli4.c +10
-0+* +* @return Returns 0 on success, or non-zero otherwise. +*/ +static int +sli_cmd_common_destroy_cq (struct sli4_s *sli4,void *buf, +size_t size,u16 cq_id) +{ +struct sli4_rqst_cmn_destroy_cq_s *cq =NULL ; + +/* Payload length must accommodate both request and response */
Is this common? Is this true for all commands? If so maybe have this kind of information at the beginning of the file explaining some of the inner workings of the code would certainly help.
drivers/scsi/elx/libefc_sli/sli4.c static struct sli4_asic_entry_t sli4_asic_table[] = { · line 227
Quoted 4 lines
drivers/scsi/elx/libefc_sli/sli4.c +4
-0+ cq =sli_config_cmd_init (sli4, buf, size, +SLI_CONFIG_PYLD_LENGTH (cmn_destroy_cq),NULL ); +if (!cq) +return EFC_FAIL ;
return -EFC_FAIL ?
(I stop report this one now)
Quoted 10 lines
drivers/scsi/elx/libefc_sli/sli4.c +10
-0+ + cq->hdr.opcode =CMN_DESTROY_CQ ; + cq->hdr.subsystem =SLI4_SUBSYSTEM_COMMON ; + cq->hdr.request_length =CFG_RQST_PYLD_LEN (cmn_destroy_cq); + cq->cq_id =cpu_to_le16 (cq_id); + +return EFC_SUCCESS ; +} + +/**
drivers/scsi/elx/libefc_sli/sli4.c static struct sli4_asic_entry_t sli4_asic_table[] = { · line 247
Quoted 10 lines
drivers/scsi/elx/libefc_sli/sli4.c +10
-0+* @brief Write a COMMON_CREATE_EQ command. +* +* @param sli4 SLI context. +* @param buf Destination buffer for the command. +* @param size Buffer size, in bytes. +* @param qmem DMA memory for the queue. +* @param ignored1 Ignored +* (used for consistency among queue creation functions). +* @param ignored2 Ignored +* (used for consistency among queue creation functions).
There is no ignored2 in the function declarations.
drivers/scsi/elx/libefc_sli/sli4.c static struct sli4_asic_entry_t sli4_asic_table[] = { · line 260
Quoted 13 lines
drivers/scsi/elx/libefc_sli/sli4.c +13
-0+* +* @note Other queue creation routines use the last parameter to pass in +* the associated Q_ID and ULP. EQ doesn't have an associated queue or ULP, +* so these parameters are ignored +* +* @note This creates a Version 0 message +* +* @return Returns 0 on success, or non-zero otherwise. +*/ +static int +sli_cmd_common_create_eq (struct sli4_s *sli4,void *buf,size_t size, +struct efc_dma_s *qmem, +u16 ignored1)
If you want to be consistent with the other function declarations, ignored1 should go on the same line as qmem.
drivers/scsi/elx/libefc_sli/sli4.c static struct sli4_asic_entry_t sli4_asic_table[] = { · line 261
Quoted 2 lines
drivers/scsi/elx/libefc_sli/sli4.c +2
-0+{ +struct sli4_rqst_cmn_create_eq_s *eq =NULL ;
No need to set eq to NULL because it will set as first thing in the function
drivers/scsi/elx/libefc_sli/sli4.c static struct sli4_asic_entry_t sli4_asic_table[] = { · line 270
Quoted 8 lines
drivers/scsi/elx/libefc_sli/sli4.c +8
-0+u32 p; +uintptr_t addr; +u16 num_pages; +u32 dw5_flags =0 ; +u32 dw6_flags =0 ; + + eq =sli_config_cmd_init (sli4, buf, size, +SLI_CONFIG_PYLD_LENGTH (cmn_create_eq),NULL );
You should test for NULL since sli_config_cmd_init() can return NULL.
drivers/scsi/elx/libefc_sli/sli4.c static struct sli4_asic_entry_t sli4_asic_table[] = { · line 275
Quoted 5 lines
drivers/scsi/elx/libefc_sli/sli4.c +5
-0+ + eq->hdr.opcode =CMN_CREATE_EQ ; + eq->hdr.subsystem =SLI4_SUBSYSTEM_COMMON ; +if (sli4->if_type ==SLI4_INTF_IF_TYPE_6 ) + eq->hdr.dw3_version =cpu_to_le32 (CMD_V2 );
Same question on the command version number as above.
Quoted 26 lines
drivers/scsi/elx/libefc_sli/sli4.c +26
-0+ + eq->hdr.request_length =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_info (sli4,"num_pages %d not valid\n" , num_pages); +return EFC_FAIL ; + } + +if (sli4->if_type ==SLI4_INTF_IF_TYPE_6 )
drivers/scsi/elx/libefc_sli/sli4.c static struct sli4_asic_entry_t sli4_asic_table[] = { · line 311
Quoted 10 lines
drivers/scsi/elx/libefc_sli/sli4.c +10
-0+ 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 ) {
One line?
Quoted 8 lines
drivers/scsi/elx/libefc_sli/sli4.c +8
-0+ 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 ; +} + +/**
drivers/scsi/elx/libefc_sli/sli4.c static struct sli4_asic_entry_t sli4_asic_table[] = { · line 329
Quoted 10 lines
drivers/scsi/elx/libefc_sli/sli4.c +10
-0+* @brief Write a COMMON_DESTROY_EQ command. +* +* @param sli4 SLI context. +* @param buf Destination buffer for the command. +* @param size Buffer size, in bytes. +* @param eq_id Queue ID to destroy. +* +* @note Other queue creation routines use the last parameter to pass in +* the associated Q_ID. EQ doesn't have an associated queue so this +* parameter is ignored.
Too much copy paste?
drivers/scsi/elx/libefc_sli/sli4.c static struct sli4_asic_entry_t sli4_asic_table[] = { · line 339
Quoted 10 lines
drivers/scsi/elx/libefc_sli/sli4.c +10
-0+* +* @note This creates a Version 0 message. +* +* @return Returns zero for success and non-zero for failure. +*/ +static int +sli_md_common_destroy_eq (struct sli4_s *sli4,void *buf,size_t size, +u16 eq_id) +{ +struct sli4_rqst_cmn_destroy_eq_s *eq =NULL ;
No need to initialized eq
Quoted 26 lines
drivers/scsi/elx/libefc_sli/sli4.c +26
-0+ + eq =sli_config_cmd_init (sli4, buf, size, +SLI_CONFIG_PYLD_LENGTH (cmn_destroy_eq),NULL ); +if (!eq) +return EFC_FAIL ; + + eq->hdr.opcode =CMN_DESTROY_EQ ; + eq->hdr.subsystem =SLI4_SUBSYSTEM_COMMON ; + eq->hdr.request_length =CFG_RQST_PYLD_LEN (cmn_destroy_eq); + + eq->eq_id =cpu_to_le16 (eq_id); + +return EFC_SUCCESS ; +} + +/** +* @brief Write a COMMON_CREATE_MQ_EXT command. +* +* @param sli4 SLI context. +* @param buf Destination buffer for the command. +* @param size Buffer size, in bytes. +* @param qmem DMA memory for the queue. +* @param cq_id Associated CQ_ID. +* @param ignored This parameter carries the ULP +* which is only used for WQ and RQs +*
drivers/scsi/elx/libefc_sli/sli4.c static struct sli4_asic_entry_t sli4_asic_table[] = { · line 375
Quoted 10 lines
drivers/scsi/elx/libefc_sli/sli4.c +10
-0+* @note This creates a Version 0 message. +* +* @return Returns zero for success and non-zero for failure. +*/ +static int +sli_cmd_common_create_mq_ext (struct sli4_s *sli4,void *buf,size_t size, +struct efc_dma_s *qmem, +u16 cq_id) +{ +struct sli4_rqst_cmn_create_mq_ext_s *mq =NULL ;
Too many spaces between type and variable.
Quoted 39 lines
drivers/scsi/elx/libefc_sli/sli4.c +39
-0+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 ; + + mq->hdr.opcode =CMN_CREATE_MQ_EXT ; + mq->hdr.subsystem =SLI4_SUBSYSTEM_COMMON ; + mq->hdr.request_length =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) {
drivers/scsi/elx/libefc_sli/sli4.c static struct sli4_asic_entry_t sli4_asic_table[] = { · line 424
Quoted 10 lines
drivers/scsi/elx/libefc_sli/sli4.c +10
-0+ 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 ) {
On one line?
drivers/scsi/elx/libefc_sli/sli4.c static struct sli4_asic_entry_t sli4_asic_table[] = { · line 428
Quoted 4 lines
drivers/scsi/elx/libefc_sli/sli4.c +4
-0+ 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));
And these as well?
Quoted 26 lines
drivers/scsi/elx/libefc_sli/sli4.c +26
-0+ } + +return EFC_SUCCESS ; +} + +/** +* @brief Write a COMMON_DESTROY_MQ command. +* +* @param sli4 SLI context. +* @param buf Destination buffer for the command. +* @param size Buffer size, in bytes. +* @param mq_id MQ ID +* +* @note This creates a Version 0 message. +* +* @return Returns zero for success and non-zero for failure. +*/ +static int +sli_cmd_common_destroy_mq (struct sli4_s *sli4,void *buf,size_t size, +u16 mq_id) +{ +struct sli4_rqst_cmn_destroy_mq_s *mq =NULL ; + + mq =sli_config_cmd_init (sli4, buf, size, +SLI_CONFIG_PYLD_LENGTH (cmn_destroy_mq),NULL ); +if (!mq)
drivers/scsi/elx/libefc_sli/sli4.c static struct sli4_asic_entry_t sli4_asic_table[] = { · line 464
Quoted 10 lines
drivers/scsi/elx/libefc_sli/sli4.c +10
-0+return EFC_FAIL ; + + mq->hdr.opcode =CMN_DESTROY_MQ ; + mq->hdr.subsystem =SLI4_SUBSYSTEM_COMMON ; + mq->hdr.request_length =CFG_RQST_PYLD_LEN (cmn_destroy_mq); + + mq->mq_id =cpu_to_le16 (mq_id); + +return EFC_SUCCESS ; +}
sli_cmd_common_destroy_eq(), sli_cmd_common_destroy_cq() and sli_cmd_common_destroy_mq() look almost identically. Could those function be unified?
Quoted 10 lines
drivers/scsi/elx/libefc_sli/sli4.c +10
-0+ +/** +* @ingroup sli_fc +* @brief Write an WQ_CREATE command. +* +* @param sli4 SLI context. +* @param buf Destination buffer for the command. +* @param size Buffer size, in bytes. +* @param qmem DMA memory for the queue. +* @param cq_id Associated CQ_ID.
drivers/scsi/elx/libefc_sli/sli4.c static struct sli4_asic_entry_t sli4_asic_table[] = { · line 484
Quoted 10 lines
drivers/scsi/elx/libefc_sli/sli4.c +10
-0+* +* @note This creates a Version 0 message. +* +* @return Returns zero for success and non-zero for failure. +*/ +int +sli_cmd_wq_create (struct sli4_s *sli4,void *buf,size_t size, +struct efc_dma_s *qmem,u16 cq_id) +{ +struct sli4_rqst_wq_create_s *wq =NULL ;
Too many spaces between type and variable.
Quoted 6 lines
drivers/scsi/elx/libefc_sli/sli4.c +6
-0+u32 p; +uintptr_t addr; + + wq =sli_config_cmd_init (sli4, buf, size, +SLI_CONFIG_PYLD_LENGTH (wq_create),NULL ); +if (!wq)
drivers/scsi/elx/libefc_sli/sli4.c static struct sli4_asic_entry_t sli4_asic_table[] = { · line 500
Quoted 10 lines
drivers/scsi/elx/libefc_sli/sli4.c +10
-0+return EFC_FAIL ; + + wq->hdr.opcode =SLI4_OPC_WQ_CREATE ; + wq->hdr.subsystem =SLI4_SUBSYSTEM_FC ; + wq->hdr.request_length =CFG_RQST_PYLD_LEN (wq_create); + +/* valid values for number of pages: 1-4 (sec 4.5.1) */ + wq->num_pages =sli_page_count (qmem->size,SLI_PAGE_SIZE ); +if (!wq->num_pages || + wq->num_pages >SLI4_WQ_CREATE_V0_MAX_PAGES )
On one line
drivers/scsi/elx/libefc_sli/sli4.c static struct sli4_asic_entry_t sli4_asic_table[] = { · line 511
Quoted 11 lines
drivers/scsi/elx/libefc_sli/sli4.c +11
-0+return EFC_FAIL ; + + wq->cq_id =cpu_to_le16 (cq_id); + +for (p =0 , addr = qmem->phys; + p < wq->num_pages; + p++, addr +=SLI_PAGE_SIZE ) { + 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));
At least the last two assignments fit on one line.
Quoted 11 lines
drivers/scsi/elx/libefc_sli/sli4.c +11
-0+ } + +return EFC_SUCCESS ; +} + +/** +* @ingroup sli_fc +* @brief Write an WQ_CREATE_V1 command. +* +* @param sli4 SLI context. +* @param buf Destination buffer for the command.
drivers/scsi/elx/libefc_sli/sli4.c static struct sli4_asic_entry_t sli4_asic_table[] = { · line 532
Quoted 10 lines
drivers/scsi/elx/libefc_sli/sli4.c +10
-0+* @param size Buffer size, in bytes. +* @param qmem DMA memory for the queue. +* @param cq_id Associated CQ_ID. +* +* @return Returns zero for success and non-zero for failure. +*/ +int +sli_cmd_wq_create_v1 (struct sli4_s *sli4,void *buf,size_t size, +struct efc_dma_s *qmem, +u16 cq_id)
cq_id on the same line as qmem?
Quoted 14 lines
drivers/scsi/elx/libefc_sli/sli4.c +14
-0+{ +struct sli4_rqst_wq_create_v1_s *wq =NULL ; +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_v1),NULL ); +if (!wq) +return EFC_FAIL ; +
drivers/scsi/elx/libefc_sli/sli4.c static struct sli4_asic_entry_t sli4_asic_table[] = { · line 556
Quoted 10 lines
drivers/scsi/elx/libefc_sli/sli4.c +10
-0+ wq->hdr.opcode =SLI4_OPC_WQ_CREATE ; + wq->hdr.subsystem =SLI4_SUBSYSTEM_FC ; + wq->hdr.request_length =CFG_RQST_PYLD_LEN (wq_create_v1); + wq->hdr.dw3_version =cpu_to_le32 (CMD_V1 ); + + n_wqe = qmem->size / sli4->wqe_size; + +/* +* This heuristic to determine the page size is simplistic but could +* be made more sophisticated
Okay, but what is too simple?
Quoted 12 lines
drivers/scsi/elx/libefc_sli/sli4.c +12
-0+*/ +switch (qmem->size) { +case 4096 : +case 8192 : +case 16384 : +case 32768 : + page_size =1 ; +break ; +case 65536 : + page_size =2 ; +break ; +case 131072 :
drivers/scsi/elx/libefc_sli/sli4.c static struct sli4_asic_entry_t sli4_asic_table[] = { · line 578
Quoted 10 lines
drivers/scsi/elx/libefc_sli/sli4.c +10
-0+ page_size =4 ; +break ; +case 262144 : + page_size =8 ; +break ; +case 524288 : + page_size =10 ; +break ; +default : +return 0 ;
Isn't this an error?
drivers/scsi/elx/libefc_sli/sli4.c static struct sli4_asic_entry_t sli4_asic_table[] = { · line 582
Quoted 4 lines
drivers/scsi/elx/libefc_sli/sli4.c +4
-0+ } + page_bytes = page_size *SLI_PAGE_SIZE ; + +/* valid values for number of pages: 1-8 */
This comment is for num_pages, right? If so maybe it helps to add the variable name to the comment "... number of pages (num_pages): 1.8". I got slightly distracted by page_size :)
drivers/scsi/elx/libefc_sli/sli4.c static struct sli4_asic_entry_t sli4_asic_table[] = { · line 586
Quoted 4 lines
drivers/scsi/elx/libefc_sli/sli4.c +4
-0+ 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_V1_MAX_PAGES )
On one line?
Quoted 10 lines
drivers/scsi/elx/libefc_sli/sli4.c +10
-0+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 ;
drivers/scsi/elx/libefc_sli/sli4.c static struct sli4_asic_entry_t sli4_asic_table[] = { · line 606
Quoted 10 lines
drivers/scsi/elx/libefc_sli/sli4.c +10
-0+ + 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));
These assignments fit on one line
Quoted 25 lines
drivers/scsi/elx/libefc_sli/sli4.c +25
-0+ } + +return EFC_SUCCESS ; +} + +/** +* @ingroup sli_fc +* @brief Write an WQ_DESTROY command. +* +* @param sli4 SLI context. +* @param buf Destination buffer for the command. +* @param size Buffer size, in bytes. +* @param wq_id WQ_ID. +* +* @return Returns zero for success and non-zero for failure. +*/ +int +sli_cmd_wq_destroy (struct sli4_s *sli4,void *buf,size_t size, +u16 wq_id) +{ +struct sli4_rqst_wq_destroy_s *wq =NULL ; + + wq =sli_config_cmd_init (sli4, buf, size, +SLI_CONFIG_PYLD_LENGTH (wq_destroy),NULL ); +if (!wq)
drivers/scsi/elx/libefc_sli/sli4.c static struct sli4_asic_entry_t sli4_asic_table[] = { · line 641
Quoted 10 lines
drivers/scsi/elx/libefc_sli/sli4.c +10
-0+return EFC_FAIL ; + + wq->hdr.opcode =SLI4_OPC_WQ_DESTROY ; + wq->hdr.subsystem =SLI4_SUBSYSTEM_FC ; + wq->hdr.request_length =CFG_RQST_PYLD_LEN (wq_destroy); + + wq->wq_id =cpu_to_le16 (wq_id); + +return EFC_SUCCESS ; +}
So many function look almost identical. Is there no better way to create the commands? Or is something like a generic command creation function worse to maintain? There is so much copy paste... I stop now pointing out the same issues again.
Thanks,
Daniel
Re: [PATCH 04/32] elx: libefc_sli: queue create/destroy/parse routines
Thanks. We mostly agree with the comment written and will work on the changes.
Exceptions or answers to questions are inline below.
-- james
Quoted 8 lines · Daniel Wagner
Quoted 8 lines
drivers/scsi/elx/libefc_sli/sli4.c +8
-0+static void * +sli_config_cmd_init (struct sli4_s *sli4,void *buf, +size_t size,u32 length, +struct efc_dma_s *dma) +{ +struct sli4_cmd_sli_config_s *sli_config =NULL ; +u32 flags =0 ; +
Quoted 8 lines
drivers/scsi/elx/libefc_sli/sli4.c static struct sli4_asic_entry_t sli4_asic_table[] = { · line 64
Quoted 5 lines
drivers/scsi/elx/libefc_sli/sli4.c +5
-0+if (length >sizeof (sli_config->payload.embed) && !dma) { +efc_log_info (sli4,"length(%d) > payload(%ld)\n" , + length,sizeof (sli_config->payload.embed)); +return NULL ; + }...this logs something but what does it tell? I suppose it has something to do if a data are embedded or not.
yep - if its too big to be embedded and there's isn't a dma address to use for non-embedded format, it's an error. We will make that log message reflect what I just said.
Quoted 6 lines
drivers/scsi/elx/libefc_sli/sli4.c static struct sli4_asic_entry_t sli4_asic_table[] = { · line 152
Quoted 3 lines
drivers/scsi/elx/libefc_sli/sli4.c +3
-0+ cqv2->hdr.opcode =CMN_CREATE_CQ ; + cqv2->hdr.subsystem =SLI4_SUBSYSTEM_COMMON ; + cqv2->hdr.dw3_version =cpu_to_le32 (CMD_V2 );Is this now a the command version? Shouldn't it be V0 as the documentation writes?
nope comment was wrong. We'll remove the comment. We won't bother with routine names reflecting cmd version # unless the driver has to use more than 1 version.
Quoted 11 lines
drivers/scsi/elx/libefc_sli/sli4.c static struct sli4_asic_entry_t sli4_asic_table[] = { · line 223
Quoted 7 lines
drivers/scsi/elx/libefc_sli/sli4.c +7
-0+static int +sli_cmd_common_destroy_cq (struct sli4_s *sli4,void *buf, +size_t size,u16 cq_id) +{ +struct sli4_rqst_cmn_destroy_cq_s *cq =NULL ; + +/* Payload length must accommodate both request and response */ Is this common? Is this true for all commands? If so maybe have this kind of information at the beginning of the file explaining some of the inner workings of the code would certainly help.
For the SLI_CONFIG mailbox command, which is a wrapper that issues a bunch of other mailbox commands specified by subsystem and subsystem-specific opcode - yes, it's true.
We'll clean this up. Likely remove the indicated comment and say something up in sli_config_cmd_init().
Quoted 3 lines
sli_cmd_common_destroy_eq(),sli_cmd_common_destroy_cq()andsli_cmd_common_destroy_mq()look almost identically. Could those function be unified?
We'll look at better commonizing through small service routines and/or macros. We'll see if unification falls out.
Quoted 4 lines
So many function look almost identical. Is there no better way to create the commands? Or is something like a generic command creation function worse to maintain? There is so much copy paste... I stop now pointing out the same issues again.
Same as last comment. A few helper macros should distill it to the items that are specific to the individual commands.
PATCH 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 | 2102 ++++++++++++++++++++++++++++++++++++ drivers/scsi/elx/libefc_sli/sli4.h | 2 + 2 files changed, 2104 insertions(+)
drivers/scsi/elx/libefc_sli/sli4.c +2102 -0
@@ -2179,3 +2179,2105 @@ sli_cq_parse(struct sli4_s *sli4, struct sli4_queue_s *cq, u8 *cqe,return rc; } + +/** +* @ingroup sli_fc +* @brief Write an ABORT_WQE work queue entry. +* +* @param sli4 SLI context. +* @param buf Destination buffer for the WQE. +* @param size Buffer size, in bytes. +* @param type Abort type, such as XRI, abort tag, and request tag. +* @param send_abts Boolean to cause the hardware to automatically generate an +* ABTS. +* @param ids ID of IOs to abort. +* @param mask Mask applied to the ID values to abort. +* @param tag Tag value associated with this abort. +* @param cq_id The id of the completion queue where the WQE response is sent. +* @param dnrx When set to 1, this field indicates that the SLI Port must not +* return the associated XRI to the SLI +* Port's optimized write XRI pool. +* +* @return Returns 0 on success, or a non-zero value on failure. +*/ +int +sli_abort_wqe (struct sli4_s *sli4,void *buf,size_t size, +enum sli4_abort_type_e type,bool send_abts,u32 ids, +u32 mask,u16 tag,u16 cq_id) +{ +struct sli4_abort_wqe_s *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 ; +} + +/** +* @ingroup sli_fc +* @brief Write an ELS_REQUEST64_WQE work queue entry. +* +* @param sli4 SLI context. +* @param buf Destination buffer for the WQE. +* @param size Buffer size, in bytes. +* @param sgl DMA memory for the ELS request. +* @param req_type ELS request type. +* @param req_len Length of ELS request in bytes. +* @param max_rsp_len Max length of ELS response in bytes. +* @param timeout Time, in seconds, before an IO times out. Zero means 2 * +* R_A_TOV. +* @param xri XRI for this exchange. +* @param tag IO tag value. +* @param cq_id The id of the completion queue where the WQE response is sent. +* @param rnode Destination of ELS request (that is, the remote node). +* +* @return Returns 0 on success, or a non-zero value on failure. +*/ +int +sli_els_request64_wqe (struct sli4_s *sli4,void *buf,size_t size, +struct efc_dma_s *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_s *els = buf; +struct sli4_sge_s *sge = sgl->virt; +bool is_fabric = false; +struct sli4_bde_s *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_s )) & +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 ; +} + +/** +* @ingroup sli_fc +* @brief Write an FCP_ICMND64_WQE work queue entry. +* +* @param sli4 SLI context. +* @param buf Destination buffer for the WQE. +* @param size Buffer size, in bytes. +* @param sgl DMA memory for the scatter gather list. +* @param xri XRI for this exchange. +* @param tag IO tag value. +* @param cq_id The id of the completion queue where the WQE response is sent. +* @param rpi remote node indicator (RPI) +* @param rnode Destination request (that is, the remote node). +* @param timeout Time, in seconds, before an IO times out. Zero means no +* timeout. +* +* @return Returns 0 on success, or a non-zero value on failure. +*/ +int +sli_fcp_icmnd64_wqe (struct sli4_s *sli4,void *buf,size_t size, +struct efc_dma_s *sgl,u16 xri,u16 tag, +u16 cq_id,u32 rpi,bool hlm, +u32 rnode_fcid,u8 timeout) +{ +struct sli4_fcp_icmnd64_wqe_s *icmnd = buf; +struct sli4_sge_s *sge =NULL ; +struct sli4_bde_s *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 = &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)); + } + + icmnd->payload_offset_length = (sge[0 ].buffer_length + + sge[1 ].buffer_length); + 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 ; +} + +/** +* @ingroup sli_fc +* @brief Write an FCP_IREAD64_WQE work queue entry. +* +* @param sli4 SLI context. +* @param buf Destination buffer for the WQE. +* @param size Buffer size, in bytes. +* @param sgl DMA memory for the scatter gather list. +* @param first_data_sge Index of first data sge (used if perf hints are +* enabled) +* @param xfer_len Data transfer length. +* @param xri XRI for this exchange. +* @param tag IO tag value. +* @param cq_id The id of the completion queue where the WQE response is sent. +* @param rpi remote node indicator (RPI) +* @param rnode Destination request (i.e. remote node). +* @param dif T10 DIF operation, or 0 to disable. +* @param bs T10 DIF block size, or 0 if DIF is disabled. +* @param timeout Time, in seconds, before an IO times out. Zero means no +* timeout. +* +* @return Returns 0 on success, or a non-zero value on failure. +*/ +int +sli_fcp_iread64_wqe (struct sli4_s *sli4,void *buf,size_t size, +struct efc_dma_s *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_s *iread = buf; +struct sli4_sge_s *sge =NULL ; +struct sli4_bde_s *bptr; +u32 sge_flags =0 ; + +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) +*/ + iread->fcp_cmd_buffer_length = +cpu_to_le16 (sge[0 ].buffer_length); + + sge_flags = sge[1 ].dw2_flags; + sge_flags &= (~SLI4_SGE_TYPE_MASK ); + sge_flags |= (SLI4_SGE_TYPE_SKIP <<SLI4_SGE_TYPE_SHIFT ); + sge[1 ].dw2_flags = sge_flags; + } + + iread->payload_offset_length = (sge[0 ].buffer_length + + sge[1 ].buffer_length); + 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 ; +} + +/** +* @ingroup sli_fc +* @brief Write an FCP_IWRITE64_WQE work queue entry. +* +* @param sli4 SLI context. +* @param buf Destination buffer for the WQE. +* @param size Buffer size, in bytes. +* @param sgl DMA memory for the scatter gather list. +* @param first_data_sge Index of first data sge (used if perf hints are +* enabled) +* @param xfer_len Data transfer length. +* @param first_burst The number of first burst bytes +* @param xri XRI for this exchange. +* @param tag IO tag value. +* @param cq_id The id of the completion queue where the WQE response is sent. +* @param rpi remote node indicator (RPI) +* @param rnode Destination request (i.e. remote node) +* @param dif T10 DIF operation, or 0 to disable +* @param bs T10 DIF block size, or 0 if DIF is disabled +* @param timeout Time, in seconds, before an IO times out. Zero means no +* timeout. +* +* @return Returns 0 on success, or a non-zero value on failure. +*/ +int +sli_fcp_iwrite64_wqe (struct sli4_s *sli4,void *buf,size_t size, +struct efc_dma_s *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_s *iwrite = buf; +struct sli4_sge_s *sge =NULL ; +struct sli4_bde_s *bptr; +u32 sge_flags =0 , min =0 ; + +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) +*/ + iwrite->fcp_cmd_buffer_length = +cpu_to_le16 (sge[0 ].buffer_length); + sge_flags = sge[1 ].dw2_flags; + sge_flags &= ~SLI4_SGE_TYPE_MASK ; + sge_flags |= (SLI4_SGE_TYPE_SKIP <<SLI4_SGE_TYPE_SHIFT ); + sge[1 ].dw2_flags = sge_flags; + } + + iwrite->payload_offset_length = (sge[0 ].buffer_length + + sge[1 ].buffer_length); + 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 ; +} + +/** +* @ingroup sli_fc +* @brief Write an FCP_TRECEIVE64_WQE work queue entry. +* +* @param sli4 SLI context. +* @param buf Destination buffer for the WQE. +* @param size Buffer size, in bytes. +* @param sgl DMA memory for the Scatter-Gather List. +* @param first_data_sge Index of first data sge (used if perf hints are +* enabled) +* @param relative_off Relative offset of the IO (if any). +* @param xfer_len Data transfer length. +* @param xri XRI for this exchange. +* @param tag IO tag value. +* @param xid OX_ID for the exchange. +* @param cq_id The id of the completion queue where the WQE response is sent. +* @param rpi remote node indicator (RPI) +* @param rnode Destination request (i.e. remote node). +* @param flags Optional attributes, including: +* - ACTIVE - IO is already active. +* - AUTO RSP - Automatically generate a good FCP_RSP. +* @param dif T10 DIF operation, or 0 to disable. +* @param bs T10 DIF block size, or 0 if DIF is disabled. +* @param csctl value of csctl field. +* @param app_id value for VM application header. +* +* @return Returns 0 on success, or a non-zero value on failure. +*/ +int +sli_fcp_treceive64_wqe (struct sli4_s *sli4,void *buf,size_t size, +struct efc_dma_s *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_s *trecv = buf; +struct sli4_fcp_128byte_wqe_s *trecv_128 = buf; +struct sli4_sge_s *sge =NULL ; +struct sli4_bde_s *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 ] =cpu_to_le32 (app_id); + } +return 0 ; +} + +/** +* @ingroup sli_fc +* @brief Write an FCP_CONT_TRECEIVE64_WQE work queue entry. +* +* @param sli4 SLI context. +* @param buf Destination buffer for the WQE. +* @param size Buffer size, in bytes. +* @param sgl DMA memory for the Scatter-Gather List. +* @param first_data_sge Index of first data sge (used if perf hints are +* enabled) +* @param relative_off Relative offset of the IO (if any). +* @param xfer_len Data transfer length. +* @param xri XRI for this exchange. +* @param tag IO tag value. +* @param xid OX_ID for the exchange. +* @param cq_id The id of the completion queue where the WQE response is sent. +* @param rpi remote node indicator (RPI) +* @param rnode Destination request (i.e. remote node). +* @param flags Optional attributes, including: +* - ACTIVE - IO is already active. +* - AUTO RSP - Automatically generate a good FCP_RSP. +* @param dif T10 DIF operation, or 0 to disable. +* @param bs T10 DIF block size, or 0 if DIF is disabled. +* @param csctl value of csctl field. +* @param app_id value for VM application header. +* +* @return Returns 0 on success, or a non-zero value on failure. +*/ +int +sli_fcp_cont_treceive64_wqe (struct sli4_s *sli4,void *buf,size_t size, +struct efc_dma_s *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_s *trecv = buf; + + trecv->command =SLI4_WQE_FCP_CONT_TRECEIVE64 ; + trecv->dword5.sec_xri_tag =cpu_to_le16 (sec_xri); + } +return rc; +} + +/** +* @ingroup sli_fc +* @brief Write an FCP_TRSP64_WQE work queue entry. +* +* @param sli4 SLI context. +* @param buf Destination buffer for the WQE. +* @param size Buffer size, in bytes. +* @param sgl DMA memory for the Scatter-Gather List. +* @param rsp_len Response data length. +* @param xri XRI for this exchange. +* @param tag IO tag value. +* @param cq_id The id of the completion queue where the WQE response is sent. +* @param xid OX_ID for the exchange. +* @param rpi remote node indicator (RPI) +* @param rnode Destination request (i.e. remote node). +* @param flags Optional attributes, including: +* - ACTIVE - IO is already active +* - AUTO RSP - Automatically generate a good FCP_RSP. +* @param csctl value of csctl field. +* @param port_owned 0/1 to indicate if the XRI is port owned (used to seti +* XBL=0) +* @param app_id value for VM application header. +* +* @return Returns 0 on success, or a non-zero value on failure. +*/ +int +sli_fcp_trsp64_wqe (struct sli4_s *sli4,void *buf,size_t size, +struct efc_dma_s *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_s *trsp = buf; +struct sli4_fcp_128byte_wqe_s *trsp_128 = buf; +struct sli4_bde_s *bptr; + +memset (buf,0 , size); + +if (flags &SLI4_IO_AUTO_GOOD_RESPONSE ) { + trsp->class_ag_byte |=SLI4_TRSP_WQE_AG ; + }else { +struct sli4_sge_s *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 ] =cpu_to_le32 (app_id); + } +return 0 ; +} + +/** +* @ingroup sli_fc +* @brief Write an FCP_TSEND64_WQE work queue entry. +* +* @param sli4 SLI context. +* @param buf Destination buffer for the WQE. +* @param size Buffer size, in bytes. +* @param sgl DMA memory for the scatter gather list. +* @param first_data_sge Index of first data sge (used if perf hints are +* enabled) +* @param relative_off Relative offset of the IO (if any). +* @param xfer_len Data transfer length. +* @param xri XRI for this exchange. +* @param tag IO tag value. +* @param cq_id The id of the completion queue where the WQE response is sent. +* @param xid OX_ID for the exchange. +* @param rpi remote node indicator (RPI) +* @param rnode Destination request (i.e. remote node). +* @param flags Optional attributes, including: +* - ACTIVE - IO is already active. +* - AUTO RSP - Automatically generate a good FCP_RSP. +* @param dif T10 DIF operation, or 0 to disable. +* @param bs T10 DIF block size, or 0 if DIF is disabled. +* @param csctl value of csctl field. +* @param app_id value for VM application header. +* +* @return Returns 0 on success, or a non-zero value on failure. +*/ +int +sli_fcp_tsend64_wqe (struct sli4_s *sli4,void *buf,size_t size, +struct efc_dma_s *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_s *tsend = buf; +struct sli4_fcp_128byte_wqe_s *tsend_128 = buf; +struct sli4_sge_s *sge =NULL ; +struct sli4_bde_s *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 <= 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 ] =cpu_to_le32 (app_id); + } +return 0 ; +} + +/** +* @ingroup sli_fc +* @brief Write a GEN_REQUEST64 work queue entry. +* +* @note This WQE is only used to send FC-CT commands. +* +* @param sli4 SLI context. +* @param buf Destination buffer for the WQE. +* @param size Buffer size, in bytes. +* @param sgl DMA memory for the request. +* @param req_len Length of request. +* @param max_rsp_len Max length of response. +* @param timeout Time, in seconds, before an IO times out. +* Zero means infinite. +* @param xri XRI for this exchange. +* @param tag IO tag value. +* @param cq_id The id of the completion queue where the WQE response is sent. +* @param rnode Destination of request (that is, the remote node). +* @param r_ctl R_CTL value for sequence. +* @param type TYPE value for sequence. +* @param df_ctl DF_CTL value for sequence. +* +* @return Returns 0 on success, or a non-zero value on failure. +*/ +int +sli_gen_request64_wqe (struct sli4_s *sli4,void *buf,size_t size, +struct efc_dma_s *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_s *gen = buf; +struct sli4_sge_s *sge =NULL ; +struct sli4_bde_s *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_s )) & +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 ; +} + +/** +* @ingroup sli_fc +* @brief Write a SEND_FRAME work queue entry +* +* @param sli4 SLI context. +* @param buf Destination buffer for the WQE. +* @param size Buffer size, in bytes. +* @param sof Start of frame value +* @param eof End of frame value +* @param hdr Pointer to FC header data +* @param payload DMA memory for the payload. +* @param req_len Length of payload. +* @param timeout Time, in seconds, before an IO times out. Zero means infinite. +* @param xri XRI for this exchange. +* @param req_tag IO tag value. +* +* @return Returns 0 on success, or a non-zero value on failure. +*/ +int +sli_send_frame_wqe (struct sli4_s *sli4,void *buf,size_t size, +u8 sof,u8 eof,u32 *hdr, +struct efc_dma_s *payload,u32 req_len, +u8 timeout,u16 xri,u16 req_tag) +{ +struct sli4_send_frame_wqe_s *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 =0xffff ; + +return 0 ; +} + +/** +* @ingroup sli_fc +* @brief Write an XMIT_BLS_RSP64_WQE work queue entry. +* +* @param sli4 SLI context. +* @param buf Destination buffer for the WQE. +* @param size Buffer size, in bytes. +* @param payload Contents of the BLS payload to be sent. +* @param xri XRI for this exchange. +* @param tag IO tag value. +* @param cq_id The id of the completion queue where the WQE response is sent. +* @param rnode Destination of request (that is, the remote node). +* @param s_id Source ID to use in the response. If U32_MAX, use SLI Port's +* ID. +* +* @return Returns 0 on success, or a non-zero value on failure. +*/ +int +sli_xmit_bls_rsp64_wqe (struct sli4_s *sli4,void *buf,size_t size, +struct sli_bls_payload_s *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_s *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 =cpu_to_le16 (payload->u.acc.high_seq_cnt); + bls->low_seq_cnt =cpu_to_le16 (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 =cpu_to_le16 (payload->ox_id); + bls->rx_id =cpu_to_le16 (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 ; +} + +/** +* @ingroup sli_fc +* @brief Write a XMIT_ELS_RSP64_WQE work queue entry. +* +* @param sli4 SLI context. +* @param buf Destination buffer for the WQE. +* @param size Buffer size, in bytes. +* @param rsp DMA memory for the ELS response. +* @param rsp_len Length of ELS response, in bytes. +* @param xri XRI for this exchange. +* @param tag IO tag value. +* @param cq_id The id of the completion queue where the WQE response is sent. +* @param ox_id OX_ID of the exchange containing the request. +* @param rnode Destination of the ELS response (that is, the remote node). +* @param flags Optional attributes, including: +* - SLI4_IO_CONTINUATION - IO is already active. +* @param s_id S_ID used for special responses. +* +* @return Returns 0 on success, or a non-zero value on failure. +*/ +int +sli_xmit_els_rsp64_wqe (struct sli4_s *sli4,void *buf,size_t size, +struct efc_dma_s *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_s *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 = 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 ; +} + +/** +* @ingroup sli_fc +* @brief Write a XMIT_SEQUENCE64 work queue entry. +* +* This WQE is used to send FC-CT response frames. +* +* @note This API implements a restricted use for this WQE, +* +* @param sli4 SLI context. +* @param buf Destination buffer for the WQE. +* @param size Buffer size, in bytes. +* @param payload DMA memory for the request. +* @param payload_len Length of request. +* @param timeout Time, in seconds, before an IO times out. +* Zero means infinite. +* @param ox_id originator exchange ID +* @param xri XRI for this exchange. +* @param tag IO tag value. +* @param rnode Destination of request (that is, the remote node). +* @param r_ctl R_CTL value for sequence. +* @param type TYPE value for sequence. +* @param df_ctl DF_CTL value for sequence. +* +* @return Returns 0 on success, or a non-zero value on failure. +*/ +int +sli_xmit_sequence64_wqe (struct sli4_s *sli4,void *buf,size_t size, +struct efc_dma_s *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_s *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 |= 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 |= 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 ; +} + +/** +* @ingroup sli_fc +* @brief Write a REQUEUE_XRI_WQE work queue entry. +* +* @param sli4 SLI context. +* @param buf Destination buffer for the WQE. +* @param size Buffer size, in bytes. +* @param xri XRI for this exchange. +* @param tag IO tag value. +* @param cq_id The id of the completion queue where the WQE response is sent. +* +* @return Returns 0 on success, or a non-zero value on failure. +*/ +int +sli_requeue_xri_wqe (struct sli4_s *sli4,void *buf,size_t size, +u16 xri,u16 tag,u16 cq_id) +{ +struct sli4_requeue_xri_wqe_s *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 |=SLI4_REQU_XRI_WQE_XC ; + requeue->flags1 |=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 ; +} + +/** +* @ingroup sli_fc +* @brief Process an asynchronous Link State event entry. +* +* @par Description +* Parses Asynchronous Completion Queue Entry (ACQE), +* creates an abstracted event, and calls registered callback functions. +* +* @param sli4 SLI context. +* @param acqe Pointer to the ACQE. +* +* @return Returns 0 on success, or a non-zero value on failure. +*/ +int +sli_fc_process_link_state (struct sli4_s *sli4,void *acqe) +{ +struct sli4_link_state_s *link_state = acqe; +struct sli4_link_event_s 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; +} + +/** +* @ingroup sli_fc +* @brief Process an asynchronous Link Attention event entry. +* +* @par Description +* Parses Asynchronous Completion Queue Entry (ACQE), +* creates an abstracted event, and calls the registered callback functions. +* +* @param sli4 SLI context. +* @param acqe Pointer to the ACQE. +* +* @return Returns 0 on success, or a non-zero value on failure. +*/ +int +sli_fc_process_link_attention (struct sli4_s *sli4,void *acqe) +{ +struct sli4_link_attention_s *link_attn = acqe; +struct sli4_link_event_s 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 ; +} + +/** +* @ingroup sli_fc +* @brief Parse an FC/FCoE work queue CQ entry. +* +* @param sli4 SLI context. +* @param cq CQ to process. +* @param cqe Pointer to the CQ entry. +* @param etype CQ event type. +* @param r_id Resource ID associated with this completion message (such as the +* IO tag). +* +* @return Returns 0 on success, or a non-zero value on failure. +*/ +int +sli_fc_cqe_parse (struct sli4_s *sli4,struct sli4_queue_s *cq, +u8 *cqe,enum sli4_qentry_e *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_s *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_s *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_s *rcqe = (void *)cqe; + + *etype =SLI_QENTRY_RQ ; + *r_id = rcqe->rq_id; + rc = rcqe->status; +break ; + } +case SLI4_CQE_CODE_OPTIMIZED_WRITE_CMD : + { +struct sli4_fc_optimized_write_cmd_cqe_s *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_s *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_s *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_s *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_s *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; +} + +/** +* @ingroup sli_fc +* @brief Return the ELS/CT response length. +* +* @param sli4 SLI context. +* @param cqe Pointer to the CQ entry. +* +* @return Returns the length, in bytes. +*/ +u32 +sli_fc_response_length (struct sli4_s *sli4,u8 *cqe) +{ +struct sli4_fc_wcqe_s *wcqe = (void *)cqe; + +return le32_to_cpu (wcqe->wqe_specific_1); +} + +/** +* @ingroup sli_fc +* @brief Return the FCP IO length. +* +* @param sli4 SLI context. +* @param cqe Pointer to the CQ entry. +* +* @return Returns the length, in bytes. +*/ +u32 +sli_fc_io_length (struct sli4_s *sli4,u8 *cqe) +{ +struct sli4_fc_wcqe_s *wcqe = (void *)cqe; + +return le32_to_cpu (wcqe->wqe_specific_1); +} + +/** +* @ingroup sli_fc +* @brief Retrieve the D_ID from the completion. +* +* @param sli4 SLI context. +* @param cqe Pointer to the CQ entry. +* @param d_id Pointer where the D_ID is written. +* +* @return Returns 0 on success, or a non-zero value on failure. +*/ +int +sli_fc_els_did (struct sli4_s *sli4,u8 *cqe,u32 *d_id) +{ +struct sli4_fc_wcqe_s *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_s *sli4,u8 *cqe) +{ +struct sli4_fc_wcqe_s *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; +} + +/** +* @ingroup sli_fc +* @brief Retrieve the RQ index from the completion. +* +* @param sli4 SLI context. +* @param cqe Pointer to the CQ entry. +* @param rq_id Pointer where the rq_id is written. +* @param index Pointer where the index is written. +* +* @return Returns 0 on success, or a non-zero value on failure. +*/ +int +sli_fc_rqe_rqid_and_index (struct sli4_s *sli4,u8 *cqe, +u16 *rq_id,u32 *index) +{ +struct sli4_fc_async_rcqe_s *rcqe = (void *)cqe; +struct sli4_fc_async_rcqe_v1_s *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_s *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_s *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
PATCH 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 | 1767 ++++++++++++++++++++++++++++++++++++ drivers/scsi/elx/libefc_sli/sli4.h | 2 + 2 files changed, 1769 insertions(+)
drivers/scsi/elx/libefc_sli/sli4.c +1767 -0
@@ -4281,3 +4281,1770 @@ sli_fc_rqe_rqid_and_index(struct sli4_s *sli4, u8 *cqe,return rc; } + +/* +* @brief Wait for the bootstrap mailbox to report "ready". +* +* @param sli4 SLI context pointer. +* @param msec Number of milliseconds to wait. +* +* @return Returns 0 if BMBX is ready, or non-zero otherwise +* (i.e. time out occurred). +*/ +static int +sli_bmbx_wait (struct sli4_s *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; +} + +/** +* @brief Write bootstrap mailbox. +* +* @param sli4 SLI context pointer. +* +* @return Returns 0 if command succeeded, or non-zero otherwise. +*/ +static int +sli_bmbx_write (struct sli4_s *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 ); +} + +/** +* @ingroup sli +* @brief Submit a command to the bootstrap mailbox and check the status. +* +* @param sli4 SLI context pointer. +* +* @return Returns 0 on success, or a non-zero value on failure. +*/ +int +sli_bmbx_command (struct sli4_s *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_s *)cqe)->dw3_flags) & +SLI4_MCQE_VALID ) { +return sli_cqe_mq (sli4, cqe); + } +efc_log_crit (sli4,"invalid or wrong type\n" ); +return -1 ; +} + +/** +* @ingroup sli +* @brief Write a CONFIG_LINK command to the provided buffer. +* +* @param sli4 SLI context pointer. +* @param buf Virtual pointer to the destination buffer. +* @param size Buffer size, in bytes. +* +* @return Returns the number of bytes written. +*/ +int +sli_cmd_config_link (struct sli4_s *sli4,void *buf,size_t size) +{ +struct sli4_cmd_config_link_s *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 ; +} + +/** +* @ingroup sli +* @brief Write a DOWN_LINK command to the provided buffer. +* +* @param sli4 SLI context pointer. +* @param buf Virtual pointer to the destination buffer. +* @param size Buffer size, in bytes. +* +* @return Returns the number of bytes written. +*/ +int +sli_cmd_down_link (struct sli4_s *sli4,void *buf,size_t size) +{ +struct sli4_mbox_command_header_s *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 ; +} + +/** +* @ingroup sli +* @brief Write a DUMP Type 4 command to the provided buffer. +* +* @param sli4 SLI context pointer. +* @param buf Virtual pointer to the destination buffer. +* @param size Buffer size, in bytes. +* @param wki The well known item ID. +* +* @return Returns the number of bytes written. +*/ +int +sli_cmd_dump_type4 (struct sli4_s *sli4,void *buf, +size_t size,u16 wki) +{ +struct sli4_cmd_dump4_s *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 ; +} + +/** +* @ingroup sli +* @brief Write a COMMON_READ_TRANSCEIVER_DATA command. +* +* @param sli4 SLI context. +* @param buf Destination buffer for the command. +* @param size Buffer size, in bytes. +* @param page_num The page of SFP data to retrieve (0xa0 or 0xa2). +* @param dma DMA structure from which the data will be copied. +* +* @note This creates a Version 0 message. +* +* @return Returns the number of bytes written. +*/ +int +sli_cmd_common_read_transceiver_data (struct sli4_s *sli4,void *buf, +size_t size,u32 page_num, +struct efc_dma_s *dma) +{ +struct sli4_rqst_cmn_read_transceiver_data_s *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 ; + + req->hdr.opcode =CMN_READ_TRANS_DATA ; + req->hdr.subsystem =SLI4_SUBSYSTEM_COMMON ; + req->hdr.request_length =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 ; +} + +/** +* @ingroup sli +* @brief Write a READ_LINK_STAT command to the provided buffer. +* +* @param sli4 SLI context pointer. +* @param buf Virtual pointer to the destination buffer. +* @param size Buffer size, in bytes. +* @param req_ext_counters If TRUE, +* then the extended counters will be requested. +* @param clear_overflow_flags If TRUE, then overflow flags will be cleared. +* @param clear_all_counters If TRUE, the counters will be cleared. +* +* @return Returns the number of bytes written. +*/ +int +sli_cmd_read_link_stats (struct sli4_s *sli4,void *buf,size_t size, +u8 req_ext_counters, +u8 clear_overflow_flags, +u8 clear_all_counters) +{ +struct sli4_cmd_read_link_stats_s *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 ; +} + +/** +* @ingroup sli +* @brief Write a READ_STATUS command to the provided buffer. +* +* @param sli4 SLI context pointer. +* @param buf Virtual pointer to the destination buffer. +* @param size Buffer size, in bytes. +* @param clear_counters If TRUE, the counters will be cleared. +* +* @return Returns the number of bytes written. +*/ +int +sli_cmd_read_status (struct sli4_s *sli4,void *buf,size_t size, +u8 clear_counters) +{ +struct sli4_cmd_read_status_s *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 ; +} + +/** +* @ingroup sli +* @brief Write an INIT_LINK command to the provided buffer. +* +* @param sli4 SLI context pointer. +* @param buf Virtual pointer to the destination buffer. +* @param size Buffer size, in bytes. +* @param speed Link speed. +* @param reset_alpa For native FC, this is the selective reset AL_PA +* +* @return Returns the number of bytes written. +*/ +int +sli_cmd_init_link (struct sli4_s *sli4,void *buf,size_t size, +u32 speed,u8 reset_alpa) +{ +struct sli4_cmd_init_link_s *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 ; +} + +/** +* @ingroup sli +* @brief Write an INIT_VFI command to the provided buffer. +* +* @param sli4 SLI context pointer. +* @param buf Virtual pointer to the destination buffer. +* @param size Buffer size, in bytes. +* @param vfi VFI +* @param fcfi FCFI +* @param vpi VPI (Set to -1 if unused.) +* +* @return Returns the number of bytes written. +*/ +int +sli_cmd_init_vfi (struct sli4_s *sli4,void *buf,size_t size, +u16 vfi,u16 fcfi,u16 vpi) +{ +struct sli4_cmd_init_vfi_s *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 ; +} + +/** +* @ingroup sli +* @brief Write an INIT_VPI command to the provided buffer. +* +* @param sli4 SLI context pointer. +* @param buf Virtual pointer to the destination buffer. +* @param size Buffer size, in bytes. +* @param vpi VPI allocated. +* @param vfi VFI associated with this VPI. +* +* @return Returns the number of bytes written. +*/ +int +sli_cmd_init_vpi (struct sli4_s *sli4,void *buf,size_t size, +u16 vpi,u16 vfi) +{ +struct sli4_cmd_init_vpi_s *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 ; +} + +/** +* @ingroup sli +* @brief Write a POST_XRI command to the provided buffer. +* +* @param sli4 SLI context pointer. +* @param buf Virtual pointer to the destination buffer. +* @param size Buffer size, in bytes. +* @param xri_base Starting XRI value for range of XRI given to SLI Port. +* @param xri_count Number of XRIs provided to the SLI Port. +* +* @return Returns the number of bytes written. +*/ +int +sli_cmd_post_xri (struct sli4_s *sli4,void *buf,size_t size, +u16 xri_base,u16 xri_count) +{ +struct sli4_cmd_post_xri_s *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 ; +} + +/** +* @ingroup sli +* @brief Write a RELEASE_XRI command to the provided buffer. +* +* @param sli4 SLI context pointer. +* @param buf Virtual pointer to the destination buffer. +* @param size Buffer size, in bytes. +* @param num_xri The number of XRIs to be released. +* +* @return Returns the number of bytes written. +*/ +int +sli_cmd_release_xri (struct sli4_s *sli4,void *buf,size_t size, +u8 num_xri) +{ +struct sli4_cmd_release_xri_s *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 ; +} + +/** +* @brief Write a READ_CONFIG command to the provided buffer. +* +* @param sli4 SLI context pointer. +* @param buf Virtual pointer to the destination buffer. +* @param size Buffer size, in bytes +* +* @return Returns the number of bytes written. +*/ +static int +sli_cmd_read_config (struct sli4_s *sli4,void *buf,size_t size) +{ +struct sli4_cmd_read_config_s *read_config = buf; + +memset (buf,0 , size); + + read_config->hdr.command =MBX_CMD_READ_CONFIG ; + +return EFC_SUCCESS ; +} + +/** +* @brief Write a READ_NVPARMS command to the provided buffer. +* +* @param sli4 SLI context pointer. +* @param buf Virtual pointer to the destination buffer. +* @param size Buffer size, in bytes. +* +* @return Returns the number of bytes written. +*/ +int +sli_cmd_read_nvparms (struct sli4_s *sli4,void *buf,size_t size) +{ +struct sli4_cmd_read_nvparms_s *read_nvparms = buf; + +memset (buf,0 , size); + + read_nvparms->hdr.command =MBX_CMD_READ_NVPARMS ; + +return EFC_SUCCESS ; +} + +/** +* @brief Write a WRITE_NVPARMS command to the provided buffer. +* +* @param sli4 SLI context pointer. +* @param buf Virtual pointer to the destination buffer. +* @param size Buffer size, in bytes. +* @param wwpn WWPN to write - pointer to array of 8 u8. +* @param wwnn WWNN to write - pointer to array of 8 u8. +* @param hard_alpa Hard ALPA to write. +* @param preferred_d_id Preferred D_ID to write. +* +* @return Returns the number of bytes written. +*/ +int +sli_cmd_write_nvparms (struct sli4_s *sli4,void *buf,size_t size, +u8 *wwpn,u8 *wwnn,u8 hard_alpa, +u32 preferred_d_id) +{ +struct sli4_cmd_write_nvparms_s *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 ; +} + +/** +* @brief Write a READ_REV command to the provided buffer. +* +* @param sli4 SLI context pointer. +* @param buf Virtual pointer to the destination buffer. +* @param size Buffer size, in bytes. +* @param vpd Pointer to the buffer. +* +* @return Returns the number of bytes written. +*/ +static int +sli_cmd_read_rev (struct sli4_s *sli4,void *buf,size_t size, +struct efc_dma_s *vpd) +{ +struct sli4_cmd_read_rev_s *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_le16 (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 ; +} + +/** +* @ingroup sli +* @brief Write a READ_SPARM64 command to the provided buffer. +* +* @param sli4 SLI context pointer. +* @param buf Virtual pointer to the destination buffer. +* @param size Buffer size, in bytes. +* @param dma DMA buffer for the service parameters. +* @param vpi VPI used to determine the WWN. +* +* @return Returns the number of bytes written. +*/ +int +sli_cmd_read_sparm64 (struct sli4_s *sli4,void *buf,size_t size, +struct efc_dma_s *dma, +u16 vpi) +{ +struct sli4_cmd_read_sparm64_s *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 ; +} + +/** +* @ingroup sli +* @brief Write a READ_TOPOLOGY command to the provided buffer. +* +* @param sli4 SLI context pointer. +* @param buf Virtual pointer to the destination buffer. +* @param size Buffer size, in bytes. +* @param dma DMA buffer for loop map (optional). +* +* @return Returns the number of bytes written. +*/ +int +sli_cmd_read_topology (struct sli4_s *sli4,void *buf,size_t size, +struct efc_dma_s *dma) +{ +struct sli4_cmd_read_topology_s *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 ; +} + +/** +* @ingroup sli +* @brief Write a REG_FCFI command to the provided buffer. +* +* @param sli4 SLI context pointer. +* @param buf Virtual pointer to the destination buffer. +* @param size Buffer size, in bytes. +* @param index FCF index returned by READ_FCF_TABLE. +* @param rq_cfg RQ_ID/R_CTL/TYPE routing information +* +* @return Returns the number of bytes written. +*/ +int +sli_cmd_reg_fcfi (struct sli4_s *sli4,void *buf,size_t size, +u16 index, +struct sli4_cmd_rq_cfg_s rq_cfg[SLI4_CMD_REG_FCFI_NUM_RQ_CFG ]) +{ +struct sli4_cmd_reg_fcfi_s *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 =cpu_to_le16 (rq_cfg[0 ].rq_id); +break ; +case 1 : + reg_fcfi->rqid1 =cpu_to_le16 (rq_cfg[1 ].rq_id); +break ; +case 2 : + reg_fcfi->rqid2 =cpu_to_le16 (rq_cfg[2 ].rq_id); +break ; +case 3 : + reg_fcfi->rqid3 =cpu_to_le16 (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 ; +} + +/** +* @brief Write REG_FCFI_MRQ to provided command buffer +* +* @param sli4 SLI context pointer. +* @param buf Virtual pointer to the destination buffer. +* @param size Buffer size, in bytes. +* @param fcf_index FCF index returned by READ_FCF_TABLE. +* @param rr_quant Round robin quanta if RQ selection policy is 2 +* @param rq_selection_policy RQ selection policy +* @param num_rqs Array of count of RQs per filter +* @param rq_ids Array of RQ ids per filter +* @param rq_cfg RQ_ID/R_CTL/TYPE routing information +* +* @return returns 0 for success, a negative error code value for failure. +*/ +int +sli_cmd_reg_fcfi_mrq (struct sli4_s *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_s rq_cfg[SLI4_CMD_REG_FCFI_NUM_RQ_CFG ]) +{ +struct sli4_cmd_reg_fcfi_mrq_s *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 =cpu_to_le16 (rq_cfg[i].rq_id); +break ; +case 2 : + reg_fcfi_mrq->rqid2 =cpu_to_le16 (rq_cfg[i].rq_id); +break ; +case 1 : + reg_fcfi_mrq->rqid1 =cpu_to_le16 (rq_cfg[i].rq_id); +break ; +case 0 : + reg_fcfi_mrq->rqid0 =cpu_to_le16 (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 ; +} + +/** +* @ingroup sli +* @brief Write a REG_RPI command to the provided buffer. +* +* @param sli4 SLI context pointer. +* @param buf Virtual pointer to the destination buffer. +* @param size Buffer size, in bytes. +* @param nport_id Remote F/N_Port_ID. +* @param rpi Previously-allocated Remote Port Indicator. +* @param vpi Previously-allocated Virtual Port Indicator. +* @param dma DMA buffer that contains the remote port's service parameters. +* @param update Boolean indicating an update to an existing RPI (TRUE) +* or a new registration (FALSE). +* +* @return Returns the number of bytes written. +*/ +int +sli_cmd_reg_rpi (struct sli4_s *sli4,void *buf,size_t size, +u32 nport_id,u16 rpi,u16 vpi, +struct efc_dma_s *dma,u8 update, +u8 enable_t10_pi) +{ +struct sli4_cmd_reg_rpi_s *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 ; +} + +/** +* @ingroup sli +* @brief Write a REG_VFI command to the provided buffer. +* +* @param sli4 SLI context pointer. +* @param buf Virtual pointer to the destination buffer. +* @param size Buffer size, in bytes. +* @param domain Pointer to the domain object. +* +* @return Returns the number of bytes written. +*/ +int +sli_cmd_reg_vfi (struct sli4_s *sli4,void *buf,size_t size, +u16 vfi,u16 fcfi,struct efc_dma_s dma, +u16 vpi,__be64 sli_wwpn,u32 fc_id) +{ +struct sli4_cmd_reg_vfi_s *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 |=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 ; +} + +/** +* @ingroup sli +* @brief Write a REG_VPI command to the provided buffer. +* +* @param sli4 SLI context pointer. +* @param buf Virtual pointer to the destination buffer. +* @param size Buffer size, in bytes. +* @param sport Point to SLI Port object. +* @param update Boolean indicating whether to update the existing VPI (true) +* or create a new VPI (false). +* +* @return Returns the number of bytes written. +*/ +int +sli_cmd_reg_vpi (struct sli4_s *sli4,void *buf,size_t size, +u32 fc_id,__be64 sli_wwpn,u16 vpi,u16 vfi, +bool update) +{ +struct sli4_cmd_reg_vpi_s *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 ; +} + +/** +* @brief Write a REQUEST_FEATURES command to the provided buffer. +* +* @param sli4 SLI context pointer. +* @param buf Virtual pointer to the destination buffer. +* @param size Buffer size, in bytes. +* @param mask Features to request. +* @param query Use feature query mode (does not change FW). +* +* @return Returns the number of bytes written. +*/ +static int +sli_cmd_request_features (struct sli4_s *sli4,void *buf,size_t size, +u32 features_mask,bool query) +{ +struct sli4_cmd_request_features_s *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 ; +} + +/** +* @ingroup sli +* @brief Write a UNREG_FCFI command to the provided buffer. +* +* @param sli4 SLI context pointer. +* @param buf Virtual pointer to the destination buffer. +* @param size Buffer size, in bytes. +* @param indicator Indicator value. +* +* @return Returns the number of bytes written. +*/ +int +sli_cmd_unreg_fcfi (struct sli4_s *sli4,void *buf,size_t size, +u16 indicator) +{ +struct sli4_cmd_unreg_fcfi_s *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 ; +} + +/** +* @ingroup sli +* @brief Write an UNREG_RPI command to the provided buffer. +* +* @param sli4 SLI context pointer. +* @param buf Virtual pointer to the destination buffer. +* @param size Buffer size, in bytes. +* @param indicator Indicator value. +* @param which Type of unregister, such as node, port, domain, or FCF. +* @param fc_id FC address. +* +* @return Returns the number of bytes written. +*/ +int +sli_cmd_unreg_rpi (struct sli4_s *sli4,void *buf,size_t size, +u16 indicator, +enum sli4_resource_e which,u32 fc_id) +{ +struct sli4_cmd_unreg_rpi_s *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 ; +} + +/** +* @ingroup sli +* @brief Write an UNREG_VFI command to the provided buffer. +* +* @param sli4 SLI context pointer. +* @param buf Virtual pointer to the destination buffer. +* @param size Buffer size, in bytes. +* @param domain Pointer to the domain object +* @param which Type of unregister, such as domain, FCFI, or everything. +* +* @return Returns the number of bytes written. +*/ +int +sli_cmd_unreg_vfi (struct sli4_s *sli4,void *buf,size_t size, +u16 index,u32 which) +{ +struct sli4_cmd_unreg_vfi_s *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 ; +} + +/** +* @ingroup sli +* @brief Write an UNREG_VPI command to the provided buffer. +* +* @param sli4 SLI context pointer. +* @param buf Virtual pointer to the destination buffer. +* @param size Buffer size, in bytes. +* @param indicator Indicator value. +* @param which Type of unregister: port, domain, FCFI, everything +* +* @return Returns the number of bytes written. +*/ +int +sli_cmd_unreg_vpi (struct sli4_s *sli4,void *buf,size_t size, +u16 indicator,u32 which) +{ +struct sli4_cmd_unreg_vpi_s *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 ; +} + +/** +* @brief Write a COMMON_MODIFY_EQ_DELAY command. +* +* @param sli4 SLI context. +* @param buf Destination buffer for the command. +* @param size Buffer size, in bytes. +* @param q Queue object array. +* @param num_q Queue object array count. +* @param shift Phase shift for staggering interrupts. +* @param delay_mult Delay multiplier for limiting interrupt frequency. +* +* @return Returns the number of bytes written. +*/ +static int +sli_cmd_common_modify_eq_delay (struct sli4_s *sli4,void *buf,size_t size, +struct sli4_queue_s *q,int num_q,u32 shift, +u32 delay_mult) +{ +struct sli4_rqst_cmn_modify_eq_delay_s *modify_delay =NULL ; +int i; + + modify_delay =sli_config_cmd_init (sli4, buf, size, +SLI_CONFIG_PYLD_LENGTH (cmn_modify_eq_delay), +NULL ); +if (!modify_delay) +return EFC_FAIL ; + + modify_delay->hdr.opcode =CMN_MODIFY_EQ_DELAY ; + modify_delay->hdr.subsystem =SLI4_SUBSYSTEM_COMMON ; + modify_delay->hdr.request_length = +CFG_RQST_PYLD_LEN (cmn_modify_eq_delay); + modify_delay->num_eq =cpu_to_le32 (num_q); + +for (i =0 ; i < num_q; i++) { + modify_delay->eq_delay_record[i].eq_id =cpu_to_le32 (q[i].id); + modify_delay->eq_delay_record[i].phase =cpu_to_le32 (shift); + modify_delay->eq_delay_record[i].delay_multiplier = +cpu_to_le32 (delay_mult); + } + +return EFC_SUCCESS ; +} + +/** +* @brief Write a LOWLEVEL_SET_WATCHDOG command. +* +* @param sli4 SLI context. +* @param buf Destination buffer for the command. +* @param size Buffer size, in bytes. +* @param timeout watchdog timer timeout in seconds +* +* @return void +*/ +void +sli4_cmd_lowlevel_set_watchdog (struct sli4_s *sli4,void *buf, +size_t size,u16 timeout) +{ +struct sli4_rqst_lowlevel_set_watchdog_s *req =NULL ; + + req =sli_config_cmd_init (sli4, buf, size, +SLI_CONFIG_PYLD_LENGTH (lowlevel_set_watchdog), +NULL ); +if (!req) +return ; + + req->hdr.opcode =SLI4_OPC_LOWLEVEL_SET_WATCHDOG ; + req->hdr.subsystem =SLI4_SUBSYSTEM_LOWLEVEL ; + req->hdr.request_length =CFG_RQST_PYLD_LEN (lowlevel_set_watchdog); + req->watchdog_timeout =cpu_to_le16 (timeout); +} + +static int +sli_cmd_common_get_cntl_attributes (struct sli4_s *sli4,void *buf,size_t size, +struct efc_dma_s *dma) +{ +struct sli4_rqst_hdr_s *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 ; +} + +/** +* @brief Write a COMMON_GET_CNTL_ADDL_ATTRIBUTES command. +* +* @param sli4 SLI context. +* @param buf Destination buffer for the command. +* @param size Buffer size, in bytes. +* @param dma DMA structure from which the data will be copied. +* +* @note This creates a Version 0 message. +* +* @return Returns the number of bytes written. +*/ +static int +sli_cmd_common_get_cntl_addl_attributes (struct sli4_s *sli4,void *buf, +size_t size,struct efc_dma_s *dma) +{ +struct sli4_rqst_hdr_s *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 ; +} + +/** +* @ingroup sli +* @brief Write a COMMON_NOP command +* +* @param sli4 SLI context. +* @param buf Destination buffer for the command. +* @param size Buffer size, in bytes. +* @param context NOP context value (passed to response, except on FC/FCoE). +* +* @return Returns the number of bytes written. +*/ +int +sli_cmd_common_nop (struct sli4_s *sli4,void *buf, +size_t size,uint64_t context) +{ +struct sli4_rqst_cmn_nop_s *nop =NULL ; + + nop =sli_config_cmd_init (sli4, buf, size, +SLI_CONFIG_PYLD_LENGTH (cmn_nop),NULL ); +if (!nop) +return EFC_FAIL ; + + nop->hdr.opcode =CMN_NOP ; + nop->hdr.subsystem =SLI4_SUBSYSTEM_COMMON ; + nop->hdr.request_length =CFG_RQST_PYLD_LEN (cmn_nop); + +memcpy (&nop->context, &context,sizeof (context)); + +return EFC_SUCCESS ; +} + +/** +* @ingroup sli +* @brief Write a COMMON_GET_RESOURCE_EXTENT_INFO command. +* +* @param sli4 SLI context. +* @param buf Destination buffer for the command. +* @param size Buffer size, in bytes. +* @param rtype Resource type (for example, XRI, VFI, VPI, and RPI). +* +* @return Returns the number of bytes written. +*/ +int +sli_cmd_common_get_resource_extent_info (struct sli4_s *sli4,void *buf, +size_t size,u16 rtype) +{ +struct sli4_rqst_cmn_get_resource_extent_info_s *extent =NULL ; + + extent =sli_config_cmd_init (sli4, buf, size, +CFG_RQST_CMDSZ (cmn_get_resource_extent_info), +NULL ); +if (extent) +return EFC_FAIL ; + + extent->hdr.opcode =CMN_GET_RSC_EXTENT_INFO ; + extent->hdr.subsystem =SLI4_SUBSYSTEM_COMMON ; + extent->hdr.request_length = +CFG_RQST_PYLD_LEN (cmn_get_resource_extent_info); + + extent->resource_type =cpu_to_le16 (rtype); + +return EFC_SUCCESS ; +} + +/** +* @ingroup sli +* @brief Write a COMMON_GET_SLI4_PARAMETERS command. +* +* @param sli4 SLI context. +* @param buf Destination buffer for the command. +* @param size Buffer size, in bytes. +* +* @return Returns the number of bytes written. +*/ +int +sli_cmd_common_get_sli4_parameters (struct sli4_s *sli4,void *buf, +size_t size) +{ +struct sli4_rqst_hdr_s *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 ; +} + +/** +* @brief Write a COMMON_GET_PORT_NAME command to the provided buffer. +* +* @param sli4 SLI context pointer. +* @param buf Virtual pointer to destination buffer. +* @param size Buffer size in bytes. +* +* @note Function supports both version 0 and 1 forms of this command via +* the IF_TYPE. +* +* @return Returns the number of bytes written. +*/ +static int +sli_cmd_common_get_port_name (struct sli4_s *sli4,void *buf,size_t size) +{ +struct sli4_rqst_cmn_get_port_name_s *pname; + + pname =sli_config_cmd_init (sli4, buf, size, +SLI_CONFIG_PYLD_LENGTH (cmn_get_port_name), +NULL ); +if (!pname) +return EFC_FAIL ; + + pname->hdr.opcode =CMN_GET_PORT_NAME ; + pname->hdr.subsystem =SLI4_SUBSYSTEM_COMMON ; + pname->hdr.request_length =CFG_RQST_PYLD_LEN (cmn_get_port_name); + pname->hdr.dw3_version =cpu_to_le32 (CMD_V1 ); + +/* Set the port type value (ethernet=0, FC=1) for V1 commands */ + pname->port_type =PORT_TYPE_FC ; + +return EFC_SUCCESS ; +} + +/** +* @ingroup sli +* @brief Write a COMMON_WRITE_OBJECT command. +* +* @param sli4 SLI context. +* @param buf Destination buffer for the command. +* @param size Buffer size, in bytes. +* @param noc True if the object should be written but not committed to flash. +* @param eof True if this is the last write for this object. +* @param desired_write_length Number of bytes of data to write to the object. +* @param offset Offset, in bytes, from the start of the object. +* @param object_name Name of the object to write. +* @param dma DMA structure from which the data will be copied. +* +* @return Returns the number of bytes written. +*/ +int +sli_cmd_common_write_object (struct sli4_s *sli4,void *buf,size_t size, +u16 noc, +u16 eof,u32 desired_write_length, +u32 offset,char *object_name, +struct efc_dma_s *dma) +{ +struct sli4_rqst_cmn_write_object_s *wr_obj =NULL ; +struct sli4_bde_s *host_buf; +u32 dwflags =0 ; + + wr_obj =sli_config_cmd_init (sli4, buf, size, +CFG_RQST_CMDSZ (cmn_write_object) + +sizeof (*host_buf),NULL ); +if (!wr_obj) +return EFC_FAIL ; + + wr_obj->hdr.opcode =CMN_WRITE_OBJECT ; + wr_obj->hdr.subsystem =SLI4_SUBSYSTEM_COMMON ; + wr_obj->hdr.request_length =CFG_RQST_PYLD_LEN_VAR (cmn_write_object, +sizeof (*host_buf)); + wr_obj->hdr.timeout =0 ; + wr_obj->hdr.dw3_version =CMD_V0 ; + +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 ); + + host_buf = (struct sli4_bde_s *)wr_obj->host_buffer_descriptor; + +/* Setup to transfer xfer_size bytes to device */ + host_buf->bde_type_buflen = +cpu_to_le32 ((BDE_TYPE_BDE_64 <<BDE_TYPE_SHIFT ) | + (desired_write_length &SLI4_BDE_MASK_BUFFER_LEN )); + host_buf->u.data.low = +cpu_to_le32 (lower_32_bits (dma->phys)); + host_buf->u.data.high = +cpu_to_le32 (upper_32_bits (dma->phys)); + +return EFC_SUCCESS ; +} + +/** +* @ingroup sli +* @brief Write a COMMON_DELETE_OBJECT command. +* +* @param sli4 SLI context. +* @param buf Destination buffer for the command. +* @param size Buffer size, in bytes. +* @param object_name Name of the object to write. +* +* @return Returns the number of bytes written. +*/ +int +sli_cmd_common_delete_object (struct sli4_s *sli4,void *buf,size_t size, +char *object_name) +{ +struct sli4_rqst_cmn_delete_object_s *del_obj =NULL ; + + del_obj =sli_config_cmd_init (sli4, buf, size, +CFG_RQST_CMDSZ (cmn_delete_object),NULL ); +if (!del_obj) +return EFC_FAIL ; + + del_obj->hdr.opcode =CMN_DELETE_OBJECT ; + del_obj->hdr.subsystem =SLI4_SUBSYSTEM_COMMON ; + del_obj->hdr.request_length =CFG_RQST_PYLD_LEN (cmn_delete_object); + del_obj->hdr.timeout =0 ; + del_obj->hdr.dw3_version =CMD_V0 ; + +strncpy (del_obj->object_name, object_name, +sizeof (del_obj->object_name)); +return EFC_SUCCESS ; +} + +/** +* @ingroup sli +* @brief Write a COMMON_READ_OBJECT command. +* +* @param sli4 SLI context. +* @param buf Destination buffer for the command. +* @param size Buffer size, in bytes. +* @param desired_read_length Number of bytes of data to read from the object. +* @param offset Offset, in bytes, from the start of the object. +* @param object_name Name of the object to read. +* @param dma DMA structure from which the data will be copied. +* +* @return Returns the number of bytes written. +*/ +int +sli_cmd_common_read_object (struct sli4_s *sli4,void *buf,size_t size, +u32 desired_read_length,u32 offset, +char *object_name,struct efc_dma_s *dma) +{ +struct sli4_rqst_cmn_read_object_s *rd_obj =NULL ; +struct sli4_bde_s *host_buf; + + rd_obj =sli_config_cmd_init (sli4, buf, size, +CFG_RQST_CMDSZ (cmn_read_object) + +sizeof (*host_buf),NULL ); +if (!rd_obj) +return EFC_FAIL ; + + rd_obj->hdr.opcode =CMN_READ_OBJECT ; + rd_obj->hdr.subsystem =SLI4_SUBSYSTEM_COMMON ; + rd_obj->hdr.request_length =CFG_RQST_PYLD_LEN_VAR (cmn_read_object, +sizeof (*host_buf)); + rd_obj->hdr.timeout =0 ; + rd_obj->hdr.dw3_version =CMD_V0 ; + + 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 ); + + host_buf = (struct sli4_bde_s *)rd_obj->host_buffer_descriptor; + +/* Setup to transfer xfer_size bytes to device */ + host_buf->bde_type_buflen = +cpu_to_le32 ((BDE_TYPE_BDE_64 <<BDE_TYPE_SHIFT ) | + (desired_read_length &SLI4_BDE_MASK_BUFFER_LEN )); +if (dma) { + host_buf->u.data.low = +cpu_to_le32 (lower_32_bits (dma->phys)); + host_buf->u.data.high = +cpu_to_le32 (upper_32_bits (dma->phys)); + }else { + host_buf->u.data.low =0 ; + host_buf->u.data.high =0 ; + } + +return EFC_SUCCESS ; +} + +/** +* @ingroup sli +* @brief Write a DMTF_EXEC_CLP_CMD command. +* +* @param sli4 SLI context. +* @param buf Destination buffer for the command. +* @param size Buffer size, in bytes. +* @param cmd DMA structure that describes the buffer for the command. +* @param resp DMA structure that describes the buffer for the response. +* +* @return Returns the number of bytes written. +*/ +int +sli_cmd_dmtf_exec_clp_cmd (struct sli4_s *sli4,void *buf,size_t size, +struct efc_dma_s *cmd, +struct efc_dma_s *resp) +{ +struct sli4_rqst_dmtf_exec_clp_cmd_s *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 ; + + clp_cmd->hdr.opcode =DMTF_EXEC_CLP_CMD ; + clp_cmd->hdr.subsystem =SLI4_SUBSYSTEM_DMTF ; + clp_cmd->hdr.request_length =CFG_RQST_PYLD_LEN (dmtf_exec_clp_cmd); + clp_cmd->hdr.timeout =0 ; + clp_cmd->hdr.dw3_version =CMD_V0 ; + 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 ; +} + +/** +* @ingroup sli +* @brief Write a COMMON_SET_DUMP_LOCATION command. +* +* @param sli4 SLI context. +* @param buf Destination buffer for the command. +* @param size Buffer size, in bytes. +* @param query Zero to set dump location, non-zero to query dump size +* @param is_buffer_list Set to one if the buffer +* is a set of buffer descriptors or +* set to 0 if the buffer is a contiguous dump area. +* @param buffer DMA structure to which the dump will be copied. +* +* @return Returns the number of bytes written. +*/ +int +sli_cmd_common_set_dump_location (struct sli4_s *sli4,void *buf, +size_t size,bool query, +bool is_buffer_list, +struct efc_dma_s *buffer,u8 fdb) +{ +struct sli4_rqst_cmn_set_dump_location_s *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 ; + + set_dump_loc->hdr.opcode =CMN_SET_DUMP_LOCATION ; + set_dump_loc->hdr.subsystem =SLI4_SUBSYSTEM_COMMON ; + set_dump_loc->hdr.request_length = +CFG_RQST_PYLD_LEN (cmn_set_dump_location); + set_dump_loc->hdr.timeout =0 ; + set_dump_loc->hdr.dw3_version =CMD_V0 ; + +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 ; +} + +/** +* @ingroup sli +* @brief Write a COMMON_SET_FEATURES command. +* +* @param sli4 SLI context. +* @param buf Destination buffer for the command. +* @param size Buffer size, in bytes. +* @param feature Feature to set. +* @param param_len Length of the parameter (must be a multiple of 4 bytes). +* @param parameter Pointer to the parameter value. +* +* @return Returns the number of bytes written. +*/ +int +sli_cmd_common_set_features (struct sli4_s *sli4,void *buf,size_t size, +u32 feature, +u32 param_len, +void *parameter) +{ +struct sli4_rqst_cmn_set_features_s *cmd =NULL ; + + cmd =sli_config_cmd_init (sli4, buf, size, +CFG_RQST_CMDSZ (cmn_set_features),NULL ); +if (!cmd) +return EFC_FAIL ; + + cmd->hdr.opcode =CMN_SET_FEATURES ; + cmd->hdr.subsystem =SLI4_SUBSYSTEM_COMMON ; + cmd->hdr.request_length =CFG_RQST_PYLD_LEN (cmn_set_features); + cmd->hdr.timeout =0 ; + cmd->hdr.dw3_version =CMD_V0 ; + + cmd->feature =cpu_to_le32 (feature); + cmd->param_len =cpu_to_le32 (param_len); +memcpy (cmd->params, parameter, param_len); + +return EFC_SUCCESS ; +} + +/** +* @ingroup sli +* @brief Check the mailbox/queue completion entry. +* +* @param buf Pointer to the MCQE. +* +* @return Returns 0 on success, or a non-zero value on failure. +*/ +int +sli_cqe_mq (struct sli4_s *sli4,void *buf) +{ +struct sli4_mcqe_s *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); +} + +/** +* @ingroup sli +* @brief Check the asynchronous event completion entry. +* +* @param sli4 SLI context. +* @param buf Pointer to the ACQE. +* +* @return Returns 0 on success, or a non-zero value on failure. +*/ +int +sli_cqe_async (struct sli4_s *sli4,void *buf) +{ +struct sli4_acqe_s *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
PATCH 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 | 1472 ++++++++++++++++++++++++++++++++++++ drivers/scsi/elx/libefc_sli/sli4.h | 578 ++++++++++++++ 2 files changed, 2050 insertions(+)
drivers/scsi/elx/libefc_sli/sli4.c +1472 -0
@@ -6048,3 +6048,1475 @@ sli_cqe_async(struct sli4_s *sli4, void *buf)return rc; } + +/** +* @ingroup sli +* @brief Determine if the chip FW is in a ready state +* +* @param sli4 SLI context. +* +* @return +* - 0 if call completed correctly and FW is not ready. +* - 1 if call completed correctly and FW is ready. +* - -1 if call failed. +*/ +int +sli_fw_ready (struct sli4_s *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 ; +} + +/** +* @brief Initialize SLI Port control register. +* +* @param sli4 SLI context pointer. +* @param endian Endian value to write. +* +* @return Returns 0 on success, or a negative error code value on failure. +*/ + +static int +sli_sliport_reset (struct sli4_s *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; +} +/** +* @brief check to see if the FW is ready. +* +* @par Description +* Based on <i>SLI-4 Architecture Specification, Revision 4.x0-13 (2012).</i>. +* +* @param sli4 SLI context. +* @param timeout_ms Time, in milliseconds, to wait for the port to be ready +* before failing. +* +* @return Returns TRUE for ready, or FALSE otherwise. +*/ +static bool +sli_wait_for_fw_ready (struct sli4_s *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; +} + +/** +* @brief Initialize the firmware. +* +* @par Description +* Based on <i>SLI-4 Architecture Specification, Revision 4.x0-13 (2012).</i>. +* +* @param sli4 SLI context. +* +* @return Returns 0 on success, or a non-zero value on failure. +*/ +static int +sli_fw_init (struct sli4_s *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 ; +} + +/** +* @brief Terminate the firmware. +* +* @param sli4 SLI context. +* +* @return Returns 0 on success, or a non-zero value on failure. +*/ +static int +sli_fw_term (struct sli4_s *sli4) +{ +/* type 2 etc. use SLIPORT_CONTROL to initialize port */ +sli_sliport_reset (sli4); +return 0 ; +} + +static int +sli_request_features (struct sli4_s *sli4,u32 *features,bool query) +{ +if (!sli_cmd_request_features (sli4, sli4->bmbx.virt,SLI4_BMBX_SIZE , + *features, query)) { +struct sli4_cmd_request_features_s *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 ; +} + +/** +* @brief Calculate max queue entries. +* +* @param sli4 SLI context. +* +* @return Returns 0 on success, or a non-zero value on failure. +*/ +void +sli_calc_max_qentries (struct sli4_s *sli4) +{ +enum sli4_qtype_e q; +u32 alloc_size, qentries, qentry_size; + +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]; + qentry_size =sli_get_queue_entry_size (sli4, q); + alloc_size = qentries * qentry_size; + +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_s *sli4) +{ +struct efc_dma_s data; +u32 psize; + +/* +* Read the device configuration +*/ +if (!sli_cmd_read_config (sli4, sli4->bmbx.virt,SLI4_BMBX_SIZE )) { +struct sli4_rsp_read_config_s *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); + }else { + ; + } + +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_s *parms = + (struct sli4_rsp_cmn_get_sli4_params_s *) + (((u8 *)sli4->bmbx.virt) + + offsetof(struct sli4_cmd_sli_config_s, 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_s *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_s ); + 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_s )); +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_s *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_s )); + } + +if (!sli_cmd_common_get_port_name (sli4, sli4->bmbx.virt, +SLI4_BMBX_SIZE )) { +struct sli4_rsp_cmn_get_port_name_s *port_name = + (struct sli4_rsp_cmn_get_port_name_s *) + (((u8 *)sli4->bmbx.virt) + + offsetof(struct sli4_cmd_sli_config_s, 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_s *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_s *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 ; +} + +/* +* Public functions +*/ + +/** +* @ingroup sli +* @brief Set up the SLI context. +* +* @param sli4 SLI context. +* @param os Device abstraction. +* @param port_type Protocol type of port (for example, FC and NIC). +* +* @return Returns 0 on success, or a non-zero value on failure. +*/ +int +sli_setup (struct sli4_s *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_s )); + + 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_s ); + 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_s )); +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_s )); +/* 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_s *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_s *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 ; +} + +/** +* @ingroup sli +* @brief Issue a Firmware Reset. +* +* @par Description +* Issues a Firmware Reset to the chip. This reset affects the entire chip, +* so all PCI function on the same PCI bus and device are affected. +* @n @n This type of reset can be used to activate newly downloaded firmware. +* @n @n The driver should be considered to be in an unknown state after this +* reset and should be reloaded. +* +* @param sli4 SLI context. +* +* @return Returns 0 on success, or -1 otherwise. +*/ + +int +sli_fw_reset (struct sli4_s *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 ; +} + +/** +* @ingroup sli +* @brief Tear down a SLI context. +* +* @param sli4 SLI context. +* +* @return Returns 0 on success, or non-zero otherwise. +*/ +int +sli_teardown (struct sli4_s *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 ; +} + +/** +* @ingroup sli +* @brief Register a callback for the given event. +* +* @param sli4 SLI context. +* @param which Event of interest. +* @param func Function to call when the event occurs. +* @param arg Argument passed to the callback function. +* +* @return Returns 0 on success, or non-zero otherwise. +*/ +int +sli_callback (struct sli4_s *sli4,enum sli4_callback_e 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 ; +} + +/** +* @ingroup sli +* @brief Modify the delay timer for all the EQs +* +* @param sli4 SLI context. +* @param eq Array of EQs. +* @param num_eq Count of EQs. +* @param shift Phase shift for staggering interrupts. +* @param delay_mult Delay multiplier for limiting interrupt frequency. +* +* @return Returns 0 on success, or -1 otherwise. +*/ +int +sli_eq_modify_delay (struct sli4_s *sli4,struct sli4_queue_s *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 ; +} + +/** +* @ingroup sli +* @brief Allocate SLI Port resources. +* +* @par Description +* Allocate port-related resources, such as VFI, RPI, XRI, and so on. +* Resources are modeled using extents, regardless of whether the underlying +* device implements resource extents. If the device does not implement +* extents, the SLI layer models this as a single (albeit large) extent. +* +* @param sli4 SLI context. +* @param rtype Resource type (for example, RPI or XRI) +* @param rid Allocated resource ID. +* @param index Index into the bitmap. +* +* @return Returns 0 on success, or a non-zero value on failure. +*/ +int +sli_resource_alloc (struct sli4_s *sli4,enum sli4_resource_e 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; +} + +/** +* @ingroup sli +* @brief Free the SLI Port resources. +* +* @par Description +* Free port-related resources, such as VFI, RPI, XRI, and so. +* See discussion of "extent" usage in sli_resource_alloc. +* +* @param sli4 SLI context. +* @param rtype Resource type (for example, RPI or XRI). +* @param rid Allocated resource ID. +* +* @return Returns 0 on success, or a non-zero value on failure. +*/ +int +sli_resource_free (struct sli4_s *sli4, +enum sli4_resource_e 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_s *sli4,enum sli4_resource_e 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; +} + +/** +* @ingroup sli +* @brief Cause chip to enter an unrecoverable error state. +* +* @par Description +* Cause chip to enter an unrecoverable error state. This is +* used when detecting unexpected FW behavior so FW can be +* hwted from the driver as soon as error is detected. +* +* @param sli4 SLI context. +* @param dump Generate dump as part of reset. +* +* @return Returns 0 if call completed correctly, +* or -1 if call failed (unsupported chip). +*/ +int sli_raise_ue (struct sli4_s *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 ; +} + +/** +* @ingroup sli +* @brief Read the SLIPORT_STATUS register to to check if a dump is present. +* +* @param sli4 SLI context. +* +* @return Returns 1 if the chip is ready, +* or 0 if the chip is not ready, 2 if fdp is present. +*/ +int sli_dump_is_ready (struct sli4_s *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; +} + +/** +* @ingroup sli +* @brief Read the SLIPORT_STATUS register to check if a dump is present. +* +* @param sli4 SLI context. +* +* @return +* - 0 if call completed correctly and no dump is present. +* - 1 if call completed and dump is present. +* - -1 if call failed (unsupported chip). +*/ +int sli_dump_is_present (struct sli4_s *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 ; + } +} + +/** +* @ingroup sli +* @brief Read the SLIPORT_STATUS register to check if +* the reset required is set. +* +* @param sli4 SLI context. +* +* @return +* - 0 if call completed correctly and reset is not required. +* - 1 if call completed and reset is required. +* - -1 if call failed. +*/ +int sli_reset_required (struct sli4_s *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 ; + } +} + +/** +* @ingroup sli_fc +* @brief Write an POST_SGL_PAGES command. +* +* @param sli4 SLI context. +* @param buf Destination buffer for the command. +* @param size Buffer size, in bytes. +* @param xri starting XRI +* @param xri_count XRI +* @param page0 First SGL memory page. +* @param page1 Second SGL memory page (optional). +* @param dma DMA buffer for non-embedded mailbox command (options) +* +* if non-embedded mbx command is used, dma buffer must be at least +* (32 + xri_count*16) in length +* +* @return Returns the number of bytes written. +*/ +int +sli_cmd_post_sgl_pages (struct sli4_s *sli4,void *buf,size_t size, +u16 xri, +u32 xri_count,struct efc_dma_s *page0[], +struct efc_dma_s *page1[],struct efc_dma_s *dma) +{ +struct sli4_rqst_post_sgl_pages_s *post =NULL ; +u32 i; + + post =sli_config_cmd_init (sli4, buf, size, +SLI_CONFIG_PYLD_LENGTH (post_sgl_pages), + dma); +if (!post) +return EFC_FAIL ; + + post->hdr.opcode =SLI4_OPC_POST_SGL_PAGES ; + post->hdr.subsystem =SLI4_SUBSYSTEM_FC ; +/* 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 */ + post->hdr.request_length = +cpu_to_le32 (4 + (xri_count * (sizeof (uint64_t ) *2 ))); + + 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 = +lower_32_bits (page1[i]->phys); + post->page_set[i].page1_high = +upper_32_bits (page1[i]->phys); + } + } + +return EFC_SUCCESS ; +} + +/** +* @ingroup sli_fc +* @brief Write an POST_HDR_TEMPLATES command. +* +* @param sli4 SLI context. +* @param buf Destination buffer for the command. +* @param size Buffer size, in bytes. +* @param dma Pointer to DMA memory structure. This is allocated by the caller. +* @param rpi Starting RPI index for the header templates. +* @param payload_dma Pointer to DMA memory used to hold larger descriptor +* counts. +* +* @return Returns the number of bytes written. +*/ +int +sli_cmd_post_hdr_templates (struct sli4_s *sli4,void *buf, +size_t size,struct efc_dma_s *dma, +u16 rpi, +struct efc_dma_s *payload_dma) +{ +struct sli4_rqst_post_hdr_templates_s *template =NULL ; +uintptr_t phys =0 ; +u32 i =0 ; +u32 page_count; +u32 payload_size; + + page_count =sli_page_count (dma->size,SLI_PAGE_SIZE ); + + payload_size =CFG_RQST_PYLD_LEN_VAR (post_hdr_templates, + page_count *SZ_DMAADDR ); + +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_s )); +efc_log_err (sli4,"mbox payload memory allocation fail\n" ); +return EFC_FAIL ; + } + template =sli_config_cmd_init (sli4, buf, size, + payload_size, payload_dma); + }else { + template =sli_config_cmd_init (sli4, buf, size, + payload_size,NULL ); + } + +if (!template) +return EFC_FAIL ; + +if (rpi ==U16_MAX ) + rpi = sli4->extent[SLI_RSRC_RPI ].base[0 ]; + + template->hdr.opcode =SLI4_OPC_POST_HDR_TEMPLATES ; + template->hdr.subsystem =SLI4_SUBSYSTEM_FC ; + template->hdr.request_length =CFG_RQST_PYLD_LEN (post_hdr_templates); + + template->rpi_offset =cpu_to_le16 (rpi); + template->page_count =cpu_to_le16 (page_count); + phys = dma->phys; +for (i =0 ; i < page_count; i++) { + template->page_descriptor[i].low = +cpu_to_le32 (lower_32_bits (phys)); + template->page_descriptor[i].high = +cpu_to_le32 (upper_32_bits (phys)); + + phys +=SLI_PAGE_SIZE ; + } + +return EFC_SUCCESS ; +} + +/** +* @ingroup sli_fc +* @brief Get the RPI resource requirements. +* +* @param sli4 SLI context. +* @param n_rpi Number of RPIs desired. +* +* @return Returns the number of bytes needed. This value may be zero. +*/ +u32 +sli_fc_get_rpi_requirements (struct sli4_s *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; +} + +/** +* @ingroup sli_fc +* @brief Return a text string corresponding to a CQE status value +* +* @param status Status value +* +* @return Returns corresponding string, otherwise "unknown" +*/ +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 +578 -0
582 lines not on this page · raw message
Signature · 1 line
2.13.7
PATCH 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 | 275 +++++++++++++++++++++++++++++++++++++++ drivers/scsi/elx/libefc/efc_sm.h | 171 ++++++++++++++++++++++++ 2 files changed, 446 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 +275 -0
@@ -0,0 +1,275 @@ +// 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" +}; + +/** +* @brief Post an event to a context. +* +* @param ctx State machine context +* @param evt Event to post +* @param data Event-specific data (if any) +* +* @return 0 if successfully posted event; -1 if state machine +* is disabled +*/ +int +efc_sm_post_event (struct efc_sm_ctx_s *ctx, +enum efc_sm_event_e evt,void *data) +{ +if (ctx->current_state) { + ctx->current_state (ctx, evt, data); +return 0 ; + }else { +return -1 ; + } +} + +/** +* @brief Transition to a new state. +*/ +void +efc_sm_transition (struct efc_sm_ctx_s *ctx, +void *(*state)(struct efc_sm_ctx_s *, +enum efc_sm_event_e ,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); + } +} + +/** +* @brief Disable further state machine processing. +*/ +void +efc_sm_disable (struct efc_sm_ctx_s *ctx) +{ + ctx->current_state =NULL ; +} + +const char *efc_sm_event_name (enum efc_sm_event_e 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_RFT_ID_RCVD : +return "EFC_EVT_RFT_ID_RCVD" ; +case EFC_EVT_RFF_ID_RCVD : +return "EFC_EVT_RFF_ID_RCVD" ; +case EFC_EVT_GNN_ID_RCVD : +return "EFC_EVT_GNN_ID_RCVD" ; +case EFC_EVT_GPN_ID_RCVD : +return "EFC_EVT_GPN_ID_RCVD" ; +case EFC_EVT_GFPN_ID_RCVD : +return "EFC_EVT_GFPN_ID_RCVD" ; +case EFC_EVT_GFF_ID_RCVD : +return "EFC_EVT_GFF_ID_RCVD" ; +case EFC_EVT_GID_FT_RCVD : +return "EFC_EVT_GID_FT_RCVD" ; +case EFC_EVT_GID_PT_RCVD : +return "EFC_EVT_GID_PT_RCVD" ; +case EFC_EVT_RPN_ID_RCVD : +return "EFC_EVT_RPN_ID_RCVD" ; +case EFC_EVT_RNN_ID_RCVD : +return "EFC_EVT_RNN_ID_RCVD" ; +case EFC_EVT_RCS_ID_RCVD : +return "EFC_EVT_RCS_ID_RCVD" ; +case EFC_EVT_RSNN_NN_RCVD : +return "EFC_EVT_RSNN_NN_RCVD" ; +case EFC_EVT_RSPN_ID_RCVD : +return "EFC_EVT_RSPN_ID_RCVD" ; +case EFC_EVT_RHBA_RCVD : +return "EFC_EVT_RHBA_RCVD" ; +case EFC_EVT_RPA_RCVD : +return "EFC_EVT_RPA_RCVD" ; + +case EFC_EVT_GIDPT_DELAY_EXPIRED : +return "EFC_EVT_GIDPT_DELAY_EXPIRED" ; + +case EFC_EVT_ABORT_IO : +return "EFC_EVT_ABORT_IO" ; +case EFC_EVT_ABORT_IO_NO_RESP : +return "EFC_EVT_ABORT_IO_NO_RESP" ; +case EFC_EVT_IO_CMPL : +return "EFC_EVT_IO_CMPL" ; +case EFC_EVT_IO_CMPL_ERRORS : +return "EFC_EVT_IO_CMPL_ERRORS" ; +case EFC_EVT_RESP_CMPL : +return "EFC_EVT_RESP_CMPL" ; +case EFC_EVT_ABORT_CMPL : +return "EFC_EVT_ABORT_CMPL" ; +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" ; +case EFC_EVT_IO_ABORTED_BY_TMF : +return "EFC_EVT_IO_ABORTED_BY_TMF" ; +case EFC_EVT_IO_ABORT_IGNORED : +return "EFC_EVT_IO_ABORT_IGNORED" ; +case EFC_EVT_IO_FIRST_BURST : +return "EFC_EVT_IO_FIRST_BURST" ; +case EFC_EVT_IO_FIRST_BURST_ERR : +return "EFC_EVT_IO_FIRST_BURST_ERR" ; +case EFC_EVT_IO_FIRST_BURST_ABORTED : +return "EFC_EVT_IO_FIRST_BURST_ABORTED" ; + +default : +break ; + } +return "unknown" ; +}
drivers/scsi/elx/libefc/efc_sm.h new file +171 -0
171 lines not on this page · raw message
Signature · 1 line
2.13.7
PATCH 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 | 188 +++++++++ drivers/scsi/elx/libefc/efc_lib.c | 263 +++++++++++++ drivers/scsi/elx/libefc/efclib.h | 796 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 1247 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 +188 -0
@@ -0,0 +1,188 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* +* Copyright (C) 2019 Broadcom. All Rights Reserved. The term +* “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. +*/ + +/* +* EFC linux driver common include file +*/ + +#if !defined(__EFC_H__) +#define __EFC_H__ + +/*************************************************************************** +* OS specific includes +*/ +#include <stdarg.h> +#include <linux/version.h> +#include <linux/init.h> +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/list.h> +#include <linux/interrupt.h> +#include <asm-generic/ioctl.h> +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/pci.h> +#include <linux/dma-mapping.h> +#include <linux/bitmap.h> +#include <linux/slab.h> +#include <linux/spinlock.h> +#include <asm/byteorder.h> +#include <linux/timer.h> +#include <linux/delay.h> +#include <linux/fs.h> +#include <linux/uaccess.h> +#include <linux/sched.h> +#include <asm/current.h> +#include <asm/cacheflush.h> +#include <linux/pagemap.h> +#include <linux/kthread.h> +#include <linux/proc_fs.h> +#include <linux/seq_file.h> +#include <linux/random.h> +#include <linux/sched.h> +#include <linux/jiffies.h> +#include <linux/ctype.h> +#include <linux/debugfs.h> +#include <linux/firmware.h> + +#include "../include/efc_common.h" +#include "efclib.h" + +/* Linux driver specific definitions */ + +#define EFC_MIN_DMA_ALIGNMENT 16 +/* maximum DMA allocation that is expected to reliably succeed */ +#define EFC_MAX_DMA_ALLOC (64 * 1024) + +#define EFC_MAX_LUN 256 +#define EFC_NUM_UNSOLICITED_FRAMES 1024 + +#define EFC_MAX_NUMA_NODES 8 + +/* Per driver instance (efc_t) definitions */ +#define EFC_MAX_DOMAINS 1 +#define EFC_MAX_REMOTE_NODES 2048 + +/** +* @brief Sparse vector structure. +*/ +struct sparse_vector_s { +void *os; +u32 max_idx;/**< maximum index value */ +void **array;/**< pointer to 3D array */ +}; + +/** +* @brief 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. +*/ +/*! +* @defgroup spv Sparse Vector +*/ + +#define SPV_ROWLEN 256 +#define SPV_DIM 3 + +void efc_spv_del (struct sparse_vector_s *spv); +struct sparse_vector_s *efc_spv_new (void *os); +void efc_spv_set (struct sparse_vector_s *sv,u32 idx,void *value); +void *efc_spv_get (struct sparse_vector_s *sv,u32 idx); + +#define efc_assert (cond, ...) \ + do { \ + if (!(cond)) { \ + pr_err("%s(%d) assertion (%s) failed\n",\ + __FILE__, __LINE__, #cond);\ + dump_stack();\ + } \ + } while (0) + +int efc_dma_copy_in (struct efc_dma_s *dma,void *buffer, +u32 buffer_length); + +#include "efc_sm.h" + +struct efc_drv_s { +bool attached; +}; + +#define efc_is_fc_initiator_enabled () (efc->enable_ini) +#define efc_is_fc_target_enabled () (efc->enable_tgt) + +#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))\ + +enum efc_hw_rtn_e { +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_e { +EFC_SCSI_INITIATOR_DELETED , +EFC_SCSI_INITIATOR_MISSING , +}; + +enum efc_scsi_del_target_reason_e { +EFC_SCSI_TARGET_DELETED , +EFC_SCSI_TARGET_MISSING , +}; + +#define EFC_SCSI_CALL_COMPLETE 0/* All work is done */ +#define EFC_SCSI_CALL_ASYNC 1/* Work will be completed asynchronously */ + +#include "efc_domain.h" +#include "efc_sport.h" +#include "efc_node.h" + +/* Timeouts */ +#ifndef EFC_FC_ELS_SEND_DEFAULT_TIMEOUT +#define EFC_FC_ELS_SEND_DEFAULT_TIMEOUT 0 +#endif + +#ifndef EFC_FC_ELS_DEFAULT_RETRIES +#define EFC_FC_ELS_DEFAULT_RETRIES 3 +#endif + +#ifndef EFC_FC_FLOGI_TIMEOUT_SEC +#define EFC_FC_FLOGI_TIMEOUT_SEC 5/* shorter than default */ +#endif + +#ifndef EFC_FC_DOMAIN_SHUTDOWN_TIMEOUT_USEC +#define EFC_FC_DOMAIN_SHUTDOWN_TIMEOUT_USEC 30000000/* 30 seconds */ +#endif + +#endif /* __EFC_H__ */
drivers/scsi/elx/libefc/efc_lib.c new file +263 -0
263 lines not on this page · raw message
drivers/scsi/elx/libefc/efclib.h new file +796 -0
796 lines not on this page · raw message
Signature · 1 line
2.13.7
PATCH 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 | 1393 ++++++++++++++++++++++++++++++++++ drivers/scsi/elx/libefc/efc_domain.h | 57 ++ 2 files changed, 1450 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 +1393 -0
@@ -0,0 +1,1393 @@ +// 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" +#include "efc_fabric.h" +#include "efc_device.h" + +/** +* @brief Accept domain callback events from the HW. +* +* <h3 class="desc">Description</h3> +* HW calls this function with various domain-related events. +* +* @param arg Application-specified argument. +* @param event Domain event. +* @param data Event specific data. +* +* @return Returns 0 on success; or a negative error value on failure. +*/ + +int +efc_domain_cb (void *arg,int event,void *data) +{ +struct efc_lport *efc = arg; +struct efc_domain_s *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_s *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; +} + +/** +* @brief Allocate a domain object. +* +* <h3 class="desc">Description</h3> +* A domain object is allocated and initialized. It is associated with the +* \c efc argument. +* +* @param efc Pointer to the EFC device. +* @param fcf_wwn FCF WWN of the domain. +* +* @return Returns a pointer to the struct efc_domain_s object; or NULL. +*/ + +struct efc_domain_s * +efc_domain_alloc (struct efc_lport *efc,uint64_t fcf_wwn) +{ +struct efc_domain_s *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; +} + +/** +* @brief Free a domain object. +* +* <h3 class="desc">Description</h3> +* The domain object is freed. +* +* @param domain Domain object to free. +* +* @return None. +*/ + +void +efc_domain_free (struct efc_domain_s *domain) +{ +struct efc_lport *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); +} + +/** +* @brief Free memory resources of a domain object. +* +* <h3 class="desc">Description</h3> +* After the domain object is freed, its child objects are also freed. +* +* @param domain Pointer to a domain object. +* +* @return None. +*/ + +void +efc_domain_force_free (struct efc_domain_s *domain) +{ +struct efc_sli_port_s *sport; +struct efc_sli_port_s *next; +struct efc_lport *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); +} + +/** +* @brief Register a callback when the domain_list goes empty. +* +* <h3 class="desc">Description</h3> +* A function callback may be registered when the domain is freed. +* +* @param efc Pointer to a device object. +* @param callback Callback function. +* @param arg Callback argument. +* +* @return None. +*/ + +void +efc_register_domain_free_cb (struct efc_lport *efc, +void (*callback)(struct efc_lport *efc,void *arg), +void *arg) +{ + efc->domain_free_cb = callback; + efc->domain_free_cb_arg = arg; +if (!efc->domain && callback) + (*callback)(efc, arg); +} + +/** +* @ingroup domain_sm +* @brief Domain state machine: Common event handler. +* +* <h3 class="desc">Description</h3> +* Common/shared events are handled here for the domain state machine. +* +* @param funcname Function name text. +* @param ctx Domain state machine context. +* @param evt Event to process. +* @param arg Per event optional argument. +* +* @return Returns NULL. +*/ + +static void * +__efc_domain_common (const char *funcname,struct efc_sm_ctx_s *ctx, +enum efc_sm_event_e evt,void *arg) +{ +struct efc_domain_s *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 ; +} + +/** +* @ingroup domain_sm +* @brief Domain state machine: Common shutdown. +* +* <h3 class="desc">Description</h3> +* Handles common shutdown events. +* +* @param funcname Function name text. +* @param ctx Remote node state machine context. +* @param evt Event to process. +* @param arg Per event optional argument. +* +* @return Returns NULL. +*/ + +static void * +__efc_domain_common_shutdown (const char *funcname,struct efc_sm_ctx_s *ctx, +enum efc_sm_event_e evt,void *arg) +{ +struct efc_domain_s *domain = ctx->app; + +switch (evt) { +case EFC_EVT_ENTER : +case EFC_EVT_REENTER : +case EFC_EVT_EXIT : +break ; +case EFC_EVT_DOMAIN_FOUND : +/* sm: / 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 :/* clear drec available */ +/* sm: / 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_s *domain = NULL;\ + struct efc_lport *efc = NULL;\ + \ + efc_assert(ctx, NULL);\ + efc_assert(ctx->app, NULL);\ + domain = ctx->app;\ + efc_assert(domain->efc, NULL);\ + efc = domain->efc + +/** +* @ingroup domain_sm +* @brief Domain state machine: Initial state. +* +* <h3 class="desc">Description</h3> +* The initial state for a domain. Each domain is initialized to +* this state at start of day (SOD). +* +* @param ctx Domain state machine context. +* @param evt Event to process. +* @param arg Per event optional argument. +* +* @return Returns NULL. +*/ + +void * +__efc_domain_init (struct efc_sm_ctx_s *ctx,enum efc_sm_event_e 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_s *drec = arg; +struct efc_sli_port_s *sport; + +u64 my_wwnn = efc->req_wwnn; +u64 my_wwpn = efc->req_wwpn; +__be64 be_wwpn; + +/* +* For now, user must specify both port name and node name, +* or we let firmware pick both (same as for vports). +* do we want to allow setting only port name or +* only node name? +*/ +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_s 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 ; + } + +/* initialize domain object */ + 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_s *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 ; +} + +/** +* @ingroup domain_sm +* @brief Domain state machine: Wait for the domain allocation to complete. +* +* <h3 class="desc">Description</h3> +* Waits for the domain state to be allocated. After the HW domain +* allocation process has been initiated, this state waits for +* that process to complete (i.e. a domain-alloc-ok event). +* +* @param ctx Domain state machine context. +* @param evt Event to process. +* @param arg Per event optional argument. +* +* @return Returns NULL. +*/ + +void * +__efc_domain_wait_alloc (struct efc_sm_ctx_s *ctx, +enum efc_sm_event_e evt,void *arg) +{ +struct efc_sli_port_s *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_s *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 ; +} + +/** +* @ingroup domain_sm +* @brief Domain state machine: Wait for the domain attach request. +* +* <h3 class="desc">Description</h3> +* In this state, the domain has been allocated and is waiting for +* a domain attach request. +* The attach request comes from a node instance completing the fabric login, +* or from a point-to-point negotiation and login. +* +* @param ctx Remote node state machine context. +* @param evt Event to process. +* @param arg Per event optional argument. +* +* @return Returns NULL. +*/ + +void * +__efc_domain_allocated (struct efc_sm_ctx_s *ctx, +enum efc_sm_event_e 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_s *sport =NULL ; +struct efc_sli_port_s *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 ; +} + +/** +* @ingroup domain_sm +* @brief Domain state machine: Wait for the HW domain attach to complete. +* +* <h3 class="desc">Description</h3> +* Waits for the HW domain attach to complete. Forwards attach ok event to the +* fabric node state machine. +* +* @param ctx Remote node state machine context. +* @param evt Event to process. +* @param arg Per event optional argument. +* +* @return Returns NULL. +*/ + +void * +__efc_domain_wait_attach (struct efc_sm_ctx_s *ctx, +enum efc_sm_event_e evt,void *arg) +{ +std_domain_state_decl (); + +domain_sm_trace (domain); + +switch (evt) { +case EFC_EVT_DOMAIN_ATTACH_OK : { +struct efc_node_s *node =NULL ; +struct efc_node_s *next_node =NULL ; +struct efc_sli_port_s *sport; +struct efc_sli_port_s *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 ; +} + +/** +* @ingroup domain_sm +* @brief Domain state machine: Ready state. +* +* <h3 class="desc">Description</h3> +* This is a domain ready state. +* It waits for a domain-lost event, and initiates shutdown. +* +* @param ctx Remote node state machine context. +* @param evt Event to process. +* @param arg Per event optional argument. +* +* @return Returns NULL. +*/ + +void * +__efc_domain_ready (struct efc_sm_ctx_s *ctx, +enum efc_sm_event_e 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_s *sport =NULL ; +struct efc_sli_port_s *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 ; +} + +/** +* @ingroup domain_sm +* @brief Domain state machine: +* Wait for nodes to free prior to the domain shutdown. +* +* <h3 class="desc">Description</h3> +* All nodes are freed, and ready for a domain shutdown. +* +* @param ctx Remote node sm context. +* @param evt Event to process. +* @param arg Per event optional argument. +* +* @return Returns NULL. +*/ + +void * +__efc_domain_wait_sports_free (struct efc_sm_ctx_s *ctx, +enum efc_sm_event_e 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 ; +} + +/** +* @ingroup domain_sm +* @brief Domain state machine: Complete the domain shutdown. +* +* <h3 class="desc">Description</h3> +* Waits for a HW domain free to complete. +* +* @param ctx Remote node state machine context. +* @param evt Event to process. +* @param arg Per event optional argument. +* +* @return Returns NULL. +*/ + +void * +__efc_domain_wait_shutdown (struct efc_sm_ctx_s *ctx, +enum efc_sm_event_e 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_s 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 ; +} + +/** +* @ingroup domain_sm +* @brief Domain state machine: Wait for the domain alloc/attach completion +* after receiving a domain lost. +* +* <h3 class="desc">Description</h3> +* This state is entered when receiving a domain lost +* while waiting for a domain alloc +* or a domain attach to complete. +* +* @param ctx Remote node state machine context. +* @param evt Event to process. +* @param arg Per event optional argument. +* +* @return Returns NULL. +*/ + +void * +__efc_domain_wait_domain_lost (struct efc_sm_ctx_s *ctx, +enum efc_sm_event_e 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_s *sport =NULL ; +struct efc_sli_port_s *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 ; +} + +/** +* @brief Initiator domain attach. (internal call only) +* +* Assumes that the domain SM lock is already locked +* +* <h3 class="desc">Description</h3> +* The HW domain attach function is started. +* +* @param domain Pointer to the domain object. +* @param s_id FC_ID of which to register this domain. +* +* @return None. +*/ + +void +__efc_domain_attach_internal (struct efc_domain_s *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); +} + +/** +* @brief Initiator domain attach. +* +* <h3 class="desc">Description</h3> +* The HW domain attach function is started. +* +* @param domain Pointer to the domain object. +* @param s_id FC_ID of which to register this domain. +* +* @return None. +*/ + +void +efc_domain_attach (struct efc_domain_s *domain,u32 s_id) +{ +__efc_domain_attach_internal (domain, s_id); +} + +int +efc_domain_post_event (struct efc_domain_s *domain, +enum efc_sm_event_e event,void *arg) +{ +int rc; +bool accept_frames; +bool req_domain_free; +struct efc_lport *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; +} + +/** +* @ingroup unsol +* @brief Dispatch unsolicited FC frame. +* +* <h3 class="desc">Description</h3> +* This function processes an unsolicited FC frame queued at the +* domain level. +* +* @param arg Pointer to efc object. +* @param seq Header/payload sequence buffers. +* +* @return Returns 0 if frame processed and RX buffers cleaned +* up appropriately, -1 if frame not handled. +*/ + +int +efc_domain_dispatch_frame (void *arg,struct efc_hw_sequence_s *seq) +{ +struct efc_domain_s *domain = (struct efc_domain_s *)arg; +struct efc_lport *efc = domain->efc; +struct fc_frame_header *hdr; +u32 s_id; +u32 d_id; +struct efc_node_s *node =NULL ; +struct efc_sli_port_s *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); +} + +/** +* @ingroup unsol +* @brief Dispatch a frame. +* +* <h3 class="desc">Description</h3> +* A frame is dispatched from the \c node to the handler. +* +* @param arg Node that originated the frame. +* @param seq Header/payload sequence buffers. +* +* @return Returns 0 if frame processed and RX buffers cleaned +* up appropriately, -1 if frame not handled. +*/ +int +efc_node_dispatch_frame (void *arg,struct efc_hw_sequence_s *seq) +{ +struct fc_frame_header *hdr = seq->header->dma.virt; +u32 port_id; +struct efc_node_s *node = (struct efc_node_s *)arg; +int rc =-1 ; +int sit_set =0 ; + +struct efc_lport *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 +57 -0
57 lines not on this page · raw message
Signature · 1 line
2.13.7
PATCH 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 | 1157 +++++++++++++++++++++++++++++++++++ drivers/scsi/elx/libefc/efc_sport.h | 52 ++ 2 files changed, 1209 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 +1157 -0
@@ -0,0 +1,1157 @@ +// 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" +#include "efc_fabric.h" +#include "efc_device.h" + +static void efc_vport_update_spec (struct efc_sli_port_s *sport); +static void efc_vport_link_down (struct efc_sli_port_s *sport); + +/*! +*@defgroup sport_sm SLI Port (sport) State Machine: States +*/ + +/** +* @ingroup sport_sm +* @brief SLI port HW callback. +* +* @par Description +* This function is called in response to a HW sport event. +* This code resolves +* the reference to the sport object, and posts the corresponding event. +* +* @param arg Pointer to the EFC context. +* @param event HW sport event. +* @param data Application-specific event (pointer to the sport). +* +* @return Returns 0 on success, or a negative error value on failure. +*/ + +int +efc_lport_cb (void *arg,int event,void *data) +{ +struct efc_lport *efc = arg; +struct efc_sli_port_s *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 ; +} + +/** +* @ingroup sport_sm +* @brief Allocate a SLI port object. +* +* @par Description +* A sport object is allocated and associated with the domain. Various +* structure members are initialized. +* +* @param domain Pointer to the domain structure. +* @param wwpn World wide port name in host endian. +* @param wwnn World wide node name in host endian. +* @param fc_id Port ID of sport may be specified, +* use U32_MAX to fabric choose +* @param enable_ini Enables initiator capability +* on this port using a non-zero value. +* @param enable_tgt Enables target capability +* on this port using a non-zero value. +* +* @return Pointer to an struct efc_sli_port_s object; or NULL. +*/ + +struct efc_sli_port_s * +efc_sport_alloc (struct efc_domain_s *domain,uint64_t wwpn,uint64_t wwnn, +u32 fc_id,bool enable_ini,bool enable_tgt) +{ +struct efc_sli_port_s *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) { + 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; +} + +/** +* @ingroup sport_sm +* @brief Free a SLI port object. +* +* @par Description +* The sport object is freed. +* +* @param sport Pointer to the SLI port object. +* +* @return None. +*/ + +void +efc_sport_free (struct efc_sli_port_s *sport) +{ +struct efc_domain_s *domain; +bool post_all_free = false; + +if (sport) { + 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 ; + +/* +* Remove the sport from the domain's +* sparse vector lookup table +*/ +efc_spv_set (domain->lookup, sport->fc_id,NULL ); + +/* +* If the domain's sport_list is empty, +* then post the ALL_NODES_FREE event to the domain, +* after the lock is released. The domain may be +* free'd as a result of the event. +*/ +if (list_empty (&domain->sport_list)) + post_all_free = true; + +if (post_all_free) { +efc_domain_post_event (domain, +EFC_EVT_ALL_CHILD_NODES_FREE , +NULL ); + } + +kfree (sport); + } +} + +/** +* @ingroup sport_sm +* @brief Free memory resources of a SLI port object. +* +* @par Description +* After the sport object is freed, its child objects are freed. +* +* @param sport Pointer to the SLI port object. +* +* @return None. +*/ + +void +efc_sport_force_free (struct efc_sli_port_s *sport) +{ +struct efc_node_s *node; +struct efc_node_s *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); +} + +/** +* @ingroup sport_sm +* @brief Find a SLI port object, given an FC_ID. +* +* @par Description +* Returns a pointer to the sport object, given an FC_ID. +* +* @param domain Pointer to the domain. +* @param d_id FC_ID to find. +* +* @return Returns a pointer to the struct efc_sli_port_s; or NULL. +*/ + +struct efc_sli_port_s * +efc_sport_find (struct efc_domain_s *domain,u32 d_id) +{ +struct efc_sli_port_s *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; +} + +/** +* @ingroup sport_sm +* @brief Find a SLI port, given the WWNN and WWPN. +* +* @par Description +* Return a pointer to a sport, given the WWNN and WWPN. +* +* @param domain Pointer to the domain. +* @param wwnn World wide node name. +* @param wwpn World wide port name. +* +* @return Returns a pointer to a SLI port, if found; or NULL. +*/ + +struct efc_sli_port_s * +efc_sport_find_wwn (struct efc_domain_s *domain,uint64_t wwnn,uint64_t wwpn) +{ +struct efc_sli_port_s *sport =NULL ; + +list_for_each_entry (sport, &domain->sport_list, list_entry) { +if (sport->wwnn == wwnn && sport->wwpn == wwpn) +return sport; + } +return NULL ; +} + +/** +* @ingroup sport_sm +* @brief Request a SLI port attach. +* +* @par Description +* External call to request an attach for a sport, given an FC_ID. +* +* @param sport Pointer to the sport context. +* @param fc_id FC_ID of which to attach. +* +* @return Returns 0 on success, or a negative error value on failure. +*/ + +int +efc_sport_attach (struct efc_sli_port_s *sport,u32 fc_id) +{ +int rc; +struct efc_node_s *node; +struct efc_lport *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_s *sport) +{ +struct efc_lport *efc = sport->efc; +struct efc_node_s *node; +struct efc_node_s *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 ); + } + } +} + +/** +* @brief SLI port state machine: Common event handler. +* +* @par Description +* Handle common sport events. +* +* @param funcname Function name to display. +* @param ctx Sport state machine context. +* @param evt Event to process. +* @param arg Per event optional argument. +* +* @return Returns NULL. +*/ + +static void * +__efc_sport_common (const char *funcname,struct efc_sm_ctx_s *ctx, +enum efc_sm_event_e evt,void *arg) +{ +struct efc_sli_port_s *sport = ctx->app; +struct efc_domain_s *domain = sport->domain; +struct efc_lport *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 ; +} + +/** +* @ingroup sport_sm +* @brief SLI port state machine: Physical sport allocated. +* +* @par Description +* This is the initial state for sport objects. +* +* @param ctx Remote node state machine context. +* @param evt Event to process. +* @param arg Per event optional argument. +* +* @return Returns NULL. +*/ + +void * +__efc_sport_allocated (struct efc_sm_ctx_s *ctx, +enum efc_sm_event_e evt,void *arg) +{ +struct efc_sli_port_s *sport = ctx->app; +struct efc_domain_s *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 ; +} + +/** +* @ingroup sport_sm +* @brief SLI port state machine: Handle initial virtual port events. +* +* @par Description +* This state is entered when a virtual port is instantiated, +* +* @param ctx Remote node state machine context. +* @param evt Event to process. +* @param arg Per event optional argument. +* +* @return Returns NULL. +*/ + +void * +__efc_sport_vport_init (struct efc_sm_ctx_s *ctx, +enum efc_sm_event_e evt,void *arg) +{ +struct efc_sli_port_s *sport = ctx->app; +struct efc_lport *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 ; +} + +/** +* @ingroup sport_sm +* @brief SLI port state machine: +* Wait for the HW SLI port allocation to complete. +* +* @par Description +* Waits for the HW sport allocation request to complete. +* +* @param ctx Remote node state machine context. +* @param evt Event to process. +* @param arg Per event optional argument. +* +* @return Returns NULL. +*/ + +void * +__efc_sport_vport_wait_alloc (struct efc_sm_ctx_s *ctx, +enum efc_sm_event_e evt,void *arg) +{ +struct efc_sli_port_s *sport = ctx->app; +struct efc_lport *efc = sport->efc; + +sport_sm_trace (sport); + +switch (evt) { +case EFC_EVT_SPORT_ALLOC_OK : { +struct fc_els_flogi *sp; +struct efc_node_s *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 ; +} + +/** +* @ingroup sport_sm +* @brief SLI port state machine: virtual sport allocated. +* +* @par Description +* 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. +* +* @param ctx Remote node state machine context. +* @param evt Event to process. +* @param arg Per event optional argument. +* +* @return Returns NULL. +*/ + +void * +__efc_sport_vport_allocated (struct efc_sm_ctx_s *ctx, +enum efc_sm_event_e evt,void *arg) +{ +struct efc_sli_port_s *sport = ctx->app; +struct efc_lport *efc = sport->efc; + +sport_sm_trace (sport); + +switch (evt) { +case EFC_EVT_SPORT_ATTACH_OK : { +struct efc_node_s *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 ; +} + +/** +* @ingroup sport_sm +* @brief SLI port state machine: Attached. +* +* @par Description +* State entered after the sport attach has completed. +* +* @param ctx Remote node state machine context. +* @param evt Event to process. +* @param arg Per event optional argument. +* +* @return Returns NULL. +*/ + +void * +__efc_sport_attached (struct efc_sm_ctx_s *ctx, +enum efc_sm_event_e evt,void *arg) +{ +struct efc_sli_port_s *sport = ctx->app; +struct efc_lport *efc = sport->efc; + +sport_sm_trace (sport); + +switch (evt) { +case EFC_EVT_ENTER : { +struct efc_node_s *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 ; +} + +/** +* @ingroup sport_sm +* @brief SLI port state machine: Wait for the node shutdowns to complete. +* +* @par Description +* Waits for the ALL_CHILD_NODES_FREE event to be posted from the node +* shutdown process. +* +* @param ctx Remote node state machine context. +* @param evt Event to process. +* @param arg Per event optional argument. +* +* @return Returns NULL. +*/ + +void * +__efc_sport_wait_shutdown (struct efc_sm_ctx_s *ctx, +enum efc_sm_event_e evt,void *arg) +{ +struct efc_sli_port_s *sport = ctx->app; +struct efc_domain_s *domain = sport->domain; +struct efc_lport *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 ; +} + +/** +* @ingroup sport_sm +* @brief SLI port state machine: Wait for the HW's port free to complete. +* +* @par Description +* Waits for the HW's port free to complete. +* +* @param ctx Remote node state machine context. +* @param evt Event to process. +* @param arg Per event optional argument. +* +* @return Returns NULL. +*/ + +void * +__efc_sport_wait_port_free (struct efc_sm_ctx_s *ctx, +enum efc_sm_event_e evt,void *arg) +{ +struct efc_sli_port_s *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 ; +} + +/** +* @ingroup sport_sm +* @brief Start the vports on a domain +* +* @par Description +* Use the vport specification to find the associated vports and start them. +* +* @param domain Pointer to the domain context. +* +* @return Returns 0 on success, or a negative error value on failure. +*/ +int +efc_vport_start (struct efc_domain_s *domain) +{ +struct efc_lport *efc = domain->efc; +struct efc_vport_spec_s *vport; +struct efc_vport_spec_s *next; +struct efc_sli_port_s *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 ; + } + } + +/* Allocate a sport */ +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; + +/* Transition to vport_init */ +efc_sm_transition (&sport->sm, __efc_sport_vport_init, +NULL ); + } + } + +return rc; +} + +/** +* @ingroup sport_sm +* @brief Clear the sport reference in the vport specification. +* +* @par Description +* Clear the sport pointer on the vport specification when +* the vport is torn down. This allows it to be +* re-created when the link is re-established. +* +* @param sport Pointer to the sport context. +*/ +static void +efc_vport_link_down (struct efc_sli_port_s *sport) +{ +struct efc_lport *efc = sport->efc; +struct efc_vport_spec_s *vport; + +list_for_each_entry (vport, &efc->vport_list, list_entry) { +if (vport->sport == sport) { + vport->sport =NULL ; +break ; + } + } +} + +/** +* @ingroup sport_sm +* @brief Allocate a new virtual SLI port. +* +* @par Description +* A new sport is created, in response to an external management request. +* +* @n @b Note: If the WWPN is zero, the firmware will assign the WWNs. +* +* @param domain Pointer to the domain context. +* @param wwpn World wide port name. +* @param wwnn World wide node name +* @param fc_id Requested port ID (used in fabric emulation mode). +* @param ini TRUE, if port is created as an initiator node. +* @param tgt TRUE, if port is created as a target node. +* @param tgt_data Pointer to target specific data +* @param ini_data Pointer to initiator specific data +* @param restore_vport If TRUE, then the vport will be re-created automatically +* on link disruption. +* +* @return Returns 0 on success; or a negative error value on failure. +*/ + +int +efc_sport_vport_new (struct efc_domain_s *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_s *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 ; +} + +/** +* @ingroup sport_sm +* @brief Remove a previously-allocated virtual port. +* +* @par Description +* A previously-allocated virtual port is removed by +* posting the shutdown event to the +* sport with a matching WWN. +* +* @param efc Pointer to the device object. +* @param domain Pointer to the domain structure (may be NULL). +* @param wwpn World wide port name of the port to delete (host endian). +* @param wwnn World wide node name of the port to delete (host endian). +* +* @return Returns 0 on success, or a negative error value on failure. +*/ + +int +efc_sport_vport_del (struct efc_lport *efc,struct efc_domain_s *domain, +u64 wwpn,uint64_t wwnn) +{ +struct efc_sli_port_s *sport; +int found =0 ; +struct efc_vport_spec_s *vport; +struct efc_vport_spec_s *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 ; +} + +/** +* @brief Force free all saved vports. +* +* @par Description +* Delete all device vports. +* +* @param efc Pointer to the device object. +* +* @return None. +*/ + +void +efc_vport_del_all (struct efc_lport *efc) +{ +struct efc_vport_spec_s *vport; +struct efc_vport_spec_s *next; + +list_for_each_entry_safe (vport, next, &efc->vport_list, list_entry) { +list_del (&vport->list_entry); +kfree (vport); + } +} + +/** +* @brief Save the virtual port's parameters. +* +* @par Description +* The information required to restore a virtual port is saved. +* +* @param sport Pointer to the sport context. +* +* @return None. +*/ + +static void +efc_vport_update_spec (struct efc_sli_port_s *sport) +{ +struct efc_lport *efc = sport->efc; +struct efc_vport_spec_s *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 ; + } + } +} + +/** +* @brief 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. +* +* @param efc Pointer to device context. +* @param wwnn World wide node name (may be zero for auto-select). +* @param wwpn World wide port name (may be zero for auto-select). +* @param fc_id Requested port ID (used in fabric emulation mode). +* @param enable_ini TRUE if vport is to be an initiator port. +* @param enable_tgt TRUE if vport is to be a target port. +* @param tgt_data Pointer to target specific data. +* @param ini_data Pointer to initiator specific data. +* +* @return None. +*/ + +int8_t +efc_vport_create_spec (struct efc_lport *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_s *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->domain_instance =0 ; + 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
PATCH 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 | 1878 ++++++++++++++++++++++++++++++++++++ drivers/scsi/elx/libefc/efc_node.h | 196 ++++ 2 files changed, 2074 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 +1878 -0
@@ -0,0 +1,1878 @@ +// SPDX-License-Identifier: GPL-2.0 +/* +* Copyright (C) 2019 Broadcom. All Rights Reserved. The term +* “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. +*/ + +/* +* EFC driver remote node handler. This file contains code that is shared +* between fabric (efc_fabric.c) and device (efc_device.c) nodes. +*/ + +#include "efc.h" +#include "efc_device.h" + +#define SCSI_IOFMT "[%04x][i:%0*x t:%0*x h:%04x]" +#define SCSI_ITT_SIZE (efc) 4 + +#define SCSI_IOFMT_ARGS (io) \ + (io->instance_index, SCSI_ITT_SIZE(io->efc), \ + io->init_task_tag, SCSI_ITT_SIZE(io->efc), \ + io->tgt_task_tag, io->hw_tag) + +#define scsi_io_printf (io, fmt, ...) \ + efc_log_debug(io->efc, "[%s]" SCSI_IOFMT fmt, \ + io->node->display_name, SCSI_IOFMT_ARGS(io), ##__VA_ARGS__) + +#define MAX_ACC_REJECT_PAYLOAD sizeof(struct fc_els_ls_rjt) + +/** +* @ingroup node_common +* @brief Handle remote node events from HW +* +* Handle remote node events from HW. +* Essentially the HW event is translated into +* a node state machine event that is posted to the affected node. +* +* @param arg pointer to efc +* @param event HW event to proceoss +* @param data application specific data (pointer to the affected node) +* +* @return returns 0 for success, a negative error code value for failure. +*/ +int +efc_remote_node_cb (void *arg,int event, +void *data) +{ +struct efc_lport *efc = arg; +enum efc_sm_event_e sm_event =EFC_EVT_LAST ; +struct efc_remote_node_s *rnode = data; +struct efc_node_s *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 ; +} + +/** +* @ingroup node_alloc +* @brief Find an FC node structure given the FC port ID +* +* @param sport the SPORT to search +* @param port_id FC port ID +* +* @return pointer to the object or NULL if not found +*/ +struct efc_node_s * +efc_node_find (struct efc_sli_port_s *sport,u32 port_id) +{ +struct efc_node_s *node; + + node =efc_spv_get (sport->lookup, port_id); +return node; +} + +/** +* @ingroup node_alloc +* @brief allocate node object pool +* +* A pool of struct efc_node_s objects is allocated. +* +* @param efc pointer to driver instance context +* @param node_count count of nodes to allocate +* +* @return returns 0 for success, a negative error code value for failure. +*/ + +int +efc_node_create_pool (struct efc_lport *efc,u32 node_count) +{ +u32 i; +struct efc_node_s *node; +u64 max_xfer_size; +struct efc_dma_s *dma; + + efc->nodes_count = node_count; + + efc->nodes =kmalloc_array (node_count,sizeof (struct efc_node_s *), +GFP_ATOMIC ); +if (!efc->nodes) +return -1 ; + +memset (efc->nodes,0 , node_count *sizeof (struct efc_node_s *)); + +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 ; +} + +/** +* @ingroup node_alloc +* @brief free node object pool +* +* The pool of previously allocated node objects is freed +* +* @param efc pointer to driver instance context +* +* @return none +*/ + +void +efc_node_free_pool (struct efc_lport *efc) +{ +struct efc_node_s *node; +u32 i; +struct efc_dma_s *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 ; + } +} + +/** +* @ingroup node_alloc +* @brief return pointer to node object given instance index +* +* A pointer to the node object given by an instance index is returned. +* +* @param efc pointer to driver instance context +* @param index instance index +* +* @return returns pointer to node object, or NULL +*/ + +struct efc_node_s * +efc_node_get_instance (struct efc_lport *efc,u32 index) +{ +struct efc_node_s *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 ; +} + +/** +* @ingroup node_alloc +* @brief Allocate an fc node structure and add to node list +* +* @param sport pointer to the SPORT from which this node is allocated +* @param port_id FC port ID of new node +* @param init Port is an inititiator (sent a plogi) +* @param targ Port is potentially a target +* +* @return pointer to the object or NULL if none available +*/ + +struct efc_node_s *efc_node_alloc (struct efc_sli_port_s *sport, +u32 port_id,bool init,bool targ) +{ +int rc; +struct efc_node_s *node =NULL ; +u32 instance_index; +u64 max_wr_xfer_size; +struct efc_lport *efc = sport->efc; +struct efc_dma_s 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_s, 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; +} + +/** +* @ingroup node_alloc +* @brief free a node structure +* +* The node structure given by 'node' is free'd +* +* @param node the node to free +* +* @return returns 0 for success, a negative error code value for failure. +*/ + +int +efc_node_free (struct efc_node_s *node) +{ +struct efc_sli_port_s *sport; +struct efc_lport *efc; +int rc =0 ; +struct efc_node_s *ns =NULL ; +bool post_all_free = false; + + 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 ); + } + +/* Remove from node list */ +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)) + post_all_free = true; + +if (post_all_free) { +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; +} + +/** +* @brief free memory resources of a node object +* +* The node object's child objects are freed after which the +* node object is freed. +* +* @param node pointer to a node object +* +* @return none +*/ + +void +efc_node_force_free (struct efc_node_s *node) +{ +struct efc_lport *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); +} + +/** +* @ingroup node_common +* @brief Perform HW call to attach a remote node +* +* @param node pointer to node object +* +* @return 0 on success, non-zero otherwise +*/ +int +efc_node_attach (struct efc_node_s *node) +{ +int rc =0 ; +struct efc_sli_port_s *sport = node->sport; +struct efc_domain_s *domain = sport->domain; +struct efc_lport *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; +} + +/** +* @ingroup node_common +* @brief Generate text for a node's fc_id +* +* The text for a nodes fc_id is generated, +* either as a well known name, or a 6 digit +* hex value. +* +* @param fc_id fc_id +* @param buffer text buffer +* @param buffer_length text buffer length in bytes +* +* @return none +*/ + +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 ; + } +} + +/** +* @brief update the node's display name +* +* The node's display name is updated, sometimes needed because the sport part +* is updated after the node is allocated. +* +* @param node pointer to the node object +* +* @return none +*/ + +void +efc_node_update_display_name (struct efc_node_s *node) +{ +u32 port_id = node->rnode.fc_id; +struct efc_sli_port_s *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); +} + +/** +* @brief cleans up an XRI for the pending link services accept by aborting the +* XRI if required. +* +* <h3 class="desc">Description</h3> +* This function is called when the LS accept is not sent. +* +* @param node Node for which should be cleaned up +*/ + +void +efc_node_send_ls_io_cleanup (struct efc_node_s *node) +{ +struct efc_lport *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 ; + } +} + +/** +* @ingroup node_common +* @brief state: shutdown a node +* +* A node is shutdown, +* +* @param ctx remote node sm context +* @param evt event to process +* @param arg per event optional argument +* +* @return returns NULL +* +* @note +*/ + +void * +__efc_node_shutdown (struct efc_sm_ctx_s *ctx, +enum efc_sm_event_e evt,void *arg) +{ +int rc; +unsigned long flags =0 ; +struct efc_node_s *node = ctx->app; +struct efc_lport *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 ; +} + +/** +* @ingroup common_node +* @brief Checks to see if ELS's have been quiesced +* +* Check if ELS's have been quiesced. If so, transition to the +* next state in the shutdown process. +* +* @param node Node for which ELS's are checked +* +* @return Returns 1 if ELS's have been quiesced, 0 otherwise. +*/ +static int +efc_node_check_els_quiesced (struct efc_node_s *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 ; +} + +/** +* @ingroup common_node +* @brief Initiate node IO cleanup. +* +* Note: this function must be called with a non-attached node +* or a node for which the node detach (efc_hw_node_detach()) +* has already been initiated. +* +* @param node Node for which shutdown is initiated +* +* @return Returns None. +*/ + +void +efc_node_initiate_cleanup (struct efc_node_s *node) +{ +struct efc_lport *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 ); + } +} + +/** +* @ingroup node_common +* @brief Node state machine: Wait for all ELSs to complete. +* +* <h3 class="desc">Description</h3> +* State waits for all ELSs to complete after aborting all +* outstanding . +* +* @param ctx Remote node state machine context. +* @param evt Event to process. +* @param arg Per event optional argument. +* +* @return Returns NULL. +*/ + +void * +__efc_node_wait_els_shutdown (struct efc_sm_ctx_s *ctx, +enum efc_sm_event_e evt,void *arg) +{ +bool check_quiesce = false; +struct efc_node_s *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 ; +} + +/** +* @ingroup node_command +* @brief Node state machine: Wait for a HW node free event to +* complete. +* +* <h3 class="desc">Description</h3> +* State waits for the node free event to be received from the HW. +* +* @param ctx Remote node state machine context. +* @param evt Event to process. +* @param arg Per event optional argument. +* +* @return Returns NULL. +*/ + +void * +__efc_node_wait_node_free (struct efc_sm_ctx_s *ctx, +enum efc_sm_event_e evt,void *arg) +{ +struct efc_node_s *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 ; +} + +/** +* @ingroup node_common +* @brief state: initiate node shutdown +* +* 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. +* +* @param ctx remote node sm context +* @param evt event to process +* @param arg per event optional argument +* +* @return returns NULL +*/ + +void * +__efc_node_wait_ios_shutdown (struct efc_sm_ctx_s *ctx, +enum efc_sm_event_e evt,void *arg) +{ +struct efc_node_s *node = ctx->app; +struct efc_lport *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 ; +} + +/** +* @ingroup node_common +* @brief state: common node event handler +* +* Handle common/shared node events +* +* @param funcname calling function's name +* @param ctx remote node sm context +* @param evt event to process +* @param arg per event optional argument +* +* @return returns NULL +*/ + +void * +__efc_node_common (const char *funcname,struct efc_sm_ctx_s *ctx, +enum efc_sm_event_e evt,void *arg) +{ +struct efc_node_s *node =NULL ; +struct efc_lport *efc =NULL ; +struct efc_node_cb_s *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_GID_PT_RCVD : +case EFC_EVT_RFT_ID_RCVD : +case EFC_EVT_RFF_ID_RCVD : { +struct fc_frame_header *hdr = cbdata->header->dma.virt; + +efc_log_debug (efc,"[%s] (%s) %s sending CT_REJECT\n" , + node->display_name, funcname, +efc_sm_event_name (evt)); + efc->tt.send_ct_rsp (efc, node, hdr->fh_ox_id, + cbdata->payload->dma.virt, +FC_FS_RJT ,FC_FS_RJT_UNSUP ,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 ; +} + +/** +* @ingroup node_common +* @brief save node service parameters +* +* Service parameters are copyed into the node structure +* +* @param node pointer to node structure +* @param payload pointer to service parameters to save +* +* @return none +*/ + +void +efc_node_save_sparms (struct efc_node_s *node,void *payload) +{ +memcpy (node->service_params, payload,sizeof (node->service_params)); +} + +/** +* @ingroup node_common +* @brief Post event to node state machine context +* +* This is used by the node state machine code to post events to the nodes. +* Upon completion of the event posting, if the nesting depth is zero and +* we're not holding inbound frames, then the pending frames are processed. +* +* @param node pointer to node +* @param evt event to post +* @param arg event posting argument +* +* @return none +*/ + +void +efc_node_post_event (struct efc_node_s *node, +enum efc_sm_event_e 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); +} + +/** +* @ingroup node_common +* @brief transition state of a node +* +* The node's state is transitioned to the requested state. +* Entry/Exit events are posted as needed. +* +* @param node pointer to node +* @param state state to transition to +* @param data transition data +* +* @return none +*/ + +void +efc_node_transition (struct efc_node_s *node, +void *(*state)(struct efc_sm_ctx_s *, +enum efc_sm_event_e ,void *),void *data) + +{ +struct efc_sm_ctx_s *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); + } +} + +/** +* @ingroup node_common +* @brief build EUI formatted WWN +* +* Build a WWN given the somewhat transport agnostic +* iScsi naming specification, for FC +* use the eui. format, an ascii string such as: "eui.10000000C9A19501" +* +* @param buffer buffer to place formatted name into +* @param buffer_len length in bytes of the buffer +* @param eui_name cpu endian 64 bit WWN value +* +* @return none +*/ + +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); +} + +/** +* @ingroup node_common +* @brief return nodes' WWPN as a uint64_t +* +* The WWPN is computed from service parameters and returned as a uint64_t +* +* @param node pointer to node structure +* +* @return WWPN +* +*/ + +uint64_t +efc_node_get_wwpn (struct efc_node_s *node) +{ +struct fc_els_flogi *sp = + (struct fc_els_flogi *)node->service_params; + +return be64_to_cpu (sp->fl_wwpn); +} + +/** +* @ingroup node_common +* @brief return nodes' WWNN as a uint64_t +* +* The WWNN is computed from service parameters and returned as a uint64_t +* +* @param node pointer to node structure +* +* @return WWNN +* +*/ + +uint64_t +efc_node_get_wwnn (struct efc_node_s *node) +{ +struct fc_els_flogi *sp = + (struct fc_els_flogi *)node->service_params; + +return be64_to_cpu (sp->fl_wwnn); +} + +/** +* @brief check ELS request completion +* +* Check ELS request completion event to make sure it's for the +* ELS request we expect. If not, invoke given common event +* handler and return an error. +* +* @param ctx state machine context +* @param evt ELS request event +* @param arg event argument +* @param cmd ELS command expected +* @param node_common_func common event handler to call if ELS +* doesn't match +* @param funcname function name that called this +* +* @return zero if ELS command matches, -1 otherwise +*/ +int +efc_node_check_els_req (struct efc_sm_ctx_s *ctx,enum efc_sm_event_e evt, +void *arg,uint8_t cmd, +void *(*efc_node_common_func)(const char *, +struct efc_sm_ctx_s *, +enum efc_sm_event_e ,void *), +const char *funcname) +{ +return 0 ; +} + +/** +* @brief check NS request completion +* +* Check ELS request completion event to make sure it's for the +* nameserver request we expect. If not, invoke given common +* event handler and return an error. +* +* @param ctx state machine context +* @param evt ELS request event +* @param arg event argument +* @param cmd nameserver command expected +* @param node_common_func common event handler to call if +* nameserver cmd doesn't match +* @param funcname function name that called this +* +* @return zero if NS command matches, -1 otherwise +*/ +int +efc_node_check_ns_req (struct efc_sm_ctx_s *ctx,enum efc_sm_event_e evt, +void *arg,uint16_t cmd, +void *(*efc_node_common_func)(const char *, +struct efc_sm_ctx_s *, +enum efc_sm_event_e ,void *), +const char *funcname) +{ +return 0 ; +} + +/** +* @brief Return TRUE if active ios list is empty +* +* Test if node->active_ios list is empty while +* holding the node->active_ios_lock. +* +* @param node pointer to node object +* +* @return TRUE if node active ios list is empty +*/ + +int +efc_node_active_ios_empty (struct efc_node_s *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_s *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; +} + +/** +* @brief Pause a node +* +* The node is placed in the __efc_node_paused state after saving the state +* to return to +* +* @param node Pointer to node object +* @param state State to resume to +* +* @return none +*/ + +void +efc_node_pause (struct efc_node_s *node, +void *(*state)(struct efc_sm_ctx_s *, +enum efc_sm_event_e ,void *)) + +{ + node->nodedb_state = state; +efc_node_transition (node, __efc_node_paused,NULL ); +} + +/** +* @brief Paused node state +* +* This state is entered when a state is "paused". When resumed, the node +* is transitioned to a previously saved state (node->ndoedb_state) +* +* @param ctx Remote node state machine context. +* @param evt Event to process. +* @param arg Per event optional argument. +* +* @return returns NULL +*/ + +void * +__efc_node_paused (struct efc_sm_ctx_s *ctx, +enum efc_sm_event_e evt,void *arg) +{ +struct efc_node_s *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_s *ctx, +enum efc_sm_event_e 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 ; +} + +/** +* @brief Resume a paused state +* +* Posts a resume event to the paused node. +* +* @param node Pointer to node object +* +* @return returns 0 for success, a negative error code value for failure. +*/ + +int +efc_node_resume (struct efc_node_s *node) +{ +efc_node_post_event (node,EFC_EVT_RESUME ,NULL ); + +return 0 ; +} + +/** +* @ingroup node_common +* @brief Dispatch a ELS frame. +* +* <h3 class="desc">Description</h3> +* An ELS frame is dispatched to the \c node state machine. +* RQ Pair mode: this function is always called with a NULL hw +* io. +* +* @param node Node that originated the frame. +* @param seq header/payload sequence buffers +* +* @return Returns 0 if frame processed and RX buffers cleaned +* up appropriately, -1 if frame not handled and RX buffers need +* to be returned. +*/ + +int +efc_node_recv_els_frame (struct efc_node_s *node, +struct efc_hw_sequence_s *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_e 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_s cbdata; +u8 *buf = seq->payload->dma.virt; +enum efc_sm_event_e 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 ; +} + +/** +* @ingroup node_common +* @brief Dispatch a CT frame. +* +* <h3 class="desc">Description</h3> +* A CT frame is dispatched to the \c node state machine. +* RQ Pair mode: this function is always called with a NULL hw +* io. +* +* @param node Node that originated the frame. +* @param seq header/payload sequence buffers +* +* @return Returns 0 if frame processed and RX buffers cleaned +* up appropriately, -1 if frame not handled and RX buffers need +* to be returned. +*/ + +int +efc_node_recv_ct_frame (struct efc_node_s *node, +struct efc_hw_sequence_s *seq) +{ +struct fc_ct_hdr *iu = seq->payload->dma.virt; +enum efc_sm_event_e evt =EFC_EVT_ELS_RCVD ; +u16 gscmd =be16_to_cpu (iu->ct_cmd); +struct efc_node_cb_s cbdata; +unsigned long flags =0 ; +u32 i; +struct { +u32 cmd; +enum efc_sm_event_e evt; +u32 payload_size; + } ct_cmd_list[] = { + {FC_NS_RFF_ID ,EFC_EVT_RFF_ID_RCVD ,100 }, + {FC_NS_RFT_ID ,EFC_EVT_RFT_ID_RCVD ,100 }, + {FC_NS_GNN_ID ,EFC_EVT_GNN_ID_RCVD ,100 }, + {FC_NS_GPN_ID ,EFC_EVT_GPN_ID_RCVD ,100 }, + {FC_NS_GID_PT ,EFC_EVT_GID_PT_RCVD ,256 }, + {FC_NS_RPN_ID ,EFC_EVT_RPN_ID_RCVD ,100 }, + {FC_NS_RNN_ID ,EFC_EVT_RNN_ID_RCVD ,100 }, + {FC_NS_RSNN_NN ,EFC_EVT_RSNN_NN_RCVD ,100 }, + {FC_NS_RSPN_ID ,EFC_EVT_RSPN_ID_RCVD ,100 }, + }; + +memset (&cbdata,0 ,sizeof (cbdata)); + cbdata.header = seq->header; + cbdata.payload = seq->payload; + +/* find a matching event for the ELS/GS command */ +for (i =0 ; i <ARRAY_SIZE (ct_cmd_list); i++) { +if (ct_cmd_list[i].cmd == gscmd) { + evt = ct_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 ; +} + +/* +*@ingroup node_common +* @brief Dispatch a FCP command frame when the node is not ready. +* +* <h3 class="desc">Description</h3> +* A frame is dispatched to the \c node state machine. +* +* @param node Node that originated the frame. +* @param seq header/payload sequence buffers +* +* @return Returns 0 if frame processed and RX buffers cleaned +* up appropriately, -1 if frame not handled. +*/ + +int +efc_node_recv_fcp_cmd (struct efc_node_s *node,struct efc_hw_sequence_s *seq) +{ +struct efc_node_cb_s 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 ; +} + +/** +* @ingroup node_common +* @brief Stub handler for non-ABTS BLS frames +* +* <h3 class="desc">Description</h3> +* Log message and drop. Customer can plumb it to their back-end as needed +* +* @param node Node that originated the frame. +* @param seq header/payload sequence buffers +* +* @return Returns 0 +*/ + +int +efc_node_recv_bls_no_sit (struct efc_node_s *node, +struct efc_hw_sequence_s *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 ; +} + +/** +* @ingroup unsol +* @brief Process pending frames queued to the given node. +* +* <h3 class="desc">Description</h3> +* Frames that are queued for the \c node are dispatched and returned +* to the RQ. +* +* @param node Node of the queued frames that are to be dispatched. +* +* @return Returns 0 on success, or a negative error value on failure. +*/ + +int +efc_process_node_pending (struct efc_node_s *node) +{ +struct efc_lport *efc = node->efc; +struct efc_hw_sequence_s *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_s, + 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 ; +} + +/* +* @ingroup scsi_api_base +* @brief Notify that delete initiator is complete. +* +* @par Description +* Sent by the target-server to notify the base driver that the work +* started from efc_scsi_del_initiator() is now complete and that it +* is safe for the node to release the rest of its resources. +* +* @param node Pointer to the node. +* +* @return None. +*/ + +void +efc_scsi_del_initiator_complete (struct efc_lport *efc,struct efc_node_s *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); +} + +/* +* @ingroup scsi_api_base +* @brief Notify that delete target is complete. +* +* @par Description +* Sent by the initiator-client to notify the base driver that the +* work started from efc_scsi_del_target() is now complete and +* that it is safe for the node to release the rest of its resources. +* +* @param node Pointer to the node. +* +* @return None. +*/ +void +efc_scsi_del_target_complete (struct efc_lport *efc,struct efc_node_s *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_TGT_COMPLETE ,NULL ); +spin_unlock_irqrestore (&node->efc->lock, flags); +} + +void +efc_scsi_io_list_empty (struct efc_lport *efc,struct efc_node_s *node) +{ +unsigned long flags =0 ; + +spin_lock_irqsave (&node->efc->lock, flags); +efc_node_post_event (node,EFC_EVT_NODE_ACTIVE_IO_LIST_EMPTY ,NULL ); +spin_unlock_irqrestore (&node->efc->lock, flags); +} + +void efc_node_post_els_resp (struct efc_node_s *node, +enum efc_hw_node_els_event_e evt,void *arg) +{ +enum efc_sm_event_e sm_event =EFC_EVT_LAST ; +struct efc_lport *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_s *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 +196 -0
196 lines not on this page · raw message
Signature · 1 line
2.13.7