Bring in the Broadcom/Emulex Fibre Channel driver, ocs_fc(4).

The ocs_fc(4) driver supports the following hardware:

Emulex 16/8G FC GEN 5 HBAS
	LPe15004 FC Host Bus Adapters
	LPe160XX FC Host Bus Adapters

Emulex 32/16G FC GEN 6 HBAS
	LPe3100X FC Host Bus Adapters
	LPe3200X FC Host Bus Adapters

The driver supports target and initiator mode, and also supports FC-Tape.

Note that the driver only currently works on little endian platforms.  It
is only included in the module build for amd64 and i386, and in GENERIC
on amd64 only.

Submitted by:	Ram Kishore Vegesna <ram.vegesna@broadcom.com>
Reviewed by:	mav
MFC after:	5 days
Relnotes:	yes
Sponsored by:	Broadcom
Differential Revision:	https://reviews.freebsd.org/D11423
This commit is contained in:
Kenneth D. Merry 2018-03-30 15:28:25 +00:00
parent 9c9f60dbd6
commit ef270ab1b6
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=331766
55 changed files with 69390 additions and 0 deletions

View file

@ -402,6 +402,7 @@ MAN= aac.4 \
${_nvram2env.4} \
${_nxge.4} \
oce.4 \
ocs_fc.4\
ohci.4 \
orm.4 \
ow.4 \

194
share/man/man4/ocs_fc.4 Normal file
View file

@ -0,0 +1,194 @@
.\" Copyright (c) 2017 Broadcom. All rights reserved.
.\" The term "Broadcom" refers to Broadcom Limited and/or its subsidiaries.
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions are met:
.\"
.\" 1. Redistributions of source code must retain the above copyright notice,
.\" this list of conditions and the following disclaimer.
.\"
.\" 2. Redistributions in binary form must reproduce the above copyright notice,
.\" this list of conditions and the following disclaimer in the documentation
.\" and/or other materials provided with the distribution.
.\"
.\" 3. Neither the name of the copyright holder nor the names of its contributors
.\" may be used to endorse or promote products derived from this software
.\" without specific prior written permission.
.\"
.\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
.\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
.\" ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
.\" LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
.\" POSSIBILITY OF SUCH DAMAGE.
.\"
.\" $FreeBSD$
.\"
.Dd March 30, 2018
.Dt OCS_FC 4
.Os
.Sh NAME
.Nm ocs_fc
.Nd "Device driver for Emulex Fibre Channel Host Adapters"
.Sh SYNOPSIS
To compile this driver into the kernel, add this line to the
kernel configuration file:
.Bd -ragged -offset indent
.Cd "device ocs_fc"
.Ed
.Pp
To load the driver as a module at boot, add this line to
.Xr loader.conf 5 :
.Bd -literal -offset indent
ocs_fc_load="YES"
.Ed
.Sh DESCRIPTION
The
.Nm
driver provides access to Fibre Channel SCSI devices.
.Pp
The
.Nm
driver supports initiator and target modes.
Support is available for Arbitrated loops, Point-to-Point,
and Fabric connections.
FC-Tape is highly recommended for connections to tape drives that support
it.
FC-Tape includes four elements from the T-10 FCP-4 specification:
.Bl -bullet -offset indent
.It
Precise Delivery of Commands
.It
Confirmed Completion of FCP I/O Operations
.It
Retransmission of Unsuccessfully Transmitted IUs
.It
Task Retry Identification
.El
.Pp
Together these features allow for link level error recovery with tape
devices.
Without link level error recovery, an initiator cannot, for instance, tell whether a tape write
command that has timed out resulted in all, part, or none of the data going to
the tape drive.
FC-Tape is automatically enabled when both the controller and target support it.
.Sh HARDWARE
The
.Nm
driver supports these Fibre Channel adapters:
.Bl -tag -width xxxxxx -offset indent
.It Emulex 16/8G FC GEN 5 HBAS
.Bd -literal -offset indent
LPe15004 FC Host Bus Adapters
LPe160XX FC Host Bus Adapters
.Ed
.It Emulex 32/16G FC GEN 6 HBAS
.Bd -literal -offset indent
LPe3100X FC Host Bus Adapters
LPe3200X FC Host Bus Adapters
.Ed
.El
.Sh UPDATING FIRMWARE
Adapter firmware updates are persistent.
.Pp
Firmware can be updated by following these steps:
.Bl -enum
.It
Copy this code to a
.Pa Makefile :
.Bd -literal -offset indent
KMOD=ocsflash
FIRMWS=imagename.grp:ocsflash
\&.include <bsd.kmod.mk>
.Ed
.It
Replace
.Pa imagename
with the name of the GRP file.
.It
Copy the
.Pa Makefile
and GRP file to a local directory
.It
Execute
.Cm make
and copy the generated
.Pa ocsflash.ko
file to
.Pa /lib/modules
.It
.Cm sysctl dev.ocs_fc.<N>.fw_upgrade=ocsflash
.It
Check kernel messages regarding status of the operation
.It
Reboot the machine
.El
.Pp
.Sh BOOT OPTIONS
Options are controlled by setting values in
.Pa /boot/device.hints .
.Pp
They are:
.Bl -tag -width indent
.It Va hint.ocs_fc.N.initiator
Enable initiator functionality.
Default 1 (enabled), 0 to disable.
.It Va hint.ocs_fc.N.target
Enable target functionality.
Default 1 (enabled), 0 to disable.
.It Va hint.ocs_fc.N.topology
Topology: 0 for Auto, 1 for NPort only, 2 for Loop only.
.It Va hint.ocs_fc.N.speed
Link speed in megabits per second.
Possible values include:
0 Auto-speed negotiation (default), 4000 (4GFC), 8000 (8GFC), 16000 (16GFC).
.El
.Sh SYSCTL OPTIONS
.Bl -tag -width indent
.It Va dev.ocs_fc.N.port_state
Port state (read/write).
Valid values are
.Li online
and
.Li offline .
.It Va dev.ocs_fc.N.wwpn
World Wide Port Name (read/write).
.It Va dev.ocs_fc.N.wwnn
World Wide Node Name (read/write).
.It Va dev.ocs_fc.N.fwrev
Firmware revision (read-only).
.It Va dev.ocs_fc.N.sn
Adapter serial number (read-only).
.It Va dev.ocs_fc.N.configured_speed
Configured Port Speed (read/write).
Valid values are:
0 Auto-speed negotiation (default), 4000 (4GFC), 8000 (8GFC), 16000 (16GFC).
.It Va dev.ocs_fc.N.configured_topology
Configured Port Topology (read/write).
Valid values are:
0-Auto; 1-NPort; 2-Loop.
.It Va dev.ocs_fc.N.current_speed
Current Port Speed (read-only).
.It Va dev.ocs_fc.N.current_topology
Current Port Topology (read-only).
.El
.Sh SUPPORT
For general information and support,
go to the Broadcom website at:
.Pa http://www.broadcom.com/
or E-Mail at
.Pa ocs-driver-team.pdl@broadcom.com.
.Sh SEE ALSO
.Xr ifconfig 8
.Sh AUTHORS
.An -nosplit
The
.Nm
driver was written by
.An Broadcom.

View file

@ -141,6 +141,7 @@ device adw # Advansys wide SCSI adapters
device aic # Adaptec 15[012]x SCSI adapters, AIC-6[23]60.
device bt # Buslogic/Mylex MultiMaster SCSI adapters
device isci # Intel C600 SAS controller
device ocs_fc # Emulex FC adapters
# ATA/SCSI peripherals
device scbus # SCSI bus (required for ATA/SCSI)

View file

@ -2578,6 +2578,27 @@ dev/oce/oce_mbox.c optional oce pci
dev/oce/oce_queue.c optional oce pci
dev/oce/oce_sysctl.c optional oce pci
dev/oce/oce_util.c optional oce pci
dev/ocs_fc/ocs_pci.c optional ocs_fc pci
dev/ocs_fc/ocs_ioctl.c optional ocs_fc pci
dev/ocs_fc/ocs_os.c optional ocs_fc pci
dev/ocs_fc/ocs_utils.c optional ocs_fc pci
dev/ocs_fc/ocs_hw.c optional ocs_fc pci
dev/ocs_fc/ocs_hw_queues.c optional ocs_fc pci
dev/ocs_fc/sli4.c optional ocs_fc pci
dev/ocs_fc/ocs_sm.c optional ocs_fc pci
dev/ocs_fc/ocs_device.c optional ocs_fc pci
dev/ocs_fc/ocs_xport.c optional ocs_fc pci
dev/ocs_fc/ocs_domain.c optional ocs_fc pci
dev/ocs_fc/ocs_sport.c optional ocs_fc pci
dev/ocs_fc/ocs_els.c optional ocs_fc pci
dev/ocs_fc/ocs_fabric.c optional ocs_fc pci
dev/ocs_fc/ocs_io.c optional ocs_fc pci
dev/ocs_fc/ocs_node.c optional ocs_fc pci
dev/ocs_fc/ocs_scsi.c optional ocs_fc pci
dev/ocs_fc/ocs_unsol.c optional ocs_fc pci
dev/ocs_fc/ocs_ddump.c optional ocs_fc pci
dev/ocs_fc/ocs_mgmt.c optional ocs_fc pci
dev/ocs_fc/ocs_cam.c optional ocs_fc pci
dev/ofw/ofw_bus_if.m optional fdt
dev/ofw/ofw_bus_subr.c optional fdt
dev/ofw/ofw_cpu.c optional fdt

261
sys/dev/ocs_fc/ocs.h Normal file
View file

@ -0,0 +1,261 @@
/*-
* Copyright (c) 2017 Broadcom. All rights reserved.
* The term "Broadcom" refers to Broadcom Limited and/or its subsidiaries.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* $FreeBSD$
*/
/**
* @file
* OCS bsd driver common include file
*/
#if !defined(__OCS_H__)
#define __OCS_H__
#include "ocs_os.h"
#include "ocs_utils.h"
#include "ocs_hw.h"
#include "ocs_scsi.h"
#include "ocs_io.h"
#include "version.h"
#define DRV_NAME "ocs_fc"
#define DRV_VERSION \
STR_BE_MAJOR "." STR_BE_MINOR "." STR_BE_BUILD "." STR_BE_BRANCH
/**
* @brief Interrupt context
*/
typedef struct ocs_intr_ctx_s {
uint32_t vec; /** Zero based interrupt vector */
void *softc; /** software context for interrupt */
char name[64]; /** label for this context */
} ocs_intr_ctx_t;
typedef struct ocs_fcport_s {
struct cam_sim *sim;
struct cam_path *path;
uint32_t role;
ocs_tgt_resource_t targ_rsrc_wildcard;
ocs_tgt_resource_t targ_rsrc[OCS_MAX_LUN];
ocs_vport_spec_t *vport;
} ocs_fcport;
#define FCPORT(ocs, chan) (&((ocs_fcport *)(ocs)->fcports)[(chan)])
/**
* @brief Driver's context
*/
struct ocs_softc {
device_t dev;
struct cdev *cdev;
ocs_pci_reg_t reg[PCI_MAX_BAR];
uint32_t instance_index;
const char *desc;
uint32_t irqid;
struct resource *irq;
void *tag;
ocs_intr_ctx_t intr_ctx;
uint32_t n_vec;
bus_dma_tag_t dmat; /** Parent DMA tag */
bus_dma_tag_t buf_dmat;/** IO buffer DMA tag */
char display_name[OCS_DISPLAY_NAME_LENGTH];
uint16_t pci_vendor;
uint16_t pci_device;
uint16_t pci_subsystem_vendor;
uint16_t pci_subsystem_device;
char businfo[16];
const char *driver_version;
const char *fw_version;
const char *model;
ocs_hw_t hw;
ocs_rlock_t lock; /**< device wide lock */
ocs_xport_e ocs_xport;
ocs_xport_t *xport; /**< pointer to transport object */
ocs_domain_t *domain;
ocs_list_t domain_list;
uint32_t domain_instance_count;
void (*domain_list_empty_cb)(ocs_t *ocs, void *arg);
void *domain_list_empty_cb_arg;
uint8_t enable_ini;
uint8_t enable_tgt;
uint8_t fc_type;
int ctrlmask;
uint8_t explicit_buffer_list;
uint8_t external_loopback;
uint8_t skip_hw_teardown;
int speed;
int topology;
int ethernet_license;
int num_scsi_ios;
uint8_t enable_hlm;
uint32_t hlm_group_size;
uint32_t max_isr_time_msec; /*>> Maximum ISR time */
uint32_t auto_xfer_rdy_size; /*>> Max sized write to use auto xfer rdy*/
uint8_t esoc;
int logmask;
char *hw_war_version;
uint32_t num_vports;
uint32_t target_io_timer_sec;
uint32_t hw_bounce;
uint8_t rq_threads;
uint8_t rq_selection_policy;
uint8_t rr_quanta;
char *filter_def;
uint32_t max_remote_nodes;
/*
* tgt_rscn_delay - delay in kicking off RSCN processing
* (nameserver queries) after receiving an RSCN on the target.
* This prevents thrashing of nameserver requests due to a huge burst of
* RSCNs received in a short period of time.
* Note: this is only valid when target RSCN handling is enabled -- see
* ctrlmask.
*/
time_t tgt_rscn_delay_msec; /*>> minimum target RSCN delay */
/*
* tgt_rscn_period - determines maximum frequency when processing
* back-to-back RSCNs; e.g. if this value is 30, there will never be
* any more than 1 RSCN handling per 30s window. This prevents
* initiators on a faulty link generating many RSCN from causing the
* target to continually query the nameserver.
* Note: This is only valid when target RSCN handling is enabled
*/
time_t tgt_rscn_period_msec; /*>> minimum target RSCN period */
uint32_t enable_task_set_full;
uint32_t io_in_use;
uint32_t io_high_watermark; /**< used to send task set full */
struct mtx sim_lock;
uint32_t config_tgt:1, /**< Configured to support target mode */
config_ini:1; /**< Configured to support initiator mode */
uint32_t nodedb_mask; /**< Node debugging mask */
char modeldesc[64];
char serialnum[64];
char fwrev[64];
char sli_intf[9];
ocs_ramlog_t *ramlog;
ocs_textbuf_t ddump_saved;
ocs_mgmt_functions_t *mgmt_functions;
ocs_mgmt_functions_t *tgt_mgmt_functions;
ocs_mgmt_functions_t *ini_mgmt_functions;
ocs_err_injection_e err_injection;
uint32_t cmd_err_inject;
time_t delay_value_msec;
bool attached;
struct mtx dbg_lock;
struct cam_devq *devq;
ocs_fcport *fcports;
void* tgt_ocs;
};
static inline void
ocs_device_lock_init(ocs_t *ocs)
{
ocs_rlock_init(ocs, &ocs->lock, "ocsdevicelock");
}
static inline int32_t
ocs_device_lock_try(ocs_t *ocs)
{
return ocs_rlock_try(&ocs->lock);
}
static inline void
ocs_device_lock(ocs_t *ocs)
{
ocs_rlock_acquire(&ocs->lock);
}
static inline void
ocs_device_unlock(ocs_t *ocs)
{
ocs_rlock_release(&ocs->lock);
}
static inline void
ocs_device_lock_free(ocs_t *ocs)
{
ocs_rlock_free(&ocs->lock);
}
extern int32_t ocs_device_detach(ocs_t *ocs);
extern int32_t ocs_device_attach(ocs_t *ocs);
#define ocs_is_initiator_enabled() (ocs->enable_ini)
#define ocs_is_target_enabled() (ocs->enable_tgt)
#include "ocs_xport.h"
#include "ocs_domain.h"
#include "ocs_sport.h"
#include "ocs_node.h"
#include "ocs_unsol.h"
#include "ocs_scsi.h"
#include "ocs_ioctl.h"
static inline ocs_io_t *
ocs_io_alloc(ocs_t *ocs)
{
return ocs_io_pool_io_alloc(ocs->xport->io_pool);
}
static inline void
ocs_io_free(ocs_t *ocs, ocs_io_t *io)
{
ocs_io_pool_io_free(ocs->xport->io_pool, io);
}
#endif /* __OCS_H__ */

2640
sys/dev/ocs_fc/ocs_cam.c Normal file

File diff suppressed because it is too large Load diff

122
sys/dev/ocs_fc/ocs_cam.h Normal file
View file

@ -0,0 +1,122 @@
/*-
* Copyright (c) 2017 Broadcom. All rights reserved.
* The term "Broadcom" refers to Broadcom Limited and/or its subsidiaries.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* $FreeBSD$
*/
#ifndef __OCS_CAM_H__
#define __OCS_CAM_H__
#include <cam/cam.h>
#include <cam/cam_sim.h>
#include <cam/cam_ccb.h>
#include <cam/cam_periph.h>
#include <cam/cam_xpt_sim.h>
#include <cam/scsi/scsi_message.h>
#define ccb_ocs_ptr spriv_ptr0
#define ccb_io_ptr spriv_ptr1
typedef STAILQ_HEAD(ocs_hdr_list_s, ccb_hdr) ocs_hdr_list_t;
typedef struct ocs_tgt_resource_s {
ocs_hdr_list_t atio;
ocs_hdr_list_t inot;
uint8_t enabled;
lun_id_t lun;
} ocs_tgt_resource_t;
/* Common SCSI Domain structure declarations */
typedef struct {
} ocs_scsi_tgt_domain_t;
typedef struct {
} ocs_scsi_ini_domain_t;
/* Common SCSI SLI port structure declarations */
typedef struct {
} ocs_scsi_tgt_sport_t;
typedef struct {
} ocs_scsi_ini_sport_t;
/* Common IO structure declarations */
typedef enum {
OCS_CAM_IO_FREE, /* IO unused (SIM) */
OCS_CAM_IO_COMMAND, /* ATIO returned to BE (CTL) */
OCS_CAM_IO_DATA, /* data phase (SIM) */
OCS_CAM_IO_DATA_DONE, /* CTIO returned to BE (CTL) */
OCS_CAM_IO_RESP, /* send response (SIM) */
OCS_CAM_IO_MAX
} ocs_cam_io_state_t;
typedef struct {
bus_dmamap_t dmap;
uint64_t lun; /* target_lun */
void *app; /** application specific pointer */
ocs_cam_io_state_t state;
bool sendresp;
uint32_t flags;
#define OCS_CAM_IO_F_DMAPPED BIT(0) /* associated buffer bus_dmamap'd */
#define OCS_CAM_IO_F_ABORT_RECV BIT(1) /* received ABORT TASK */
#define OCS_CAM_IO_F_ABORT_DEV BIT(2) /* abort WQE pending */
#define OCS_CAM_IO_F_ABORT_TMF BIT(3) /* TMF response sent */
#define OCS_CAM_IO_F_ABORT_NOTIFY BIT(4) /* XPT_NOTIFY sent to CTL */
#define OCS_CAM_IO_F_ABORT_CAM BIT(5) /* received ABORT or CTIO from CAM */
} ocs_scsi_tgt_io_t;
typedef struct {
} ocs_scsi_ini_io_t;
struct ocs_lun_crn {
uint64_t lun; /* target_lun */
uint8_t crnseed; /* next command reference number */
};
/* Common NODE structure declarations */
typedef struct {
struct ocs_lun_crn *lun_crn[OCS_MAX_LUN];
} ocs_scsi_ini_node_t;
typedef struct {
uint32_t busy_sent;
} ocs_scsi_tgt_node_t;
extern int32_t ocs_cam_attach(ocs_t *ocs);
extern int32_t ocs_cam_detach(ocs_t *ocs);
#endif /* __OCS_CAM_H__ */

424
sys/dev/ocs_fc/ocs_common.h Normal file
View file

@ -0,0 +1,424 @@
/*-
* Copyright (c) 2017 Broadcom. All rights reserved.
* The term "Broadcom" refers to Broadcom Limited and/or its subsidiaries.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* $FreeBSD$
*/
/**
* @file
* Contains declarations shared between the alex layer and HW/SLI4
*/
#if !defined(__OCS_COMMON_H__)
#define __OCS_COMMON_H__
#include "ocs_sm.h"
#include "ocs_utils.h"
#define OCS_CTRLMASK_XPORT_DISABLE_AUTORSP_TSEND (1U << 0)
#define OCS_CTRLMASK_XPORT_DISABLE_AUTORSP_TRECEIVE (1U << 1)
#define OCS_CTRLMASK_XPORT_ENABLE_TARGET_RSCN (1U << 3)
#define OCS_CTRLMASK_TGT_ALWAYS_VERIFY_DIF (1U << 4)
#define OCS_CTRLMASK_TGT_SET_DIF_REF_TAG_CRC (1U << 5)
#define OCS_CTRLMASK_TEST_CHAINED_SGLS (1U << 6)
#define OCS_CTRLMASK_ISCSI_ISNS_ENABLE (1U << 7)
#define OCS_CTRLMASK_ENABLE_FABRIC_EMULATION (1U << 8)
#define OCS_CTRLMASK_INHIBIT_INITIATOR (1U << 9)
#define OCS_CTRLMASK_CRASH_RESET (1U << 10)
#define enable_target_rscn(ocs) \
((ocs->ctrlmask & OCS_CTRLMASK_XPORT_ENABLE_TARGET_RSCN) != 0)
/* Used for error injection testing. */
typedef enum {
NO_ERR_INJECT = 0,
INJECT_DROP_CMD,
INJECT_FREE_DROPPED,
INJECT_DROP_DATA,
INJECT_DROP_RESP,
INJECT_DELAY_CMD,
} ocs_err_injection_e;
#define MAX_OCS_DEVICES 64
typedef enum {OCS_XPORT_FC, OCS_XPORT_ISCSI} ocs_xport_e;
#define OCS_SERVICE_PARMS_LENGTH 0x74
#define OCS_DISPLAY_NAME_LENGTH 32
#define OCS_DISPLAY_BUS_INFO_LENGTH 16
#define OCS_WWN_LENGTH 32
typedef struct ocs_hw_s ocs_hw_t;
typedef struct ocs_domain_s ocs_domain_t;
typedef struct ocs_sli_port_s ocs_sli_port_t;
typedef struct ocs_sli_port_s ocs_sport_t;
typedef struct ocs_remote_node_s ocs_remote_node_t;
typedef struct ocs_remote_node_group_s ocs_remote_node_group_t;
typedef struct ocs_node_s ocs_node_t;
typedef struct ocs_io_s ocs_io_t;
typedef struct ocs_xport_s ocs_xport_t;
typedef struct ocs_node_cb_s ocs_node_cb_t;
typedef struct ocs_ns_s ocs_ns_t;
/* Node group data structure */
typedef struct ocs_node_group_dir_s ocs_node_group_dir_t;
#include "ocs_cam.h"
/*--------------------------------------------------
* Shared HW/SLI objects
*
* Several objects used by the HW/SLI layers are communal; part of the
* object is for the sole use of the lower layers, but implementations
* are free to add their own fields if desired.
*/
/**
* @brief Description of discovered Fabric Domain
*
* @note Not all fields are valid for all mediums (FC/ethernet).
*/
typedef struct ocs_domain_record_s {
uint32_t index; /**< FCF table index (used in REG_FCFI) */
uint32_t priority; /**< FCF reported priority */
uint8_t address[6]; /**< Switch MAC/FC address */
uint8_t wwn[8]; /**< Switch WWN */
union {
uint8_t vlan[512]; /**< bitmap of valid VLAN IDs */
uint8_t loop[128]; /**< FC-AL position map */
} map;
uint32_t speed; /**< link speed */
uint32_t fc_id; /**< our ports fc_id */
uint32_t is_fc:1, /**< Connection medium is native FC */
is_ethernet:1, /**< Connection medium is ethernet (FCoE) */
is_loop:1, /**< Topology is FC-AL */
is_nport:1, /**< Topology is N-PORT */
:28;
} ocs_domain_record_t;
/**
* @brief Node group directory entry
*/
struct ocs_node_group_dir_s {
uint32_t instance_index; /*<< instance index */
ocs_sport_t *sport; /*<< pointer to sport */
uint8_t service_params[OCS_SERVICE_PARMS_LENGTH]; /**< Login parameters */
ocs_list_link_t link; /**< linked list link */
ocs_list_t node_group_list; /**< linked list of node groups */
uint32_t node_group_list_count; /**< current number of elements on the node group list */
uint32_t next_idx; /*<< index of the next node group in list */
};
typedef enum {
OCS_SPORT_TOPOLOGY_UNKNOWN=0,
OCS_SPORT_TOPOLOGY_FABRIC,
OCS_SPORT_TOPOLOGY_P2P,
OCS_SPORT_TOPOLOGY_LOOP,
} ocs_sport_topology_e;
/**
* @brief SLI Port object
*
* The SLI Port object represents the connection between the driver and the
* FC/FCoE domain. In some topologies / hardware, it is possible to have
* multiple connections to the domain via different WWN. Each would require
* a separate SLI port object.
*/
struct ocs_sli_port_s {
ocs_t *ocs; /**< pointer to ocs */
uint32_t tgt_id; /**< target id */
uint32_t index; /**< ??? */
uint32_t instance_index;
char display_name[OCS_DISPLAY_NAME_LENGTH]; /**< sport display name */
ocs_domain_t *domain; /**< current fabric domain */
uint32_t is_vport:1; /**< this SPORT is a virtual port */
uint64_t wwpn; /**< WWPN from HW (host endian) */
uint64_t wwnn; /**< WWNN from HW (host endian) */
ocs_list_t node_list; /**< list of nodes */
ocs_scsi_ini_sport_t ini_sport; /**< initiator backend private sport data */
ocs_scsi_tgt_sport_t tgt_sport; /**< target backend private sport data */
void *tgt_data; /**< target backend private pointer */
void *ini_data; /**< initiator backend private pointer */
ocs_mgmt_functions_t *mgmt_functions;
/*
* Members private to HW/SLI
*/
ocs_sm_ctx_t ctx; /**< state machine context */
ocs_hw_t *hw; /**< pointer to HW */
uint32_t indicator; /**< VPI */
uint32_t fc_id; /**< FC address */
ocs_dma_t dma; /**< memory for Service Parameters */
uint8_t wwnn_str[OCS_WWN_LENGTH]; /**< WWN (ASCII) */
uint64_t sli_wwpn; /**< WWPN (wire endian) */
uint64_t sli_wwnn; /**< WWNN (wire endian) */
uint32_t sm_free_req_pending:1; /**< Free request received while waiting for attach response */
/*
* Implementation specific fields allowed here
*/
ocs_sm_ctx_t sm; /**< sport context state machine */
sparse_vector_t lookup; /**< fc_id to node lookup object */
ocs_list_link_t link;
uint32_t enable_ini:1, /**< SCSI initiator enabled for this node */
enable_tgt:1, /**< SCSI target enabled for this node */
enable_rscn:1, /**< This SPORT will be expecting RSCN */
shutting_down:1, /**< sport in process of shutting down */
p2p_winner:1; /**< TRUE if we're the point-to-point winner */
ocs_sport_topology_e topology; /**< topology: fabric/p2p/unknown */
uint8_t service_params[OCS_SERVICE_PARMS_LENGTH]; /**< Login parameters */
uint32_t p2p_remote_port_id; /**< Remote node's port id for p2p */
uint32_t p2p_port_id; /**< our port's id */
/* List of remote node group directory entries (used by high login mode) */
ocs_lock_t node_group_lock;
uint32_t node_group_dir_next_instance; /**< HLM next node group directory instance value */
uint32_t node_group_next_instance; /**< HLM next node group instance value */
ocs_list_t node_group_dir_list;
};
/**
* @brief Fibre Channel domain object
*
* This object is a container for the various SLI components needed
* to connect to the domain of a FC or FCoE switch
*/
struct ocs_domain_s {
ocs_t *ocs; /**< pointer back to ocs */
uint32_t instance_index; /**< unique instance index value */
char display_name[OCS_DISPLAY_NAME_LENGTH]; /**< Node display name */
ocs_list_t sport_list; /**< linked list of SLI ports */
ocs_scsi_ini_domain_t ini_domain; /**< initiator backend private domain data */
ocs_scsi_tgt_domain_t tgt_domain; /**< target backend private domain data */
ocs_mgmt_functions_t *mgmt_functions;
/* Declarations private to HW/SLI */
ocs_hw_t *hw; /**< pointer to HW */
ocs_sm_ctx_t sm; /**< state machine context */
uint32_t fcf; /**< FC Forwarder table index */
uint32_t fcf_indicator; /**< FCFI */
uint32_t vlan_id; /**< VLAN tag for this domain */
uint32_t indicator; /**< VFI */
ocs_dma_t dma; /**< memory for Service Parameters */
uint32_t req_rediscover_fcf:1; /**< TRUE if fcf rediscover is needed (in response
* to Vlink Clear async event */
/* Declarations private to FC transport */
uint64_t fcf_wwn; /**< WWN for FCF/switch */
ocs_list_link_t link;
ocs_sm_ctx_t drvsm; /**< driver domain sm context */
uint32_t attached:1, /**< set true after attach completes */
is_fc:1, /**< is FC */
is_loop:1, /**< is loop topology */
is_nlport:1, /**< is public loop */
domain_found_pending:1, /**< A domain found is pending, drec is updated */
req_domain_free:1, /**< True if domain object should be free'd */
req_accept_frames:1, /**< set in domain state machine to enable frames */
domain_notify_pend:1; /** Set in domain SM to avoid duplicate node event post */
ocs_domain_record_t pending_drec; /**< Pending drec if a domain found is pending */
uint8_t service_params[OCS_SERVICE_PARMS_LENGTH]; /**< any sports service parameters */
uint8_t flogi_service_params[OCS_SERVICE_PARMS_LENGTH]; /**< Fabric/P2p service parameters from FLOGI */
uint8_t femul_enable; /**< TRUE if Fabric Emulation mode is enabled */
/* Declarations shared with back-ends */
sparse_vector_t lookup; /**< d_id to node lookup object */
ocs_lock_t lookup_lock;
ocs_sli_port_t *sport; /**< Pointer to first (physical) SLI port (also at the head of sport_list) */
uint32_t sport_instance_count; /**< count of sport instances */
/* Fabric Emulation */
ocs_bitmap_t *portid_pool;
ocs_ns_t *ocs_ns; /*>> Directory(Name) services data */
};
/**
* @brief Remote Node object
*
* This object represents a connection between the SLI port and another
* Nx_Port on the fabric. Note this can be either a well known port such
* as a F_Port (i.e. ff:ff:fe) or another N_Port.
*/
struct ocs_remote_node_s {
/*
* Members private to HW/SLI
*/
uint32_t indicator; /**< RPI */
uint32_t index;
uint32_t fc_id; /**< FC address */
uint32_t attached:1, /**< true if attached */
node_group:1, /**< true if in node group */
free_group:1; /**< true if the node group should be free'd */
ocs_sli_port_t *sport; /**< associated SLI port */
/*
* Implementation specific fields allowed here
*/
void *node; /**< associated node */
};
struct ocs_remote_node_group_s {
/*
* Members private to HW/SLI
*/
uint32_t indicator; /**< RPI */
uint32_t index;
/*
* Implementation specific fields allowed here
*/
uint32_t instance_index; /*<< instance index */
ocs_node_group_dir_t *node_group_dir; /*<< pointer to the node group directory */
ocs_list_link_t link; /*<< linked list link */
};
typedef enum {
OCS_NODE_SHUTDOWN_DEFAULT = 0,
OCS_NODE_SHUTDOWN_EXPLICIT_LOGO,
OCS_NODE_SHUTDOWN_IMPLICIT_LOGO,
} ocs_node_shutd_rsn_e;
typedef enum {
OCS_NODE_SEND_LS_ACC_NONE = 0,
OCS_NODE_SEND_LS_ACC_PLOGI,
OCS_NODE_SEND_LS_ACC_PRLI,
} ocs_node_send_ls_acc_e;
/**
* @brief FC Node object
*
*/
struct ocs_node_s {
ocs_t *ocs; /**< pointer back to ocs structure */
uint32_t instance_index; /**< unique instance index value */
char display_name[OCS_DISPLAY_NAME_LENGTH]; /**< Node display name */
ocs_sport_t *sport;
uint32_t hold_frames:1; /**< hold incoming frames if true */
ocs_rlock_t lock; /**< node wide lock */
ocs_lock_t active_ios_lock; /**< active SCSI and XPORT I/O's for this node */
ocs_list_t active_ios; /**< active I/O's for this node */
uint32_t max_wr_xfer_size; /**< Max write IO size per phase for the transport */
ocs_scsi_ini_node_t ini_node; /**< backend initiator private node data */
ocs_scsi_tgt_node_t tgt_node; /**< backend target private node data */
ocs_mgmt_functions_t *mgmt_functions;
/* Declarations private to HW/SLI */
ocs_remote_node_t rnode; /**< Remote node */
/* Declarations private to FC transport */
ocs_sm_ctx_t sm; /**< state machine context */
uint32_t evtdepth; /**< current event posting nesting depth */
uint32_t req_free:1, /**< this node is to be free'd */
attached:1, /**< node is attached (REGLOGIN complete) */
fcp_enabled:1, /**< node is enabled to handle FCP */
rscn_pending:1, /**< for name server node RSCN is pending */
send_plogi:1, /**< if initiator, send PLOGI at node initialization */
send_plogi_acc:1,/**< send PLOGI accept, upon completion of node attach */
io_alloc_enabled:1, /**< TRUE if ocs_scsi_io_alloc() and ocs_els_io_alloc() are enabled */
sent_prli:1; /**< if initiator, sent prli. */
ocs_node_send_ls_acc_e send_ls_acc; /**< type of LS acc to send */
ocs_io_t *ls_acc_io; /**< SCSI IO for LS acc */
uint32_t ls_acc_oxid; /**< OX_ID for pending accept */
uint32_t ls_acc_did; /**< D_ID for pending accept */
ocs_node_shutd_rsn_e shutdown_reason;/**< reason for node shutdown */
ocs_dma_t sparm_dma_buf; /**< service parameters buffer */
uint8_t service_params[OCS_SERVICE_PARMS_LENGTH]; /**< plogi/acc frame from remote device */
ocs_lock_t pend_frames_lock; /**< lock for inbound pending frames list */
ocs_list_t pend_frames; /**< inbound pending frames list */
uint32_t pend_frames_processed; /**< count of frames processed in hold frames interval */
uint32_t ox_id_in_use; /**< used to verify one at a time us of ox_id */
uint32_t els_retries_remaining; /**< for ELS, number of retries remaining */
uint32_t els_req_cnt; /**< number of outstanding ELS requests */
uint32_t els_cmpl_cnt; /**< number of outstanding ELS completions */
uint32_t abort_cnt; /**< Abort counter for debugging purpose */
char current_state_name[OCS_DISPLAY_NAME_LENGTH]; /**< current node state */
char prev_state_name[OCS_DISPLAY_NAME_LENGTH]; /**< previous node state */
ocs_sm_event_t current_evt; /**< current event */
ocs_sm_event_t prev_evt; /**< current event */
uint32_t targ:1, /**< node is target capable */
init:1, /**< node is initiator capable */
refound:1, /**< Handle node refound case when node is being deleted */
fcp2device:1, /* FCP2 device */
reserved:4,
fc_type:8;
ocs_list_t els_io_pend_list; /**< list of pending (not yet processed) ELS IOs */
ocs_list_t els_io_active_list; /**< list of active (processed) ELS IOs */
ocs_sm_function_t nodedb_state; /**< Node debugging, saved state */
ocs_timer_t gidpt_delay_timer; /**< GIDPT delay timer */
time_t time_last_gidpt_msec; /**< Start time of last target RSCN GIDPT */
/* WWN */
char wwnn[OCS_WWN_LENGTH]; /**< remote port WWN (uses iSCSI naming) */
char wwpn[OCS_WWN_LENGTH]; /**< remote port WWN (uses iSCSI naming) */
/* Statistics */
uint32_t chained_io_count; /**< count of IOs with chained SGL's */
ocs_list_link_t link; /**< node list link */
ocs_remote_node_group_t *node_group; /**< pointer to node group (if HLM enabled) */
};
/**
* @brief Virtual port specification
*
* Collection of the information required to restore a virtual port across
* link events
*/
typedef struct ocs_vport_spec_s ocs_vport_spec_t;
struct ocs_vport_spec_s {
uint32_t domain_instance; /*>> instance index of this domain for the sport */
uint64_t wwnn; /*>> node name */
uint64_t wwpn; /*>> port name */
uint32_t fc_id; /*>> port id */
uint32_t enable_tgt:1, /*>> port is a target */
enable_ini:1; /*>> port is an initiator */
ocs_list_link_t link; /*>> link */
void *tgt_data; /**< target backend pointer */
void *ini_data; /**< initiator backend pointer */
ocs_sport_t *sport; /**< Used to match record after attaching for update */
};
#endif /* __OCS_COMMON_H__*/

881
sys/dev/ocs_fc/ocs_ddump.c Normal file
View file

@ -0,0 +1,881 @@
/*-
* Copyright (c) 2017 Broadcom. All rights reserved.
* The term "Broadcom" refers to Broadcom Limited and/or its subsidiaries.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* $FreeBSD$
*/
/**
* @file
* generate FC ddump
*
*/
#include "ocs.h"
#include "ocs_ddump.h"
#define DEFAULT_SAVED_DUMP_SIZE (4*1024*1024)
void hw_queue_ddump(ocs_textbuf_t *textbuf, ocs_hw_t *hw);
/**
* @brief Generate sli4 queue ddump
*
* Generates sli4 queue ddump data
*
* @param textbuf pointer to text buffer
* @param name name of SLI4 queue
* @param hw pointer HW context
* @param q pointer to SLI4 queues array
* @param q_count count of SLI4 queues
* @param qentries number of SLI4 queue entries to dump
*
* @return none
*/
static void
ocs_ddump_sli4_queue(ocs_textbuf_t *textbuf, const char *name, ocs_hw_t *hw, sli4_queue_t *q, uint32_t q_count, uint32_t qentries)
{
uint32_t i;
for (i = 0; i < q_count; i ++, q ++) {
ocs_ddump_section(textbuf, name, i);
ocs_ddump_value(textbuf, "index", "%d", q->index);
ocs_ddump_value(textbuf, "size", "%d", q->size);
ocs_ddump_value(textbuf, "length", "%d", q->length);
ocs_ddump_value(textbuf, "n_posted", "%d", q->n_posted);
ocs_ddump_value(textbuf, "id", "%d", q->id);
ocs_ddump_value(textbuf, "type", "%d", q->type);
ocs_ddump_value(textbuf, "proc_limit", "%d", q->proc_limit);
ocs_ddump_value(textbuf, "posted_limit", "%d", q->posted_limit);
ocs_ddump_value(textbuf, "max_num_processed", "%d", q->max_num_processed);
ocs_ddump_value(textbuf, "max_process_time", "%ld", (unsigned long)q->max_process_time);
ocs_ddump_value(textbuf, "virt_addr", "%p", q->dma.virt);
ocs_ddump_value(textbuf, "phys_addr", "%lx", (unsigned long)q->dma.phys);
/* queue-specific information */
switch (q->type) {
case SLI_QTYPE_MQ:
ocs_ddump_value(textbuf, "r_idx", "%d", q->u.r_idx);
break;
case SLI_QTYPE_CQ:
ocs_ddump_value(textbuf, "is_mq", "%d", q->u.flag.is_mq);
break;
case SLI_QTYPE_WQ:
break;
case SLI_QTYPE_RQ: {
uint32_t i;
uint32_t j;
uint32_t rqe_count = 0;
hw_rq_t *rq;
ocs_ddump_value(textbuf, "is_hdr", "%d", q->u.flag.is_hdr);
ocs_ddump_value(textbuf, "rq_batch", "%d", q->u.flag.rq_batch);
/* loop through RQ tracker to see how many RQEs were produced */
for (i = 0; i < hw->hw_rq_count; i++) {
rq = hw->hw_rq[i];
for (j = 0; j < rq->entry_count; j++) {
if (rq->rq_tracker[j] != NULL) {
rqe_count++;
}
}
}
ocs_ddump_value(textbuf, "rqes_produced", "%d", rqe_count);
break;
}
}
ocs_ddump_queue_entries(textbuf, q->dma.virt, q->size, q->length,
((q->type == SLI_QTYPE_MQ) ? q->u.r_idx : q->index),
qentries);
ocs_ddump_endsection(textbuf, name, i);
}
}
/**
* @brief Generate SLI4 ddump
*
* Generates sli4 ddump
*
* @param textbuf pointer to text buffer
* @param sli4 pointer SLI context
* @param qtype SLI4 queue type
*
* @return none
*/
static void
ocs_ddump_sli_q_fields(ocs_textbuf_t *textbuf, sli4_t *sli4, sli4_qtype_e qtype)
{
char * q_desc;
switch(qtype) {
case SLI_QTYPE_EQ: q_desc = "EQ"; break;
case SLI_QTYPE_CQ: q_desc = "CQ"; break;
case SLI_QTYPE_MQ: q_desc = "MQ"; break;
case SLI_QTYPE_WQ: q_desc = "WQ"; break;
case SLI_QTYPE_RQ: q_desc = "RQ"; break;
default: q_desc = "unknown"; break;
}
ocs_ddump_section(textbuf, q_desc, qtype);
ocs_ddump_value(textbuf, "max_qcount", "%d", sli4->config.max_qcount[qtype]);
ocs_ddump_value(textbuf, "max_qentries", "%d", sli4->config.max_qentries[qtype]);
ocs_ddump_value(textbuf, "qpage_count", "%d", sli4->config.qpage_count[qtype]);
ocs_ddump_endsection(textbuf, q_desc, qtype);
}
/**
* @brief Generate SLI4 ddump
*
* Generates sli4 ddump
*
* @param textbuf pointer to text buffer
* @param sli4 pointer SLI context
*
* @return none
*/
static void
ocs_ddump_sli(ocs_textbuf_t *textbuf, sli4_t *sli4)
{
sli4_sgl_chaining_params_t *cparams = &sli4->config.sgl_chaining_params;
const char *p;
ocs_ddump_section(textbuf, "sli4", 0);
ocs_ddump_value(textbuf, "sli_rev", "%d", sli4->sli_rev);
ocs_ddump_value(textbuf, "sli_family", "%d", sli4->sli_family);
ocs_ddump_value(textbuf, "if_type", "%d", sli4->if_type);
switch(sli4->asic_type) {
case SLI4_ASIC_TYPE_BE3: p = "BE3"; break;
case SLI4_ASIC_TYPE_SKYHAWK: p = "Skyhawk"; break;
case SLI4_ASIC_TYPE_LANCER: p = "Lancer"; break;
case SLI4_ASIC_TYPE_LANCERG6: p = "LancerG6"; break;
default: p = "unknown"; break;
}
ocs_ddump_value(textbuf, "asic_type", "%s", p);
switch(sli4->asic_rev) {
case SLI4_ASIC_REV_FPGA: p = "fpga"; break;
case SLI4_ASIC_REV_A0: p = "A0"; break;
case SLI4_ASIC_REV_A1: p = "A1"; break;
case SLI4_ASIC_REV_A2: p = "A2"; break;
case SLI4_ASIC_REV_A3: p = "A3"; break;
case SLI4_ASIC_REV_B0: p = "B0"; break;
case SLI4_ASIC_REV_C0: p = "C0"; break;
case SLI4_ASIC_REV_D0: p = "D0"; break;
default: p = "unknown"; break;
}
ocs_ddump_value(textbuf, "asic_rev", "%s", p);
ocs_ddump_value(textbuf, "e_d_tov", "%d", sli4->config.e_d_tov);
ocs_ddump_value(textbuf, "r_a_tov", "%d", sli4->config.r_a_tov);
ocs_ddump_value(textbuf, "link_module_type", "%d", sli4->config.link_module_type);
ocs_ddump_value(textbuf, "rq_batch", "%d", sli4->config.rq_batch);
ocs_ddump_value(textbuf, "topology", "%d", sli4->config.topology);
ocs_ddump_value(textbuf, "wwpn", "%02x%02x%02x%02x%02x%02x%02x%02x",
sli4->config.wwpn[0],
sli4->config.wwpn[1],
sli4->config.wwpn[2],
sli4->config.wwpn[3],
sli4->config.wwpn[4],
sli4->config.wwpn[5],
sli4->config.wwpn[6],
sli4->config.wwpn[7]);
ocs_ddump_value(textbuf, "wwnn", "%02x%02x%02x%02x%02x%02x%02x%02x",
sli4->config.wwnn[0],
sli4->config.wwnn[1],
sli4->config.wwnn[2],
sli4->config.wwnn[3],
sli4->config.wwnn[4],
sli4->config.wwnn[5],
sli4->config.wwnn[6],
sli4->config.wwnn[7]);
ocs_ddump_value(textbuf, "fw_rev0", "%d", sli4->config.fw_rev[0]);
ocs_ddump_value(textbuf, "fw_rev1", "%d", sli4->config.fw_rev[1]);
ocs_ddump_value(textbuf, "fw_name0", "%s", (char*)sli4->config.fw_name[0]);
ocs_ddump_value(textbuf, "fw_name1", "%s", (char*)sli4->config.fw_name[1]);
ocs_ddump_value(textbuf, "hw_rev0", "%x", sli4->config.hw_rev[0]);
ocs_ddump_value(textbuf, "hw_rev1", "%x", sli4->config.hw_rev[1]);
ocs_ddump_value(textbuf, "hw_rev2", "%x", sli4->config.hw_rev[2]);
ocs_ddump_value(textbuf, "sge_supported_length", "%x", sli4->config.sge_supported_length);
ocs_ddump_value(textbuf, "sgl_page_sizes", "%x", sli4->config.sgl_page_sizes);
ocs_ddump_value(textbuf, "max_sgl_pages", "%x", sli4->config.max_sgl_pages);
ocs_ddump_value(textbuf, "high_login_mode", "%x", sli4->config.high_login_mode);
ocs_ddump_value(textbuf, "sgl_pre_registered", "%x", sli4->config.sgl_pre_registered);
ocs_ddump_value(textbuf, "sgl_pre_registration_required", "%x", sli4->config.sgl_pre_registration_required);
ocs_ddump_value(textbuf, "sgl_chaining_capable", "%x", cparams->chaining_capable);
ocs_ddump_value(textbuf, "frag_num_field_offset", "%x", cparams->frag_num_field_offset);
ocs_ddump_value(textbuf, "frag_num_field_mask", "%016llx", (unsigned long long)cparams->frag_num_field_mask);
ocs_ddump_value(textbuf, "sgl_index_field_offset", "%x", cparams->sgl_index_field_offset);
ocs_ddump_value(textbuf, "sgl_index_field_mask", "%016llx", (unsigned long long)cparams->sgl_index_field_mask);
ocs_ddump_value(textbuf, "chain_sge_initial_value_lo", "%x", cparams->chain_sge_initial_value_lo);
ocs_ddump_value(textbuf, "chain_sge_initial_value_hi", "%x", cparams->chain_sge_initial_value_hi);
ocs_ddump_value(textbuf, "max_vfi", "%d", sli_get_max_rsrc(sli4, SLI_RSRC_FCOE_VFI));
ocs_ddump_value(textbuf, "max_vpi", "%d", sli_get_max_rsrc(sli4, SLI_RSRC_FCOE_VPI));
ocs_ddump_value(textbuf, "max_rpi", "%d", sli_get_max_rsrc(sli4, SLI_RSRC_FCOE_RPI));
ocs_ddump_value(textbuf, "max_xri", "%d", sli_get_max_rsrc(sli4, SLI_RSRC_FCOE_XRI));
ocs_ddump_value(textbuf, "max_fcfi", "%d", sli_get_max_rsrc(sli4, SLI_RSRC_FCOE_FCFI));
ocs_ddump_sli_q_fields(textbuf, sli4, SLI_QTYPE_EQ);
ocs_ddump_sli_q_fields(textbuf, sli4, SLI_QTYPE_CQ);
ocs_ddump_sli_q_fields(textbuf, sli4, SLI_QTYPE_MQ);
ocs_ddump_sli_q_fields(textbuf, sli4, SLI_QTYPE_WQ);
ocs_ddump_sli_q_fields(textbuf, sli4, SLI_QTYPE_RQ);
ocs_ddump_endsection(textbuf, "sli4", 0);
}
/**
* @brief Dump HW IO
*
* Dump HW IO
*
* @param textbuf pointer to text buffer
* @param io pointer to HW IO object
*
* @return none
*/
static void
ocs_ddump_hw_io(ocs_textbuf_t *textbuf, ocs_hw_io_t *io)
{
ocs_assert(io);
ocs_ddump_section(textbuf, "hw_io", io->indicator);
ocs_ddump_value(textbuf, "state", "%d", io->state);
ocs_ddump_value(textbuf, "xri", "0x%x", io->indicator);
ocs_ddump_value(textbuf, "tag", "0x%x", io->reqtag);
ocs_ddump_value(textbuf, "abort_reqtag", "0x%x", io->abort_reqtag);
ocs_ddump_value(textbuf, "ref_count", "%d", ocs_ref_read_count(&io->ref));
/* just to make it obvious, display abort bit from tag */
ocs_ddump_value(textbuf, "abort", "0x%x", io->abort_in_progress);
ocs_ddump_value(textbuf, "wq_index", "%d", (io->wq == NULL ? 0xffff : io->wq->instance));
ocs_ddump_value(textbuf, "type", "%d", io->type);
ocs_ddump_value(textbuf, "xbusy", "%d", io->xbusy);
ocs_ddump_value(textbuf, "active_wqe_link", "%d", ocs_list_on_list(&io->wqe_link));
ocs_ddump_value(textbuf, "def_sgl_count", "%d", io->def_sgl_count);
ocs_ddump_value(textbuf, "n_sge", "%d", io->n_sge);
ocs_ddump_value(textbuf, "has_ovfl_sgl", "%s", (io->ovfl_sgl != NULL ? "TRUE" : "FALSE"));
ocs_ddump_value(textbuf, "has_ovfl_io", "%s", (io->ovfl_io != NULL ? "TRUE" : "FALSE"));
ocs_ddump_endsection(textbuf, "hw_io", io->indicator);
}
#if defined(OCS_DEBUG_QUEUE_HISTORY)
/**
* @brief Generate queue history ddump
*
* @param textbuf pointer to text buffer
* @param q_hist Pointer to queue history object.
*/
static void
ocs_ddump_queue_history(ocs_textbuf_t *textbuf, ocs_hw_q_hist_t *q_hist)
{
uint32_t x;
ocs_ddump_section(textbuf, "q_hist", 0);
ocs_ddump_value(textbuf, "count", "%ld", OCS_Q_HIST_SIZE);
ocs_ddump_value(textbuf, "index", "%d", q_hist->q_hist_index);
if (q_hist->q_hist == NULL) {
ocs_ddump_section(textbuf, "history", 0);
ocs_textbuf_printf(textbuf, "No history available\n");
ocs_ddump_endsection(textbuf, "history", 0);
ocs_ddump_endsection(textbuf, "q_hist", 0);
return;
}
/* start from last entry and go backwards */
ocs_textbuf_printf(textbuf, "<history>\n");
ocs_textbuf_printf(textbuf, "(newest first):\n");
ocs_lock(&q_hist->q_hist_lock);
x = ocs_queue_history_prev_index(q_hist->q_hist_index);
do {
int i;
ocs_q_hist_ftr_t ftr;
uint32_t mask;
/* footer's mask indicates what words were captured */
ftr.word = q_hist->q_hist[x];
mask = ftr.s.mask;
i = 0;
/* if we've encountered a mask of 0, must be done */
if (mask == 0) {
break;
}
/* display entry type */
ocs_textbuf_printf(textbuf, "%s:\n",
ocs_queue_history_type_name(ftr.s.type));
if (ocs_queue_history_timestamp_enabled()) {
uint64_t tsc_value;
x = ocs_queue_history_prev_index(x);
tsc_value = ((q_hist->q_hist[x]) & 0x00000000FFFFFFFFull);
x = ocs_queue_history_prev_index(x);
tsc_value |= (((uint64_t)q_hist->q_hist[x] << 32) & 0xFFFFFFFF00000000ull);
ocs_textbuf_printf(textbuf, " t: %" PRIu64 "\n", tsc_value);
}
if (ocs_queue_history_q_info_enabled()) {
if (ftr.s.type == OCS_Q_HIST_TYPE_CWQE ||
ftr.s.type == OCS_Q_HIST_TYPE_CXABT ||
ftr.s.type == OCS_Q_HIST_TYPE_WQE) {
x = ocs_queue_history_prev_index(x);
ocs_textbuf_printf(textbuf, " qid=0x%x idx=0x%x\n",
((q_hist->q_hist[x] >> 16) & 0xFFFF),
((q_hist->q_hist[x] >> 0) & 0xFFFF));
}
}
while (mask) {
if ((mask & 1) && (x != q_hist->q_hist_index)){
/* get next word */
x = ocs_queue_history_prev_index(x);
ocs_textbuf_printf(textbuf, " [%d]=%x\n",
i, q_hist->q_hist[x]);
}
mask = (mask >> 1UL);
i++;
}
/* go backwards to next element */
x = ocs_queue_history_prev_index(x);
} while (x != ocs_queue_history_prev_index(q_hist->q_hist_index));
ocs_unlock(&q_hist->q_hist_lock);
ocs_textbuf_printf(textbuf, "</history>\n");
ocs_ddump_endsection(textbuf, "q_hist", 0);
}
#endif
/**
* @brief Generate hw ddump
*
* Generates hw ddump
*
* @param textbuf pointer to text buffer
* @param hw pointer HW context
* @param flags ddump flags
* @param qentries number of qentries to dump
*
* @return none
*/
static void
ocs_ddump_hw(ocs_textbuf_t *textbuf, ocs_hw_t *hw, uint32_t flags, uint32_t qentries)
{
ocs_t *ocs = hw->os;
uint32_t cnt = 0;
ocs_hw_io_t *io = NULL;
uint32_t i;
uint32_t j;
uint32_t max_rpi = sli_get_max_rsrc(&hw->sli, SLI_RSRC_FCOE_RPI);
ocs_assert(ocs);
ocs_ddump_section(textbuf, "hw", ocs->instance_index);
/* device specific information */
switch(hw->sli.if_type) {
case 0:
ocs_ddump_value(textbuf, "uerr_mask_hi", "%08x",
sli_reg_read(&hw->sli, SLI4_REG_UERR_MASK_HI));
ocs_ddump_value(textbuf, "uerr_mask_lo", "%08x",
sli_reg_read(&hw->sli, SLI4_REG_UERR_MASK_LO));
ocs_ddump_value(textbuf, "uerr_status_hi", "%08x",
sli_reg_read(&hw->sli, SLI4_REG_UERR_STATUS_HI));
ocs_ddump_value(textbuf, "uerr_status_lo", "%08x",
sli_reg_read(&hw->sli, SLI4_REG_UERR_STATUS_LO));
break;
case 2:
ocs_ddump_value(textbuf, "sliport_status", "%08x",
sli_reg_read(&hw->sli, SLI4_REG_SLIPORT_STATUS));
ocs_ddump_value(textbuf, "sliport_error1", "%08x",
sli_reg_read(&hw->sli, SLI4_REG_SLIPORT_ERROR1));
ocs_ddump_value(textbuf, "sliport_error2", "%08x",
sli_reg_read(&hw->sli, SLI4_REG_SLIPORT_ERROR2));
break;
}
ocs_ddump_value(textbuf, "link_status", "%d", hw->link.status);
ocs_ddump_value(textbuf, "link_speed", "%d", hw->link.speed);
ocs_ddump_value(textbuf, "link_topology", "%d", hw->link.topology);
ocs_ddump_value(textbuf, "state", "%d", hw->state);
ocs_ddump_value(textbuf, "io_alloc_failed_count", "%d", ocs_atomic_read(&hw->io_alloc_failed_count));
ocs_ddump_value(textbuf, "n_io", "%d", hw->config.n_io);
ocs_ddump_value(textbuf, "queue_topology", "%s", hw->config.queue_topology);
ocs_ddump_value(textbuf, "rq_selection_policy", "%d", hw->config.rq_selection_policy);
ocs_ddump_value(textbuf, "rr_quanta", "%d", hw->config.rr_quanta);
for (i = 0; i < ARRAY_SIZE(hw->config.filter_def); i++) {
ocs_ddump_value(textbuf, "filter_def", "%08X", hw->config.filter_def[i]);
}
ocs_ddump_value(textbuf, "n_eq", "%d", hw->eq_count);
ocs_ddump_value(textbuf, "n_cq", "%d", hw->cq_count);
ocs_ddump_value(textbuf, "n_mq", "%d", hw->mq_count);
ocs_ddump_value(textbuf, "n_rq", "%d", hw->rq_count);
ocs_ddump_value(textbuf, "n_wq", "%d", hw->wq_count);
ocs_ddump_value(textbuf, "n_sgl", "%d", hw->config.n_sgl);
ocs_ddump_sli(textbuf, &hw->sli);
ocs_ddump_sli4_queue(textbuf, "wq", hw, hw->wq, hw->wq_count,
((flags & OCS_DDUMP_FLAGS_WQES) ? qentries : 0));
ocs_ddump_sli4_queue(textbuf, "rq", hw, hw->rq, hw->rq_count,
((flags & OCS_DDUMP_FLAGS_RQES) ? qentries : 0));
ocs_ddump_sli4_queue(textbuf, "mq", hw, hw->mq, hw->mq_count,
((flags & OCS_DDUMP_FLAGS_MQES) ? qentries : 0));
ocs_ddump_sli4_queue(textbuf, "cq", hw, hw->cq, hw->cq_count,
((flags & OCS_DDUMP_FLAGS_CQES) ? qentries : 0));
ocs_ddump_sli4_queue(textbuf, "eq", hw, hw->eq, hw->eq_count,
((flags & OCS_DDUMP_FLAGS_EQES) ? qentries : 0));
/* dump the IO quarantine list */
for (i = 0; i < hw->wq_count; i++) {
ocs_ddump_section(textbuf, "io_quarantine", i);
ocs_ddump_value(textbuf, "quarantine_index", "%d", hw->hw_wq[i]->quarantine_info.quarantine_index);
for (j = 0; j < OCS_HW_QUARANTINE_QUEUE_DEPTH; j++) {
if (hw->hw_wq[i]->quarantine_info.quarantine_ios[j] != NULL) {
ocs_ddump_hw_io(textbuf, hw->hw_wq[i]->quarantine_info.quarantine_ios[j]);
}
}
ocs_ddump_endsection(textbuf, "io_quarantine", i);
}
ocs_ddump_section(textbuf, "workaround", ocs->instance_index);
ocs_ddump_value(textbuf, "fwrev", "%08llx", (unsigned long long)hw->workaround.fwrev);
ocs_ddump_endsection(textbuf, "workaround", ocs->instance_index);
ocs_lock(&hw->io_lock);
ocs_ddump_section(textbuf, "io_inuse", ocs->instance_index);
ocs_list_foreach(&hw->io_inuse, io) {
ocs_ddump_hw_io(textbuf, io);
}
ocs_ddump_endsection(textbuf, "io_inuse", ocs->instance_index);
ocs_ddump_section(textbuf, "io_wait_free", ocs->instance_index);
ocs_list_foreach(&hw->io_wait_free, io) {
ocs_ddump_hw_io(textbuf, io);
}
ocs_ddump_endsection(textbuf, "io_wait_free", ocs->instance_index);
ocs_ddump_section(textbuf, "io_free", ocs->instance_index);
ocs_list_foreach(&hw->io_free, io) {
if (io->xbusy) {
/* only display free ios if they're active */
ocs_ddump_hw_io(textbuf, io);
}
cnt++;
}
ocs_ddump_endsection(textbuf, "io_free", ocs->instance_index);
ocs_ddump_value(textbuf, "ios_free", "%d", cnt);
ocs_ddump_value(textbuf, "sec_hio_wait_count", "%d", hw->sec_hio_wait_count);
ocs_unlock(&hw->io_lock);
/* now check the IOs not in a list; i.e. sequence coalescing xris */
ocs_ddump_section(textbuf, "port_owned_ios", ocs->instance_index);
for (i = 0; i < hw->config.n_io; i++) {
io = hw->io[i];
if (!io)
continue;
if (ocs_hw_is_xri_port_owned(hw, io->indicator)) {
if (ocs_ref_read_count(&io->ref)) {
/* only display free ios if they're active */
ocs_ddump_hw_io(textbuf, io);
}
}
}
ocs_ddump_endsection(textbuf, "port_owned_ios", ocs->instance_index);
ocs_textbuf_printf(textbuf, "<rpi_ref>");
for (i = 0; i < max_rpi; i++) {
if (ocs_atomic_read(&hw->rpi_ref[i].rpi_attached) ||
ocs_atomic_read(&hw->rpi_ref[i].rpi_count) ) {
ocs_textbuf_printf(textbuf, "[%d] att=%d cnt=%d\n", i,
ocs_atomic_read(&hw->rpi_ref[i].rpi_attached),
ocs_atomic_read(&hw->rpi_ref[i].rpi_count));
}
}
ocs_textbuf_printf(textbuf, "</rpi_ref>");
for (i = 0; i < hw->wq_count; i++) {
ocs_ddump_value(textbuf, "wq_submit", "%d", hw->tcmd_wq_submit[i]);
}
for (i = 0; i < hw->wq_count; i++) {
ocs_ddump_value(textbuf, "wq_complete", "%d", hw->tcmd_wq_complete[i]);
}
hw_queue_ddump(textbuf, hw);
ocs_ddump_endsection(textbuf, "hw", ocs->instance_index);
}
void
hw_queue_ddump(ocs_textbuf_t *textbuf, ocs_hw_t *hw)
{
hw_eq_t *eq;
hw_cq_t *cq;
hw_q_t *q;
hw_mq_t *mq;
hw_wq_t *wq;
hw_rq_t *rq;
ocs_ddump_section(textbuf, "hw_queue", 0);
ocs_list_foreach(&hw->eq_list, eq) {
ocs_ddump_section(textbuf, "eq", eq->instance);
ocs_ddump_value(textbuf, "queue-id", "%d", eq->queue->id);
OCS_STAT(ocs_ddump_value(textbuf, "use_count", "%d", eq->use_count));
ocs_list_foreach(&eq->cq_list, cq) {
ocs_ddump_section(textbuf, "cq", cq->instance);
ocs_ddump_value(textbuf, "queue-id", "%d", cq->queue->id);
OCS_STAT(ocs_ddump_value(textbuf, "use_count", "%d", cq->use_count));
ocs_list_foreach(&cq->q_list, q) {
switch(q->type) {
case SLI_QTYPE_MQ:
mq = (hw_mq_t *) q;
ocs_ddump_section(textbuf, "mq", mq->instance);
ocs_ddump_value(textbuf, "queue-id", "%d", mq->queue->id);
OCS_STAT(ocs_ddump_value(textbuf, "use_count", "%d", mq->use_count));
ocs_ddump_endsection(textbuf, "mq", mq->instance);
break;
case SLI_QTYPE_WQ:
wq = (hw_wq_t *) q;
ocs_ddump_section(textbuf, "wq", wq->instance);
ocs_ddump_value(textbuf, "queue-id", "%d", wq->queue->id);
OCS_STAT(ocs_ddump_value(textbuf, "use_count", "%d", wq->use_count));
ocs_ddump_value(textbuf, "wqec_count", "%d", wq->wqec_count);
ocs_ddump_value(textbuf, "free_count", "%d", wq->free_count);
OCS_STAT(ocs_ddump_value(textbuf, "wq_pending_count", "%d",
wq->wq_pending_count));
ocs_ddump_endsection(textbuf, "wq", wq->instance);
break;
case SLI_QTYPE_RQ:
rq = (hw_rq_t *) q;
ocs_ddump_section(textbuf, "rq", rq->instance);
OCS_STAT(ocs_ddump_value(textbuf, "use_count", "%d", rq->use_count));
ocs_ddump_value(textbuf, "filter_mask", "%d", rq->filter_mask);
if (rq->hdr != NULL) {
ocs_ddump_value(textbuf, "hdr-id", "%d", rq->hdr->id);
OCS_STAT(ocs_ddump_value(textbuf, "hdr_use_count", "%d", rq->hdr_use_count));
}
if (rq->first_burst != NULL) {
OCS_STAT(ocs_ddump_value(textbuf, "fb-id", "%d", rq->first_burst->id));
OCS_STAT(ocs_ddump_value(textbuf, "fb_use_count", "%d", rq->fb_use_count));
}
if (rq->data != NULL) {
OCS_STAT(ocs_ddump_value(textbuf, "payload-id", "%d", rq->data->id));
OCS_STAT(ocs_ddump_value(textbuf, "payload_use_count", "%d", rq->payload_use_count));
}
ocs_ddump_endsection(textbuf, "rq", rq->instance);
break;
default:
break;
}
}
ocs_ddump_endsection(textbuf, "cq", cq->instance);
}
ocs_ddump_endsection(textbuf, "eq", eq->instance);
}
ocs_ddump_endsection(textbuf, "hw_queue", 0);
}
/**
* @brief Initiate ddump
*
* Traverses the ocs/domain/port/node/io data structures to generate a driver
* dump.
*
* @param ocs pointer to device context
* @param textbuf pointer to text buffer
* @param flags ddump flags
* @param qentries number of queue entries to dump
*
* @return Returns 0 on success, or a negative value on failure.
*/
int
ocs_ddump(ocs_t *ocs, ocs_textbuf_t *textbuf, uint32_t flags, uint32_t qentries)
{
ocs_xport_t *xport = ocs->xport;
ocs_domain_t *domain;
uint32_t instance;
ocs_vport_spec_t *vport;
ocs_io_t *io;
int retval = 0;
uint32_t i;
ocs_ddump_startfile(textbuf);
ocs_ddump_section(textbuf, "ocs", ocs->instance_index);
ocs_ddump_section(textbuf, "ocs_os", ocs->instance_index);
#ifdef OCS_ENABLE_NUMA_SUPPORT
ocs_ddump_value(textbuf, "numa_node", "%d", ocs->ocs_os.numa_node);
#endif
ocs_ddump_endsection(textbuf, "ocs_os", ocs->instance_index);
ocs_ddump_value(textbuf, "drv_name", "%s", DRV_NAME);
ocs_ddump_value(textbuf, "drv_version", "%s", DRV_VERSION);
ocs_ddump_value(textbuf, "display_name", "%s", ocs->display_name);
ocs_ddump_value(textbuf, "enable_ini", "%d", ocs->enable_ini);
ocs_ddump_value(textbuf, "enable_tgt", "%d", ocs->enable_tgt);
ocs_ddump_value(textbuf, "nodes_count", "%d", xport->nodes_count);
ocs_ddump_value(textbuf, "enable_hlm", "%d", ocs->enable_hlm);
ocs_ddump_value(textbuf, "hlm_group_size", "%d", ocs->hlm_group_size);
ocs_ddump_value(textbuf, "auto_xfer_rdy_size", "%d", ocs->auto_xfer_rdy_size);
ocs_ddump_value(textbuf, "io_alloc_failed_count", "%d", ocs_atomic_read(&xport->io_alloc_failed_count));
ocs_ddump_value(textbuf, "io_active_count", "%d", ocs_atomic_read(&xport->io_active_count));
ocs_ddump_value(textbuf, "io_pending_count", "%d", ocs_atomic_read(&xport->io_pending_count));
ocs_ddump_value(textbuf, "io_total_alloc", "%d", ocs_atomic_read(&xport->io_total_alloc));
ocs_ddump_value(textbuf, "io_total_free", "%d", ocs_atomic_read(&xport->io_total_free));
ocs_ddump_value(textbuf, "io_total_pending", "%d", ocs_atomic_read(&xport->io_total_pending));
ocs_ddump_value(textbuf, "io_pending_recursing", "%d", ocs_atomic_read(&xport->io_pending_recursing));
ocs_ddump_value(textbuf, "max_isr_time_msec", "%d", ocs->max_isr_time_msec);
for (i = 0; i < SLI4_MAX_FCFI; i++) {
ocs_lock(&xport->fcfi[i].pend_frames_lock);
if (!ocs_list_empty(&xport->fcfi[i].pend_frames)) {
ocs_hw_sequence_t *frame;
ocs_ddump_section(textbuf, "pending_frames", i);
ocs_ddump_value(textbuf, "hold_frames", "%d", xport->fcfi[i].hold_frames);
ocs_list_foreach(&xport->fcfi[i].pend_frames, frame) {
fc_header_t *hdr;
char buf[128];
hdr = frame->header->dma.virt;
ocs_snprintf(buf, sizeof(buf), "%02x/%04x/%04x len %zu",
hdr->r_ctl, ocs_be16toh(hdr->ox_id), ocs_be16toh(hdr->rx_id),
frame->payload->dma.len);
ocs_ddump_value(textbuf, "frame", "%s", buf);
}
ocs_ddump_endsection(textbuf, "pending_frames", i);
}
ocs_unlock(&xport->fcfi[i].pend_frames_lock);
}
ocs_lock(&xport->io_pending_lock);
ocs_ddump_section(textbuf, "io_pending_list", ocs->instance_index);
ocs_list_foreach(&xport->io_pending_list, io) {
ocs_ddump_io(textbuf, io);
}
ocs_ddump_endsection(textbuf, "io_pending_list", ocs->instance_index);
ocs_unlock(&xport->io_pending_lock);
#if defined(ENABLE_LOCK_DEBUG)
/* Dump the lock list */
ocs_ddump_section(textbuf, "locks", 0);
ocs_lock(&ocs->ocs_os.locklist_lock); {
ocs_lock_t *l;
uint32_t idx = 0;
ocs_list_foreach(&ocs->ocs_os.locklist, l) {
ocs_ddump_section(textbuf, "lock", idx);
ocs_ddump_value(textbuf, "name", "%s", l->name);
ocs_ddump_value(textbuf, "inuse", "%d", l->inuse);
ocs_ddump_value(textbuf, "caller", "%p", l->caller[0]);
ocs_ddump_value(textbuf, "pid", "%08x", l->pid.l);
ocs_ddump_endsection(textbuf, "lock", idx);
idx++;
}
} ocs_unlock(&ocs->ocs_os.locklist_lock);
ocs_ddump_endsection(textbuf, "locks", 0);
#endif
/* Dump any pending vports */
if (ocs_device_lock_try(ocs) != TRUE) {
/* Didn't get the lock */
return -1;
}
instance = 0;
ocs_list_foreach(&xport->vport_list, vport) {
ocs_ddump_section(textbuf, "vport_spec", instance);
ocs_ddump_value(textbuf, "domain_instance", "%d", vport->domain_instance);
ocs_ddump_value(textbuf, "wwnn", "%llx", (unsigned long long)vport->wwnn);
ocs_ddump_value(textbuf, "wwpn", "%llx", (unsigned long long)vport->wwpn);
ocs_ddump_value(textbuf, "fc_id", "0x%x", vport->fc_id);
ocs_ddump_value(textbuf, "enable_tgt", "%d", vport->enable_tgt);
ocs_ddump_value(textbuf, "enable_ini", "%d" PRIx64, vport->enable_ini);
ocs_ddump_endsection(textbuf, "vport_spec", instance ++);
}
ocs_device_unlock(ocs);
/* Dump target and initiator private data */
ocs_scsi_ini_ddump(textbuf, OCS_SCSI_DDUMP_DEVICE, ocs);
ocs_scsi_tgt_ddump(textbuf, OCS_SCSI_DDUMP_DEVICE, ocs);
ocs_ddump_hw(textbuf, &ocs->hw, flags, qentries);
if (ocs_device_lock_try(ocs) != TRUE) {
/* Didn't get the lock */
return -1;
}
/* Here the device lock is held */
ocs_list_foreach(&ocs->domain_list, domain) {
retval = ocs_ddump_domain(textbuf, domain);
if (retval != 0) {
break;
}
}
/* Dump ramlog */
ocs_ddump_ramlog(textbuf, ocs->ramlog);
ocs_device_unlock(ocs);
#if !defined(OCS_DEBUG_QUEUE_HISTORY)
ocs_ddump_section(textbuf, "q_hist", ocs->instance_index);
ocs_textbuf_printf(textbuf, "<history>\n");
ocs_textbuf_printf(textbuf, "No history available\n");
ocs_textbuf_printf(textbuf, "</history>\n");
ocs_ddump_endsection(textbuf, "q_hist", ocs->instance_index);
#else
ocs_ddump_queue_history(textbuf, &ocs->hw.q_hist);
#endif
#if defined(OCS_DEBUG_MEMORY)
ocs_memory_allocated_ddump(textbuf);
#endif
ocs_ddump_endsection(textbuf, "ocs", ocs->instance_index);
ocs_ddump_endfile(textbuf);
return retval;
}
/**
* @brief Capture and save ddump
*
* Captures and saves a ddump to the ocs_t structure to save the
* current state. The goal of this function is to save a ddump
* as soon as an issue is encountered. The saved ddump will be
* kept until the user reads it.
*
* @param ocs pointer to device context
* @param flags ddump flags
* @param qentries number of queue entries to dump
*
* @return 0 if ddump was saved; > 0 of one already exists; < 0
* error
*/
int32_t
ocs_save_ddump(ocs_t *ocs, uint32_t flags, uint32_t qentries)
{
if (ocs_textbuf_get_written(&ocs->ddump_saved) > 0) {
ocs_log_debug(ocs, "Saved ddump already exists\n");
return 1;
}
if (!ocs_textbuf_initialized(&ocs->ddump_saved)) {
ocs_log_err(ocs, "Saved ddump not allocated\n");
return -1;
}
ocs_log_debug(ocs, "Saving ddump\n");
ocs_ddump(ocs, &ocs->ddump_saved, flags, qentries);
ocs_log_debug(ocs, "Saved ddump: %d bytes written\n", ocs_textbuf_get_written(&ocs->ddump_saved));
return 0;
}
/**
* @brief Capture and save ddump for all OCS instances
*
* Calls ocs_save_ddump() for each OCS instance.
*
* @param flags ddump flags
* @param qentries number of queue entries to dump
* @param alloc_flag allocate dump buffer if not already allocated
*
* @return 0 if ddump was saved; > 0 of one already exists; < 0
* error
*/
int32_t
ocs_save_ddump_all(uint32_t flags, uint32_t qentries, uint32_t alloc_flag)
{
ocs_t *ocs;
uint32_t i;
int32_t rc = 0;
for (i = 0; (ocs = ocs_get_instance(i)) != NULL; i++) {
if (alloc_flag && (!ocs_textbuf_initialized(&ocs->ddump_saved))) {
rc = ocs_textbuf_alloc(ocs, &ocs->ddump_saved, DEFAULT_SAVED_DUMP_SIZE);
if (rc) {
break;
}
}
rc = ocs_save_ddump(ocs, flags, qentries);
if (rc < 0) {
break;
}
}
return rc;
}
/**
* @brief Clear saved ddump
*
* Clears saved ddump to make room for next one.
*
* @param ocs pointer to device context
*
* @return 0 if ddump was cleared; > 0 no saved ddump found
*/
int32_t
ocs_clear_saved_ddump(ocs_t *ocs)
{
/* if there's a saved ddump, copy to newly allocated textbuf */
if (ocs_textbuf_get_written(&ocs->ddump_saved)) {
ocs_log_debug(ocs, "saved ddump cleared\n");
ocs_textbuf_reset(&ocs->ddump_saved);
return 0;
} else {
ocs_log_debug(ocs, "no saved ddump found\n");
return 1;
}
}

View file

@ -0,0 +1,60 @@
/*-
* Copyright (c) 2017 Broadcom. All rights reserved.
* The term "Broadcom" refers to Broadcom Limited and/or its subsidiaries.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* $FreeBSD$
*/
#if !defined(__OCS_DDUMP_H__)
#define __OCS_DDUMP_H__
#include "ocs_utils.h"
#define OCS_DDUMP_FLAGS_WQES (1U << 0)
#define OCS_DDUMP_FLAGS_CQES (1U << 1)
#define OCS_DDUMP_FLAGS_MQES (1U << 2)
#define OCS_DDUMP_FLAGS_RQES (1U << 3)
#define OCS_DDUMP_FLAGS_EQES (1U << 4)
extern int ocs_ddump(ocs_t *ocs, ocs_textbuf_t *textbuf, uint32_t flags, uint32_t qentries);
extern void ocs_ddump_startfile(ocs_textbuf_t *textbuf);
extern void ocs_ddump_endfile(ocs_textbuf_t *textbuf);
extern void ocs_ddump_section(ocs_textbuf_t *textbuf, const char *name, uint32_t instance);
extern void ocs_ddump_endsection(ocs_textbuf_t *textbuf, const char *name, uint32_t instance);
__attribute__((format(printf,3,4)))
extern void ocs_ddump_value(ocs_textbuf_t *textbuf, const char *name, const char *fmt, ...);
extern void ocs_ddump_buffer(ocs_textbuf_t *textbuf, const char *name, uint32_t instance, void *buffer, uint32_t size);
extern int32_t ocs_save_ddump(ocs_t *ocs, uint32_t flags, uint32_t qentries);
extern int32_t ocs_get_saved_ddump(ocs_t *ocs, ocs_textbuf_t *textbuf);
extern int32_t ocs_save_ddump_all(uint32_t flags, uint32_t qentries, uint32_t alloc_flag);
extern int32_t ocs_clear_saved_ddump(ocs_t *ocs);
extern void ocs_ddump_queue_entries(ocs_textbuf_t *textbuf, void *q_addr, uint32_t size, uint32_t length, int32_t index, uint32_t qentries);
#endif

1929
sys/dev/ocs_fc/ocs_device.c Normal file

File diff suppressed because it is too large Load diff

133
sys/dev/ocs_fc/ocs_device.h Normal file
View file

@ -0,0 +1,133 @@
/*-
* Copyright (c) 2017 Broadcom. All rights reserved.
* The term "Broadcom" refers to Broadcom Limited and/or its subsidiaries.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* $FreeBSD$
*/
/**
* @file
* Node state machine functions for remote device node sm
*/
#if !defined(__OCS_DEVICE_H__)
#define __OCS_DEVICE_H__
/***************************************************************************
* Receive queue configuration
*/
#ifndef OCS_FC_RQ_SIZE_DEFAULT
#define OCS_FC_RQ_SIZE_DEFAULT 1024
#endif
/***************************************************************************
* IO Configuration
*/
/**
* @brief Defines the number of SGLs allocated on each IO object
*/
#ifndef OCS_FC_MAX_SGL
#define OCS_FC_MAX_SGL 128
#endif
/***************************************************************************
* DIF Configuration
*/
/**
* @brief Defines the DIF seed value used for the CRC calculation.
*/
#ifndef OCS_FC_DIF_SEED
#define OCS_FC_DIF_SEED 0
#endif
/***************************************************************************
* Timeouts
*/
#ifndef OCS_FC_ELS_SEND_DEFAULT_TIMEOUT
#define OCS_FC_ELS_SEND_DEFAULT_TIMEOUT 0
#endif
#ifndef OCS_FC_ELS_CT_SEND_DEFAULT_TIMEOUT
#define OCS_FC_ELS_CT_SEND_DEFAULT_TIMEOUT 5
#endif
#ifndef OCS_FC_ELS_DEFAULT_RETRIES
#define OCS_FC_ELS_DEFAULT_RETRIES 3
#endif
#ifndef OCS_FC_FLOGI_TIMEOUT_SEC
#define OCS_FC_FLOGI_TIMEOUT_SEC 5 /* shorter than default */
#endif
#ifndef OCS_FC_DOMAIN_SHUTDOWN_TIMEOUT_USEC
#define OCS_FC_DOMAIN_SHUTDOWN_TIMEOUT_USEC 30000000 /* 30 seconds */
#endif
/***************************************************************************
* Watermark
*/
#ifndef OCS_WATERMARK_HIGH_PCT
#define OCS_WATERMARK_HIGH_PCT 90
#endif
#ifndef OCS_WATERMARK_LOW_PCT
#define OCS_WATERMARK_LOW_PCT 80
#endif
#ifndef OCS_IO_WATERMARK_PER_INITIATOR
#define OCS_IO_WATERMARK_PER_INITIATOR 8
#endif
extern void ocs_node_init_device(ocs_node_t *node, int send_plogi);
extern void ocs_process_prli_payload(ocs_node_t *node, fc_prli_payload_t *prli);
extern void ocs_d_send_prli_rsp(ocs_io_t *io, uint16_t ox_id);
extern void ocs_send_ls_acc_after_attach(ocs_io_t *io, fc_header_t *hdr, ocs_node_send_ls_acc_e ls);
extern void*__ocs_d_wait_loop(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg);
extern void*__ocs_d_wait_plogi_acc_cmpl(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg);
extern void*__ocs_d_init(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg);
extern void*__ocs_d_wait_plogi_rsp(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg);
extern void*__ocs_d_wait_plogi_rsp_recvd_prli(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg);
extern void*__ocs_d_wait_domain_attach(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg);
extern void*__ocs_d_wait_topology_notify(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg);
extern void*__ocs_d_wait_node_attach(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg);
extern void*__ocs_d_wait_attach_evt_shutdown(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg);
extern void*__ocs_d_initiate_shutdown(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg);
extern void*__ocs_d_port_logged_in(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg);
extern void*__ocs_d_wait_logo_acc_cmpl(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg);
extern void*__ocs_d_device_ready(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg);
extern void*__ocs_d_device_gone(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg);
extern void*__ocs_d_wait_adisc_rsp(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg);
extern void*__ocs_d_wait_logo_rsp(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg);
extern void*__ocs_d_wait_prlo_rsp(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg);
#endif /* __OCS_DEVICE_H__ */

1585
sys/dev/ocs_fc/ocs_domain.c Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,91 @@
/*-
* Copyright (c) 2017 Broadcom. All rights reserved.
* The term "Broadcom" refers to Broadcom Limited and/or its subsidiaries.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* $FreeBSD$
*/
/**
* @file
* Declare driver's domain handler exported interface
*/
#if !defined(__OCS_DOMAIN_H__)
#define __OCS_DOMAIN_H__
extern int32_t ocs_domain_init(ocs_t *ocs, ocs_domain_t *domain);
extern ocs_domain_t *ocs_domain_find(ocs_t *ocs, uint64_t fcf_wwn);
extern ocs_domain_t *ocs_domain_alloc(ocs_t *ocs, uint64_t fcf_wwn);
extern void ocs_domain_free(ocs_domain_t *domain);
extern void ocs_domain_force_free(ocs_domain_t *domain);
extern void ocs_register_domain_list_empty_cb(ocs_t *ocs, void (*callback)(ocs_t *ocs, void *arg), void *arg);
extern uint64_t ocs_get_wwn(ocs_hw_t *hw, ocs_hw_property_e prop);
static inline void
ocs_domain_lock_init(ocs_domain_t *domain)
{
}
static inline int32_t
ocs_domain_lock_try(ocs_domain_t *domain)
{
/* Use the device wide lock */
return ocs_device_lock_try(domain->ocs);
}
static inline void
ocs_domain_lock(ocs_domain_t *domain)
{
/* Use the device wide lock */
ocs_device_lock(domain->ocs);
}
static inline void
ocs_domain_unlock(ocs_domain_t *domain)
{
/* Use the device wide lock */
ocs_device_unlock(domain->ocs);
}
extern int32_t ocs_domain_cb(void *arg, ocs_hw_domain_event_e event, void *data);
extern void *__ocs_domain_init(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg);
extern void *__ocs_domain_wait_alloc(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg);
extern void *__ocs_domain_allocated(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg);
extern void *__ocs_domain_wait_attach(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg);
extern void *__ocs_domain_ready(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg);
extern void *__ocs_domain_wait_sports_free(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg);
extern void *__ocs_domain_wait_shutdown(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg);
extern void *__ocs_domain_wait_domain_lost(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg);
extern void ocs_domain_save_sparms(ocs_domain_t *domain, void *payload);
extern void ocs_domain_attach(ocs_domain_t *domain, uint32_t s_id);
extern int ocs_domain_post_event(ocs_domain_t *domain, ocs_sm_event_t, void *);
extern int ocs_ddump_domain(ocs_textbuf_t *textbuf, ocs_domain_t *domain);
extern void __ocs_domain_attach_internal(ocs_domain_t *domain, uint32_t s_id);;
#endif

212
sys/dev/ocs_fc/ocs_drv_fc.h Normal file
View file

@ -0,0 +1,212 @@
/*-
* Copyright (c) 2017 Broadcom. All rights reserved.
* The term "Broadcom" refers to Broadcom Limited and/or its subsidiaries.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* $FreeBSD$
*/
/**
* @file
* OCS linux driver common include file
*/
#if !defined(__OCS_DRV_FC_H__)
#define __OCS_DRV_FC_H__
#define OCS_INCLUDE_FC
#include "ocs_os.h"
#include "ocs_debug.h"
#include "ocs_common.h"
#include "ocs_hw.h"
#include "ocs_io.h"
#include "ocs_pm.h"
#include "ocs_xport.h"
#include "ocs_stats.h"
struct ocs_s {
ocs_os_t ocs_os;
char display_name[OCS_DISPLAY_NAME_LENGTH];
ocs_rlock_t lock; /*>> Device wide lock */
ocs_list_t domain_list; /*>> linked list of virtual fabric objects */
ocs_io_pool_t *io_pool; /**< pointer to IO pool */
ocs_ramlog_t *ramlog;
ocs_drv_t drv_ocs;
ocs_scsi_tgt_t tgt_ocs;
ocs_scsi_ini_t ini_ocs;
ocs_xport_e ocs_xport;
ocs_xport_t *xport; /*>> Pointer to transport object */
bool enable_ini;
bool enable_tgt;
uint8_t fc_type;
int ctrlmask;
int logmask;
uint32_t max_isr_time_msec; /*>> Maximum ISR time */
char *hw_war_version;
ocs_pm_context_t pm_context; /*<< power management context */
ocs_mgmt_functions_t *mgmt_functions;
ocs_mgmt_functions_t *tgt_mgmt_functions;
ocs_mgmt_functions_t *ini_mgmt_functions;
ocs_err_injection_e err_injection; /**< for error injection testing */
uint32_t cmd_err_inject; /**< specific cmd to inject error into */
time_t delay_value_msec; /**< for injecting delays */
const char *desc;
uint32_t instance_index;
uint16_t pci_vendor;
uint16_t pci_device;
uint16_t pci_subsystem_vendor;
uint16_t pci_subsystem_device;
char businfo[OCS_DISPLAY_BUS_INFO_LENGTH];
const char *model;
const char *driver_version;
const char *fw_version;
ocs_hw_t hw;
ocs_domain_t *domain; /*>> pointer to first (physical) domain (also on domain_list) */
uint32_t domain_instance_count; /*>> domain instance count */
void (*domain_list_empty_cb)(ocs_t *ocs, void *arg); /*>> domain list empty callback */
void *domain_list_empty_cb_arg; /*>> domain list empty callback argument */
bool explicit_buffer_list;
bool external_loopback;
uint32_t num_vports;
uint32_t hw_bounce;
uint32_t rq_threads;
uint32_t rq_selection_policy;
uint32_t rr_quanta;
char *filter_def;
uint32_t max_remote_nodes;
bool soft_wwn_enable;
/*
* tgt_rscn_delay - delay in kicking off RSCN processing (nameserver queries)
* after receiving an RSCN on the target. This prevents thrashing of nameserver
* requests due to a huge burst of RSCNs received in a short period of time
* Note: this is only valid when target RSCN handling is enabled -- see ctrlmask.
*/
time_t tgt_rscn_delay_msec; /*>> minimum target RSCN delay */
/*
* tgt_rscn_period - determines maximum frequency when processing back-to-back
* RSCNs; e.g. if this value is 30, there will never be any more than 1 RSCN
* handling per 30s window. This prevents initiators on a faulty link generating
* many RSCN from causing the target to continually query the nameserver. Note:
* this is only valid when target RSCN handling is enabled
*/
time_t tgt_rscn_period_msec; /*>> minimum target RSCN period */
/*
* Target IO timer value:
* Zero: target command timeout disabled.
* Non-zero: Timeout value, in seconds, for target commands
*/
uint32_t target_io_timer_sec;
int speed;
int topology;
int ethernet_license;
int num_scsi_ios;
bool enable_hlm; /*>> high login mode is enabled */
uint32_t hlm_group_size; /*>> RPI count for high login mode */
char *wwn_bump;
uint32_t nodedb_mask; /*>> Node debugging mask */
uint32_t auto_xfer_rdy_size; /*>> Maximum sized write to use auto xfer rdy */
bool esoc;
uint8_t ocs_req_fw_upgrade;
ocs_textbuf_t ddump_saved;
};
#define ocs_is_fc_initiator_enabled() (ocs->enable_ini)
#define ocs_is_fc_target_enabled() (ocs->enable_tgt)
static inline void
ocs_device_lock_init(ocs_t *ocs)
{
ocs_rlock_init(ocs, &ocs->lock, "ocsdevicelock");
}
static inline void
ocs_device_lock_free(ocs_t *ocs)
{
ocs_rlock_free(&ocs->lock);
}
static inline int32_t
ocs_device_lock_try(ocs_t *ocs)
{
return ocs_rlock_try(&ocs->lock);
}
static inline void
ocs_device_lock(ocs_t *ocs)
{
ocs_rlock_acquire(&ocs->lock);
}
static inline void
ocs_device_unlock(ocs_t *ocs)
{
ocs_rlock_release(&ocs->lock);
}
extern ocs_t *ocs_get_instance(uint32_t index);
extern int32_t ocs_get_bus_dev_func(ocs_t *ocs, uint8_t* bus, uint8_t* dev, uint8_t* func);
static inline ocs_io_t *
ocs_io_alloc(ocs_t *ocs)
{
return ocs_io_pool_io_alloc(ocs->xport->io_pool);
}
static inline void
ocs_io_free(ocs_t *ocs, ocs_io_t *io)
{
ocs_io_pool_io_free(ocs->xport->io_pool, io);
}
extern void ocs_stop_event_processing(ocs_os_t *ocs_os);
extern int32_t ocs_start_event_processing(ocs_os_t *ocs_os);
#include "ocs_domain.h"
#include "ocs_sport.h"
#include "ocs_node.h"
#include "ocs_io.h"
#include "ocs_unsol.h"
#include "ocs_scsi.h"
#include "ocs_ioctl.h"
#include "ocs_elxu.h"
#endif

2777
sys/dev/ocs_fc/ocs_els.c Normal file

File diff suppressed because it is too large Load diff

110
sys/dev/ocs_fc/ocs_els.h Normal file
View file

@ -0,0 +1,110 @@
/*-
* Copyright (c) 2017 Broadcom. All rights reserved.
* The term "Broadcom" refers to Broadcom Limited and/or its subsidiaries.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* $FreeBSD$
*/
/**
* @file
* Declarations for the interface exported by ocs_els.
*/
#if !defined(__OCS_ELS_H__)
#define __OCS_ELS_H__
#include "ocs.h"
#define OCS_ELS_RSP_LEN 1024
#define OCS_ELS_GID_PT_RSP_LEN 8096 /* Enough for 2K remote target nodes */
#define OCS_ELS_REQ_LEN 116 /*Max request length*/
typedef enum {
OCS_ELS_ROLE_ORIGINATOR,
OCS_ELS_ROLE_RESPONDER,
} ocs_els_role_e;
extern ocs_io_t *ocs_els_io_alloc(ocs_node_t *node, uint32_t reqlen, ocs_els_role_e role);
extern ocs_io_t *ocs_els_io_alloc_size(ocs_node_t *node, uint32_t reqlen, uint32_t rsplen, ocs_els_role_e role);
extern void ocs_els_io_free(ocs_io_t *els);
/* ELS command send */
typedef void (*els_cb_t)(ocs_node_t *node, ocs_node_cb_t *cbdata, void *arg);
extern ocs_io_t *ocs_send_plogi(ocs_node_t *node, uint32_t timeout_sec, uint32_t retries, els_cb_t cb, void *cbarg);
extern ocs_io_t *ocs_send_flogi(ocs_node_t *node, uint32_t timeout_sec, uint32_t retries, els_cb_t cb, void *cbarg);
extern ocs_io_t *ocs_send_fdisc(ocs_node_t *node, uint32_t timeout_sec, uint32_t retries, els_cb_t cb, void *cbarg);
extern ocs_io_t *ocs_send_prli(ocs_node_t *node, uint32_t timeout_sec, uint32_t retries, els_cb_t cb, void *cbarg);
extern ocs_io_t *ocs_send_prlo(ocs_node_t *node, uint32_t timeout_sec, uint32_t retries, els_cb_t cb, void *cbarg);
extern ocs_io_t *ocs_send_logo(ocs_node_t *node, uint32_t timeout_sec, uint32_t retries, els_cb_t cb, void *cbarg);
extern ocs_io_t *ocs_send_adisc(ocs_node_t *node, uint32_t timeout_sec, uint32_t retries, els_cb_t cb, void *cbarg);
extern ocs_io_t *ocs_send_pdisc(ocs_node_t *node, uint32_t timeout_sec, uint32_t retries, els_cb_t cb, void *cbarg);
extern ocs_io_t *ocs_send_scr(ocs_node_t *node, uint32_t timeout_sec, uint32_t retries, els_cb_t cb, void *cbarg);
extern ocs_io_t *ocs_send_rrq(ocs_node_t *node, uint32_t timeout_sec, uint32_t retries, els_cb_t cb, void *cbarg);
extern ocs_io_t *ocs_ns_send_rftid(ocs_node_t *node, uint32_t timeout_sec, uint32_t retries, els_cb_t cb, void *cbarg);
extern ocs_io_t *ocs_ns_send_rffid(ocs_node_t *node, uint32_t timeout_sec, uint32_t retries, els_cb_t cb, void *cbarg);
extern ocs_io_t *ocs_ns_send_gidpt(ocs_node_t *node, uint32_t timeout_sec, uint32_t retries, els_cb_t cb, void *cbarg);
extern ocs_io_t *ocs_send_rscn(ocs_node_t *node, uint32_t timeout_sec, uint32_t retries,
void *port_ids, uint32_t port_ids_count, els_cb_t cb, void *cbarg);
extern void ocs_els_io_cleanup(ocs_io_t *els, ocs_sm_event_t node_evt, void *arg);
/* ELS acc send */
extern ocs_io_t *ocs_send_ls_acc(ocs_io_t *io, uint32_t ox_id, els_cb_t cb, void *cbarg);
extern ocs_io_t *ocs_send_ls_rjt(ocs_io_t *io, uint32_t ox_id, uint32_t reason_cod, uint32_t reason_code_expl,
uint32_t vendor_unique, els_cb_t cb, void *cbarg);
extern ocs_io_t *ocs_send_flogi_p2p_acc(ocs_io_t *io, uint32_t ox_id, uint32_t s_id, els_cb_t cb, void *cbarg);
extern ocs_io_t *ocs_send_flogi_acc(ocs_io_t *io, uint32_t ox_id, uint32_t is_fport, els_cb_t cb, void *cbarg);
extern ocs_io_t *ocs_send_plogi_acc(ocs_io_t *io, uint32_t ox_id, els_cb_t cb, void *cbarg);
extern ocs_io_t *ocs_send_prli_acc(ocs_io_t *io, uint32_t ox_id, uint8_t fc_type, els_cb_t cb, void *cbarg);
extern ocs_io_t *ocs_send_logo_acc(ocs_io_t *io, uint32_t ox_id, els_cb_t cb, void *cbarg);
extern ocs_io_t *ocs_send_prlo_acc(ocs_io_t *io, uint32_t ox_id, uint8_t fc_type, els_cb_t cb, void *cbarg);
extern ocs_io_t *ocs_send_adisc_acc(ocs_io_t *io, uint32_t ox_id, els_cb_t cb, void *cbarg);
extern void ocs_ddump_els(ocs_textbuf_t *textbuf, ocs_io_t *els);
/* BLS acc send */
extern ocs_io_t *ocs_bls_send_acc_hdr(ocs_io_t *io, fc_header_t *hdr);
/* ELS IO state machine */
extern void ocs_els_post_event(ocs_io_t *els, ocs_sm_event_t evt, void *data);
extern void *__ocs_els_common(const char *funcname, ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg);
extern void *__ocs_els_init(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg);
extern void *__ocs_els_wait_resp(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg);
extern void *__ocs_els_aborting(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg);
extern void *__ocs_els_aborting_wait_req_cmpl(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg);
extern void *__ocs_els_aborting_wait_abort_cmpl(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg);
extern void *__ocs_els_retry(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg);
extern void * __ocs_els_aborted_delay_retry(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg);
extern void *__ocs_els_delay_retry(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg);
/* Misc */
extern int32_t ocs_els_io_list_empty(ocs_node_t *node, ocs_list_t *list);
/* CT */
extern int32_t ocs_send_ct_rsp(ocs_io_t *io, uint32_t ox_id, fcct_iu_header_t *ct_hdr, uint32_t cmd_rsp_code, uint32_t reason_code, uint32_t reason_code_explanation);
#endif

2046
sys/dev/ocs_fc/ocs_fabric.c Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,82 @@
/*-
* Copyright (c) 2017 Broadcom. All rights reserved.
* The term "Broadcom" refers to Broadcom Limited and/or its subsidiaries.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* $FreeBSD$
*/
/**
* @file
* Declarations for the interface exported by ocs_fabric
*/
#if !defined(__OCS_FABRIC_H__)
#define __OCS_FABRIC_H__
extern void *__ocs_fabric_init(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg);
extern void *__ocs_fabric_flogi_wait_rsp(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg);
extern void *__ocs_fabric_domain_attach_wait(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg);
extern void *__ocs_fabric_wait_domain_attach(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg);
extern void *__ocs_vport_fabric_init(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg);
extern void *__ocs_fabric_fdisc_wait_rsp(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg);
extern void *__ocs_fabric_wait_sport_attach(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg);
extern void *__ocs_ns_init(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg);
extern void *__ocs_ns_plogi_wait_rsp(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg);
extern void *__ocs_ns_rftid_wait_rsp(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg);
extern void *__ocs_ns_rffid_wait_rsp(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg);
extern void *__ocs_ns_wait_node_attach(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg);
extern void *__ocs_fabric_wait_attach_evt_shutdown(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg);
extern void *__ocs_ns_logo_wait_rsp(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg);
extern void *__ocs_ns_gidpt_wait_rsp(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg);
extern void *__ocs_ns_idle(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg);
extern void *__ocs_ns_gidpt_delay(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg);
extern void *__ocs_fabctl_init(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg);
extern void *__ocs_fabctl_wait_node_attach(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg);
extern void *__ocs_fabctl_wait_scr_rsp(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg);
extern void *__ocs_fabctl_ready(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg);
extern void *__ocs_fabctl_wait_ls_acc_cmpl(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg);
extern void *__ocs_fabric_idle(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg);
extern void *__ocs_p2p_rnode_init(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg);
extern void *__ocs_p2p_domain_attach_wait(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg);
extern void *__ocs_p2p_wait_flogi_acc_cmpl(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg);
extern void *__ocs_p2p_wait_plogi_rsp(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg);
extern void *__ocs_p2p_wait_plogi_rsp_recvd_prli(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg);
extern void *__ocs_p2p_wait_domain_attach(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg);
extern void *__ocs_p2p_wait_node_attach(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg);
extern int32_t ocs_rnode_is_nport(fc_plogi_payload_t *remote_sparms);
extern int32_t ocs_p2p_setup(ocs_sport_t *sport);
extern void ocs_fabric_set_topology(ocs_node_t *node, ocs_sport_topology_e topology);
extern void ocs_fabric_notify_topology(ocs_node_t *node);
#endif

747
sys/dev/ocs_fc/ocs_fcp.h Normal file
View file

@ -0,0 +1,747 @@
/*-
* Copyright (c) 2017 Broadcom. All rights reserved.
* The term "Broadcom" refers to Broadcom Limited and/or its subsidiaries.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* $FreeBSD$
*/
/**
* @file
* Define Fibre Channel types and structures.
*/
#ifndef _OCS_FCP_H
#define _OCS_FCP_H
#define FC_ELS_CMD_RJT 0x01
#define FC_ELS_CMD_ACC 0x02
#define FC_ELS_CMD_PLOGI 0x03
#define FC_ELS_CMD_FLOGI 0x04
#define FC_ELS_CMD_LOGO 0x05
#define FC_ELS_CMD_RRQ 0x12
#define FC_ELS_CMD_PRLI 0x20
#define FC_ELS_CMD_PRLO 0x21
#define FC_ELS_CMD_PDISC 0x50
#define FC_ELS_CMD_FDISC 0x51
#define FC_ELS_CMD_ADISC 0x52
#define FC_ELS_CMD_RSCN 0x61
#define FC_ELS_CMD_SCR 0x62
#define FC_TYPE_BASIC_LINK 0
#define FC_TYPE_FCP 0x08
#define FC_TYPE_GS 0x20
#define FC_TYPE_SW 0x22
#define FC_ADDR_FABRIC 0xfffffe /** well known fabric address */
#define FC_ADDR_CONTROLLER 0xfffffd /** well known fabric controller address */
#define FC_ADDR_IS_DOMAIN_CTRL(x) (((x) & 0xffff00) == 0xfffc00) /** is well known domain controller */
#define FC_ADDR_GET_DOMAIN_CTRL(x) ((x) & 0x0000ff) /** get domain controller number */
#define FC_ADDR_NAMESERVER 0xfffffc /** well known directory server address */
#define FC_GS_TYPE_ALIAS_SERVICE 0xf8
#define FC_GS_TYPE_MANAGEMENT_SERVICE 0xfa
#define FC_GS_TYPE_DIRECTORY_SERVICE 0xfc
#define FC_GS_SUBTYPE_NAME_SERVER 0x02
/**
* Generic Services FC Type Bit mask macros:
*/
#define FC_GS_TYPE_WORD(type) ((type) >> 5)
#define FC_GS_TYPE_BIT(type) ((type) & 0x1f)
/**
* Generic Services Name Server Request Command codes:
*/
#define FC_GS_NAMESERVER_GPN_ID 0x0112
#define FC_GS_NAMESERVER_GNN_ID 0x0113
#define FC_GS_NAMESERVER_GFPN_ID 0x011c
#define FC_GS_NAMESERVER_GFF_ID 0x011f
#define FC_GS_NAMESERVER_GID_FT 0x0171
#define FC_GS_NAMESERVER_GID_PT 0x01a1
#define FC_GS_NAMESERVER_RHBA 0x0200
#define FC_GS_NAMESERVER_RPA 0x0211
#define FC_GS_NAMESERVER_RPN_ID 0x0212
#define FC_GS_NAMESERVER_RNN_ID 0x0213
#define FC_GS_NAMESERVER_RCS_ID 0x0214
#define FC_GS_NAMESERVER_RFT_ID 0x0217
#define FC_GS_NAMESERVER_RFF_ID 0x021f
#define FC_GS_NAMESERVER_RSNN_NN 0x0239
#define FC_GS_NAMESERVER_RSPN_ID 0x0218
#define FC_GS_REVISION 0x03
#define FC_GS_IO_PARAMS { .fc_ct.r_ctl = 0x02, \
.fc_ct.type = FC_TYPE_GS, \
.fc_ct.df_ctl = 0x00 }
typedef struct fc_vft_header_s {
uint32_t :1,
vf_id:12,
priority:3,
e:1,
:1,
type:4,
ver:2,
r_ctl:8;
uint32_t :24,
hopct:8;
} fc_vft_header_t;
#if BYTE_ORDER == LITTLE_ENDIAN
static inline uint32_t fc_be24toh(uint32_t x) { return (ocs_be32toh(x) >> 8); }
#else
static inline uint32_t fc_be24toh(uint32_t x) { }
#endif
static inline uint32_t fc_htobe24(uint32_t x) { return fc_be24toh(x); }
#define FC_SOFI3 0x2e
#define FC_SOFn3 0x36
#define FC_EOFN 0x41
#define FC_EOFT 0x42
/**
* @brief FC header in big-endian order
*/
typedef struct fc_header_s {
uint32_t info:4,
r_ctl:4,
d_id:24;
uint32_t cs_ctl:8,
s_id:24;
uint32_t type:8,
f_ctl:24;
uint32_t seq_id:8,
df_ctl:8,
seq_cnt:16;
uint32_t ox_id:16,
rx_id:16;
uint32_t parameter;
} fc_header_t;
/**
* @brief FC header in little-endian order
*/
typedef struct fc_header_le_s {
#if BYTE_ORDER == LITTLE_ENDIAN
uint32_t d_id:24,
info:4,
r_ctl:4;
uint32_t s_id:24,
cs_ctl:8;
uint32_t f_ctl:24,
type:8;
uint32_t seq_cnt:16,
df_ctl:8,
seq_id:8;
uint32_t rx_id:16,
ox_id:16;
uint32_t parameter;
#else
#error big endian version not defined
#endif
} fc_header_le_t;
/**
* @brief FC VM header in big-endian order
*/
typedef struct fc_vm_header_s {
uint32_t dst_vmid;
uint32_t src_vmid;
uint32_t rsvd0;
uint32_t rsvd1;
} fc_vm_header_t;
#define FC_DFCTL_DEVICE_HDR_16_MASK 0x1
#define FC_DFCTL_NETWORK_HDR_MASK 0x20
#define FC_DFCTL_ESP_HDR_MASK 0x40
#define FC_DFCTL_NETWORK_HDR_SIZE 16
#define FC_DFCTL_ESP_HDR_SIZE 0 //FIXME
#define FC_RCTL_FC4_DATA 0
#define FC_RCTL_ELS 2
#define FC_RCTL_BLS 8
#define FC_RCTL_INFO_UNCAT 0
#define FC_RCTL_INFO_SOL_DATA 1
#define FC_RCTL_INFO_UNSOL_CTRL 2
#define FC_RCTL_INFO_SOL_CTRL 3
#define FC_RCTL_INFO_UNSOL_DATA 4
#define FC_RCTL_INFO_DATA_DESC 5
#define FC_RCTL_INFO_UNSOL_CMD 6
#define FC_RCTL_INFO_CMD_STATUS 7
#define FC_FCTL_EXCHANGE_RESPONDER 0x800000
#define FC_FCTL_SEQUENCE_CONTEXT 0x400000
#define FC_FCTL_FIRST_SEQUENCE 0x200000
#define FC_FCTL_LAST_SEQUENCE 0x100000
#define FC_FCTL_END_SEQUENCE 0x080000
#define FC_FCTL_END_CONNECTION 0x040000
#define FC_FCTL_PRIORITY_ENABLE 0x020000
#define FC_FCTL_SEQUENCE_INITIATIVE 0x010000
#define FC_FCTL_FILL_DATA_BYTES_MASK 0x000003
/**
* Common BLS definitions:
*/
#define FC_INFO_NOP 0x0
#define FC_INFO_ABTS 0x1
#define FC_INFO_RMC 0x2
/* reserved 0x3 */
#define FC_INFO_BA_ACC 0x4
#define FC_INFO_BA_RJT 0x5
#define FC_INFO_PRMT 0x6
/* (FC-LS) LS_RJT Reason Codes */
#define FC_REASON_INVALID_COMMAND_CODE 0x01
#define FC_REASON_LOGICAL_ERROR 0x03
#define FC_REASON_LOGICAL_BUSY 0x05
#define FC_REASON_PROTOCOL_ERROR 0x07
#define FC_REASON_UNABLE_TO_PERFORM 0x09
#define FC_REASON_COMMAND_NOT_SUPPORTED 0x0b
#define FC_REASON_COMMAND_IN_PROGRESS 0x0e
#define FC_REASON_VENDOR_SPECIFIC 0xff
/* (FC-LS) LS_RJT Reason Codes Explanations */
#define FC_EXPL_NO_ADDITIONAL 0x00
#define FC_EXPL_SPARAM_OPTIONS 0x01
#define FC_EXPL_SPARAM_INITIATOR 0x03
#define FC_EXPL_SPARAM_RECPIENT 0x05
#define FC_EXPL_SPARM_DATA_SIZE 0x07
#define FC_EXPL_SPARM_CONCURRENT 0x09
#define FC_EXPL_SPARM_CREDIT 0x0b
#define FC_EXPL_INV_PORT_NAME 0x0d
#define FC_EXPL_INV_NODE_NAME 0x0e
#define FC_EXPL_INV_COMMON_SPARAMS 0x0f
#define FC_EXPL_INV_ASSOC_HEADER 0x11
#define FC_EXPL_ASSOC_HDR_REQUIRED 0x13
#define FC_EXPL_INV_ORIGINATOR_S_ID 0x15
#define FC_EXPL_INV_X_ID_COMBINATION 0x17
#define FC_EXPL_COMMAND_IN_PROGRESS 0x19
#define FC_EXPL_NPORT_LOGIN_REQUIRED 0x1e
#define FC_EXPL_N_PORT_ID 0x1f
#define FC_EXPL_INSUFFICIENT_RESOURCES 0x29
#define FC_EXPL_UNABLE_TO_SUPPLY_DATA 0x2a
#define FC_EXPL_REQUEST_NOT_SUPPORTED 0x2c
#define FC_EXPL_INV_PAYLOAD_LEN 0x1d
#define FC_EXPL_INV_PORT_NODE_NAME 0x44
#define FC_EXPL_LOGIN_EXT_NOT_SUPPORTED 0x46
#define FC_EXPL_AUTH_REQUIRED 0x48
#define FC_EXPL_SCAN_VALUE_NOT_ALLOWED 0x50
#define FC_EXPL_SCAN_VALUE_NOT_SUPPORTED 0x51
#define FC_EXPL_NO_RESOURCES_ASSIGNED 0x52
#define FC_EXPL_MAC_ADDR_MODE_NOT_SUPPORTED 0x60
#define FC_EXPL_MAC_ADDR_INCORRECTLY_FORMED 0x61
#define FC_EXPL_VN2VN_PORT_NOT_IN_NEIGHBOR_SET 0x62
#define FC_EXPL_INV_X_ID 0x03 /* invalid OX_ID - RX_ID combination */
#define FC_EXPL_SEQUENCE_ABORTED 0x05
typedef struct fc_ba_acc_payload_s {
#define FC_SEQ_ID_VALID 0x80
#define FC_SEQ_ID_INVALID 0x00
uint32_t seq_id_validity:8,
seq_id:8,
:16;
uint32_t ox_id:16,
rx_id:16;
uint32_t low_seq_cnt:16,
high_seq_cnt:16;
} fc_ba_acc_payload_t;
typedef struct fc_ba_rjt_payload_s {
uint32_t vendor_unique:8,
reason_explanation:8,
reason_code:8,
:8;
} fc_ba_rjt_payload_t;
typedef struct fc_els_gen_s {
uint32_t command_code: 8,
resv1: 24;
} fc_els_gen_t;
typedef struct fc_plogi_playload_s {
uint32_t command_code: 8,
resv1: 24;
uint32_t common_service_parameters[4];
uint32_t port_name_hi;
uint32_t port_name_lo;
uint32_t node_name_hi;
uint32_t node_name_lo;
uint32_t class1_service_parameters[4];
uint32_t class2_service_parameters[4];
uint32_t class3_service_parameters[4];
uint32_t class4_service_parameters[4];
uint32_t vendor_version_level[4];
} fc_plogi_payload_t;
typedef fc_plogi_payload_t fc_sparms_t;
typedef struct fc_logo_payload_s {
uint32_t command_code: 8,
resv1:24;
uint32_t :8,
port_id:24;
uint32_t port_name_hi;
uint32_t port_name_lo;
} fc_logo_payload_t;
typedef struct fc_acc_payload_s {
uint32_t command_code: 8,
resv1:24;
} fc_acc_payload_t;
typedef struct fc_ls_rjt_payload_s {
uint32_t command_code:8,
resv1:24;
uint32_t resv2:8,
reason_code:8,
reason_code_exp:8,
vendor_unique:8;
} fc_ls_rjt_payload_t;
typedef struct fc_prli_payload_s {
uint32_t command_code:8,
page_length:8,
payload_length:16;
uint32_t type:8,
type_ext:8,
flags:16;
uint32_t originator_pa;
uint32_t responder_pa;
uint32_t :16,
service_params:16;
} fc_prli_payload_t;
typedef struct fc_prlo_payload_s {
uint32_t command_code:8,
page_length:8,
payload_length:16;
uint32_t type:8,
type_ext:8,
:16;
uint32_t :32;
uint32_t :32;
uint32_t :32;
} fc_prlo_payload_t;
typedef struct fc_prlo_acc_payload_s {
uint32_t command_code:8,
page_length:8,
payload_length:16;
uint32_t type:8,
type_ext:8,
:4,
response_code:4,
:8;
uint32_t :32;
uint32_t :32;
uint32_t :32;
} fc_prlo_acc_payload_t;
typedef struct fc_adisc_payload_s {
uint32_t command_code:8,
payload_length:24;
uint32_t :8,
hard_address:24;
uint32_t port_name_hi;
uint32_t port_name_lo;
uint32_t node_name_hi;
uint32_t node_name_lo;
uint32_t :8,
port_id:24;
} fc_adisc_payload_t;
/* PRLI flags */
#define FC_PRLI_ORIGINATOR_PA_VALID 0x8000
#define FC_PRLI_RESPONDER_PA_VALID 0x4000
#define FC_PRLI_ESTABLISH_IMAGE_PAIR 0x2000
#define FC_PRLI_SERVICE_PARAM_INVALID 0x0800
#define FC_PRLI_REQUEST_EXECUTED 0x0100
/* PRLI Service Parameters */
#define FC_PRLI_REC_SUPPORT 0x0400
#define FC_PRLI_TASK_RETRY_ID_REQ 0x0200
#define FC_PRLI_RETRY 0x0100
#define FC_PRLI_CONFIRMED_COMPLETION 0x0080
#define FC_PRLI_DATA_OVERLAY 0x0040
#define FC_PRLI_INITIATOR_FUNCTION 0x0020
#define FC_PRLI_TARGET_FUNCTION 0x0010
#define FC_PRLI_READ_XRDY_DISABLED 0x0002
#define FC_PRLI_WRITE_XRDY_DISABLED 0x0001
/* PRLO Logout flags */
#define FC_PRLO_REQUEST_EXECUTED 0x0001
typedef struct fc_scr_payload_s {
uint32_t command_code:8,
:24;
uint32_t :24,
function:8;
} fc_scr_payload_t;
#define FC_SCR_REG_FABRIC 1
#define FC_SCR_REG_NPORT 2
#define FC_SCR_REG_FULL 3
typedef struct {
uint32_t :2,
rscn_event_qualifier:4,
address_format:2,
port_id:24;
} fc_rscn_affected_port_id_page_t;
typedef struct fc_rscn_payload_s {
uint32_t command_code:8,
page_length:8,
payload_length:16;
fc_rscn_affected_port_id_page_t port_list[1];
} fc_rscn_payload_t;
typedef struct fcct_iu_header_s {
#if BYTE_ORDER == LITTLE_ENDIAN
uint32_t revision:8,
in_id:24;
uint32_t gs_type:8,
gs_subtype:8,
options:8,
resv1:8;
uint32_t cmd_rsp_code:16,
max_residual_size:16;
uint32_t fragment_id:8,
reason_code:8,
reason_code_explanation:8,
vendor_specific:8;
#else
#error big endian version not defined
#endif
} fcct_iu_header_t;
#define FCCT_REJECT_INVALID_COMMAND_CODE 1
#define FCCT_REJECT_INVALID_VERSION_LEVEL 2
#define FCCT_LOGICAL_ERROR 3
#define FCCT_INVALID_CT_IU_SIZE 4
#define FCCT_LOGICAL_BUSY 5
#define FCCT_PROTOCOL_ERROR 7
#define FCCT_UNABLE_TO_PERFORM 9
#define FCCT_COMMAND_NOT_SUPPORTED 0x0b
#define FCCT_FABRIC_PORT_NAME_NOT_REGISTERED 0x0c
#define FCCT_SERVER_NOT_AVAILABLE 0x0d
#define FCCT_SESSION_COULD_NOT_BE_ESTABLISHED 0x0e
#define FCCT_VENDOR_SPECIFIC_ERROR 0xff
#define FCCT_NO_ADDITIONAL_EXPLANATION 0
#define FCCT_AUTHORIZATION_EXCEPTION 0xf0
#define FCCT_AUTHENTICATION_EXCEPTION 0xf1
#define FCCT_DATA_BASE_FULL 0xf2
#define FCCT_DATA_BASE_EMPTY 0xf3
#define FCCT_PROCESSING_REQUEST 0xf4
#define FCCT_UNABLE_TO_VERIFY_CONNECTION 0xf5
#define FCCT_DEVICES_NOT_IN_COMMON_ZONE 0xf6
typedef struct {
fcct_iu_header_t hdr;
#if BYTE_ORDER == LITTLE_ENDIAN
uint32_t port_id;
uint32_t fc4_types;
#else
#error big endian version not defined
#endif
} fcgs_rft_id_t;
typedef struct {
fcct_iu_header_t hdr;
#if BYTE_ORDER == LITTLE_ENDIAN
uint32_t port_id;
uint32_t :16,
fc4_features:8,
type_code:8;
#else
#error big endian version not defined
#endif
} fcgs_rff_id_t;
#pragma pack(1)
typedef struct {
fcct_iu_header_t hdr;
#if BYTE_ORDER == LITTLE_ENDIAN
uint32_t port_id;
uint64_t port_name;
#else
#error big endian version not defined
#endif
} fcgs_rpn_id_t;
#pragma pack()
#pragma pack(1)
typedef struct {
fcct_iu_header_t hdr;
#if BYTE_ORDER == LITTLE_ENDIAN
uint32_t port_id;
uint64_t node_name;
#else
#error big endian version not defined
#endif
} fcgs_rnn_id_t;
#pragma pack()
#define FCCT_CLASS_OF_SERVICE_F 0x1
#define FCCT_CLASS_OF_SERVICE_2 0x4
#define FCCT_CLASS_OF_SERVICE_3 0x8
#pragma pack(1)
typedef struct {
fcct_iu_header_t hdr;
#if BYTE_ORDER == LITTLE_ENDIAN
uint32_t port_id;
uint32_t class_of_srvc;
#else
#error big endian version not defined
#endif
} fcgs_rcs_id_t;
#pragma pack()
#pragma pack(1)
typedef struct {
fcct_iu_header_t hdr;
#if BYTE_ORDER == LITTLE_ENDIAN
uint64_t node_name;
uint8_t name_len;
char sym_node_name[1];
/*TODO: need name length and symbolic name */
#else
#error big endian version not defined
#endif
} fcgs_rsnn_nn_t;
#pragma pack()
#define FCCT_HDR_CMDRSP_ACCEPT 0x8002
#define FCCT_HDR_CMDRSP_REJECT 0x8001
static inline void fcct_build_req_header(fcct_iu_header_t *hdr, uint16_t cmd, uint16_t max_size)
{
/* use old rev (1) to accommodate older switches */
hdr->revision = 1;
hdr->in_id = 0;
hdr->gs_type = FC_GS_TYPE_DIRECTORY_SERVICE;
hdr->gs_subtype = FC_GS_SUBTYPE_NAME_SERVER;
hdr->options = 0;
hdr->resv1 = 0;
hdr->cmd_rsp_code = ocs_htobe16(cmd);
hdr->max_residual_size = ocs_htobe16(max_size/(sizeof(uint32_t))); /* words */
hdr->fragment_id = 0;
hdr->reason_code = 0;
hdr->reason_code_explanation = 0;
hdr->vendor_specific = 0;
}
typedef struct fcct_rftid_req_s {
fcct_iu_header_t hdr;
uint32_t port_id;
uint32_t fc4_types[8];
} fcct_rftid_req_t;
#define FC4_FEATURE_TARGET (1U << 0)
#define FC4_FEATURE_INITIATOR (1U << 1)
typedef struct fcct_rffid_req_s {
fcct_iu_header_t hdr;
uint32_t port_id;
uint32_t :16,
fc4_feature_bits:8,
type:8;
} fcct_rffid_req_t;
typedef struct fcct_gnnid_req_s {
fcct_iu_header_t hdr;
uint32_t :8,
port_id:24;
} fcct_gnnid_req_t;
typedef struct fcct_gpnid_req_s {
fcct_iu_header_t hdr;
uint32_t :8,
port_id:24;
} fcct_gpnid_req_t;
typedef struct fcct_gffid_req_s {
fcct_iu_header_t hdr;
uint32_t :8,
port_id:24;
} fcct_gffid_req_t;
typedef struct fcct_gidft_req_s {
fcct_iu_header_t hdr;
uint32_t :8,
domain_id_scope:8,
area_id_scope:8,
type:8;
} fcct_gidft_req_t;
typedef struct fcct_gidpt_req_s {
fcct_iu_header_t hdr;
uint32_t port_type:8,
domain_id_scope:8,
area_id_scope:8,
flags:8;
} fcct_gidpt_req_t;
typedef struct fcct_gnnid_acc_s {
fcct_iu_header_t hdr;
uint64_t node_name;
} fcct_gnnid_acc_t;
typedef struct fcct_gpnid_acc_s {
fcct_iu_header_t hdr;
uint64_t port_name;
} fcct_gpnid_acc_t;
typedef struct fcct_gffid_acc_s {
fcct_iu_header_t hdr;
uint8_t fc4_feature_bits;
} fcct_gffid_acc_t;
typedef struct fcct_gidft_acc_s {
fcct_iu_header_t hdr;
struct {
uint32_t ctl:8,
port_id:24;
} port_list[1];
} fcct_gidft_acc_t;
typedef struct fcct_gidpt_acc_s {
fcct_iu_header_t hdr;
struct {
uint32_t ctl:8,
port_id:24;
} port_list[1];
} fcct_gidpt_acc_t;
#define FCCT_GID_PT_LAST_ID 0x80
#define FCCT_GIDPT_ID_MASK 0x00ffffff
typedef struct fcp_cmnd_iu_s {
uint8_t fcp_lun[8];
uint8_t command_reference_number;
uint8_t task_attribute:3,
command_priority:4,
:1;
uint8_t task_management_flags;
uint8_t wrdata:1,
rddata:1,
additional_fcp_cdb_length:6;
uint8_t fcp_cdb[16];
uint8_t fcp_cdb_and_dl[20]; /* < May contain up to 16 bytes of CDB, followed by fcp_dl */
} fcp_cmnd_iu_t;
#define FCP_LUN_ADDRESS_METHOD_SHIFT 6
#define FCP_LUN_ADDRESS_METHOD_MASK 0xc0
#define FCP_LUN_ADDR_METHOD_PERIPHERAL 0x0
#define FCP_LUN_ADDR_METHOD_FLAT 0x1
#define FCP_LUN_ADDR_METHOD_LOGICAL 0x2
#define FCP_LUN_ADDR_METHOD_EXTENDED 0x3
#define FCP_LUN_ADDR_SIMPLE_MAX 0xff
#define FCP_LUN_ADDR_FLAT_MAX 0x3fff
#define FCP_TASK_ATTR_SIMPLE 0x0
#define FCP_TASK_ATTR_HEAD_OF_QUEUE 0x1
#define FCP_TASK_ATTR_ORDERED 0x2
#define FCP_TASK_ATTR_ACA 0x4
#define FCP_TASK_ATTR_UNTAGGED 0x5
#define FCP_QUERY_TASK_SET BIT(0)
#define FCP_ABORT_TASK_SET BIT(1)
#define FCP_CLEAR_TASK_SET BIT(2)
#define FCP_QUERY_ASYNCHRONOUS_EVENT BIT(3)
#define FCP_LOGICAL_UNIT_RESET BIT(4)
#define FCP_TARGET_RESET BIT(5)
#define FCP_CLEAR_ACA BIT(6)
/* SPC-4 says that the maximum length of sense data is 252 bytes */
#define FCP_MAX_SENSE_LEN 252
#define FCP_MAX_RSP_LEN 8
/*
* FCP_RSP buffer will either have sense or response data, but not both
* so pick the larger.
*/
#define FCP_MAX_RSP_INFO_LEN FCP_MAX_SENSE_LEN
typedef struct fcp_rsp_iu_s {
uint8_t rsvd[8];
uint8_t status_qualifier[2];
uint8_t flags;
uint8_t scsi_status;
uint8_t fcp_resid[4];
uint8_t fcp_sns_len[4];
uint8_t fcp_rsp_len[4];
uint8_t data[FCP_MAX_RSP_INFO_LEN];
} fcp_rsp_iu_t;
/** Flag field defines: */
#define FCP_RSP_LEN_VALID BIT(0)
#define FCP_SNS_LEN_VALID BIT(1)
#define FCP_RESID_OVER BIT(2)
#define FCP_RESID_UNDER BIT(3)
#define FCP_CONF_REQ BIT(4)
#define FCP_BIDI_READ_RESID_OVER BIT(5)
#define FCP_BIDI_READ_RESID_UNDER BIT(6)
#define FCP_BIDI_RSP BIT(7)
/** Status values: */
#define FCP_TMF_COMPLETE 0x00
#define FCP_DATA_LENGTH_MISMATCH 0x01
#define FCP_INVALID_FIELD 0x02
#define FCP_DATA_RO_MISMATCH 0x03
#define FCP_TMF_REJECTED 0x04
#define FCP_TMF_FAILED 0x05
#define FCP_TMF_SUCCEEDED 0x08
#define FCP_TMF_INCORRECT_LUN 0x09
/** FCP-4 Table 28, TMF response information: */
typedef struct fc_rsp_info_s {
uint8_t addl_rsp_info[3];
uint8_t rsp_code;
uint32_t :32;
} fcp_rsp_info_t;
typedef struct fcp_xfer_rdy_iu_s {
uint8_t fcp_data_ro[4];
uint8_t fcp_burst_len[4];
uint8_t rsvd[4];
} fcp_xfer_rdy_iu_t;
#define MAX_ACC_REJECT_PAYLOAD (sizeof(fc_ls_rjt_payload_t) > sizeof(fc_acc_payload_t) ? sizeof(fc_ls_rjt_payload_t) : sizeof(fc_acc_payload_t))
#endif /* !_OCS_FCP_H */

12551
sys/dev/ocs_fc/ocs_hw.c Normal file

File diff suppressed because it is too large Load diff

1547
sys/dev/ocs_fc/ocs_hw.h Normal file

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,97 @@
/*-
* Copyright (c) 2017 Broadcom. All rights reserved.
* The term "Broadcom" refers to Broadcom Limited and/or its subsidiaries.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* $FreeBSD$
*/
/**
* @file
*
*/
#ifndef __OCS_HW_QUEUES_H__
#define __OCS_HW_QUEUES_H__
#define OCS_HW_MQ_DEPTH 128
typedef enum {
QTOP_EQ = 0,
QTOP_CQ,
QTOP_WQ,
QTOP_RQ,
QTOP_MQ,
QTOP_LAST,
} ocs_hw_qtop_entry_e;
typedef struct {
ocs_hw_qtop_entry_e entry;
uint8_t set_default;
uint32_t len;
uint8_t class;
uint8_t ulp;
uint8_t filter_mask;
} ocs_hw_qtop_entry_t;
typedef struct {
struct rq_config {
hw_eq_t *eq;
uint32_t len;
uint8_t class;
uint8_t ulp;
uint8_t filter_mask;
} rq_cfg[16];
uint32_t num_pairs;
} ocs_hw_mrq_t;
#define MAX_TOKENS 256
#define OCS_HW_MAX_QTOP_ENTRIES 200
typedef struct {
ocs_os_handle_t os;
ocs_hw_qtop_entry_t *entries;
uint32_t alloc_count;
uint32_t inuse_count;
uint32_t entry_counts[QTOP_LAST];
uint32_t rptcount[10];
uint32_t rptcount_idx;
} ocs_hw_qtop_t;
extern ocs_hw_qtop_t *ocs_hw_qtop_parse(ocs_hw_t *hw, const char *qtop_string);
extern void ocs_hw_qtop_free(ocs_hw_qtop_t *qtop);
extern const char *ocs_hw_qtop_entry_name(ocs_hw_qtop_entry_e entry);
extern uint32_t ocs_hw_qtop_eq_count(ocs_hw_t *hw);
extern ocs_hw_rtn_e ocs_hw_init_queues(ocs_hw_t *hw, ocs_hw_qtop_t *qtop);
extern void hw_thread_eq_handler(ocs_hw_t *hw, hw_eq_t *eq, uint32_t max_isr_time_msec);
extern void hw_thread_cq_handler(ocs_hw_t *hw, hw_cq_t *cq);
extern hw_wq_t *ocs_hw_queue_next_wq(ocs_hw_t *hw, ocs_hw_io_t *io);
#endif /* __OCS_HW_QUEUES_H__ */

491
sys/dev/ocs_fc/ocs_io.c Normal file
View file

@ -0,0 +1,491 @@
/*-
* Copyright (c) 2017 Broadcom. All rights reserved.
* The term "Broadcom" refers to Broadcom Limited and/or its subsidiaries.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* $FreeBSD$
*/
/**
* @file
* Provide IO object allocation.
*/
/*!
* @defgroup io_alloc IO allocation
*/
#include "ocs.h"
#include "ocs_scsi.h"
#include "ocs_els.h"
#include "ocs_utils.h"
void ocs_mgmt_io_list(ocs_textbuf_t *textbuf, void *io);
void ocs_mgmt_io_get_all(ocs_textbuf_t *textbuf, void *io);
int ocs_mgmt_io_get(ocs_textbuf_t *textbuf, char *parent, char *name, void *io);
static ocs_mgmt_functions_t io_mgmt_functions = {
.get_list_handler = ocs_mgmt_io_list,
.get_handler = ocs_mgmt_io_get,
.get_all_handler = ocs_mgmt_io_get_all,
};
/**
* @brief IO pool.
*
* Structure encapsulating a pool of IO objects.
*
*/
struct ocs_io_pool_s {
ocs_t *ocs; /* Pointer to device object */
ocs_lock_t lock; /* IO pool lock */
uint32_t io_num_ios; /* Total IOs allocated */
ocs_pool_t *pool;
};
/**
* @brief Create a pool of IO objects.
*
* @par Description
* This function allocates memory in larger chucks called
* "slabs" which are a fixed size. It calculates the number of IO objects that
* fit within each "slab" and determines the number of "slabs" required to
* allocate the number of IOs requested. Each of the slabs is allocated and
* then it grabs each IO object within the slab and adds it to the free list.
* Individual command, response and SGL DMA buffers are allocated for each IO.
*
* "Slabs"
* +----------------+
* | |
* +----------------+ |
* | IO | |
* +----------------+ |
* | ... | |
* +----------------+__+
* | IO |
* +----------------+
*
* @param ocs Driver instance's software context.
* @param num_io Number of IO contexts to allocate.
* @param num_sgl Number of SGL entries to allocate for each IO.
*
* @return Returns a pointer to a new ocs_io_pool_t on success,
* or NULL on failure.
*/
ocs_io_pool_t *
ocs_io_pool_create(ocs_t *ocs, uint32_t num_io, uint32_t num_sgl)
{
uint32_t i = 0;
int32_t rc = -1;
ocs_io_pool_t *io_pool;
/* Allocate the IO pool */
io_pool = ocs_malloc(ocs, sizeof(*io_pool), OCS_M_ZERO | OCS_M_NOWAIT);
if (io_pool == NULL) {
ocs_log_err(ocs, "allocate of IO pool failed\n");
return NULL;;
}
io_pool->ocs = ocs;
io_pool->io_num_ios = num_io;
/* initialize IO pool lock */
ocs_lock_init(ocs, &io_pool->lock, "io_pool lock[%d]", ocs->instance_index);
io_pool->pool = ocs_pool_alloc(ocs, sizeof(ocs_io_t), io_pool->io_num_ios, FALSE);
for (i = 0; i < io_pool->io_num_ios; i++) {
ocs_io_t *io = ocs_pool_get_instance(io_pool->pool, i);
io->tag = i;
io->instance_index = i;
io->ocs = ocs;
/* allocate a command/response dma buffer */
if (ocs->enable_ini) {
rc = ocs_dma_alloc(ocs, &io->cmdbuf, SCSI_CMD_BUF_LENGTH, OCS_MIN_DMA_ALIGNMENT);
if (rc) {
ocs_log_err(ocs, "ocs_dma_alloc cmdbuf failed\n");
ocs_io_pool_free(io_pool);
return NULL;
}
}
/* Allocate a response buffer */
rc = ocs_dma_alloc(ocs, &io->rspbuf, SCSI_RSP_BUF_LENGTH, OCS_MIN_DMA_ALIGNMENT);
if (rc) {
ocs_log_err(ocs, "ocs_dma_alloc cmdbuf failed\n");
ocs_io_pool_free(io_pool);
return NULL;
}
/* Allocate SGL */
io->sgl = ocs_malloc(ocs, sizeof(*io->sgl) * num_sgl, OCS_M_NOWAIT | OCS_M_ZERO);
if (io->sgl == NULL) {
ocs_log_err(ocs, "malloc sgl's failed\n");
ocs_io_pool_free(io_pool);
return NULL;
}
io->sgl_allocated = num_sgl;
io->sgl_count = 0;
/* Make IO backend call to initialize IO */
ocs_scsi_tgt_io_init(io);
ocs_scsi_ini_io_init(io);
rc = ocs_dma_alloc(ocs, &io->els_req, OCS_ELS_REQ_LEN, OCS_MIN_DMA_ALIGNMENT);
if (rc) {
ocs_log_err(ocs, "ocs_dma_alloc els_req failed\n");
ocs_io_pool_free(io_pool);
return NULL;
}
rc = ocs_dma_alloc(ocs, &io->els_rsp, OCS_ELS_GID_PT_RSP_LEN, OCS_MIN_DMA_ALIGNMENT);
if (rc) {
ocs_log_err(ocs, "ocs_dma_alloc els_rsp failed\n");
ocs_io_pool_free(io_pool);
return NULL;
}
}
return io_pool;
}
/**
* @brief Free IO objects pool
*
* @par Description
* The pool of IO objects are freed.
*
* @param io_pool Pointer to IO pool object.
*
* @return Returns 0 on success, or a negative error code value on failure.
*/
int32_t
ocs_io_pool_free(ocs_io_pool_t *io_pool)
{
ocs_t *ocs;
uint32_t i;
ocs_io_t *io;
if (io_pool != NULL) {
ocs = io_pool->ocs;
for (i = 0; i < io_pool->io_num_ios; i++) {
io = ocs_pool_get_instance(io_pool->pool, i);
if (!io)
continue;
ocs_scsi_tgt_io_exit(io);
ocs_scsi_ini_io_exit(io);
if (io->sgl) {
ocs_free(ocs, io->sgl, sizeof(*io->sgl) * io->sgl_allocated);
}
ocs_dma_free(ocs, &io->cmdbuf);
ocs_dma_free(ocs, &io->rspbuf);
ocs_dma_free(ocs, &io->els_req);
ocs_dma_free(ocs, &io->els_rsp);
}
if (io_pool->pool != NULL) {
ocs_pool_free(io_pool->pool);
}
ocs_lock_free(&io_pool->lock);
ocs_free(ocs, io_pool, sizeof(*io_pool));
ocs->xport->io_pool = NULL;
}
return 0;
}
uint32_t ocs_io_pool_allocated(ocs_io_pool_t *io_pool)
{
return io_pool->io_num_ios;
}
/**
* @ingroup io_alloc
* @brief Allocate an object used to track an IO.
*
* @param io_pool Pointer to the IO pool.
*
* @return Returns the pointer to a new object, or NULL if none available.
*/
ocs_io_t *
ocs_io_pool_io_alloc(ocs_io_pool_t *io_pool)
{
ocs_io_t *io = NULL;
ocs_t *ocs;
ocs_assert(io_pool, NULL);
ocs = io_pool->ocs;
ocs_lock(&io_pool->lock);
if ((io = ocs_pool_get(io_pool->pool)) != NULL) {
ocs_unlock(&io_pool->lock);
io->io_type = OCS_IO_TYPE_MAX;
io->hio_type = OCS_HW_IO_MAX;
io->hio = NULL;
io->transferred = 0;
io->ocs = ocs;
io->timeout = 0;
io->sgl_count = 0;
io->tgt_task_tag = 0;
io->init_task_tag = 0;
io->hw_tag = 0;
io->display_name = "pending";
io->seq_init = 0;
io->els_req_free = 0;
io->mgmt_functions = &io_mgmt_functions;
io->io_free = 0;
ocs_atomic_add_return(&ocs->xport->io_active_count, 1);
ocs_atomic_add_return(&ocs->xport->io_total_alloc, 1);
} else {
ocs_unlock(&io_pool->lock);
}
return io;
}
/**
* @ingroup io_alloc
* @brief Free an object used to track an IO.
*
* @param io_pool Pointer to IO pool object.
* @param io Pointer to the IO object.
*/
void
ocs_io_pool_io_free(ocs_io_pool_t *io_pool, ocs_io_t *io)
{
ocs_t *ocs;
ocs_hw_io_t *hio = NULL;
ocs_assert(io_pool);
ocs = io_pool->ocs;
ocs_lock(&io_pool->lock);
hio = io->hio;
io->hio = NULL;
ocs_pool_put(io_pool->pool, io);
ocs_unlock(&io_pool->lock);
if (hio) {
ocs_hw_io_free(&ocs->hw, hio);
}
io->io_free = 1;
ocs_atomic_sub_return(&ocs->xport->io_active_count, 1);
ocs_atomic_add_return(&ocs->xport->io_total_free, 1);
}
/**
* @ingroup io_alloc
* @brief Find an I/O given it's node and ox_id.
*
* @param ocs Driver instance's software context.
* @param node Pointer to node.
* @param ox_id OX_ID to find.
* @param rx_id RX_ID to find (0xffff for unassigned).
*/
ocs_io_t *
ocs_io_find_tgt_io(ocs_t *ocs, ocs_node_t *node, uint16_t ox_id, uint16_t rx_id)
{
ocs_io_t *io = NULL;
ocs_lock(&node->active_ios_lock);
ocs_list_foreach(&node->active_ios, io)
if ((io->cmd_tgt && (io->init_task_tag == ox_id)) &&
((rx_id == 0xffff) || (io->tgt_task_tag == rx_id))) {
break;
}
ocs_unlock(&node->active_ios_lock);
return io;
}
/**
* @ingroup io_alloc
* @brief Return IO context given the instance index.
*
* @par Description
* Returns a pointer to the IO context given by the instance index.
*
* @param ocs Pointer to driver structure.
* @param index IO instance index to return.
*
* @return Returns a pointer to the IO context, or NULL if not found.
*/
ocs_io_t *
ocs_io_get_instance(ocs_t *ocs, uint32_t index)
{
ocs_xport_t *xport = ocs->xport;
ocs_io_pool_t *io_pool = xport->io_pool;
return ocs_pool_get_instance(io_pool->pool, index);
}
/**
* @brief Generate IO context ddump data.
*
* The ddump data for an IO context is generated.
*
* @param textbuf Pointer to text buffer.
* @param io Pointer to IO context.
*
* @return None.
*/
void
ocs_ddump_io(ocs_textbuf_t *textbuf, ocs_io_t *io)
{
ocs_ddump_section(textbuf, "io", io->instance_index);
ocs_ddump_value(textbuf, "display_name", "%s", io->display_name);
ocs_ddump_value(textbuf, "node_name", "%s", io->node->display_name);
ocs_ddump_value(textbuf, "ref_count", "%d", ocs_ref_read_count(&io->ref));
ocs_ddump_value(textbuf, "io_type", "%d", io->io_type);
ocs_ddump_value(textbuf, "hio_type", "%d", io->hio_type);
ocs_ddump_value(textbuf, "cmd_tgt", "%d", io->cmd_tgt);
ocs_ddump_value(textbuf, "cmd_ini", "%d", io->cmd_ini);
ocs_ddump_value(textbuf, "send_abts", "%d", io->send_abts);
ocs_ddump_value(textbuf, "init_task_tag", "0x%x", io->init_task_tag);
ocs_ddump_value(textbuf, "tgt_task_tag", "0x%x", io->tgt_task_tag);
ocs_ddump_value(textbuf, "hw_tag", "0x%x", io->hw_tag);
ocs_ddump_value(textbuf, "tag", "0x%x", io->tag);
ocs_ddump_value(textbuf, "timeout", "%d", io->timeout);
ocs_ddump_value(textbuf, "tmf_cmd", "%d", io->tmf_cmd);
ocs_ddump_value(textbuf, "abort_rx_id", "0x%x", io->abort_rx_id);
ocs_ddump_value(textbuf, "busy", "%d", ocs_io_busy(io));
ocs_ddump_value(textbuf, "transferred", "%zu", io->transferred);
ocs_ddump_value(textbuf, "auto_resp", "%d", io->auto_resp);
ocs_ddump_value(textbuf, "exp_xfer_len", "%d", io->exp_xfer_len);
ocs_ddump_value(textbuf, "xfer_req", "%d", io->xfer_req);
ocs_ddump_value(textbuf, "seq_init", "%d", io->seq_init);
ocs_ddump_value(textbuf, "alloc_link", "%d", ocs_list_on_list(&io->io_alloc_link));
ocs_ddump_value(textbuf, "pending_link", "%d", ocs_list_on_list(&io->io_pending_link));
ocs_ddump_value(textbuf, "backend_link", "%d", ocs_list_on_list(&io->link));
if (io->hio) {
ocs_ddump_value(textbuf, "hw_tag", "%#x", io->hio->reqtag);
ocs_ddump_value(textbuf, "hw_xri", "%#x", io->hio->indicator);
ocs_ddump_value(textbuf, "hw_type", "%#x", io->hio->type);
} else {
ocs_ddump_value(textbuf, "hw_tag", "%s", "pending");
ocs_ddump_value(textbuf, "hw_xri", "%s", "pending");
ocs_ddump_value(textbuf, "hw_type", "%s", "pending");
}
ocs_scsi_ini_ddump(textbuf, OCS_SCSI_DDUMP_IO, io);
ocs_scsi_tgt_ddump(textbuf, OCS_SCSI_DDUMP_IO, io);
ocs_ddump_endsection(textbuf, "io", io->instance_index);
}
void
ocs_mgmt_io_list(ocs_textbuf_t *textbuf, void *object)
{
/* Readonly values */
ocs_mgmt_emit_property_name(textbuf, MGMT_MODE_RD, "display_name");
ocs_mgmt_emit_property_name(textbuf, MGMT_MODE_RD, "init_task_tag");
ocs_mgmt_emit_property_name(textbuf, MGMT_MODE_RD, "tag");
ocs_mgmt_emit_property_name(textbuf, MGMT_MODE_RD, "transferred");
ocs_mgmt_emit_property_name(textbuf, MGMT_MODE_RD, "auto_resp");
ocs_mgmt_emit_property_name(textbuf, MGMT_MODE_RD, "exp_xfer_len");
ocs_mgmt_emit_property_name(textbuf, MGMT_MODE_RD, "xfer_req");
}
int
ocs_mgmt_io_get(ocs_textbuf_t *textbuf, char *parent, char *name, void *object)
{
char qualifier[80];
int retval = -1;
ocs_io_t *io = (ocs_io_t *) object;
snprintf(qualifier, sizeof(qualifier), "%s/io[%d]", parent, io->instance_index);
/* If it doesn't start with my qualifier I don't know what to do with it */
if (ocs_strncmp(name, qualifier, strlen(qualifier)) == 0) {
char *unqualified_name = name + strlen(qualifier) +1;
/* See if it's a value I can supply */
if (ocs_strcmp(unqualified_name, "display_name") == 0) {
ocs_mgmt_emit_string(textbuf, MGMT_MODE_RD, "display_name", io->display_name);
retval = 0;
} else if (ocs_strcmp(unqualified_name, "init_task_tag") == 0) {
ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "init_task_tag", "0x%x", io->init_task_tag);
retval = 0;
} else if (ocs_strcmp(unqualified_name, "tgt_task_tag") == 0) {
ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "tgt_task_tag", "0x%x", io->tgt_task_tag);
retval = 0;
} else if (ocs_strcmp(unqualified_name, "hw_tag") == 0) {
ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "hw_tag", "0x%x", io->hw_tag);
retval = 0;
} else if (ocs_strcmp(unqualified_name, "tag") == 0) {
ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "tag", "0x%x", io->tag);
retval = 0;
} else if (ocs_strcmp(unqualified_name, "transferred") == 0) {
ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "transferred", "%zu", io->transferred);
retval = 0;
} else if (ocs_strcmp(unqualified_name, "auto_resp") == 0) {
ocs_mgmt_emit_boolean(textbuf, MGMT_MODE_RD, "auto_resp", io->auto_resp);
retval = 0;
} else if (ocs_strcmp(unqualified_name, "exp_xfer_len") == 0) {
ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "exp_xfer_len", "%d", io->exp_xfer_len);
retval = 0;
} else if (ocs_strcmp(unqualified_name, "xfer_req") == 0) {
ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "xfer_req", "%d", io->xfer_req);
retval = 0;
}
}
return retval;
}
void
ocs_mgmt_io_get_all(ocs_textbuf_t *textbuf, void *object)
{
ocs_io_t *io = (ocs_io_t *) object;
ocs_mgmt_emit_string(textbuf, MGMT_MODE_RD, "display_name", io->display_name);
ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "init_task_tag", "0x%x", io->init_task_tag);
ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "tgt_task_tag", "0x%x", io->tgt_task_tag);
ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "hw_tag", "0x%x", io->hw_tag);
ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "tag", "0x%x", io->tag);
ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "transferred", "%zu", io->transferred);
ocs_mgmt_emit_boolean(textbuf, MGMT_MODE_RD, "auto_resp", io->auto_resp);
ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "exp_xfer_len", "%d", io->exp_xfer_len);
ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "xfer_req", "%d", io->xfer_req);
}

196
sys/dev/ocs_fc/ocs_io.h Normal file
View file

@ -0,0 +1,196 @@
/*-
* Copyright (c) 2017 Broadcom. All rights reserved.
* The term "Broadcom" refers to Broadcom Limited and/or its subsidiaries.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* $FreeBSD$
*/
/**
* @file
* OCS linux driver IO declarations
*/
#if !defined(__OCS_IO_H__)
#define __OCS_IO_H__
#define io_error_log(io, fmt, ...) \
do { \
if (OCS_LOG_ENABLE_IO_ERRORS(io->ocs)) \
ocs_log_warn(io->ocs, fmt, ##__VA_ARGS__); \
} while (0)
/**
* @brief FCP IO context
*
* This structure is used for transport and backend IO requests and responses.
*/
#define SCSI_CMD_BUF_LENGTH 48
#define SCSI_RSP_BUF_LENGTH sizeof(fcp_rsp_iu_t)
/**
* @brief OCS IO types
*/
typedef enum {
OCS_IO_TYPE_IO = 0,
OCS_IO_TYPE_ELS,
OCS_IO_TYPE_CT,
OCS_IO_TYPE_CT_RESP,
OCS_IO_TYPE_BLS_RESP,
OCS_IO_TYPE_ABORT,
OCS_IO_TYPE_MAX, /**< must be last */
} ocs_io_type_e;
struct ocs_io_s {
ocs_t *ocs; /**< pointer back to ocs */
uint32_t instance_index; /**< unique instance index value */
const char *display_name; /**< display name */
ocs_node_t *node; /**< pointer to node */
ocs_list_link_t io_alloc_link; /**< (io_pool->io_free_list) free list link */
uint32_t init_task_tag; /**< initiator task tag (OX_ID) for back-end and SCSI logging */
uint32_t tgt_task_tag; /**< target task tag (RX_ID) - for back-end and SCSI logging */
uint32_t hw_tag; /**< HW layer unique IO id - for back-end and SCSI logging */
uint32_t tag; /**< unique IO identifier */
ocs_scsi_sgl_t *sgl; /**< SGL */
uint32_t sgl_allocated; /**< Number of allocated SGEs */
uint32_t sgl_count; /**< Number of SGEs in this SGL */
ocs_scsi_ini_io_t ini_io; /**< backend initiator private IO data */
ocs_scsi_tgt_io_t tgt_io; /**< backend target private IO data */
uint32_t exp_xfer_len; /**< expected data transfer length, based on FC or iSCSI header */
ocs_mgmt_functions_t *mgmt_functions;
/* Declarations private to HW/SLI */
void *hw_priv; /**< HW private context */
/* Declarations private to FC Transport */
ocs_io_type_e io_type; /**< indicates what this ocs_io_t structure is used for */
ocs_ref_t ref; /**< refcount object */
void *dslab_item; /**< pointer back to dslab allocation object */
ocs_hw_io_t *hio; /**< HW IO context */
size_t transferred; /**< Number of bytes transferred so far */
uint32_t auto_resp:1, /**< set if auto_trsp was set */
low_latency:1, /**< set if low latency request */
wq_steering:4, /**< selected WQ steering request */
wq_class:4; /**< selected WQ class if steering is class */
uint32_t xfer_req; /**< transfer size for current request */
ocs_scsi_rsp_io_cb_t scsi_ini_cb; /**< initiator callback function */
void *scsi_ini_cb_arg; /**< initiator callback function argument */
ocs_scsi_io_cb_t scsi_tgt_cb; /**< target callback function */
void *scsi_tgt_cb_arg; /**< target callback function argument */
ocs_scsi_io_cb_t abort_cb; /**< abort callback function */
void *abort_cb_arg; /**< abort callback function argument */
ocs_scsi_io_cb_t bls_cb; /**< BLS callback function */
void *bls_cb_arg; /**< BLS callback function argument */
ocs_scsi_tmf_cmd_e tmf_cmd; /**< TMF command being processed */
uint16_t abort_rx_id; /**< rx_id from the ABTS that initiated the command abort */
uint32_t cmd_tgt:1, /**< True if this is a Target command */
send_abts:1, /**< when aborting, indicates ABTS is to be sent */
cmd_ini:1, /**< True if this is an Initiator command */
seq_init:1; /**< True if local node has sequence initiative */
ocs_hw_io_param_t iparam; /**< iparams for hw io send call */
ocs_hw_dif_info_t hw_dif; /**< HW formatted DIF parameters */
ocs_scsi_dif_info_t scsi_dif_info; /**< DIF info saved for DIF error recovery */
ocs_hw_io_type_e hio_type; /**< HW IO type */
uint32_t wire_len; /**< wire length */
void *hw_cb; /**< saved HW callback */
ocs_list_link_t io_pending_link;/**< link list link pending */
ocs_dma_t ovfl_sgl; /**< Overflow SGL */
/* for ELS requests/responses */
uint32_t els_pend:1, /**< True if ELS is pending */
els_active:1; /**< True if ELS is active */
ocs_dma_t els_req; /**< ELS request payload buffer */
ocs_dma_t els_rsp; /**< ELS response payload buffer */
ocs_sm_ctx_t els_sm; /**< EIO IO state machine context */
uint32_t els_evtdepth; /**< current event posting nesting depth */
uint32_t els_req_free:1; /**< this els is to be free'd */
uint32_t els_retries_remaining; /*<< Retries remaining */
void (*els_callback)(ocs_node_t *node, ocs_node_cb_t *cbdata, void *cbarg);
void *els_callback_arg;
uint32_t els_timeout_sec; /**< timeout */
ocs_timer_t delay_timer; /**< delay timer */
/* for abort handling */
ocs_io_t *io_to_abort; /**< pointer to IO to abort */
ocs_list_link_t link; /**< linked list link */
ocs_dma_t cmdbuf; /**< SCSI Command buffer, used for CDB (initiator) */
ocs_dma_t rspbuf; /**< SCSI Response buffer (i+t) */
uint32_t timeout; /**< Timeout value in seconds for this IO */
uint8_t cs_ctl; /**< CS_CTL priority for this IO */
uint8_t io_free; /**< Is io object in freelist > */
uint32_t app_id;
};
/**
* @brief common IO callback argument
*
* Callback argument used as common I/O callback argument
*/
typedef struct {
int32_t status; /**< completion status */
int32_t ext_status; /**< extended completion status */
void *app; /**< application argument */
} ocs_io_cb_arg_t;
/**
* @brief Test if IO object is busy
*
* Return True if IO object is busy. Busy is defined as the IO object not being on
* the free list
*
* @param io Pointer to IO object
*
* @return returns True if IO is busy
*/
static inline int32_t
ocs_io_busy(ocs_io_t *io)
{
return !(io->io_free);
}
typedef struct ocs_io_pool_s ocs_io_pool_t;
extern ocs_io_pool_t *ocs_io_pool_create(ocs_t *ocs, uint32_t num_io, uint32_t num_sgl);
extern int32_t ocs_io_pool_free(ocs_io_pool_t *io_pool);
extern uint32_t ocs_io_pool_allocated(ocs_io_pool_t *io_pool);
extern ocs_io_t *ocs_io_pool_io_alloc(ocs_io_pool_t *io_pool);
extern void ocs_io_pool_io_free(ocs_io_pool_t *io_pool, ocs_io_t *io);
extern ocs_io_t *ocs_io_find_tgt_io(ocs_t *ocs, ocs_node_t *node, uint16_t ox_id, uint16_t rx_id);
extern void ocs_ddump_io(ocs_textbuf_t *textbuf, ocs_io_t *io);
#endif

1253
sys/dev/ocs_fc/ocs_ioctl.c Normal file

File diff suppressed because it is too large Load diff

368
sys/dev/ocs_fc/ocs_ioctl.h Normal file
View file

@ -0,0 +1,368 @@
/*-
* Copyright (c) 2017 Broadcom. All rights reserved.
* The term "Broadcom" refers to Broadcom Limited and/or its subsidiaries.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* $FreeBSD$
*/
/**
* @file
* Common declartaions for the driver's IOCTL interface
*/
#if !defined(__OCS_IOCTL_H__)
#define __OCS_IOCTL_H__
/**
* @brief OCS test ioctl
*
* Simple structure for testing the IOCTL interface
*/
typedef struct {
char string[32]; /**< fixed string buffer */
} ocs_ioctl_test_t;
/**
* @brief DRIVER_INFO ioctl structure
*
* Structure is returned whtn the OCS_IOCTL_CMD_DRIVER_INFO is issued by a user space program.
*/
typedef struct {
uint16_t pci_vendor; /**< PCI vender ID value (binary) */
uint16_t pci_device; /**< PCI device ID value (binary) */
char businfo[16]; /**< Bus information (text) */
uint32_t sli_intf; /**< SLI_INTF register value (binary) */
char desc[64]; /**< description (text) */
char fw_rev[32]; /**< firmware revision (text) */
union {
struct {
uint8_t wwnn[8]; /**< WWNN (binary) */
uint8_t wwpn[8]; /**< WWPN (binary) */
} fc;
struct {
uint8_t mac_addr[6]; /**< MAC address (binary) */
uint8_t reserved[10];
} iscsi;
} hw_addr;
char serialnum[32]; /**< board serial number (text) */
} ocs_ioctl_driver_info_t;
#define ELXU_BSD_MAGIC 0x30584c45
/**
* @brief IOCTL_CMD_IOCTL_ELXU_MBOX ioctl structure
*
* Structure used to submit elxsdkutil mailbox requests for firmware download and
* dump file retrieveal.
*/
typedef struct {
uint32_t magic; /**< magic number */
uint32_t size; /**< size of MBX command */
uint8_t payload[256]; /**< MBX command in/out payload buffer */
uint64_t in_addr; /**< user space address of input buffer */
uint64_t in_bytes; /**< length of user space input buffer in bytes */
uint64_t out_addr; /**< user space address of output buffer */
uint64_t out_bytes; /**< length of user space output buffer in bytes */
} ocs_ioctl_elxu_mbox_t;
enum {
ocs_ioctl_scsi_cmd_loop, /**< Start command loop */
ocs_ioctl_scsi_cmd_loop_wait, /**< Start command loop and wait for completion */
ocs_ioctl_scsi_cmd_stop, /**< Stop command loop */
ocs_ioctl_scsi_cmd, /**< Start one command */
ocs_ioctl_scsi_cmd_wait, /**< Wait for a command to complete */
ocs_ioctl_scsi_cmd_abort, /**< Start an abort */
ocs_ioctl_scsi_cmd_tmf, /**< Start a tmf */
ocs_ioctl_els_send, /**< Start an ELS */
ocs_ioctl_tgt_logout, /**< logout of a target */
ocs_ioctl_scsi_cmd_wait_any, /**< Wait for any command to complete */
};
enum {
ocs_ioctl_scsi_cmd_rd = (1U << 0), /**< direction is read */
ocs_ioctl_scsi_cmd_wr = (1U << 1), /**< direction is write */
};
/**
* @brief OCS_IOCTL_CMD_SCSI_CMD ioctl command structure
*/
typedef enum {
DIF_OP_DISABLE = 0,
DIF_OP_IN_NODIF_OUT_CRC,
DIF_OP_IN_CRC_OUT_NODIF,
DIF_OP_IN_NODIF_OUT_CHKSUM,
DIF_OP_IN_CHKSUM_OUT_NODIF,
DIF_OP_IN_CRC_OUT_CRC,
DIF_OP_IN_CHKSUM_OUT_CHKSUM,
DIF_OP_IN_CRC_OUT_CHKSUM,
DIF_OP_IN_CHKSUM_OUT_CRC,
DIF_OP_IN_RAW_OUT_RAW,
} dif_op_t;
#define DIF_OP_PASS_THRU DIF_OP_IN_CRC_OUT_CRC
#define DIF_OP_STRIP DIF_OP_IN_CRC_OUT_NODIF
#define DIF_OP_INSERT DIF_OP_IN_NODIF_OUT_CRC
typedef struct {
dif_op_t dif_op;
uint32_t
check_ref_tag:1, /* check reference tag on initiator writes */
check_app_tag:1, /* check application tag on initiator writes */
check_guard:1, /* check CRC on initiator writes */
dif_separate:1; /* use DIF separate transfers */
uint32_t ref_tag; /* DIF reference tag */
uint16_t app_tag; /* DIF application tag */
uint32_t blocksize; /* DIF blocksize */
} dif_info_t;
typedef struct {
int command; /**< SCSI command request command */
uint32_t target_idx; /**< Target device index */
uint32_t dir; /**< rd or wr */
uint32_t lun; /**< lun value */
int32_t tmf; /**< TMF */
uint8_t cdb[32]; /**< SCSI CDB */
uint32_t cdb_len; /**< SCSI CDB length in bytes */
uint32_t els_cmd; /**< ELS command */
uint32_t flags; /**< command flags */
uint32_t queue_depth; /**< queue depth for command looping */
uint32_t payload_length; /**< payload length for command */
uint32_t dif_payload_length; /**< DIF payload length for command if separate */
uint32_t io_count; /**< command count for looping */
uint32_t io_timeout; /**< IO timeout in seconds (0 = no timeout) */
uint32_t directio; /**< If set, DMA to and from user buffers */
uint32_t first_burst:1; /**< If true send IO writes with first burst */
uint32_t first_burst_size; /**< If first burst is enabled, then this size */
int32_t wait_timeout_usec; /**< Wait timeout (usec) for wait, wait_any */
/* T10-PI */
dif_info_t dif; /* DIF info */
/* user space buffers */
void *payload; /**< pointer to user space payload buffer */
void *dif_payload; /**< pointer to DIF block data if separate */
uint8_t scsi_status; /**< SCSI status */
uint16_t scsi_status_qualifier; /**< SCSI status qualifier */
void *sense_data; /**< pointer to sense data buffer */
uint32_t sense_data_length; /**< length of sense data buffer (call=buffer leng, return=data written) */
int32_t residual; /**< residual */
uint32_t tag_to_abort; /**< tag to abort for an abort task request */
/* return value */
int32_t status; /**< returned status */
uint32_t data_transferred; /**< updated with data transferred */
uint32_t tag; /**< returned unique I/O context tag */
/* for scsi loop */
uint32_t submit_count; /**< count of submitted IOs */
uint32_t complete_count; /**< count of completed IOs */
} ocs_ioctl_scsi_cmd_t;
/**
* @brief coredump helper function command values
*/
typedef enum {
OCS_ECD_HELPER_CFG_READ8,
OCS_ECD_HELPER_CFG_READ16,
OCS_ECD_HELPER_CFG_READ32,
OCS_ECD_HELPER_CFG_WRITE8,
OCS_ECD_HELPER_CFG_WRITE16,
OCS_ECD_HELPER_CFG_WRITE32,
OCS_ECD_HELPER_BAR_READ8,
OCS_ECD_HELPER_BAR_READ16,
OCS_ECD_HELPER_BAR_READ32,
OCS_ECD_HELPER_BAR_WRITE8,
OCS_ECD_HELPER_BAR_WRITE16,
OCS_ECD_HELPER_BAR_WRITE32,
} ocs_ecd_helper_cmd_t;
/**
* @brief OCS_IOCTL_CMD_ECD_HELPER ioctl structure
*/
typedef struct {
ocs_ecd_helper_cmd_t cmd; /*<< coredump helper function command */
uint32_t bar; /*<< BAR value to use */
uint32_t offset; /*<< offset value to use */
uint32_t data; /*<< 32 bit data value to write or return read data in */
int status; /*<< status of helper function request */
} ocs_ioctl_ecd_helper_t;
/**
* @brief OCS_IOCTL_CMD_VPORT ioctl structure
*/
typedef struct {
uint32_t domain_index; /*<< domain instance index */
uint32_t req_create:1, /*<< 1 = create vport, zero = remove vport */
enable_ini:1, /*<< 1 = enable vport as an initiator */
enable_tgt:1; /*<< 1 = enable vport as a target */
uint64_t wwpn; /*<< wwpn to create or delete */
uint64_t wwnn; /*<< wwnn to create or delete */
int status; /*<< status of helper function request */
} ocs_ioctl_vport_t;
/**
* @brief connection info ioctl structure
*
* Structure is returned when the OCS_IOCTL_CMD_CONNECTION_INFO is issued by a user space program.
*/
typedef struct {
uint32_t connection_handle;
uint16_t connection_id;
uint8_t source_ip_type;
uint8_t source_ip[16];
uint16_t source_port;
uint8_t dest_ip_type;
uint8_t dest_ip[16];
uint16_t dest_port;
} ocs_ioctl_connection_info_t;
typedef struct {
uint32_t max_connections;
uint32_t num_connections;
ocs_ioctl_connection_info_t *connections;
} ocs_ioctl_connections_t;
/**
* @brief driver-dump actions
*/
typedef enum {
OCS_IOCTL_DDUMP_GET,
OCS_IOCTL_DDUMP_GET_SAVED,
OCS_IOCTL_DDUMP_CLR_SAVED,
} ocs_ddump_action_t;
#define OCS_IOCTL_DDUMP_FLAGS_WQES (1U << 0)
#define OCS_IOCTL_DDUMP_FLAGS_CQES (1U << 1)
#define OCS_IOCTL_DDUMP_FLAGS_MQES (1U << 2)
#define OCS_IOCTL_DDUMP_FLAGS_RQES (1U << 3)
#define OCS_IOCTL_DDUMP_FLAGS_EQES (1U << 4)
typedef struct {
ocs_ddump_action_t action;
uint32_t flags;
uint32_t q_entries;
} ocs_ioctl_ddump_arg_t;
/**
* @brief OCS_CTL_CMD_GET_DDUMP ioctl structure
*/
typedef struct {
ocs_ioctl_ddump_arg_t args; /*<< arguments for ddump */
uint8_t *user_buffer; /*<< pointer to user space buffer */
uint32_t user_buffer_len; /*<< length in bytes of user space buffer */
uint32_t bytes_written; /*<< number of bytes written */
} ocs_ioctl_ddump_t;
/**
* @brief OCS_CTL_CMD_GET_STATUS, OCS_CTL_CMD_GET_CONFIG
*/
typedef struct {
uint8_t *user_buffer; /*<< pointer to user space buffer */
uint32_t user_buffer_len; /*<< length in bytes of user space buffer */
uint32_t bytes_written; /*<< number of bytes written */
} ocs_ioctl_mgmt_buffer_t;
typedef struct {
uint8_t *name; /*<< Input: name of property to retrieve */
uint8_t *value; /*<< Output: user space buffer in which to place the response */
uint32_t value_length; /*<< Input: size of the user space buffer */
} ocs_ioctl_cmd_get_t;
typedef struct {
uint8_t *name; /*<< Input: name of property to set */
uint8_t *value; /*<< Input: user space buffer which contains the new value */
int32_t result; /*<< Output: result */
} ocs_ioctl_cmd_set_t;
typedef struct {
uint8_t *name; /*<< Input: name of action to execute */
void *arg_in; /*<< Input: pointer to argument in user space */
uint32_t arg_in_length; /*<< Input: size of arg_in in bytes */
void *arg_out; /*<< Output: pointer to argument from kernel to user */
uint32_t arg_out_length; /*<< Input: size of arg_out in bytes */
int32_t result; /*<< Output: result */
} ocs_ioctl_action_t;
#define FC_HEADER_LEN 24
typedef struct {
uint8_t fc_header[FC_HEADER_LEN]; /*<< FC Header to send */
uint8_t *payload; /*<< payload */
uint32_t payload_len; /*<< payload length (bytes) */
uint8_t sof; /*<< SOF value */
uint8_t eof; /*<< EOF Value */
} ocs_ioctl_send_frame_t;
/**
* @brief linkcfg strings
*/
#define OCS_CONFIG_LINKCFG_4X10G "ETH_4x10G"
#define OCS_CONFIG_LINKCFG_1X40G "ETH_1x40G"
#define OCS_CONFIG_LINKCFG_2X16G "FC_2x16G"
#define OCS_CONFIG_LINKCFG_4X8G "FC_4x8G"
#define OCS_CONFIG_LINKCFG_4X1G "FC_4x1G"
#define OCS_CONFIG_LINKCFG_2X10G "ETH_2x10G"
#define OCS_CONFIG_LINKCFG_2X10G_2X8G "ETH_2x10G_FC_2x8G"
#define OCS_CONFIG_LINKCFG_UNKNOWN "UNKNOWN"
#define OCS_IOCTL_CMD_BASE 'o'
#define OCS_IOCTL_CMD_TEST _IOWR(OCS_IOCTL_CMD_BASE, 1, ocs_ioctl_test_t)
#define OCS_IOCTL_CMD_ELXU_MBOX _IOWR(OCS_IOCTL_CMD_BASE, 2, ocs_ioctl_elxu_mbox_t)
#define OCS_IOCTL_CMD_SCSI_CMD _IOWR(OCS_IOCTL_CMD_BASE, 3, ocs_ioctl_scsi_cmd_t)
#define OCS_IOCTL_CMD_DRIVER_INFO _IOWR(OCS_IOCTL_CMD_BASE, 4, ocs_ioctl_driver_info_t)
#define OCS_IOCTL_CMD_ECD_HELPER _IOWR(OCS_IOCTL_CMD_BASE, 5, ocs_ioctl_ecd_helper_t)
#define OCS_IOCTL_CMD_CONNECTION_INFO _IOWR(OCS_IOCTL_CMD_BASE, 6, ocs_ioctl_connection_info_t)
#define OCS_IOCTL_CMD_VPORT _IOWR(OCS_IOCTL_CMD_BASE, 7, ocs_ioctl_vport_t)
#define OCS_IOCTL_CMD_GET_DDUMP _IOWR(OCS_IOCTL_CMD_BASE, 8, ocs_ioctl_ddump_t)
#define OCS_IOCTL_CMD_MGMT_GET _IOWR(OCS_IOCTL_CMD_BASE, 9, ocs_ioctl_cmd_get_t)
#define OCS_IOCTL_CMD_MGMT_GET_ALL _IOWR(OCS_IOCTL_CMD_BASE, 10, ocs_ioctl_mgmt_buffer_t)
#define OCS_IOCTL_CMD_MGMT_SET _IOWR(OCS_IOCTL_CMD_BASE, 11, ocs_ioctl_cmd_set_t)
#define OCS_IOCTL_CMD_MGMT_LIST _IOWR(OCS_IOCTL_CMD_BASE, 12, ocs_ioctl_mgmt_buffer_t)
#define OCS_IOCTL_CMD_MGMT_EXEC _IOWR(OCS_IOCTL_CMD_BASE, 13, ocs_ioctl_action_t)
#define OCS_IOCTL_CMD_LINK_ONLINE _IOWR(OCS_IOCTL_CMD_BASE, 16, int)
#define OCS_IOCTL_CMD_GEN_DUMP _IOWR(OCS_IOCTL_CMD_BASE, 17, int)
#define OCS_IOCTL_CMD_UNLOAD _IO(OCS_IOCTL_CMD_BASE, 18)
#define OCS_IOCTL_CMD_SEND_FRAME _IOWR(OCS_IOCTL_CMD_BASE, 19, ocs_ioctl_send_frame_t)
extern void ocs_info_get_xport_address(ocs_t *ocs, ocs_ioctl_driver_info_t *info);
extern int32_t ocs_device_ioctl_xport(ocs_t *ocs, unsigned int cmd, unsigned long arg);
#endif

449
sys/dev/ocs_fc/ocs_list.h Normal file
View file

@ -0,0 +1,449 @@
/*-
* Copyright (c) 2017 Broadcom. All rights reserved.
* The term "Broadcom" refers to Broadcom Limited and/or its subsidiaries.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* $FreeBSD$
*/
/**
* @file
*
* OCS linked list API
*
*/
#if !defined(__OCS_LIST_H__)
#define __OCS_LIST_H__
#define OCS_LIST_DEBUG
#if defined(OCS_LIST_DEBUG)
#define ocs_list_magic_decl uint32_t magic;
#define OCS_LIST_LIST_MAGIC 0xcafe0000
#define OCS_LIST_LINK_MAGIC 0xcafe0001
#define ocs_list_set_list_magic list->magic = OCS_LIST_LIST_MAGIC
#define ocs_list_set_link_magic list->magic = OCS_LIST_LINK_MAGIC
#define ocs_list_assert(cond, ...) \
if (!(cond)) { \
return __VA_ARGS__; \
}
#else
#define ocs_list_magic_decl
#define ocs_list_assert(cond, ...)
#define ocs_list_set_list_magic
#define ocs_list_set_link_magic
#endif
/**
* @brief list/link structure
*
* used for both the list object, and the link object(s). offset
* is specified when the list is initialized; this implies that a list
* will always point to objects of the same type. offset is not used
* when ocs_list_t is used as a link (ocs_list_link_t).
*
*/
typedef struct ocs_list_s ocs_list_t;
struct ocs_list_s {
ocs_list_magic_decl /*<< used if debugging is enabled */
ocs_list_t *next; /*<< pointer to head of list (or next if link) */
ocs_list_t *prev; /*<< pointer to tail of list (or previous if link) */
uint32_t offset; /*<< offset in bytes to the link element of the objects in list */
};
typedef ocs_list_t ocs_list_link_t;
/* item2link - return pointer to link given pointer to an item */
#define item2link(list, item) ((ocs_list_t*) (((uint8_t*)(item)) + (list)->offset))
/* link2item - return pointer to item given pointer to a link */
#define link2item(list, link) ((void*) (((uint8_t*)(link)) - (list)->offset))
/**
* @brief Initialize a list
*
* A list object is initialized. Helper define is used to call _ocs_list_init() with
* offsetof(type, link)
*
* @param list Pointer to list
* @param offset Offset in bytes in item to the link element
*
* @return none
*/
static inline void
_ocs_list_init(ocs_list_t *list, uint32_t offset)
{
ocs_list_assert(list);
ocs_list_set_list_magic;
list->next = list;
list->prev = list;
list->offset = offset;
}
#define ocs_list_init(head, type, link) _ocs_list_init(head, offsetof(type, link))
/**
* @ingroup os
* @brief Test if a list is empty
*
* @param list Pointer to list head
*
* @return 1 if empty, 0 otherwise
*/
static inline int32_t
ocs_list_empty(ocs_list_t *list)
{
ocs_list_assert(list, 1);
ocs_list_assert(list->magic == OCS_LIST_LIST_MAGIC, 1);
return list->next == list;
}
/**
* @ingroup os
* @brief Test if a list is valid (ready for use)
*
* @param list Pointer to list head
*
* @return true if list is usable, false otherwise
*/
static inline int
ocs_list_valid(ocs_list_t *list)
{
return (list->magic == OCS_LIST_LIST_MAGIC);
}
/**
* @brief Insert link between two other links
*
* Inserts a link in between two other links
*
* @param a Pointer to first link
* @param b Pointer to next link
* @param c Pointer to link to insert between a and b
*
* @return none
*/
static inline void
_ocs_list_insert_link(ocs_list_t *a, ocs_list_t *b, ocs_list_t *c)
{
ocs_list_assert(a);
ocs_list_assert((a->magic == OCS_LIST_LIST_MAGIC) || (a->magic == OCS_LIST_LINK_MAGIC));
ocs_list_assert(a->next);
ocs_list_assert(a->prev);
ocs_list_assert(b);
ocs_list_assert((b->magic == OCS_LIST_LIST_MAGIC) || (b->magic == OCS_LIST_LINK_MAGIC));
ocs_list_assert(b->next);
ocs_list_assert(b->prev);
ocs_list_assert(c);
ocs_list_assert((c->magic == OCS_LIST_LIST_MAGIC) || (c->magic == OCS_LIST_LINK_MAGIC));
ocs_list_assert(!c->next);
ocs_list_assert(!c->prev);
ocs_list_assert(a->offset == b->offset);
ocs_list_assert(b->offset == c->offset);
c->next = a->next;
c->prev = b->prev;
a->next = c;
b->prev = c;
}
#if defined(OCS_LIST_DEBUG)
/**
* @brief Initialize a list link for debug purposes
*
* For debugging a linked list link element has a magic number that is initialized,
* and the offset value initialzied and used for subsequent assertions.
*
*
* @param list Pointer to list head
* @param link Pointer to link to be initialized
*
* @return none
*/
static inline void
ocs_list_init_link(ocs_list_t *list, ocs_list_t *link)
{
ocs_list_assert(list);
ocs_list_assert(list->magic == OCS_LIST_LIST_MAGIC);
ocs_list_assert(link);
if (link->magic == 0) {
link->magic = OCS_LIST_LINK_MAGIC;
link->offset = list->offset;
link->next = NULL;
link->prev = NULL;
}
}
#else
#define ocs_list_init_link(...)
#endif
/**
* @ingroup os
* @brief Add an item to the head of the list
*
* @param list Pointer to list head
* @param item Item to add
*/
static inline void
ocs_list_add_head(ocs_list_t *list, void *item)
{
ocs_list_t *link;
ocs_list_assert(list);
ocs_list_assert(list->magic == OCS_LIST_LIST_MAGIC);
ocs_list_assert(item);
link = item2link(list, item);
ocs_list_init_link(list, link);
ocs_list_assert(link->magic == OCS_LIST_LINK_MAGIC);
ocs_list_assert(link->offset == list->offset);
ocs_list_assert(link->next == NULL);
ocs_list_assert(link->prev == NULL);
_ocs_list_insert_link(list, list->next, item2link(list, item));
}
/**
* @ingroup os
* @brief Add an item to the tail of the list
*
* @param list Head of the list
* @param item Item to add
*/
static inline void
ocs_list_add_tail(ocs_list_t *list, void *item)
{
ocs_list_t *link;
ocs_list_assert(list);
ocs_list_assert(list->magic == OCS_LIST_LIST_MAGIC);
ocs_list_assert(item);
link = item2link(list, item);
ocs_list_init_link(list, link);
ocs_list_assert(link->magic == OCS_LIST_LINK_MAGIC);
ocs_list_assert(link->offset == list->offset);
ocs_list_assert(link->next == NULL);
ocs_list_assert(link->prev == NULL);
_ocs_list_insert_link(list->prev, list, link);
}
/**
* @ingroup os
* @brief Return the first item in the list
*
* @param list Head of the list
*
* @return pointer to the first item, NULL otherwise
*/
static inline void *
ocs_list_get_head(ocs_list_t *list)
{
ocs_list_assert(list, NULL);
ocs_list_assert(list->magic == OCS_LIST_LIST_MAGIC, NULL);
return ocs_list_empty(list) ? NULL : link2item(list, list->next);
}
/**
* @ingroup os
* @brief Return the first item in the list
*
* @param list head of the list
*
* @return pointer to the last item, NULL otherwise
*/
static inline void *
ocs_list_get_tail(ocs_list_t *list)
{
ocs_list_assert(list, NULL);
ocs_list_assert(list->magic == OCS_LIST_LIST_MAGIC, NULL);
return ocs_list_empty(list) ? NULL : link2item(list, list->prev);
}
/**
* @ingroup os
* @brief Return the last item in the list
*
* @param list Pointer to list head
*
* @return pointer to the last item, NULL otherwise
*/
static inline void *ocs_list_tail(ocs_list_t *list)
{
ocs_list_assert(list, NULL);
ocs_list_assert(list->magic == OCS_LIST_LIST_MAGIC, NULL);
return ocs_list_empty(list) ? NULL : link2item(list, list->prev);
}
/**
* @ingroup os
* @brief Get the next item on the list
*
* @param list head of the list
* @param item current item
*
* @return pointer to the next item, NULL otherwise
*/
static inline void *ocs_list_next(ocs_list_t *list, void *item)
{
ocs_list_t *link;
if (item == NULL) {
return NULL;
}
ocs_list_assert(list, NULL);
ocs_list_assert(list->magic == OCS_LIST_LIST_MAGIC, NULL);
ocs_list_assert(item, NULL);
link = item2link(list, item);
ocs_list_assert(link->magic == OCS_LIST_LINK_MAGIC, NULL);
ocs_list_assert(link->offset == list->offset, NULL);
ocs_list_assert(link->next, NULL);
ocs_list_assert(link->prev, NULL);
if ((link->next) == list) {
return NULL;
}
return link2item(list, link->next);
}
/**
* @ingroup os
* @brief Remove and return an item from the head of the list
*
* @param list head of the list
*
* @return pointer to returned item, or NULL if list is empty
*/
#define ocs_list_remove_head(list) ocs_list_remove(list, ocs_list_get_head(list))
/**
* @ingroup os
* @brief Remove an item from the list
*
* @param list Head of the list
* @param item Item to remove
*
* @return pointer to item, or NULL if item is not found.
*/
static inline void *ocs_list_remove(ocs_list_t *list, void *item)
{
ocs_list_t *link;
ocs_list_t *prev;
ocs_list_t *next;
if (item == NULL) {
return NULL;
}
ocs_list_assert(list, NULL);
ocs_list_assert(list->magic == OCS_LIST_LIST_MAGIC, NULL);
link = item2link(list, item);
ocs_list_assert(link->magic == OCS_LIST_LINK_MAGIC, NULL);
ocs_list_assert(link->offset == list->offset, NULL);
ocs_list_assert(link->next, NULL);
ocs_list_assert(link->prev, NULL);
prev = link->prev;
next = link->next;
prev->next = next;
next->prev = prev;
link->next = link->prev = NULL;
return item;
}
/**
* @brief Iterate a linked list
*
* Iterate a linked list.
*
* @param list Pointer to list
* @param item Pointer to iterated item
*
* note, item is NULL after full list is traversed.
* @return none
*/
#define ocs_list_foreach(list, item) \
for (item = ocs_list_get_head((list)); item; item = ocs_list_next((list), item) )
/**
* @brief Iterate a linked list safely
*
* Iterate a linked list safely, meaning that the iterated item
* may be safely removed from the list.
*
* @param list Pointer to list
* @param item Pointer to iterated item
* @param nxt Pointer to saveed iterated item
*
* note, item is NULL after full list is traversed.
*
* @return none
*/
#define ocs_list_foreach_safe(list, item, nxt) \
for (item = ocs_list_get_head(list), nxt = item ? ocs_list_next(list, item) : NULL; item; \
item = nxt, nxt = ocs_list_next(list, item))
/**
* @brief Test if object is on a list
*
* Returns True if object is on a list
*
* @param link Pointer to list link
*
* @return returns True if object is on a list
*/
static inline int32_t
ocs_list_on_list(ocs_list_link_t *link)
{
return (link->next != NULL);
}
#endif /* __OCS_LIST_H__ */

2923
sys/dev/ocs_fc/ocs_mgmt.c Normal file

File diff suppressed because it is too large Load diff

121
sys/dev/ocs_fc/ocs_mgmt.h Normal file
View file

@ -0,0 +1,121 @@
/*-
* Copyright (c) 2017 Broadcom. All rights reserved.
* The term "Broadcom" refers to Broadcom Limited and/or its subsidiaries.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* $FreeBSD$
*/
/**
* @file
* Declarations for the common functions used by ocs_mgmt.
*/
#if !defined(__OCS_MGMT_H__)
#define __OCS_MGMT_H__
#include "ocs_utils.h"
#define OCS_MGMT_MAX_NAME 128
#define OCS_MGMT_MAX_VALUE 128
#define MGMT_MODE_RD 4
#define MGMT_MODE_WR 2
#define MGMT_MODE_EX 1
#define MGMT_MODE_RW (MGMT_MODE_RD | MGMT_MODE_WR)
#define FW_WRITE_BUFSIZE 64*1024
typedef struct ocs_mgmt_fw_write_result {
ocs_sem_t semaphore;
int32_t status;
uint32_t actual_xfer;
uint32_t change_status;
} ocs_mgmt_fw_write_result_t;
/*
* This structure is used in constructing a table of internal handler functions.
*/
typedef void (*ocs_mgmt_get_func)(ocs_t *, char *, ocs_textbuf_t*);
typedef int (*ocs_mgmt_set_func)(ocs_t *, char *, char *);
typedef int (*ocs_mgmt_action_func)(ocs_t *, char *, void *, uint32_t, void *, uint32_t);
typedef struct ocs_mgmt_table_entry_s {
char *name;
ocs_mgmt_get_func get_handler;
ocs_mgmt_set_func set_handler;
ocs_mgmt_action_func action_handler;
} ocs_mgmt_table_entry_t;
/*
* This structure is used when defining the top level management handlers for
* different types of objects (sport, node, domain, etc)
*/
typedef void (*ocs_mgmt_get_list_handler)(ocs_textbuf_t *textbuf, void* object);
typedef void (*ocs_mgmt_get_all_handler)(ocs_textbuf_t *textbuf, void* object);
typedef int (*ocs_mgmt_get_handler)(ocs_textbuf_t *, char *parent, char *name, void *object);
typedef int (*ocs_mgmt_set_handler)(char *parent, char *name, char *value, void *object);
typedef int (*ocs_mgmt_exec_handler)(char *parent, char *action, void *arg_in, uint32_t arg_in_length,
void *arg_out, uint32_t arg_out_length, void *object);
typedef struct ocs_mgmt_functions_s {
ocs_mgmt_get_list_handler get_list_handler;
ocs_mgmt_get_handler get_handler;
ocs_mgmt_get_all_handler get_all_handler;
ocs_mgmt_set_handler set_handler;
ocs_mgmt_exec_handler exec_handler;
} ocs_mgmt_functions_t;
/* Helper functions */
extern void ocs_mgmt_start_section(ocs_textbuf_t *textbuf, const char *name, int index);
extern void ocs_mgmt_start_unnumbered_section(ocs_textbuf_t *textbuf, const char *name);
extern void ocs_mgmt_end_section(ocs_textbuf_t *textbuf, const char *name, int index);
extern void ocs_mgmt_end_unnumbered_section(ocs_textbuf_t *textbuf, const char *name);
extern void ocs_mgmt_emit_property_name(ocs_textbuf_t *textbuf, int access, const char *name);
extern void ocs_mgmt_emit_string(ocs_textbuf_t *textbuf, int access, const char *name, const char *value);
__attribute__((format(printf,4,5)))
extern void ocs_mgmt_emit_int(ocs_textbuf_t *textbuf, int access, const char *name, const char *fmt, ...);
extern void ocs_mgmt_emit_boolean(ocs_textbuf_t *textbuf, int access, const char *name, const int value);
extern int parse_wwn(char *wwn_in, uint64_t *wwn_out);
/* Top level management functions - called by the ioctl */
extern void ocs_mgmt_get_list(ocs_t *ocs, ocs_textbuf_t *textbuf);
extern void ocs_mgmt_get_all(ocs_t *ocs, ocs_textbuf_t *textbuf);
extern int ocs_mgmt_get(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf);
extern int ocs_mgmt_set(ocs_t *ocs, char *name, char *value);
extern int ocs_mgmt_exec(ocs_t *ocs, char *action, void *arg_in, uint32_t arg_in_length,
void *arg_out, uint32_t arg_out_length);
extern int set_req_wwnn(ocs_t*, char*, char*);
extern int set_req_wwpn(ocs_t*, char*, char*);
extern int set_configured_speed(ocs_t*, char*, char*);
extern int set_configured_topology(ocs_t*, char*, char*);
#endif

2376
sys/dev/ocs_fc/ocs_node.c Normal file

File diff suppressed because it is too large Load diff

240
sys/dev/ocs_fc/ocs_node.h Normal file
View file

@ -0,0 +1,240 @@
/*-
* Copyright (c) 2017 Broadcom. All rights reserved.
* The term "Broadcom" refers to Broadcom Limited and/or its subsidiaries.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* $FreeBSD$
*/
/**
* @file
* OCS linux driver remote node callback declarations
*/
#if !defined(__OCS_NODE_H__)
#define __OCS_NODE_H__
#define node_sm_trace() \
do { \
if (OCS_LOG_ENABLE_SM_TRACE(node->ocs)) \
ocs_log_info(node->ocs, "[%s] %-20s\n", node->display_name, ocs_sm_event_name(evt)); \
} while (0)
#define node_printf(node, fmt, ...) ocs_log_debug(node->ocs, "[%s] " fmt, node->display_name, ##__VA_ARGS__)
#define std_node_state_decl(...) \
ocs_node_t *node = NULL; \
ocs_t *ocs = NULL; \
node = ctx->app; \
ocs_assert(node, NULL); \
ocs = node->ocs; \
ocs_assert(ocs, NULL); \
if (evt == OCS_EVT_ENTER) { \
ocs_strncpy(node->current_state_name, __func__, sizeof(node->current_state_name)); \
} else if (evt == OCS_EVT_EXIT) { \
ocs_strncpy(node->prev_state_name, node->current_state_name, sizeof(node->prev_state_name)); \
ocs_strncpy(node->current_state_name, "invalid", sizeof(node->current_state_name)); \
} \
node->prev_evt = node->current_evt; \
node->current_evt = evt;
#define OCS_NODEDB_PAUSE_FABRIC_LOGIN (1U << 0)
#define OCS_NODEDB_PAUSE_NAMESERVER (1U << 1)
#define OCS_NODEDB_PAUSE_NEW_NODES (1U << 2)
/**
* @brief Node SM IO Context Callback structure
*
* Structure used as callback argument
*/
struct ocs_node_cb_s {
ocs_io_t *io; /**< SCSI IO for sending response */
int32_t status; /**< completion status */
int32_t ext_status; /**< extended completion status */
ocs_hw_rq_buffer_t *header; /**< completion header buffer */
ocs_hw_rq_buffer_t *payload; /**< completion payload buffers */
ocs_io_t *els; /**< ELS IO object */
};
/**
* @brief hold frames in pending frame list
*
* Unsolicited receive frames are held on the node pending frame list, rather than
* being processed.
*
* @param node pointer to node structure
*
* @return none
*/
static inline void
ocs_node_hold_frames(ocs_node_t *node)
{
ocs_assert(node);
node->hold_frames = TRUE;
}
/**
* @brief accept frames
*
* Unsolicited receive frames processed rather than being held on the node
* pending frame list.
*
* @param node pointer to node structure
*
* @return none
*/
static inline void
ocs_node_accept_frames(ocs_node_t *node)
{
ocs_assert(node);
node->hold_frames = FALSE;
}
extern int32_t ocs_node_create_pool(ocs_t *ocs, uint32_t node_count);
extern void ocs_node_free_pool(ocs_t *ocs);
extern ocs_node_t *ocs_node_get_instance(ocs_t *ocs, uint32_t index);
static inline void
ocs_node_lock_init(ocs_node_t *node)
{
ocs_rlock_init(node->ocs, &node->lock, "node rlock");
}
static inline void
ocs_node_lock_free(ocs_node_t *node)
{
ocs_rlock_free(&node->lock);
}
static inline int32_t
ocs_node_lock_try(ocs_node_t *node)
{
return ocs_rlock_try(&node->lock);
}
static inline void
ocs_node_lock(ocs_node_t *node)
{
ocs_rlock_acquire(&node->lock);
}
static inline void
ocs_node_unlock(ocs_node_t *node)
{
ocs_rlock_release(&node->lock);
}
/**
* @brief Node initiator/target enable defines
*
* All combinations of the SLI port (sport) initiator/target enable, and remote
* node initiator/target enable are enumerated.
*
*/
typedef enum {
OCS_NODE_ENABLE_x_TO_x,
OCS_NODE_ENABLE_x_TO_T,
OCS_NODE_ENABLE_x_TO_I,
OCS_NODE_ENABLE_x_TO_IT,
OCS_NODE_ENABLE_T_TO_x,
OCS_NODE_ENABLE_T_TO_T,
OCS_NODE_ENABLE_T_TO_I,
OCS_NODE_ENABLE_T_TO_IT,
OCS_NODE_ENABLE_I_TO_x,
OCS_NODE_ENABLE_I_TO_T,
OCS_NODE_ENABLE_I_TO_I,
OCS_NODE_ENABLE_I_TO_IT,
OCS_NODE_ENABLE_IT_TO_x,
OCS_NODE_ENABLE_IT_TO_T,
OCS_NODE_ENABLE_IT_TO_I,
OCS_NODE_ENABLE_IT_TO_IT,
} ocs_node_enable_e;
static inline ocs_node_enable_e ocs_node_get_enable(ocs_node_t *node)
{
uint32_t retval = 0;
if (node->sport->enable_ini) retval |= (1U << 3);
if (node->sport->enable_tgt) retval |= (1U << 2);
if (node->init) retval |= (1U << 1);
if (node->targ) retval |= (1U << 0);
return (ocs_node_enable_e) retval;
}
typedef void* (*ocs_node_common_func_t)(const char *funcname, ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg);
extern int32_t node_check_els_req(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg, uint8_t cmd, ocs_node_common_func_t node_common_func, const char *funcname);
extern int32_t node_check_ns_req(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg, uint32_t cmd, ocs_node_common_func_t node_common_func, const char *funcname);
extern int32_t ocs_remote_node_cb(void *arg, ocs_hw_remote_node_event_e event, void *data);
extern int32_t ocs_node_attach(ocs_node_t *node);
extern ocs_node_t *ocs_node_find(ocs_sport_t *sport, uint32_t port_id);
extern ocs_node_t *ocs_node_find_wwpn(ocs_sport_t *sport, uint64_t wwpn);
extern void ocs_node_dump(ocs_t *ocs);
extern ocs_node_t *ocs_node_alloc(ocs_sport_t *sport, uint32_t port_id, uint8_t init, uint8_t targ);
extern int32_t ocs_node_free(ocs_node_t *node);
extern void ocs_node_force_free(ocs_node_t *node);
extern void ocs_node_fcid_display(uint32_t fc_id, char *buffer, uint32_t buffer_length);
extern void ocs_node_update_display_name(ocs_node_t *node);
extern void *__ocs_node_shutdown(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg);
extern void * __ocs_node_wait_node_free(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg);
extern void *__ocs_node_wait_els_shutdown(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg);
extern void *__ocs_node_wait_ios_shutdown(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg);
extern void ocs_node_save_sparms(ocs_node_t *node, void *payload);
extern void ocs_node_post_event(ocs_node_t *node, ocs_sm_event_t evt, void *arg);
extern void ocs_node_transition(ocs_node_t *node, ocs_sm_function_t state, void *data);
extern void *__ocs_node_common(const char *funcname, ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg);
extern void ocs_node_initiate_cleanup(ocs_node_t *node);
extern int ocs_ddump_node(ocs_textbuf_t *textbuf, ocs_node_t *node);
extern void ocs_node_build_eui_name(char *buffer, uint32_t buffer_len, uint64_t eui_name);
extern uint64_t ocs_node_get_wwpn(ocs_node_t *node);
extern uint64_t ocs_node_get_wwnn(ocs_node_t *node);
extern void ocs_node_abort_all_els(ocs_node_t *node);
extern void ocs_node_pause(ocs_node_t *node, ocs_sm_function_t state);
extern int32_t ocs_node_resume(ocs_node_t *node);
extern void *__ocs_node_paused(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg);
extern int ocs_node_active_ios_empty(ocs_node_t *node);
extern void ocs_node_send_ls_io_cleanup(ocs_node_t *node);
extern int32_t ocs_node_recv_link_services_frame(ocs_node_t *node, ocs_hw_sequence_t *seq);
extern int32_t ocs_node_recv_abts_frame(ocs_node_t *node, ocs_hw_sequence_t *seq);
extern int32_t ocs_node_recv_els_frame(ocs_node_t *node, ocs_hw_sequence_t *seq);
extern int32_t ocs_node_recv_ct_frame(ocs_node_t *node, ocs_hw_sequence_t *seq);
extern int32_t ocs_node_recv_fcp_cmd(ocs_node_t *node, ocs_hw_sequence_t *seq);
extern int32_t ocs_node_recv_bls_no_sit(ocs_node_t *node, ocs_hw_sequence_t *seq);
#endif

1046
sys/dev/ocs_fc/ocs_os.c Normal file

File diff suppressed because it is too large Load diff

1406
sys/dev/ocs_fc/ocs_os.h Normal file

File diff suppressed because it is too large Load diff

963
sys/dev/ocs_fc/ocs_pci.c Normal file
View file

@ -0,0 +1,963 @@
/*-
* Copyright (c) 2017 Broadcom. All rights reserved.
* The term "Broadcom" refers to Broadcom Limited and/or its subsidiaries.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* $FreeBSD$
*/
#define OCS_COPYRIGHT "Copyright (C) 2017 Broadcom. All rights reserved."
/**
* @file
* Implementation of required FreeBSD PCI interface functions
*/
#include "ocs.h"
#include "version.h"
#include <sys/sysctl.h>
#include <sys/malloc.h>
static MALLOC_DEFINE(M_OCS, "OCS", "OneCore Storage data");
#include <dev/pci/pcireg.h>
#include <dev/pci/pcivar.h>
#include <machine/bus.h>
/**
* Tunable parameters for transport
*/
int logmask = 0;
int ctrlmask = 2;
int logdest = 1;
int loglevel = LOG_INFO;
int ramlog_size = 1*1024*1024;
int ddump_saved_size = 0;
static const char *queue_topology = "eq cq rq cq mq $nulp($nwq(cq wq:ulp=$rpt1)) cq wq:len=256:class=1";
static void ocs_release_bus(struct ocs_softc *);
static int32_t ocs_intr_alloc(struct ocs_softc *);
static int32_t ocs_intr_setup(struct ocs_softc *);
static int32_t ocs_intr_teardown(struct ocs_softc *);
static int ocs_pci_intx_filter(void *);
static void ocs_pci_intr(void *);
static int32_t ocs_init_dma_tag(struct ocs_softc *ocs);
static int32_t ocs_setup_fcports(ocs_t *ocs);
ocs_t *ocs_devices[MAX_OCS_DEVICES];
/**
* @brief Check support for the given device
*
* Determine support for a given device by examining the PCI vendor and
* device IDs
*
* @param dev device abstraction
*
* @return 0 if device is supported, ENXIO otherwise
*/
static int
ocs_pci_probe(device_t dev)
{
char *desc = NULL;
if (pci_get_vendor(dev) != PCI_VENDOR_EMULEX) {
return ENXIO;
}
switch (pci_get_device(dev)) {
case PCI_PRODUCT_EMULEX_OCE16001:
desc = "Emulex LightPulse FC Adapter";
break;
case PCI_PRODUCT_EMULEX_LPE31004:
desc = "Emulex LightPulse FC Adapter";
break;
case PCI_PRODUCT_EMULEX_OCE50102:
desc = "Emulex LightPulse 10GbE FCoE/NIC Adapter";
break;
default:
return ENXIO;
}
device_set_desc(dev, desc);
return BUS_PROBE_DEFAULT;
}
static int
ocs_map_bars(device_t dev, struct ocs_softc *ocs)
{
/*
* Map PCI BAR0 register into the CPU's space.
*/
ocs->reg[0].rid = PCIR_BAR(PCI_64BIT_BAR0);
ocs->reg[0].res = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
&ocs->reg[0].rid, RF_ACTIVE);
if (ocs->reg[0].res == NULL) {
device_printf(dev, "bus_alloc_resource failed rid=%#x\n",
ocs->reg[0].rid);
return ENXIO;
}
ocs->reg[0].btag = rman_get_bustag(ocs->reg[0].res);
ocs->reg[0].bhandle = rman_get_bushandle(ocs->reg[0].res);
return 0;
}
static int
ocs_setup_params(struct ocs_softc *ocs)
{
int32_t i = 0;
const char *hw_war_version;
/* Setup tunable parameters */
ocs->ctrlmask = ctrlmask;
ocs->speed = 0;
ocs->topology = 0;
ocs->ethernet_license = 0;
ocs->num_scsi_ios = 8192;
ocs->enable_hlm = 0;
ocs->hlm_group_size = 8;
ocs->logmask = logmask;
ocs->config_tgt = FALSE;
if (0 == resource_int_value(device_get_name(ocs->dev), device_get_unit(ocs->dev),
"target", &i)) {
if (1 == i) {
ocs->config_tgt = TRUE;
device_printf(ocs->dev, "Enabling target\n");
}
}
ocs->config_ini = TRUE;
if (0 == resource_int_value(device_get_name(ocs->dev), device_get_unit(ocs->dev),
"initiator", &i)) {
if (0 == i) {
ocs->config_ini = FALSE;
device_printf(ocs->dev, "Disabling initiator\n");
}
}
ocs->enable_ini = ocs->config_ini;
if (!ocs->config_ini && !ocs->config_tgt) {
device_printf(ocs->dev, "Unsupported, both initiator and target mode disabled.\n");
return 1;
}
if (0 == resource_int_value(device_get_name(ocs->dev), device_get_unit(ocs->dev),
"logmask", &logmask)) {
device_printf(ocs->dev, "logmask = %#x\n", logmask);
}
if (0 == resource_int_value(device_get_name(ocs->dev), device_get_unit(ocs->dev),
"logdest", &logdest)) {
device_printf(ocs->dev, "logdest = %#x\n", logdest);
}
if (0 == resource_int_value(device_get_name(ocs->dev), device_get_unit(ocs->dev),
"loglevel", &loglevel)) {
device_printf(ocs->dev, "loglevel = %#x\n", loglevel);
}
if (0 == resource_int_value(device_get_name(ocs->dev), device_get_unit(ocs->dev),
"ramlog_size", &ramlog_size)) {
device_printf(ocs->dev, "ramlog_size = %#x\n", ramlog_size);
}
if (0 == resource_int_value(device_get_name(ocs->dev), device_get_unit(ocs->dev),
"ddump_saved_size", &ddump_saved_size)) {
device_printf(ocs->dev, "ddump_saved_size= %#x\n", ddump_saved_size);
}
/* If enabled, initailize a RAM logging buffer */
if (logdest & 2) {
ocs->ramlog = ocs_ramlog_init(ocs, ramlog_size/OCS_RAMLOG_DEFAULT_BUFFERS,
OCS_RAMLOG_DEFAULT_BUFFERS);
/* If NULL was returned, then we'll simply skip using the ramlog but */
/* set logdest to 1 to ensure that we at least get default logging. */
if (ocs->ramlog == NULL) {
logdest = 1;
}
}
/* initialize a saved ddump */
if (ddump_saved_size) {
if (ocs_textbuf_alloc(ocs, &ocs->ddump_saved, ddump_saved_size)) {
ocs_log_err(ocs, "failed to allocate memory for saved ddump\n");
}
}
if (0 == resource_string_value(device_get_name(ocs->dev), device_get_unit(ocs->dev),
"hw_war_version", &hw_war_version)) {
device_printf(ocs->dev, "hw_war_version = %s\n", hw_war_version);
ocs->hw_war_version = strdup(hw_war_version, M_OCS);
}
if (0 == resource_int_value(device_get_name(ocs->dev), device_get_unit(ocs->dev),
"explicit_buffer_list", &i)) {
ocs->explicit_buffer_list = i;
}
if (0 == resource_int_value(device_get_name(ocs->dev), device_get_unit(ocs->dev),
"ethernet_license", &i)) {
ocs->ethernet_license = i;
}
if (0 == resource_int_value(device_get_name(ocs->dev), device_get_unit(ocs->dev),
"speed", &i)) {
device_printf(ocs->dev, "speed = %d Mbps\n", i);
ocs->speed = i;
}
ocs->desc = device_get_desc(ocs->dev);
ocs_device_lock_init(ocs);
ocs->driver_version = STR_BE_MAJOR "." STR_BE_MINOR "." STR_BE_BUILD "." STR_BE_BRANCH;
ocs->model = ocs_pci_model(ocs->pci_vendor, ocs->pci_device);
if (0 == resource_int_value(device_get_name(ocs->dev), device_get_unit(ocs->dev),
"enable_hlm", &i)) {
device_printf(ocs->dev, "enable_hlm = %d\n", i);
ocs->enable_hlm = i;
if (ocs->enable_hlm) {
ocs->hlm_group_size = 8;
if (0 == resource_int_value(device_get_name(ocs->dev), device_get_unit(ocs->dev),
"hlm_group_size", &i)) {
ocs->hlm_group_size = i;
}
device_printf(ocs->dev, "hlm_group_size = %d\n", i);
}
}
if (0 == resource_int_value(device_get_name(ocs->dev), device_get_unit(ocs->dev),
"num_scsi_ios", &i)) {
ocs->num_scsi_ios = i;
device_printf(ocs->dev, "num_scsi_ios = %d\n", ocs->num_scsi_ios);
} else {
ocs->num_scsi_ios = 8192;
}
if (0 == resource_int_value(device_get_name(ocs->dev), device_get_unit(ocs->dev),
"topology", &i)) {
ocs->topology = i;
device_printf(ocs->dev, "Setting topology=%#x\n", i);
}
if (0 == resource_int_value(device_get_name(ocs->dev), device_get_unit(ocs->dev),
"num_vports", &i)) {
if (i >= 0 && i <= 254) {
device_printf(ocs->dev, "num_vports = %d\n", i);
ocs->num_vports = i;
} else {
device_printf(ocs->dev, "num_vports: %d not supported \n", i);
}
}
if (0 == resource_int_value(device_get_name(ocs->dev), device_get_unit(ocs->dev),
"external_loopback", &i)) {
device_printf(ocs->dev, "external_loopback = %d\n", i);
ocs->external_loopback = i;
}
if (0 == resource_int_value(device_get_name(ocs->dev), device_get_unit(ocs->dev),
"tgt_rscn_delay", &i)) {
device_printf(ocs->dev, "tgt_rscn_delay = %d\n", i);
ocs->tgt_rscn_delay_msec = i * 1000;
}
if (0 == resource_int_value(device_get_name(ocs->dev), device_get_unit(ocs->dev),
"tgt_rscn_period", &i)) {
device_printf(ocs->dev, "tgt_rscn_period = %d\n", i);
ocs->tgt_rscn_period_msec = i * 1000;
}
if (0 == resource_int_value(device_get_name(ocs->dev), device_get_unit(ocs->dev),
"target_io_timer", &i)) {
device_printf(ocs->dev, "target_io_timer = %d\n", i);
ocs->target_io_timer_sec = i;
}
hw_global.queue_topology_string = queue_topology;
ocs->rq_selection_policy = 0;
ocs->rr_quanta = 1;
ocs->filter_def = "0,0,0,0";
return 0;
}
static int32_t
ocs_setup_fcports(ocs_t *ocs)
{
uint32_t i = 0, role = 0;
uint64_t sli_wwpn, sli_wwnn;
size_t size;
ocs_xport_t *xport = ocs->xport;
ocs_vport_spec_t *vport;
ocs_fcport *fcp = NULL;
size = sizeof(ocs_fcport) * (ocs->num_vports + 1);
ocs->fcports = ocs_malloc(ocs, size, M_ZERO|M_NOWAIT);
if (ocs->fcports == NULL) {
device_printf(ocs->dev, "Can't allocate fcport \n");
return 1;
}
role = (ocs->enable_ini)? KNOB_ROLE_INITIATOR: 0 |
(ocs->enable_tgt)? KNOB_ROLE_TARGET: 0;
fcp = FCPORT(ocs, i);
fcp->role = role;
i++;
ocs_list_foreach(&xport->vport_list, vport) {
fcp = FCPORT(ocs, i);
vport->tgt_data = fcp;
fcp->vport = vport;
fcp->role = role;
if (ocs_hw_get_def_wwn(ocs, i, &sli_wwpn, &sli_wwnn)) {
ocs_log_err(ocs, "Get default wwn failed \n");
i++;
continue;
}
vport->wwpn = ocs_be64toh(sli_wwpn);
vport->wwnn = ocs_be64toh(sli_wwnn);
i++;
ocs_log_debug(ocs, "VPort wwpn: %lx wwnn: %lx \n", vport->wwpn, vport->wwnn);
}
return 0;
}
int32_t
ocs_device_attach(ocs_t *ocs)
{
int32_t i;
ocs_io_t *io = NULL;
if (ocs->attached) {
ocs_log_warn(ocs, "%s: Device is already attached\n", __func__);
return -1;
}
/* Allocate transport object and bring online */
ocs->xport = ocs_xport_alloc(ocs);
if (ocs->xport == NULL) {
device_printf(ocs->dev, "failed to allocate transport object\n");
return ENOMEM;
} else if (ocs_xport_attach(ocs->xport) != 0) {
device_printf(ocs->dev, "%s: failed to attach transport object\n", __func__);
goto fail_xport_attach;
} else if (ocs_xport_initialize(ocs->xport) != 0) {
device_printf(ocs->dev, "%s: failed to initialize transport object\n", __func__);
goto fail_xport_init;
}
if (ocs_init_dma_tag(ocs)) {
goto fail_intr_setup;
}
for (i = 0; (io = ocs_io_get_instance(ocs, i)); i++) {
if (bus_dmamap_create(ocs->buf_dmat, 0, &io->tgt_io.dmap)) {
device_printf(ocs->dev, "%s: bad dma map create\n", __func__);
}
io->tgt_io.state = OCS_CAM_IO_FREE;
}
if (ocs_setup_fcports(ocs)) {
device_printf(ocs->dev, "FCports creation failed\n");
goto fail_intr_setup;
}
if(ocs_cam_attach(ocs)) {
device_printf(ocs->dev, "cam attach failed \n");
goto fail_intr_setup;
}
if (ocs_intr_setup(ocs)) {
device_printf(ocs->dev, "Interrupt setup failed\n");
goto fail_intr_setup;
}
if (ocs->enable_ini || ocs->enable_tgt) {
if (ocs_xport_control(ocs->xport, OCS_XPORT_PORT_ONLINE)) {
device_printf(ocs->dev, "Can't init port\n");
goto fail_xport_online;
}
}
ocs->attached = true;
return 0;
fail_xport_online:
if (ocs_xport_control(ocs->xport, OCS_XPORT_SHUTDOWN)) {
device_printf(ocs->dev, "Transport Shutdown timed out\n");
}
ocs_intr_teardown(ocs);
fail_intr_setup:
fail_xport_init:
ocs_xport_detach(ocs->xport);
if (ocs->config_tgt)
ocs_scsi_tgt_del_device(ocs);
ocs_xport_free(ocs->xport);
ocs->xport = NULL;
fail_xport_attach:
if (ocs->xport)
ocs_free(ocs, ocs->xport, sizeof(*(ocs->xport)));
ocs->xport = NULL;
return ENXIO;
}
/**
* @brief Connect the driver to the given device
*
* If the probe routine is successful, the OS will give the driver
* the opportunity to connect itself to the device. This routine
* maps PCI resources (memory BARs and interrupts) and initialize a
* hardware object.
*
* @param dev device abstraction
*
* @return 0 if the driver attaches to the device, ENXIO otherwise
*/
static int
ocs_pci_attach(device_t dev)
{
struct ocs_softc *ocs;
int instance;
instance = device_get_unit(dev);
ocs = (struct ocs_softc *)device_get_softc(dev);
if (NULL == ocs) {
device_printf(dev, "cannot allocate softc\n");
return ENOMEM;
}
memset(ocs, 0, sizeof(struct ocs_softc));
if (instance < ARRAY_SIZE(ocs_devices)) {
ocs_devices[instance] = ocs;
} else {
device_printf(dev, "got unexpected ocs instance number %d\n", instance);
}
ocs->instance_index = instance;
ocs->dev = dev;
pci_enable_io(dev, SYS_RES_MEMORY);
pci_enable_busmaster(dev);
ocs->pci_vendor = pci_get_vendor(dev);
ocs->pci_device = pci_get_device(dev);
snprintf(ocs->businfo, sizeof(ocs->businfo), "%02X:%02X:%02X",
pci_get_bus(dev), pci_get_slot(dev), pci_get_function(dev));
/* Map all memory BARs */
if (ocs_map_bars(dev, ocs)) {
device_printf(dev, "Failed to map pci bars\n");
goto release_bus;
}
/* create a root DMA tag for the device */
if (bus_dma_tag_create(bus_get_dma_tag(dev),
1, /* byte alignment */
0, /* no boundary restrictions */
BUS_SPACE_MAXADDR, /* no minimum low address */
BUS_SPACE_MAXADDR, /* no maximum high address */
NULL, /* no filter function */
NULL, /* or arguments */
BUS_SPACE_MAXSIZE, /* max size covered by tag */
BUS_SPACE_UNRESTRICTED, /* no segment count restrictions */
BUS_SPACE_MAXSIZE, /* no segment length restrictions */
0, /* flags */
NULL, /* no lock manipulation function */
NULL, /* or arguments */
&ocs->dmat)) {
device_printf(dev, "parent DMA tag allocation failed\n");
goto release_bus;
}
if (ocs_intr_alloc(ocs)) {
device_printf(dev, "Interrupt allocation failed\n");
goto release_bus;
}
if (PCIC_SERIALBUS == pci_get_class(dev) &&
PCIS_SERIALBUS_FC == pci_get_subclass(dev))
ocs->ocs_xport = OCS_XPORT_FC;
else {
device_printf(dev, "unsupported class (%#x : %#x)\n",
pci_get_class(dev),
pci_get_class(dev));
goto release_bus;
}
/* Setup tunable parameters */
if (ocs_setup_params(ocs)) {
device_printf(ocs->dev, "failed to setup params\n");
goto release_bus;
}
if (ocs_device_attach(ocs)) {
device_printf(ocs->dev, "failed to attach device\n");
goto release_params;
}
ocs->fc_type = FC_TYPE_FCP;
ocs_debug_attach(ocs);
return 0;
release_params:
ocs_ramlog_free(ocs, ocs->ramlog);
ocs_device_lock_free(ocs);
free(ocs->hw_war_version, M_OCS);
release_bus:
ocs_release_bus(ocs);
return ENXIO;
}
/**
* @brief free resources when pci device detach
*
* @param ocs pointer to ocs structure
*
* @return 0 for success, a negative error code value for failure.
*/
int32_t
ocs_device_detach(ocs_t *ocs)
{
int32_t rc = 0, i;
ocs_io_t *io = NULL;
if (ocs != NULL) {
if (!ocs->attached) {
ocs_log_warn(ocs, "%s: Device is not attached\n", __func__);
return -1;
}
rc = ocs_xport_control(ocs->xport, OCS_XPORT_SHUTDOWN);
if (rc) {
ocs_log_err(ocs, "%s: Transport Shutdown timed out\n", __func__);
}
ocs_intr_teardown(ocs);
if (ocs_xport_detach(ocs->xport) != 0) {
ocs_log_err(ocs, "%s: Transport detach failed\n", __func__);
}
ocs_cam_detach(ocs);
ocs_free(ocs, ocs->fcports, sizeof(ocs->fcports));
for (i = 0; (io = ocs_io_get_instance(ocs, i)); i++) {
if (bus_dmamap_destroy(ocs->buf_dmat, io->tgt_io.dmap)) {
device_printf(ocs->dev, "%s: bad dma map destroy\n", __func__);
}
}
bus_dma_tag_destroy(ocs->dmat);
ocs_xport_free(ocs->xport);
ocs->xport = NULL;
ocs->attached = FALSE;
}
return 0;
}
/**
* @brief Detach the driver from the given device
*
* If the driver is a loadable module, this routine gets called at unload
* time. This routine will stop the device and free any allocated resources.
*
* @param dev device abstraction
*
* @return 0 if the driver detaches from the device, ENXIO otherwise
*/
static int
ocs_pci_detach(device_t dev)
{
struct ocs_softc *ocs;
ocs = (struct ocs_softc *)device_get_softc(dev);
if (!ocs) {
device_printf(dev, "no driver context?!?\n");
return -1;
}
if (ocs->config_tgt && ocs->enable_tgt) {
device_printf(dev, "can't detach with target mode enabled\n");
return EBUSY;
}
ocs_device_detach(ocs);
/*
* Workaround for OCS SCSI Transport quirk.
*
* CTL requires that target mode is disabled prior to unloading the
* driver (ie ocs->enable_tgt = FALSE), but once the target is disabled,
* the transport will not call ocs_scsi_tgt_del_device() which deallocates
* CAM resources. The workaround is to explicitly make the call here.
*/
if (ocs->config_tgt)
ocs_scsi_tgt_del_device(ocs);
/* free strdup created buffer.*/
free(ocs->hw_war_version, M_OCS);
ocs_device_lock_free(ocs);
ocs_debug_detach(ocs);
ocs_ramlog_free(ocs, ocs->ramlog);
ocs_release_bus(ocs);
return 0;
}
/**
* @brief Notify driver of system shutdown
*
* @param dev device abstraction
*
* @return 0 if the driver attaches to the device, ENXIO otherwise
*/
static int
ocs_pci_shutdown(device_t dev)
{
device_printf(dev, "%s\n", __func__);
return 0;
}
/**
* @brief Release bus resources allocated within the soft context
*
* @param ocs Pointer to the driver's context
*
* @return none
*/
static void
ocs_release_bus(struct ocs_softc *ocs)
{
if (NULL != ocs) {
uint32_t i;
ocs_intr_teardown(ocs);
if (ocs->irq) {
bus_release_resource(ocs->dev, SYS_RES_IRQ,
rman_get_rid(ocs->irq), ocs->irq);
if (ocs->n_vec) {
pci_release_msi(ocs->dev);
ocs->n_vec = 0;
}
ocs->irq = NULL;
}
bus_dma_tag_destroy(ocs->dmat);
for (i = 0; i < PCI_MAX_BAR; i++) {
if (ocs->reg[i].res) {
bus_release_resource(ocs->dev, SYS_RES_MEMORY,
ocs->reg[i].rid,
ocs->reg[i].res);
}
}
}
}
/**
* @brief Allocate and initialize interrupts
*
* @param ocs Pointer to the driver's context
*
* @return none
*/
static int32_t
ocs_intr_alloc(struct ocs_softc *ocs)
{
ocs->n_vec = 1;
if (pci_alloc_msix(ocs->dev, &ocs->n_vec)) {
device_printf(ocs->dev, "MSI-X allocation failed\n");
if (pci_alloc_msi(ocs->dev, &ocs->n_vec)) {
device_printf(ocs->dev, "MSI allocation failed \n");
ocs->irqid = 0;
ocs->n_vec = 0;
} else
ocs->irqid = 1;
} else {
ocs->irqid = 1;
}
ocs->irq = bus_alloc_resource_any(ocs->dev, SYS_RES_IRQ, &ocs->irqid,
RF_ACTIVE | RF_SHAREABLE);
if (NULL == ocs->irq) {
device_printf(ocs->dev, "could not allocate interrupt\n");
return -1;
}
ocs->intr_ctx.vec = 0;
ocs->intr_ctx.softc = ocs;
snprintf(ocs->intr_ctx.name, sizeof(ocs->intr_ctx.name),
"%s_intr_%d",
device_get_nameunit(ocs->dev),
ocs->intr_ctx.vec);
return 0;
}
/**
* @brief Create and attach an interrupt handler
*
* @param ocs Pointer to the driver's context
*
* @return 0 on success, non-zero otherwise
*/
static int32_t
ocs_intr_setup(struct ocs_softc *ocs)
{
driver_filter_t *filter = NULL;
if (0 == ocs->n_vec) {
filter = ocs_pci_intx_filter;
}
if (bus_setup_intr(ocs->dev, ocs->irq, INTR_MPSAFE | INTR_TYPE_CAM,
filter, ocs_pci_intr, &ocs->intr_ctx,
&ocs->tag)) {
device_printf(ocs->dev, "could not initialize interrupt\n");
return -1;
}
return 0;
}
/**
* @brief Detach an interrupt handler
*
* @param ocs Pointer to the driver's context
*
* @return 0 on success, non-zero otherwise
*/
static int32_t
ocs_intr_teardown(struct ocs_softc *ocs)
{
if (!ocs) {
printf("%s: bad driver context?!?\n", __func__);
return -1;
}
if (ocs->tag) {
bus_teardown_intr(ocs->dev, ocs->irq, ocs->tag);
ocs->tag = NULL;
}
return 0;
}
/**
* @brief PCI interrupt handler
*
* @param arg pointer to the driver's software context
*
* @return FILTER_HANDLED if interrupt is processed, FILTER_STRAY otherwise
*/
static int
ocs_pci_intx_filter(void *arg)
{
ocs_intr_ctx_t *intr = arg;
struct ocs_softc *ocs = NULL;
uint16_t val = 0;
if (NULL == intr) {
return FILTER_STRAY;
}
ocs = intr->softc;
#ifndef PCIM_STATUS_INTR
#define PCIM_STATUS_INTR 0x0008
#endif
val = pci_read_config(ocs->dev, PCIR_STATUS, 2);
if (0xffff == val) {
device_printf(ocs->dev, "%s: pci_read_config(PCIR_STATUS) failed\n", __func__);
return FILTER_STRAY;
}
if (0 == (val & PCIM_STATUS_INTR)) {
return FILTER_STRAY;
}
val = pci_read_config(ocs->dev, PCIR_COMMAND, 2);
val |= PCIM_CMD_INTxDIS;
pci_write_config(ocs->dev, PCIR_COMMAND, val, 2);
return FILTER_SCHEDULE_THREAD;
}
/**
* @brief interrupt handler
*
* @param context pointer to the interrupt context
*/
static void
ocs_pci_intr(void *context)
{
ocs_intr_ctx_t *intr = context;
struct ocs_softc *ocs = intr->softc;
mtx_lock(&ocs->sim_lock);
ocs_hw_process(&ocs->hw, intr->vec, OCS_OS_MAX_ISR_TIME_MSEC);
mtx_unlock(&ocs->sim_lock);
}
/**
* @brief Initialize DMA tag
*
* @param ocs the driver instance's software context
*
* @return 0 on success, non-zero otherwise
*/
static int32_t
ocs_init_dma_tag(struct ocs_softc *ocs)
{
uint32_t max_sgl = 0;
uint32_t max_sge = 0;
/*
* IOs can't use the parent DMA tag and must create their
* own, based primarily on a restricted number of DMA segments.
* This is more of a BSD requirement than a SLI Port requirement
*/
ocs_hw_get(&ocs->hw, OCS_HW_N_SGL, &max_sgl);
ocs_hw_get(&ocs->hw, OCS_HW_MAX_SGE, &max_sge);
if (bus_dma_tag_create(ocs->dmat,
1, /* byte alignment */
0, /* no boundary restrictions */
BUS_SPACE_MAXADDR, /* no minimum low address */
BUS_SPACE_MAXADDR, /* no maximum high address */
NULL, /* no filter function */
NULL, /* or arguments */
BUS_SPACE_MAXSIZE, /* max size covered by tag */
max_sgl, /* segment count restrictions */
max_sge, /* segment length restrictions */
0, /* flags */
NULL, /* no lock manipulation function */
NULL, /* or arguments */
&ocs->buf_dmat)) {
device_printf(ocs->dev, "%s: bad bus_dma_tag_create(buf_dmat)\n", __func__);
return -1;
}
return 0;
}
int32_t
ocs_get_property(const char *prop_name, char *buffer, uint32_t buffer_len)
{
return -1;
}
/**
* @brief return pointer to ocs structure given instance index
*
* A pointer to an ocs structure is returned given an instance index.
*
* @param index index to ocs_devices array
*
* @return ocs pointer
*/
ocs_t *ocs_get_instance(uint32_t index)
{
if (index < ARRAY_SIZE(ocs_devices)) {
return ocs_devices[index];
}
return NULL;
}
/**
* @brief Return instance index of an opaque ocs structure
*
* Returns the ocs instance index
*
* @param os pointer to ocs instance
*
* @return pointer to ocs instance index
*/
uint32_t
ocs_instance(void *os)
{
ocs_t *ocs = os;
return ocs->instance_index;
}
static device_method_t ocs_methods[] = {
DEVMETHOD(device_probe, ocs_pci_probe),
DEVMETHOD(device_attach, ocs_pci_attach),
DEVMETHOD(device_detach, ocs_pci_detach),
DEVMETHOD(device_shutdown, ocs_pci_shutdown),
{0, 0}
};
static driver_t ocs_driver = {
"ocs_fc",
ocs_methods,
sizeof(struct ocs_softc)
};
static devclass_t ocs_devclass;
DRIVER_MODULE(ocs_fc, pci, ocs_driver, ocs_devclass, 0, 0);
MODULE_VERSION(ocs_fc, 1);

2960
sys/dev/ocs_fc/ocs_scsi.c Normal file

File diff suppressed because it is too large Load diff

454
sys/dev/ocs_fc/ocs_scsi.h Normal file
View file

@ -0,0 +1,454 @@
/*-
* Copyright (c) 2017 Broadcom. All rights reserved.
* The term "Broadcom" refers to Broadcom Limited and/or its subsidiaries.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* $FreeBSD$
*/
/**
* @file
* OCS SCSI API declarations
*
*/
#if !defined(__OCS_SCSI_H__)
#define __OCS_SCSI_H__
#include "ocs_ddump.h"
#include "ocs_mgmt.h"
#include "ocs_utils.h"
/* ocs_scsi_rcv_cmd() ocs_scsi_rcv_tmf() flags */
#define OCS_SCSI_CMD_DIR_IN (1U << 0)
#define OCS_SCSI_CMD_DIR_OUT (1U << 1)
#define OCS_SCSI_CMD_SIMPLE (1U << 2)
#define OCS_SCSI_CMD_HEAD_OF_QUEUE (1U << 3)
#define OCS_SCSI_CMD_ORDERED (1U << 4)
#define OCS_SCSI_CMD_UNTAGGED (1U << 5)
#define OCS_SCSI_CMD_ACA (1U << 6)
#define OCS_SCSI_FIRST_BURST_ERR (1U << 7)
#define OCS_SCSI_FIRST_BURST_ABORTED (1U << 8)
/* ocs_scsi_send_rd_data/recv_wr_data/send_resp flags */
#define OCS_SCSI_LAST_DATAPHASE (1U << 0)
#define OCS_SCSI_NO_AUTO_RESPONSE (1U << 1)
#define OCS_SCSI_LOW_LATENCY (1U << 2)
#define OCS_SCSI_WQ_STEERING_SHIFT (16)
#define OCS_SCSI_WQ_STEERING_MASK (0xf << OCS_SCSI_WQ_STEERING_SHIFT)
#define OCS_SCSI_WQ_STEERING_CLASS (0 << OCS_SCSI_WQ_STEERING_SHIFT)
#define OCS_SCSI_WQ_STEERING_REQUEST (1 << OCS_SCSI_WQ_STEERING_SHIFT)
#define OCS_SCSI_WQ_STEERING_CPU (2 << OCS_SCSI_WQ_STEERING_SHIFT)
#define OCS_SCSI_WQ_CLASS_SHIFT (20)
#define OCS_SCSI_WQ_CLASS_MASK (0xf << OCS_SCSI_WQ_CLASS_SHIFT)
#define OCS_SCSI_WQ_CLASS(x) ((x & OCS_SCSI_WQ_CLASS_MASK) << OCS_SCSI_WQ_CLASS_SHIFT)
#define OCS_SCSI_WQ_CLASS_LOW_LATENCY (1)
/*!
* @defgroup scsi_api_base SCSI Base Target/Initiator
* @defgroup scsi_api_target SCSI Target
* @defgroup scsi_api_initiator SCSI Initiator
*/
/**
* @brief SCSI command response.
*
* This structure is used by target-servers to specify SCSI status and
* sense data. In this case all but the @b residual element are used. For
* initiator-clients, this structure is used by the SCSI API to convey the
* response data for issued commands, including the residual element.
*/
typedef struct {
uint8_t scsi_status; /**< SCSI status */
uint16_t scsi_status_qualifier; /**< SCSI status qualifier */
uint8_t *response_data; /**< pointer to response data buffer */
uint32_t response_data_length; /**< length of response data buffer (bytes) */
uint8_t *sense_data; /**< pointer to sense data buffer */
uint32_t sense_data_length; /**< length of sense data buffer (bytes) */
int32_t residual; /**< command residual (not used for target), positive value
* indicates an underflow, negative value indicates overflow
*/
uint32_t response_wire_length; /**< Command response length received in wcqe */
} ocs_scsi_cmd_resp_t;
/* Status values returned by IO callbacks */
typedef enum {
OCS_SCSI_STATUS_GOOD = 0,
OCS_SCSI_STATUS_ABORTED,
OCS_SCSI_STATUS_ERROR,
OCS_SCSI_STATUS_DIF_GUARD_ERROR,
OCS_SCSI_STATUS_DIF_REF_TAG_ERROR,
OCS_SCSI_STATUS_DIF_APP_TAG_ERROR,
OCS_SCSI_STATUS_DIF_UNKNOWN_ERROR,
OCS_SCSI_STATUS_PROTOCOL_CRC_ERROR,
OCS_SCSI_STATUS_NO_IO,
OCS_SCSI_STATUS_ABORT_IN_PROGRESS,
OCS_SCSI_STATUS_CHECK_RESPONSE,
OCS_SCSI_STATUS_COMMAND_TIMEOUT,
OCS_SCSI_STATUS_TIMEDOUT_AND_ABORTED,
OCS_SCSI_STATUS_SHUTDOWN,
OCS_SCSI_STATUS_NEXUS_LOST,
} ocs_scsi_io_status_e;
/* SCSI command status */
#define SCSI_STATUS_GOOD 0x00
#define SCSI_STATUS_CHECK_CONDITION 0x02
#define SCSI_STATUS_CONDITION_MET 0x04
#define SCSI_STATUS_BUSY 0x08
#define SCSI_STATUS_RESERVATION_CONFLICT 0x18
#define SCSI_STATUS_TASK_SET_FULL 0x28
#define SCSI_STATUS_ACA_ACTIVE 0x30
#define SCSI_STATUS_TASK_ABORTED 0x40
/* Callback used by send_rd_data(), recv_wr_data(), send_resp() */
typedef int32_t (*ocs_scsi_io_cb_t)(ocs_io_t *io, ocs_scsi_io_status_e status, uint32_t flags,
void *arg);
/* Callback used by send_rd_io(), send_wr_io() */
typedef int32_t (*ocs_scsi_rsp_io_cb_t)(ocs_io_t *io, ocs_scsi_io_status_e status, ocs_scsi_cmd_resp_t *rsp,
uint32_t flags, void *arg);
/* ocs_scsi_cb_t flags */
#define OCS_SCSI_IO_CMPL (1U << 0) /* IO completed */
#define OCS_SCSI_IO_CMPL_RSP_SENT (1U << 1) /* IO completed, response sent */
#define OCS_SCSI_IO_ABORTED (1U << 2) /* IO was aborted */
/* ocs_scsi_recv_tmf() request values */
typedef enum {
OCS_SCSI_TMF_ABORT_TASK = 1,
OCS_SCSI_TMF_QUERY_TASK_SET,
OCS_SCSI_TMF_ABORT_TASK_SET,
OCS_SCSI_TMF_CLEAR_TASK_SET,
OCS_SCSI_TMF_QUERY_ASYNCHRONOUS_EVENT,
OCS_SCSI_TMF_LOGICAL_UNIT_RESET,
OCS_SCSI_TMF_CLEAR_ACA,
OCS_SCSI_TMF_TARGET_RESET,
} ocs_scsi_tmf_cmd_e;
/* ocs_scsi_send_tmf_resp() response values */
typedef enum {
OCS_SCSI_TMF_FUNCTION_COMPLETE = 1,
OCS_SCSI_TMF_FUNCTION_SUCCEEDED,
OCS_SCSI_TMF_FUNCTION_IO_NOT_FOUND,
OCS_SCSI_TMF_FUNCTION_REJECTED,
OCS_SCSI_TMF_INCORRECT_LOGICAL_UNIT_NUMBER,
OCS_SCSI_TMF_SERVICE_DELIVERY,
} ocs_scsi_tmf_resp_e;
/**
* @brief property names for ocs_scsi_get_property() functions
*/
typedef enum {
OCS_SCSI_MAX_SGE,
OCS_SCSI_MAX_SGL,
OCS_SCSI_WWNN,
OCS_SCSI_WWPN,
OCS_SCSI_SERIALNUMBER,
OCS_SCSI_PARTNUMBER,
OCS_SCSI_PORTNUM,
OCS_SCSI_BIOS_VERSION_STRING,
OCS_SCSI_MAX_IOS,
OCS_SCSI_DIF_CAPABLE,
OCS_SCSI_DIF_MULTI_SEPARATE,
OCS_SCSI_MAX_FIRST_BURST,
OCS_SCSI_ENABLE_TASK_SET_FULL,
} ocs_scsi_property_e;
#define DIF_SIZE 8
/**
* @brief T10 DIF operations
*
* WARNING: do not reorder or insert to this list without making appropriate changes in ocs_dif.c
*/
typedef enum {
OCS_SCSI_DIF_OPER_DISABLED,
OCS_SCSI_DIF_OPER_IN_NODIF_OUT_CRC,
OCS_SCSI_DIF_OPER_IN_CRC_OUT_NODIF,
OCS_SCSI_DIF_OPER_IN_NODIF_OUT_CHKSUM,
OCS_SCSI_DIF_OPER_IN_CHKSUM_OUT_NODIF,
OCS_SCSI_DIF_OPER_IN_CRC_OUT_CRC,
OCS_SCSI_DIF_OPER_IN_CHKSUM_OUT_CHKSUM,
OCS_SCSI_DIF_OPER_IN_CRC_OUT_CHKSUM,
OCS_SCSI_DIF_OPER_IN_CHKSUM_OUT_CRC,
OCS_SCSI_DIF_OPER_IN_RAW_OUT_RAW,
} ocs_scsi_dif_oper_e;
#define OCS_SCSI_DIF_OPER_PASS_THRU OCS_SCSI_DIF_OPER_IN_CRC_OUT_CRC
#define OCS_SCSI_DIF_OPER_STRIP OCS_SCSI_DIF_OPER_IN_CRC_OUT_NODIF
#define OCS_SCSI_DIF_OPER_INSERT OCS_SCSI_DIF_OPER_IN_NODIF_OUT_CRC
/**
* @brief T10 DIF block sizes
*/
typedef enum {
OCS_SCSI_DIF_BK_SIZE_512,
OCS_SCSI_DIF_BK_SIZE_1024,
OCS_SCSI_DIF_BK_SIZE_2048,
OCS_SCSI_DIF_BK_SIZE_4096,
OCS_SCSI_DIF_BK_SIZE_520,
OCS_SCSI_DIF_BK_SIZE_4104
} ocs_scsi_dif_blk_size_e;
/**
* @brief generic scatter-gather list structure
*/
typedef struct ocs_scsi_sgl_s {
uintptr_t addr; /**< physical address */
uintptr_t dif_addr; /**< address of DIF segment, zero if DIF is interleaved */
size_t len; /**< length */
} ocs_scsi_sgl_t;
/**
* @brief T10 DIF information passed to the transport
*/
typedef struct ocs_scsi_dif_info_s {
ocs_scsi_dif_oper_e dif_oper;
ocs_scsi_dif_blk_size_e blk_size;
uint32_t ref_tag;
uint32_t app_tag:16,
check_ref_tag:1,
check_app_tag:1,
check_guard:1,
dif_separate:1,
/* If the APP TAG is 0xFFFF, disable checking the REF TAG and CRC fields */
disable_app_ffff:1,
/* if the APP TAG is 0xFFFF and REF TAG is 0xFFFF_FFFF, disable checking the received CRC field. */
disable_app_ref_ffff:1,
:10;
uint64_t lba;
} ocs_scsi_dif_info_t;
/* Return values for calls from base driver to target-server/initiator-client */
#define OCS_SCSI_CALL_COMPLETE 0 /* All work is done */
#define OCS_SCSI_CALL_ASYNC 1 /* Work will be completed asynchronously */
/* Calls from target/initiator to base driver */
typedef enum {
OCS_SCSI_IO_ROLE_ORIGINATOR,
OCS_SCSI_IO_ROLE_RESPONDER,
} ocs_scsi_io_role_e;
extern void ocs_scsi_io_alloc_enable(ocs_node_t *node);
extern void ocs_scsi_io_alloc_disable(ocs_node_t *node);
extern ocs_io_t *ocs_scsi_io_alloc(ocs_node_t *node, ocs_scsi_io_role_e role);
extern void ocs_scsi_io_free(ocs_io_t *io);
extern ocs_io_t *ocs_io_get_instance(ocs_t *ocs, uint32_t index);
extern void ocs_scsi_register_bounce(ocs_t *ocs, void(*fctn)(void(*fctn)(void *arg), void *arg,
uint32_t s_id, uint32_t d_id, uint32_t ox_id));
/* Calls from base driver to target-server */
extern int32_t ocs_scsi_tgt_driver_init(void);
extern int32_t ocs_scsi_tgt_driver_exit(void);
extern int32_t ocs_scsi_tgt_io_init(ocs_io_t *io);
extern int32_t ocs_scsi_tgt_io_exit(ocs_io_t *io);
extern int32_t ocs_scsi_tgt_new_device(ocs_t *ocs);
extern int32_t ocs_scsi_tgt_del_device(ocs_t *ocs);
extern int32_t ocs_scsi_tgt_new_domain(ocs_domain_t *domain);
extern void ocs_scsi_tgt_del_domain(ocs_domain_t *domain);
extern int32_t ocs_scsi_tgt_new_sport(ocs_sport_t *sport);
extern void ocs_scsi_tgt_del_sport(ocs_sport_t *sport);
extern void ocs_scsi_sport_deleted(ocs_sport_t *sport);
extern int32_t ocs_scsi_validate_initiator(ocs_node_t *node);
extern int32_t ocs_scsi_new_initiator(ocs_node_t *node);
typedef enum {
OCS_SCSI_INITIATOR_DELETED,
OCS_SCSI_INITIATOR_MISSING,
} ocs_scsi_del_initiator_reason_e;
extern int32_t ocs_scsi_del_initiator(ocs_node_t *node, ocs_scsi_del_initiator_reason_e reason);
extern int32_t ocs_scsi_recv_cmd(ocs_io_t *io, uint64_t lun, uint8_t *cdb, uint32_t cdb_len, uint32_t flags);
extern int32_t ocs_scsi_recv_cmd_first_burst(ocs_io_t *io, uint64_t lun, uint8_t *cdb, uint32_t cdb_len, uint32_t flags,
ocs_dma_t first_burst_buffers[], uint32_t first_burst_bytes);
extern int32_t ocs_scsi_recv_tmf(ocs_io_t *tmfio, uint64_t lun, ocs_scsi_tmf_cmd_e cmd, ocs_io_t *abortio,
uint32_t flags);
extern ocs_sport_t *ocs_sport_get_instance(ocs_domain_t *domain, uint32_t index);
extern ocs_domain_t *ocs_domain_get_instance(ocs_t *ocs, uint32_t index);
/* Calls from target-server to base driver */
extern int32_t ocs_scsi_send_rd_data(ocs_io_t *io, uint32_t flags,
ocs_scsi_dif_info_t *dif_info,
ocs_scsi_sgl_t *sgl, uint32_t sgl_count,
uint32_t wire_len, ocs_scsi_io_cb_t cb, void *arg);
extern int32_t ocs_scsi_recv_wr_data(ocs_io_t *io, uint32_t flags,
ocs_scsi_dif_info_t *dif_info,
ocs_scsi_sgl_t *sgl, uint32_t sgl_count,
uint32_t wire_len, ocs_scsi_io_cb_t cb, void *arg);
extern int32_t ocs_scsi_send_resp(ocs_io_t *io, uint32_t flags, ocs_scsi_cmd_resp_t *rsp,
ocs_scsi_io_cb_t cb, void *arg);
extern int32_t ocs_scsi_send_tmf_resp(ocs_io_t *io, ocs_scsi_tmf_resp_e rspcode, uint8_t addl_rsp_info[3],
ocs_scsi_io_cb_t cb, void *arg);
extern int32_t ocs_scsi_tgt_abort_io(ocs_io_t *io, ocs_scsi_io_cb_t cb, void *arg);
extern void ocs_scsi_io_complete(ocs_io_t *io);
extern uint32_t ocs_scsi_get_property(ocs_t *ocs, ocs_scsi_property_e prop);
extern void *ocs_scsi_get_property_ptr(ocs_t *ocs, ocs_scsi_property_e prop);
extern void ocs_scsi_del_initiator_complete(ocs_node_t *node);
extern void ocs_scsi_update_first_burst_transferred(ocs_io_t *io, uint32_t transferred);
/* Calls from base driver to initiator-client */
extern int32_t ocs_scsi_ini_driver_init(void);
extern int32_t ocs_scsi_ini_driver_exit(void);
extern int32_t ocs_scsi_ini_io_init(ocs_io_t *io);
extern int32_t ocs_scsi_ini_io_exit(ocs_io_t *io);
extern int32_t ocs_scsi_ini_new_device(ocs_t *ocs);
extern int32_t ocs_scsi_ini_del_device(ocs_t *ocs);
extern int32_t ocs_scsi_ini_new_domain(ocs_domain_t *domain);
extern void ocs_scsi_ini_del_domain(ocs_domain_t *domain);
extern int32_t ocs_scsi_ini_new_sport(ocs_sport_t *sport);
extern void ocs_scsi_ini_del_sport(ocs_sport_t *sport);
extern int32_t ocs_scsi_new_target(ocs_node_t *node);
typedef enum {
OCS_SCSI_TARGET_DELETED,
OCS_SCSI_TARGET_MISSING,
} ocs_scsi_del_target_reason_e;
extern int32_t ocs_scsi_del_target(ocs_node_t *node, ocs_scsi_del_target_reason_e reason);
/* Calls from the initiator-client to the base driver */
extern int32_t ocs_scsi_send_rd_io(ocs_node_t *node, ocs_io_t *io, uint64_t lun, void *cdb, uint32_t cdb_len,
ocs_scsi_dif_info_t *dif_info,
ocs_scsi_sgl_t *sgl, uint32_t sgl_count, uint32_t wire_len, ocs_scsi_rsp_io_cb_t cb, void *arg);
extern int32_t ocs_scsi_send_wr_io(ocs_node_t *node, ocs_io_t *io, uint64_t lun, void *cdb, uint32_t cdb_len,
ocs_scsi_dif_info_t *dif_info,
ocs_scsi_sgl_t *sgl, uint32_t sgl_count, uint32_t wire_len, ocs_scsi_rsp_io_cb_t cb, void *arg);
extern int32_t ocs_scsi_send_wr_io_first_burst(ocs_node_t *node, ocs_io_t *io, uint64_t lun, void *cdb, uint32_t cdb_len,
ocs_scsi_dif_info_t *dif_info,
ocs_scsi_sgl_t *sgl, uint32_t sgl_count, uint32_t wire_len, uint32_t first_burst,
ocs_scsi_rsp_io_cb_t cb, void *arg);
extern int32_t ocs_scsi_send_tmf(ocs_node_t *node, ocs_io_t *io, ocs_io_t *io_to_abort, uint64_t lun,
ocs_scsi_tmf_cmd_e tmf, ocs_scsi_sgl_t *sgl, uint32_t sgl_count, uint32_t len, ocs_scsi_rsp_io_cb_t cb, void *arg);
extern int32_t ocs_scsi_send_nodata_io(ocs_node_t *node, ocs_io_t *io, uint64_t lun, void *cdb, uint32_t cdb_len, ocs_scsi_rsp_io_cb_t cb, void *arg);
extern void ocs_scsi_del_target_complete(ocs_node_t *node);
typedef enum {
OCS_SCSI_DDUMP_DEVICE,
OCS_SCSI_DDUMP_DOMAIN,
OCS_SCSI_DDUMP_SPORT,
OCS_SCSI_DDUMP_NODE,
OCS_SCSI_DDUMP_IO,
} ocs_scsi_ddump_type_e;
/* base driver to target/initiator */
struct ocs_scsi_vaddr_len_s {
void *vaddr;
uint32_t length;
} ;
extern int32_t ocs_scsi_get_block_vaddr(ocs_io_t *io, uint64_t blocknumber, ocs_scsi_vaddr_len_t addrlen[],
uint32_t max_addrlen, void **dif_vaddr);
extern void ocs_scsi_ini_ddump(ocs_textbuf_t *textbuf, ocs_scsi_ddump_type_e type, void *obj);
extern void ocs_scsi_tgt_ddump(ocs_textbuf_t *textbuf, ocs_scsi_ddump_type_e type, void *obj);
/* Calls within base driver */
extern int32_t ocs_scsi_io_dispatch(ocs_io_t *io, void *cb);
extern int32_t ocs_scsi_io_dispatch_abort(ocs_io_t *io, void *cb);
extern void ocs_scsi_check_pending(ocs_t *ocs);
extern uint32_t ocs_scsi_dif_blocksize(ocs_scsi_dif_info_t *dif_info);
extern int32_t ocs_scsi_dif_set_blocksize(ocs_scsi_dif_info_t *dif_info, uint32_t blocksize);
extern int32_t ocs_scsi_dif_mem_blocksize(ocs_scsi_dif_info_t *dif_info, int wiretomem);
extern int32_t ocs_scsi_dif_wire_blocksize(ocs_scsi_dif_info_t *dif_info, int wiretomem);
uint32_t ocs_get_crn(ocs_node_t *node, uint8_t *crn, uint64_t lun);
void ocs_del_crn(ocs_node_t *node);
void ocs_reset_crn(ocs_node_t *node, uint64_t lun);
/**
* @brief Notification from base driver that domain is in force-free path.
*
* @par Description Domain is forcefully going away. Cleanup any resources associated with it.
*
* @param domain Pointer to domain being free'd.
*
* @return None.
*/
static inline void
ocs_scsi_notify_domain_force_free(ocs_domain_t *domain)
{
/* Nothing to do */
return;
}
/**
* @brief Notification from base driver that sport is in force-free path.
*
* @par Description Sport is forcefully going away. Cleanup any resources associated with it.
*
* @param sport Pointer to sport being free'd.
*
* @return None.
*/
static inline void
ocs_scsi_notify_sport_force_free(ocs_sport_t *sport)
{
/* Nothing to do */
return;
}
/**
* @brief Notification from base driver that node is in force-free path.
*
* @par Description Node is forcefully going away. Cleanup any resources associated with it.
*
* @param node Pointer to node being free'd.
*
* @return None.
*/
static inline void
ocs_scsi_notify_node_force_free(ocs_node_t *node)
{
/* Nothing to do */
return;
}
#endif /* __OCS_SCSI_H__ */

207
sys/dev/ocs_fc/ocs_sm.c Normal file
View file

@ -0,0 +1,207 @@
/*-
* Copyright (c) 2017 Broadcom. All rights reserved.
* The term "Broadcom" refers to Broadcom Limited and/or its subsidiaries.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* $FreeBSD$
*/
/**
* @file
* Generic state machine framework.
*/
#include "ocs_os.h"
#include "ocs_sm.h"
const char *ocs_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
ocs_sm_post_event(ocs_sm_ctx_t *ctx, ocs_sm_event_t 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
ocs_sm_transition(ocs_sm_ctx_t *ctx, ocs_sm_function_t state, void *data)
{
if (ctx->current_state == state) {
ocs_sm_post_event(ctx, OCS_EVT_REENTER, data);
} else {
ocs_sm_post_event(ctx, OCS_EVT_EXIT, data);
ctx->current_state = state;
ocs_sm_post_event(ctx, OCS_EVT_ENTER, data);
}
}
/**
* @brief Disable further state machine processing.
*/
void
ocs_sm_disable(ocs_sm_ctx_t *ctx)
{
ctx->current_state = NULL;
}
const char *ocs_sm_event_name(ocs_sm_event_t evt)
{
switch (evt) {
#define RETEVT(x) case x: return #x;
RETEVT(OCS_EVT_ENTER)
RETEVT(OCS_EVT_REENTER)
RETEVT(OCS_EVT_EXIT)
RETEVT(OCS_EVT_SHUTDOWN)
RETEVT(OCS_EVT_RESPONSE)
RETEVT(OCS_EVT_RESUME)
RETEVT(OCS_EVT_TIMER_EXPIRED)
RETEVT(OCS_EVT_ERROR)
RETEVT(OCS_EVT_SRRS_ELS_REQ_OK)
RETEVT(OCS_EVT_SRRS_ELS_CMPL_OK)
RETEVT(OCS_EVT_SRRS_ELS_REQ_FAIL)
RETEVT(OCS_EVT_SRRS_ELS_CMPL_FAIL)
RETEVT(OCS_EVT_SRRS_ELS_REQ_RJT)
RETEVT(OCS_EVT_NODE_ATTACH_OK)
RETEVT(OCS_EVT_NODE_ATTACH_FAIL)
RETEVT(OCS_EVT_NODE_FREE_OK)
RETEVT(OCS_EVT_ELS_REQ_TIMEOUT)
RETEVT(OCS_EVT_ELS_REQ_ABORTED)
RETEVT(OCS_EVT_ABORT_ELS)
RETEVT(OCS_EVT_ELS_ABORT_CMPL)
RETEVT(OCS_EVT_DOMAIN_FOUND)
RETEVT(OCS_EVT_DOMAIN_ALLOC_OK)
RETEVT(OCS_EVT_DOMAIN_ALLOC_FAIL)
RETEVT(OCS_EVT_DOMAIN_REQ_ATTACH)
RETEVT(OCS_EVT_DOMAIN_ATTACH_OK)
RETEVT(OCS_EVT_DOMAIN_ATTACH_FAIL)
RETEVT(OCS_EVT_DOMAIN_LOST)
RETEVT(OCS_EVT_DOMAIN_FREE_OK)
RETEVT(OCS_EVT_DOMAIN_FREE_FAIL)
RETEVT(OCS_EVT_HW_DOMAIN_REQ_ATTACH)
RETEVT(OCS_EVT_HW_DOMAIN_REQ_FREE)
RETEVT(OCS_EVT_ALL_CHILD_NODES_FREE)
RETEVT(OCS_EVT_SPORT_ALLOC_OK)
RETEVT(OCS_EVT_SPORT_ALLOC_FAIL)
RETEVT(OCS_EVT_SPORT_ATTACH_OK)
RETEVT(OCS_EVT_SPORT_ATTACH_FAIL)
RETEVT(OCS_EVT_SPORT_FREE_OK)
RETEVT(OCS_EVT_SPORT_FREE_FAIL)
RETEVT(OCS_EVT_SPORT_TOPOLOGY_NOTIFY)
RETEVT(OCS_EVT_HW_PORT_ALLOC_OK)
RETEVT(OCS_EVT_HW_PORT_ALLOC_FAIL)
RETEVT(OCS_EVT_HW_PORT_ATTACH_OK)
RETEVT(OCS_EVT_HW_PORT_REQ_ATTACH)
RETEVT(OCS_EVT_HW_PORT_REQ_FREE)
RETEVT(OCS_EVT_HW_PORT_FREE_OK)
RETEVT(OCS_EVT_NODE_FREE_FAIL)
RETEVT(OCS_EVT_ABTS_RCVD)
RETEVT(OCS_EVT_NODE_MISSING)
RETEVT(OCS_EVT_NODE_REFOUND)
RETEVT(OCS_EVT_SHUTDOWN_IMPLICIT_LOGO)
RETEVT(OCS_EVT_SHUTDOWN_EXPLICIT_LOGO)
RETEVT(OCS_EVT_ELS_FRAME)
RETEVT(OCS_EVT_PLOGI_RCVD)
RETEVT(OCS_EVT_FLOGI_RCVD)
RETEVT(OCS_EVT_LOGO_RCVD)
RETEVT(OCS_EVT_PRLI_RCVD)
RETEVT(OCS_EVT_PRLO_RCVD)
RETEVT(OCS_EVT_PDISC_RCVD)
RETEVT(OCS_EVT_FDISC_RCVD)
RETEVT(OCS_EVT_ADISC_RCVD)
RETEVT(OCS_EVT_RSCN_RCVD)
RETEVT(OCS_EVT_SCR_RCVD)
RETEVT(OCS_EVT_ELS_RCVD)
RETEVT(OCS_EVT_LAST)
RETEVT(OCS_EVT_FCP_CMD_RCVD)
RETEVT(OCS_EVT_RFT_ID_RCVD)
RETEVT(OCS_EVT_RFF_ID_RCVD)
RETEVT(OCS_EVT_GNN_ID_RCVD)
RETEVT(OCS_EVT_GPN_ID_RCVD)
RETEVT(OCS_EVT_GFPN_ID_RCVD)
RETEVT(OCS_EVT_GFF_ID_RCVD)
RETEVT(OCS_EVT_GID_FT_RCVD)
RETEVT(OCS_EVT_GID_PT_RCVD)
RETEVT(OCS_EVT_RPN_ID_RCVD)
RETEVT(OCS_EVT_RNN_ID_RCVD)
RETEVT(OCS_EVT_RCS_ID_RCVD)
RETEVT(OCS_EVT_RSNN_NN_RCVD)
RETEVT(OCS_EVT_RSPN_ID_RCVD)
RETEVT(OCS_EVT_RHBA_RCVD)
RETEVT(OCS_EVT_RPA_RCVD)
RETEVT(OCS_EVT_GIDPT_DELAY_EXPIRED)
RETEVT(OCS_EVT_ABORT_IO)
RETEVT(OCS_EVT_ABORT_IO_NO_RESP)
RETEVT(OCS_EVT_IO_CMPL)
RETEVT(OCS_EVT_IO_CMPL_ERRORS)
RETEVT(OCS_EVT_RESP_CMPL)
RETEVT(OCS_EVT_ABORT_CMPL)
RETEVT(OCS_EVT_NODE_ACTIVE_IO_LIST_EMPTY)
RETEVT(OCS_EVT_NODE_DEL_INI_COMPLETE)
RETEVT(OCS_EVT_NODE_DEL_TGT_COMPLETE)
RETEVT(OCS_EVT_IO_ABORTED_BY_TMF)
RETEVT(OCS_EVT_IO_ABORT_IGNORED)
RETEVT(OCS_EVT_IO_FIRST_BURST)
RETEVT(OCS_EVT_IO_FIRST_BURST_ERR)
RETEVT(OCS_EVT_IO_FIRST_BURST_ABORTED)
default:
break;
#undef RETEVT
}
return "unknown";
}

203
sys/dev/ocs_fc/ocs_sm.h Normal file
View file

@ -0,0 +1,203 @@
/*-
* Copyright (c) 2017 Broadcom. All rights reserved.
* The term "Broadcom" refers to Broadcom Limited and/or its subsidiaries.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* $FreeBSD$
*/
/**
* @file
* Generic state machine framework declarations.
*/
#ifndef _OCS_SM_H
#define _OCS_SM_H
/**
* State Machine (SM) IDs.
*/
enum {
OCS_SM_COMMON = 0,
OCS_SM_DOMAIN,
OCS_SM_PORT,
OCS_SM_LOGIN,
OCS_SM_LAST
};
#define OCS_SM_EVENT_SHIFT 24
#define OCS_SM_EVENT_START(id) ((id) << OCS_SM_EVENT_SHIFT)
extern const char *ocs_sm_id[]; /**< String format of the above enums. */
/**
* State Machine events.
*/
typedef enum {
/* Common Events */
OCS_EVT_ENTER = OCS_SM_EVENT_START(OCS_SM_COMMON),
OCS_EVT_REENTER,
OCS_EVT_EXIT,
OCS_EVT_SHUTDOWN,
OCS_EVT_ALL_CHILD_NODES_FREE,
OCS_EVT_RESUME,
OCS_EVT_TIMER_EXPIRED,
/* Domain Events */
OCS_EVT_RESPONSE = OCS_SM_EVENT_START(OCS_SM_DOMAIN),
OCS_EVT_ERROR,
OCS_EVT_DOMAIN_FOUND,
OCS_EVT_DOMAIN_ALLOC_OK,
OCS_EVT_DOMAIN_ALLOC_FAIL,
OCS_EVT_DOMAIN_REQ_ATTACH,
OCS_EVT_DOMAIN_ATTACH_OK,
OCS_EVT_DOMAIN_ATTACH_FAIL,
OCS_EVT_DOMAIN_LOST,
OCS_EVT_DOMAIN_FREE_OK,
OCS_EVT_DOMAIN_FREE_FAIL,
OCS_EVT_HW_DOMAIN_REQ_ATTACH,
OCS_EVT_HW_DOMAIN_REQ_FREE,
/* Sport Events */
OCS_EVT_SPORT_ALLOC_OK = OCS_SM_EVENT_START(OCS_SM_PORT),
OCS_EVT_SPORT_ALLOC_FAIL,
OCS_EVT_SPORT_ATTACH_OK,
OCS_EVT_SPORT_ATTACH_FAIL,
OCS_EVT_SPORT_FREE_OK,
OCS_EVT_SPORT_FREE_FAIL,
OCS_EVT_SPORT_TOPOLOGY_NOTIFY,
OCS_EVT_HW_PORT_ALLOC_OK,
OCS_EVT_HW_PORT_ALLOC_FAIL,
OCS_EVT_HW_PORT_ATTACH_OK,
OCS_EVT_HW_PORT_REQ_ATTACH,
OCS_EVT_HW_PORT_REQ_FREE,
OCS_EVT_HW_PORT_FREE_OK,
/* Login Events */
OCS_EVT_SRRS_ELS_REQ_OK = OCS_SM_EVENT_START(OCS_SM_LOGIN),
OCS_EVT_SRRS_ELS_CMPL_OK,
OCS_EVT_SRRS_ELS_REQ_FAIL,
OCS_EVT_SRRS_ELS_CMPL_FAIL,
OCS_EVT_SRRS_ELS_REQ_RJT,
OCS_EVT_NODE_ATTACH_OK,
OCS_EVT_NODE_ATTACH_FAIL,
OCS_EVT_NODE_FREE_OK,
OCS_EVT_NODE_FREE_FAIL,
OCS_EVT_ELS_FRAME,
OCS_EVT_ELS_REQ_TIMEOUT,
OCS_EVT_ELS_REQ_ABORTED,
OCS_EVT_ABORT_ELS, /**< request an ELS IO be aborted */
OCS_EVT_ELS_ABORT_CMPL, /**< ELS abort process complete */
OCS_EVT_ABTS_RCVD,
OCS_EVT_NODE_MISSING, /**< node is not in the GID_PT payload */
OCS_EVT_NODE_REFOUND, /**< node is allocated and in the GID_PT payload */
OCS_EVT_SHUTDOWN_IMPLICIT_LOGO, /**< node shutting down due to PLOGI recvd (implicit logo) */
OCS_EVT_SHUTDOWN_EXPLICIT_LOGO, /**< node shutting down due to LOGO recvd/sent (explicit logo) */
OCS_EVT_PLOGI_RCVD,
OCS_EVT_FLOGI_RCVD,
OCS_EVT_LOGO_RCVD,
OCS_EVT_RRQ_RCVD,
OCS_EVT_PRLI_RCVD,
OCS_EVT_PRLO_RCVD,
OCS_EVT_PDISC_RCVD,
OCS_EVT_FDISC_RCVD,
OCS_EVT_ADISC_RCVD,
OCS_EVT_RSCN_RCVD,
OCS_EVT_SCR_RCVD,
OCS_EVT_ELS_RCVD,
OCS_EVT_FCP_CMD_RCVD,
/* Used by fabric emulation */
OCS_EVT_RFT_ID_RCVD,
OCS_EVT_RFF_ID_RCVD,
OCS_EVT_GNN_ID_RCVD,
OCS_EVT_GPN_ID_RCVD,
OCS_EVT_GFPN_ID_RCVD,
OCS_EVT_GFF_ID_RCVD,
OCS_EVT_GID_FT_RCVD,
OCS_EVT_GID_PT_RCVD,
OCS_EVT_RPN_ID_RCVD,
OCS_EVT_RNN_ID_RCVD,
OCS_EVT_RCS_ID_RCVD,
OCS_EVT_RSNN_NN_RCVD,
OCS_EVT_RSPN_ID_RCVD,
OCS_EVT_RHBA_RCVD,
OCS_EVT_RPA_RCVD,
OCS_EVT_GIDPT_DELAY_EXPIRED,
/* SCSI Target Server events */
OCS_EVT_ABORT_IO,
OCS_EVT_ABORT_IO_NO_RESP,
OCS_EVT_IO_CMPL,
OCS_EVT_IO_CMPL_ERRORS,
OCS_EVT_RESP_CMPL,
OCS_EVT_ABORT_CMPL,
OCS_EVT_NODE_ACTIVE_IO_LIST_EMPTY,
OCS_EVT_NODE_DEL_INI_COMPLETE,
OCS_EVT_NODE_DEL_TGT_COMPLETE,
OCS_EVT_IO_ABORTED_BY_TMF,
OCS_EVT_IO_ABORT_IGNORED,
OCS_EVT_IO_FIRST_BURST,
OCS_EVT_IO_FIRST_BURST_ERR,
OCS_EVT_IO_FIRST_BURST_ABORTED,
/* Must be last */
OCS_EVT_LAST
} ocs_sm_event_t;
/* Declare ocs_sm_ctx_s */
typedef struct ocs_sm_ctx_s ocs_sm_ctx_t;
/* State machine state function */
typedef void *(*ocs_sm_function_t)(ocs_sm_ctx_t *, ocs_sm_event_t, void *);
/* State machine context header */
struct ocs_sm_ctx_s {
ocs_sm_function_t current_state;
const char *description;
void *app; /** Application-specific handle. */
};
extern int ocs_sm_post_event(ocs_sm_ctx_t *, ocs_sm_event_t, void *);
extern void ocs_sm_transition(ocs_sm_ctx_t *, ocs_sm_function_t, void *);
extern void ocs_sm_disable(ocs_sm_ctx_t *ctx);
extern const char *ocs_sm_event_name(ocs_sm_event_t evt);
#if 0
#define smtrace(sm) ocs_log_debug(NULL, "%s: %-20s --> %s\n", sm, ocs_sm_event_name(evt), __func__)
#else
#define smtrace(...)
#endif
#endif /* ! _OCS_SM_H */

1926
sys/dev/ocs_fc/ocs_sport.c Normal file

File diff suppressed because it is too large Load diff

113
sys/dev/ocs_fc/ocs_sport.h Normal file
View file

@ -0,0 +1,113 @@
/*-
* Copyright (c) 2017 Broadcom. All rights reserved.
* The term "Broadcom" refers to Broadcom Limited and/or its subsidiaries.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* $FreeBSD$
*/
/**
* @file
* OCS FC SLI port (SPORT) exported declarations
*
*/
#if !defined(__OCS_SPORT_H__)
#define __OCS_SPORT_H__
extern int32_t ocs_port_cb(void *arg, ocs_hw_port_event_e event, void *data);
extern ocs_sport_t *ocs_sport_alloc(ocs_domain_t *domain, uint64_t wwpn, uint64_t wwnn, uint32_t fc_id,
uint8_t enable_ini, uint8_t enable_tgt);
extern void ocs_sport_free(ocs_sport_t *sport);
extern void ocs_sport_force_free(ocs_sport_t *sport);
static inline void
ocs_sport_lock_init(ocs_sport_t *sport)
{
}
static inline void
ocs_sport_lock_free(ocs_sport_t *sport)
{
}
static inline int32_t
ocs_sport_lock_try(ocs_sport_t *sport)
{
/* Use the device wide lock */
return ocs_device_lock_try(sport->ocs);
}
static inline void
ocs_sport_lock(ocs_sport_t *sport)
{
/* Use the device wide lock */
ocs_device_lock(sport->ocs);
}
static inline void
ocs_sport_unlock(ocs_sport_t *sport)
{
/* Use the device wide lock */
ocs_device_unlock(sport->ocs);
}
extern ocs_sport_t *ocs_sport_find(ocs_domain_t *domain, uint32_t d_id);
extern ocs_sport_t *ocs_sport_find_wwn(ocs_domain_t *domain, uint64_t wwnn, uint64_t wwpn);
extern int32_t ocs_sport_attach(ocs_sport_t *sport, uint32_t fc_id);
extern void *__ocs_sport_allocated(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg);
extern void *__ocs_sport_wait_shutdown(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg);
extern void *__ocs_sport_wait_port_free(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg);
extern void *__ocs_sport_vport_init(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg);
extern void *__ocs_sport_vport_wait_alloc(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg);
extern void *__ocs_sport_vport_allocated(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg);
extern void *__ocs_sport_attached(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg);
extern int32_t ocs_vport_start(ocs_domain_t *domain);
extern int32_t ocs_sport_vport_new(ocs_domain_t *domain, uint64_t wwpn, uint64_t wwnn, uint32_t fc_id, uint8_t ini, uint8_t tgt, void *tgt_data, void *ini_data, uint8_t restore_vport);
extern int32_t ocs_sport_vport_alloc(ocs_domain_t *domain, ocs_vport_spec_t *vport);
extern int32_t ocs_sport_vport_del(ocs_t *ocs, ocs_domain_t *domain, uint64_t wwpn, uint64_t wwnn);
extern void ocs_vport_del_all(ocs_t *ocs);
extern int8_t ocs_vport_create_spec(ocs_t *ocs, uint64_t wwnn, uint64_t wwpn, uint32_t fc_id, uint32_t enable_ini, uint32_t enable_tgt, void *tgt_data, void *ini_data);
extern int ocs_ddump_sport(ocs_textbuf_t *textbuf, ocs_sport_t *sport);
/* Node group API */
extern int ocs_sparm_cmp(uint8_t *sparms1, uint8_t *sparms2);
extern ocs_node_group_dir_t *ocs_node_group_dir_alloc(ocs_sport_t *sport, uint8_t *sparms);
extern void ocs_node_group_dir_free(ocs_node_group_dir_t *node_group_dir);
extern ocs_node_group_dir_t *ocs_node_group_dir_find(ocs_sport_t *sport, uint8_t *sparms);
extern ocs_remote_node_group_t *ocs_remote_node_group_alloc(ocs_node_group_dir_t *node_group_dir);
extern void ocs_remote_node_group_free(ocs_remote_node_group_t *node_group);
extern int ocs_node_group_init(ocs_node_t *node);
extern void ocs_node_group_free(ocs_node_t *node);
#endif

View file

@ -0,0 +1,49 @@
/*-
* Copyright (c) 2017 Broadcom. All rights reserved.
* The term "Broadcom" refers to Broadcom Limited and/or its subsidiaries.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* $FreeBSD$
*/
/**
* @file
*
*/
#if !defined(__OCS_STATS_H__)
#define __OCS_STATS_H__
#define OCS_STAT_ENABLE 0
#if OCS_STAT_ENABLE
#define OCS_STAT(x) x
#else
#define OCS_STAT(x)
#endif
#endif

1399
sys/dev/ocs_fc/ocs_unsol.c Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,53 @@
/*-
* Copyright (c) 2017 Broadcom. All rights reserved.
* The term "Broadcom" refers to Broadcom Limited and/or its subsidiaries.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* $FreeBSD$
*/
/**
* @file
* Declarations for the interface exported by ocs_unsol.c
*/
#if !defined(__OSC_UNSOL_H__)
#define __OSC_UNSOL_H__
extern int32_t ocs_unsol_rq_thread(ocs_thread_t *mythread);
extern int32_t ocs_unsolicited_cb(void *arg, ocs_hw_sequence_t *seq);
extern int32_t ocs_node_purge_pending(ocs_node_t *node);
extern int32_t ocs_process_node_pending(ocs_node_t *node);
extern int32_t ocs_domain_process_pending(ocs_domain_t *domain);
extern int32_t ocs_domain_purge_pending(ocs_domain_t *domain);
extern int32_t ocs_dispatch_unsolicited_bls(ocs_node_t *node, ocs_hw_sequence_t *seq);
extern void ocs_domain_hold_frames(ocs_domain_t *domain);
extern void ocs_domain_accept_frames(ocs_domain_t *domain);
extern void ocs_seq_coalesce_cleanup(ocs_hw_io_t *hio, uint8_t abort_io);
extern int32_t ocs_sframe_send_bls_acc(ocs_node_t *node, ocs_hw_sequence_t *seq);
#endif

2826
sys/dev/ocs_fc/ocs_utils.c Normal file

File diff suppressed because it is too large Load diff

345
sys/dev/ocs_fc/ocs_utils.h Normal file
View file

@ -0,0 +1,345 @@
/*-
* Copyright (c) 2017 Broadcom. All rights reserved.
* The term "Broadcom" refers to Broadcom Limited and/or its subsidiaries.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* $FreeBSD$
*/
/**
* @file
*
*/
#ifndef __OCS_UTILS_H
#define __OCS_UTILS_H
#include "ocs_list.h"
typedef struct ocs_array_s ocs_array_t;
extern void ocs_array_set_slablen(uint32_t len);
extern ocs_array_t *ocs_array_alloc(ocs_os_handle_t os, uint32_t size, uint32_t count);
extern void ocs_array_free(ocs_array_t *array);
extern void *ocs_array_get(ocs_array_t *array, uint32_t idx);
extern uint32_t ocs_array_get_count(ocs_array_t *array);
extern uint32_t ocs_array_get_size(ocs_array_t *array);
/* Void pointer array and iterator */
typedef struct ocs_varray_s ocs_varray_t;
extern ocs_varray_t *ocs_varray_alloc(ocs_os_handle_t os, uint32_t entry_count);
extern void ocs_varray_free(ocs_varray_t *ai);
extern int32_t ocs_varray_add(ocs_varray_t *ai, void *entry);
extern void ocs_varray_iter_reset(ocs_varray_t *ai);
extern void *ocs_varray_iter_next(ocs_varray_t *ai);
extern void *_ocs_varray_iter_next(ocs_varray_t *ai);
extern void ocs_varray_lock(ocs_varray_t *ai);
extern void ocs_varray_unlock(ocs_varray_t *ai);
extern uint32_t ocs_varray_get_count(ocs_varray_t *ai);
/***************************************************************************
* Circular buffer
*
*/
typedef struct ocs_cbuf_s ocs_cbuf_t;
extern ocs_cbuf_t *ocs_cbuf_alloc(ocs_os_handle_t os, uint32_t entry_count);
extern void ocs_cbuf_free(ocs_cbuf_t *cbuf);
extern void *ocs_cbuf_get(ocs_cbuf_t *cbuf, int32_t timeout_usec);
extern int32_t ocs_cbuf_put(ocs_cbuf_t *cbuf, void *elem);
extern int32_t ocs_cbuf_prime(ocs_cbuf_t *cbuf, ocs_array_t *array);
typedef struct {
void *vaddr;
uint32_t length;
} ocs_scsi_vaddr_len_t;
#define OCS_TEXTBUF_MAX_ALLOC_LEN (256*1024)
typedef struct {
ocs_list_link_t link;
uint8_t user_allocated:1;
uint8_t *buffer;
uint32_t buffer_length;
uint32_t buffer_written;
} ocs_textbuf_segment_t;
typedef struct {
ocs_t *ocs;
ocs_list_t segment_list;
uint8_t extendable:1;
uint32_t allocation_length;
uint32_t total_allocation_length;
uint32_t max_allocation_length;
} ocs_textbuf_t;
extern int32_t ocs_textbuf_alloc(ocs_t *ocs, ocs_textbuf_t *textbuf, uint32_t length);
extern uint32_t ocs_textbuf_initialized(ocs_textbuf_t *textbuf);
extern int32_t ocs_textbuf_init(ocs_t *ocs, ocs_textbuf_t *textbuf, void *buffer, uint32_t length);
extern void ocs_textbuf_free(ocs_t *ocs, ocs_textbuf_t *textbuf);
extern void ocs_textbuf_putc(ocs_textbuf_t *textbuf, uint8_t c);
extern void ocs_textbuf_puts(ocs_textbuf_t *textbuf, char *s);
__attribute__((format(printf,2,3)))
extern void ocs_textbuf_printf(ocs_textbuf_t *textbuf, const char *fmt, ...);
__attribute__((format(printf,2,0)))
extern void ocs_textbuf_vprintf(ocs_textbuf_t *textbuf, const char *fmt, va_list ap);
extern void ocs_textbuf_buffer(ocs_textbuf_t *textbuf, uint8_t *buffer, uint32_t buffer_length);
extern void ocs_textbuf_copy(ocs_textbuf_t *textbuf, uint8_t *buffer, uint32_t buffer_length);
extern int32_t ocs_textbuf_remaining(ocs_textbuf_t *textbuf);
extern void ocs_textbuf_reset(ocs_textbuf_t *textbuf);
extern uint8_t *ocs_textbuf_get_buffer(ocs_textbuf_t *textbuf);
extern int32_t ocs_textbuf_get_length(ocs_textbuf_t *textbuf);
extern int32_t ocs_textbuf_get_written(ocs_textbuf_t *textbuf);
extern uint8_t *ocs_textbuf_ext_get_buffer(ocs_textbuf_t *textbuf, uint32_t idx);
extern int32_t ocs_textbuf_ext_get_length(ocs_textbuf_t *textbuf, uint32_t idx);
extern int32_t ocs_textbuf_ext_get_written(ocs_textbuf_t *textbuf, uint32_t idx);
typedef struct ocs_pool_s ocs_pool_t;
extern ocs_pool_t *ocs_pool_alloc(ocs_os_handle_t os, uint32_t size, uint32_t count, uint32_t use_lock);
extern void ocs_pool_reset(ocs_pool_t *pool);
extern void ocs_pool_free(ocs_pool_t *pool);
extern void *ocs_pool_get(ocs_pool_t *pool);
extern void ocs_pool_put(ocs_pool_t *pool, void *item);
extern uint32_t ocs_pool_get_count(ocs_pool_t *pool);
extern void *ocs_pool_get_instance(ocs_pool_t *pool, uint32_t idx);
extern uint32_t ocs_pool_get_freelist_count(ocs_pool_t *pool);
/* Uncomment this line to enable logging extended queue history
*/
//#define OCS_DEBUG_QUEUE_HISTORY
/* Allocate maximum allowed (4M) */
#if defined(OCS_DEBUG_QUEUE_HISTORY)
#define OCS_Q_HIST_SIZE (1000000UL) /* Size in words */
#endif
#define OCS_LOG_ENABLE_SM_TRACE(ocs) (((ocs) != NULL) ? (((ocs)->logmask & (1U << 0)) != 0) : 0)
#define OCS_LOG_ENABLE_ELS_TRACE(ocs) (((ocs) != NULL) ? (((ocs)->logmask & (1U << 1)) != 0) : 0)
#define OCS_LOG_ENABLE_SCSI_TRACE(ocs) (((ocs) != NULL) ? (((ocs)->logmask & (1U << 2)) != 0) : 0)
#define OCS_LOG_ENABLE_SCSI_TGT_TRACE(ocs) (((ocs) != NULL) ? (((ocs)->logmask & (1U << 3)) != 0) : 0)
#define OCS_LOG_ENABLE_DOMAIN_SM_TRACE(ocs) (((ocs) != NULL) ? (((ocs)->logmask & (1U << 4)) != 0) : 0)
#define OCS_LOG_ENABLE_Q_FULL_BUSY_MSG(ocs) (((ocs) != NULL) ? (((ocs)->logmask & (1U << 5)) != 0) : 0)
#define OCS_LOG_ENABLE_IO_ERRORS(ocs) (((ocs) != NULL) ? (((ocs)->logmask & (1U << 6)) != 0) : 0)
extern void ocs_dump32(uint32_t, ocs_os_handle_t, const char *, void *, uint32_t);
extern void ocs_debug_enable(uint32_t mask);
extern void ocs_debug_disable(uint32_t mask);
extern int ocs_debug_is_enabled(uint32_t mask);
extern void ocs_debug_attach(void *);
extern void ocs_debug_detach(void *);
#if defined(OCS_DEBUG_QUEUE_HISTORY)
/**
* @brief Queue history footer
*/
typedef union ocs_q_hist_ftr_u {
uint32_t word;
struct {
#define Q_HIST_TYPE_LEN 3
#define Q_HIST_MASK_LEN 29
uint32_t mask:Q_HIST_MASK_LEN,
type:Q_HIST_TYPE_LEN;
} s;
} ocs_q_hist_ftr_t;
/**
* @brief WQE command mask lookup
*/
typedef struct ocs_q_hist_wqe_mask_s {
uint8_t command;
uint32_t mask;
} ocs_q_hist_wqe_mask_t;
/**
* @brief CQE mask lookup
*/
typedef struct ocs_q_hist_cqe_mask_s {
uint8_t ctype;
uint32_t :Q_HIST_MASK_LEN,
type:Q_HIST_TYPE_LEN;
uint32_t mask;
uint32_t mask_err;
} ocs_q_hist_cqe_mask_t;
/**
* @brief Queue history type
*/
typedef enum {
/* changes need to be made to ocs_queue_history_type_name() as well */
OCS_Q_HIST_TYPE_WQE = 0,
OCS_Q_HIST_TYPE_CWQE,
OCS_Q_HIST_TYPE_CXABT,
OCS_Q_HIST_TYPE_MISC,
} ocs_q_hist_type_t;
static __inline const char *
ocs_queue_history_type_name(ocs_q_hist_type_t type)
{
switch (type) {
case OCS_Q_HIST_TYPE_WQE: return "wqe"; break;
case OCS_Q_HIST_TYPE_CWQE: return "wcqe"; break;
case OCS_Q_HIST_TYPE_CXABT: return "xacqe"; break;
case OCS_Q_HIST_TYPE_MISC: return "misc"; break;
default: return "unknown"; break;
}
}
typedef struct {
ocs_t *ocs;
uint32_t *q_hist;
uint32_t q_hist_index;
ocs_lock_t q_hist_lock;
} ocs_hw_q_hist_t;
extern void ocs_queue_history_cqe(ocs_hw_q_hist_t*, uint8_t, uint32_t *, uint8_t, uint32_t, uint32_t);
extern void ocs_queue_history_wq(ocs_hw_q_hist_t*, uint32_t *, uint32_t, uint32_t);
extern void ocs_queue_history_misc(ocs_hw_q_hist_t*, uint32_t *, uint32_t);
extern void ocs_queue_history_init(ocs_t *, ocs_hw_q_hist_t*);
extern void ocs_queue_history_free(ocs_hw_q_hist_t*);
extern uint32_t ocs_queue_history_prev_index(uint32_t);
extern uint8_t ocs_queue_history_q_info_enabled(void);
extern uint8_t ocs_queue_history_timestamp_enabled(void);
#else
#define ocs_queue_history_wq(...)
#define ocs_queue_history_cqe(...)
#define ocs_queue_history_misc(...)
#define ocs_queue_history_init(...)
#define ocs_queue_history_free(...)
#endif
#define OCS_DEBUG_ALWAYS (1U << 0)
#define OCS_DEBUG_ENABLE_MQ_DUMP (1U << 1)
#define OCS_DEBUG_ENABLE_CQ_DUMP (1U << 2)
#define OCS_DEBUG_ENABLE_WQ_DUMP (1U << 3)
#define OCS_DEBUG_ENABLE_EQ_DUMP (1U << 4)
#define OCS_DEBUG_ENABLE_SPARAM_DUMP (1U << 5)
extern void _ocs_assert(const char *cond, const char *filename, int linenum);
#define ocs_assert(cond, ...) \
do { \
if (!(cond)) { \
_ocs_assert(#cond, __FILE__, __LINE__); \
return __VA_ARGS__; \
} \
} while (0)
extern void ocs_dump_service_params(const char *label, void *sparms);
extern void ocs_display_sparams(const char *prelabel, const char *reqlabel, int dest, void *textbuf, void *sparams);
typedef struct {
uint16_t crc;
uint16_t app_tag;
uint32_t ref_tag;
} ocs_dif_t;
/* DIF guard calculations */
extern uint16_t ocs_scsi_dif_calc_crc(const uint8_t *, uint32_t size, uint16_t crc);
extern uint16_t ocs_scsi_dif_calc_checksum(ocs_scsi_vaddr_len_t addrlen[], uint32_t addrlen_count);
/**
* @brief Power State change message types
*
*/
typedef enum {
OCS_PM_PREPARE = 1,
OCS_PM_SLEEP,
OCS_PM_HIBERNATE,
OCS_PM_RESUME,
} ocs_pm_msg_e;
/**
* @brief Power State values
*
*/
typedef enum {
OCS_PM_STATE_S0 = 0,
OCS_PM_STATE_S1,
OCS_PM_STATE_S2,
OCS_PM_STATE_S3,
OCS_PM_STATE_S4,
} ocs_pm_state_e;
typedef struct {
ocs_pm_state_e pm_state; /*<< Current PM state */
} ocs_pm_context_t;
extern int32_t ocs_pm_request(ocs_t *ocs, ocs_pm_msg_e msg, int32_t (*callback)(ocs_t *ocs, int32_t status, void *arg),
void *arg);
extern ocs_pm_state_e ocs_pm_get_state(ocs_t *ocs);
extern const char *ocs_pm_get_state_string(ocs_t *ocs);
#define SPV_ROWLEN 256
#define SPV_DIM 3
/*!
* @defgroup spv Sparse Vector
*/
/**
* @brief Sparse vector structure.
*/
typedef struct sparse_vector_s {
ocs_os_handle_t os;
uint32_t max_idx; /**< maximum index value */
void **array; /**< pointer to 3D array */
} *sparse_vector_t;
extern void spv_del(sparse_vector_t spv);
extern sparse_vector_t spv_new(ocs_os_handle_t os);
extern void spv_set(sparse_vector_t sv, uint32_t idx, void *value);
extern void *spv_get(sparse_vector_t sv, uint32_t idx);
extern unsigned short t10crc16(const unsigned char *blk_adr, unsigned long blk_len, unsigned short crc);
typedef struct ocs_ramlog_s ocs_ramlog_t;
#define OCS_RAMLOG_DEFAULT_BUFFERS 5
extern ocs_ramlog_t *ocs_ramlog_init(ocs_t *ocs, uint32_t buffer_len, uint32_t buffer_count);
extern void ocs_ramlog_free(ocs_t *ocs, ocs_ramlog_t *ramlog);
extern void ocs_ramlog_clear(ocs_t *ocs, ocs_ramlog_t *ramlog, int clear_start_of_day, int clear_recent);
__attribute__((format(printf,2,3)))
extern int32_t ocs_ramlog_printf(void *os, const char *fmt, ...);
__attribute__((format(printf,2,0)))
extern int32_t ocs_ramlog_vprintf(ocs_ramlog_t *ramlog, const char *fmt, va_list ap);
extern int32_t ocs_ddump_ramlog(ocs_textbuf_t *textbuf, ocs_ramlog_t *ramlog);
#endif

203
sys/dev/ocs_fc/ocs_vpd.h Normal file
View file

@ -0,0 +1,203 @@
/*-
* Copyright (c) 2017 Broadcom. All rights reserved.
* The term "Broadcom" refers to Broadcom Limited and/or its subsidiaries.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* $FreeBSD$
*/
/**
* @file
* OCS VPD parser
*/
#if !defined(__OCS_VPD_H__)
#define __OCS_VPD_H__
/**
* @brief VPD buffer structure
*/
typedef struct {
uint8_t *buffer;
uint32_t length;
uint32_t offset;
uint8_t checksum;
} vpdbuf_t;
/**
* @brief return next VPD byte
*
* Returns next VPD byte and updates accumulated checksum
*
* @param vpd pointer to vpd buffer
*
* @return returns next byte for success, or a negative error code value for failure.
*
*/
static inline int
vpdnext(vpdbuf_t *vpd)
{
int rc = -1;
if (vpd->offset < vpd->length) {
rc = vpd->buffer[vpd->offset++];
vpd->checksum += rc;
}
return rc;
}
/**
* @brief return true if no more vpd buffer data
*
* return true if the vpd buffer data has been completely consumed
*
* @param vpd pointer to vpd buffer
*
* @return returns true if no more data
*
*/
static inline int
vpddone(vpdbuf_t *vpd)
{
return vpd->offset >= vpd->length;
}
/**
* @brief return pointer to current VPD data location
*
* Returns a pointer to the current location in the VPD data
*
* @param vpd pointer to vpd buffer
*
* @return pointer to current VPD data location
*/
static inline uint8_t *
vpdref(vpdbuf_t *vpd)
{
return &vpd->buffer[vpd->offset];
}
#define VPD_LARGE_RESOURCE_TYPE_ID_STRING_TAG 0x82
#define VPD_LARGE_RESOURCE_TYPE_R_TAG 0x90
#define VPD_LARGE_RESOURCE_TYPE_W_TAG 0x91
#define VPD_SMALL_RESOURCE_TYPE_END_TAG 0x78
/**
* @brief find a VPD entry
*
* Finds a VPD entry given the two character code
*
* @param vpddata pointer to raw vpd data buffer
* @param vpddata_length length of vpddata buffer in bytes
* @param key key to look up
* @return returns a pointer to the key location or NULL if not found or checksum error
*/
static inline uint8_t *
ocs_find_vpd(uint8_t *vpddata, uint32_t vpddata_length, const char *key)
{
vpdbuf_t vpdbuf;
uint8_t *pret = NULL;
uint8_t c0 = key[0];
uint8_t c1 = key[1];
vpdbuf.buffer = (uint8_t*) vpddata;
vpdbuf.length = vpddata_length;
vpdbuf.offset = 0;
vpdbuf.checksum = 0;
while (!vpddone(&vpdbuf)) {
int type = vpdnext(&vpdbuf);
int len_lo;
int len_hi;
int len;
int i;
if (type == VPD_SMALL_RESOURCE_TYPE_END_TAG) {
break;
}
len_lo = vpdnext(&vpdbuf);
len_hi = vpdnext(&vpdbuf);
len = len_lo + (len_hi << 8);
if ((type == VPD_LARGE_RESOURCE_TYPE_R_TAG) || (type == VPD_LARGE_RESOURCE_TYPE_W_TAG)) {
while (len > 0) {
int rc0;
int rc1;
int sublen;
uint8_t *pstart;
rc0 = vpdnext(&vpdbuf);
rc1 = vpdnext(&vpdbuf);
/* Mark this location */
pstart = vpdref(&vpdbuf);
sublen = vpdnext(&vpdbuf);
/* Adjust remaining len */
len -= (sublen + 3);
/* check for match with request */
if ((c0 == rc0) && (c1 == rc1)) {
pret = pstart;
for (i = 0; i < sublen; i++) {
vpdnext(&vpdbuf);
}
/* check for "RV" end */
} else if ('R' == rc0 && 'V' == rc1) {
/* Read the checksum */
for (i = 0; i < sublen; i++) {
vpdnext(&vpdbuf);
}
/* The accumulated checksum should be zero here */
if (vpdbuf.checksum != 0) {
ocs_log_test(NULL, "checksum error\n");
return NULL;
}
}
else
for (i = 0; i < sublen; i++) {
vpdnext(&vpdbuf);
}
}
}
for (i = 0; i < len; i++) {
vpdnext(&vpdbuf);
}
}
return pret;
}
#endif

1105
sys/dev/ocs_fc/ocs_xport.c Normal file

File diff suppressed because it is too large Load diff

213
sys/dev/ocs_fc/ocs_xport.h Normal file
View file

@ -0,0 +1,213 @@
/*-
* Copyright (c) 2017 Broadcom. All rights reserved.
* The term "Broadcom" refers to Broadcom Limited and/or its subsidiaries.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* $FreeBSD$
*/
/**
* @file
*
*/
#if !defined(__OCS_XPORT_H__)
#define __OCS_XPORT_H__
/**
* @brief FCFI lookup/pending frames
*/
typedef struct ocs_xport_fcfi_s {
ocs_lock_t pend_frames_lock;
ocs_list_t pend_frames;
uint32_t hold_frames:1; /*<< hold pending frames */
uint32_t pend_frames_processed; /*<< count of pending frames that were processed */
} ocs_xport_fcfi_t;
/**
* @brief Structure to hold the information related to an RQ processing thread used
* to increase 40G performance.
*/
typedef struct ocs_xport_rq_thread_info_s {
ocs_t *ocs;
uint8_t thread_started;
ocs_thread_t thread;
ocs_cbuf_t * seq_cbuf;
char thread_name[64];
} ocs_xport_rq_thread_info_t;
typedef enum {
OCS_XPORT_PORT_ONLINE=1,
OCS_XPORT_PORT_OFFLINE,
OCS_XPORT_SHUTDOWN,
OCS_XPORT_POST_NODE_EVENT,
OCS_XPORT_WWNN_SET,
OCS_XPORT_WWPN_SET,
} ocs_xport_ctrl_e;
typedef enum {
OCS_XPORT_PORT_STATUS,
OCS_XPORT_CONFIG_PORT_STATUS,
OCS_XPORT_LINK_SPEED,
OCS_XPORT_IS_SUPPORTED_LINK_SPEED,
OCS_XPORT_LINK_STATISTICS,
OCS_XPORT_LINK_STAT_RESET,
OCS_XPORT_IS_QUIESCED
} ocs_xport_status_e;
typedef struct ocs_xport_link_stats_s {
uint32_t rec:1,
gec:1,
w02of:1,
w03of:1,
w04of:1,
w05of:1,
w06of:1,
w07of:1,
w08of:1,
w09of:1,
w10of:1,
w11of:1,
w12of:1,
w13of:1,
w14of:1,
w15of:1,
w16of:1,
w17of:1,
w18of:1,
w19of:1,
w20of:1,
w21of:1,
resv0:8,
clrc:1,
clof:1;
uint32_t link_failure_error_count;
uint32_t loss_of_sync_error_count;
uint32_t loss_of_signal_error_count;
uint32_t primitive_sequence_error_count;
uint32_t invalid_transmission_word_error_count;
uint32_t crc_error_count;
uint32_t primitive_sequence_event_timeout_count;
uint32_t elastic_buffer_overrun_error_count;
uint32_t arbitration_fc_al_timout_count;
uint32_t advertised_receive_bufftor_to_buffer_credit;
uint32_t current_receive_buffer_to_buffer_credit;
uint32_t advertised_transmit_buffer_to_buffer_credit;
uint32_t current_transmit_buffer_to_buffer_credit;
uint32_t received_eofa_count;
uint32_t received_eofdti_count;
uint32_t received_eofni_count;
uint32_t received_soff_count;
uint32_t received_dropped_no_aer_count;
uint32_t received_dropped_no_available_rpi_resources_count;
uint32_t received_dropped_no_available_xri_resources_count;
} ocs_xport_link_stats_t;
typedef struct ocs_xport_host_stats_s {
uint32_t cc:1,
:31;
uint32_t transmit_kbyte_count;
uint32_t receive_kbyte_count;
uint32_t transmit_frame_count;
uint32_t receive_frame_count;
uint32_t transmit_sequence_count;
uint32_t receive_sequence_count;
uint32_t total_exchanges_originator;
uint32_t total_exchanges_responder;
uint32_t receive_p_bsy_count;
uint32_t receive_f_bsy_count;
uint32_t dropped_frames_due_to_no_rq_buffer_count;
uint32_t empty_rq_timeout_count;
uint32_t dropped_frames_due_to_no_xri_count;
uint32_t empty_xri_pool_count;
} ocs_xport_host_stats_t;
typedef struct ocs_xport_host_statistics_s {
ocs_sem_t semaphore;
ocs_xport_link_stats_t link_stats;
ocs_xport_host_stats_t host_stats;
} ocs_xport_host_statistics_t;
typedef union ocs_xport {
uint32_t value;
ocs_xport_host_statistics_t stats;
} ocs_xport_stats_t;
/**
* @brief Transport private values
*/
struct ocs_xport_s {
ocs_t *ocs;
uint64_t req_wwpn; /*<< wwpn requested by user for primary sport */
uint64_t req_wwnn; /*<< wwnn requested by user for primary sport */
ocs_xport_fcfi_t fcfi[SLI4_MAX_FCFI];
/* Nodes */
uint32_t nodes_count; /**< number of allocated nodes */
ocs_node_t **nodes; /**< array of pointers to nodes */
ocs_list_t nodes_free_list; /**< linked list of free nodes */
/* Io pool and counts */
ocs_io_pool_t *io_pool; /**< pointer to IO pool */
ocs_atomic_t io_alloc_failed_count; /**< used to track how often IO pool is empty */
ocs_lock_t io_pending_lock; /**< lock for io_pending_list */
ocs_list_t io_pending_list; /**< list of IOs waiting for HW resources
** lock: xport->io_pending_lock
** link: ocs_io_t->io_pending_link
*/
ocs_atomic_t io_total_alloc; /**< count of totals IOS allocated */
ocs_atomic_t io_total_free; /**< count of totals IOS free'd */
ocs_atomic_t io_total_pending; /**< count of totals IOS that were pended */
ocs_atomic_t io_active_count; /**< count of active IOS */
ocs_atomic_t io_pending_count; /**< count of pending IOS */
ocs_atomic_t io_pending_recursing; /**< non-zero if ocs_scsi_check_pending is executing */
/* vport */
ocs_list_t vport_list; /**< list of VPORTS (NPIV) */
/* Port */
uint32_t configured_link_state; /**< requested link state */
/* RQ processing threads */
uint32_t num_rq_threads;
ocs_xport_rq_thread_info_t *rq_thread_info;
ocs_timer_t stats_timer; /**< Timer for Statistics */
ocs_xport_stats_t fc_xport_stats;
};
extern ocs_xport_t *ocs_xport_alloc(ocs_t *ocs);
extern int32_t ocs_xport_attach(ocs_xport_t *xport);
extern int32_t ocs_xport_initialize(ocs_xport_t *xport);
extern int32_t ocs_xport_detach(ocs_xport_t *xport);
extern int32_t ocs_xport_control(ocs_xport_t *xport, ocs_xport_ctrl_e cmd, ...);
extern int32_t ocs_xport_status(ocs_xport_t *xport, ocs_xport_status_e cmd, ocs_xport_stats_t *result);
extern void ocs_xport_free(ocs_xport_t *xport);
#endif

8648
sys/dev/ocs_fc/sli4.c Normal file

File diff suppressed because it is too large Load diff

5609
sys/dev/ocs_fc/sli4.h Normal file

File diff suppressed because it is too large Load diff

84
sys/dev/ocs_fc/version.h Normal file
View file

@ -0,0 +1,84 @@
/*-
* Copyright (c) 2017 Broadcom. All rights reserved.
* The term "Broadcom" refers to Broadcom Limited and/or its subsidiaries.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* $FreeBSD$
*/
#define STR_BE_BRANCH "0"
#define STR_BE_BUILD "9999"
#define STR_BE_DOT "0"
#define STR_BE_MINOR "0"
#define STR_BE_MAJOR "0"
#define BE_BRANCH 0
#define BE_BUILD 9999
#define BE_DOT 0
#define BE_MINOR 0
#define BE_MAJOR 0
#define MGMT_BRANCH 0
#define MGMT_BUILDNUM 476
#define MGMT_MINOR 100
#define MGMT_MAJOR 2
#define BE_REDBOOT_VERSION "2.0.5.0"
//start-auto
#define BUILD_MONTH "6"
#define BUILD_MONTH_NAME "June"
#define BUILD_DAY "12"
#define BUILD_YEAR "2009"
#define BUILD_24HOUR "5"
#define BUILD_12HOUR "5"
#define BUILD_AM_PM "AM"
#define BUILD_MIN "37"
#define BUILD_SEC "17"
#define BUILD_MONTH_NUMBER 6
#define BUILD_DAY_NUMBER 12
#define BUILD_YEAR_NUMBER 2009
#define BUILD_24HOUR_NUMBER 5
#define BUILD_12HOUR_NUMBER 5
#define BUILD_MIN_NUMBER 37
#define BUILD_SEC_NUMBER 17
#undef MAJOR_BUILD
#undef MINOR_BUILD
#undef DOT_BUILD
#undef NUMBERED_BUILD
#undef BRANCH_BUILD
//end-auto
#define ELX_FCOE_XROM_BIOS_VER "7.03a1"
#define ELX_FCoE_X86_VER "4.02a1"
#define ELX_FCoE_EFI_VER "5.01a1"
#define ELX_FCoE_FCODE_VER "4.01a0"
#define ELX_PXE_BIOS_VER "3.00a5"
#define ELX_UEFI_NIC_VER "2.10A10"
#define ELX_UEFI_FCODE_VER "1.10A1"
#define ELX_ISCSI_BIOS_VER "1.00A8"

View file

@ -296,6 +296,7 @@ SUBDIR= \
${_nvram} \
${_nxge} \
oce \
${_ocs_fc} \
otus \
${_otusfw} \
ow \
@ -609,6 +610,7 @@ _lio= lio
.endif
_nctgpio= nctgpio
_ndis= ndis
_ocs_fc= ocs_fc
_pccard= pccard
.if ${MK_OFED} != "no" || defined(ALL_MODULES)
_rdma= rdma

View file

@ -0,0 +1,45 @@
# $FreeBSD$
.PATH: ${SRCTOP}/sys/dev/ocs_fc
KMOD = ocs_fc
SRCS = \
device_if.h \
bus_if.h \
pci_if.h \
opt_scsi.h \
opt_cam.h
# OS
SRCS += ocs_pci.c ocs_ioctl.c ocs_os.c ocs_utils.c
# hw
SRCS += ocs_hw.c ocs_hw_queues.c
# SLI
SRCS += sli4.c ocs_sm.c
# Transport
SRCS += \
ocs_device.c \
ocs_xport.c \
ocs_domain.c \
ocs_sport.c \
ocs_els.c \
ocs_fabric.c \
ocs_io.c \
ocs_node.c \
ocs_scsi.c \
ocs_unsol.c \
ocs_ddump.c \
ocs_mgmt.c
# CAM initiator/target
SRCS += ocs_cam.c
CINCS = -I.
CLEANFILES += ${PROG}.debug ${PROG}.symbols cscope.* .depend.*
.include <bsd.kmod.mk>