summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDan Williams <dan.j.williams@intel.com>2011-07-02 22:56:22 -0700
committerDan Williams <dan.j.williams@intel.com>2011-07-02 22:56:22 -0700
commit6f231dda68080759f1aed3769896e94c73099f0f (patch)
tree45b6ce02fa40e0e9c35526ac6c45950138387516
parent59c5f46fbe01a00eedf54a23789634438bb80603 (diff)
downloadlinux-next-6f231dda68080759f1aed3769896e94c73099f0f.tar.gz
isci: Intel(R) C600 Series Chipset Storage Control Unit Driver
Support for the up to 2x4-port 6Gb/s SAS controllers embedded in the chipset. This is a snapshot of the first publicly available version of the driver, commit 4c1db2d0 in the 'historical' branch. git://git.kernel.org/pub/scm/linux/kernel/git/djbw/isci.git historical Signed-off-by: Maciej Trela <maciej.trela@intel.com> Signed-off-by: Dave Jiang <dave.jiang@intel.com> Signed-off-by: Edmund Nadolski <edmund.nadolski@intel.com> Signed-off-by: Dan Williams <dan.j.williams@intel.com>
-rw-r--r--drivers/scsi/Kconfig34
-rw-r--r--drivers/scsi/Makefile1
-rw-r--r--drivers/scsi/isci/Makefile30
-rw-r--r--drivers/scsi/isci/core/intel_ata.h554
-rw-r--r--drivers/scsi/isci/core/intel_sas.h948
-rw-r--r--drivers/scsi/isci/core/intel_sat.h95
-rw-r--r--drivers/scsi/isci/core/intel_sata.h280
-rw-r--r--drivers/scsi/isci/core/intel_scsi.h474
-rw-r--r--drivers/scsi/isci/core/sati_device.h156
-rw-r--r--drivers/scsi/isci/core/sati_translator_sequence.h304
-rw-r--r--drivers/scsi/isci/core/sati_types.h145
-rw-r--r--drivers/scsi/isci/core/sci_base_controller.h306
-rw-r--r--drivers/scsi/isci/core/sci_base_memory_descriptor_list.c159
-rw-r--r--drivers/scsi/isci/core/sci_base_memory_descriptor_list.h155
-rw-r--r--drivers/scsi/isci/core/sci_base_phy.h205
-rw-r--r--drivers/scsi/isci/core/sci_base_port.h203
-rw-r--r--drivers/scsi/isci/core/sci_base_remote_device.h277
-rw-r--r--drivers/scsi/isci/core/sci_base_request.h195
-rw-r--r--drivers/scsi/isci/core/sci_base_state.h90
-rw-r--r--drivers/scsi/isci/core/sci_base_state_machine.c182
-rw-r--r--drivers/scsi/isci/core/sci_base_state_machine.h139
-rw-r--r--drivers/scsi/isci/core/sci_controller.h100
-rw-r--r--drivers/scsi/isci/core/sci_controller_constants.h215
-rw-r--r--drivers/scsi/isci/core/sci_memory_descriptor_list.h169
-rw-r--r--drivers/scsi/isci/core/sci_object.h99
-rw-r--r--drivers/scsi/isci/core/sci_pool.h199
-rw-r--r--drivers/scsi/isci/core/sci_status.h409
-rw-r--r--drivers/scsi/isci/core/sci_types.h88
-rw-r--r--drivers/scsi/isci/core/sci_util.c70
-rw-r--r--drivers/scsi/isci/core/sci_util.h138
-rw-r--r--drivers/scsi/isci/core/scic_config_parameters.h347
-rw-r--r--drivers/scsi/isci/core/scic_controller.h586
-rw-r--r--drivers/scsi/isci/core/scic_io_request.h512
-rw-r--r--drivers/scsi/isci/core/scic_phy.h303
-rw-r--r--drivers/scsi/isci/core/scic_port.h213
-rw-r--r--drivers/scsi/isci/core/scic_remote_device.h295
-rw-r--r--drivers/scsi/isci/core/scic_sds_controller.c4147
-rw-r--r--drivers/scsi/isci/core/scic_sds_controller.h706
-rw-r--r--drivers/scsi/isci/core/scic_sds_controller_registers.h463
-rw-r--r--drivers/scsi/isci/core/scic_sds_pci.h95
-rw-r--r--drivers/scsi/isci/core/scic_sds_phy.c2807
-rw-r--r--drivers/scsi/isci/core/scic_sds_phy.h491
-rw-r--r--drivers/scsi/isci/core/scic_sds_phy_registers.h187
-rw-r--r--drivers/scsi/isci/core/scic_sds_port.c2757
-rw-r--r--drivers/scsi/isci/core/scic_sds_port.h514
-rw-r--r--drivers/scsi/isci/core/scic_sds_port_configuration_agent.c851
-rw-r--r--drivers/scsi/isci/core/scic_sds_port_configuration_agent.h108
-rw-r--r--drivers/scsi/isci/core/scic_sds_port_registers.h223
-rw-r--r--drivers/scsi/isci/core/scic_sds_remote_device.c2252
-rw-r--r--drivers/scsi/isci/core/scic_sds_remote_device.h602
-rw-r--r--drivers/scsi/isci/core/scic_sds_remote_node_context.c1244
-rw-r--r--drivers/scsi/isci/core/scic_sds_remote_node_context.h342
-rw-r--r--drivers/scsi/isci/core/scic_sds_remote_node_table.c600
-rw-r--r--drivers/scsi/isci/core/scic_sds_remote_node_table.h196
-rw-r--r--drivers/scsi/isci/core/scic_sds_request.c2179
-rw-r--r--drivers/scsi/isci/core/scic_sds_request.h484
-rw-r--r--drivers/scsi/isci/core/scic_sds_smp_remote_device.c410
-rw-r--r--drivers/scsi/isci/core/scic_sds_smp_request.c669
-rw-r--r--drivers/scsi/isci/core/scic_sds_smp_request.h70
-rw-r--r--drivers/scsi/isci/core/scic_sds_ssp_request.c340
-rw-r--r--drivers/scsi/isci/core/scic_sds_stp_packet_request.c838
-rw-r--r--drivers/scsi/isci/core/scic_sds_stp_packet_request.h154
-rw-r--r--drivers/scsi/isci/core/scic_sds_stp_pio_request.h116
-rw-r--r--drivers/scsi/isci/core/scic_sds_stp_remote_device.c975
-rw-r--r--drivers/scsi/isci/core/scic_sds_stp_request.c2004
-rw-r--r--drivers/scsi/isci/core/scic_sds_stp_request.h221
-rw-r--r--drivers/scsi/isci/core/scic_sds_unsolicited_frame_control.c379
-rw-r--r--drivers/scsi/isci/core/scic_sds_unsolicited_frame_control.h286
-rw-r--r--drivers/scsi/isci/core/scic_task_request.h148
-rw-r--r--drivers/scsi/isci/core/scic_user_callback.h740
-rw-r--r--drivers/scsi/isci/core/scu_completion_codes.h280
-rw-r--r--drivers/scsi/isci/core/scu_constants.h151
-rw-r--r--drivers/scsi/isci/core/scu_event_codes.h336
-rw-r--r--drivers/scsi/isci/core/scu_registers.h1824
-rw-r--r--drivers/scsi/isci/core/scu_remote_node_context.h230
-rw-r--r--drivers/scsi/isci/core/scu_task_context.h943
-rw-r--r--drivers/scsi/isci/core/scu_unsolicited_frame.h117
-rw-r--r--drivers/scsi/isci/core/scu_viit_data.h179
-rw-r--r--drivers/scsi/isci/deprecated.c491
-rw-r--r--drivers/scsi/isci/events.c619
-rw-r--r--drivers/scsi/isci/firmware/Makefile19
-rw-r--r--drivers/scsi/isci/firmware/README36
-rw-r--r--drivers/scsi/isci/firmware/create_fw.c177
-rw-r--r--drivers/scsi/isci/host.c781
-rw-r--r--drivers/scsi/isci/host.h283
-rw-r--r--drivers/scsi/isci/init.c613
-rw-r--r--drivers/scsi/isci/isci.h138
-rw-r--r--drivers/scsi/isci/phy.c179
-rw-r--r--drivers/scsi/isci/phy.h104
-rw-r--r--drivers/scsi/isci/port.c484
-rw-r--r--drivers/scsi/isci/port.h153
-rw-r--r--drivers/scsi/isci/remote_device.c698
-rw-r--r--drivers/scsi/isci/remote_device.h154
-rw-r--r--drivers/scsi/isci/request.c1472
-rw-r--r--drivers/scsi/isci/request.h429
-rw-r--r--drivers/scsi/isci/sata.c356
-rw-r--r--drivers/scsi/isci/sata.h83
-rw-r--r--drivers/scsi/isci/sci_environment.h112
-rw-r--r--drivers/scsi/isci/task.c1691
-rw-r--r--drivers/scsi/isci/task.h368
-rw-r--r--drivers/scsi/isci/timers.c319
-rw-r--r--drivers/scsi/isci/timers.h126
-rw-r--r--firmware/Makefile1
-rw-r--r--firmware/isci/isci_firmware.bin.ihex11
104 files changed, 51230 insertions, 0 deletions
diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig
index 4a1f029c4fe9..3aa664fa892e 100644
--- a/drivers/scsi/Kconfig
+++ b/drivers/scsi/Kconfig
@@ -830,6 +830,40 @@ config SCSI_GDTH
To compile this driver as a module, choose M here: the
module will be called gdth.
+config SCSI_ISCI
+ tristate "Intel(R) C600 Series Chipset SAS Controller"
+ depends on PCI && SCSI
+ # little endian host assumptions
+ depends on X86
+ # (temporary): dma api misuse
+ depends on !DMAR
+ # (temporary): known alpha quality driver
+ depends on EXPERIMENTAL
+ select SCSI_SAS_LIBSAS
+ ---help---
+ This driver supports the 6Gb/s SAS capabilities of the storage
+ control unit found in the Intel(R) C600 series chipset.
+
+ The experimental tag will be removed after the driver exits alpha
+
+choice
+ prompt "Default Silicon Revision"
+ depends on SCSI_ISCI
+ default PBG_HBA_A2
+ # temporary A-step silicon is pre-production
+
+config PBG_HBA_BETA
+ bool "B0"
+
+config PBG_HBA_A2
+ bool "A2"
+
+config PBG_HBA_A0
+ bool "A0"
+
+endchoice
+
+
config SCSI_GENERIC_NCR5380
tristate "Generic NCR5380/53c400 SCSI PIO support"
depends on ISA && SCSI
diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile
index 7ad0b8a79ae8..3c08f5352b2d 100644
--- a/drivers/scsi/Makefile
+++ b/drivers/scsi/Makefile
@@ -73,6 +73,7 @@ obj-$(CONFIG_SCSI_AACRAID) += aacraid/
obj-$(CONFIG_SCSI_AIC7XXX_OLD) += aic7xxx_old.o
obj-$(CONFIG_SCSI_AIC94XX) += aic94xx/
obj-$(CONFIG_SCSI_PM8001) += pm8001/
+obj-$(CONFIG_SCSI_ISCI) += isci/
obj-$(CONFIG_SCSI_IPS) += ips.o
obj-$(CONFIG_SCSI_FD_MCS) += fd_mcs.o
obj-$(CONFIG_SCSI_FUTURE_DOMAIN)+= fdomain.o
diff --git a/drivers/scsi/isci/Makefile b/drivers/scsi/isci/Makefile
new file mode 100644
index 000000000000..34f7af3525f4
--- /dev/null
+++ b/drivers/scsi/isci/Makefile
@@ -0,0 +1,30 @@
+#TODO kill SCIC_SDS_4_ENABLED it is always true for this
+#generation of silicon
+EXTRA_CFLAGS += -DSCIC_SDS_4_ENABLED
+
+#temporary until atapi support ready
+EXTRA_CFLAGS += -DDISABLE_ATAPI
+
+EXTRA_CFLAGS += -Idrivers/scsi/isci/core/ -Idrivers/scsi/isci/
+obj-$(CONFIG_SCSI_ISCI) += isci.o
+isci-objs := init.o phy.o request.o sata.o \
+ remote_device.o port.o timers.o deprecated.o \
+ host.o task.o events.o \
+ core/scic_sds_controller.o \
+ core/scic_sds_remote_device.o \
+ core/scic_sds_request.o \
+ core/scic_sds_stp_request.o \
+ core/scic_sds_stp_packet_request.o \
+ core/scic_sds_stp_remote_device.o \
+ core/scic_sds_port.o \
+ core/scic_sds_port_configuration_agent.o \
+ core/scic_sds_phy.o \
+ core/scic_sds_ssp_request.o \
+ core/scic_sds_remote_node_context.o \
+ core/scic_sds_smp_request.o \
+ core/scic_sds_smp_remote_device.o \
+ core/scic_sds_remote_node_table.o \
+ core/scic_sds_unsolicited_frame_control.o \
+ core/sci_base_memory_descriptor_list.o \
+ core/sci_base_state_machine.o \
+ core/sci_util.o
diff --git a/drivers/scsi/isci/core/intel_ata.h b/drivers/scsi/isci/core/intel_ata.h
new file mode 100644
index 000000000000..48b297e50bd0
--- /dev/null
+++ b/drivers/scsi/isci/core/intel_ata.h
@@ -0,0 +1,554 @@
+/*
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Intel Corporation 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
+ * OWNER 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.
+ */
+
+/**
+ * This file defines all of the ATA related constants, enumerations, and types.
+ * Please note that this file does not necessarily contain an exhaustive
+ * list of all constants, commands, sub-commands, etc.
+ *
+ *
+ */
+
+#ifndef _ATA_H_
+#define _ATA_H_
+
+#include <linux/types.h>
+
+/**
+ *
+ *
+ * ATA_COMMAND_CODES These constants depict the various ATA command codes
+ * defined in the ATA/ATAPI specification.
+ */
+#define ATA_IDENTIFY_DEVICE 0xEC
+#define ATA_CHECK_POWER_MODE 0xE5
+#define ATA_STANDBY 0xE2
+#define ATA_STANDBY_IMMED 0xE0
+#define ATA_IDLE_IMMED 0xE1
+#define ATA_IDLE 0xE3
+#define ATA_FLUSH_CACHE 0xE7
+#define ATA_FLUSH_CACHE_EXT 0xEA
+#define ATA_READ_DMA_EXT 0x25
+#define ATA_READ_DMA 0xC8
+#define ATA_READ_SECTORS_EXT 0x24
+#define ATA_READ_SECTORS 0x20
+#define ATA_WRITE_DMA_EXT 0x35
+#define ATA_WRITE_DMA 0xCA
+#define ATA_WRITE_SECTORS_EXT 0x34
+#define ATA_WRITE_SECTORS 0x30
+#define ATA_WRITE_UNCORRECTABLE 0x45
+#define ATA_READ_VERIFY_SECTORS 0x40
+#define ATA_READ_VERIFY_SECTORS_EXT 0x42
+#define ATA_READ_BUFFER 0xE4
+#define ATA_WRITE_BUFFER 0xE8
+#define ATA_EXECUTE_DEVICE_DIAG 0x90
+#define ATA_SET_FEATURES 0xEF
+#define ATA_SMART 0xB0
+#define ATA_PACKET_IDENTIFY 0xA1
+#define ATA_PACKET 0xA0
+#define ATA_READ_FPDMA 0x60
+#define ATA_WRITE_FPDMA 0x61
+#define ATA_READ_LOG_EXT 0x2F
+#define ATA_NOP 0x00
+#define ATA_DEVICE_RESET 0x08
+#define ATA_MEDIA_EJECT 0xED
+
+/**
+ *
+ *
+ * ATA_SMART_SUB_COMMAND_CODES These constants define the ATA SMART command
+ * sub-codes that can be executed.
+ */
+#define ATA_SMART_SUB_CMD_ENABLE 0xD8
+#define ATA_SMART_SUB_CMD_DISABLE 0xD9
+#define ATA_SMART_SUB_CMD_RETURN_STATUS 0xDA
+#define ATA_SMART_SUB_CMD_READ_LOG 0xD5
+
+/**
+ *
+ *
+ * ATA_SET_FEATURES_SUB_COMMAND_CODES These constants define the ATA SET
+ * FEATURES command sub-codes that can be executed.
+ */
+#define ATA_SET_FEATURES_SUB_CMD_ENABLE_CACHE 0x02
+#define ATA_SET_FEATURES_SUB_CMD_DISABLE_CACHE 0x82
+#define ATA_SET_FEATURES_SUB_CMD_DISABLE_READ_AHEAD 0x55
+#define ATA_SET_FEATURES_SUB_CMD_ENABLE_READ_AHEAD 0xAA
+#define ATA_SET_FEATURES_SUB_CMD_SET_TRANSFER_MODE 0x3
+
+/**
+ *
+ *
+ * ATA_READ_LOG_EXT_PAGE_CODES This is a list of log page codes available for
+ * use.
+ */
+#define ATA_LOG_PAGE_NCQ_ERROR 0x10
+#define ATA_LOG_PAGE_SMART_SELF_TEST 0x06
+#define ATA_LOG_PAGE_EXTENDED_SMART_SELF_TEST 0x07
+
+/**
+ *
+ *
+ * ATA_LOG_PAGE_NCQ_ERROR_CONSTANTS These constants define standard values for
+ * use when requesting the NCQ error log page.
+ */
+#define ATA_LOG_PAGE_NCQ_ERROR_SECTOR 0
+#define ATA_LOG_PAGE_NCQ_ERROR_SECTOR_COUNT 1
+
+/**
+ *
+ *
+ * ATA_STATUS_REGISTER_BITS The following are status register bit definitions
+ * per ATA/ATAPI-7.
+ */
+#define ATA_STATUS_REG_BSY_BIT 0x80
+#define ATA_STATUS_REG_DEVICE_FAULT_BIT 0x20
+#define ATA_STATUS_REG_ERROR_BIT 0x01
+
+/**
+ *
+ *
+ * ATA_ERROR_REGISTER_BITS The following are error register bit definitions per
+ * ATA/ATAPI-7.
+ */
+#define ATA_ERROR_REG_NO_MEDIA_BIT 0x02
+#define ATA_ERROR_REG_ABORT_BIT 0x04
+#define ATA_ERROR_REG_MEDIA_CHANGE_REQUEST_BIT 0x08
+#define ATA_ERROR_REG_ID_NOT_FOUND_BIT 0x10
+#define ATA_ERROR_REG_MEDIA_CHANGE_BIT 0x20
+#define ATA_ERROR_REG_UNCORRECTABLE_BIT 0x40
+#define ATA_ERROR_REG_WRITE_PROTECTED_BIT 0x40
+#define ATA_ERROR_REG_ICRC_BIT 0x80
+
+/**
+ *
+ *
+ * ATA_CONTROL_REGISTER_BITS The following are control register bit definitions
+ * per ATA/ATAPI-7
+ */
+#define ATA_CONTROL_REG_INTERRUPT_ENABLE_BIT 0x02
+#define ATA_CONTROL_REG_SOFT_RESET_BIT 0x04
+#define ATA_CONTROL_REG_HIGH_ORDER_BYTE_BIT 0x80
+
+/**
+ *
+ *
+ * ATA_DEVICE_HEAD_REGISTER_BITS The following are device/head register bit
+ * definitions per ATA/ATAPI-7.
+ */
+#define ATA_DEV_HEAD_REG_LBA_MODE_ENABLE 0x40
+#define ATA_DEV_HEAD_REG_FUA_ENABLE 0x80
+
+/**
+ *
+ *
+ * ATA_IDENTIFY_DEVICE_FIELD_LENGTHS The following constants define the number
+ * of bytes contained in various fields found in the IDENTIFY DEVICE data
+ * structure.
+ */
+#define ATA_IDENTIFY_SERIAL_NUMBER_LEN 20
+#define ATA_IDENTIFY_MODEL_NUMBER_LEN 40
+#define ATA_IDENTIFY_FW_REVISION_LEN 8
+#define ATA_IDENTIFY_48_LBA_LEN 8
+#define ATA_IDENTIFY_MEDIA_SERIAL_NUMBER_LEN 30
+#define ATA_IDENTIFY_WWN_LEN 8
+
+/**
+ *
+ *
+ * ATA_IDENTIFY_DEVICE_FIELD_MASKS The following constants define bit masks
+ * utilized to determine if a feature is supported/enabled or if a bit is
+ * simply set inside of the IDENTIFY DEVICE data structre.
+ */
+#define ATA_IDENTIFY_REMOVABLE_MEDIA_ENABLE 0x0080
+#define ATA_IDENTIFY_CAPABILITIES1_NORMAL_DMA_ENABLE 0x0100
+#define ATA_IDENTIFY_CAPABILITIES1_STANDBY_ENABLE 0x2000
+#define ATA_IDENTIFY_COMMAND_SET_SUPPORTED0_SMART_ENABLE 0x0001
+#define ATA_IDENTIFY_COMMAND_SET_SUPPORTED1_48BIT_ENABLE 0x0400
+#define ATA_IDENTIFY_COMMAND_SET_WWN_SUPPORT_ENABLE 0x0100
+#define ATA_IDENTIFY_COMMAND_SET_ENABLED0_SMART_ENABLE 0x0001
+#define ATA_IDENTIFY_SATA_CAPABILITIES_NCQ_ENABLE 0x0100
+#define ATA_IDENTIFY_NCQ_QUEUE_DEPTH_ENABLE 0x001F
+#define ATA_IDENTIFY_SECTOR_LARGER_THEN_512_ENABLE 0x0100
+#define ATA_IDENTIFY_LOGICAL_SECTOR_PER_PHYSICAL_SECTOR_MASK 0x000F
+#define ATA_IDENTIFY_LOGICAL_SECTOR_PER_PHYSICAL_SECTOR_ENABLE 0x2000
+#define ATA_IDENTIFY_WRITE_UNCORRECTABLE_SUPPORT 0x0004
+#define ATA_IDENTIFY_COMMAND_SET_SMART_SELF_TEST_SUPPORTED 0x0002
+
+/**
+ *
+ *
+ * ATAPI_IDENTIFY_DEVICE_FIELD_MASKS These constants define the various bit
+ * definitions for the fields in the PACKET IDENTIFY DEVICE data structure.
+ */
+#define ATAPI_IDENTIFY_16BYTE_CMD_PCKT_ENABLE 0x01
+
+/**
+ *
+ *
+ * ATA_PACKET_FEATURE_BITS These constants define the various bit definitions
+ * for the ATA PACKET feature register.
+ */
+#define ATA_PACKET_FEATURE_DMA 0x01
+#define ATA_PACKET_FEATURE_OVL 0x02
+#define ATA_PACKET_FEATURE_DMADIR 0x04
+
+/**
+ *
+ *
+ * ATA_Device_Power_Mode_Values These constants define the power mode values
+ * returned by ATA_Check_Power_Mode
+ */
+#define ATA_STANDBY_POWER_MODE 0x00
+#define ATA_IDLE_POWER_MODE 0x80
+#define ATA_ACTIVE_POWER_MODE 0xFF
+
+/**
+ *
+ *
+ * ATA_WRITE_UNCORRECTIABLE feature field values These constants define the
+ * Write Uncorrectable feature values used with the SATI translation.
+ */
+#define ATA_WRITE_UNCORRECTABLE_PSUEDO 0x55
+#define ATA_WRITE_UNCORRECTABLE_FLAGGED 0xAA
+
+
+
+/**
+ * struct ATA_IDENTIFY_DEVICE - This structure depicts the ATA IDENTIFY DEVICE
+ * data format.
+ *
+ *
+ */
+struct ata_identify_device_data {
+ u16 general_config_bits; /* word 00 */
+ u16 obsolete0; /* word 01 (num cylinders) */
+ u16 vendor_specific_config_bits; /* word 02 */
+ u16 obsolete1; /* word 03 (num heads) */
+ u16 retired1[2]; /* words 04-05 */
+ u16 obsolete2; /* word 06 (sectors / track) */
+ u16 reserved_for_compact_flash1[2]; /* words 07-08 */
+ u16 retired0; /* word 09 */
+ u8 serial_number[ATA_IDENTIFY_SERIAL_NUMBER_LEN]; /* word 10-19 */
+ u16 retired2[2]; /* words 20-21 */
+ u16 obsolete4; /* word 22 */
+ u8 firmware_revision[ATA_IDENTIFY_FW_REVISION_LEN]; /* words 23-26 */
+ u8 model_number[ATA_IDENTIFY_MODEL_NUMBER_LEN]; /* words 27-46 */
+ u16 max_sectors_per_multiple; /* word 47 */
+ u16 reserved0; /* word 48 */
+ u16 capabilities1; /* word 49 */
+ u16 capabilities2; /* word 50 */
+ u16 obsolete5[2]; /* words 51-52 */
+ u16 validity_bits; /* word 53 */
+ u16 obsolete6[5]; /*
+ * words 54-58 Used to be:
+ * current cylinders,
+ * current heads,
+ * current sectors/Track,
+ * current capacity */
+ u16 current_max_sectors_per_multiple; /* word 59 */
+ u8 total_num_sectors[4]; /* words 60-61 */
+ u16 obsolete7; /* word 62 */
+ u16 multi_word_dma_mode; /* word 63 */
+ u16 pio_modes_supported; /* word 64 */
+ u16 min_multiword_dma_transfer_cycle; /* word 65 */
+ u16 rec_min_multiword_dma_transfer_cycle; /* word 66 */
+ u16 min_pio_transfer_no_flow_ctrl; /* word 67 */
+ u16 min_pio_transfer_with_flow_ctrl; /* word 68 */
+ u16 reserved1[2]; /* words 69-70 */
+ u16 reserved2[4]; /* words 71-74 */
+ u16 queue_depth; /* word 75 */
+ u16 serial_ata_capabilities; /* word 76 */
+ u16 serial_ata_reserved; /* word 77 */
+ u16 serial_ata_features_supported; /* word 78 */
+ u16 serial_ata_features_enabled; /* word 79 */
+ u16 major_version_number; /* word 80 */
+ u16 minor_version_number; /* word 81 */
+ u16 command_set_supported0; /* word 82 */
+ u16 command_set_supported1; /* word 83 */
+ u16 command_set_supported_extention; /* word 84 */
+ u16 command_set_enabled0; /* word 85 */
+ u16 command_set_enabled1; /* word 86 */
+ u16 command_set_default; /* word 87 */
+ u16 ultra_dma_mode; /* word 88 */
+ u16 security_erase_completion_time; /* word 89 */
+ u16 enhanced_security_erase_time; /* word 90 */
+ u16 current_power_mgmt_value; /* word 91 */
+ u16 master_password_revision; /* word 92 */
+ u16 hardware_reset_result; /* word 93 */
+ u16 current_acoustic_management_value; /* word 94 */
+ u16 stream_min_request_size; /* word 95 */
+ u16 stream_transfer_time; /* word 96 */
+ u16 stream_access_latency; /* word 97 */
+ u16 stream_performance_granularity[2]; /* words 98-99 */
+ u8 max_48bit_lba[ATA_IDENTIFY_48_LBA_LEN]; /* words 100-103 */
+ u16 streaming_transfer_time; /* word 104 */
+ u16 reserved3; /* word 105 */
+ u16 physical_logical_sector_info; /* word 106 */
+ u16 acoustic_test_interseek_delay; /* word 107 */
+ u8 world_wide_name[ATA_IDENTIFY_WWN_LEN]; /* words 108-111 */
+ u8 reserved_for_wwn_extention[ATA_IDENTIFY_WWN_LEN]; /* words 112-115 */
+ u16 reserved4; /* word 116 */
+ u8 words_per_logical_sector[4]; /* words 117-118 */
+ u16 command_set_supported2; /* word 119 */
+ u16 reserved5[7]; /* words 120-126 */
+ u16 removable_media_status; /* word 127 */
+ u16 security_status; /* word 128 */
+ u16 vendor_specific1[31]; /* words 129-159 */
+ u16 cfa_power_mode1; /* word 160 */
+ u16 reserved_for_compact_flash2[7]; /* words 161-167 */
+ u16 device_nominal_form_factor; /* word 168 */
+ u16 reserved_for_compact_flash3[7]; /* words 169-175 */
+ u16 current_media_serial_number[ATA_IDENTIFY_MEDIA_SERIAL_NUMBER_LEN]; /* words 176-205 */
+ u16 reserved6[3]; /* words 206-208 */
+ u16 logical_sector_alignment; /* words 209 */
+ u16 reserved7[7]; /* words 210-216 */
+ u16 nominal_media_rotation_rate; /* word 217 */
+ u16 reserved8[37]; /* words 218-254 */
+ u16 integrity_word; /* word 255 */
+
+};
+
+#define ATA_IDENTIFY_DEVICE_GET_OFFSET(field_name) \
+ ((unsigned long)&(((struct ata_identify_device_data *)0)->field_name))
+#define ATA_IDENTIFY_DEVICE_WCE_ENABLE 0x20
+#define ATA_IDENTIFY_DEVICE_RA_ENABLE 0x40
+
+/**
+ * struct ATAPI_IDENTIFY_PACKET_DATA - The following structure depicts the
+ * ATA-ATAPI 7 version of the IDENTIFY PACKET DEVICE data structure.
+ *
+ *
+ */
+struct atapi_identify_packet_device {
+ u16 generalConfigBits; /* word 00 */
+ u16 reserved0; /* word 01 (num cylinders) */
+ u16 uniqueConfigBits; /* word 02 */
+ u16 reserved1[7]; /* words 03 - 09 */
+ u8 serialNumber[ATA_IDENTIFY_SERIAL_NUMBER_LEN]; /* word 10-19 */
+ u16 reserved2[3]; /* words 20-22 */
+ u8 firmwareRevision[ATA_IDENTIFY_FW_REVISION_LEN]; /* words 23-26 */
+ u8 modelNumber[ATA_IDENTIFY_MODEL_NUMBER_LEN]; /* words 27-46 */
+ u16 reserved4[2]; /* words 47-48 */
+ u16 capabilities1; /* word 49 */
+ u16 capabilities2; /* word 50 */
+ u16 obsolete0[2]; /* words 51-52 */
+ u16 validityBits; /* word 53 */
+ u16 reserved[8]; /* words 54-61 */
+
+ u16 DMADIRBitRequired; /* word 62, page2 */
+ u16 multiWordDmaMode; /* word 63 */
+ u16 pioModesSupported; /* word 64 */
+ u16 minMultiwordDmaTransferCycle; /* word 65 */
+ u16 recMinMultiwordDmaTransferCycle; /* word 66 */
+ u16 minPioTransferNoFlowCtrl; /* word 67 */
+ u16 minPioTransferWithFlowCtrl; /* word 68 */
+ u16 reserved6[2]; /* words 69-70 */
+ u16 nsFromPACKETReceiptToBusRelease; /* word 71 */
+ u16 nsFromSERVICEReceiptToBSYreset; /* wore 72 */
+ u16 reserved7[2]; /* words 73-74 */
+ u16 queueDepth; /* word 75 */
+ u16 serialAtaCapabilities; /* word 76 */
+ u16 serialAtaReserved; /* word 77 */
+ u16 serialAtaFeaturesSupported; /* word 78 */
+ u16 serialAtaFeaturesEnabled; /* word 79 */
+
+ u16 majorVersionNumber; /* word 80, page3 */
+ u16 minorVersionNumber; /* word 81 */
+ u16 commandSetSupported0; /* word 82 */
+ u16 commandSetSupported1; /* word 83 */
+
+ u16 commandSetSupportedExtention; /* word 84, page4 */
+ u16 commandSetEnabled0; /* word 85 */
+ u16 commandSetEnabled1; /* word 86 */
+ u16 commandSetDefault; /* word 87 */
+
+ u16 ultraDmaMode; /* word 88, page5 */
+ u16 reserved8[4]; /* words 89 - 92 */
+
+ u16 hardwareResetResult; /* word 93, page6 */
+ u16 currentAcousticManagementValue; /* word 94 */
+ u16 reserved9[30]; /* words 95-124 */
+ u16 ATAPIByteCount0Behavior; /* word 125 */
+ u16 obsolete1; /* word 126 */
+ u16 removableMediaStatus; /* word 127, */
+
+ u16 securityStatus; /* word 128, page7 */
+ u16 vendorSpecific1[31]; /* words 129-159 */
+ u16 reservedForCompactFlash[16]; /* words 160-175 */
+ u16 reserved10[79]; /* words 176-254 */
+ u16 integrityWord; /* word 255 */
+};
+
+/**
+ * struct ata_extended_smart_self_test_log - The following structure depicts
+ * the ATA-8 version of the Extended SMART self test log page descriptor
+ * entry.
+ *
+ *
+ */
+union ata_descriptor_entry {
+ struct DESCRIPTOR_ENTRY {
+ u8 lba_field;
+ u8 status_byte;
+ u8 time_stamp_low;
+ u8 time_stamp_high;
+ u8 checkpoint_byte;
+ u8 failing_lba_low;
+ u8 failing_lba_mid;
+ u8 failing_lba_high;
+ u8 failing_lba_low_ext;
+ u8 failing_lba_mid_ext;
+ u8 failing_lba_high_ext;
+
+ u8 vendor_specific1;
+ u8 vendor_specific2;
+ u8 vendor_specific3;
+ u8 vendor_specific4;
+ u8 vendor_specific5;
+ u8 vendor_specific6;
+ u8 vendor_specific7;
+ u8 vendor_specific8;
+ u8 vendor_specific9;
+ u8 vendor_specific10;
+ u8 vendor_specific11;
+ u8 vendor_specific12;
+ u8 vendor_specific13;
+ u8 vendor_specific14;
+ u8 vendor_specific15;
+ } DESCRIPTOR_ENTRY;
+
+ u8 descriptor_entry[26];
+
+};
+
+/**
+ * struct ata_extended_smart_self_test_log - The following structure depicts
+ * the ATA-8 version of the SMART self test log page descriptor entry.
+ *
+ *
+ */
+union ata_smart_descriptor_entry {
+ struct SMART_DESCRIPTOR_ENTRY {
+ u8 lba_field;
+ u8 status_byte;
+ u8 time_stamp_low;
+ u8 time_stamp_high;
+ u8 checkpoint_byte;
+ u8 failing_lba_low;
+ u8 failing_lba_mid;
+ u8 failing_lba_high;
+ u8 failing_lba_low_ext;
+
+ u8 vendor_specific1;
+ u8 vendor_specific2;
+ u8 vendor_specific3;
+ u8 vendor_specific4;
+ u8 vendor_specific5;
+ u8 vendor_specific6;
+ u8 vendor_specific7;
+ u8 vendor_specific8;
+ u8 vendor_specific9;
+ u8 vendor_specific10;
+ u8 vendor_specific11;
+ u8 vendor_specific12;
+ u8 vendor_specific13;
+ u8 vendor_specific14;
+ u8 vendor_specific15;
+ } SMART_DESCRIPTOR_ENTRY;
+
+ u8 smart_descriptor_entry[24];
+
+};
+
+/**
+ * struct ata_extended_smart_self_test_log - The following structure depicts
+ * the ATA-8 version of the Extended SMART self test log page.
+ *
+ *
+ */
+struct ata_extended_smart_self_test_log {
+ u8 self_test_log_data_structure_revision_number; /* byte 0 */
+ u8 reserved0; /* byte 1 */
+ u8 self_test_descriptor_index[2]; /* byte 2-3 */
+
+ union ata_descriptor_entry descriptor_entrys[19]; /* bytes 4-497 */
+
+ u8 vendor_specific[2]; /* byte 498-499 */
+ u8 reserved1[11]; /* byte 500-510 */
+ u8 data_structure_checksum; /* byte 511 */
+
+};
+
+/**
+ * struct ata_extended_smart_self_test_log - The following structure depicts
+ * the ATA-8 version of the SMART self test log page.
+ *
+ *
+ */
+struct ata_smart_self_test_log {
+ u8 self_test_log_data_structure_revision_number[2]; /* bytes 0-1 */
+
+ union ata_smart_descriptor_entry descriptor_entrys[21]; /* bytes 2-505 */
+
+ u8 vendor_specific[2]; /* byte 506-507 */
+ u8 self_test_index; /* byte 508 */
+ u8 reserved1[2]; /* byte 509-510 */
+ u8 data_structure_checksum; /* byte 511 */
+
+};
+
+#endif /* _ATA_H_ */
+
diff --git a/drivers/scsi/isci/core/intel_sas.h b/drivers/scsi/isci/core/intel_sas.h
new file mode 100644
index 000000000000..eb9686ea35f1
--- /dev/null
+++ b/drivers/scsi/isci/core/intel_sas.h
@@ -0,0 +1,948 @@
+/*
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Intel Corporation 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
+ * OWNER 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.
+ */
+
+#ifndef _INTEL_SAS_H_
+#define _INTEL_SAS_H_
+
+/**
+ * This file contains all of the definitions relating to structures, constants,
+ * etc. defined by the SAS specification.
+ *
+ *
+ */
+
+#include "intel_sata.h"
+#include "intel_scsi.h"
+
+/**
+ * struct sci_sas_address - This structure depicts how a SAS address is
+ * represented by SCI.
+ *
+ *
+ */
+struct sci_sas_address {
+ /**
+ * This member contains the higher 32-bits of the SAS address.
+ */
+ u32 high;
+
+ /**
+ * This member contains the lower 32-bits of the SAS address.
+ */
+ u32 low;
+
+};
+
+/**
+ * struct sci_sas_identify_address_frame_protocols - This structure depicts the
+ * contents of bytes 2 and 3 in the SAS IDENTIFY ADDRESS FRAME (IAF).
+ *
+ * For specific information on each of these individual fields please reference
+ * the SAS specification Link layer section on address frames.
+ */
+struct sci_sas_identify_address_frame_protocols {
+ union {
+ struct {
+ u16 restricted1:1;
+ u16 smp_initiator:1;
+ u16 stp_initiator:1;
+ u16 ssp_initiator:1;
+ u16 reserved3:4;
+ u16 restricted2:1;
+ u16 smp_target:1;
+ u16 stp_target:1;
+ u16 ssp_target:1;
+ u16 reserved4:4;
+ } bits;
+
+ u16 all;
+ } u;
+
+};
+
+/**
+ * struct sci_sas_identify_address_frame - This structure depicts the contents
+ * of the SAS IDENTIFY ADDRESS FRAME (IAF).
+ *
+ * For specific information on each of these individual fields please reference
+ * the SAS specification Link layer section on address frames.
+ */
+struct sci_sas_identify_address_frame {
+ u16 address_frame_type:4;
+ u16 device_type:3;
+ u16 reserved1:1;
+ u16 reason:4;
+ u16 reserved2:4;
+
+ struct sci_sas_identify_address_frame_protocols protocols;
+
+ struct sci_sas_address device_name;
+ struct sci_sas_address sas_address;
+
+ u32 phy_identifier:8;
+ u32 break_reply_capable:1;
+ u32 requested_in_zpsds:1;
+ u32 in_zpsds_persistent:1;
+ u32 reserved5:21;
+
+ u32 reserved6[4];
+
+};
+
+/**
+ * struct sas_capabilities - This structure depicts the various SAS
+ * capabilities supported by the directly attached target device. For
+ * specific information on each of these individual fields please reference
+ * the SAS specification Phy layer section on speed negotiation windows.
+ *
+ *
+ */
+struct sas_capabilities {
+ union {
+#if defined (SCIC_SDS_4_ENABLED)
+ struct {
+ /**
+ * The SAS specification indicates the start bit shall always be set to
+ * 1. This implementation will have the start bit set to 0 if the
+ * PHY CAPABILITIES were either not received or speed negotiation failed.
+ */
+ u32 start:1;
+ u32 tx_ssc_type:1;
+ u32 reserved1:2;
+ u32 requested_logical_link_rate:4;
+
+ u32 gen1_without_ssc_supported:1;
+ u32 gen1_with_ssc_supported:1;
+ u32 gen2_without_ssc_supported:1;
+ u32 gen2_with_ssc_supported:1;
+ u32 gen3_without_ssc_supported:1;
+ u32 gen3_with_ssc_supported:1;
+ u32 reserved2:17;
+ u32 parity:1;
+ } bits;
+#endif /* (SCIC_SDS_4_ENABLED) */
+
+ u32 all;
+ } u;
+
+};
+
+/**
+ * enum _SCI_SAS_LINK_RATE - This enumeration depicts the SAS specification
+ * defined link speeds.
+ *
+ *
+ */
+enum sci_sas_link_rate {
+ SCI_SAS_NO_LINK_RATE = 0,
+ SCI_SATA_SPINUP_HOLD = 0x3,
+ SCI_SAS_150_GB = 0x8,
+ SCI_SAS_300_GB = 0x9,
+ SCI_SAS_600_GB = 0xA
+};
+
+/**
+ * enum _SCI_SAS_TASK_ATTRIBUTE - This enumeration depicts the SAM/SAS
+ * specification defined task attribute values for a command information
+ * unit.
+ *
+ *
+ */
+enum sci_sas_task_attribute {
+ SCI_SAS_SIMPLE_ATTRIBUTE = 0,
+ SCI_SAS_HEAD_OF_QUEUE_ATTRIBUTE = 1,
+ SCI_SAS_ORDERED_ATTRIBUTE = 2,
+ SCI_SAS_ACA_ATTRIBUTE = 4,
+};
+
+/**
+ * enum _SCI_SAS_TASK_MGMT_FUNCTION - This enumeration depicts the SAM/SAS
+ * specification defined task management functions.
+ *
+ * This HARD_RESET function listed here is not actually defined as a task
+ * management function in the industry standard.
+ */
+enum sci_sas_task_mgmt_function {
+ SCI_SAS_ABORT_TASK = SCSI_TASK_REQUEST_ABORT_TASK,
+ SCI_SAS_ABORT_TASK_SET = SCSI_TASK_REQUEST_ABORT_TASK_SET,
+ SCI_SAS_CLEAR_TASK_SET = SCSI_TASK_REQUEST_CLEAR_TASK_SET,
+ SCI_SAS_LOGICAL_UNIT_RESET = SCSI_TASK_REQUEST_LOGICAL_UNIT_RESET,
+ SCI_SAS_I_T_NEXUS_RESET = SCSI_TASK_REQUEST_I_T_NEXUS_RESET,
+ SCI_SAS_CLEAR_ACA = SCSI_TASK_REQUEST_CLEAR_ACA,
+ SCI_SAS_QUERY_TASK = SCSI_TASK_REQUEST_QUERY_TASK,
+ SCI_SAS_QUERY_TASK_SET = SCSI_TASK_REQUEST_QUERY_TASK_SET,
+ SCI_SAS_QUERY_ASYNCHRONOUS_EVENT = SCSI_TASK_REQUEST_QUERY_UNIT_ATTENTION,
+ SCI_SAS_HARD_RESET = 0xFF
+};
+
+
+/**
+ * enum _SCI_SAS_FRAME_TYPE - This enumeration depicts the SAS specification
+ * defined SSP frame types.
+ *
+ *
+ */
+enum sci_sas_frame_type {
+ SCI_SAS_DATA_FRAME = 0x01,
+ SCI_SAS_XFER_RDY_FRAME = 0x05,
+ SCI_SAS_COMMAND_FRAME = 0x06,
+ SCI_SAS_RESPONSE_FRAME = 0x07,
+ SCI_SAS_TASK_FRAME = 0x16
+};
+
+/**
+ * struct sci_ssp_command_iu - This structure depicts the contents of the SSP
+ * COMMAND INFORMATION UNIT. For specific information on each of these
+ * individual fields please reference the SAS specification SSP transport
+ * layer section.
+ *
+ *
+ */
+struct sci_ssp_command_iu {
+ u32 lun_upper;
+ u32 lun_lower;
+
+ u32 additional_cdb_length:6;
+ u32 reserved0:2;
+ u32 reserved1:8;
+ u32 enable_first_burst:1;
+ u32 task_priority:4;
+ u32 task_attribute:3;
+ u32 reserved2:8;
+
+ u32 cdb[4];
+
+};
+
+/**
+ * struct sci_ssp_task_iu - This structure depicts the contents of the SSP TASK
+ * INFORMATION UNIT. For specific information on each of these individual
+ * fields please reference the SAS specification SSP transport layer section.
+ *
+ *
+ */
+struct sci_ssp_task_iu {
+ u32 lun_upper;
+ u32 lun_lower;
+
+ u32 reserved0:8;
+ u32 task_function:8;
+ u32 reserved1:8;
+ u32 reserved2:8;
+
+ u32 reserved3:16;
+ u32 task_tag:16;
+
+ u32 reserved4[3];
+
+};
+
+#define SSP_RESPONSE_IU_MAX_DATA 64
+
+#define SCI_SSP_RESPONSE_IU_DATA_PRESENT_MASK (0x03)
+
+
+#define sci_ssp_get_sense_data_length(sense_data_length_buffer) \
+ SCIC_BUILD_DWORD(sense_data_length_buffer)
+
+#define sci_ssp_get_response_data_length(response_data_length_buffer) \
+ SCIC_BUILD_DWORD(response_data_length_buffer)
+
+/**
+ * struct sci_ssp_response_iu - This structure depicts the contents of the SSP
+ * RESPONSE INFORMATION UNIT. For specific information on each of these
+ * individual fields please reference the SAS specification SSP transport
+ * layer section.
+ *
+ *
+ */
+struct sci_ssp_response_iu {
+ u8 reserved0[8];
+
+ u8 retry_delay_timer[2];
+ u8 data_present;
+ u8 status;
+
+ u8 reserved1[4];
+ u8 sense_data_length[4];
+ u8 response_data_length[4];
+
+ u32 data[SSP_RESPONSE_IU_MAX_DATA];
+
+};
+
+/**
+ * enum _SCI_SAS_DATA_PRESENT_TYPE - This enumeration depicts the SAS
+ * specification defined SSP data present types in struct sci_ssp_response_iu.
+ *
+ *
+ */
+enum sci_ssp_response_iu_data_present_type {
+ SCI_SSP_RESPONSE_IU_NO_DATA = 0x00,
+ SCI_SSP_RESPONSE_IU_RESPONSE_DATA = 0x01,
+ SCI_SSP_RESPONSE_IU_SENSE_DATA = 0x02
+};
+
+/**
+ * struct sci_ssp_frame_header - This structure depicts the contents of an SSP
+ * frame header. For specific information on the individual fields please
+ * reference the SAS specification transport layer SSP frame format.
+ *
+ *
+ */
+struct sci_ssp_frame_header {
+ /* Word 0 */
+ u32 hashed_destination_address:24;
+ u32 frame_type:8;
+
+ /* Word 1 */
+ u32 hashed_source_address:24;
+ u32 reserved1_0:8;
+
+ /* Word 2 */
+ u32 reserved2_2:6;
+ u32 fill_bytes:2;
+ u32 reserved2_1:3;
+ u32 tlr_control:2;
+ u32 retry_data_frames:1;
+ u32 retransmit:1;
+ u32 changing_data_pointer:1;
+ u32 reserved2_0:16;
+
+ /* Word 3 */
+ u32 uiResv4;
+
+ /* Word 4 */
+ u16 target_port_transfer_tag;
+ u16 tag;
+
+ /* Word 5 */
+ u32 data_offset;
+
+};
+
+/**
+ * struct smp_request_header - This structure defines the contents of an SMP
+ * Request header.
+ *
+ * For specific information on each of these individual fields please reference
+ * the SAS specification.
+ */
+struct smp_request_header {
+ u8 smp_frame_type; /* byte 0 */
+ u8 function; /* byte 1 */
+ u8 allocated_response_length; /* byte 2 */
+ u8 request_length; /* byte 3 */
+};
+
+/**
+ * struct smp_response_header - This structure depicts the contents of the SAS
+ * SMP DISCOVER RESPONSE frame. For specific information on each of these
+ * individual fields please reference the SAS specification Link layer
+ * section on address frames.
+ *
+ *
+ */
+struct smp_response_header {
+ u8 smp_frame_type; /* byte 0 */
+ u8 function; /* byte 1 */
+ u8 function_result; /* byte 2 */
+ u8 response_length; /* byte 3 */
+};
+
+/**
+ * struct smp_request_general - This structure defines the contents of an SMP
+ * Request that is comprised of the struct smp_request_header and a CRC.
+ *
+ * For specific information on each of these individual fields please reference
+ * the SAS specification.
+ */
+struct smp_request_general {
+ u32 crc; /* bytes 4-7 */
+
+};
+
+/**
+ * struct smp_request_phy_identifier - This structure defines the contents of
+ * an SMP Request that is comprised of the struct smp_request_header and a phy
+ * identifier. Examples: SMP_REQUEST_DISCOVER, SMP_REQUEST_REPORT_PHY_SATA.
+ *
+ * For specific information on each of these individual fields please reference
+ * the SAS specification.
+ */
+struct smp_request_phy_identifier {
+ u32 reserved_byte4_7; /* bytes 4-7 */
+
+ u32 ignore_zone_group:1; /* byte 8 */
+ u32 reserved_byte8:7;
+
+ u32 phy_identifier:8; /* byte 9 */
+ u32 reserved_byte10:8; /* byte 10 */
+ u32 reserved_byte11:8; /* byte 11 */
+
+};
+
+/**
+ * struct smp_request_configure_route_information - This structure defines the
+ * contents of an SMP Configure Route Information request.
+ *
+ * For specific information on each of these individual fields please reference
+ * the SAS specification.
+ */
+struct smp_request_configure_route_information {
+ u32 expected_expander_change_count:16; /* bytes 4-5 */
+ u32 expander_route_index_high:8;
+ u32 expander_route_index:8; /* bytes 6-7 */
+
+ u32 reserved_byte8:8; /* bytes 8 */
+ u32 phy_identifier:8; /* bytes 9 */
+ u32 reserved_byte_10_11:16; /* bytes 10-11 */
+
+ u32 reserved_byte_12_bit_0_6:7;
+ u32 disable_route_entry:1; /* byte 12 */
+ u32 reserved_byte_13_15:24; /* bytes 13-15 */
+
+ u32 routed_sas_address[2]; /* bytes 16-23 */
+ u8 reserved_byte_24_39[16]; /* bytes 24-39 */
+
+};
+
+/**
+ * struct smp_request_phy_control - This structure defines the contents of an
+ * SMP Phy Controler request.
+ *
+ * For specific information on each of these individual fields please reference
+ * the SAS specification.
+ */
+struct smp_request_phy_control {
+ u16 expected_expander_change_count; /* byte 4-5 */
+
+ u16 reserved_byte_6_7; /* byte 6-7 */
+ u8 reserved_byte_8; /* byte 8 */
+
+ u8 phy_identifier; /* byte 9 */
+ u8 phy_operation; /* byte 10 */
+
+ u8 update_partial_pathway_timeout_value:1;
+ u8 reserved_byte_11_bit_1_7:7; /* byte 11 */
+
+ u8 reserved_byte_12_23[12]; /* byte 12-23 */
+
+ u8 attached_device_name[8]; /* byte 24-31 */
+
+ u8 reserved_byte_32_bit_3_0:4; /* byte 32 */
+ u8 programmed_minimum_physical_link_rate:4;
+
+ u8 reserved_byte_33_bit_3_0:4; /* byte 33 */
+ u8 programmed_maximum_physical_link_rate:4;
+
+ u16 reserved_byte_34_35; /* byte 34-35 */
+
+ u8 partial_pathway_timeout_value:4;
+ u8 reserved_byte_36_bit_4_7:4; /* byte 36 */
+
+ u16 reserved_byte_37_38; /* byte 37-38 */
+ u8 reserved_byte_39; /* byte 39 */
+
+};
+
+/**
+ * struct smp_request_vendor_specific - This structure depicts the vendor
+ * specific space for SMP request.
+ *
+ *
+ */
+ #define SMP_REQUEST_VENDOR_SPECIFIC_MAX_LENGTH 1016
+struct smp_request_vendor_specific {
+ u8 request_bytes[SMP_REQUEST_VENDOR_SPECIFIC_MAX_LENGTH];
+};
+
+/**
+ * struct smp_request - This structure simply unionizes the existing request
+ * structures into a common request type.
+ *
+ *
+ */
+struct smp_request {
+ struct smp_request_header header;
+
+ union { /* bytes 4-N */
+ struct smp_request_general report_general;
+ struct smp_request_phy_identifier discover;
+ struct smp_request_general report_manufacturer_information;
+ struct smp_request_phy_identifier report_phy_sata;
+ struct smp_request_phy_control phy_control;
+ struct smp_request_phy_identifier report_phy_error_log;
+ struct smp_request_phy_identifier report_route_information;
+ struct smp_request_configure_route_information configure_route_information;
+ struct smp_request_vendor_specific vendor_specific_request;
+ } request;
+
+};
+
+
+/**
+ * struct smp_response_report_general - This structure depicts the SMP Report
+ * General for expander devices. It adheres to the SAS-2.1 specification.
+ *
+ * For specific information on each of these individual fields please reference
+ * the SAS specification Application layer section on SMP.
+ */
+struct smp_response_report_general {
+ u16 expander_change_count; /* byte 4-5 */
+ u16 expander_route_indexes; /* byte 6-7 */
+
+ u32 reserved_byte8:7; /* byte 8 bit 0-6 */
+ u32 long_response:1; /* byte 8 bit 7 */
+
+ u32 number_of_phys:8; /* byte 9 */
+
+ u32 configurable_route_table:1; /* byte 10 */
+ u32 configuring:1;
+ u32 configures_others:1;
+ u32 open_reject_retry_supported:1;
+ u32 stp_continue_awt:1;
+ u32 self_configuring:1;
+ u32 zone_configuring:1;
+ u32 table_to_table_supported:1;
+
+ u32 reserved_byte11:8; /* byte 11 */
+
+ u32 enclosure_logical_identifier_high; /* byte 12-15 */
+ u32 enclosure_logical_identifier_low; /* byte 16-19 */
+
+ u32 reserved_byte20_23;
+ u32 reserved_byte24_27;
+
+};
+
+struct smp_response_report_general_long {
+ struct smp_response_report_general sas1_1;
+
+ struct {
+ u16 reserved1;
+ u16 stp_bus_inactivity_time_limit;
+ u16 stp_max_connect_time_limit;
+ u16 stp_smp_i_t_nexus_loss_time;
+
+ u32 zoning_enabled:1;
+ u32 zoning_supported:1;
+ u32 physicaL_presence_asserted:1;
+ u32 zone_locked:1;
+ u32 reserved2:1;
+ u32 num_zone_groups:3;
+ u32 saving_zoning_enabled_supported:3;
+ u32 saving_zone_perms_table_supported:1;
+ u32 saving_zone_phy_info_supported:1;
+ u32 saving_zone_manager_password_supported:1;
+ u32 saving:1;
+ u32 reserved3:1;
+ u32 max_number_routed_sas_addresses:16;
+
+ struct sci_sas_address active_zone_manager_sas_address;
+
+ u16 zone_lock_inactivity_time_limit;
+ u16 reserved4;
+
+ u8 reserved5;
+ u8 first_enclosure_connector_element_index;
+ u8 number_of_enclosure_connector_element_indices;
+ u8 reserved6;
+
+ u32 reserved7:7;
+ u32 reduced_functionality:1;
+ u32 time_to_reduce_functionality:8;
+ u32 initial_time_to_reduce_functionality:8;
+ u8 max_reduced_functionality_time;
+
+ u16 last_self_config_status_descriptor_index;
+ u16 max_number_of_stored_self_config_status_descriptors;
+
+ u16 last_phy_event_list_descriptor_index;
+ u16 max_number_of_stored_phy_event_list_descriptors;
+ } sas2;
+
+};
+
+/**
+ * struct smp_response_report_manufacturer_information - This structure depicts
+ * the SMP report manufacturer information for expander devices. It adheres
+ * to the SAS-2.1 specification.
+ *
+ * For specific information on each of these individual fields please reference
+ * the SAS specification Application layer section on SMP.
+ */
+struct smp_response_report_manufacturer_information {
+ u32 expander_change_count:16; /* bytes 4-5 */
+ u32 reserved1:16;
+
+ u32 sas1_1_format:1;
+ u32 reserved2:31;
+
+ u8 vendor_id[8];
+ u8 product_id[16];
+ u8 product_revision_level[4];
+ u8 component_vendor_id[8];
+ u8 component_id[2];
+ u8 component_revision_level;
+ u8 reserved3;
+ u8 vendor_specific[8];
+
+};
+
+#define SMP_RESPONSE_DISCOVER_FORMAT_1_1_SIZE 52
+#define SMP_RESPONSE_DISCOVER_FORMAT_2_SIZE 116
+
+/**
+ * struct smp_discover_response_protocols - This structure depicts the discover
+ * response where the supported protocols by the remote phy are specified.
+ *
+ * For specific information on each of these individual fields please reference
+ * the SAS specification Link layer section on address frames.
+ */
+struct smp_discover_response_protocols {
+ union {
+ struct {
+ u16 attached_sata_host:1;
+ u16 attached_smp_initiator:1;
+ u16 attached_stp_initiator:1;
+ u16 attached_ssp_initiator:1;
+ u16 reserved3:4;
+ u16 attached_sata_device:1;
+ u16 attached_smp_target:1;
+ u16 attached_stp_target:1;
+ u16 attached_ssp_target:1;
+ u16 reserved4:3;
+ u16 attached_sata_port_selector:1;
+ } bits;
+
+ u16 all;
+ } u;
+
+};
+
+/**
+ * struct SMP_RESPONSE_DISCOVER_FORMAT - This structure defines the SMP phy
+ * discover response format. It handles both SAS1.1 and SAS 2 definitions.
+ * The unions indicate locations where the SAS specification versions differ
+ * from one another.
+ *
+ *
+ */
+struct smp_response_discover {
+
+ union {
+ struct {
+ u8 reserved[2];
+ } sas1_1;
+
+ struct {
+ u16 expander_change_count;
+ } sas2;
+
+ } u1;
+
+ u8 reserved1[3];
+ u8 phy_identifier;
+ u8 reserved2[2];
+
+ union {
+ struct {
+ u16 reserved1:4;
+ u16 attached_device_type:3;
+ u16 reserved2:1;
+ u16 negotiated_physical_link_rate:4;
+ u16 reserved3:4;
+ } sas1_1;
+
+ struct {
+ u16 attached_reason:4;
+ u16 attached_device_type:3;
+ u16 reserved2:1;
+ u16 negotiated_logical_link_rate:4;
+ u16 reserved3:4;
+ } sas2;
+
+ } u2;
+
+ struct smp_discover_response_protocols protocols;
+ struct sci_sas_address sas_address;
+ struct sci_sas_address attached_sas_address;
+
+ u8 attached_phy_identifier;
+
+ union {
+ struct {
+ u8 reserved;
+ } sas1_1;
+
+ struct {
+ u8 attached_break_reply_capable:1;
+ u8 attached_requested_inside_zpsds:1;
+ u8 attached_inside_zpsds_persistent:1;
+ u8 reserved1:5;
+ } sas2;
+
+ } u3;
+
+ u8 reserved_for_identify[6];
+
+ u32 hardware_min_physical_link_rate:4;
+ u32 programmed_min_physical_link_rate:4;
+ u32 hardware_max_physical_link_rate:4;
+ u32 programmed_max_physical_link_rate:4;
+ u32 phy_change_count:8;
+ u32 partial_pathway_timeout_value:4;
+ u32 reserved5:3;
+ u32 virtual_phy:1;
+
+ u32 routing_attribute:4;
+ u32 reserved6:4;
+ u32 connector_type:7;
+ u32 reserved7:1;
+ u32 connector_element_index:8;
+ u32 connector_physical_link:8;
+
+ u16 reserved8;
+ u16 vendor_specific;
+
+ union {
+ struct {
+ /**
+ * In the SAS 1.1 specification this structure ends after 52 bytes.
+ * As a result, the contents of this field should never have a
+ * real value. It is undefined.
+ */
+ u8 undefined[SMP_RESPONSE_DISCOVER_FORMAT_2_SIZE
+ - SMP_RESPONSE_DISCOVER_FORMAT_1_1_SIZE];
+ } sas1_1;
+
+ struct {
+ struct sci_sas_address attached_device_name;
+
+ u32 zoning_enabled:1;
+ u32 inside_zpsds:1;
+ u32 zone_group_persistent:1;
+ u32 reserved1:1;
+ u32 requested_inside_zpsds:1;
+ u32 inside_zpsds_persistent:1;
+ u32 requested_inside_zpsds_changed_by_expander:1;
+ u32 reserved2:1;
+ u32 reserved_for_zoning_fields:16;
+ u32 zone_group:8;
+
+ u8 self_configuration_status;
+ u8 self_configuration_levels_completed;
+ u16 reserved_for_self_config_fields;
+
+ struct sci_sas_address self_configuration_sas_address;
+
+ u32 programmed_phy_capabilities;
+ u32 current_phy_capabilities;
+ u32 attached_phy_capabilities;
+
+ u32 reserved3;
+
+ u32 reserved4:16;
+ u32 negotiated_physical_link_rate:4;
+ u32 reason:4;
+ u32 hardware_muxing_supported:1;
+ u32 negotiated_ssc:1;
+ u32 reserved5:6;
+
+ u32 default_zoning_enabled:1;
+ u32 reserved6:1;
+ u32 default_zone_group_persistent:1;
+ u32 reserved7:1;
+ u32 default_requested_inside_zpsds:1;
+ u32 default_inside_zpsds_persistent:1;
+ u32 reserved8:2;
+ u32 reserved9:16;
+ u32 default_zone_group:8;
+
+ u32 saved_zoning_enabled:1;
+ u32 reserved10:1;
+ u32 saved_zone_group_persistent:1;
+ u32 reserved11:1;
+ u32 saved_requested_inside_zpsds:1;
+ u32 saved_inside_zpsds_persistent:1;
+ u32 reserved12:18;
+ u32 saved_zone_group:8;
+
+ u32 reserved14:2;
+ u32 shadow_zone_group_persistent:1;
+ u32 reserved15:1;
+ u32 shadow_requested_inside_zpsds:1;
+ u32 shadow_inside_zpsds_persistent:1;
+ u32 reserved16:18;
+ u32 shadow_zone_group:8;
+
+ u8 device_slot_number;
+ u8 device_slot_group_number;
+ u8 device_slot_group_output_connector[6];
+ } sas2;
+
+ } u4;
+
+};
+
+/**
+ * struct smp_response_report_phy_sata - This structure depicts the contents of
+ * the SAS SMP REPORT PHY SATA frame. For specific information on each of
+ * these individual fields please reference the SAS specification Link layer
+ * section on address frames.
+ *
+ *
+ */
+struct smp_response_report_phy_sata {
+ u32 ignored_byte_4_7; /* bytes 4-7 */
+
+ u32 affiliations_valid:1;
+ u32 affiliations_supported:1;
+ u32 reserved_byte11:6; /* byte 11 */
+ u32 ignored_byte10:8; /* byte 10 */
+ u32 phy_identifier:8; /* byte 9 */
+ u32 reserved_byte_8:8; /* byte 8 */
+
+ u32 reserved_12_15;
+ u32 stp_sas_address[2];
+ u8 device_to_host_fis[20];
+ u32 reserved_44_47;
+ u32 affiliated_stp_initiator_sas_address[2];
+
+};
+
+struct smp_response_vendor_specific {
+ u8 response_bytes[SMP_REQUEST_VENDOR_SPECIFIC_MAX_LENGTH];
+};
+
+union smp_response_body {
+ struct smp_response_report_general report_general;
+ struct smp_response_report_manufacturer_information report_manufacturer_information;
+ struct smp_response_discover discover;
+ struct smp_response_report_phy_sata report_phy_sata;
+ struct smp_response_vendor_specific vendor_specific_response;
+};
+
+/**
+ * struct smp_response - This structure simply unionizes the existing response
+ * structures into a common response type.
+ *
+ *
+ */
+struct smp_response {
+ struct smp_response_header header;
+
+ union smp_response_body response;
+
+};
+
+/* SMP Request Functions */
+#define SMP_FUNCTION_REPORT_GENERAL 0x00
+#define SMP_FUNCTION_REPORT_MANUFACTURER_INFORMATION 0x01
+#define SMP_FUNCTION_DISCOVER 0x10
+#define SMP_FUNCTION_REPORT_PHY_ERROR_LOG 0x11
+#define SMP_FUNCTION_REPORT_PHY_SATA 0x12
+#define SMP_FUNCTION_REPORT_ROUTE_INFORMATION 0X13
+#define SMP_FUNCTION_CONFIGURE_ROUTE_INFORMATION 0X90
+#define SMP_FUNCTION_PHY_CONTROL 0x91
+#define SMP_FUNCTION_PHY_TEST 0x92
+
+#define SMP_FRAME_TYPE_REQUEST 0x40
+#define SMP_FRAME_TYPE_RESPONSE 0x41
+
+#define PHY_OPERATION_NOP 0x00
+#define PHY_OPERATION_LINK_RESET 0x01
+#define PHY_OPERATION_HARD_RESET 0x02
+#define PHY_OPERATION_DISABLE 0x03
+#define PHY_OPERATION_CLEAR_ERROR_LOG 0x05
+#define PHY_OPERATION_CLEAR_AFFILIATION 0x06
+
+#define NPLR_PHY_ENABLED_UNK_LINK_RATE 0x00
+#define NPLR_PHY_DISABLED 0x01
+#define NPLR_PHY_ENABLED_SPD_NEG_FAILED 0x02
+#define NPLR_PHY_ENABLED_SATA_HOLD 0x03
+#define NPLR_PHY_ENABLED_1_5G 0x08
+#define NPLR_PHY_ENABLED_3_0G 0x09
+
+/* SMP Function Result values. */
+#define SMP_RESULT_FUNCTION_ACCEPTED 0x00
+#define SMP_RESULT_UNKNOWN_FUNCTION 0x01
+#define SMP_RESULT_FUNCTION_FAILED 0x02
+#define SMP_RESULT_INVALID_REQUEST_FRAME_LEN 0x03
+#define SMP_RESULT_INAVALID_EXPANDER_CHANGE_COUNT 0x04
+#define SMP_RESULT_BUSY 0x05
+#define SMP_RESULT_INCOMPLETE_DESCRIPTOR_LIST 0x06
+#define SMP_RESULT_PHY_DOES_NOT_EXIST 0x10
+#define SMP_RESULT_INDEX_DOES_NOT_EXIST 0x11
+#define SMP_RESULT_PHY_DOES_NOT_SUPPORT_SATA 0x12
+#define SMP_RESULT_UNKNOWN_PHY_OPERATION 0x13
+#define SMP_RESULT_UNKNOWN_PHY_TEST_FUNCTION 0x14
+#define SMP_RESULT_PHY_TEST_IN_PROGRESS 0x15
+#define SMP_RESULT_PHY_VACANT 0x16
+
+/* Attached Device Types */
+#define SMP_NO_DEVICE_ATTACHED 0
+#define SMP_END_DEVICE_ONLY 1
+#define SMP_EDGE_EXPANDER_DEVICE 2
+#define SMP_FANOUT_EXPANDER_DEVICE 3
+
+/* Expander phy routine attribute */
+#define DIRECT_ROUTING_ATTRIBUTE 0
+#define SUBTRACTIVE_ROUTING_ATTRIBUTE 1
+#define TABLE_ROUTING_ATTRIBUTE 2
+
+#endif /* _INTEL_SAS_H_ */
+
diff --git a/drivers/scsi/isci/core/intel_sat.h b/drivers/scsi/isci/core/intel_sat.h
new file mode 100644
index 000000000000..c4d78ed35cf1
--- /dev/null
+++ b/drivers/scsi/isci/core/intel_sat.h
@@ -0,0 +1,95 @@
+/*
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Intel Corporation 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
+ * OWNER 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.
+ */
+
+#ifndef _SAT_H_
+#define _SAT_H_
+
+/**
+ * This file contains constants and constructs defined in the SCSI to ATA
+ * Translation (SAT) T10 standard. For more information please refer to
+ * www.t10.org.
+ *
+ *
+ */
+
+/**
+ *
+ *
+ * SAT_PROTOCOLS These constants indicate the various protocol values that can
+ * be supported in a SAT translator.
+ */
+#define SAT_PROTOCOL_ATA_HARD_RESET 0
+#define SAT_PROTOCOL_SOFT_RESET 1
+#define SAT_PROTOCOL_NON_DATA 3
+#define SAT_PROTOCOL_PIO_DATA_IN 4
+#define SAT_PROTOCOL_PIO_DATA_OUT 5
+#define SAT_PROTOCOL_DMA 6
+#define SAT_PROTOCOL_DMA_QUEUED 7
+#define SAT_PROTOCOL_DEVICE_DIAGNOSTIC 8
+#define SAT_PROTOCOL_DEVICE_RESET 9
+#define SAT_PROTOCOL_UDMA_DATA_IN 10
+#define SAT_PROTOCOL_UDMA_DATA_OUT 11
+#define SAT_PROTOCOL_FPDMA 12
+#define SAT_PROTOCOL_RETURN_RESPONSE_INFO 15
+
+#define SAT_PROTOCOL_PACKET 0x10
+#define SAT_PROTOCOL_PACKET_NON_DATA (SAT_PROTOCOL_PACKET | 0x0)
+#define SAT_PROTOCOL_PACKET_DMA_DATA_IN (SAT_PROTOCOL_PACKET | 0x1)
+#define SAT_PROTOCOL_PACKET_DMA_DATA_OUT (SAT_PROTOCOL_PACKET | 0x2)
+#define SAT_PROTOCOL_PACKET_PIO_DATA_IN (SAT_PROTOCOL_PACKET | 0x3)
+#define SAT_PROTOCOL_PACKET_PIO_DATA_OUT (SAT_PROTOCOL_PACKET | 0x4)
+
+#endif /* _SAT_H_ */
+
diff --git a/drivers/scsi/isci/core/intel_sata.h b/drivers/scsi/isci/core/intel_sata.h
new file mode 100644
index 000000000000..47390d54064d
--- /dev/null
+++ b/drivers/scsi/isci/core/intel_sata.h
@@ -0,0 +1,280 @@
+/*
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Intel Corporation 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
+ * OWNER 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.
+ */
+
+#ifndef _SATA_H_
+#define _SATA_H_
+
+#include <linux/types.h>
+
+/**
+ * This file defines all of the SATA releated constants, enumerations, and
+ * types. Please note that this file does not necessarily contain an
+ * exhaustive list of all contants and commands.
+ *
+ *
+ */
+
+/**
+ *
+ *
+ * SATA FIS Types These constants depict the various SATA FIS types devined in
+ * the serial ATA specification.
+ */
+#define SATA_FIS_TYPE_REGH2D 0x27
+#define SATA_FIS_TYPE_REGD2H 0x34
+#define SATA_FIS_TYPE_SETDEVBITS 0xA1
+#define SATA_FIS_TYPE_DMA_ACTIVATE 0x39
+#define SATA_FIS_TYPE_DMA_SETUP 0x41
+#define SATA_FIS_TYPE_BIST_ACTIVATE 0x58
+#define SATA_FIS_TYPE_PIO_SETUP 0x5F
+#define SATA_FIS_TYPE_DATA 0x46
+
+#define SATA_REGISTER_FIS_SIZE 0x20
+
+/**
+ * struct sata_fis_header - This is the common definition for a SATA FIS Header
+ * word. A different header word is defined for any FIS type that does not
+ * use the standard header.
+ *
+ *
+ */
+struct sata_fis_header {
+ u32 fis_type:8; /* word 0 */
+ u32 pm_port:4;
+ u32 reserved:1;
+ u32 direction_flag:1; /* direction */
+ u32 interrupt_flag:1;
+ u32 command_flag:1; /* command, auto_activate, or notification */
+ u32 status:8;
+ u32 error:8;
+};
+
+
+/**
+ * struct sata_fis_reg_h2d - This is the definition for a SATA Host to Device
+ * Register FIS.
+ *
+ *
+ */
+struct sata_fis_reg_h2d {
+ u32 fis_type:8; /* word 0 */
+ u32 pm_port:4;
+ u32 reserved0:3;
+ u32 command_flag:1;
+ u32 command:8;
+ u32 features:8;
+ u32 lba_low:8; /* word 1 */
+ u32 lba_mid:8;
+ u32 lba_high:8;
+ u32 device:8;
+ u32 lba_low_exp:8; /* word 2 */
+ u32 lba_mid_exp:8;
+ u32 lba_high_exp:8;
+ u32 features_exp:8;
+ u32 sector_count:8; /* word 3 */
+ u32 sector_count_exp:8;
+ u32 reserved1:8;
+ u32 control:8;
+ u32 reserved2; /* word 4 */
+};
+
+/**
+ * struct sata_fis_reg_d2h - SATA Device To Host FIS
+ *
+ *
+ */
+struct sata_fis_reg_d2h {
+ u32 fis_type:8; /* word 0 */
+ u32 pm_port:4;
+ u32 reserved0:2;
+ u32 irq:1;
+ u32 reserved1:1;
+ u32 status:8;
+ u32 error:8;
+ u8 lba_low; /* word 1 */
+ u8 lba_mid;
+ u8 lba_high;
+ u8 device;
+ u8 lba_low_exp; /* word 2 */
+ u8 lba_mid_exp;
+ u8 lba_high_exp;
+ u8 reserved;
+ u8 sector_count; /* word 3 */
+ u8 sector_count_exp;
+ u16 reserved2;
+ u32 reserved3;
+};
+
+/**
+ *
+ *
+ * Status field bit definitions
+ */
+#define SATA_FIS_STATUS_DEVBITS_MASK (0x77)
+
+/**
+ * struct sata_fis_set_dev_bits - SATA Set Device Bits FIS
+ *
+ *
+ */
+struct sata_fis_set_dev_bits {
+ u32 fis_type:8; /* word 0 */
+ u32 pm_port:4;
+ u32 reserved0:2;
+ u32 irq:1;
+ u32 notification:1;
+ u32 status_low:4;
+ u32 status_high:4;
+ u32 error:8;
+ u32 s_active; /* word 1 */
+};
+
+/**
+ * struct sata_fis_dma_activate - SATA DMA Activate FIS
+ *
+ *
+ */
+struct sata_fis_dma_activate {
+ u32 fis_type:8; /* word 0 */
+ u32 pm_port:4;
+ u32 reserved0:24;
+};
+
+/**
+ *
+ *
+ * The lower 5 bits in the DMA Buffer ID Low field of the DMA Setup are used to
+ * communicate the command tag.
+ */
+#define SATA_DMA_SETUP_TAG_ENABLE 0x1F
+
+#define SATA_DMA_SETUP_AUTO_ACT_ENABLE 0x80
+
+/**
+ * struct sata_fis_dma_setup - SATA DMA Setup FIS
+ *
+ *
+ */
+struct sata_fis_dma_setup {
+ u32 fis_type:8; /* word 0 */
+ u32 pm_port:4;
+ u32 reserved_00:1;
+ u32 direction:1;
+ u32 irq:1;
+ u32 auto_activate:1;
+ u32 reserved_01:16;
+ u32 dma_buffer_id_low; /* word 1 */
+ u32 dma_buffer_id_high; /* word 2 */
+ u32 reserved0; /* word 3 */
+ u32 dma_buffer_offset; /* word 4 */
+ u32 dma_transfer_count; /* word 5 */
+ u32 reserved1; /* word 6 */
+};
+
+/**
+ * struct sata_fis_bist_activate - SATA BIST Activate FIS
+ *
+ *
+ */
+struct sata_fis_bist_activate {
+ u32 fis_type:8; /* word 0 */
+ u32 reserved0:8;
+ u32 pattern_definition:8;
+ u32 reserved1:8;
+ u32 data1; /* word 1 */
+ u32 data2; /* word 1 */
+};
+
+/*
+ * SATA PIO Setup FIS
+ */
+struct sata_fis_pio_setup {
+ u32 fis_type:8; /* word 0 */
+ u32 pm_port:4;
+ u32 reserved_00:1;
+ u32 direction:1;
+ u32 irq:1;
+ u32 reserved_01:1;
+ u32 status:8;
+ u32 error:8;
+ u32 lba_low:8; /* word 1 */
+ u32 lba_mid:8;
+ u32 lba_high:8;
+ u32 device:8;
+ u32 lba_low_exp:8; /* word 2 */
+ u32 lba_mid_exp:8;
+ u32 lba_high_exp:8;
+ u32 reserved:8;
+ u32 sector_count:8; /* word 3 */
+ u32 sector_count_exp:8;
+ u32 reserved1:8;
+ u32 ending_status:8;
+ u32 transfter_count:16; /* word 4 */
+ u32 reserved3:16;
+};
+
+/**
+ * struct sata_fis_data - SATA Data FIS
+ *
+ *
+ */
+struct sata_fis_data {
+ u32 fis_type:8; /* word 0 */
+ u32 pm_port:4;
+ u32 reserved0:24;
+ u8 data[4]; /* word 1 */
+};
+
+#endif /* _SATA_H_ */
diff --git a/drivers/scsi/isci/core/intel_scsi.h b/drivers/scsi/isci/core/intel_scsi.h
new file mode 100644
index 000000000000..1e45d3c98127
--- /dev/null
+++ b/drivers/scsi/isci/core/intel_scsi.h
@@ -0,0 +1,474 @@
+/*
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Intel Corporation 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
+ * OWNER 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.
+ */
+
+/**
+ * This file defines all of the SCSI related constants, enumerations, and
+ * types. Please note that this file does not necessarily contain an
+ * exhaustive list of all constants, commands, sub-commands, etc.
+ *
+ *
+ */
+
+#ifndef _SCSI_H__
+#define _SCSI_H__
+
+
+/*
+ * ******************************************************************************
+ * * C O N S T A N T S A N D M A C R O S
+ * ****************************************************************************** */
+
+/**
+ * enum _SCSI_TASK_MGMT_REQUEST_CODES - This enumberation contains the
+ * constants to be used for SCSI task management request codes. SAM does
+ * not specify any particular values for these codes so constants used here
+ * are the same as those specified in SAS.
+ *
+ *
+ */
+enum scsi_task_mgmt_request_codes {
+ SCSI_TASK_REQUEST_ABORT_TASK = 0x01,
+ SCSI_TASK_REQUEST_ABORT_TASK_SET = 0x02,
+ SCSI_TASK_REQUEST_CLEAR_TASK_SET = 0x04,
+ SCSI_TASK_REQUEST_LOGICAL_UNIT_RESET = 0x08,
+ SCSI_TASK_REQUEST_I_T_NEXUS_RESET = 0x10,
+ SCSI_TASK_REQUEST_CLEAR_ACA = 0x40,
+ SCSI_TASK_REQUEST_QUERY_TASK = 0x80,
+ SCSI_TASK_REQUEST_QUERY_TASK_SET = 0x81,
+ SCSI_TASK_REQUEST_QUERY_UNIT_ATTENTION = 0x82,
+
+};
+
+/**
+ * enum _SCSI_TASK_MGMT_RESPONSE_CODES - This enumeration contains all of the
+ * SCSI task management response codes.
+ *
+ *
+ */
+enum scsi_task_mgmt_response_codes {
+ SCSI_TASK_MGMT_FUNC_COMPLETE = 0,
+ SCSI_INVALID_FRAME = 2,
+ SCSI_TASK_MGMT_FUNC_NOT_SUPPORTED = 4,
+ SCSI_TASK_MGMT_FUNC_FAILED = 5,
+ SCSI_TASK_MGMT_FUNC_SUCCEEDED = 8,
+ SCSI_INVALID_LUN = 9
+};
+
+/**
+ * enum _SCSI_SENSE_RESPONSE_CODE - this enumeration depicts the types of sense
+ * data responses as per SPC-3.
+ *
+ *
+ */
+enum scsi_sense_response_code {
+ SCSI_FIXED_CURRENT_RESPONSE_CODE = 0x70,
+ SCSI_FIXED_DEFERRED_RESPONSE_CODE = 0x71,
+ SCSI_DESCRIPTOR_CURRENT_RESPONSE_CODE = 0x72,
+ SCSI_DESCRIPTOR_DEFERRED_RESPONSE_CODE = 0x73
+
+};
+
+/*
+ * This constant represents the valid bit located in byte 0 of a FIXED
+ * format sense data. */
+#define SCSI_FIXED_SENSE_DATA_VALID_BIT 0x80
+
+#define SCSI_FIXED_SENSE_DATA_BASE_LENGTH 18
+
+/* This value is used in the DATAPRES field of the SCSI Response IU. */
+#define SCSI_RESPONSE_DATA_PRES_SENSE_DATA 0x02
+
+/**
+ *
+ *
+ * SCSI_SENSE_KEYS These constants delineate all of the SCSI protocol sense key
+ * constants
+ */
+#define SCSI_SENSE_NO_SENSE 0x00
+#define SCSI_SENSE_RECOVERED_ERROR 0x01
+#define SCSI_SENSE_NOT_READY 0x02
+#define SCSI_SENSE_MEDIUM_ERROR 0x03
+#define SCSI_SENSE_HARDWARE_ERROR 0x04
+#define SCSI_SENSE_ILLEGAL_REQUEST 0x05
+#define SCSI_SENSE_UNIT_ATTENTION 0x06
+#define SCSI_SENSE_DATA_PROTECT 0x07
+#define SCSI_SENSE_BLANK_CHECK 0x08
+#define SCSI_SENSE_VENDOR_SPECIFIC 0x09
+#define SCSI_SENSE_COPY_ABORTED 0x0A
+#define SCSI_SENSE_ABORTED_COMMAND 0x0B
+#define SCSI_SENSE_VOLUME_OVERFLOW 0x0D
+#define SCSI_SENSE_MISCOMPARE 0x0E
+
+/**
+ *
+ *
+ * SCSI_ADDITIONAL_SENSE_CODES These constants delineate all of the SCSI
+ * protocol additional sense code constants.
+ */
+#define SCSI_ASC_NO_ADDITIONAL_SENSE 0x00
+#define SCSI_ASC_INITIALIZING_COMMAND_REQUIRED 0x04
+#define SCSI_ASC_LUN_SELF_TEST_IN_PROGRESS 0x04
+#define SCSI_ASC_LUN_FORMAT_IN_PROGRESS 0x04
+#define SCSI_ASC_LUN_NOT_RESPOND_TO_SELECTION 0x05
+#define SCSI_ASC_UNRECOVERED_READ_ERROR 0x11
+#define SCSI_ASC_INVALID_COMMAND_OPERATION_CODE 0x20
+#define SCSI_ASC_LBA_OUT_OF_RANGE 0x21
+#define SCSI_ASC_INVALID_FIELD_IN_CDB 0x24
+#define SCSI_ASC_INVALID_FIELD_IN_PARM_LIST 0x26
+#define SCSI_ASC_WRITE_PROTECTED 0x27
+#define SCSI_ASC_NOT_READY_TO_READY_CHANGE 0x28
+#define SCSI_ASC_SAVING_PARMS_NOT_SUPPORTED 0x39
+#define SCSI_ASC_MEDIUM_NOT_PRESENT 0x3A
+#define SCSI_ASC_INTERNAL_TARGET_FAILURE 0x44
+#define SCSI_ASC_IU_CRC_ERROR_DETECTED 0x47
+#define SCSI_ASC_MEDIUM_REMOVAL_REQUEST 0x5A
+#define SCSI_ASC_COMMAND_SEQUENCE_ERROR 0x2C
+#define SCSI_ASC_MEDIA_LOAD_OR_EJECT_FAILED 0x53
+#define SCSI_ASC_HARDWARE_IMPENDING_FAILURE 0x5D
+#define SCSI_ASC_POWER_STATE_CHANGE 0x5E
+#define SCSI_DIAGNOSTIC_FAILURE_ON_COMPONENT 0x40
+#define SCSI_ASC_ATA_DEVICE_FEATURE_NOT_ENABLED 0x67
+
+/**
+ *
+ *
+ * SCSI_ADDITIONAL_SENSE_CODE_QUALIFIERS This enumeration contains all of the
+ * used SCSI protocol additional sense code qualifier constants.
+ */
+#define SCSI_ASCQ_NO_ADDITIONAL_SENSE 0x00
+#define SCSI_ASCQ_INVALID_FIELD_IN_CDB 0x00
+#define SCSI_ASCQ_INVALID_FIELD_IN_PARM_LIST 0x00
+#define SCSI_ASCQ_LUN_NOT_RESPOND_TO_SELECTION 0x00
+#define SCSI_ASCQ_INTERNAL_TARGET_FAILURE 0x00
+#define SCSI_ASCQ_LBA_OUT_OF_RANGE 0x00
+#define SCSI_ASCQ_MEDIUM_NOT_PRESENT 0x00
+#define SCSI_ASCQ_NOT_READY_TO_READY_CHANGE 0x00
+#define SCSI_ASCQ_WRITE_PROTECTED 0x00
+#define SCSI_ASCQ_UNRECOVERED_READ_ERROR 0x00
+#define SCSI_ASCQ_SAVING_PARMS_NOT_SUPPORTED 0x00
+#define SCSI_ASCQ_INVALID_COMMAND_OPERATION_CODE 0x00
+#define SCSI_ASCQ_MEDIUM_REMOVAL_REQUEST 0x01
+#define SCSI_ASCQ_INITIALIZING_COMMAND_REQUIRED 0x02
+#define SCSI_ASCQ_IU_CRC_ERROR_DETECTED 0x03
+#define SCSI_ASCQ_LUN_FORMAT_IN_PROGRESS 0x04
+#define SCSI_ASCQ_LUN_SELF_TEST_IN_PROGRESS 0x09
+#define SCSI_ASCQ_GENERAL_HARD_DRIVE_FAILURE 0x10
+#define SCSI_ASCQ_IDLE_CONDITION_ACTIVATE_BY_COMMAND 0x03
+#define SCSI_ASCQ_STANDBY_CONDITION_ACTIVATE_BY_COMMAND 0x04
+#define SCSI_ASCQ_POWER_STATE_CHANGE_TO_IDLE 0x42
+#define SCSI_ASCQ_POWER_STATE_CHANGE_TO_STANDBY 0x43
+#define SCSI_ASCQ_ATA_DEVICE_FEATURE_NOT_ENABLED 0x0B
+#define SCSI_ASCQ_UNRECOVERED_READ_ERROR_AUTO_REALLOCATE_FAIL 0x04
+
+
+
+/**
+ *
+ *
+ * SCSI_STATUS_CODES These constants define all of the used SCSI status values.
+ */
+#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_TASKFULL 0x28
+#define SCSI_STATUS_ACA 0x30
+#define SCSI_STATUS_ABORT 0x40
+
+/**
+ *
+ *
+ * SCSI_OPERATION_CODES These constants delineate all of the SCSI
+ * command/operation codes.
+ */
+#define SCSI_INQUIRY 0x12
+#define SCSI_READ_CAPACITY_10 0x25
+#define SCSI_SERVICE_ACTION_IN_16 0x9E
+#define SCSI_TEST_UNIT_READY 0x00
+#define SCSI_START_STOP_UNIT 0x1B
+#define SCSI_SYNCHRONIZE_CACHE_10 0x35
+#define SCSI_SYNCHRONIZE_CACHE_16 0x91
+#define SCSI_REQUEST_SENSE 0x03
+#define SCSI_REPORT_LUNS 0xA0
+#define SCSI_REASSIGN_BLOCKS 0x07
+#define SCSI_READ_6 0x08
+#define SCSI_READ_10 0x28
+#define SCSI_READ_12 0xA8
+#define SCSI_READ_16 0x88
+#define SCSI_WRITE_6 0x0A
+#define SCSI_WRITE_10 0x2A
+#define SCSI_WRITE_12 0xAA
+#define SCSI_WRITE_16 0x8A
+#define SCSI_VERIFY_10 0x2F
+#define SCSI_VERIFY_12 0xAF
+#define SCSI_VERIFY_16 0x8F
+#define SCSI_SEEK_6 0x01
+#define SCSI_SEEK_10 0x02
+#define SCSI_WRITE_VERIFY 0x2E
+#define SCSI_FORMAT_UNIT 0x04
+#define SCSI_READ_BUFFER 0x3C
+#define SCSI_WRITE_BUFFER 0x3B
+#define SCSI_SEND_DIAGNOSTIC 0x1D
+#define SCSI_RECEIVE_DIAGNOSTIC 0x1C
+#define SCSI_MODE_SENSE_6 0x1A
+#define SCSI_MODE_SENSE_10 0x5A
+#define SCSI_MODE_SELECT_6 0x15
+#define SCSI_MODE_SELECT_10 0x55
+#define SCSI_MAINTENANCE_IN 0xA3
+#define SCSI_LOG_SENSE 0x4D
+#define SCSI_LOG_SELECT 0x4C
+#define SCSI_RESERVE_6 0x16
+#define SCSI_RESERVE_10 0x56
+#define SCSI_RELEASE_6 0x17
+#define SCSI_RELEASE_10 0x57
+#define SCSI_ATA_PASSTHRU_12 0xA1
+#define SCSI_ATA_PASSTHRU_16 0x85
+#define SCSI_WRITE_LONG_10 0x3F
+#define SCSI_WRITE_LONG_16 0x9F
+#define SCSI_PERSISTENT_RESERVE_IN 0x5E
+#define SCSI_PERSISTENT_RESERVE_OUT 0x5F
+
+/**
+ *
+ *
+ * SCSI_SERVICE_ACTION_IN_CODES Service action in operations.
+ */
+#define SCSI_SERVICE_ACTION_IN_CODES_READ_CAPACITY_16 0x10
+
+#define SCSI_SERVICE_ACTION_MASK 0x1f
+
+/**
+ *
+ *
+ * SCSI_MAINTENANCE_IN_SERVICE_ACTION_CODES MAINTENANCE IN service action codes.
+ */
+#define SCSI_REPORT_TASK_MGMT 0x0D
+#define SCSI_REPORT_OP_CODES 0x0C
+
+/**
+ *
+ *
+ * SCSI_MODE_PAGE_CONTROLS These constants delineate all of the used SCSI Mode
+ * Page control values.
+ */
+#define SCSI_MODE_SENSE_PC_CURRENT 0x0
+#define SCSI_MODE_SENSE_PC_CHANGEABLE 0x1
+#define SCSI_MODE_SENSE_PC_DEFAULT 0x2
+#define SCSI_MODE_SENSE_PC_SAVED 0x3
+
+#define SCSI_MODE_SENSE_PC_SHIFT 0x06
+#define SCSI_MODE_SENSE_PAGE_CODE_ENABLE 0x3F
+#define SCSI_MODE_SENSE_DBD_ENABLE 0x08
+#define SCSI_MODE_SENSE_LLBAA_ENABLE 0x10
+
+/**
+ *
+ *
+ * SCSI_MODE_PAGE_CODES These constants delineate all of the used SCSI Mode
+ * Page codes.
+ */
+#define SCSI_MODE_PAGE_READ_WRITE_ERROR 0x01
+#define SCSI_MODE_PAGE_DISCONNECT_RECONNECT 0x02
+#define SCSI_MODE_PAGE_CACHING 0x08
+#define SCSI_MODE_PAGE_CONTROL 0x0A
+#define SCSI_MODE_PAGE_PROTOCOL_SPECIFIC_PORT 0x19
+#define SCSI_MODE_PAGE_POWER_CONDITION 0x1A
+#define SCSI_MODE_PAGE_INFORMATIONAL_EXCP_CONTROL 0x1C
+#define SCSI_MODE_PAGE_ALL_PAGES 0x3F
+
+#define SCSI_MODE_SENSE_ALL_SUB_PAGES_CODE 0xFF
+#define SCSI_MODE_SENSE_NO_SUB_PAGES_CODE 0x0
+#define SCSI_MODE_SENSE_PROTOCOL_PORT_NUM_SUBPAGES 0x1
+#define SCSI_MODE_PAGE_CACHE_PAGE_WCE_BIT 0x04
+#define SCSI_MODE_PAGE_CACHE_PAGE_DRA_BIT 0x20
+#define SCSI_MODE_PAGE_DEXCPT_ENABLE 0x08
+#define SCSI_MODE_SENSE_HEADER_FUA_ENABLE 0x10
+#define SCSI_MODE_PAGE_POWER_CONDITION_STANDBY 0x1
+#define SCSI_MODE_PAGE_POWER_CONDITION_IDLE 0x2
+
+#define SCSI_MODE_SENSE_6_HEADER_LENGTH 4
+#define SCSI_MODE_SENSE_10_HEADER_LENGTH 8
+#define SCSI_MODE_SENSE_STD_BLOCK_DESCRIPTOR_LENGTH 8
+#define SCSI_MODE_SENSE_LLBA_BLOCK_DESCRIPTOR_LENGTH 16
+
+#define SCSI_MODE_PAGE_INFORMATIONAL_EXCP_DXCPT_ENABLE 0x08
+#define SCSI_MODE_PAGE_19_SAS_ID 0x6
+#define SCSI_MODE_PAGE_19_SUB1_PAGE_NUM 0x1
+#define SCSI_MODE_PAGE_19_SUB1_PC 0x59
+
+#define SCSI_MODE_HEADER_MEDIUM_TYPE_SBC 0x00
+
+/* Mode Select constrains related masks value */
+#define SCSI_MODE_SELECT_PF_BIT 0x1
+#define SCSI_MODE_SELECT_PF_MASK 0x10
+#define SCSI_MODE_SELECT_MODE_PAGE_MRIE_BYTE 0x6
+#define SCSI_MODE_SELECT_MODE_PAGE_MRIE_MASK 0x0F
+#define SCSI_MODE_SELECT_MODE_PAGE_SPF_MASK 0x40
+#define SCSI_MODE_SELECT_MODE_PAGE_01_AWRE_MASK 0x80
+#define SCSI_MODE_SELECT_MODE_PAGE_01_ARRE_MASK 0x40
+#define SCSI_MODE_SELECT_MODE_PAGE_01_RC_ERBITS_MASK 0x1F
+#define SCSI_MODE_SELECT_MODE_PAGE_08_FSW_LBCSS_NVDIS 0xC1
+#define SCSI_MODE_SELECT_MODE_PAGE_1C_PERF_TEST 0x84
+#define SCSI_MODE_SELECT_MODE_PAGE_0A_TST_TMF_RLEC 0xF1
+#define SCSI_MODE_SELECT_MODE_PAGE_0A_MODIFIER 0xF0
+#define SCSI_MODE_SELECT_MODE_PAGE_0A_UA_SWP 0x38
+#define SCSI_MODE_SELECT_MODE_PAGE_0A_TAS_AUTO 0x47
+
+
+#define SCSI_CONTROL_BYTE_NACA_BIT_ENABLE 0x04
+#define SCSI_MOVE_FUA_BIT_ENABLE 0x08
+#define SCSI_READ_CAPACITY_PMI_BIT_ENABLE 0x01
+#define SCSI_READ_CAPACITY_10_DATA_LENGTH 8
+#define SCSI_READ_CAPACITY_16_DATA_LENGTH 32
+
+/* Inquiry constants */
+#define SCSI_INQUIRY_EVPD_ENABLE 0x01
+#define SCSI_INQUIRY_PAGE_CODE_OFFSET 0x02
+#define SCSI_INQUIRY_SUPPORTED_PAGES_PAGE 0x00
+#define SCSI_INQUIRY_UNIT_SERIAL_NUM_PAGE 0x80
+#define SCSI_INQUIRY_DEVICE_ID_PAGE 0x83
+#define SCSI_INQUIRY_ATA_INFORMATION_PAGE 0x89
+#define SCSI_INQUIRY_BLOCK_DEVICE_PAGE 0xB1
+#define SCSI_INQUIRY_BLOCK_DEVICE_LENGTH 0x3C
+#define SCSI_INQUIRY_STANDARD_ALLOCATION_LENGTH 0x24 /* 36 */
+
+#define SCSI_REQUEST_SENSE_ALLOCATION_LENGTH 0xFC /* 252 */
+
+/** Defines the log page codes that are use in gathing Smart data
+ */
+#define SCSI_LOG_PAGE_SUPPORTED_PAGES 0x00
+#define SCSI_LOG_PAGE_INFORMATION_EXCEPTION 0x2F
+#define SCSI_LOG_PAGE_SELF_TEST 0x10
+
+/**
+ *
+ *
+ * SCSI_INQUIRY_VPD The following are constants used with vital product data
+ * inquiry pages. Values are already shifted into the proper nibble location.
+ */
+#define SCSI_PIV_ENABLE 0x80
+#define SCSI_LUN_ASSOCIATION 0x00
+#define SCSI_TARGET_PORT_ASSOCIATION 0x10
+
+#define SCSI_VEN_UNIQUE_IDENTIFIER_TYPE 0x00
+#define SCSI_NAA_IDENTIFIER_TYPE 0x03
+
+#define SCSI_T10_IDENTIFIER_TYPE 0x01
+#define SCSI_BINARY_CODE_SET 0x01
+#define SCSI_ASCII_CODE_SET 0x02
+#define SCSI_FC_PROTOCOL_IDENTIFIER 0x00
+#define SCSI_SAS_PROTOCOL_IDENTIFIER 0x60
+
+#define SCSI_VERIFY_BYTCHK_ENABLED 0x02
+
+#define SCSI_SYNCHRONIZE_CACHE_IMMED_ENABLED 0x02
+/**
+ *
+ *
+ * SCSI_START_STOP_UNIT_POWER_CONDITION_CODES The following are SCSI Start Stop
+ * Unit command Power Condition codes.
+ */
+#define SCSI_START_STOP_UNIT_POWER_CONDITION_START_VALID 0x0
+#define SCSI_START_STOP_UNIT_POWER_CONDITION_ACTIVE 0x1
+#define SCSI_START_STOP_UNIT_POWER_CONDITION_IDLE 0x2
+#define SCSI_START_STOP_UNIT_POWER_CONDITION_STANDBY 0x3
+#define SCSI_START_STOP_UNIT_POWER_CONDITION_LU_CONTROL 0x7
+#define SCSI_START_STOP_UNIT_POWER_CONDITION_FORCE_S_CONTROL 0xB
+
+#define SCSI_START_STOP_UNIT_IMMED_MASK 0x1
+#define SCSI_START_STOP_UNIT_IMMED_SHIFT 0
+
+#define SCSI_START_STOP_UNIT_START_BIT_MASK 0x1
+#define SCSI_START_STOP_UNIT_START_BIT_SHIFT 0
+
+#define SCSI_START_STOP_UNIT_LOEJ_BIT_MASK 0x2
+#define SCSI_START_STOP_UNIT_LOEJ_BIT_SHIFT 1
+
+#define SCSI_START_STOP_UNIT_NO_FLUSH_MASK 0x4
+#define SCSI_START_STOP_UNIT_NO_FLUSH_SHIFT 2
+
+#define SCSI_START_STOP_UNIT_POWER_CONDITION_MODIFIER_MASK 0xF
+#define SCSI_START_STOP_UNIT_POWER_CONDITION_MODIFIER_SHIFT 0
+
+#define SCSI_START_STOP_UNIT_POWER_CONDITION_MASK 0xF0
+#define SCSI_START_STOP_UNIT_POWER_CONDITION_SHIFT 4
+
+#define SCSI_LOG_SENSE_PC_FIELD_MASK 0xC0
+#define SCSI_LOG_SENSE_PC_FIELD_SHIFT 6
+
+#define SCSI_LOG_SENSE_PAGE_CODE_FIELD_MASK 0x3F
+#define SCSI_LOG_SENSE_PAGE_CODE_FIELD_SHIFT 0
+
+/**
+ *
+ *
+ * MRIE - Method of reporting informational exceptions codes
+ */
+#define NO_REPORTING_INFO_EXCEPTION_CONDITION 0x0
+#define ASYNCHRONOUS_EVENT_REPORTING 0x1
+#define ESTABLISH_UNIT_ATTENTION_CONDITION 0x2
+#define CONDITIONALLY_GENERATE_RECOVERED_ERROR 0x3
+#define UNCONDITIONALLY_GENERATE_RECOVERED_ERROR 0x4
+#define GENERATE_NO_SENSE 0x5
+#define REPORT_INFO_EXCEPTION_CONDITION_ON_REQUEST 0x6
+
+#define SCSI_INFORMATION_EXCEPTION_DEXCPT_BIT 0x08
+
+/* Reassign Blocks masks */
+#define SCSI_REASSIGN_BLOCKS_LONGLBA_BIT 0x02
+#define SCSI_REASSIGN_BLOCKS_LONGLIST_BIT 0x01
+
+#endif /* _SCSI_H_ */
+
diff --git a/drivers/scsi/isci/core/sati_device.h b/drivers/scsi/isci/core/sati_device.h
new file mode 100644
index 000000000000..4d1cfde12cae
--- /dev/null
+++ b/drivers/scsi/isci/core/sati_device.h
@@ -0,0 +1,156 @@
+/*
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Intel Corporation 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
+ * OWNER 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.
+ */
+
+#ifndef _SATI_DEVICE_H_
+#define _SATI_DEVICE_H_
+
+/**
+ * This file contains all of the defintions for the SATI remote device object.
+ * Some translations require information to be remembered on a per device
+ * basis. This information is stored in the object defined in this file.
+ *
+ *
+ */
+
+#include "sati_types.h"
+#include "intel_ata.h"
+
+/**
+ * enum _SATI_DEVICE_STATE - This enumeration depicts the various states
+ * possible for the a translation remote device object.
+ *
+ *
+ */
+enum sati_device_state {
+ SATI_DEVICE_STATE_OPERATIONAL,
+ SATI_DEVICE_STATE_STOPPED,
+ SATI_DEVICE_STATE_STANDBY,
+ SATI_DEVICE_STATE_IDLE,
+ SATI_DEVICE_STATE_DEVICE_FAULT_OCCURRED,
+ SATI_DEVICE_STATE_FORMAT_UNIT_IN_PROGRESS,
+ SATI_DEVICE_STATE_SELF_TEST_IN_PROGRESS,
+ SATI_DEVICE_STATE_SEQUENCE_INCOMPLETE,
+ SATI_DEVICE_STATE_UNIT_ATTENTION_CONDITION
+
+};
+
+/**
+ *
+ *
+ * SATI_DEVICE_CAPABILITIES These constants define the various capabilities
+ * that a remote device may support for which there is an impact on translation.
+ */
+#define SATI_DEVICE_CAP_UDMA_ENABLE 0x00000001
+#define SATI_DEVICE_CAP_NCQ_REQUESTED_ENABLE 0x00000002
+#define SATI_DEVICE_CAP_NCQ_SUPPORTED_ENABLE 0x00000004
+#define SATI_DEVICE_CAP_48BIT_ENABLE 0x00000008
+#define SATI_DEVICE_CAP_DMA_FUA_ENABLE 0x00000010
+#define SATI_DEVICE_CAP_SMART_SUPPORT 0x00000020
+#define SATI_DEVICE_CAP_REMOVABLE_MEDIA 0x00000040
+#define SATI_DEVICE_CAP_SMART_ENABLE 0x00000080
+#define SATI_DEVICE_CAP_WRITE_UNCORRECTABLE_ENABLE 0x00000100
+#define SATI_DEVICE_CAP_MULTIPLE_SECTORS_PER_PHYSCIAL_SECTOR 0x00000200
+#define SATI_DEVICE_CAP_SMART_SELF_TEST_SUPPORT 0x00000400
+
+
+/**
+ * struct sati_device - The SATI_DEVICE structure define the state of the
+ * remote device with respect to translation.
+ *
+ *
+ */
+struct sati_device {
+ /**
+ * This field simply dictates the state of the SATI device.
+ */
+ enum sati_device_state state;
+
+ /**
+ * This field indicates features supported by the remote device that
+ * impact translation execution.
+ */
+ u16 capabilities;
+
+ /**
+ * This field indicates the depth of the native command queue supported
+ * by the device.
+ */
+ u8 ncq_depth;
+
+ /**
+ * This field stores the additional sense code for a unit attention
+ * condition.
+ */
+ u8 unit_attention_asc;
+
+ /**
+ * This field indicates the additional sense code qualifier for a unit
+ * attention condition.
+ */
+ u8 unit_attention_ascq;
+
+};
+
+void sati_device_construct(
+ struct sati_device *device,
+ bool is_ncq_enabled,
+ u8 max_ncq_depth);
+
+void sati_device_update_capabilities(
+ struct sati_device *device,
+ struct ata_identify_device_data *identify);
+
+#endif /* _SATI_TRANSLATOR_SEQUENCE_H_ */
+
diff --git a/drivers/scsi/isci/core/sati_translator_sequence.h b/drivers/scsi/isci/core/sati_translator_sequence.h
new file mode 100644
index 000000000000..592570d50ebd
--- /dev/null
+++ b/drivers/scsi/isci/core/sati_translator_sequence.h
@@ -0,0 +1,304 @@
+/*
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Intel Corporation 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
+ * OWNER 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.
+ */
+
+#ifndef _SATI_TRANSLATOR_SEQUENCE_H_
+#define _SATI_TRANSLATOR_SEQUENCE_H_
+
+/**
+ * This file contains all of the defintions for the SATI translator sequence.
+ * A translator sequence is simply a defintion for the various sequences of
+ * commands that occur in this translator.
+ *
+ *
+ */
+
+#include "sati_device.h"
+
+/**
+ * enum _SATI_TRANSLATOR_SEQUENCE_TYPE - This enumeration defines the possible
+ * sequence types for the translator.
+ *
+ *
+ */
+enum sati_translator_sequence_type {
+ /* SCSI Primary Command (SPC) sequences. */
+ SATI_SEQUENCE_REPORT_LUNS,
+ SATI_SEQUENCE_TEST_UNIT_READY,
+ SATI_SEQUENCE_INQUIRY_STANDARD,
+ SATI_SEQUENCE_INQUIRY_SUPPORTED_PAGES,
+ SATI_SEQUENCE_INQUIRY_SERIAL_NUMBER,
+ SATI_SEQUENCE_INQUIRY_DEVICE_ID,
+ SATI_SEQUENCE_INQUIRY_BLOCK_DEVICE,
+ SATI_SEQUENCE_MODE_SENSE_6_CACHING,
+ SATI_SEQUENCE_MODE_SENSE_6_INFORMATIONAL_EXCP_CONTROL,
+ SATI_SEQUENCE_MODE_SENSE_6_READ_WRITE_ERROR,
+ SATI_SEQUENCE_MODE_SENSE_6_DISCONNECT_RECONNECT,
+ SATI_SEQUENCE_MODE_SENSE_6_CONTROL,
+ SATI_SEQUENCE_MODE_SENSE_6_ALL_PAGES,
+ SATI_SEQUENCE_MODE_SENSE_10_CACHING,
+ SATI_SEQUENCE_MODE_SENSE_10_INFORMATIONAL_EXCP_CONTROL,
+ SATI_SEQUENCE_MODE_SENSE_10_READ_WRITE_ERROR,
+ SATI_SEQUENCE_MODE_SENSE_10_DISCONNECT_RECONNECT,
+ SATI_SEQUENCE_MODE_SENSE_10_CONTROL,
+ SATI_SEQUENCE_MODE_SENSE_10_ALL_PAGES,
+ SATI_SEQUENCE_MODE_SELECT_MODE_PAGE_CACHING,
+ SATI_SEQUENCE_MODE_SELECT_MODE_POWER_CONDITION,
+ SATI_SEQUENCE_MODE_SELECT_MODE_INFORMATION_EXCEPT_CONTROL,
+
+ /* Log Sense Sequences */
+ SATI_SEQUENCE_LOG_SENSE_SELF_TEST_LOG_PAGE,
+ SATI_SEQUENCE_LOG_SENSE_EXTENDED_SELF_TEST_LOG_PAGE,
+ SATI_SEQUENCE_LOG_SENSE_SUPPORTED_LOG_PAGE,
+ SATI_SEQUENCE_LOG_SENSE_INFO_EXCEPTION_LOG_PAGE,
+
+ /* SCSI Block Command (SBC) sequences. */
+
+ SATI_SEQUENCE_READ_6,
+ SATI_SEQUENCE_READ_10,
+ SATI_SEQUENCE_READ_12,
+ SATI_SEQUENCE_READ_16,
+
+ SATI_SEQUENCE_READ_CAPACITY_10,
+ SATI_SEQUENCE_READ_CAPACITY_16,
+
+ SATI_SEQUENCE_SYNCHRONIZE_CACHE,
+
+ SATI_SEQUENCE_VERIFY_10,
+ SATI_SEQUENCE_VERIFY_12,
+ SATI_SEQUENCE_VERIFY_16,
+
+ SATI_SEQUENCE_WRITE_6,
+ SATI_SEQUENCE_WRITE_10,
+ SATI_SEQUENCE_WRITE_12,
+ SATI_SEQUENCE_WRITE_16,
+
+ SATI_SEQUENCE_START_STOP_UNIT,
+
+ SATI_SEQUENCE_REASSIGN_BLOCKS,
+
+ /* SCSI Task Requests sequences */
+
+ SATI_SEQUENCE_LUN_RESET,
+
+ SATI_SEQUENCE_REQUEST_SENSE_SMART_RETURN_STATUS,
+ SATI_SEQUENCE_REQUEST_SENSE_CHECK_POWER_MODE,
+
+ SATI_SEQUENCE_WRITE_LONG
+
+};
+
+#define SATI_SEQUENCE_TYPE_READ_MIN SATI_SEQUENCE_READ_6
+#define SATI_SEQUENCE_TYPE_READ_MAX SATI_SEQUENCE_READ_16
+
+/**
+ *
+ *
+ * SATI_SEQUENCE_STATES These constants depict the various state values
+ * associated with a translation sequence.
+ */
+#define SATI_SEQUENCE_STATE_INITIAL 0
+#define SATI_SEQUENCE_STATE_TRANSLATE_DATA 1
+#define SATI_SEQUENCE_STATE_AWAIT_RESPONSE 2
+#define SATI_SEQUENCE_STATE_FINAL 3
+#define SATI_SEQUENCE_STATE_INCOMPLETE 4
+
+/**
+ *
+ *
+ * SATI_DATA_DIRECTIONS These constants depict the various types of data
+ * directions for a translation sequence. Data can flow in/out (read/write) or
+ * no data at all.
+ */
+#define SATI_DATA_DIRECTION_NONE 0
+#define SATI_DATA_DIRECTION_IN 1
+#define SATI_DATA_DIRECTION_OUT 2
+
+/**
+ * struct SATI_MODE_SELECT_PROCESSING_STATE - This structure contains all of
+ * the current processing states for processing mode select 6 and 10
+ * commands' parameter fields.
+ *
+ *
+ */
+typedef struct SATI_MODE_SELECT_PROCESSING_STATE {
+ u8 *mode_pages;
+ u32 mode_page_offset;
+ u32 mode_pages_size;
+ u32 size_of_data_processed;
+ u32 total_ata_command_sent;
+ u32 ata_command_sent_for_cmp; /* cmp: current mode page */
+ bool current_mode_page_processed;
+
+} SATI_MODE_SELECT_PROCESSING_STATE_T;
+
+
+enum SATI_REASSIGN_BLOCKS_ATA_COMMAND_STATUS {
+ SATI_REASSIGN_BLOCKS_READY_TO_SEND,
+ SATI_REASSIGN_BLOCKS_COMMAND_FAIL,
+ SATI_REASSIGN_BLOCKS_COMMAND_SUCCESS,
+};
+
+/**
+ * struct sati_reassign_blocks_processing_state - This structure contains all
+ * of the current processing states for processing reassign block command's
+ * parameter fields.
+ *
+ *
+ */
+struct sati_reassign_blocks_processing_state {
+ u32 lba_offset;
+ u32 block_lists_size;
+ u8 lba_size;
+ u32 size_of_data_processed;
+ u32 ata_command_sent_for_current_lba;
+ bool current_lba_processed;
+ enum SATI_REASSIGN_BLOCKS_ATA_COMMAND_STATUS ata_command_status;
+
+};
+
+#define SATI_ATAPI_REQUEST_SENSE_CDB_LENGTH 12
+
+/**
+ * struct sati_atapi_data - The SATI_ATAPI_DATA structure is for sati atapi IO
+ * specific data.
+ *
+ *
+ */
+struct sati_atapi_data {
+ u8 request_sense_cdb[SATI_ATAPI_REQUEST_SENSE_CDB_LENGTH];
+};
+
+/**
+ * struct sati_translator_sequence - This structure contains all of the
+ * translation information associated with a particular request.
+ *
+ *
+ */
+struct sati_translator_sequence {
+ /**
+ * This field contains the sequence type determined by the SATI.
+ */
+ u8 type;
+
+ /**
+ * This field indicates the current state for the sequence.
+ */
+ u8 state;
+
+ /**
+ * This field indicates the data direction (none, read, or write) for
+ * the translated request.
+ */
+ u8 data_direction;
+
+ /**
+ * This field contains the SATA/ATA protocol to be utilized during
+ * the IO transfer.
+ */
+ u8 protocol;
+
+ /**
+ * This field is utilized for sequences requiring data translation.
+ * It specifies the amount of data requested by the caller from the
+ * operation. It's necessary, because at times the user requests less
+ * data than is available. Thus, we need to avoid overrunning the
+ * buffer.
+ */
+ u32 allocation_length;
+
+ /**
+ * This field specifies the amount of data that will actually be
+ * transfered across the wire for this ATA request.
+ */
+ u32 ata_transfer_length;
+
+ /**
+ * This field specifies the amount of data bytes that have been
+ * set in a translation sequence. It will be incremented every time
+ * a data byte has been set by a sati translation.
+ */
+ u16 number_data_bytes_set;
+
+ /**
+ * This field indicates whether or not the sense response has been set
+ * by the translation sequence.
+ */
+ bool is_sense_response_set;
+
+ /**
+ * This field specifies the remote device context for which this
+ * translator sequence is destined.
+ */
+ struct sati_device *device;
+
+ /**
+ * This field is utilized to provide the translator with memory space
+ * required for translations that utilize multiple requests.
+ */
+ union {
+ u32 translated_command;
+ u32 move_sector_count;
+ u32 scratch;
+ struct sati_reassign_blocks_processing_state reassign_blocks_process_state;
+ SATI_MODE_SELECT_PROCESSING_STATE_T process_state;
+ struct sati_atapi_data sati_atapi_data;
+ } command_specific_data;
+
+};
+
+
+
+#endif /* _SATI_TRANSLATOR_SEQUENCE_H_ */
+
diff --git a/drivers/scsi/isci/core/sati_types.h b/drivers/scsi/isci/core/sati_types.h
new file mode 100644
index 000000000000..b6159e06c280
--- /dev/null
+++ b/drivers/scsi/isci/core/sati_types.h
@@ -0,0 +1,145 @@
+/*
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Intel Corporation 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
+ * OWNER 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.
+ */
+
+#ifndef _SATI_TYPES_H_
+#define _SATI_TYPES_H_
+
+/**
+ * This file contains various type definitions to be utilized with SCSI to ATA
+ * Translation Implementation.
+ *
+ *
+ */
+
+/**
+ * enum _SATI_STATUS - This enumeration defines the possible return values from
+ * the SATI translation methods.
+ *
+ *
+ */
+enum sati_status {
+ /**
+ * This indicates that the translation was supported and occurred
+ * without error.
+ */
+ SATI_SUCCESS,
+
+ /**
+ * This indicates that the translation was supported, occurred without
+ * error, and no additional translation is necessary. This is done in
+ * conditions where the SCSI command doesn't require any interaction with
+ * the remote device.
+ */
+ SATI_COMPLETE,
+
+ /**
+ * This indicated everything SATI_COMPLETE does in addition to the response data
+ * not using all the memory allocated by the OS.
+ */
+ SATI_COMPLETE_IO_DONE_EARLY,
+
+ /**
+ * This indicates that translator sequence has finished some specific
+ * command in the sequence, but additional commands are necessary.
+ */
+ SATI_SEQUENCE_INCOMPLETE,
+
+ /**
+ * This indicates a general failure has occurred for which no further
+ * specification information is available.
+ */
+ SATI_FAILURE,
+
+ /**
+ * This indicates that the result of the IO request indicates a
+ * failure. The caller should reference the corresponding response
+ * data for further details.
+ */
+ SATI_FAILURE_CHECK_RESPONSE_DATA,
+
+ /**
+ * This status indicates that the supplied sequence type doesn't map
+ * to an existing definition.
+ */
+ SATI_FAILURE_INVALID_SEQUENCE_TYPE,
+
+ /**
+ * This status indicates that the supplied sequence state doesn't match
+ * the operation being requested by the user.
+ */
+ SATI_FAILURE_INVALID_STATE
+
+};
+
+#if (!defined(DISABLE_SATI_MODE_SENSE) \
+ || !defined(DISABLE_SATI_MODE_SELECT) \
+ || !defined(DISABLE_SATI_REQUEST_SENSE)) \
+
+#if !defined(ENABLE_SATI_MODE_PAGES)
+/**
+ *
+ *
+ * This macro enables the common mode page data structures and code. Currently,
+ * MODE SENSE, MODE SELECT, and REQUEST SENSE all make reference to this common
+ * code. As a result, enable the common mode page code if any of these 3 are
+ * being translated.
+ */
+#define ENABLE_SATI_MODE_PAGES
+#endif /* !defined(ENABLE_SATI_MODE_PAGES) */
+
+#endif /* MODE_SENSE/SELECT/REQUEST_SENSE */
+
+#endif /* _SATI_TYPES_H_ */
+
diff --git a/drivers/scsi/isci/core/sci_base_controller.h b/drivers/scsi/isci/core/sci_base_controller.h
new file mode 100644
index 000000000000..36c53406ea5a
--- /dev/null
+++ b/drivers/scsi/isci/core/sci_base_controller.h
@@ -0,0 +1,306 @@
+/*
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Intel Corporation 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
+ * OWNER 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.
+ */
+
+#ifndef _SCI_BASE_CONTROLLER_H_
+#define _SCI_BASE_CONTROLLER_H_
+
+#include "intel_sas.h"
+#include "sci_controller_constants.h"
+#include "sci_base_state.h"
+#include "sci_base_memory_descriptor_list.h"
+#include "sci_base_state_machine.h"
+#include "sci_object.h"
+
+struct sci_base_memory_descriptor_list;
+
+/**
+ * enum sci_base_controller_states - This enumeration depicts all the states
+ * for the common controller state machine.
+ *
+ *
+ */
+enum sci_base_controller_states {
+ /**
+ * Simply the initial state for the base controller state machine.
+ */
+ SCI_BASE_CONTROLLER_STATE_INITIAL = 0,
+
+ /**
+ * This state indicates that the controller is reset. The memory for
+ * the controller is in it's initial state, but the controller requires
+ * initialization.
+ * This state is entered from the INITIAL state.
+ * This state is entered from the RESETTING state.
+ */
+ SCI_BASE_CONTROLLER_STATE_RESET,
+
+ /**
+ * This state is typically an action state that indicates the controller
+ * is in the process of initialization. In this state no new IO operations
+ * are permitted.
+ * This state is entered from the RESET state.
+ */
+ SCI_BASE_CONTROLLER_STATE_INITIALIZING,
+
+ /**
+ * This state indicates that the controller has been successfully
+ * initialized. In this state no new IO operations are permitted.
+ * This state is entered from the INITIALIZING state.
+ */
+ SCI_BASE_CONTROLLER_STATE_INITIALIZED,
+
+ /**
+ * This state indicates the the controller is in the process of becoming
+ * ready (i.e. starting). In this state no new IO operations are permitted.
+ * This state is entered from the INITIALIZED state.
+ */
+ SCI_BASE_CONTROLLER_STATE_STARTING,
+
+ /**
+ * This state indicates the controller is now ready. Thus, the user
+ * is able to perform IO operations on the controller.
+ * This state is entered from the STARTING state.
+ */
+ SCI_BASE_CONTROLLER_STATE_READY,
+
+ /**
+ * This state is typically an action state that indicates the controller
+ * is in the process of resetting. Thus, the user is unable to perform
+ * IO operations on the controller. A reset is considered destructive in
+ * most cases.
+ * This state is entered from the READY state.
+ * This state is entered from the FAILED state.
+ * This state is entered from the STOPPED state.
+ */
+ SCI_BASE_CONTROLLER_STATE_RESETTING,
+
+ /**
+ * This state indicates that the controller is in the process of stopping.
+ * In this state no new IO operations are permitted, but existing IO
+ * operations are allowed to complete.
+ * This state is entered from the READY state.
+ */
+ SCI_BASE_CONTROLLER_STATE_STOPPING,
+
+ /**
+ * This state indicates that the controller has successfully been stopped.
+ * In this state no new IO operations are permitted.
+ * This state is entered from the STOPPING state.
+ */
+ SCI_BASE_CONTROLLER_STATE_STOPPED,
+
+ /**
+ * This state indicates that the controller could not successfully be
+ * initialized. In this state no new IO operations are permitted.
+ * This state is entered from the INITIALIZING state.
+ * This state is entered from the STARTING state.
+ * This state is entered from the STOPPING state.
+ * This state is entered from the RESETTING state.
+ */
+ SCI_BASE_CONTROLLER_STATE_FAILED,
+
+ SCI_BASE_CONTROLLER_MAX_STATES
+
+};
+
+/**
+ * struct sci_base_controller - The base controller object abstracts the fields
+ * common to all SCI controller objects.
+ *
+ *
+ */
+struct sci_base_controller {
+ /**
+ * The field specifies that the parent object for the base controller
+ * is the base object itself.
+ */
+ struct sci_base_object parent;
+
+ /**
+ * This field points to the memory descriptor list associated with this
+ * controller. The MDL indicates the memory requirements necessary for
+ * this controller object.
+ */
+ struct sci_base_memory_descriptor_list mdl;
+
+ /**
+ * This field contains the information for the base controller state
+ * machine.
+ */
+ struct sci_base_state_machine state_machine;
+};
+
+/* Forward declarations */
+struct sci_base_remote_device;
+struct sci_base_request;
+
+typedef enum sci_status
+(*sci_base_controller_handler_t)(struct sci_base_controller *);
+
+typedef enum sci_status
+(*sci_base_controller_timed_handler_t)(struct sci_base_controller *, u32);
+
+typedef enum sci_status
+(*sci_base_controller_request_handler_t)(struct sci_base_controller *,
+ struct sci_base_remote_device *,
+ struct sci_base_request *);
+
+typedef enum sci_status
+(*sci_base_controller_start_request_handler_t)(struct sci_base_controller *,
+ struct sci_base_remote_device *,
+ struct sci_base_request *, u16);
+
+/**
+ * struct sci_base_controller_state_handler - This structure contains all of
+ * the state handler methods common to base controller state machines.
+ * Handler methods provide the ability to change the behavior for user
+ * requests or transitions depending on the state the machine is in.
+ *
+ *
+ */
+struct sci_base_controller_state_handler {
+ /**
+ * The start_handler specifies the method invoked when a user attempts to
+ * start a controller.
+ */
+ sci_base_controller_timed_handler_t start;
+
+ /**
+ * The stop_handler specifies the method invoked when a user attempts to
+ * stop a controller.
+ */
+ sci_base_controller_timed_handler_t stop;
+
+ /**
+ * The reset_handler specifies the method invoked when a user attempts to
+ * reset a controller.
+ */
+ sci_base_controller_handler_t reset;
+
+ /**
+ * The initialize_handler specifies the method invoked when a user
+ * attempts to initialize a controller.
+ */
+ sci_base_controller_handler_t initialize;
+
+ /**
+ * The start_io_handler specifies the method invoked when a user
+ * attempts to start an IO request for a controller.
+ */
+ sci_base_controller_start_request_handler_t start_io;
+
+ /**
+ * The complete_io_handler specifies the method invoked when a user
+ * attempts to complete an IO request for a controller.
+ */
+ sci_base_controller_request_handler_t complete_io;
+
+ /**
+ * The continue_io_handler specifies the method invoked when a user
+ * attempts to continue an IO request for a controller.
+ */
+ sci_base_controller_request_handler_t continue_io;
+
+ /**
+ * The start_task_handler specifies the method invoked when a user
+ * attempts to start a task management request for a controller.
+ */
+ sci_base_controller_start_request_handler_t start_task;
+
+ /**
+ * The complete_task_handler specifies the method invoked when a user
+ * attempts to complete a task management request for a controller.
+ */
+ sci_base_controller_request_handler_t complete_task;
+
+};
+
+/**
+ * sci_base_controller_construct() - Construct the base controller
+ * @this_controller: This parameter specifies the base controller to be
+ * constructed.
+ * @state_table: This parameter specifies the table of state definitions to be
+ * utilized for the controller state machine.
+ * @mde_array: This parameter specifies the array of memory descriptor entries
+ * to be managed by this list.
+ * @mde_array_length: This parameter specifies the size of the array of entries.
+ * @next_mdl: This parameter specifies a subsequent MDL object to be managed by
+ * this MDL object.
+ * @oem_parameters: This parameter specifies the original equipment
+ * manufacturer parameters to be utilized by this controller object.
+ *
+ */
+static inline void sci_base_controller_construct(
+ struct sci_base_controller *scic_base,
+ const struct sci_base_state *state_table,
+ struct sci_physical_memory_descriptor *mdes,
+ u32 mde_count,
+ struct sci_base_memory_descriptor_list *next_mdl)
+{
+ scic_base->parent.private = NULL;
+
+ sci_base_state_machine_construct(
+ &scic_base->state_machine,
+ &scic_base->parent,
+ state_table,
+ SCI_BASE_CONTROLLER_STATE_INITIAL
+ );
+
+ sci_base_mdl_construct(&scic_base->mdl, mdes, mde_count, next_mdl);
+
+ sci_base_state_machine_start(&scic_base->state_machine);
+}
+
+#endif /* _SCI_BASE_CONTROLLER_H_ */
diff --git a/drivers/scsi/isci/core/sci_base_memory_descriptor_list.c b/drivers/scsi/isci/core/sci_base_memory_descriptor_list.c
new file mode 100644
index 000000000000..86ae6a855399
--- /dev/null
+++ b/drivers/scsi/isci/core/sci_base_memory_descriptor_list.c
@@ -0,0 +1,159 @@
+/*
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Intel Corporation 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
+ * OWNER 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.
+ */
+
+/**
+ * This file contains the base implementation for the memory descriptor list.
+ * This is currently comprised of MDL iterator methods.
+ *
+ *
+ */
+
+#include "sci_environment.h"
+#include "sci_base_memory_descriptor_list.h"
+
+/*
+ * ******************************************************************************
+ * * P U B L I C M E T H O D S
+ * ****************************************************************************** */
+
+void sci_mdl_first_entry(
+ struct sci_base_memory_descriptor_list *base_mdl)
+{
+ base_mdl->next_index = 0;
+
+ /*
+ * If this MDL is managing another MDL, then recursively rewind that MDL
+ * object as well. */
+ if (base_mdl->next_mdl != SCI_INVALID_HANDLE)
+ sci_mdl_first_entry(base_mdl->next_mdl);
+}
+
+
+void sci_mdl_next_entry(
+ struct sci_base_memory_descriptor_list *base_mdl)
+{
+ /*
+ * If there is at least one more entry left in the array, then change
+ * the next pointer to it. */
+ if (base_mdl->next_index < base_mdl->length)
+ base_mdl->next_index++;
+ else if (base_mdl->next_index == base_mdl->length) {
+ /*
+ * This MDL has exhausted it's set of entries. If this MDL is managing
+ * another MDL, then start iterating through that MDL. */
+ if (base_mdl->next_mdl != SCI_INVALID_HANDLE)
+ sci_mdl_next_entry(base_mdl->next_mdl);
+ }
+}
+
+
+struct sci_physical_memory_descriptor *sci_mdl_get_current_entry(
+ struct sci_base_memory_descriptor_list *base_mdl)
+{
+ if (base_mdl->next_index < base_mdl->length)
+ return &base_mdl->mde_array[base_mdl->next_index];
+ else if (base_mdl->next_index == base_mdl->length) {
+ /*
+ * This MDL has exhausted it's set of entries. If this MDL is managing
+ * another MDL, then return it's current entry. */
+ if (base_mdl->next_mdl != SCI_INVALID_HANDLE)
+ return sci_mdl_get_current_entry(base_mdl->next_mdl);
+ }
+
+ return NULL;
+}
+
+/*
+ * ******************************************************************************
+ * * P R O T E C T E D M E T H O D S
+ * ****************************************************************************** */
+
+void sci_base_mdl_construct(
+ struct sci_base_memory_descriptor_list *mdl,
+ struct sci_physical_memory_descriptor *mde_array,
+ u32 mde_array_length,
+ struct sci_base_memory_descriptor_list *next_mdl)
+{
+ mdl->length = mde_array_length;
+ mdl->mde_array = mde_array;
+ mdl->next_index = 0;
+ mdl->next_mdl = next_mdl;
+}
+
+/* --------------------------------------------------------------------------- */
+
+bool sci_base_mde_is_valid(
+ struct sci_physical_memory_descriptor *mde,
+ u32 alignment,
+ u32 size,
+ u16 attributes)
+{
+ /* Only need the lower 32 bits to ensure alignment is met. */
+ u32 physical_address = lower_32_bits(mde->physical_address);
+
+ if (
+ ((((unsigned long)mde->virtual_address) & (alignment - 1)) != 0)
+ || ((physical_address & (alignment - 1)) != 0)
+ || (mde->constant_memory_alignment != alignment)
+ || (mde->constant_memory_size != size)
+ || (mde->virtual_address == NULL)
+ || (mde->constant_memory_attributes != attributes)
+ ) {
+ return false;
+ }
+
+ return true;
+}
+
diff --git a/drivers/scsi/isci/core/sci_base_memory_descriptor_list.h b/drivers/scsi/isci/core/sci_base_memory_descriptor_list.h
new file mode 100644
index 000000000000..257d6e368b4a
--- /dev/null
+++ b/drivers/scsi/isci/core/sci_base_memory_descriptor_list.h
@@ -0,0 +1,155 @@
+/*
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Intel Corporation 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
+ * OWNER 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.
+ */
+
+#ifndef _SCI_BASE_MEMORY_DESCRIPTOR_LIST_H_
+#define _SCI_BASE_MEMORY_DESCRIPTOR_LIST_H_
+
+/**
+ * This file contains the protected interface structures, constants and
+ * interface methods for the struct sci_base_memory_descriptor_list object.
+ *
+ *
+ */
+
+
+#include "sci_types.h"
+#include "sci_memory_descriptor_list.h"
+
+
+/**
+ * struct sci_base_memory_descriptor_list - This structure contains all of the
+ * fields necessary to implement a simple stack for managing the list of
+ * available controller indices.
+ *
+ *
+ */
+struct sci_base_memory_descriptor_list {
+ /**
+ * This field indicates the length of the memory descriptor entry array.
+ */
+ u32 length;
+
+ /**
+ * This field is utilized to provide iterator pattern functionality.
+ * It indicates the index of the next memory descriptor in the iteration.
+ */
+ u32 next_index;
+
+ /**
+ * This field will point to the list of memory descriptors.
+ */
+ struct sci_physical_memory_descriptor *mde_array;
+
+ /**
+ * This field simply allows a user to chain memory descriptor lists
+ * together if desired. This field will be initialized to
+ * SCI_INVALID_HANDLE.
+ */
+ struct sci_base_memory_descriptor_list *next_mdl;
+
+};
+
+/**
+ * sci_base_mdl_construct() - This method is invoked to construct an memory
+ * descriptor list. It initializes the fields of the MDL.
+ * @mdl: This parameter specifies the memory descriptor list to be constructed.
+ * @mde_array: This parameter specifies the array of memory descriptor entries
+ * to be managed by this list.
+ * @mde_array_length: This parameter specifies the size of the array of entries.
+ * @next_mdl: This parameter specifies a subsequent MDL object to be managed by
+ * this MDL object.
+ *
+ * none.
+ */
+void sci_base_mdl_construct(
+ struct sci_base_memory_descriptor_list *mdl,
+ struct sci_physical_memory_descriptor *mde_array,
+ u32 mde_array_length,
+ struct sci_base_memory_descriptor_list *next_mdl);
+
+/**
+ * sci_base_mde_construct() -
+ *
+ * This macro constructs an memory descriptor entry with the given alignment
+ * and size
+ */
+#define sci_base_mde_construct(mde, alignment, size, attributes) \
+ { \
+ (mde)->constant_memory_alignment = (alignment); \
+ (mde)->constant_memory_size = (size); \
+ (mde)->constant_memory_attributes = (attributes); \
+ }
+
+/**
+ * sci_base_mde_is_valid() - This method validates that the memory descriptor
+ * is correctly filled out by the SCI User
+ * @mde: This parameter is the mde entry to validate
+ * @alignment: This parameter specifies the expected alignment of the memory
+ * for the mde.
+ * @size: This parameter specifies the memory size expected for the mde its
+ * value should not have been changed by the SCI User.
+ * @attributes: This parameter specifies the attributes for the memory
+ * descriptor provided.
+ *
+ * bool This method returns an indication as to whether the supplied MDE is
+ * valid or not. true The MDE is valid. false The MDE is not valid.
+ */
+bool sci_base_mde_is_valid(
+ struct sci_physical_memory_descriptor *mde,
+ u32 alignment,
+ u32 size,
+ u16 attributes);
+
+#endif /* _SCI_BASE_MEMORY_DESCRIPTOR_LIST_H_ */
diff --git a/drivers/scsi/isci/core/sci_base_phy.h b/drivers/scsi/isci/core/sci_base_phy.h
new file mode 100644
index 000000000000..6c0d9bbbc95f
--- /dev/null
+++ b/drivers/scsi/isci/core/sci_base_phy.h
@@ -0,0 +1,205 @@
+/*
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Intel Corporation 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
+ * OWNER 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.
+ */
+
+#ifndef _SCI_BASE_PHY_H_
+#define _SCI_BASE_PHY_H_
+
+/**
+ * This file contains all of the structures, constants, and methods common to
+ * all phy object definitions.
+ *
+ *
+ */
+
+#include "sci_base_state_machine.h"
+
+/**
+ * enum sci_base_phy_states - This enumeration depicts the standard states
+ * common to all phy state machine implementations.
+ *
+ *
+ */
+enum sci_base_phy_states {
+ /**
+ * Simply the initial state for the base domain state machine.
+ */
+ SCI_BASE_PHY_STATE_INITIAL,
+
+ /**
+ * This state indicates that the phy has successfully been stopped.
+ * In this state no new IO operations are permitted on this phy.
+ * This state is entered from the INITIAL state.
+ * This state is entered from the STARTING state.
+ * This state is entered from the READY state.
+ * This state is entered from the RESETTING state.
+ */
+ SCI_BASE_PHY_STATE_STOPPED,
+
+ /**
+ * This state indicates that the phy is in the process of becomming
+ * ready. In this state no new IO operations are permitted on this phy.
+ * This state is entered from the STOPPED state.
+ * This state is entered from the READY state.
+ * This state is entered from the RESETTING state.
+ */
+ SCI_BASE_PHY_STATE_STARTING,
+
+ /**
+ * This state indicates the the phy is now ready. Thus, the user
+ * is able to perform IO operations utilizing this phy as long as it
+ * is currently part of a valid port.
+ * This state is entered from the STARTING state.
+ */
+ SCI_BASE_PHY_STATE_READY,
+
+ /**
+ * This state indicates that the phy is in the process of being reset.
+ * In this state no new IO operations are permitted on this phy.
+ * This state is entered from the READY state.
+ */
+ SCI_BASE_PHY_STATE_RESETTING,
+
+ /**
+ * Simply the final state for the base phy state machine.
+ */
+ SCI_BASE_PHY_STATE_FINAL,
+
+ SCI_BASE_PHY_MAX_STATES
+
+};
+
+/**
+ * struct sci_base_phy - This structure defines all of the fields common to PHY
+ * objects.
+ *
+ *
+ */
+struct sci_base_phy {
+ /**
+ * This field depicts the parent object (struct sci_base_object) for the phy.
+ */
+ struct sci_base_object parent;
+
+ /**
+ * This field contains the information for the base phy state machine.
+ */
+ struct sci_base_state_machine state_machine;
+};
+
+typedef enum sci_status (*SCI_BASE_PHY_HANDLER_T)(
+ struct sci_base_phy *
+ );
+
+/**
+ * struct sci_base_phy_state_handler - This structure contains all of the state
+ * handler methods common to base phy state machines. Handler methods
+ * provide the ability to change the behavior for user requests or
+ * transitions depending on the state the machine is in.
+ *
+ *
+ */
+struct sci_base_phy_state_handler {
+ /**
+ * The start_handler specifies the method invoked when there is an
+ * attempt to start a phy.
+ */
+ SCI_BASE_PHY_HANDLER_T start_handler;
+
+ /**
+ * The stop_handler specifies the method invoked when there is an
+ * attempt to stop a phy.
+ */
+ SCI_BASE_PHY_HANDLER_T stop_handler;
+
+ /**
+ * The reset_handler specifies the method invoked when there is an
+ * attempt to reset a phy.
+ */
+ SCI_BASE_PHY_HANDLER_T reset_handler;
+
+ /**
+ * The destruct_handler specifies the method invoked when attempting to
+ * destruct a phy.
+ */
+ SCI_BASE_PHY_HANDLER_T destruct_handler;
+
+};
+
+/**
+ * sci_base_phy_construct() - Construct the base phy
+ * @this_phy: This parameter specifies the base phy to be constructed.
+ * @state_table: This parameter specifies the table of state definitions to be
+ * utilized for the phy state machine.
+ *
+ */
+static inline void sci_base_phy_construct(
+ struct sci_base_phy *base_phy,
+ const struct sci_base_state *state_table)
+{
+ base_phy->parent.private = NULL;
+ sci_base_state_machine_construct(
+ &base_phy->state_machine,
+ &base_phy->parent,
+ state_table,
+ SCI_BASE_PHY_STATE_INITIAL
+ );
+
+ sci_base_state_machine_start(
+ &base_phy->state_machine
+ );
+}
+
+
+#endif /* _SCI_BASE_PHY_H_ */
diff --git a/drivers/scsi/isci/core/sci_base_port.h b/drivers/scsi/isci/core/sci_base_port.h
new file mode 100644
index 000000000000..4e2031d195f0
--- /dev/null
+++ b/drivers/scsi/isci/core/sci_base_port.h
@@ -0,0 +1,203 @@
+/*
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Intel Corporation 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
+ * OWNER 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.
+ */
+
+#ifndef _SCI_BASE_PORT_H_
+#define _SCI_BASE_PORT_H_
+
+#include "sci_base_state_machine.h"
+#include "sci_object.h"
+
+/**
+ * enum sci_base_port_states - This enumeration depicts all the states for the
+ * common port state machine.
+ *
+ *
+ */
+enum sci_base_port_states {
+ /**
+ * This state indicates that the port has successfully been stopped.
+ * In this state no new IO operations are permitted.
+ * This state is entered from the STOPPING state.
+ */
+ SCI_BASE_PORT_STATE_STOPPED,
+
+ /**
+ * This state indicates that the port is in the process of stopping.
+ * In this state no new IO operations are permitted, but existing IO
+ * operations are allowed to complete.
+ * This state is entered from the READY state.
+ */
+ SCI_BASE_PORT_STATE_STOPPING,
+
+ /**
+ * This state indicates the port is now ready. Thus, the user is
+ * able to perform IO operations on this port.
+ * This state is entered from the STARTING state.
+ */
+ SCI_BASE_PORT_STATE_READY,
+
+ /**
+ * This state indicates the port is in the process of performing a hard
+ * reset. Thus, the user is unable to perform IO operations on this
+ * port.
+ * This state is entered from the READY state.
+ */
+ SCI_BASE_PORT_STATE_RESETTING,
+
+ /**
+ * This state indicates the port has failed a reset request. This state
+ * is entered when a port reset request times out.
+ * This state is entered from the RESETTING state.
+ */
+ SCI_BASE_PORT_STATE_FAILED,
+
+ SCI_BASE_PORT_MAX_STATES
+
+};
+
+/**
+ * struct sci_base_port - The base port object abstracts the fields common to
+ * all SCI port objects.
+ *
+ *
+ */
+struct sci_base_port {
+ /**
+ * The field specifies that the parent object for the base controller
+ * is the base object itself.
+ */
+ struct sci_base_object parent;
+
+ /**
+ * This field contains the information for the base port state machine.
+ */
+ struct sci_base_state_machine state_machine;
+};
+
+struct sci_base_phy;
+
+typedef enum sci_status (*SCI_BASE_PORT_HANDLER_T)(
+ struct sci_base_port *
+ );
+
+typedef enum sci_status (*SCI_BASE_PORT_PHY_HANDLER_T)(
+ struct sci_base_port *,
+ struct sci_base_phy *
+ );
+
+typedef enum sci_status (*SCI_BASE_PORT_RESET_HANDLER_T)(
+ struct sci_base_port *,
+ u32 timeout
+ );
+
+/**
+ * struct sci_base_port_state_handler - This structure contains all of the
+ * state handler methods common to base port state machines. Handler
+ * methods provide the ability to change the behavior for user requests or
+ * transitions depending on the state the machine is in.
+ *
+ *
+ */
+struct sci_base_port_state_handler {
+ /**
+ * The start_handler specifies the method invoked when a user attempts to
+ * start a port.
+ */
+ SCI_BASE_PORT_HANDLER_T start_handler;
+
+ /**
+ * The stop_handler specifies the method invoked when a user attempts to
+ * stop a port.
+ */
+ SCI_BASE_PORT_HANDLER_T stop_handler;
+
+ /**
+ * The destruct_handler specifies the method invoked when attempting to
+ * destruct a port.
+ */
+ SCI_BASE_PORT_HANDLER_T destruct_handler;
+
+ /**
+ * The reset_handler specifies the method invoked when a user attempts to
+ * hard reset a port.
+ */
+ SCI_BASE_PORT_RESET_HANDLER_T reset_handler;
+
+ /**
+ * The add_phy_handler specifies the method invoked when a user attempts to
+ * add another phy into the port.
+ */
+ SCI_BASE_PORT_PHY_HANDLER_T add_phy_handler;
+
+ /**
+ * The remove_phy_handler specifies the method invoked when a user
+ * attempts to remove a phy from the port.
+ */
+ SCI_BASE_PORT_PHY_HANDLER_T remove_phy_handler;
+
+};
+
+/**
+ * sci_base_port_construct() - Construct the base port object
+ * @this_port: This parameter specifies the base port to be constructed.
+ * @state_table: This parameter specifies the table of state definitions to be
+ * utilized for the domain state machine.
+ *
+ */
+void sci_base_port_construct(
+ struct sci_base_port *this_port,
+ const struct sci_base_state *state_table);
+
+#endif /* _SCI_BASE_PORT_H_ */
diff --git a/drivers/scsi/isci/core/sci_base_remote_device.h b/drivers/scsi/isci/core/sci_base_remote_device.h
new file mode 100644
index 000000000000..fe6614b8ef5b
--- /dev/null
+++ b/drivers/scsi/isci/core/sci_base_remote_device.h
@@ -0,0 +1,277 @@
+/*
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Intel Corporation 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
+ * OWNER 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.
+ */
+
+#ifndef _SCI_BASE_REMOTE_DEVICE_H_
+#define _SCI_BASE_REMOTE_DEVICE_H_
+
+/**
+ * This file contains all of the structures, constants, and methods common to
+ * all remote device object definitions.
+ *
+ *
+ */
+
+#include "sci_base_state_machine.h"
+
+struct sci_base_request;
+
+/**
+ * enum sci_base_remote_device_states - This enumeration depicts all the states
+ * for the common remote device state machine.
+ *
+ *
+ */
+enum sci_base_remote_device_states {
+ /**
+ * Simply the initial state for the base remote device state machine.
+ */
+ SCI_BASE_REMOTE_DEVICE_STATE_INITIAL,
+
+ /**
+ * This state indicates that the remote device has successfully been
+ * stopped. In this state no new IO operations are permitted.
+ * This state is entered from the INITIAL state.
+ * This state is entered from the STOPPING state.
+ */
+ SCI_BASE_REMOTE_DEVICE_STATE_STOPPED,
+
+ /**
+ * This state indicates the the remote device is in the process of
+ * becoming ready (i.e. starting). In this state no new IO operations
+ * are permitted.
+ * This state is entered from the STOPPED state.
+ */
+ SCI_BASE_REMOTE_DEVICE_STATE_STARTING,
+
+ /**
+ * This state indicates the remote device is now ready. Thus, the user
+ * is able to perform IO operations on the remote device.
+ * This state is entered from the STARTING state.
+ */
+ SCI_BASE_REMOTE_DEVICE_STATE_READY,
+
+ /**
+ * This state indicates that the remote device is in the process of
+ * stopping. In this state no new IO operations are permitted, but
+ * existing IO operations are allowed to complete.
+ * This state is entered from the READY state.
+ * This state is entered from the FAILED state.
+ */
+ SCI_BASE_REMOTE_DEVICE_STATE_STOPPING,
+
+ /**
+ * This state indicates that the remote device has failed.
+ * In this state no new IO operations are permitted.
+ * This state is entered from the INITIALIZING state.
+ * This state is entered from the READY state.
+ */
+ SCI_BASE_REMOTE_DEVICE_STATE_FAILED,
+
+ /**
+ * This state indicates the device is being reset.
+ * In this state no new IO operations are permitted.
+ * This state is entered from the READY state.
+ */
+ SCI_BASE_REMOTE_DEVICE_STATE_RESETTING,
+
+ /**
+ * Simply the final state for the base remote device state machine.
+ */
+ SCI_BASE_REMOTE_DEVICE_STATE_FINAL,
+
+ SCI_BASE_REMOTE_DEVICE_MAX_STATES
+
+};
+
+/**
+ * struct sci_base_remote_device - The base remote device object abstracts the
+ * fields common to all SCI remote device objects.
+ *
+ *
+ */
+struct sci_base_remote_device {
+ /**
+ * The field specifies that the parent object for the base remote
+ * device is the base object itself.
+ */
+ struct sci_base_object parent;
+
+ /**
+ * This field contains the information for the base remote device state
+ * machine.
+ */
+ struct sci_base_state_machine state_machine;
+};
+
+
+typedef enum sci_status (*SCI_BASE_REMOTE_DEVICE_HANDLER_T)(
+ struct sci_base_remote_device *
+ );
+
+typedef enum sci_status (*SCI_BASE_REMOTE_DEVICE_REQUEST_HANDLER_T)(
+ struct sci_base_remote_device *,
+ struct sci_base_request *
+ );
+
+typedef enum sci_status (*SCI_BASE_REMOTE_DEVICE_HIGH_PRIORITY_REQUEST_COMPLETE_HANDLER_T)(
+ struct sci_base_remote_device *,
+ struct sci_base_request *,
+ void *,
+ enum sci_io_status
+ );
+
+/**
+ * struct sci_base_remote_device_state_handler - This structure contains all of
+ * the state handler methods common to base remote device state machines.
+ * Handler methods provide the ability to change the behavior for user
+ * requests or transitions depending on the state the machine is in.
+ *
+ *
+ */
+struct sci_base_remote_device_state_handler {
+ /**
+ * The start_handler specifies the method invoked when a user attempts to
+ * start a remote device.
+ */
+ SCI_BASE_REMOTE_DEVICE_HANDLER_T start_handler;
+
+ /**
+ * The stop_handler specifies the method invoked when a user attempts to
+ * stop a remote device.
+ */
+ SCI_BASE_REMOTE_DEVICE_HANDLER_T stop_handler;
+
+ /**
+ * The fail_handler specifies the method invoked when a remote device
+ * failure has occurred. A failure may be due to an inability to
+ * initialize/configure the device.
+ */
+ SCI_BASE_REMOTE_DEVICE_HANDLER_T fail_handler;
+
+ /**
+ * The destruct_handler specifies the method invoked when attempting to
+ * destruct a remote device.
+ */
+ SCI_BASE_REMOTE_DEVICE_HANDLER_T destruct_handler;
+
+ /**
+ * The reset handler specifies the method invloked when requesting to reset a
+ * remote device.
+ */
+ SCI_BASE_REMOTE_DEVICE_HANDLER_T reset_handler;
+
+ /**
+ * The reset complete handler specifies the method invloked when reporting
+ * that a reset has completed to the remote device.
+ */
+ SCI_BASE_REMOTE_DEVICE_HANDLER_T reset_complete_handler;
+
+ /**
+ * The start_io_handler specifies the method invoked when a user
+ * attempts to start an IO request for a remote device.
+ */
+ SCI_BASE_REMOTE_DEVICE_REQUEST_HANDLER_T start_io_handler;
+
+ /**
+ * The complete_io_handler specifies the method invoked when a user
+ * attempts to complete an IO request for a remote device.
+ */
+ SCI_BASE_REMOTE_DEVICE_REQUEST_HANDLER_T complete_io_handler;
+
+ /**
+ * The continue_io_handler specifies the method invoked when a user
+ * attempts to continue an IO request for a remote device.
+ */
+ SCI_BASE_REMOTE_DEVICE_REQUEST_HANDLER_T continue_io_handler;
+
+ /**
+ * The start_task_handler specifies the method invoked when a user
+ * attempts to start a task management request for a remote device.
+ */
+ SCI_BASE_REMOTE_DEVICE_REQUEST_HANDLER_T start_task_handler;
+
+ /**
+ * The complete_task_handler specifies the method invoked when a user
+ * attempts to complete a task management request for a remote device.
+ */
+ SCI_BASE_REMOTE_DEVICE_REQUEST_HANDLER_T complete_task_handler;
+
+};
+
+/**
+ * sci_base_remote_device_construct() - Construct the base remote device
+ * @this_remote_device: This parameter specifies the base remote device to be
+ * constructed.
+ * @state_table: This parameter specifies the table of state definitions to be
+ * utilized for the remote device state machine.
+ *
+ */
+static inline void sci_base_remote_device_construct(
+ struct sci_base_remote_device *base_dev,
+ const struct sci_base_state *state_table)
+{
+ base_dev->parent.private = NULL;
+ sci_base_state_machine_construct(
+ &base_dev->state_machine,
+ &base_dev->parent,
+ state_table,
+ SCI_BASE_REMOTE_DEVICE_STATE_INITIAL
+ );
+
+ sci_base_state_machine_start(
+ &base_dev->state_machine
+ );
+}
+#endif /* _SCI_BASE_REMOTE_DEVICE_H_ */
diff --git a/drivers/scsi/isci/core/sci_base_request.h b/drivers/scsi/isci/core/sci_base_request.h
new file mode 100644
index 000000000000..d1b2195b228a
--- /dev/null
+++ b/drivers/scsi/isci/core/sci_base_request.h
@@ -0,0 +1,195 @@
+/*
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Intel Corporation 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
+ * OWNER 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.
+ */
+
+#ifndef _SCI_BASE_REQUST_H_
+#define _SCI_BASE_REQUST_H_
+
+/**
+ * This file contains all of the constants, types, and method declarations for
+ * the SCI base IO and task request objects.
+ *
+ *
+ */
+
+#include "sci_base_state_machine.h"
+
+/**
+ * enum sci_base_request_states - This enumeration depicts all the states for
+ * the common request state machine.
+ *
+ *
+ */
+enum sci_base_request_states {
+ /**
+ * Simply the initial state for the base request state machine.
+ */
+ SCI_BASE_REQUEST_STATE_INITIAL,
+
+ /**
+ * This state indicates that the request has been constructed. This state
+ * is entered from the INITIAL state.
+ */
+ SCI_BASE_REQUEST_STATE_CONSTRUCTED,
+
+ /**
+ * This state indicates that the request has been started. This state is
+ * entered from the CONSTRUCTED state.
+ */
+ SCI_BASE_REQUEST_STATE_STARTED,
+
+ /**
+ * This state indicates that the request has completed.
+ * This state is entered from the STARTED state. This state is entered from
+ * the ABORTING state.
+ */
+ SCI_BASE_REQUEST_STATE_COMPLETED,
+
+ /**
+ * This state indicates that the request is in the process of being
+ * terminated/aborted.
+ * This state is entered from the CONSTRUCTED state.
+ * This state is entered from the STARTED state.
+ */
+ SCI_BASE_REQUEST_STATE_ABORTING,
+
+ /**
+ * Simply the final state for the base request state machine.
+ */
+ SCI_BASE_REQUEST_STATE_FINAL,
+};
+
+/**
+ * struct sci_base_request - The base request object abstracts the fields
+ * common to all SCI IO and task request objects.
+ *
+ *
+ */
+struct sci_base_request {
+ /**
+ * The field specifies that the parent object for the base request is the
+ * base object itself.
+ */
+ struct sci_base_object parent;
+
+ /**
+ * This field contains the information for the base request state machine.
+ */
+ struct sci_base_state_machine state_machine;
+};
+
+typedef enum sci_status (*SCI_BASE_REQUEST_HANDLER_T)(
+ struct sci_base_request *this_request
+ );
+
+/**
+ * struct sci_base_request_state_handler - This structure contains all of the
+ * state handler methods common to base IO and task request state machines.
+ * Handler methods provide the ability to change the behavior for user
+ * requests or transitions depending on the state the machine is in.
+ *
+ *
+ */
+struct sci_base_request_state_handler {
+ /**
+ * The start_handler specifies the method invoked when a user attempts to
+ * start a request.
+ */
+ SCI_BASE_REQUEST_HANDLER_T start_handler;
+
+ /**
+ * The abort_handler specifies the method invoked when a user attempts to
+ * abort a request.
+ */
+ SCI_BASE_REQUEST_HANDLER_T abort_handler;
+
+ /**
+ * The complete_handler specifies the method invoked when a user attempts to
+ * complete a request.
+ */
+ SCI_BASE_REQUEST_HANDLER_T complete_handler;
+
+ /**
+ * The destruct_handler specifies the method invoked when a user attempts to
+ * destruct a request.
+ */
+ SCI_BASE_REQUEST_HANDLER_T destruct_handler;
+
+};
+
+/**
+ * sci_base_request_construct() - Construct the base request.
+ * @this_request: This parameter specifies the base request to be constructed.
+ * @state_table: This parameter specifies the table of state definitions to be
+ * utilized for the request state machine.
+ *
+ */
+static inline void sci_base_request_construct(
+ struct sci_base_request *base_req,
+ const struct sci_base_state *my_state_table)
+{
+ base_req->parent.private = NULL;
+ sci_base_state_machine_construct(
+ &base_req->state_machine,
+ &base_req->parent,
+ my_state_table,
+ SCI_BASE_REQUEST_STATE_INITIAL
+ );
+
+ sci_base_state_machine_start(
+ &base_req->state_machine
+ );
+}
+
+#endif /* _SCI_BASE_REQUST_H_ */
diff --git a/drivers/scsi/isci/core/sci_base_state.h b/drivers/scsi/isci/core/sci_base_state.h
new file mode 100644
index 000000000000..d6b9c1a951b1
--- /dev/null
+++ b/drivers/scsi/isci/core/sci_base_state.h
@@ -0,0 +1,90 @@
+/*
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Intel Corporation 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
+ * OWNER 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.
+ */
+
+#ifndef _SCI_BASE_STATE_H_
+#define _SCI_BASE_STATE_H_
+
+#include "sci_object.h"
+
+typedef void (*SCI_BASE_STATE_HANDLER_T)(
+ void
+ );
+
+typedef void (*SCI_STATE_TRANSITION_T)(
+ struct sci_base_object *base_object
+ );
+
+/**
+ * struct sci_base_state - The base state object abstracts the fields common to
+ * all state objects defined in SCI.
+ *
+ *
+ */
+struct sci_base_state {
+ /**
+ * This field is a function pointer that defines the method to be
+ * invoked when the state is entered.
+ */
+ SCI_STATE_TRANSITION_T enter_state;
+
+ /**
+ * This field is a function pointer that defines the method to be
+ * invoked when the state is exited.
+ */
+ SCI_STATE_TRANSITION_T exit_state;
+
+};
+
+#endif /* _SCI_BASE_STATE_H_ */
diff --git a/drivers/scsi/isci/core/sci_base_state_machine.c b/drivers/scsi/isci/core/sci_base_state_machine.c
new file mode 100644
index 000000000000..5b1e8da55fe6
--- /dev/null
+++ b/drivers/scsi/isci/core/sci_base_state_machine.c
@@ -0,0 +1,182 @@
+/*
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Intel Corporation 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
+ * OWNER 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.
+ */
+
+/**
+ * This file contains all of the functionality common to all state machine
+ * object implementations.
+ *
+ *
+ */
+
+#include "sci_base_state_machine.h"
+
+static void sci_state_machine_exit_state(struct sci_base_state_machine *sm)
+{
+ u32 state = sm->current_state_id;
+ SCI_STATE_TRANSITION_T exit = sm->state_table[state].exit_state;
+
+ if (exit)
+ exit(sm->state_machine_owner);
+}
+
+static void sci_state_machine_enter_state(struct sci_base_state_machine *sm)
+{
+ u32 state = sm->current_state_id;
+ SCI_STATE_TRANSITION_T enter = sm->state_table[state].enter_state;
+
+ if (enter)
+ enter(sm->state_machine_owner);
+}
+
+/*
+ * ******************************************************************************
+ * * P R O T E C T E D M E T H O D S
+ * ****************************************************************************** */
+
+/**
+ * This method will set the initial state and state table for the state
+ * machine. The caller should follow this request with the initialize
+ * request to cause the state machine to start.
+ * @sm: This parameter provides the state machine object to be
+ * constructed.
+ * @state_machine_owner: This parameter indicates the object that is owns the
+ * state machine being constructed.
+ * @state_table: This parameter specifies the table of state objects that is
+ * managed by this state machine.
+ * @initial_state: This parameter specifies the value of the initial state for
+ * this state machine.
+ *
+ */
+void sci_base_state_machine_construct(struct sci_base_state_machine *sm,
+ struct sci_base_object *owner,
+ const struct sci_base_state *state_table,
+ u32 initial_state)
+{
+ sm->state_machine_owner = owner;
+ sm->initial_state_id = initial_state;
+ sm->previous_state_id = initial_state;
+ sm->current_state_id = initial_state;
+ sm->state_table = state_table;
+}
+
+/**
+ * This method will cause the state machine to enter the initial state.
+ * @sm: This parameter specifies the state machine that is to
+ * be started.
+ *
+ * sci_base_state_machine_construct() for how to set the initial state none
+ */
+void sci_base_state_machine_start(struct sci_base_state_machine *sm)
+{
+ sm->current_state_id = sm->initial_state_id;
+#if defined(SCI_BASE_ENABLE_SUBJECT_NOTIFICATION)
+ sci_base_subject_notify(&sm->parent);
+#endif
+ sci_state_machine_enter_state(sm);
+}
+
+/**
+ * This method will cause the state machine to exit it's current state only.
+ * @sm: This parameter specifies the state machine that is to
+ * be stopped.
+ *
+ */
+void sci_base_state_machine_stop(
+ struct sci_base_state_machine *sm)
+{
+ sci_state_machine_exit_state(sm);
+#if defined(SCI_BASE_ENABLE_SUBJECT_NOTIFICATION)
+ sci_base_subject_notify(&sm->parent);
+#endif
+}
+
+/**
+ * This method performs an update to the current state of the state machine.
+ * @sm: This parameter specifies the state machine for which
+ * the caller wishes to perform a state change.
+ * @next_state: This parameter specifies the new state for the state machine.
+ *
+ */
+void sci_base_state_machine_change_state(
+ struct sci_base_state_machine *sm,
+ u32 next_state)
+{
+ sci_state_machine_exit_state(sm);
+
+ sm->previous_state_id = sm->current_state_id;
+ sm->current_state_id = next_state;
+
+#if defined(SCI_BASE_ENABLE_SUBJECT_NOTIFICATION)
+ /* Notify of the state change prior to entering the state. */
+ sci_base_subject_notify(&sm->parent);
+#endif
+
+ sci_state_machine_enter_state(sm);
+}
+
+/**
+ * This method simply returns the current state of the state machine to the
+ * caller.
+ * @sm: This parameter specifies the state machine for which to
+ * retrieve the current state.
+ *
+ * This method returns a u32 value indicating the current state for the
+ * supplied state machine.
+ */
+u32 sci_base_state_machine_get_state(struct sci_base_state_machine *sm)
+{
+ return sm->current_state_id;
+}
+
diff --git a/drivers/scsi/isci/core/sci_base_state_machine.h b/drivers/scsi/isci/core/sci_base_state_machine.h
new file mode 100644
index 000000000000..cee38bd3d127
--- /dev/null
+++ b/drivers/scsi/isci/core/sci_base_state_machine.h
@@ -0,0 +1,139 @@
+/*
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Intel Corporation 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
+ * OWNER 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.
+ */
+
+#ifndef _SCI_BASE_STATE_MACHINE_H_
+#define _SCI_BASE_STATE_MACHINE_H_
+
+/**
+ * This file contains all structures, constants, or method declarations common
+ * to all state machines defined in SCI.
+ *
+ *
+ */
+
+
+#include "sci_base_state.h"
+
+
+/**
+ * SET_STATE_HANDLER() -
+ *
+ * This macro simply provides simplified retrieval of an objects state handler.
+ */
+#define SET_STATE_HANDLER(object, table, state) \
+ (object)->state_handlers = &(table)[(state)]
+
+/**
+ * struct sci_base_state_machine - This structure defines the fields common to
+ * all state machines.
+ *
+ *
+ */
+struct sci_base_state_machine {
+ /**
+ * This field points to the start of the state machine's state table.
+ */
+ const struct sci_base_state *state_table;
+
+ /**
+ * This field points to the object to which this state machine is
+ * associated. It serves as a cookie to be provided to the state
+ * enter/exit methods.
+ */
+ struct sci_base_object *state_machine_owner;
+
+ /**
+ * This field simply indicates the state value for the state machine's
+ * initial state.
+ */
+ u32 initial_state_id;
+
+ /**
+ * This field indicates the current state of the state machine.
+ */
+ u32 current_state_id;
+
+ /**
+ * This field indicates the previous state of the state machine.
+ */
+ u32 previous_state_id;
+
+};
+
+/*
+ * ******************************************************************************
+ * * P R O T E C T E D M E T H O D S
+ * ****************************************************************************** */
+
+void sci_base_state_machine_construct(
+ struct sci_base_state_machine *this_state_machine,
+ struct sci_base_object *state_machine_owner,
+ const struct sci_base_state *state_table,
+ u32 initial_state);
+
+void sci_base_state_machine_start(
+ struct sci_base_state_machine *this_state_machine);
+
+void sci_base_state_machine_stop(
+ struct sci_base_state_machine *this_state_machine);
+
+void sci_base_state_machine_change_state(
+ struct sci_base_state_machine *this_state_machine,
+ u32 next_state);
+
+u32 sci_base_state_machine_get_state(
+ struct sci_base_state_machine *this_state_machine);
+
+#endif /* _SCI_BASE_STATE_MACHINE_H_ */
diff --git a/drivers/scsi/isci/core/sci_controller.h b/drivers/scsi/isci/core/sci_controller.h
new file mode 100644
index 000000000000..26c3548cbf7a
--- /dev/null
+++ b/drivers/scsi/isci/core/sci_controller.h
@@ -0,0 +1,100 @@
+/*
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Intel Corporation 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
+ * OWNER 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.
+ */
+
+#ifndef _SCI_CONTROLLER_H_
+#define _SCI_CONTROLLER_H_
+
+/**
+ * This file contains all of the interface methods that can be called by an SCI
+ * user on all SCI controller objects.
+ *
+ *
+ */
+
+
+#include "sci_types.h"
+
+struct sci_base_memory_descriptor_list;
+struct scic_sds_controller;
+
+#define SCI_CONTROLLER_INVALID_IO_TAG 0xFFFF
+
+/**
+ * sci_controller_get_memory_descriptor_list_handle() - This method simply
+ * returns a handle for the memory descriptor list associated with the
+ * supplied controller. The descriptor list provides DMA safe/capable
+ * memory requirements for this controller.
+ * @controller: This parameter specifies the controller for which to retrieve
+ * the DMA safe memory descriptor list.
+ *
+ * The user must adhere to the alignment requirements specified in memory
+ * descriptor. In situations where the operating environment does not offer
+ * memory allocation utilities supporting alignment, then it is the
+ * responsibility of the user to manually align the memory buffer for SCI.
+ * Thus, the user may have to allocate a larger buffer to meet the alignment.
+ * Additionally, the user will need to remember the actual memory allocation
+ * addresses in order to ensure the memory can be properly freed when necessary
+ * to do so. This method will return a valid handle, but the MDL may not be
+ * accurate until after the user has invoked the associated
+ * sci_controller_initialize() routine. A pointer to a physical memory
+ * descriptor array.
+ */
+struct sci_base_memory_descriptor_list *
+ sci_controller_get_memory_descriptor_list_handle(
+ struct scic_sds_controller *controller);
+
+
+#endif /* _SCI_CONTROLLER_H_ */
+
diff --git a/drivers/scsi/isci/core/sci_controller_constants.h b/drivers/scsi/isci/core/sci_controller_constants.h
new file mode 100644
index 000000000000..06c34c7bdd5f
--- /dev/null
+++ b/drivers/scsi/isci/core/sci_controller_constants.h
@@ -0,0 +1,215 @@
+/*
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Intel Corporation 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
+ * OWNER 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.
+ */
+
+#ifndef _SCI_CONTROLLER_CONSTANTS_H_
+#define _SCI_CONTROLLER_CONSTANTS_H_
+
+/**
+ * This file contains constant values that change based on the type of core or
+ * framework being managed. These constants are exported in order to
+ * provide the user with information as to the bounds (i.e. how many) of
+ * specific objects.
+ *
+ *
+ */
+
+
+#ifdef SCIC_SDS_4_ENABLED
+
+#ifndef SCI_MAX_PHYS
+/**
+ *
+ *
+ * This constant defines the maximum number of phy objects that can be
+ * supported for the SCU Driver Standard (SDS) library. This is tied directly
+ * to silicon capabilities.
+ */
+#define SCI_MAX_PHYS (4)
+#endif
+
+#ifndef SCI_MAX_PORTS
+/**
+ *
+ *
+ * This constant defines the maximum number of port objects that can be
+ * supported for the SCU Driver Standard (SDS) library. This is tied directly
+ * to silicon capabilities.
+ */
+#define SCI_MAX_PORTS SCI_MAX_PHYS
+#endif
+
+#ifndef SCI_MIN_SMP_PHYS
+/**
+ *
+ *
+ * This constant defines the minimum number of SMP phy objects that can be
+ * supported for a single expander level. This was determined by using 36
+ * physical phys and room for 2 virtual phys.
+ */
+#define SCI_MIN_SMP_PHYS (38)
+#endif
+
+#ifndef SCI_MAX_SMP_PHYS
+/**
+ *
+ *
+ * This constant defines the maximum number of SMP phy objects that can be
+ * supported for the SCU Driver Standard (SDS) library. This number can be
+ * increased if required.
+ */
+#define SCI_MAX_SMP_PHYS (384)
+#endif
+
+#ifndef SCI_MAX_REMOTE_DEVICES
+/**
+ *
+ *
+ * This constant defines the maximum number of remote device objects that can
+ * be supported for the SCU Driver Standard (SDS) library. This is tied
+ * directly to silicon capabilities.
+ */
+#define SCI_MAX_REMOTE_DEVICES (256)
+#endif
+
+#ifndef SCI_MIN_REMOTE_DEVICES
+/**
+ *
+ *
+ * This constant defines the minimum number of remote device objects that can
+ * be supported for the SCU Driver Standard (SDS) library. This # can be
+ * configured for minimum memory environments to any value less than
+ * SCI_MAX_REMOTE_DEVICES
+ */
+#define SCI_MIN_REMOTE_DEVICES (16)
+#endif
+
+#ifndef SCI_MAX_IO_REQUESTS
+/**
+ *
+ *
+ * This constant defines the maximum number of IO request objects that can be
+ * supported for the SCU Driver Standard (SDS) library. This is tied directly
+ * to silicon capabilities.
+ */
+#define SCI_MAX_IO_REQUESTS (256)
+#endif
+
+#ifndef SCI_MIN_IO_REQUESTS
+/**
+ *
+ *
+ * This constant defines the minimum number of IO request objects that can be
+ * supported for the SCU Driver Standard (SDS) library. This # can be
+ * configured for minimum memory environments to any value less than
+ * SCI_MAX_IO_REQUESTS.
+ */
+#define SCI_MIN_IO_REQUESTS (1)
+#endif
+
+#ifndef SCI_MAX_MSIX_MESSAGES
+/**
+ *
+ *
+ * This constant defines the maximum number of MSI-X interrupt vectors/messages
+ * supported for an SCU hardware controller instance.
+ */
+#define SCI_MAX_MSIX_MESSAGES (2)
+#endif
+
+#ifndef SCI_MAX_SCATTER_GATHER_ELEMENTS
+/**
+ *
+ *
+ * This constant defines the maximum number of Scatter-Gather Elements to be
+ * used by any SCI component.
+ */
+#define SCI_MAX_SCATTER_GATHER_ELEMENTS 130
+#endif
+
+#ifndef SCI_MIN_SCATTER_GATHER_ELEMENTS
+/**
+ *
+ *
+ * This constant defines the minimum number of Scatter-Gather Elements to be
+ * used by any SCI component.
+ */
+#define SCI_MIN_SCATTER_GATHER_ELEMENTS 1
+#endif
+
+#else /* SCIC_SDS_4_ENABLED */
+
+#error "SCI Core configuration left unspecified (e.g. SCIC_SDS_4_ENABLED)"
+
+#endif /* SCIC_SDS_4_ENABLED */
+
+/**
+ *
+ *
+ * This constant defines the maximum number of controllers that can occur in a
+ * single silicon package.
+ */
+#define SCI_MAX_CONTROLLERS 2
+
+/**
+ *
+ *
+ * The maximum number of supported domain objects is currently tied to the
+ * maximum number of support port objects.
+ */
+#define SCI_MAX_DOMAINS SCI_MAX_PORTS
+
+
+#endif /* _SCI_CONTROLLER_CONSTANTS_H_ */
+
diff --git a/drivers/scsi/isci/core/sci_memory_descriptor_list.h b/drivers/scsi/isci/core/sci_memory_descriptor_list.h
new file mode 100644
index 000000000000..44de1c18d2c8
--- /dev/null
+++ b/drivers/scsi/isci/core/sci_memory_descriptor_list.h
@@ -0,0 +1,169 @@
+/*
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Intel Corporation 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
+ * OWNER 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.
+ */
+
+#ifndef _SCI_MEMORY_DESCRIPTOR_LIST_H_
+#define _SCI_MEMORY_DESCRIPTOR_LIST_H_
+
+/**
+ * This file contains all of the basic data types utilized by an SCI user or
+ * implementor.
+ *
+ *
+ */
+
+
+#include "sci_types.h"
+
+struct sci_base_memory_descriptor_list;
+
+/**
+ *
+ *
+ * SCI_MDE_ATTRIBUTES These constants depict memory attributes for the Memory
+ * Descriptor Entries (MDEs) contained in the MDL.
+ */
+#define SCI_MDE_ATTRIBUTE_CACHEABLE 0x0001
+#define SCI_MDE_ATTRIBUTE_PHYSICALLY_CONTIGUOUS 0x0002
+
+/**
+ * struct sci_physical_memory_descriptor - This structure defines a description
+ * of a memory location for the SCI implementation.
+ *
+ *
+ */
+struct sci_physical_memory_descriptor {
+ /**
+ * This field contains the virtual address associated with this descriptor
+ * element. This field shall be zero when the descriptor is retrieved from
+ * the SCI implementation. The user shall set this field prior
+ * sci_controller_start()
+ */
+ void *virtual_address;
+
+ /**
+ * This field contains the physical address associated with this desciptor
+ * element. This field shall be zero when the descriptor is retrieved from
+ * the SCI implementation. The user shall set this field prior
+ * sci_controller_start()
+ */
+ dma_addr_t physical_address;
+
+ /**
+ * This field contains the size requirement for this memory descriptor.
+ * A value of zero for this field indicates the end of the descriptor
+ * list. The value should be treated as read only for an SCI user.
+ */
+ u32 constant_memory_size;
+
+ /**
+ * This field contains the alignment requirement for this memory
+ * descriptor. A value of zero for this field indicates the end of the
+ * descriptor list. All other values indicate the number of bytes to
+ * achieve the necessary alignment. The value should be treated as
+ * read only for an SCI user.
+ */
+ u32 constant_memory_alignment;
+
+ /**
+ * This field contains an indication regarding the desired memory
+ * attributes for this memory descriptor entry.
+ * Notes:
+ * - If the cacheable attribute is set, the user can allocate
+ * memory that is backed by cache for better performance. It
+ * is not required that the memory be backed by cache.
+ * - If the physically contiguous attribute is set, then the
+ * entire memory must be physically contiguous across all
+ * page boundaries.
+ */
+ u16 constant_memory_attributes;
+
+};
+
+/**
+ * sci_mdl_first_entry() - This method simply rewinds the MDL iterator back to
+ * the first memory descriptor entry in the list.
+ * @mdl: This parameter specifies the memory descriptor list that is to be
+ * rewound.
+ *
+ */
+void sci_mdl_first_entry(
+ struct sci_base_memory_descriptor_list *mdl);
+
+/**
+ * sci_mdl_next_entry() - This method simply updates the "current" pointer to
+ * the next sequential memory descriptor.
+ * @mdl: This parameter specifies the memory descriptor list for which to
+ * return the next memory descriptor entry in the list.
+ *
+ * none.
+ */
+void sci_mdl_next_entry(
+ struct sci_base_memory_descriptor_list *mdl);
+
+/**
+ * sci_mdl_get_current_entry() - This method simply returns the current memory
+ * descriptor entry.
+ * @mdl: This parameter specifies the memory descriptor list for which to
+ * return the current memory descriptor entry.
+ *
+ * This method returns a pointer to the current physical memory descriptor in
+ * the MDL. NULL This value is returned if there are no descriptors in the list.
+ */
+struct sci_physical_memory_descriptor *sci_mdl_get_current_entry(
+ struct sci_base_memory_descriptor_list *mdl);
+
+
+#endif /* _SCI_MEMORY_DESCRIPTOR_LIST_H_ */
+
diff --git a/drivers/scsi/isci/core/sci_object.h b/drivers/scsi/isci/core/sci_object.h
new file mode 100644
index 000000000000..930694264f1a
--- /dev/null
+++ b/drivers/scsi/isci/core/sci_object.h
@@ -0,0 +1,99 @@
+/*
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Intel Corporation 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
+ * OWNER 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.
+ */
+
+#ifndef _SCI_OBJECT_H_
+#define _SCI_OBJECT_H_
+
+/**
+ * This file contains all of the method and constants associated with the SCI
+ * base object. The SCI base object is the class from which all other
+ * objects derive in the Storage Controller Interface.
+ *
+ *
+ */
+
+
+#include "sci_types.h"
+#include "sci_status.h"
+
+/**
+ * struct sci_base_object - all core objects must include this as their
+ * first member to permit the casting below
+ *
+ * TODO: unwind this assumption, convert these routines and callers to pass a struct
+ * sci_base_object pointer without casting, or convert 'private' to the
+ * expected type per-object
+ *
+ */
+struct sci_base_object {
+ void *private;
+};
+
+static inline void *sci_object_get_association(void *obj)
+{
+ struct sci_base_object *base = obj;
+
+ return base->private;
+}
+
+static inline void sci_object_set_association(void *obj, void *private)
+{
+ struct sci_base_object *base = obj;
+
+ base->private = private;
+}
+
+#endif /* _SCI_OBJECT_H_ */
+
diff --git a/drivers/scsi/isci/core/sci_pool.h b/drivers/scsi/isci/core/sci_pool.h
new file mode 100644
index 000000000000..c0d2ea32529b
--- /dev/null
+++ b/drivers/scsi/isci/core/sci_pool.h
@@ -0,0 +1,199 @@
+/*
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Intel Corporation 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
+ * OWNER 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.
+ */
+
+/**
+ * This file contains the interface to the pool class. This class allows two
+ * different two different priority tasks to insert and remove items from
+ * the free pool. The user of the pool is expected to evaluate the pool
+ * condition empty before a get operation and pool condition full before a
+ * put operation. Methods Provided: - sci_pool_create() -
+ * sci_pool_initialize() - sci_pool_empty() - sci_pool_full() -
+ * sci_pool_get() - sci_pool_put()
+ *
+ *
+ */
+
+#ifndef _SCI_POOL_H_
+#define _SCI_POOL_H_
+
+/**
+ * SCI_POOL_INCREMENT() -
+ *
+ * Private operation for the pool
+ */
+#define SCI_POOL_INCREMENT(this_pool, index) \
+ (((index) + 1) == (this_pool).size ? 0 : (index) + 1)
+
+/**
+ * SCI_POOL_CREATE() -
+ *
+ * This creates a pool structure of pool_name. The members in the pool are of
+ * type with number of elements equal to size.
+ */
+#define SCI_POOL_CREATE(pool_name, type, pool_size) \
+ struct \
+ { \
+ u32 size; \
+ u32 get; \
+ u32 put; \
+ type array[(pool_size) + 1]; \
+ } pool_name
+
+
+/**
+ * sci_pool_empty() -
+ *
+ * This macro evaluates the pool and returns true if the pool is empty. If the
+ * pool is empty the user should not perform any get operation on the pool.
+ */
+#define sci_pool_empty(this_pool) \
+ ((this_pool).get == (this_pool).put)
+
+/**
+ * sci_pool_full() -
+ *
+ * This macro evaluates the pool and returns true if the pool is full. If the
+ * pool is full the user should not perform any put operation.
+ */
+#define sci_pool_full(this_pool) \
+ (SCI_POOL_INCREMENT(this_pool, (this_pool).put) == (this_pool).get)
+
+/**
+ * sci_pool_size() -
+ *
+ * This macro returns the size of the pool created. The internal size of the
+ * pool is actually 1 larger then necessary in order to ensure get and put
+ * pointers can be written simultaneously by different users. As a result,
+ * this macro subtracts 1 from the internal size
+ */
+#define sci_pool_size(this_pool) \
+ ((this_pool).size - 1)
+
+/**
+ * sci_pool_count() -
+ *
+ * This macro indicates the number of elements currently contained in the pool.
+ */
+#define sci_pool_count(this_pool) \
+ (\
+ sci_pool_empty((this_pool)) \
+ ? 0 \
+ : (\
+ sci_pool_full((this_pool)) \
+ ? sci_pool_size((this_pool)) \
+ : (\
+ (this_pool).get > (this_pool).put \
+ ? ((this_pool).size - (this_pool).get + (this_pool).put) \
+ : ((this_pool).put - (this_pool).get) \
+ ) \
+ ) \
+ )
+
+/**
+ * sci_pool_initialize() -
+ *
+ * This macro initializes the pool to an empty condition.
+ */
+#define sci_pool_initialize(this_pool) \
+ { \
+ (this_pool).size = (sizeof((this_pool).array) / sizeof((this_pool).array[0])); \
+ (this_pool).get = 0; \
+ (this_pool).put = 0; \
+ }
+
+/**
+ * sci_pool_get() -
+ *
+ * This macro will get the next free element from the pool. This should only be
+ * called if the pool is not empty.
+ */
+#define sci_pool_get(this_pool, my_value) \
+ { \
+ (my_value) = (this_pool).array[(this_pool).get]; \
+ (this_pool).get = SCI_POOL_INCREMENT((this_pool), (this_pool).get); \
+ }
+
+/**
+ * sci_pool_put() -
+ *
+ * This macro will put the value into the pool. This should only be called if
+ * the pool is not full.
+ */
+#define sci_pool_put(this_pool, the_value) \
+ { \
+ (this_pool).array[(this_pool).put] = (the_value); \
+ (this_pool).put = SCI_POOL_INCREMENT((this_pool), (this_pool).put); \
+ }
+
+/**
+ * sci_pool_erase() -
+ *
+ * This macro will search the pool and remove any elements in the pool matching
+ * the supplied value. This method can only be utilized on pools
+ */
+#define sci_pool_erase(this_pool, type, the_value) \
+ { \
+ type tmp_value; \
+ u32 index; \
+ u32 element_count = sci_pool_count((this_pool)); \
+ \
+ for (index = 0; index < element_count; index++) { \
+ sci_pool_get((this_pool), tmp_value); \
+ if (tmp_value != (the_value)) \
+ sci_pool_put((this_pool), tmp_value); \
+ } \
+ }
+
+#endif /* _SCI_POOL_H_ */
diff --git a/drivers/scsi/isci/core/sci_status.h b/drivers/scsi/isci/core/sci_status.h
new file mode 100644
index 000000000000..72b61081c28d
--- /dev/null
+++ b/drivers/scsi/isci/core/sci_status.h
@@ -0,0 +1,409 @@
+/*
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Intel Corporation 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
+ * OWNER 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.
+ */
+
+#ifndef _SCI_STATUS_H_
+#define _SCI_STATUS_H_
+
+/**
+ * This file contains all of the return status codes utilized across the
+ * various sub-components in SCI.
+ *
+ *
+ */
+
+
+/**
+ * enum _SCI_STATUS - This is the general return status enumeration for non-IO,
+ * non-task management related SCI interface methods.
+ *
+ *
+ */
+enum sci_status {
+ /**
+ * This member indicates successful completion.
+ */
+ SCI_SUCCESS = 0,
+
+ /**
+ * This value indicates that the calling method completed successfully,
+ * but that the IO may have completed before having it's start method
+ * invoked. This occurs during SAT translation for requests that do
+ * not require an IO to the target or for any other requests that may
+ * be completed without having to submit IO.
+ */
+ SCI_SUCCESS_IO_COMPLETE_BEFORE_START,
+
+ /**
+ * This Value indicates that the SCU hardware returned an early response
+ * because the io request specified more data than is returned by the
+ * target device (mode pages, inquiry data, etc.). The completion routine
+ * will handle this case to get the actual number of bytes transferred.
+ */
+ SCI_SUCCESS_IO_DONE_EARLY,
+
+ /**
+ * This member indicates that the object for which a state change is
+ * being requested is already in said state.
+ */
+ SCI_WARNING_ALREADY_IN_STATE,
+
+ /**
+ * This member indicates interrupt coalescence timer may cause SAS
+ * specification compliance issues (i.e. SMP target mode response
+ * frames must be returned within 1.9 milliseconds).
+ */
+ SCI_WARNING_TIMER_CONFLICT,
+
+ /**
+ * This field indicates a sequence of action is not completed yet. Mostly,
+ * this status is used when multiple ATA commands are needed in a SATI translation.
+ */
+ SCI_WARNING_SEQUENCE_INCOMPLETE,
+
+ /**
+ * This member indicates that there was a general failure.
+ */
+ SCI_FAILURE,
+
+ /**
+ * This member indicates that the SCI implementation is unable to complete
+ * an operation due to a critical flaw the prevents any further operation
+ * (i.e. an invalid pointer).
+ */
+ SCI_FATAL_ERROR,
+
+ /**
+ * This member indicates the calling function failed, because the state
+ * of the controller is in a state that prevents successful completion.
+ */
+ SCI_FAILURE_INVALID_STATE,
+
+ /**
+ * This member indicates the calling function failed, because there is
+ * insufficient resources/memory to complete the request.
+ */
+ SCI_FAILURE_INSUFFICIENT_RESOURCES,
+
+ /**
+ * This member indicates the calling function failed, because the
+ * controller object required for the operation can't be located.
+ */
+ SCI_FAILURE_CONTROLLER_NOT_FOUND,
+
+ /**
+ * This member indicates the calling function failed, because the
+ * discovered controller type is not supported by the library.
+ */
+ SCI_FAILURE_UNSUPPORTED_CONTROLLER_TYPE,
+
+ /**
+ * This member indicates the calling function failed, because the
+ * requested initialization data version isn't supported.
+ */
+ SCI_FAILURE_UNSUPPORTED_INIT_DATA_VERSION,
+
+ /**
+ * This member indicates the calling function failed, because the
+ * requested configuration of SAS Phys into SAS Ports is not supported.
+ */
+ SCI_FAILURE_UNSUPPORTED_PORT_CONFIGURATION,
+
+ /**
+ * This member indicates the calling function failed, because the
+ * requested protocol is not supported by the remote device, port,
+ * or controller.
+ */
+ SCI_FAILURE_UNSUPPORTED_PROTOCOL,
+
+ /**
+ * This member indicates the calling function failed, because the
+ * requested information type is not supported by the SCI implementation.
+ */
+ SCI_FAILURE_UNSUPPORTED_INFORMATION_TYPE,
+
+ /**
+ * This member indicates the calling function failed, because the
+ * device already exists.
+ */
+ SCI_FAILURE_DEVICE_EXISTS,
+
+ /**
+ * This member indicates the calling function failed, because adding
+ * a phy to the object is not possible.
+ */
+ SCI_FAILURE_ADDING_PHY_UNSUPPORTED,
+
+ /**
+ * This member indicates the calling function failed, because the
+ * requested information type is not supported by the SCI implementation.
+ */
+ SCI_FAILURE_UNSUPPORTED_INFORMATION_FIELD,
+
+ /**
+ * This member indicates the calling function failed, because the SCI
+ * implementation does not support the supplied time limit.
+ */
+ SCI_FAILURE_UNSUPPORTED_TIME_LIMIT,
+
+ /**
+ * This member indicates the calling method failed, because the SCI
+ * implementation does not contain the specified Phy.
+ */
+ SCI_FAILURE_INVALID_PHY,
+
+ /**
+ * This member indicates the calling method failed, because the SCI
+ * implementation does not contain the specified Port.
+ */
+ SCI_FAILURE_INVALID_PORT,
+
+ /**
+ * This member indicates the calling method was partly successful
+ * The port was reset but not all phys in port are operational
+ */
+ SCI_FAILURE_RESET_PORT_PARTIAL_SUCCESS,
+
+ /**
+ * This member indicates that calling method failed
+ * The port reset did not complete because none of the phys are operational
+ */
+ SCI_FAILURE_RESET_PORT_FAILURE,
+
+ /**
+ * This member indicates the calling method failed, because the SCI
+ * implementation does not contain the specified remote device.
+ */
+ SCI_FAILURE_INVALID_REMOTE_DEVICE,
+
+ /**
+ * This member indicates the calling method failed, because the remote
+ * device is in a bad state and requires a reset.
+ */
+ SCI_FAILURE_REMOTE_DEVICE_RESET_REQUIRED,
+
+ /**
+ * This member indicates the calling method failed, because the SCI
+ * implementation does not contain or support the specified IO tag.
+ */
+ SCI_FAILURE_INVALID_IO_TAG,
+
+ /**
+ * This member indicates that the operation failed and the user should
+ * check the response data associated with the IO.
+ */
+ SCI_FAILURE_IO_RESPONSE_VALID,
+
+ /**
+ * This member indicates that the operation failed, the failure is
+ * controller implementation specific, and the response data associated
+ * with the request is not valid. You can query for the controller
+ * specific error information via scic_controller_get_request_status()
+ */
+ SCI_FAILURE_CONTROLLER_SPECIFIC_IO_ERR,
+
+ /**
+ * This member indicated that the operation failed because the
+ * user requested this IO to be terminated.
+ */
+ SCI_FAILURE_IO_TERMINATED,
+
+ /**
+ * This member indicates that the operation failed and the associated
+ * request requires a SCSI abort task to be sent to the target.
+ */
+ SCI_FAILURE_IO_REQUIRES_SCSI_ABORT,
+
+ /**
+ * This member indicates that the operation failed because the supplied
+ * device could not be located.
+ */
+ SCI_FAILURE_DEVICE_NOT_FOUND,
+
+ /**
+ * This member indicates that the operation failed because the
+ * objects association is required and is not correctly set.
+ */
+ SCI_FAILURE_INVALID_ASSOCIATION,
+
+ /**
+ * This member indicates that the operation failed, because a timeout
+ * occurred.
+ */
+ SCI_FAILURE_TIMEOUT,
+
+ /**
+ * This member indicates that the operation failed, because the user
+ * specified a value that is either invalid or not supported.
+ */
+ SCI_FAILURE_INVALID_PARAMETER_VALUE,
+
+ /**
+ * This value indicates that the operation failed, because the number
+ * of messages (MSI-X) is not supported.
+ */
+ SCI_FAILURE_UNSUPPORTED_MESSAGE_COUNT,
+
+ /**
+ * This value indicates that the method failed due to a lack of
+ * available NCQ tags.
+ */
+ SCI_FAILURE_NO_NCQ_TAG_AVAILABLE,
+
+ /**
+ * This value indicates that a protocol violation has occurred on the
+ * link.
+ */
+ SCI_FAILURE_PROTOCOL_VIOLATION,
+
+ /**
+ * This value indicates a failure condition that retry may help to clear.
+ */
+ SCI_FAILURE_RETRY_REQUIRED,
+
+ /**
+ * This field indicates the retry limit was reached when a retry is attempted
+ */
+ SCI_FAILURE_RETRY_LIMIT_REACHED,
+
+ /**
+ * This member indicates the calling method was partly successful.
+ * Mostly, this status is used when a LUN_RESET issued to an expander attached
+ * STP device in READY NCQ substate needs to have RNC suspended/resumed
+ * before posting TC.
+ */
+ SCI_FAILURE_RESET_DEVICE_PARTIAL_SUCCESS,
+
+ /**
+ * This field indicates an illegal phy connection based on the routing attribute
+ * of both expander phy attached to each other.
+ */
+ SCI_FAILURE_ILLEGAL_ROUTING_ATTRIBUTE_CONFIGURATION,
+
+ /**
+ * This field indicates a CONFIG ROUTE INFO command has a response with function result
+ * INDEX DOES NOT EXIST, usually means exceeding max route index.
+ */
+ SCI_FAILURE_EXCEED_MAX_ROUTE_INDEX,
+
+ /**
+ * This value indicates that an unsupported PCI device ID has been
+ * specified. This indicates that attempts to invoke
+ * scic_library_allocate_controller() will fail.
+ */
+ SCI_FAILURE_UNSUPPORTED_PCI_DEVICE_ID
+
+};
+
+/**
+ * enum _SCI_IO_STATUS - This enumeration depicts all of the possible IO
+ * completion status values. Each value in this enumeration maps directly
+ * to a value in the enum sci_status enumeration. Please refer to that
+ * enumeration for detailed comments concerning what the status represents.
+ *
+ * Add the API to retrieve the SCU status from the core. Check to see that the
+ * following status are properly handled: - SCI_IO_FAILURE_UNSUPPORTED_PROTOCOL
+ * - SCI_IO_FAILURE_INVALID_IO_TAG
+ */
+enum sci_io_status {
+ SCI_IO_SUCCESS = SCI_SUCCESS,
+ SCI_IO_FAILURE = SCI_FAILURE,
+ SCI_IO_SUCCESS_COMPLETE_BEFORE_START = SCI_SUCCESS_IO_COMPLETE_BEFORE_START,
+ SCI_IO_SUCCESS_IO_DONE_EARLY = SCI_SUCCESS_IO_DONE_EARLY,
+ SCI_IO_FAILURE_INVALID_STATE = SCI_FAILURE_INVALID_STATE,
+ SCI_IO_FAILURE_INSUFFICIENT_RESOURCES = SCI_FAILURE_INSUFFICIENT_RESOURCES,
+ SCI_IO_FAILURE_UNSUPPORTED_PROTOCOL = SCI_FAILURE_UNSUPPORTED_PROTOCOL,
+ SCI_IO_FAILURE_RESPONSE_VALID = SCI_FAILURE_IO_RESPONSE_VALID,
+ SCI_IO_FAILURE_CONTROLLER_SPECIFIC_ERR = SCI_FAILURE_CONTROLLER_SPECIFIC_IO_ERR,
+ SCI_IO_FAILURE_TERMINATED = SCI_FAILURE_IO_TERMINATED,
+ SCI_IO_FAILURE_REQUIRES_SCSI_ABORT = SCI_FAILURE_IO_REQUIRES_SCSI_ABORT,
+ SCI_IO_FAILURE_INVALID_PARAMETER_VALUE = SCI_FAILURE_INVALID_PARAMETER_VALUE,
+ SCI_IO_FAILURE_NO_NCQ_TAG_AVAILABLE = SCI_FAILURE_NO_NCQ_TAG_AVAILABLE,
+ SCI_IO_FAILURE_PROTOCOL_VIOLATION = SCI_FAILURE_PROTOCOL_VIOLATION,
+
+ SCI_IO_FAILURE_REMOTE_DEVICE_RESET_REQUIRED = SCI_FAILURE_REMOTE_DEVICE_RESET_REQUIRED,
+
+ SCI_IO_FAILURE_RETRY_REQUIRED = SCI_FAILURE_RETRY_REQUIRED,
+ SCI_IO_FAILURE_RETRY_LIMIT_REACHED = SCI_FAILURE_RETRY_LIMIT_REACHED,
+ SCI_IO_FAILURE_INVALID_REMOTE_DEVICE = SCI_FAILURE_INVALID_REMOTE_DEVICE
+};
+
+/**
+ * enum _SCI_TASK_STATUS - This enumeration depicts all of the possible task
+ * completion status values. Each value in this enumeration maps directly
+ * to a value in the enum sci_status enumeration. Please refer to that
+ * enumeration for detailed comments concerning what the status represents.
+ *
+ * Check to see that the following status are properly handled:
+ */
+enum sci_task_status {
+ SCI_TASK_SUCCESS = SCI_SUCCESS,
+ SCI_TASK_FAILURE = SCI_FAILURE,
+ SCI_TASK_FAILURE_INVALID_STATE = SCI_FAILURE_INVALID_STATE,
+ SCI_TASK_FAILURE_INSUFFICIENT_RESOURCES = SCI_FAILURE_INSUFFICIENT_RESOURCES,
+ SCI_TASK_FAILURE_UNSUPPORTED_PROTOCOL = SCI_FAILURE_UNSUPPORTED_PROTOCOL,
+ SCI_TASK_FAILURE_INVALID_TAG = SCI_FAILURE_INVALID_IO_TAG,
+ SCI_TASK_FAILURE_RESPONSE_VALID = SCI_FAILURE_IO_RESPONSE_VALID,
+ SCI_TASK_FAILURE_CONTROLLER_SPECIFIC_ERR = SCI_FAILURE_CONTROLLER_SPECIFIC_IO_ERR,
+ SCI_TASK_FAILURE_TERMINATED = SCI_FAILURE_IO_TERMINATED,
+ SCI_TASK_FAILURE_INVALID_PARAMETER_VALUE = SCI_FAILURE_INVALID_PARAMETER_VALUE,
+
+ SCI_TASK_FAILURE_REMOTE_DEVICE_RESET_REQUIRED = SCI_FAILURE_REMOTE_DEVICE_RESET_REQUIRED,
+ SCI_TASK_FAILURE_RESET_DEVICE_PARTIAL_SUCCESS = SCI_FAILURE_RESET_DEVICE_PARTIAL_SUCCESS
+
+};
+
+
+#endif /* _SCI_STATUS_H_ */
+
diff --git a/drivers/scsi/isci/core/sci_types.h b/drivers/scsi/isci/core/sci_types.h
new file mode 100644
index 000000000000..431735d1a589
--- /dev/null
+++ b/drivers/scsi/isci/core/sci_types.h
@@ -0,0 +1,88 @@
+/*
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Intel Corporation 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
+ * OWNER 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.
+ */
+
+#ifndef _SCI_TYPES_H_
+#define _SCI_TYPES_H_
+
+#include <linux/string.h>
+
+#define sci_cb_make_physical_address(physical_addr, addr_upper, addr_lower) \
+ ((physical_addr) = (addr_lower) | ((u64)addr_upper) << 32)
+
+#define SCI_INVALID_HANDLE 0x0
+
+/**
+ * The SCI_LIBRARY_HANDLE_T will be utilized by SCI users as an opaque handle
+ * for the SCI Library object.
+ *
+ * SCI_LIBRARY_HANDLE_T
+ */
+typedef void *SCI_LIBRARY_HANDLE_T;
+
+
+typedef enum {
+ SCI_IO_REQUEST_DATA_IN = 0, /* Read operation */
+ SCI_IO_REQUEST_DATA_OUT, /* Write operation */
+ SCI_IO_REQUEST_NO_DATA
+} SCI_IO_REQUEST_DATA_DIRECTION;
+
+
+enum sci_controller_mode {
+ SCI_MODE_SPEED, /* Optimized for performance */
+ SCI_MODE_SIZE /* Optimized for memory use */
+};
+
+#endif /* _SCI_TYPES_H_ */
+
diff --git a/drivers/scsi/isci/core/sci_util.c b/drivers/scsi/isci/core/sci_util.c
new file mode 100644
index 000000000000..5cdd96f29a9e
--- /dev/null
+++ b/drivers/scsi/isci/core/sci_util.c
@@ -0,0 +1,70 @@
+/*
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Intel Corporation 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
+ * OWNER 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.
+ */
+
+#include "sci_util.h"
+
+void scic_word_copy_with_swap(
+ u32 *destination,
+ u32 *source,
+ u32 word_count)
+{
+ while (word_count--) {
+ *destination = SCIC_SWAP_DWORD(*source);
+
+ source++;
+ destination++;
+ }
+}
+
diff --git a/drivers/scsi/isci/core/sci_util.h b/drivers/scsi/isci/core/sci_util.h
new file mode 100644
index 000000000000..67e2badf8ea8
--- /dev/null
+++ b/drivers/scsi/isci/core/sci_util.h
@@ -0,0 +1,138 @@
+/*
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Intel Corporation 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
+ * OWNER 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.
+ */
+
+#ifndef _SCI_UTIL_H_
+#define _SCI_UTIL_H_
+
+#include "sci_types.h"
+
+/**
+ * SCIC_SWAP_DWORD() -
+ *
+ * Normal byte swap macro
+ */
+#define SCIC_SWAP_DWORD(x) \
+ (\
+ (((x) >> 24) & 0x000000FF) \
+ | (((x) >> 8) & 0x0000FF00) \
+ | (((x) << 8) & 0x00FF0000) \
+ | (((x) << 24) & 0xFF000000) \
+ )
+
+#define SCIC_BUILD_DWORD(char_buffer) \
+ (\
+ ((char_buffer)[0] << 24) \
+ | ((char_buffer)[1] << 16) \
+ | ((char_buffer)[2] << 8) \
+ | ((char_buffer)[3]) \
+ )
+
+#define SCI_FIELD_OFFSET(type, field) ((unsigned long)&(((type *)0)->field))
+
+/**
+ * sci_physical_address_add() -
+ *
+ * This macro simply performs addition on an dma_addr_t type. The
+ * lower u32 value is "clipped" or "wrapped" back through 0. When this occurs
+ * the upper 32-bits are incremented by 1.
+ */
+#define sci_physical_address_add(physical_address, value) \
+ { \
+ u32 lower = lower_32_bits((physical_address)); \
+ u32 upper = upper_32_bits((physical_address)); \
+ \
+ if (lower + (value) < lower) \
+ upper += 1; \
+ \
+ lower += (value); \
+ sci_cb_make_physical_address(physical_address, upper, lower); \
+ }
+
+/**
+ * sci_physical_address_subtract() -
+ *
+ * This macro simply performs subtraction on an dma_addr_t type. The
+ * lower u32 value is "clipped" or "wrapped" back through 0. When this occurs
+ * the upper 32-bits are decremented by 1.
+ */
+#define sci_physical_address_subtract(physical_address, value) \
+ { \
+ u32 lower = lower_32_bits((physical_address)); \
+ u32 upper = upper_32_bits((physical_address)); \
+ \
+ if (lower - (value) > lower) \
+ upper -= 1; \
+ \
+ lower -= (value); \
+ sci_cb_make_physical_address(physical_address, upper, lower); \
+ }
+
+/**
+ * scic_word_copy_with_swap() - Copy the data from source to destination and
+ * swap the bytes during the copy.
+ * @destination: This parameter specifies the destination address to which the
+ * data is to be copied.
+ * @source: This parameter specifies the source address from which data is to
+ * be copied.
+ * @word_count: This parameter specifies the number of 32-bit words to copy and
+ * byte swap.
+ *
+ */
+void scic_word_copy_with_swap(
+ u32 *destination,
+ u32 *source,
+ u32 word_count);
+
+#endif /* _SCI_UTIL_H_ */
diff --git a/drivers/scsi/isci/core/scic_config_parameters.h b/drivers/scsi/isci/core/scic_config_parameters.h
new file mode 100644
index 000000000000..4c16a50a0658
--- /dev/null
+++ b/drivers/scsi/isci/core/scic_config_parameters.h
@@ -0,0 +1,347 @@
+/*
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Intel Corporation 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
+ * OWNER 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.
+ */
+
+#ifndef _SCIC_SDS_USER_PARAMETERS_H_
+#define _SCIC_SDS_USER_PARAMETERS_H_
+
+/**
+ * This file contains all of the structure definitions and interface methods
+ * that can be called by a SCIC user on the SCU Driver Standard
+ * (struct scic_sds_user_parameters) user parameter block.
+ *
+ *
+ */
+
+
+#include "sci_types.h"
+#include "sci_status.h"
+#include "intel_sas.h"
+#include "sci_controller_constants.h"
+
+struct scic_sds_controller;
+
+/**
+ *
+ *
+ * SCIC_SDS_PARM_PHY_SPEED These constants define the speeds utilized for a
+ * phy/port.
+ */
+#define SCIC_SDS_PARM_NO_SPEED 0
+
+/**
+ *
+ *
+ * This value of 1 indicates generation 1 (i.e. 1.5 Gb/s).
+ */
+#define SCIC_SDS_PARM_GEN1_SPEED 1
+
+/**
+ *
+ *
+ * This value of 2 indicates generation 2 (i.e. 3.0 Gb/s).
+ */
+#define SCIC_SDS_PARM_GEN2_SPEED 2
+
+/**
+ *
+ *
+ * This value of 3 indicates generation 3 (i.e. 6.0 Gb/s).
+ */
+#define SCIC_SDS_PARM_GEN3_SPEED 3
+
+/**
+ *
+ *
+ * For range checks, the max speed generation
+ */
+#define SCIC_SDS_PARM_MAX_SPEED SCIC_SDS_PARM_GEN3_SPEED
+
+/**
+ * struct scic_sds_user_parameters - This structure delineates the various user
+ * parameters that can be changed by the core user.
+ *
+ *
+ */
+struct scic_sds_user_parameters {
+ struct {
+ /**
+ * This field specifies the NOTIFY (ENABLE SPIN UP) primitive
+ * insertion frequency for this phy index.
+ */
+ u32 notify_enable_spin_up_insertion_frequency;
+
+ /**
+ * This method specifies the number of transmitted DWORDs within which
+ * to transmit a single ALIGN primitive. This value applies regardless
+ * of what type of device is attached or connection state. A value of
+ * 0 indicates that no ALIGN primitives will be inserted.
+ */
+ u16 align_insertion_frequency;
+
+ /**
+ * This method specifies the number of transmitted DWORDs within which
+ * to transmit 2 ALIGN primitives. This applies for SAS connections
+ * only. A minimum value of 3 is required for this field.
+ */
+ u16 in_connection_align_insertion_frequency;
+
+ /**
+ * This field indicates the maximum speed generation to be utilized
+ * by phys in the supplied port.
+ * - A value of 1 indicates generation 1 (i.e. 1.5 Gb/s).
+ * - A value of 2 indicates generation 2 (i.e. 3.0 Gb/s).
+ * - A value of 3 indicates generation 3 (i.e. 6.0 Gb/s).
+ */
+ u8 max_speed_generation;
+
+ } phys[SCI_MAX_PHYS];
+
+ /**
+ * This field specifies the maximum number of direct attached devices
+ * that can have power supplied to them simultaneously.
+ */
+ u8 max_number_concurrent_device_spin_up;
+
+ /**
+ * This field specifies the number of seconds to allow a phy to consume
+ * power before yielding to another phy.
+ *
+ */
+ u8 phy_spin_up_delay_interval;
+
+ /**
+ * These timer values specifies how long a link will remain open with no
+ * activity in increments of a microsecond, it can be in increments of
+ * 100 microseconds if the upper most bit is set.
+ *
+ */
+ u16 stp_inactivity_timeout;
+ u16 ssp_inactivity_timeout;
+
+ /**
+ * These timer values specifies how long a link will remain open in increments
+ * of 100 microseconds.
+ *
+ */
+ u16 stp_max_occupancy_timeout;
+ u16 ssp_max_occupancy_timeout;
+
+ /**
+ * This timer value specifies how long a link will remain open with no
+ * outbound traffic in increments of a microsecond.
+ *
+ */
+ u8 no_outbound_task_timeout;
+
+};
+
+/**
+ * This structure/union specifies the various different user parameter sets
+ * available. Each type is specific to a hardware controller version.
+ *
+ * union scic_user_parameters
+ */
+union scic_user_parameters {
+ /**
+ * This field specifies the user parameters specific to the
+ * Storage Controller Unit (SCU) Driver Standard (SDS) version
+ * 1.
+ */
+ struct scic_sds_user_parameters sds1;
+
+};
+
+
+/**
+ *
+ *
+ * SCIC_SDS_OEM_PHY_MASK These constants define the valid values for phy_mask
+ */
+
+/**
+ *
+ *
+ * This is the min value assignable to a port's phy mask
+ */
+#define SCIC_SDS_PARM_PHY_MASK_MIN 0x0
+
+/**
+ *
+ *
+ * This is the max value assignable to a port's phy mask
+ */
+#define SCIC_SDS_PARM_PHY_MASK_MAX 0xF
+
+/**
+ * struct scic_sds_oem_parameters - This structure delineates the various OEM
+ * parameters that must be set the core user.
+ *
+ *
+ */
+struct scic_sds_oem_parameters {
+ struct {
+ /**
+ * This field indicates whether Spread Spectrum Clocking (SSC)
+ * should be enabled or disabled.
+ */
+ bool do_enable_ssc;
+
+ } controller;
+
+ struct {
+ /**
+ * This field specifies the phys to be contained inside a port.
+ * The bit position in the mask specifies the index of the phy
+ * to be contained in the port. Multiple bits (i.e. phys)
+ * can be contained in a single port.
+ */
+ u8 phy_mask;
+
+ } ports[SCI_MAX_PORTS];
+
+ struct {
+ /**
+ * This field specifies the SAS address to be transmitted on
+ * for this phy index.
+ */
+ struct sci_sas_address sas_address;
+
+ } phys[SCI_MAX_PHYS];
+
+};
+
+/**
+ * This structure/union specifies the various different OEM parameter sets
+ * available. Each type is specific to a hardware controller version.
+ *
+ * union scic_oem_parameters
+ */
+union scic_oem_parameters {
+ /**
+ * This field specifies the OEM parameters specific to the
+ * Storage Controller Unit (SCU) Driver Standard (SDS) version
+ * 1.
+ */
+ struct scic_sds_oem_parameters sds1;
+
+};
+
+/**
+ * scic_user_parameters_set() - This method allows the user to attempt to
+ * change the user parameters utilized by the controller.
+ * @controller: This parameter specifies the controller on which to set the
+ * user parameters.
+ * @user_parameters: This parameter specifies the USER_PARAMETERS object
+ * containing the potential new values.
+ *
+ * Indicate if the update of the user parameters was successful. SCI_SUCCESS
+ * This value is returned if the operation succeeded. SCI_FAILURE_INVALID_STATE
+ * This value is returned if the attempt to change the user parameter failed,
+ * because changing one of the parameters is not currently allowed.
+ * SCI_FAILURE_INVALID_PARAMETER_VALUE This value is returned if the user
+ * supplied an invalid interrupt coalescence time, spin up delay interval, etc.
+ */
+enum sci_status scic_user_parameters_set(
+ struct scic_sds_controller *controller,
+ union scic_user_parameters *user_parameters);
+
+/**
+ * scic_user_parameters_get() - This method allows the user to retrieve the
+ * user parameters utilized by the controller.
+ * @controller: This parameter specifies the controller on which to set the
+ * user parameters.
+ * @user_parameters: This parameter specifies the USER_PARAMETERS object into
+ * which the framework shall save it's parameters.
+ *
+ */
+void scic_user_parameters_get(
+ struct scic_sds_controller *controller,
+ union scic_user_parameters *user_parameters);
+
+/**
+ * scic_oem_parameters_set() - This method allows the user to attempt to change
+ * the OEM parameters utilized by the controller.
+ * @controller: This parameter specifies the controller on which to set the
+ * user parameters.
+ * @oem_parameters: This parameter specifies the OEM parameters object
+ * containing the potential new values.
+ *
+ * Indicate if the update of the user parameters was successful. SCI_SUCCESS
+ * This value is returned if the operation succeeded. SCI_FAILURE_INVALID_STATE
+ * This value is returned if the attempt to change the user parameter failed,
+ * because changing one of the parameters is not currently allowed.
+ * SCI_FAILURE_INVALID_PARAMETER_VALUE This value is returned if the user
+ * supplied an unsupported value for one of the OEM parameters.
+ */
+enum sci_status scic_oem_parameters_set(
+ struct scic_sds_controller *controller,
+ union scic_oem_parameters *oem_parameters);
+
+/**
+ * scic_oem_parameters_get() - This method allows the user to retreive the OEM
+ * parameters utilized by the controller.
+ * @controller: This parameter specifies the controller on which to set the
+ * user parameters.
+ * @oem_parameters: This parameter specifies the OEM parameters object in which
+ * to write the core's OEM parameters.
+ *
+ */
+void scic_oem_parameters_get(
+ struct scic_sds_controller *controller,
+ union scic_oem_parameters *oem_parameters);
+
+
+#endif /* _SCIC_SDS_USER_PARAMETERS_H_ */
+
diff --git a/drivers/scsi/isci/core/scic_controller.h b/drivers/scsi/isci/core/scic_controller.h
new file mode 100644
index 000000000000..756b14fcd9a4
--- /dev/null
+++ b/drivers/scsi/isci/core/scic_controller.h
@@ -0,0 +1,586 @@
+/*
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Intel Corporation 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
+ * OWNER 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.
+ */
+
+#ifndef _SCIC_CONTROLLER_H_
+#define _SCIC_CONTROLLER_H_
+
+/**
+ * This file contains all of the interface methods that can be called by an
+ * SCIC user on a controller object.
+ *
+ *
+ */
+
+
+#include "sci_types.h"
+#include "sci_status.h"
+#include "sci_controller.h"
+#include "scic_config_parameters.h"
+
+struct scic_sds_request;
+struct scic_sds_phy;
+struct scic_sds_port;
+struct scic_sds_remote_device;
+
+/**
+ * enum _SCIC_INTERRUPT_TYPE - This enumeration depicts the various types of
+ * interrupts that are potentially supported by a SCI Core implementation.
+ *
+ *
+ */
+enum scic_interrupt_type {
+ SCIC_LEGACY_LINE_INTERRUPT_TYPE,
+ SCIC_MSIX_INTERRUPT_TYPE,
+
+ /**
+ * This enumeration value indicates the use of polling.
+ */
+ SCIC_NO_INTERRUPTS
+
+};
+
+/**
+ * This method is called by the SCI user in order to have the SCI
+ * implementation handle the interrupt. This method performs minimal
+ * processing to allow for streamlined interrupt time usage.
+ *
+ * SCIC_CONTROLLER_INTERRUPT_HANDLER true: returned if there is an interrupt to
+ * process and it was processed. false: returned if no interrupt was processed.
+ */
+typedef bool (*SCIC_CONTROLLER_INTERRUPT_HANDLER)(
+ struct scic_sds_controller *controller
+ );
+
+/**
+ * This method is called by the SCI user to process completions generated as a
+ * result of a previously handled interrupt. This method will result in the
+ * completion of IO requests and handling of other controller generated
+ * events. This method should be called some time after the interrupt
+ * handler.
+ *
+ * Most, if not all, of the user callback APIs are invoked from within this
+ * API. As a result, the user should be cognizent of the operating level at
+ * which they invoke this API.
+ */
+typedef void (*SCIC_CONTROLLER_COMPLETION_HANDLER)(
+ struct scic_sds_controller *controller
+ );
+
+/**
+ * struct scic_controller_handler_methods - This structure contains an
+ * interrupt handler and completion handler function pointers.
+ *
+ *
+ */
+struct scic_controller_handler_methods {
+ SCIC_CONTROLLER_INTERRUPT_HANDLER interrupt_handler;
+ SCIC_CONTROLLER_COMPLETION_HANDLER completion_handler;
+
+};
+
+/**
+ * scic_controller_construct() - This method will attempt to construct a
+ * controller object utilizing the supplied parameter information.
+ * @c: This parameter specifies the controller to be constructed.
+ * @scu_base: mapped base address of the scu registers
+ * @smu_base: mapped base address of the smu registers
+ *
+ * Indicate if the controller was successfully constructed or if it failed in
+ * some way. SCI_SUCCESS This value is returned if the controller was
+ * successfully constructed. SCI_WARNING_TIMER_CONFLICT This value is returned
+ * if the interrupt coalescence timer may cause SAS compliance issues for SMP
+ * Target mode response processing. SCI_FAILURE_UNSUPPORTED_CONTROLLER_TYPE
+ * This value is returned if the controller does not support the supplied type.
+ * SCI_FAILURE_UNSUPPORTED_INIT_DATA_VERSION This value is returned if the
+ * controller does not support the supplied initialization data version.
+ */
+enum sci_status scic_controller_construct(struct scic_sds_controller *c,
+ void __iomem *scu_base,
+ void __iomem *smu_base);
+
+/**
+ * scic_controller_enable_interrupts() - This method will enable all controller
+ * interrupts.
+ * @controller: This parameter specifies the controller for which to enable
+ * interrupts.
+ *
+ */
+void scic_controller_enable_interrupts(
+ struct scic_sds_controller *controller);
+
+/**
+ * scic_controller_disable_interrupts() - This method will disable all
+ * controller interrupts.
+ * @controller: This parameter specifies the controller for which to disable
+ * interrupts.
+ *
+ */
+void scic_controller_disable_interrupts(
+ struct scic_sds_controller *controller);
+
+/**
+ * scic_controller_get_handler_methods() - This method will return provide
+ * function pointers for the interrupt handler and completion handler. The
+ * interrupt handler is expected to be invoked at interrupt time. The
+ * completion handler is scheduled to run as a result of the interrupt
+ * handler. The completion handler performs the bulk work for processing
+ * silicon events.
+ * @interrupt_type: This parameter informs the core which type of
+ * interrupt/completion methods are being requested. These are the types:
+ * SCIC_LEGACY_LINE_INTERRUPT_TYPE, SCIC_MSIX_INTERRUPT_TYPE,
+ * SCIC_NO_INTERRUPTS (POLLING)
+ * @message_count: This parameter informs the core the number of MSI-X messages
+ * to be utilized. This parameter must be 0 when requesting legacy line
+ * based handlers.
+ * @handler_methods: The caller provides a pointer to a buffer of type
+ * struct scic_controller_handler_methods. The size depends on the combination of
+ * the interrupt_type and message_count input parameters:
+ * SCIC_LEGACY_LINE_INTERRUPT_TYPE: - size =
+ * sizeof(struct scic_controller_handler_methods) SCIC_MSIX_INTERRUPT_TYPE:
+ * sizeof(struct scic_controller_handler_methods)
+ * @handler_methods: SCIC fills out the caller's buffer with the appropriate
+ * interrupt and completion handlers based on the info provided in the
+ * interrupt_type and message_count input parameters. For
+ * SCIC_LEGACY_LINE_INTERRUPT_TYPE, the buffer receives a single
+ * struct scic_controller_handler_methods element regardless that the
+ * message_count parameter is zero. For SCIC_MSIX_INTERRUPT_TYPE, the buffer
+ * receives an array of elements of type struct scic_controller_handler_methods
+ * where the array size is equivalent to the message_count parameter. The
+ * array is zero-relative where entry zero corresponds to message-vector
+ * zero, entry one corresponds to message-vector one, and so forth.
+ *
+ * Indicate if the handler retrieval operation was successful. SCI_SUCCESS This
+ * value is returned if retrieval succeeded.
+ * SCI_FAILURE_UNSUPPORTED_MESSAGE_COUNT This value is returned if the user
+ * supplied an unsupported number of MSI-X messages. For legacy line interrupts
+ * the only valid value is 0.
+ */
+enum sci_status scic_controller_get_handler_methods(
+ enum scic_interrupt_type interrupt_type,
+ u16 message_count,
+ struct scic_controller_handler_methods *handler_methods);
+
+/**
+ * scic_controller_initialize() - This method will initialize the controller
+ * hardware managed by the supplied core controller object. This method
+ * will bring the physical controller hardware out of reset and enable the
+ * core to determine the capabilities of the hardware being managed. Thus,
+ * the core controller can determine it's exact physical (DMA capable)
+ * memory requirements.
+ * @controller: This parameter specifies the controller to be initialized.
+ *
+ * The SCI Core user must have called scic_controller_construct() on the
+ * supplied controller object previously. Indicate if the controller was
+ * successfully initialized or if it failed in some way. SCI_SUCCESS This value
+ * is returned if the controller hardware was successfully initialized.
+ */
+enum sci_status scic_controller_initialize(
+ struct scic_sds_controller *controller);
+
+/**
+ * scic_controller_get_suggested_start_timeout() - This method returns the
+ * suggested scic_controller_start() timeout amount. The user is free to
+ * use any timeout value, but this method provides the suggested minimum
+ * start timeout value. The returned value is based upon empirical
+ * information determined as a result of interoperability testing.
+ * @controller: the handle to the controller object for which to return the
+ * suggested start timeout.
+ *
+ * This method returns the number of milliseconds for the suggested start
+ * operation timeout.
+ */
+u32 scic_controller_get_suggested_start_timeout(
+ struct scic_sds_controller *controller);
+
+/**
+ * scic_controller_start() - This method will start the supplied core
+ * controller. This method will start the staggered spin up operation. The
+ * SCI User completion callback is called when the following conditions are
+ * met: -# the return status of this method is SCI_SUCCESS. -# after all of
+ * the phys have successfully started or been given the opportunity to start.
+ * @controller: the handle to the controller object to start.
+ * @timeout: This parameter specifies the number of milliseconds in which the
+ * start operation should complete.
+ *
+ * The SCI Core user must have filled in the physical memory descriptor
+ * structure via the sci_controller_get_memory_descriptor_list() method. The
+ * SCI Core user must have invoked the scic_controller_initialize() method
+ * prior to invoking this method. The controller must be in the INITIALIZED or
+ * STARTED state. Indicate if the controller start method succeeded or failed
+ * in some way. SCI_SUCCESS if the start operation succeeded.
+ * SCI_WARNING_ALREADY_IN_STATE if the controller is already in the STARTED
+ * state. SCI_FAILURE_INVALID_STATE if the controller is not either in the
+ * INITIALIZED or STARTED states. SCI_FAILURE_INVALID_MEMORY_DESCRIPTOR if
+ * there are inconsistent or invalid values in the supplied
+ * struct sci_physical_memory_descriptor array.
+ */
+enum sci_status scic_controller_start(
+ struct scic_sds_controller *controller,
+ u32 timeout);
+
+/**
+ * scic_controller_stop() - This method will stop an individual controller
+ * object.This method will invoke the associated user callback upon
+ * completion. The completion callback is called when the following
+ * conditions are met: -# the method return status is SCI_SUCCESS. -# the
+ * controller has been quiesced. This method will ensure that all IO
+ * requests are quiesced, phys are stopped, and all additional operation by
+ * the hardware is halted.
+ * @controller: the handle to the controller object to stop.
+ * @timeout: This parameter specifies the number of milliseconds in which the
+ * stop operation should complete.
+ *
+ * The controller must be in the STARTED or STOPPED state. Indicate if the
+ * controller stop method succeeded or failed in some way. SCI_SUCCESS if the
+ * stop operation successfully began. SCI_WARNING_ALREADY_IN_STATE if the
+ * controller is already in the STOPPED state. SCI_FAILURE_INVALID_STATE if the
+ * controller is not either in the STARTED or STOPPED states.
+ */
+enum sci_status scic_controller_stop(
+ struct scic_sds_controller *controller,
+ u32 timeout);
+
+/**
+ * scic_controller_reset() - This method will reset the supplied core
+ * controller regardless of the state of said controller. This operation is
+ * considered destructive. In other words, all current operations are wiped
+ * out. No IO completions for outstanding devices occur. Outstanding IO
+ * requests are not aborted or completed at the actual remote device.
+ * @controller: the handle to the controller object to reset.
+ *
+ * Indicate if the controller reset method succeeded or failed in some way.
+ * SCI_SUCCESS if the reset operation successfully started. SCI_FATAL_ERROR if
+ * the controller reset operation is unable to complete.
+ */
+enum sci_status scic_controller_reset(
+ struct scic_sds_controller *controller);
+
+/**
+ * scic_controller_start_io() - This method is called by the SCI user to
+ * send/start an IO request. If the method invocation is successful, then
+ * the IO request has been queued to the hardware for processing.
+ * @controller: the handle to the controller object for which to start an IO
+ * request.
+ * @remote_device: the handle to the remote device object for which to start an
+ * IO request.
+ * @io_request: the handle to the io request object to start.
+ * @io_tag: This parameter specifies a previously allocated IO tag that the
+ * user desires to be utilized for this request. This parameter is optional.
+ * The user is allowed to supply SCI_CONTROLLER_INVALID_IO_TAG as the value
+ * for this parameter.
+ *
+ * - IO tags are a protected resource. It is incumbent upon the SCI Core user
+ * to ensure that each of the methods that may allocate or free available IO
+ * tags are handled in a mutually exclusive manner. This method is one of said
+ * methods requiring proper critical code section protection (e.g. semaphore,
+ * spin-lock, etc.). - For SATA, the user is required to manage NCQ tags. As a
+ * result, it is expected the user will have set the NCQ tag field in the host
+ * to device register FIS prior to calling this method. There is also a
+ * requirement for the user to call scic_stp_io_set_ncq_tag() prior to invoking
+ * the scic_controller_start_io() method. scic_controller_allocate_tag() for
+ * more information on allocating a tag. Indicate if the controller
+ * successfully started the IO request. SCI_IO_SUCCESS if the IO request was
+ * successfully started. Determine the failure situations and return values.
+ */
+enum sci_io_status scic_controller_start_io(
+ struct scic_sds_controller *controller,
+ struct scic_sds_remote_device *remote_device,
+ struct scic_sds_request *io_request,
+ u16 io_tag);
+
+
+/**
+ * scic_controller_start_task() - This method is called by the SCIC user to
+ * send/start a framework task management request.
+ * @controller: the handle to the controller object for which to start the task
+ * management request.
+ * @remote_device: the handle to the remote device object for which to start
+ * the task management request.
+ * @task_request: the handle to the task request object to start.
+ * @io_tag: This parameter specifies a previously allocated IO tag that the
+ * user desires to be utilized for this request. Note this not the io_tag
+ * of the request being managed. It is to be utilized for the task request
+ * itself. This parameter is optional. The user is allowed to supply
+ * SCI_CONTROLLER_INVALID_IO_TAG as the value for this parameter.
+ *
+ * - IO tags are a protected resource. It is incumbent upon the SCI Core user
+ * to ensure that each of the methods that may allocate or free available IO
+ * tags are handled in a mutually exclusive manner. This method is one of said
+ * methods requiring proper critical code section protection (e.g. semaphore,
+ * spin-lock, etc.). - The user must synchronize this task with completion
+ * queue processing. If they are not synchronized then it is possible for the
+ * io requests that are being managed by the task request can complete before
+ * starting the task request. scic_controller_allocate_tag() for more
+ * information on allocating a tag. Indicate if the controller successfully
+ * started the IO request. SCI_TASK_SUCCESS if the task request was
+ * successfully started. SCI_TASK_FAILURE_REQUIRES_SCSI_ABORT This value is
+ * returned if there is/are task(s) outstanding that require termination or
+ * completion before this request can succeed.
+ */
+enum sci_task_status scic_controller_start_task(
+ struct scic_sds_controller *controller,
+ struct scic_sds_remote_device *remote_device,
+ struct scic_sds_request *task_request,
+ u16 io_tag);
+
+/**
+ * scic_controller_complete_task() - This method will perform core specific
+ * completion operations for task management request. After this method is
+ * invoked, the user should consider the task request as invalid until it is
+ * properly reused (i.e. re-constructed).
+ * @controller: The handle to the controller object for which to complete the
+ * task management request.
+ * @remote_device: The handle to the remote device object for which to complete
+ * the task management request.
+ * @task_request: the handle to the task management request object to complete.
+ *
+ * Indicate if the controller successfully completed the task management
+ * request. SCI_SUCCESS if the completion process was successful.
+ */
+enum sci_status scic_controller_complete_task(
+ struct scic_sds_controller *controller,
+ struct scic_sds_remote_device *remote_device,
+ struct scic_sds_request *task_request);
+
+
+/**
+ * scic_controller_terminate_request() - This method is called by the SCI Core
+ * user to terminate an ongoing (i.e. started) core IO request. This does
+ * not abort the IO request at the target, but rather removes the IO request
+ * from the host controller.
+ * @controller: the handle to the controller object for which to terminate a
+ * request.
+ * @remote_device: the handle to the remote device object for which to
+ * terminate a request.
+ * @request: the handle to the io or task management request object to
+ * terminate.
+ *
+ * Indicate if the controller successfully began the terminate process for the
+ * IO request. SCI_SUCCESS if the terminate process was successfully started
+ * for the request. Determine the failure situations and return values.
+ */
+enum sci_status scic_controller_terminate_request(
+ struct scic_sds_controller *controller,
+ struct scic_sds_remote_device *remote_device,
+ struct scic_sds_request *request);
+
+/**
+ * scic_controller_complete_io() - This method will perform core specific
+ * completion operations for an IO request. After this method is invoked,
+ * the user should consider the IO request as invalid until it is properly
+ * reused (i.e. re-constructed).
+ * @controller: The handle to the controller object for which to complete the
+ * IO request.
+ * @remote_device: The handle to the remote device object for which to complete
+ * the IO request.
+ * @io_request: the handle to the io request object to complete.
+ *
+ * - IO tags are a protected resource. It is incumbent upon the SCI Core user
+ * to ensure that each of the methods that may allocate or free available IO
+ * tags are handled in a mutually exclusive manner. This method is one of said
+ * methods requiring proper critical code section protection (e.g. semaphore,
+ * spin-lock, etc.). - If the IO tag for a request was allocated, by the SCI
+ * Core user, using the scic_controller_allocate_io_tag() method, then it is
+ * the responsibility of the caller to invoke the scic_controller_free_io_tag()
+ * method to free the tag (i.e. this method will not free the IO tag). Indicate
+ * if the controller successfully completed the IO request. SCI_SUCCESS if the
+ * completion process was successful.
+ */
+enum sci_status scic_controller_complete_io(
+ struct scic_sds_controller *controller,
+ struct scic_sds_remote_device *remote_device,
+ struct scic_sds_request *io_request);
+
+
+/**
+ * scic_controller_get_port_handle() - This method simply provides the user
+ * with a unique handle for a given SAS/SATA core port index.
+ * @controller: This parameter represents the handle to the controller object
+ * from which to retrieve a port (SAS or SATA) handle.
+ * @port_index: This parameter specifies the port index in the controller for
+ * which to retrieve the port handle. 0 <= port_index < maximum number of
+ * phys.
+ * @port_handle: This parameter specifies the retrieved port handle to be
+ * provided to the caller.
+ *
+ * Indicate if the retrieval of the port handle was successful. SCI_SUCCESS
+ * This value is returned if the retrieval was successful.
+ * SCI_FAILURE_INVALID_PORT This value is returned if the supplied port id is
+ * not in the supported range.
+ */
+enum sci_status scic_controller_get_port_handle(
+ struct scic_sds_controller *controller,
+ u8 port_index,
+ struct scic_sds_port **port_handle);
+
+/**
+ * scic_controller_get_phy_handle() - This method simply provides the user with
+ * a unique handle for a given SAS/SATA phy index/identifier.
+ * @controller: This parameter represents the handle to the controller object
+ * from which to retrieve a phy (SAS or SATA) handle.
+ * @phy_index: This parameter specifies the phy index in the controller for
+ * which to retrieve the phy handle. 0 <= phy_index < maximum number of phys.
+ * @phy_handle: This parameter specifies the retrieved phy handle to be
+ * provided to the caller.
+ *
+ * Indicate if the retrieval of the phy handle was successful. SCI_SUCCESS This
+ * value is returned if the retrieval was successful. SCI_FAILURE_INVALID_PHY
+ * This value is returned if the supplied phy id is not in the supported range.
+ */
+enum sci_status scic_controller_get_phy_handle(
+ struct scic_sds_controller *controller,
+ u8 phy_index,
+ struct scic_sds_phy **phy_handle);
+
+/**
+ * scic_controller_allocate_io_tag() - This method will allocate a tag from the
+ * pool of free IO tags. Direct allocation of IO tags by the SCI Core user
+ * is optional. The scic_controller_start_io() method will allocate an IO
+ * tag if this method is not utilized and the tag is not supplied to the IO
+ * construct routine. Direct allocation of IO tags may provide additional
+ * performance improvements in environments capable of supporting this usage
+ * model. Additionally, direct allocation of IO tags also provides
+ * additional flexibility to the SCI Core user. Specifically, the user may
+ * retain IO tags across the lives of multiple IO requests.
+ * @controller: the handle to the controller object for which to allocate the
+ * tag.
+ *
+ * IO tags are a protected resource. It is incumbent upon the SCI Core user to
+ * ensure that each of the methods that may allocate or free available IO tags
+ * are handled in a mutually exclusive manner. This method is one of said
+ * methods requiring proper critical code section protection (e.g. semaphore,
+ * spin-lock, etc.). An unsigned integer representing an available IO tag.
+ * SCI_CONTROLLER_INVALID_IO_TAG This value is returned if there are no
+ * currently available tags to be allocated. All return other values indicate a
+ * legitimate tag.
+ */
+u16 scic_controller_allocate_io_tag(
+ struct scic_sds_controller *controller);
+
+/**
+ * scic_controller_free_io_tag() - This method will free an IO tag to the pool
+ * of free IO tags. This method provides the SCI Core user more flexibility
+ * with regards to IO tags. The user may desire to keep an IO tag after an
+ * IO request has completed, because they plan on re-using the tag for a
+ * subsequent IO request. This method is only legal if the tag was
+ * allocated via scic_controller_allocate_io_tag().
+ * @controller: This parameter specifies the handle to the controller object
+ * for which to free/return the tag.
+ * @io_tag: This parameter represents the tag to be freed to the pool of
+ * available tags.
+ *
+ * - IO tags are a protected resource. It is incumbent upon the SCI Core user
+ * to ensure that each of the methods that may allocate or free available IO
+ * tags are handled in a mutually exclusive manner. This method is one of said
+ * methods requiring proper critical code section protection (e.g. semaphore,
+ * spin-lock, etc.). - If the IO tag for a request was allocated, by the SCI
+ * Core user, using the scic_controller_allocate_io_tag() method, then it is
+ * the responsibility of the caller to invoke this method to free the tag. This
+ * method returns an indication of whether the tag was successfully put back
+ * (freed) to the pool of available tags. SCI_SUCCESS This return value
+ * indicates the tag was successfully placed into the pool of available IO
+ * tags. SCI_FAILURE_INVALID_IO_TAG This value is returned if the supplied tag
+ * is not a valid IO tag value.
+ */
+enum sci_status scic_controller_free_io_tag(
+ struct scic_sds_controller *controller,
+ u16 io_tag);
+
+
+
+
+/**
+ * scic_controller_set_mode() - This method allows the user to configure the
+ * SCI core into either a performance mode or a memory savings mode.
+ * @controller: This parameter represents the handle to the controller object
+ * for which to update the operating mode.
+ * @mode: This parameter specifies the new mode for the controller.
+ *
+ * Indicate if the user successfully change the operating mode of the
+ * controller. SCI_SUCCESS The user successfully updated the mode.
+ */
+enum sci_status scic_controller_set_mode(
+ struct scic_sds_controller *controller,
+ enum sci_controller_mode mode);
+
+
+/**
+ * scic_controller_set_interrupt_coalescence() - This method allows the user to
+ * configure the interrupt coalescence.
+ * @controller: This parameter represents the handle to the controller object
+ * for which its interrupt coalesce register is overridden.
+ * @coalesce_number: Used to control the number of entries in the Completion
+ * Queue before an interrupt is generated. If the number of entries exceed
+ * this number, an interrupt will be generated. The valid range of the input
+ * is [0, 256]. A setting of 0 results in coalescing being disabled.
+ * @coalesce_timeout: Timeout value in microseconds. The valid range of the
+ * input is [0, 2700000] . A setting of 0 is allowed and results in no
+ * interrupt coalescing timeout.
+ *
+ * Indicate if the user successfully set the interrupt coalesce parameters.
+ * SCI_SUCCESS The user successfully updated the interrutp coalescence.
+ * SCI_FAILURE_INVALID_PARAMETER_VALUE The user input value is out of range.
+ */
+enum sci_status scic_controller_set_interrupt_coalescence(
+ struct scic_sds_controller *controller,
+ u32 coalesce_number,
+ u32 coalesce_timeout);
+
+struct device;
+struct scic_sds_controller *scic_controller_alloc(struct device *dev);
+
+
+#endif /* _SCIC_CONTROLLER_H_ */
+
diff --git a/drivers/scsi/isci/core/scic_io_request.h b/drivers/scsi/isci/core/scic_io_request.h
new file mode 100644
index 000000000000..7378f335066c
--- /dev/null
+++ b/drivers/scsi/isci/core/scic_io_request.h
@@ -0,0 +1,512 @@
+/*
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Intel Corporation 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
+ * OWNER 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.
+ */
+
+#ifndef _SCIC_IO_REQUEST_H_
+#define _SCIC_IO_REQUEST_H_
+
+/**
+ * This file contains the structures and interface methods that can be
+ * referenced and used by the SCI user for the SCI IO request object.
+ *
+ * Determine the failure situations and return values.
+ */
+
+
+#include "sci_types.h"
+#include "sci_status.h"
+#include "intel_sas.h"
+
+struct scic_sds_request;
+struct scic_sds_remote_device;
+struct scic_sds_controller;
+
+/**
+ * struct scic_io_parameters - This structure contains additional optional
+ * parameters for SSP IO requests. These parameters are utilized with the
+ * scic_io_request_construct_advanced_ssp() method.
+ *
+ * Add Block-guard/DIF, TLR
+ */
+struct scic_io_parameters {
+ /**
+ * This sub-structure contains SCSI specific features (for use with SSP
+ * IO requests).
+ */
+ struct {
+ /**
+ * Data Integrity Format (DIF) is also known as protection information
+ * or block-guard. This sub-structure contains DIF specific feature
+ * information for SSP IO requests.
+ */
+ struct {
+ void *placeholder;
+ } dif;
+
+ /**
+ * Transport Layer Retries (TLR) is an SSP protocol specific feature.
+ * This sub-structure contains Transport Layer Retries (TLR) specific
+ * feature information for SSP IO requests.
+ */
+ struct {
+ void *placeholder;
+ } tlr;
+
+ } scsi;
+
+};
+
+/**
+ * struct scic_passthru_request_callbacks - This structure contains the pointer
+ * to the callback functions for constructing the passthrough request common
+ * to SSP, SMP and STP. This structure must be set by the win sci layer
+ * before the passthrough build is called
+ *
+ *
+ */
+struct scic_passthru_request_callbacks {
+ /**
+ * Function pointer to get the phy identifier for passthrough request.
+ */
+ u32 (*scic_cb_passthru_get_phy_identifier)(void *, u8 *);
+ /**
+ * Function pointer to get the port identifier for passthrough request.
+ */
+ u32 (*scic_cb_passthru_get_port_identifier)(void *, u8 *);
+ /**
+ * Function pointer to get the connection rate for passthrough request.
+ */
+ u32 (*scic_cb_passthru_get_connection_rate)(void *, void *);
+ /**
+ * Function pointer to get the destination sas address for passthrough request.
+ */
+ void (*scic_cb_passthru_get_destination_sas_address)(void *, u8 **);
+ /**
+ * Function pointer to get the transfer length for passthrough request.
+ */
+ u32 (*scic_cb_passthru_get_transfer_length)(void *);
+ /**
+ * Function pointer to get the data direction for passthrough request.
+ */
+ u32 (*scic_cb_passthru_get_data_direction)(void *);
+
+};
+
+/**
+ * struct scic_ssp_passthru_request_callbacks - This structure contains the
+ * pointer to the callback functions for constructing the passthrough
+ * request specific to SSP. This structure must be set by the win sci layer
+ * before the passthrough build is called
+ *
+ *
+ */
+struct scic_ssp_passthru_request_callbacks {
+ /**
+ * Common callbacks for all Passthru requests
+ */
+ struct scic_passthru_request_callbacks common_callbacks;
+ /**
+ * Function pointer to get the lun for passthrough request.
+ */
+ void (*scic_cb_ssp_passthru_get_lun)(void *, u8 **);
+ /**
+ * Function pointer to get the cdb
+ */
+ void (*scic_cb_ssp_passthru_get_cdb)(void *, u32 *, u8 **, u32 *, u8 **);
+ /**
+ * Function pointer to get the task attribute for passthrough request.
+ */
+ u32 (*scic_cb_ssp_passthru_get_task_attribute)(void *);
+};
+
+/**
+ * struct scic_stp_passthru_request_callbacks - This structure contains the
+ * pointer to the callback functions for constructing the passthrough
+ * request specific to STP. This structure must be set by the win sci layer
+ * before the passthrough build is called
+ *
+ *
+ */
+struct scic_stp_passthru_request_callbacks {
+ /**
+ * Common callbacks for all Passthru requests
+ */
+ struct scic_passthru_request_callbacks common_callbacks;
+ /**
+ * Function pointer to get the protocol for passthrough request.
+ */
+ u8 (*scic_cb_stp_passthru_get_protocol)(void *);
+ /**
+ * Function pointer to get the resgister fis
+ */
+ void (*scic_cb_stp_passthru_get_register_fis)(void *, u8 **);
+ /**
+ * Function pointer to get the MULTIPLE_COUNT (bits 5,6,7 in Byte 1 in the SAT-specific SCSI extenstion in ATA Pass-through (0x85))
+ */
+ u8 (*scic_cb_stp_passthru_get_multiplecount)(void *);
+ /**
+ * Function pointer to get the EXTEND (bit 0 in Byte 1 the SAT-specific SCSI extenstion in ATA Pass-through (0x85))
+ */
+ u8 (*scic_cb_stp_passthru_get_extend)(void *);
+ /**
+ * Function pointer to get the CK_COND (bit 5 in Byte 2 the SAT-specific SCSI extenstion in ATA Pass-through (0x85))
+ */
+ u8 (*scic_cb_stp_passthru_get_ckcond)(void *);
+ /**
+ * Function pointer to get the T_DIR (bit 3 in Byte 2 the SAT-specific SCSI extenstion in ATA Pass-through (0x85))
+ */
+ u8 (*scic_cb_stp_passthru_get_tdir)(void *);
+ /**
+ * Function pointer to get the BYTE_BLOCK (bit 2 in Byte 2 the SAT-specific SCSI extenstion in ATA Pass-through (0x85))
+ */
+ u8 (*scic_cb_stp_passthru_get_byteblock)(void *);
+ /**
+ * Function pointer to get the T_LENGTH (bits 0,1 in Byte 2 the SAT-specific SCSI extenstion in ATA Pass-through (0x85))
+ */
+ u8 (*scic_cb_stp_passthru_get_tlength)(void *);
+
+};
+
+/**
+ * struct scic_smp_passthru_request_callbacks - This structure contains the
+ * pointer to the callback functions for constructing the passthrough
+ * request specific to SMP. This structure must be set by the win sci layer
+ * before the passthrough build is called
+ *
+ *
+ */
+struct scic_smp_passthru_request_callbacks {
+ /**
+ * Common callbacks for all Passthru requests
+ */
+ struct scic_passthru_request_callbacks common_callbacks;
+
+ /**
+ * Function pointer to get the length of the smp request and its length
+ */
+ u32 (*scic_cb_smp_passthru_get_request)(void *, u8 **);
+ /**
+ * Function pointer to get the frame type of the smp request
+ */
+ u8 (*scic_cb_smp_passthru_get_frame_type)(void *);
+ /**
+ * Function pointer to get the function in the the smp request
+ */
+ u8 (*scic_cb_smp_passthru_get_function)(void *);
+
+ /**
+ * Function pointer to get the "allocated response length" in the the smp request
+ */
+ u8 (*scic_cb_smp_passthru_get_allocated_response_length)(void *);
+
+};
+
+/**
+ * This enumeration specifies the transport protocol utilized for the request.
+ *
+ *
+ */
+typedef enum {
+ /**
+ * This enumeration constant indicates that no protocol has yet been
+ * set.
+ */
+ SCIC_NO_PROTOCOL,
+
+ /**
+ * This enumeration constant indicates that the protocol utilized
+ * is the Serial Management Protocol.
+ */
+ SCIC_SMP_PROTOCOL,
+
+ /**
+ * This enumeration constant indicates that the protocol utilized
+ * is the Serial SCSI Protocol.
+ */
+ SCIC_SSP_PROTOCOL,
+
+ /**
+ * This enumeration constant indicates that the protocol utilized
+ * is the Serial-ATA Tunneling Protocol.
+ */
+ SCIC_STP_PROTOCOL
+
+} SCIC_TRANSPORT_PROTOCOL;
+
+
+/**
+ * scic_io_request_get_object_size() - This method simply returns the size
+ * required to build an SCI based IO request object.
+ *
+ * Return the size of the SCI IO request object.
+ */
+u32 scic_io_request_get_object_size(
+ void);
+
+/**
+ * scic_io_request_construct() - This method is called by the SCI user to
+ * construct all SCI Core IO requests. Memory initialization and
+ * functionality common to all IO request types is performed in this method.
+ * @scic_controller: the handle to the core controller object for which to
+ * build an IO request.
+ * @scic_remote_device: the handle to the core remote device object for which
+ * to build an IO request.
+ * @io_tag: This parameter specifies the IO tag to be associated with this
+ * request. If SCI_CONTROLLER_INVALID_IO_TAG is passed, then a copy of the
+ * request is built internally. The request will be copied into the actual
+ * controller request memory when the IO tag is allocated internally during
+ * the scic_controller_start_io() method.
+ * @user_io_request_object: This parameter specifies the user IO request to be
+ * utilized during IO construction. This IO pointer will become the
+ * associated object for the core IO request object.
+ * @scic_io_request_memory: This parameter specifies the memory location to be
+ * utilized when building the core request.
+ * @new_scic_io_request_handle: This parameter specifies a pointer to the
+ * handle the core will expect in further interactions with the core IO
+ * request object.
+ *
+ * The SCI core implementation will create an association between the user IO
+ * request object and the core IO request object. Indicate if the controller
+ * successfully built the IO request. SCI_SUCCESS This value is returned if the
+ * IO request was successfully built.
+ */
+enum sci_status scic_io_request_construct(
+ struct scic_sds_controller *scic_controller,
+ struct scic_sds_remote_device *scic_remote_device,
+ u16 io_tag,
+ void *user_io_request_object,
+ void *scic_io_request_memory,
+ struct scic_sds_request **new_scic_io_request_handle);
+
+/**
+ * scic_io_request_construct_basic_ssp() - This method is called by the SCI
+ * user to build an SSP IO request.
+ * @scic_io_request: This parameter specifies the handle to the io request
+ * object to be built.
+ *
+ * - The user must have previously called scic_io_request_construct() on the
+ * supplied IO request. Indicate if the controller successfully built the IO
+ * request. SCI_SUCCESS This value is returned if the IO request was
+ * successfully built. SCI_FAILURE_UNSUPPORTED_PROTOCOL This value is returned
+ * if the remote_device does not support the SSP protocol.
+ * SCI_FAILURE_INVALID_ASSOCIATION This value is returned if the user did not
+ * properly set the association between the SCIC IO request and the user's IO
+ * request. Please refer to the sci_object_set_association() routine for more
+ * information.
+ */
+enum sci_status scic_io_request_construct_basic_ssp(
+ struct scic_sds_request *scic_io_request);
+
+
+
+
+
+/**
+ * scic_io_request_construct_basic_sata() - This method is called by the SCI
+ * Core user to build an STP IO request.
+ * @scic_io_request: This parameter specifies the handle to the io request
+ * object to be built.
+ *
+ * - The user must have previously called scic_io_request_construct() on the
+ * supplied IO request. Indicate if the controller successfully built the IO
+ * request. SCI_SUCCESS This value is returned if the IO request was
+ * successfully built. SCI_FAILURE_UNSUPPORTED_PROTOCOL This value is returned
+ * if the remote_device does not support the STP protocol.
+ * SCI_FAILURE_INVALID_ASSOCIATION This value is returned if the user did not
+ * properly set the association between the SCIC IO request and the user's IO
+ * request. Please refer to the sci_object_set_association() routine for more
+ * information.
+ */
+enum sci_status scic_io_request_construct_basic_sata(
+ struct scic_sds_request *scic_io_request);
+
+
+
+
+/**
+ * scic_io_request_construct_smp() - This method is called by the SCI user to
+ * build an SMP IO request.
+ * @scic_io_request: This parameter specifies the handle to the io request
+ * object to be built.
+ *
+ * - The user must have previously called scic_io_request_construct() on the
+ * supplied IO request. Indicate if the controller successfully built the IO
+ * request. SCI_SUCCESS This value is returned if the IO request was
+ * successfully built. SCI_FAILURE_UNSUPPORTED_PROTOCOL This value is returned
+ * if the remote_device does not support the SMP protocol.
+ * SCI_FAILURE_INVALID_ASSOCIATION This value is returned if the user did not
+ * properly set the association between the SCIC IO request and the user's IO
+ * request. Please refer to the sci_object_set_association() routine for more
+ * information.
+ */
+enum sci_status scic_io_request_construct_smp(
+ struct scic_sds_request *scic_io_request);
+
+
+
+/**
+ * scic_request_get_controller_status() - This method returns the controller
+ * specific IO/Task request status. These status values are unique to the
+ * specific controller being managed by the SCIC.
+ * @io_request: the handle to the IO or task management request object for
+ * which to retrieve the status.
+ *
+ * This method returns a value indicating the controller specific request
+ * status.
+ */
+u32 scic_request_get_controller_status(
+ struct scic_sds_request *io_request);
+
+
+
+/**
+ * scic_io_request_get_command_iu_address() - This method will return the
+ * address to the command information unit.
+ * @scic_io_request: This parameter specifies the handle to the io request
+ * object to be built.
+ *
+ * The address of the SSP/SMP command information unit.
+ */
+void *scic_io_request_get_command_iu_address(
+ struct scic_sds_request *scic_io_request);
+
+/**
+ * scic_io_request_get_response_iu_address() - This method will return the
+ * address to the response information unit. For an SSP request this buffer
+ * is only valid if the IO request is completed with the status
+ * SCI_FAILURE_IO_RESPONSE_VALID.
+ * @scic_io_request: This parameter specifies the handle to the io request
+ * object to be built.
+ *
+ * The address of the SSP/SMP response information unit.
+ */
+void *scic_io_request_get_response_iu_address(
+ struct scic_sds_request *scic_io_request);
+
+/**
+ * scic_io_request_get_io_tag() - This method will return the IO tag utilized
+ * by the IO request.
+ * @scic_io_request: This parameter specifies the handle to the io request
+ * object for which to return the IO tag.
+ *
+ * An unsigned integer representing the IO tag being utilized.
+ * SCI_CONTROLLER_INVALID_IO_TAG This value is returned if the IO does not
+ * currently have an IO tag allocated to it. All return other values indicate a
+ * legitimate tag.
+ */
+u16 scic_io_request_get_io_tag(
+ struct scic_sds_request *scic_io_request);
+
+
+/**
+ * scic_stp_io_request_set_ncq_tag() - This method will assign an NCQ tag to
+ * the io request object. The caller of this function must make sure that
+ * only valid NCQ tags are assigned to the io request object.
+ * @scic_io_request: This parameter specifies the handle to the io request
+ * object to which to assign the ncq tag.
+ * @ncq_tag: This parameter specifies the NCQ tag to be utilized for the
+ * supplied core IO request. It is up to the user to make sure that this is
+ * a valid NCQ tag.
+ *
+ * none This function is only valid for SATA NCQ requests.
+ */
+void scic_stp_io_request_set_ncq_tag(
+ struct scic_sds_request *scic_io_request,
+ u16 ncq_tag);
+
+/**
+ * scic_stp_io_request_get_h2d_reg_address() - This method will return the
+ * address of the host to device register fis region for the io request
+ * object.
+ * @scic_io_request: This parameter specifies the handle to the io request
+ * object from which to get the host to device register fis buffer.
+ *
+ * The address of the host to device register fis buffer in the io request
+ * object. This function is only valid for SATA requests.
+ */
+void *scic_stp_io_request_get_h2d_reg_address(
+ struct scic_sds_request *scic_io_request);
+
+/**
+ * scic_stp_io_request_get_d2h_reg_address() - This method will return the
+ * address of the device to host register fis region for the io request
+ * object.
+ * @scic_io_request: This parameter specifies teh handle to the io request
+ * object from which to get the device to host register fis buffer.
+ *
+ * The address fo the device to host register fis ending the io request. This
+ * function is only valid for SATA requests.
+ */
+void *scic_stp_io_request_get_d2h_reg_address(
+ struct scic_sds_request *scic_io_request);
+
+
+/**
+ * scic_io_request_get_number_of_bytes_transferred() - This method will return
+ * the number of bytes transferred from the SCU
+ * @scic_io_request: This parameter specifies the handle to the io request
+ * whose data length was not eqaul to the data length specified in the
+ * request. When the driver gets an early io completion status from the
+ * hardware, this routine should be called to get the actual number of bytes
+ * transferred
+ *
+ * The return is the number of bytes transferred when the data legth is not
+ * equal to the specified length in the io request
+ */
+u32 scic_io_request_get_number_of_bytes_transferred(
+ struct scic_sds_request *scic_io_request);
+
+
+#endif /* _SCIC_IO_REQUEST_H_ */
+
diff --git a/drivers/scsi/isci/core/scic_phy.h b/drivers/scsi/isci/core/scic_phy.h
new file mode 100644
index 000000000000..25a6140fa9e4
--- /dev/null
+++ b/drivers/scsi/isci/core/scic_phy.h
@@ -0,0 +1,303 @@
+/*
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Intel Corporation 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
+ * OWNER 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.
+ */
+
+#ifndef _SCIC_PHY_H_
+#define _SCIC_PHY_H_
+
+/**
+ * This file contains all of the interface methods that can be called by an
+ * SCIC user on a phy (SAS or SATA) object.
+ *
+ *
+ */
+
+
+#include "sci_types.h"
+#include "sci_status.h"
+
+#include "intel_sata.h"
+#include "intel_sas.h"
+
+struct scic_sds_phy;
+struct scic_sds_port;
+
+/**
+ * struct scic_phy_properties - This structure defines the properties common to
+ * all phys that can be retrieved.
+ *
+ *
+ */
+struct scic_phy_properties {
+ /**
+ * This field specifies the port that currently contains the
+ * supplied phy. This field may be set to SCI_INVALID_HANDLE
+ * if the phy is not currently contained in a port.
+ */
+ struct scic_sds_port *owning_port;
+
+ /**
+ * This field specifies the link rate at which the phy is
+ * currently operating.
+ */
+ enum sci_sas_link_rate negotiated_link_rate;
+
+ /**
+ * This field indicates the protocols supported by the phy.
+ */
+ struct sci_sas_identify_address_frame_protocols protocols;
+
+ /**
+ * This field specifies the index of the phy in relation to other
+ * phys within the controller. This index is zero relative.
+ */
+ u8 index;
+
+};
+
+/**
+ * struct scic_sas_phy_properties - This structure defines the properties,
+ * specific to a SAS phy, that can be retrieved.
+ *
+ *
+ */
+struct scic_sas_phy_properties {
+ /**
+ * This field delineates the Identify Address Frame received
+ * from the remote end point.
+ */
+ struct sci_sas_identify_address_frame received_iaf;
+
+ /**
+ * This field delineates the Phy capabilities structure received
+ * from the remote end point.
+ */
+ struct sas_capabilities received_capabilities;
+
+};
+
+/**
+ * struct scic_sata_phy_properties - This structure defines the properties,
+ * specific to a SATA phy, that can be retrieved.
+ *
+ *
+ */
+struct scic_sata_phy_properties {
+ /**
+ * This field delineates the signature FIS received from the
+ * attached target.
+ */
+ struct sata_fis_reg_d2h signature_fis;
+
+ /**
+ * This field specifies to the user if a port selector is connected
+ * on the specified phy.
+ */
+ bool is_port_selector_present;
+
+};
+
+/**
+ * enum scic_phy_counter_id - This enumeration depicts the various pieces of
+ * optional information that can be retrieved for a specific phy.
+ *
+ *
+ */
+enum scic_phy_counter_id {
+ /**
+ * This PHY information field tracks the number of frames received.
+ */
+ SCIC_PHY_COUNTER_RECEIVED_FRAME,
+
+ /**
+ * This PHY information field tracks the number of frames transmitted.
+ */
+ SCIC_PHY_COUNTER_TRANSMITTED_FRAME,
+
+ /**
+ * This PHY information field tracks the number of DWORDs received.
+ */
+ SCIC_PHY_COUNTER_RECEIVED_FRAME_WORD,
+
+ /**
+ * This PHY information field tracks the number of DWORDs transmitted.
+ */
+ SCIC_PHY_COUNTER_TRANSMITTED_FRAME_DWORD,
+
+ /**
+ * This PHY information field tracks the number of times DWORD
+ * synchronization was lost.
+ */
+ SCIC_PHY_COUNTER_LOSS_OF_SYNC_ERROR,
+
+ /**
+ * This PHY information field tracks the number of received DWORDs with
+ * running disparity errors.
+ */
+ SCIC_PHY_COUNTER_RECEIVED_DISPARITY_ERROR,
+
+ /**
+ * This PHY information field tracks the number of received frames with a
+ * CRC error (not including short or truncated frames).
+ */
+ SCIC_PHY_COUNTER_RECEIVED_FRAME_CRC_ERROR,
+
+ /**
+ * This PHY information field tracks the number of DONE (ACK/NAK TIMEOUT)
+ * primitives received.
+ */
+ SCIC_PHY_COUNTER_RECEIVED_DONE_ACK_NAK_TIMEOUT,
+
+ /**
+ * This PHY information field tracks the number of DONE (ACK/NAK TIMEOUT)
+ * primitives transmitted.
+ */
+ SCIC_PHY_COUNTER_TRANSMITTED_DONE_ACK_NAK_TIMEOUT,
+
+ /**
+ * This PHY information field tracks the number of times the inactivity
+ * timer for connections on the phy has been utilized.
+ */
+ SCIC_PHY_COUNTER_INACTIVITY_TIMER_EXPIRED,
+
+ /**
+ * This PHY information field tracks the number of DONE (CREDIT TIMEOUT)
+ * primitives received.
+ */
+ SCIC_PHY_COUNTER_RECEIVED_DONE_CREDIT_TIMEOUT,
+
+ /**
+ * This PHY information field tracks the number of DONE (CREDIT TIMEOUT)
+ * primitives transmitted.
+ */
+ SCIC_PHY_COUNTER_TRANSMITTED_DONE_CREDIT_TIMEOUT,
+
+ /**
+ * This PHY information field tracks the number of CREDIT BLOCKED
+ * primitives received.
+ * @note Depending on remote device implementation, credit blocks
+ * may occur regularly.
+ */
+ SCIC_PHY_COUNTER_RECEIVED_CREDIT_BLOCKED,
+
+ /**
+ * This PHY information field contains the number of short frames
+ * received. A short frame is simply a frame smaller then what is
+ * allowed by either the SAS or SATA specification.
+ */
+ SCIC_PHY_COUNTER_RECEIVED_SHORT_FRAME,
+
+ /**
+ * This PHY information field contains the number of frames received after
+ * credit has been exhausted.
+ */
+ SCIC_PHY_COUNTER_RECEIVED_FRAME_WITHOUT_CREDIT,
+
+ /**
+ * This PHY information field contains the number of frames received after
+ * a DONE has been received.
+ */
+ SCIC_PHY_COUNTER_RECEIVED_FRAME_AFTER_DONE,
+
+ /**
+ * This PHY information field contains the number of times the phy
+ * failed to achieve DWORD synchronization during speed negotiation.
+ */
+ SCIC_PHY_COUNTER_SN_DWORD_SYNC_ERROR
+};
+
+
+/**
+ * scic_sas_phy_get_properties() - This method will enable the user to retrieve
+ * information specific to a SAS phy, such as: the received identify address
+ * frame, received phy capabilities, etc.
+ * @phy: this parameter specifies the phy for which to retrieve properties.
+ * @properties: This parameter specifies the properties structure into which to
+ * copy the requested information.
+ *
+ * This method returns an indication as to whether the SAS phy properties were
+ * successfully retrieved. SCI_SUCCESS This value is returned if the SAS
+ * properties are successfully retrieved. SCI_FAILURE This value is returned if
+ * the SAS properties are not successfully retrieved (e.g. It's not a SAS Phy).
+ */
+enum sci_status scic_sas_phy_get_properties(
+ struct scic_sds_phy *phy,
+ struct scic_sas_phy_properties *properties);
+
+/**
+ * scic_sata_phy_get_properties() - This method will enable the user to
+ * retrieve information specific to a SATA phy, such as: the received
+ * signature FIS, if a port selector is present, etc.
+ * @phy: this parameter specifies the phy for which to retrieve properties.
+ * @properties: This parameter specifies the properties structure into which to
+ * copy the requested information.
+ *
+ * This method returns an indication as to whether the SATA phy properties were
+ * successfully retrieved. SCI_SUCCESS This value is returned if the SATA
+ * properties are successfully retrieved. SCI_FAILURE This value is returned if
+ * the SATA properties are not successfully retrieved (e.g. It's not a SATA
+ * Phy).
+ */
+enum sci_status scic_sata_phy_get_properties(
+ struct scic_sds_phy *phy,
+ struct scic_sata_phy_properties *properties);
+
+
+
+
+
+
+
+#endif /* _SCIC_PHY_H_ */
+
diff --git a/drivers/scsi/isci/core/scic_port.h b/drivers/scsi/isci/core/scic_port.h
new file mode 100644
index 000000000000..34d22c04aa56
--- /dev/null
+++ b/drivers/scsi/isci/core/scic_port.h
@@ -0,0 +1,213 @@
+/*
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Intel Corporation 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
+ * OWNER 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.
+ */
+
+#ifndef _SCIC_PORT_H_
+#define _SCIC_PORT_H_
+
+/**
+ * This file contains all of the interface methods that can be called by an SCI
+ * Core user on a SAS or SATA port.
+ *
+ *
+ */
+
+
+#include "sci_types.h"
+#include "sci_status.h"
+#include "intel_sas.h"
+
+struct scic_sds_port;
+
+enum SCIC_PORT_NOT_READY_REASON_CODE {
+ SCIC_PORT_NOT_READY_NO_ACTIVE_PHYS,
+ SCIC_PORT_NOT_READY_HARD_RESET_REQUESTED,
+ SCIC_PORT_NOT_READY_INVALID_PORT_CONFIGURATION,
+ SCIC_PORT_NOT_READY_RECONFIGURING,
+
+ SCIC_PORT_NOT_READY_REASON_CODE_MAX
+};
+
+/**
+ * struct scic_port_end_point_properties - This structure defines the
+ * properties that can be retrieved for each end-point local or remote
+ * (attached) port in the controller.
+ *
+ *
+ */
+struct scic_port_end_point_properties {
+ /**
+ * This field indicates the SAS address for the associated end
+ * point in the port.
+ */
+ struct sci_sas_address sas_address;
+
+ /**
+ * This field indicates the protocols supported by the associated
+ * end-point in the port.
+ */
+ struct sci_sas_identify_address_frame_protocols protocols;
+
+};
+
+/**
+ * struct scic_port_properties - This structure defines the properties that can
+ * be retrieved for each port in the controller.
+ *
+ *
+ */
+struct scic_port_properties {
+ /**
+ * This field specifies the logical index of the port (0 relative).
+ */
+ u32 index;
+
+ /**
+ * This field indicates the local end-point properties for port.
+ */
+ struct scic_port_end_point_properties local;
+
+ /**
+ * This field indicates the remote (attached) end-point properties
+ * for the port.
+ */
+ struct scic_port_end_point_properties remote;
+
+ /**
+ * This field specifies the phys contained inside the port.
+ */
+ u32 phy_mask;
+
+};
+
+/**
+ * scic_port_get_properties() - This method simply returns the properties
+ * regarding the port, such as: physical index, protocols, sas address, etc.
+ * @port: this parameter specifies the port for which to retrieve the physical
+ * index.
+ * @properties: This parameter specifies the properties structure into which to
+ * copy the requested information.
+ *
+ * Indicate if the user specified a valid port. SCI_SUCCESS This value is
+ * returned if the specified port was valid. SCI_FAILURE_INVALID_PORT This
+ * value is returned if the specified port is not valid. When this value is
+ * returned, no data is copied to the properties output parameter.
+ */
+enum sci_status scic_port_get_properties(
+ struct scic_sds_port *port,
+ struct scic_port_properties *properties);
+
+
+
+/**
+ * scic_port_start() - This method will make the port ready for operation.
+ * Prior to calling the start method IO operation is not possible.
+ * @port: This parameter specifies the port to be started.
+ *
+ * Indicate if the port was successfully started. SCI_SUCCESS This value is
+ * returned if the port was successfully started. SCI_WARNING_ALREADY_IN_STATE
+ * This value is returned if the port is in the process of starting.
+ * SCI_FAILURE_INVALID_PORT This value is returned if the supplied port is not
+ * valid. SCI_FAILURE_INVALID_STATE This value is returned if a start operation
+ * can't be completed due to the state of port.
+ */
+enum sci_status scic_port_start(
+ struct scic_sds_port *port);
+
+/**
+ * scic_port_stop() - This method will make the port no longer ready for
+ * operation. After invoking this method IO operation is not possible.
+ * @port: This parameter specifies the port to be stopped.
+ *
+ * Indicate if the port was successfully stopped. SCI_SUCCESS This value is
+ * returned if the port was successfully stopped. SCI_WARNING_ALREADY_IN_STATE
+ * This value is returned if the port is already stopped or in the process of
+ * stopping. SCI_FAILURE_INVALID_PORT This value is returned if the supplied
+ * port is not valid. SCI_FAILURE_INVALID_STATE This value is returned if a
+ * stop operation can't be completed due to the state of port.
+ */
+enum sci_status scic_port_stop(
+ struct scic_sds_port *port);
+
+/**
+ * scic_port_hard_reset() - This method will request the SCI implementation to
+ * perform a HARD RESET on the SAS Port. If/When the HARD RESET completes
+ * the SCI user will be notified via an SCI OS callback indicating a direct
+ * attached device was found.
+ * @port: a handle corresponding to the SAS port to be hard reset.
+ * @reset_timeout: This parameter specifies the number of milliseconds in which
+ * the port reset operation should complete.
+ *
+ * The SCI User callback in SCIC_USER_CALLBACKS_T will only be called once for
+ * each phy in the SAS Port at completion of the hard reset sequence. Return a
+ * status indicating whether the hard reset started successfully. SCI_SUCCESS
+ * This value is returned if the hard reset operation started successfully.
+ */
+enum sci_status scic_port_hard_reset(
+ struct scic_sds_port *port,
+ u32 reset_timeout);
+
+/**
+ * scic_port_enable_broadcast_change_notification() - This API method enables
+ * the broadcast change notification from underneath hardware.
+ * @port: The port upon which broadcast change notifications (BCN) are to be
+ * enabled.
+ *
+ */
+void scic_port_enable_broadcast_change_notification(
+ struct scic_sds_port *port);
+
+
+#endif /* _SCIC_PORT_H_ */
+
diff --git a/drivers/scsi/isci/core/scic_remote_device.h b/drivers/scsi/isci/core/scic_remote_device.h
new file mode 100644
index 000000000000..e8c04592763e
--- /dev/null
+++ b/drivers/scsi/isci/core/scic_remote_device.h
@@ -0,0 +1,295 @@
+/*
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Intel Corporation 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
+ * OWNER 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.
+ */
+
+#ifndef _SCIC_REMOTE_DEVICE_H_
+#define _SCIC_REMOTE_DEVICE_H_
+
+/**
+ * This file contains all of the interface methods that can be called by an
+ * SCIC user on the device object.
+ *
+ *
+ */
+
+
+#include "sci_types.h"
+#include "sci_status.h"
+#include "intel_sas.h"
+
+struct scic_sds_port;
+struct scic_sds_remote_device;
+
+/**
+ *
+ *
+ *
+ */
+enum scic_remote_device_not_ready_reason_code {
+ SCIC_REMOTE_DEVICE_NOT_READY_START_REQUESTED,
+ SCIC_REMOTE_DEVICE_NOT_READY_STOP_REQUESTED,
+ SCIC_REMOTE_DEVICE_NOT_READY_SATA_REQUEST_STARTED,
+ SCIC_REMOTE_DEVICE_NOT_READY_SATA_SDB_ERROR_FIS_RECEIVED,
+ SCIC_REMOTE_DEVICE_NOT_READY_SMP_REQUEST_STARTED,
+
+ SCIC_REMOTE_DEVICE_NOT_READY_REASON_CODE_MAX
+
+};
+
+/**
+ * scic_remote_device_get_object_size() - This method simply returns the
+ * maximum memory space needed to store a remote device object.
+ *
+ * a positive integer value indicating the size (in bytes) of the remote device
+ * object.
+ */
+u32 scic_remote_device_get_object_size(
+ void);
+
+struct scic_sds_port;
+struct scic_sds_remote_device;
+/**
+ * scic_remote_device_construct() - This method will perform the construction
+ * common to all remote device objects.
+ * @sci_port: SAS/SATA port through which this device is accessed.
+ * @sci_dev: remote device to construct
+ *
+ * It isn't necessary to call scic_remote_device_destruct() for device objects
+ * that have only called this method for construction. Once subsequent
+ * construction methods have been invoked (e.g.
+ * scic_remote_device_da_construct()), then destruction should occur. none
+ */
+void scic_remote_device_construct(struct scic_sds_port *sci_port,
+ struct scic_sds_remote_device *sci_dev);
+
+/**
+ * scic_remote_device_da_construct() - This method will construct a
+ * SCIC_REMOTE_DEVICE object for a direct attached (da) device. The
+ * information (e.g. IAF, Signature FIS, etc.) necessary to build the device
+ * is known to the SCI Core since it is contained in the scic_phy object.
+ * @remote_device: This parameter specifies the remote device to be destructed.
+ *
+ * The user must have previously called scic_remote_device_construct() Remote
+ * device objects are a limited resource. As such, they must be protected.
+ * Thus calls to construct and destruct are mutually exclusive and
+ * non-reentrant. Indicate if the remote device was successfully constructed.
+ * SCI_SUCCESS Returned if the device was successfully constructed.
+ * SCI_FAILURE_DEVICE_EXISTS Returned if the device has already been
+ * constructed. If it's an additional phy for the target, then call
+ * scic_remote_device_da_add_phy(). SCI_FAILURE_UNSUPPORTED_PROTOCOL Returned
+ * if the supplied parameters necessitate creation of a remote device for which
+ * the protocol is not supported by the underlying controller hardware.
+ * SCI_FAILURE_INSUFFICIENT_RESOURCES This value is returned if the core
+ * controller associated with the supplied parameters is unable to support
+ * additional remote devices.
+ */
+enum sci_status scic_remote_device_da_construct(
+ struct scic_sds_remote_device *remote_device);
+
+/**
+ * scic_remote_device_ea_construct() - This method will construct an
+ * SCIC_REMOTE_DEVICE object for an expander attached (ea) device from an
+ * SMP Discover Response.
+ * @remote_device: This parameter specifies the remote device to be destructed.
+ * @discover_response: This parameter specifies the SMP Discovery Response to
+ * be used in device creation.
+ *
+ * The user must have previously called scic_remote_device_construct() Remote
+ * device objects are a limited resource. As such, they must be protected.
+ * Thus calls to construct and destruct are mutually exclusive and
+ * non-reentrant. Indicate if the remote device was successfully constructed.
+ * SCI_SUCCESS Returned if the device was successfully constructed.
+ * SCI_FAILURE_DEVICE_EXISTS Returned if the device has already been
+ * constructed. If it's an additional phy for the target, then call
+ * scic_ea_remote_device_add_phy(). SCI_FAILURE_UNSUPPORTED_PROTOCOL Returned
+ * if the supplied parameters necessitate creation of a remote device for which
+ * the protocol is not supported by the underlying controller hardware.
+ * SCI_FAILURE_INSUFFICIENT_RESOURCES This value is returned if the core
+ * controller associated with the supplied parameters is unable to support
+ * additional remote devices.
+ */
+enum sci_status scic_remote_device_ea_construct(
+ struct scic_sds_remote_device *remote_device,
+ struct smp_response_discover *discover_response);
+
+/**
+ * scic_remote_device_destruct() - This method is utilized to free up a core's
+ * remote device object.
+ * @remote_device: This parameter specifies the remote device to be destructed.
+ *
+ * Remote device objects are a limited resource. As such, they must be
+ * protected. Thus calls to construct and destruct are mutually exclusive and
+ * non-reentrant. The return value shall indicate if the device was
+ * successfully destructed or if some failure occurred. enum sci_status This value
+ * is returned if the device is successfully destructed.
+ * SCI_FAILURE_INVALID_REMOTE_DEVICE This value is returned if the supplied
+ * device isn't valid (e.g. it's already been destoryed, the handle isn't
+ * valid, etc.).
+ */
+enum sci_status scic_remote_device_destruct(
+ struct scic_sds_remote_device *remote_device);
+
+
+
+
+
+/**
+ * scic_remote_device_start() - This method will start the supplied remote
+ * device. This method enables normal IO requests to flow through to the
+ * remote device.
+ * @remote_device: This parameter specifies the device to be started.
+ * @timeout: This parameter specifies the number of milliseconds in which the
+ * start operation should complete.
+ *
+ * An indication of whether the device was successfully started. SCI_SUCCESS
+ * This value is returned if the device was successfully started.
+ * SCI_FAILURE_INVALID_PHY This value is returned if the user attempts to start
+ * the device when there have been no phys added to it.
+ */
+enum sci_status scic_remote_device_start(
+ struct scic_sds_remote_device *remote_device,
+ u32 timeout);
+
+/**
+ * scic_remote_device_stop() - This method will stop both transmission and
+ * reception of link activity for the supplied remote device. This method
+ * disables normal IO requests from flowing through to the remote device.
+ * @remote_device: This parameter specifies the device to be stopped.
+ * @timeout: This parameter specifies the number of milliseconds in which the
+ * stop operation should complete.
+ *
+ * An indication of whether the device was successfully stopped. SCI_SUCCESS
+ * This value is returned if the transmission and reception for the device was
+ * successfully stopped.
+ */
+enum sci_status scic_remote_device_stop(
+ struct scic_sds_remote_device *remote_device,
+ u32 timeout);
+
+/**
+ * scic_remote_device_reset() - This method will reset the device making it
+ * ready for operation. This method must be called anytime the device is
+ * reset either through a SMP phy control or a port hard reset request.
+ * @remote_device: This parameter specifies the device to be reset.
+ *
+ * This method does not actually cause the device hardware to be reset. This
+ * method resets the software object so that it will be operational after a
+ * device hardware reset completes. An indication of whether the device reset
+ * was accepted. SCI_SUCCESS This value is returned if the device reset is
+ * started.
+ */
+enum sci_status scic_remote_device_reset(
+ struct scic_sds_remote_device *remote_device);
+
+/**
+ * scic_remote_device_reset_complete() - This method informs the device object
+ * that the reset operation is complete and the device can resume operation
+ * again.
+ * @remote_device: This parameter specifies the device which is to be informed
+ * of the reset complete operation.
+ *
+ * An indication that the device is resuming operation. SCI_SUCCESS the device
+ * is resuming operation.
+ */
+enum sci_status scic_remote_device_reset_complete(
+ struct scic_sds_remote_device *remote_device);
+
+
+
+/**
+ * scic_remote_device_get_connection_rate() - This method simply returns the
+ * link rate at which communications to the remote device occur.
+ * @remote_device: This parameter specifies the device for which to get the
+ * connection rate.
+ *
+ * Return the link rate at which we transfer for the supplied remote device.
+ */
+enum sci_sas_link_rate scic_remote_device_get_connection_rate(
+ struct scic_sds_remote_device *remote_device);
+
+/**
+ * scic_remote_device_get_protocols() - This method will indicate which
+ * protocols are supported by this remote device.
+ * @remote_device: This parameter specifies the device for which to return the
+ * protocol.
+ * @protocols: This parameter specifies the output values, from the remote
+ * device object, which indicate the protocols supported by the supplied
+ * remote_device.
+ *
+ * The type of protocols supported by this device. The values are returned as
+ * part of a bit mask in order to allow for multi-protocol support.
+ */
+void scic_remote_device_get_protocols(
+ struct scic_sds_remote_device *remote_device,
+ struct smp_discover_response_protocols *protocols);
+
+
+#if !defined(DISABLE_ATAPI)
+/**
+ * scic_remote_device_is_atapi() -
+ * @this_device: The device whose type is to be decided.
+ *
+ * This method first decide whether a device is a stp target, then decode the
+ * signature fis of a DA STP device to tell whether it is a standard end disk
+ * or an ATAPI device. bool Indicate a device is ATAPI device or not.
+ */
+bool scic_remote_device_is_atapi(
+ struct scic_sds_remote_device *device_handle);
+#else /* !defined(DISABLE_ATAPI) */
+#define scic_remote_device_is_atapi(device_handle) false
+#endif /* !defined(DISABLE_ATAPI) */
+
+
+#endif /* _SCIC_REMOTE_DEVICE_H_ */
+
diff --git a/drivers/scsi/isci/core/scic_sds_controller.c b/drivers/scsi/isci/core/scic_sds_controller.c
new file mode 100644
index 000000000000..35f7796df661
--- /dev/null
+++ b/drivers/scsi/isci/core/scic_sds_controller.c
@@ -0,0 +1,4147 @@
+/*
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Intel Corporation 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
+ * OWNER 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.
+ */
+
+#include <linux/device.h>
+#include "scic_controller.h"
+#include "scic_phy.h"
+#include "scic_port.h"
+#include "scic_remote_device.h"
+#include "scic_sds_controller.h"
+#include "scic_sds_controller_registers.h"
+#include "scic_sds_pci.h"
+#include "scic_sds_phy.h"
+#include "scic_sds_port_configuration_agent.h"
+#include "scic_sds_port.h"
+#include "scic_sds_remote_device.h"
+#include "scic_sds_request.h"
+#include "scic_user_callback.h"
+#include "sci_environment.h"
+#include "sci_util.h"
+#include "scu_completion_codes.h"
+#include "scu_constants.h"
+#include "scu_event_codes.h"
+#include "scu_remote_node_context.h"
+#include "scu_task_context.h"
+#include "scu_unsolicited_frame.h"
+
+#define SCU_CONTEXT_RAM_INIT_STALL_TIME 200
+
+/**
+ * smu_dcc_get_max_ports() -
+ *
+ * This macro returns the maximum number of logical ports supported by the
+ * hardware. The caller passes in the value read from the device context
+ * capacity register and this macro will mash and shift the value appropriately.
+ */
+#define smu_dcc_get_max_ports(dcc_value) \
+ (\
+ (((dcc_value) & SMU_DEVICE_CONTEXT_CAPACITY_MAX_LP_MASK) \
+ >> SMU_DEVICE_CONTEXT_CAPACITY_MAX_LP_SHIFT) + 1 \
+ )
+
+/**
+ * smu_dcc_get_max_task_context() -
+ *
+ * This macro returns the maximum number of task contexts supported by the
+ * hardware. The caller passes in the value read from the device context
+ * capacity register and this macro will mash and shift the value appropriately.
+ */
+#define smu_dcc_get_max_task_context(dcc_value) \
+ (\
+ (((dcc_value) & SMU_DEVICE_CONTEXT_CAPACITY_MAX_TC_MASK) \
+ >> SMU_DEVICE_CONTEXT_CAPACITY_MAX_TC_SHIFT) + 1 \
+ )
+
+/**
+ * smu_dcc_get_max_remote_node_context() -
+ *
+ * This macro returns the maximum number of remote node contexts supported by
+ * the hardware. The caller passes in the value read from the device context
+ * capacity register and this macro will mash and shift the value appropriately.
+ */
+#define smu_dcc_get_max_remote_node_context(dcc_value) \
+ (\
+ (((dcc_value) & SMU_DEVICE_CONTEXT_CAPACITY_MAX_RNC_MASK) \
+ >> SMU_DEVICE_CONTEXT_CAPACITY_MAX_RNC_SHIFT) + 1 \
+ )
+
+
+static void scic_sds_controller_power_control_timer_handler(
+ void *controller);
+#define SCIC_SDS_CONTROLLER_MIN_TIMER_COUNT 3
+#define SCIC_SDS_CONTROLLER_MAX_TIMER_COUNT 3
+
+/**
+ *
+ *
+ * The number of milliseconds to wait for a phy to start.
+ */
+#define SCIC_SDS_CONTROLLER_PHY_START_TIMEOUT 100
+
+/**
+ *
+ *
+ * The number of milliseconds to wait while a given phy is consuming power
+ * before allowing another set of phys to consume power. Ultimately, this will
+ * be specified by OEM parameter.
+ */
+#define SCIC_SDS_CONTROLLER_POWER_CONTROL_INTERVAL 500
+
+/**
+ * COMPLETION_QUEUE_CYCLE_BIT() -
+ *
+ * This macro will return the cycle bit of the completion queue entry
+ */
+#define COMPLETION_QUEUE_CYCLE_BIT(x) ((x) & 0x80000000)
+
+/**
+ * NORMALIZE_GET_POINTER() -
+ *
+ * This macro will normalize the completion queue get pointer so its value can
+ * be used as an index into an array
+ */
+#define NORMALIZE_GET_POINTER(x) \
+ ((x) & SMU_COMPLETION_QUEUE_GET_POINTER_MASK)
+
+/**
+ * NORMALIZE_PUT_POINTER() -
+ *
+ * This macro will normalize the completion queue put pointer so its value can
+ * be used as an array inde
+ */
+#define NORMALIZE_PUT_POINTER(x) \
+ ((x) & SMU_COMPLETION_QUEUE_PUT_POINTER_MASK)
+
+
+/**
+ * NORMALIZE_GET_POINTER_CYCLE_BIT() -
+ *
+ * This macro will normalize the completion queue cycle pointer so it matches
+ * the completion queue cycle bit
+ */
+#define NORMALIZE_GET_POINTER_CYCLE_BIT(x) \
+ ((SMU_CQGR_CYCLE_BIT & (x)) << (31 - SMU_COMPLETION_QUEUE_GET_CYCLE_BIT_SHIFT))
+
+/**
+ * NORMALIZE_EVENT_POINTER() -
+ *
+ * This macro will normalize the completion queue event entry so its value can
+ * be used as an index.
+ */
+#define NORMALIZE_EVENT_POINTER(x) \
+ (\
+ ((x) & SMU_COMPLETION_QUEUE_GET_EVENT_POINTER_MASK) \
+ >> SMU_COMPLETION_QUEUE_GET_EVENT_POINTER_SHIFT \
+ )
+
+/**
+ * INCREMENT_COMPLETION_QUEUE_GET() -
+ *
+ * This macro will increment the controllers completion queue index value and
+ * possibly toggle the cycle bit if the completion queue index wraps back to 0.
+ */
+#define INCREMENT_COMPLETION_QUEUE_GET(controller, index, cycle) \
+ INCREMENT_QUEUE_GET(\
+ (index), \
+ (cycle), \
+ (controller)->completion_queue_entries, \
+ SMU_CQGR_CYCLE_BIT \
+ )
+
+/**
+ * INCREMENT_EVENT_QUEUE_GET() -
+ *
+ * This macro will increment the controllers event queue index value and
+ * possibly toggle the event cycle bit if the event queue index wraps back to 0.
+ */
+#define INCREMENT_EVENT_QUEUE_GET(controller, index, cycle) \
+ INCREMENT_QUEUE_GET(\
+ (index), \
+ (cycle), \
+ (controller)->completion_event_entries, \
+ SMU_CQGR_EVENT_CYCLE_BIT \
+ )
+
+struct sci_base_memory_descriptor_list *
+sci_controller_get_memory_descriptor_list_handle(struct scic_sds_controller *scic)
+{
+ return &scic->parent.mdl;
+}
+
+/*
+ * ****************************************************************************-
+ * * SCIC SDS Controller Initialization Methods
+ * ****************************************************************************- */
+
+/**
+ * This timer is used to start another phy after we have given up on the
+ * previous phy to transition to the ready state.
+ *
+ *
+ */
+static void scic_sds_controller_phy_startup_timeout_handler(
+ void *controller)
+{
+ enum sci_status status;
+ struct scic_sds_controller *this_controller;
+
+ this_controller = (struct scic_sds_controller *)controller;
+
+ this_controller->phy_startup_timer_pending = false;
+
+ status = SCI_FAILURE;
+
+ while (status != SCI_SUCCESS) {
+ status = scic_sds_controller_start_next_phy(this_controller);
+ }
+}
+
+/**
+ *
+ *
+ * This method initializes the phy startup operations for controller start.
+ */
+void scic_sds_controller_initialize_phy_startup(
+ struct scic_sds_controller *this_controller)
+{
+ this_controller->phy_startup_timer = scic_cb_timer_create(
+ this_controller,
+ scic_sds_controller_phy_startup_timeout_handler,
+ this_controller
+ );
+
+ this_controller->next_phy_to_start = 0;
+ this_controller->phy_startup_timer_pending = false;
+}
+
+/**
+ *
+ *
+ * This method initializes the power control operations for the controller
+ * object.
+ */
+void scic_sds_controller_initialize_power_control(
+ struct scic_sds_controller *this_controller)
+{
+ this_controller->power_control.timer = scic_cb_timer_create(
+ this_controller,
+ scic_sds_controller_power_control_timer_handler,
+ this_controller
+ );
+
+ memset(
+ this_controller->power_control.requesters,
+ 0,
+ sizeof(this_controller->power_control.requesters)
+ );
+
+ this_controller->power_control.phys_waiting = 0;
+}
+
+/* --------------------------------------------------------------------------- */
+
+#define SCU_REMOTE_NODE_CONTEXT_ALIGNMENT (32)
+#define SCU_TASK_CONTEXT_ALIGNMENT (256)
+#define SCU_UNSOLICITED_FRAME_ADDRESS_ALIGNMENT (64)
+#define SCU_UNSOLICITED_FRAME_BUFFER_ALIGNMENT (1024)
+#define SCU_UNSOLICITED_FRAME_HEADER_ALIGNMENT (64)
+
+/* --------------------------------------------------------------------------- */
+
+/**
+ * This method builds the memory descriptor table for this controller.
+ * @this_controller: This parameter specifies the controller object for which
+ * to build the memory table.
+ *
+ */
+static void scic_sds_controller_build_memory_descriptor_table(
+ struct scic_sds_controller *this_controller)
+{
+ sci_base_mde_construct(
+ &this_controller->memory_descriptors[SCU_MDE_COMPLETION_QUEUE],
+ SCU_COMPLETION_RAM_ALIGNMENT,
+ (sizeof(u32) * this_controller->completion_queue_entries),
+ (SCI_MDE_ATTRIBUTE_CACHEABLE | SCI_MDE_ATTRIBUTE_PHYSICALLY_CONTIGUOUS)
+ );
+
+ sci_base_mde_construct(
+ &this_controller->memory_descriptors[SCU_MDE_REMOTE_NODE_CONTEXT],
+ SCU_REMOTE_NODE_CONTEXT_ALIGNMENT,
+ this_controller->remote_node_entries * sizeof(union scu_remote_node_context),
+ SCI_MDE_ATTRIBUTE_PHYSICALLY_CONTIGUOUS
+ );
+
+ sci_base_mde_construct(
+ &this_controller->memory_descriptors[SCU_MDE_TASK_CONTEXT],
+ SCU_TASK_CONTEXT_ALIGNMENT,
+ this_controller->task_context_entries * sizeof(struct scu_task_context),
+ SCI_MDE_ATTRIBUTE_PHYSICALLY_CONTIGUOUS
+ );
+
+ /*
+ * The UF buffer address table size must be programmed to a power
+ * of 2. Find the first power of 2 that is equal to or greater then
+ * the number of unsolicited frame buffers to be utilized. */
+ scic_sds_unsolicited_frame_control_set_address_table_count(
+ &this_controller->uf_control
+ );
+
+ sci_base_mde_construct(
+ &this_controller->memory_descriptors[SCU_MDE_UF_BUFFER],
+ SCU_UNSOLICITED_FRAME_BUFFER_ALIGNMENT,
+ scic_sds_unsolicited_frame_control_get_mde_size(this_controller->uf_control),
+ SCI_MDE_ATTRIBUTE_PHYSICALLY_CONTIGUOUS
+ );
+}
+
+/**
+ * This method validates the driver supplied memory descriptor table.
+ * @this_controller:
+ *
+ * enum sci_status
+ */
+enum sci_status scic_sds_controller_validate_memory_descriptor_table(
+ struct scic_sds_controller *this_controller)
+{
+ bool mde_list_valid;
+
+ mde_list_valid = sci_base_mde_is_valid(
+ &this_controller->memory_descriptors[SCU_MDE_COMPLETION_QUEUE],
+ SCU_COMPLETION_RAM_ALIGNMENT,
+ (sizeof(u32) * this_controller->completion_queue_entries),
+ (SCI_MDE_ATTRIBUTE_CACHEABLE | SCI_MDE_ATTRIBUTE_PHYSICALLY_CONTIGUOUS)
+ );
+
+ if (mde_list_valid == false)
+ return SCI_FAILURE_UNSUPPORTED_INFORMATION_FIELD;
+
+ mde_list_valid = sci_base_mde_is_valid(
+ &this_controller->memory_descriptors[SCU_MDE_REMOTE_NODE_CONTEXT],
+ SCU_REMOTE_NODE_CONTEXT_ALIGNMENT,
+ this_controller->remote_node_entries * sizeof(union scu_remote_node_context),
+ SCI_MDE_ATTRIBUTE_PHYSICALLY_CONTIGUOUS
+ );
+
+ if (mde_list_valid == false)
+ return SCI_FAILURE_UNSUPPORTED_INFORMATION_FIELD;
+
+ mde_list_valid = sci_base_mde_is_valid(
+ &this_controller->memory_descriptors[SCU_MDE_TASK_CONTEXT],
+ SCU_TASK_CONTEXT_ALIGNMENT,
+ this_controller->task_context_entries * sizeof(struct scu_task_context),
+ SCI_MDE_ATTRIBUTE_PHYSICALLY_CONTIGUOUS
+ );
+
+ if (mde_list_valid == false)
+ return SCI_FAILURE_UNSUPPORTED_INFORMATION_FIELD;
+
+ mde_list_valid = sci_base_mde_is_valid(
+ &this_controller->memory_descriptors[SCU_MDE_UF_BUFFER],
+ SCU_UNSOLICITED_FRAME_BUFFER_ALIGNMENT,
+ scic_sds_unsolicited_frame_control_get_mde_size(this_controller->uf_control),
+ SCI_MDE_ATTRIBUTE_PHYSICALLY_CONTIGUOUS
+ );
+
+ if (mde_list_valid == false)
+ return SCI_FAILURE_UNSUPPORTED_INFORMATION_FIELD;
+
+ return SCI_SUCCESS;
+}
+
+/**
+ * This method initializes the controller with the physical memory addresses
+ * that are used to communicate with the driver.
+ * @this_controller:
+ *
+ */
+void scic_sds_controller_ram_initialization(
+ struct scic_sds_controller *this_controller)
+{
+ struct sci_physical_memory_descriptor *mde;
+
+ /*
+ * The completion queue is actually placed in cacheable memory
+ * Therefore it no longer comes out of memory in the MDL. */
+ mde = &this_controller->memory_descriptors[SCU_MDE_COMPLETION_QUEUE];
+ this_controller->completion_queue = (u32 *)mde->virtual_address;
+ SMU_CQBAR_WRITE(this_controller, mde->physical_address);
+
+ /*
+ * Program the location of the Remote Node Context table
+ * into the SCU. */
+ mde = &this_controller->memory_descriptors[SCU_MDE_REMOTE_NODE_CONTEXT];
+ this_controller->remote_node_context_table = (union scu_remote_node_context *)
+ mde->virtual_address;
+ SMU_RNCBAR_WRITE(this_controller, mde->physical_address);
+
+ /* Program the location of the Task Context table into the SCU. */
+ mde = &this_controller->memory_descriptors[SCU_MDE_TASK_CONTEXT];
+ this_controller->task_context_table = (struct scu_task_context *)
+ mde->virtual_address;
+ SMU_HTTBAR_WRITE(this_controller, mde->physical_address);
+
+ mde = &this_controller->memory_descriptors[SCU_MDE_UF_BUFFER];
+ scic_sds_unsolicited_frame_control_construct(
+ &this_controller->uf_control, mde, this_controller
+ );
+
+ /*
+ * Inform the silicon as to the location of the UF headers and
+ * address table. */
+ SCU_UFHBAR_WRITE(
+ this_controller,
+ this_controller->uf_control.headers.physical_address);
+ SCU_PUFATHAR_WRITE(
+ this_controller,
+ this_controller->uf_control.address_table.physical_address);
+}
+
+/**
+ * This method initializes the task context data for the controller.
+ * @this_controller:
+ *
+ */
+void scic_sds_controller_assign_task_entries(
+ struct scic_sds_controller *this_controller)
+{
+ u32 task_assignment;
+
+ /*
+ * Assign all the TCs to function 0
+ * TODO: Do we actually need to read this register to write it back? */
+ task_assignment = SMU_TCA_READ(this_controller, 0);
+
+ task_assignment =
+ (
+ task_assignment
+ | (SMU_TCA_GEN_VAL(STARTING, 0))
+ | (SMU_TCA_GEN_VAL(ENDING, this_controller->task_context_entries - 1))
+ | (SMU_TCA_GEN_BIT(RANGE_CHECK_ENABLE))
+ );
+
+ SMU_TCA_WRITE(this_controller, 0, task_assignment);
+}
+
+/**
+ * This method initializes the hardware completion queue.
+ *
+ *
+ */
+void scic_sds_controller_initialize_completion_queue(
+ struct scic_sds_controller *this_controller)
+{
+ u32 index;
+ u32 completion_queue_control_value;
+ u32 completion_queue_get_value;
+ u32 completion_queue_put_value;
+
+ this_controller->completion_queue_get = 0;
+
+ completion_queue_control_value = (
+ SMU_CQC_QUEUE_LIMIT_SET(this_controller->completion_queue_entries - 1)
+ | SMU_CQC_EVENT_LIMIT_SET(this_controller->completion_event_entries - 1)
+ );
+
+ SMU_CQC_WRITE(this_controller, completion_queue_control_value);
+
+ /* Set the completion queue get pointer and enable the queue */
+ completion_queue_get_value = (
+ (SMU_CQGR_GEN_VAL(POINTER, 0))
+ | (SMU_CQGR_GEN_VAL(EVENT_POINTER, 0))
+ | (SMU_CQGR_GEN_BIT(ENABLE))
+ | (SMU_CQGR_GEN_BIT(EVENT_ENABLE))
+ );
+
+ SMU_CQGR_WRITE(this_controller, completion_queue_get_value);
+
+ /* Set the completion queue put pointer */
+ completion_queue_put_value = (
+ (SMU_CQPR_GEN_VAL(POINTER, 0))
+ | (SMU_CQPR_GEN_VAL(EVENT_POINTER, 0))
+ );
+
+ SMU_CQPR_WRITE(this_controller, completion_queue_put_value);
+
+ /* Initialize the cycle bit of the completion queue entries */
+ for (index = 0; index < this_controller->completion_queue_entries; index++) {
+ /*
+ * If get.cycle_bit != completion_queue.cycle_bit
+ * its not a valid completion queue entry
+ * so at system start all entries are invalid */
+ this_controller->completion_queue[index] = 0x80000000;
+ }
+}
+
+/**
+ * This method initializes the hardware unsolicited frame queue.
+ *
+ *
+ */
+void scic_sds_controller_initialize_unsolicited_frame_queue(
+ struct scic_sds_controller *this_controller)
+{
+ u32 frame_queue_control_value;
+ u32 frame_queue_get_value;
+ u32 frame_queue_put_value;
+
+ /* Write the queue size */
+ frame_queue_control_value =
+ SCU_UFQC_GEN_VAL(QUEUE_SIZE, this_controller->uf_control.address_table.count);
+
+ SCU_UFQC_WRITE(this_controller, frame_queue_control_value);
+
+ /* Setup the get pointer for the unsolicited frame queue */
+ frame_queue_get_value = (
+ SCU_UFQGP_GEN_VAL(POINTER, 0)
+ | SCU_UFQGP_GEN_BIT(ENABLE_BIT)
+ );
+
+ SCU_UFQGP_WRITE(this_controller, frame_queue_get_value);
+
+ /* Setup the put pointer for the unsolicited frame queue */
+ frame_queue_put_value = SCU_UFQPP_GEN_VAL(POINTER, 0);
+
+ SCU_UFQPP_WRITE(this_controller, frame_queue_put_value);
+}
+
+/**
+ * This method enables the hardware port task scheduler.
+ *
+ *
+ */
+void scic_sds_controller_enable_port_task_scheduler(
+ struct scic_sds_controller *this_controller)
+{
+ u32 port_task_scheduler_value;
+
+ port_task_scheduler_value = SCU_PTSGCR_READ(this_controller);
+
+ port_task_scheduler_value |=
+ (SCU_PTSGCR_GEN_BIT(ETM_ENABLE) | SCU_PTSGCR_GEN_BIT(PTSG_ENABLE));
+
+ SCU_PTSGCR_WRITE(this_controller, port_task_scheduler_value);
+}
+
+/* --------------------------------------------------------------------------- */
+
+/**
+ *
+ *
+ * This macro is used to delay between writes to the AFE registers during AFE
+ * initialization.
+ */
+#define AFE_REGISTER_WRITE_DELAY 10
+
+static bool is_a0(void)
+{
+ return isci_si_rev == ISCI_SI_REVA0;
+}
+
+static bool is_a2(void)
+{
+ return isci_si_rev == ISCI_SI_REVA2;
+}
+
+static bool is_b0(void)
+{
+ return isci_si_rev > ISCI_SI_REVA2;
+}
+
+/* Initialize the AFE for this phy index. We need to read the AFE setup from
+ * the OEM parameters none
+ */
+void scic_sds_controller_afe_initialization(struct scic_sds_controller *scic)
+{
+ u32 afe_status;
+ u32 phy_id;
+
+ /* Clear DFX Status registers */
+ scu_afe_register_write(scic, afe_dfx_master_control0, 0x0081000f);
+ scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY);
+
+ /* Configure bias currents to normal */
+ if (is_a0())
+ scu_afe_register_write(scic, afe_bias_control, 0x00005500);
+ else
+ scu_afe_register_write(scic, afe_bias_control, 0x00005A00);
+
+
+ scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY);
+
+ /* Enable PLL */
+ if (is_b0())
+ scu_afe_register_write(scic, afe_pll_control0, 0x80040A08);
+ else
+ scu_afe_register_write(scic, afe_pll_control0, 0x80040908);
+
+ scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY);
+
+ /* Wait for the PLL to lock */
+ do {
+ afe_status = scu_afe_register_read(
+ scic, afe_common_block_status);
+ scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY);
+ } while ((afe_status & 0x00001000) == 0);
+
+ if (is_b0()) {
+ /* Shorten SAS SNW lock time (RxLock timer value from 76 us to 50 us) */
+ scu_afe_register_write(scic, afe_pmsn_master_control0, 0x7bcc96ad);
+ scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY);
+ }
+
+ for (phy_id = 0; phy_id < SCI_MAX_PHYS; phy_id++) {
+ if (is_b0()) {
+ /* Configure transmitter SSC parameters */
+ scu_afe_txreg_write(scic, phy_id, afe_tx_ssc_control, 0x00030000);
+ scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY);
+ } else {
+ /*
+ * All defaults, except the Receive Word Alignament/Comma Detect
+ * Enable....(0xe800) */
+ scu_afe_txreg_write(scic, phy_id, afe_xcvr_control0, 0x00004512);
+ scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY);
+
+ scu_afe_txreg_write(scic, phy_id, afe_xcvr_control1, 0x0050100F);
+ scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY);
+ }
+
+ /*
+ * Power up TX and RX out from power down (PWRDNTX and PWRDNRX)
+ * & increase TX int & ext bias 20%....(0xe85c) */
+ if (is_a0())
+ scu_afe_txreg_write(scic, phy_id, afe_channel_control, 0x000003D4);
+ else if (is_a2())
+ scu_afe_txreg_write(scic, phy_id, afe_channel_control, 0x000003F0);
+ else {
+ /* Power down TX and RX (PWRDNTX and PWRDNRX) */
+ scu_afe_txreg_write(scic, phy_id, afe_channel_control, 0x000003d7);
+ scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY);
+
+ /*
+ * Power up TX and RX out from power down (PWRDNTX and PWRDNRX)
+ * & increase TX int & ext bias 20%....(0xe85c) */
+ scu_afe_txreg_write(scic, phy_id, afe_channel_control, 0x000003d4);
+ }
+ scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY);
+
+ if (is_a0() || is_a2()) {
+ /* Enable TX equalization (0xe824) */
+ scu_afe_txreg_write(scic, phy_id, afe_tx_control, 0x00040000);
+ scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY);
+ }
+
+ /*
+ * RDPI=0x0(RX Power On), RXOOBDETPDNC=0x0, TPD=0x0(TX Power On),
+ * RDD=0x0(RX Detect Enabled) ....(0xe800) */
+ scu_afe_txreg_write(scic, phy_id, afe_xcvr_control0, 0x00004100);
+ scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY);
+
+ /* Leave DFE/FFE on */
+ if (is_a0())
+ scu_afe_txreg_write(scic, phy_id, afe_rx_ssc_control0, 0x3F09983F);
+ else if (is_a2())
+ scu_afe_txreg_write(scic, phy_id, afe_rx_ssc_control0, 0x3F11103F);
+ else {
+ scu_afe_txreg_write(scic, phy_id, afe_rx_ssc_control0, 0x3F11103F);
+ scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY);
+ /* Enable TX equalization (0xe824) */
+ scu_afe_txreg_write(scic, phy_id, afe_tx_control, 0x00040000);
+ }
+ scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY);
+
+ scu_afe_txreg_write(scic, phy_id, afe_tx_amp_control0, 0x000E7C03);
+ scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY);
+
+ scu_afe_txreg_write(scic, phy_id, afe_tx_amp_control1, 0x000E7C03);
+ scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY);
+
+ scu_afe_txreg_write(scic, phy_id, afe_tx_amp_control2, 0x000E7C03);
+ scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY);
+
+ scu_afe_txreg_write(scic, phy_id, afe_tx_amp_control3, 0x000E7C03);
+ scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY);
+ }
+
+ /* Transfer control to the PEs */
+ scu_afe_register_write(scic, afe_dfx_master_control0, 0x00010f00);
+ scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY);
+}
+
+/*
+ * ****************************************************************************-
+ * * SCIC SDS Controller Internal Start/Stop Routines
+ * ****************************************************************************- */
+
+
+/**
+ * This method will attempt to transition into the ready state for the
+ * controller and indicate that the controller start operation has completed
+ * if all criteria are met.
+ * @this_controller: This parameter indicates the controller object for which
+ * to transition to ready.
+ * @status: This parameter indicates the status value to be pass into the call
+ * to scic_cb_controller_start_complete().
+ *
+ * none.
+ */
+static void scic_sds_controller_transition_to_ready(
+ struct scic_sds_controller *this_controller,
+ enum sci_status status)
+{
+ if (this_controller->parent.state_machine.current_state_id
+ == SCI_BASE_CONTROLLER_STATE_STARTING) {
+ /*
+ * We move into the ready state, because some of the phys/ports
+ * may be up and operational. */
+ sci_base_state_machine_change_state(
+ scic_sds_controller_get_base_state_machine(this_controller),
+ SCI_BASE_CONTROLLER_STATE_READY
+ );
+
+ scic_cb_controller_start_complete(this_controller, status);
+ }
+}
+
+/**
+ * This method is the general timeout handler for the controller. It will take
+ * the correct timetout action based on the current controller state
+ */
+void scic_sds_controller_timeout_handler(
+ struct scic_sds_controller *scic)
+{
+ enum sci_base_controller_states current_state;
+
+ current_state = sci_base_state_machine_get_state(
+ scic_sds_controller_get_base_state_machine(scic));
+
+ if (current_state == SCI_BASE_CONTROLLER_STATE_STARTING) {
+ scic_sds_controller_transition_to_ready(
+ scic, SCI_FAILURE_TIMEOUT);
+ } else if (current_state == SCI_BASE_CONTROLLER_STATE_STOPPING) {
+ sci_base_state_machine_change_state(
+ scic_sds_controller_get_base_state_machine(scic),
+ SCI_BASE_CONTROLLER_STATE_FAILED);
+ scic_cb_controller_stop_complete(scic, SCI_FAILURE_TIMEOUT);
+ } else /* / @todo Now what do we want to do in this case? */
+ dev_err(scic_to_dev(scic),
+ "%s: Controller timer fired when controller was not "
+ "in a state being timed.\n",
+ __func__);
+}
+
+/**
+ * scic_sds_controller_get_port_configuration_mode
+ * @this_controller: This is the controller to use to determine if we are using
+ * manual or automatic port configuration.
+ *
+ * SCIC_PORT_CONFIGURATION_MODE
+ */
+enum SCIC_PORT_CONFIGURATION_MODE scic_sds_controller_get_port_configuration_mode(
+ struct scic_sds_controller *this_controller)
+{
+ u32 index;
+ enum SCIC_PORT_CONFIGURATION_MODE mode;
+
+ mode = SCIC_PORT_AUTOMATIC_CONFIGURATION_MODE;
+
+ for (index = 0; index < SCI_MAX_PORTS; index++) {
+ if (this_controller->oem_parameters.sds1.ports[index].phy_mask != 0) {
+ mode = SCIC_PORT_MANUAL_CONFIGURATION_MODE;
+ break;
+ }
+ }
+
+ return mode;
+}
+
+enum sci_status scic_sds_controller_stop_ports(struct scic_sds_controller *scic)
+{
+ u32 index;
+ enum sci_status port_status;
+ enum sci_status status = SCI_SUCCESS;
+
+ for (index = 0; index < scic->logical_port_entries; index++) {
+ port_status = scic_port_stop(&scic->port_table[index]);
+
+ if ((port_status != SCI_SUCCESS) &&
+ (port_status != SCI_FAILURE_INVALID_STATE)) {
+ status = SCI_FAILURE;
+
+ dev_warn(scic_to_dev(scic),
+ "%s: Controller stop operation failed to "
+ "stop port %d because of status %d.\n",
+ __func__,
+ scic->port_table[index].logical_port_index,
+ port_status);
+ }
+ }
+
+ return status;
+}
+
+/**
+ *
+ *
+ *
+ */
+static void scic_sds_controller_phy_timer_start(
+ struct scic_sds_controller *this_controller)
+{
+ scic_cb_timer_start(
+ this_controller,
+ this_controller->phy_startup_timer,
+ SCIC_SDS_CONTROLLER_PHY_START_TIMEOUT
+ );
+
+ this_controller->phy_startup_timer_pending = true;
+}
+
+/**
+ *
+ *
+ *
+ */
+void scic_sds_controller_phy_timer_stop(
+ struct scic_sds_controller *this_controller)
+{
+ scic_cb_timer_stop(
+ this_controller,
+ this_controller->phy_startup_timer
+ );
+
+ this_controller->phy_startup_timer_pending = false;
+}
+
+/**
+ * This method is called internally by the controller object to start the next
+ * phy on the controller. If all the phys have been starte, then this
+ * method will attempt to transition the controller to the READY state and
+ * inform the user (scic_cb_controller_start_complete()).
+ * @this_controller: This parameter specifies the controller object for which
+ * to start the next phy.
+ *
+ * enum sci_status
+ */
+enum sci_status scic_sds_controller_start_next_phy(
+ struct scic_sds_controller *this_controller)
+{
+ enum sci_status status;
+
+ status = SCI_SUCCESS;
+
+ if (this_controller->phy_startup_timer_pending == false) {
+ if (this_controller->next_phy_to_start == SCI_MAX_PHYS) {
+ bool is_controller_start_complete = true;
+ struct scic_sds_phy *the_phy;
+ u8 index;
+
+ for (index = 0; index < SCI_MAX_PHYS; index++) {
+ the_phy = &this_controller->phy_table[index];
+
+ if (scic_sds_phy_get_port(the_phy) != SCI_INVALID_HANDLE) {
+ /**
+ * The controller start operation is complete if and only
+ * if:
+ * - all links have been given an opportunity to start
+ * - have no indication of a connected device
+ * - have an indication of a connected device and it has
+ * finished the link training process.
+ */
+ if (
+ (
+ (the_phy->is_in_link_training == false)
+ && (the_phy->parent.state_machine.current_state_id
+ == SCI_BASE_PHY_STATE_INITIAL)
+ )
+ || (
+ (the_phy->is_in_link_training == false)
+ && (the_phy->parent.state_machine.current_state_id
+ == SCI_BASE_PHY_STATE_STOPPED)
+ )
+ || (
+ (the_phy->is_in_link_training == true)
+ && (the_phy->parent.state_machine.current_state_id
+ == SCI_BASE_PHY_STATE_STARTING)
+ )
+ ) {
+ is_controller_start_complete = false;
+ break;
+ }
+ }
+ }
+
+ /*
+ * The controller has successfully finished the start process.
+ * Inform the SCI Core user and transition to the READY state. */
+ if (is_controller_start_complete == true) {
+ scic_sds_controller_transition_to_ready(
+ this_controller, SCI_SUCCESS
+ );
+ scic_sds_controller_phy_timer_stop(this_controller);
+ }
+ } else {
+ struct scic_sds_phy *the_phy;
+
+ the_phy = &this_controller->phy_table[this_controller->next_phy_to_start];
+
+ if (
+ scic_sds_controller_get_port_configuration_mode(this_controller)
+ == SCIC_PORT_MANUAL_CONFIGURATION_MODE
+ ) {
+ if (scic_sds_phy_get_port(the_phy) == SCI_INVALID_HANDLE) {
+ this_controller->next_phy_to_start++;
+
+ /*
+ * Caution recursion ahead be forwarned
+ *
+ * The PHY was never added to a PORT in MPC mode so start the next phy in sequence
+ * This phy will never go link up and will not draw power the OEM parameters either
+ * configured the phy incorrectly for the PORT or it was never assigned to a PORT */
+ return scic_sds_controller_start_next_phy(this_controller);
+ }
+ }
+
+ status = scic_sds_phy_start(the_phy);
+
+ if (status == SCI_SUCCESS) {
+ scic_sds_controller_phy_timer_start(this_controller);
+ } else {
+ dev_warn(scic_to_dev(this_controller),
+ "%s: Controller stop operation failed "
+ "to stop phy %d because of status "
+ "%d.\n",
+ __func__,
+ this_controller->phy_table[this_controller->next_phy_to_start].phy_index,
+ status);
+ }
+
+ this_controller->next_phy_to_start++;
+ }
+ }
+
+ return status;
+}
+
+/**
+ *
+ * @this_controller:
+ *
+ * enum sci_status
+ */
+enum sci_status scic_sds_controller_stop_phys(
+ struct scic_sds_controller *this_controller)
+{
+ u32 index;
+ enum sci_status status;
+ enum sci_status phy_status;
+
+ status = SCI_SUCCESS;
+
+ for (index = 0; index < SCI_MAX_PHYS; index++) {
+ phy_status = scic_sds_phy_stop(&this_controller->phy_table[index]);
+
+ if (
+ (phy_status != SCI_SUCCESS)
+ && (phy_status != SCI_FAILURE_INVALID_STATE)
+ ) {
+ status = SCI_FAILURE;
+
+ dev_warn(scic_to_dev(this_controller),
+ "%s: Controller stop operation failed to stop "
+ "phy %d because of status %d.\n",
+ __func__,
+ this_controller->phy_table[index].phy_index, phy_status);
+ }
+ }
+
+ return status;
+}
+
+/**
+ *
+ * @this_controller:
+ *
+ * enum sci_status
+ */
+enum sci_status scic_sds_controller_stop_devices(
+ struct scic_sds_controller *this_controller)
+{
+ u32 index;
+ enum sci_status status;
+ enum sci_status device_status;
+
+ status = SCI_SUCCESS;
+
+ for (index = 0; index < this_controller->remote_node_entries; index++) {
+ if (this_controller->device_table[index] != SCI_INVALID_HANDLE) {
+ /* / @todo What timeout value do we want to provide to this request? */
+ device_status = scic_remote_device_stop(this_controller->device_table[index], 0);
+
+ if ((device_status != SCI_SUCCESS) &&
+ (device_status != SCI_FAILURE_INVALID_STATE)) {
+ dev_warn(scic_to_dev(this_controller),
+ "%s: Controller stop operation failed "
+ "to stop device 0x%p because of "
+ "status %d.\n",
+ __func__,
+ this_controller->device_table[index], device_status);
+ }
+ }
+ }
+
+ return status;
+}
+
+/*
+ * ****************************************************************************-
+ * * SCIC SDS Controller Power Control (Staggered Spinup)
+ * ****************************************************************************- */
+
+/**
+ *
+ *
+ * This method starts the power control timer for this controller object.
+ */
+static void scic_sds_controller_power_control_timer_start(
+ struct scic_sds_controller *this_controller)
+{
+ scic_cb_timer_start(
+ this_controller, this_controller->power_control.timer,
+ SCIC_SDS_CONTROLLER_POWER_CONTROL_INTERVAL
+ );
+
+ this_controller->power_control.timer_started = true;
+}
+
+/**
+ *
+ *
+ *
+ */
+static void scic_sds_controller_power_control_timer_handler(
+ void *controller)
+{
+ struct scic_sds_controller *this_controller;
+
+ this_controller = (struct scic_sds_controller *)controller;
+
+ if (this_controller->power_control.phys_waiting == 0) {
+ this_controller->power_control.timer_started = false;
+ } else {
+ struct scic_sds_phy *the_phy = NULL;
+ u8 i;
+
+ for (i = 0;
+ (i < SCI_MAX_PHYS)
+ && (this_controller->power_control.phys_waiting != 0);
+ i++) {
+ if (this_controller->power_control.requesters[i] != NULL) {
+ the_phy = this_controller->power_control.requesters[i];
+ this_controller->power_control.requesters[i] = NULL;
+ this_controller->power_control.phys_waiting--;
+ break;
+ }
+ }
+
+ /*
+ * It doesn't matter if the power list is empty, we need to start the
+ * timer in case another phy becomes ready. */
+ scic_sds_controller_power_control_timer_start(this_controller);
+
+ scic_sds_phy_consume_power_handler(the_phy);
+ }
+}
+
+/**
+ * This method inserts the phy in the stagger spinup control queue.
+ * @this_controller:
+ *
+ *
+ */
+void scic_sds_controller_power_control_queue_insert(
+ struct scic_sds_controller *this_controller,
+ struct scic_sds_phy *the_phy)
+{
+ BUG_ON(the_phy == NULL);
+
+ if (
+ (this_controller->power_control.timer_started)
+ && (this_controller->power_control.requesters[the_phy->phy_index] == NULL)
+ ) {
+ this_controller->power_control.requesters[the_phy->phy_index] = the_phy;
+ this_controller->power_control.phys_waiting++;
+ } else {
+ scic_sds_controller_power_control_timer_start(this_controller);
+ scic_sds_phy_consume_power_handler(the_phy);
+ }
+}
+
+/**
+ * This method removes the phy from the stagger spinup control queue.
+ * @this_controller:
+ *
+ *
+ */
+void scic_sds_controller_power_control_queue_remove(
+ struct scic_sds_controller *this_controller,
+ struct scic_sds_phy *the_phy)
+{
+ BUG_ON(the_phy == NULL);
+
+ if (this_controller->power_control.requesters[the_phy->phy_index] != NULL) {
+ this_controller->power_control.phys_waiting--;
+ }
+
+ this_controller->power_control.requesters[the_phy->phy_index] = NULL;
+}
+
+/*
+ * ****************************************************************************-
+ * * SCIC SDS Controller Completion Routines
+ * ****************************************************************************- */
+
+/**
+ * This method returns a true value if the completion queue has entries that
+ * can be processed
+ * @this_controller:
+ *
+ * bool true if the completion queue has entries to process false if the
+ * completion queue has no entries to process
+ */
+static bool scic_sds_controller_completion_queue_has_entries(
+ struct scic_sds_controller *this_controller)
+{
+ u32 get_value = this_controller->completion_queue_get;
+ u32 get_index = get_value & SMU_COMPLETION_QUEUE_GET_POINTER_MASK;
+
+ if (
+ NORMALIZE_GET_POINTER_CYCLE_BIT(get_value)
+ == COMPLETION_QUEUE_CYCLE_BIT(this_controller->completion_queue[get_index])
+ ) {
+ return true;
+ }
+
+ return false;
+}
+
+/* --------------------------------------------------------------------------- */
+
+/**
+ * This method processes a task completion notification. This is called from
+ * within the controller completion handler.
+ * @this_controller:
+ * @completion_entry:
+ *
+ */
+static void scic_sds_controller_task_completion(
+ struct scic_sds_controller *this_controller,
+ u32 completion_entry)
+{
+ u32 index;
+ struct scic_sds_request *io_request;
+
+ index = SCU_GET_COMPLETION_INDEX(completion_entry);
+ io_request = this_controller->io_request_table[index];
+
+ /* Make sure that we really want to process this IO request */
+ if (
+ (io_request != SCI_INVALID_HANDLE)
+ && (io_request->io_tag != SCI_CONTROLLER_INVALID_IO_TAG)
+ && (
+ scic_sds_io_tag_get_sequence(io_request->io_tag)
+ == this_controller->io_request_sequence[index]
+ )
+ ) {
+ /* Yep this is a valid io request pass it along to the io request handler */
+ scic_sds_io_request_tc_completion(io_request, completion_entry);
+ }
+}
+
+/**
+ * This method processes an SDMA completion event. This is called from within
+ * the controller completion handler.
+ * @this_controller:
+ * @completion_entry:
+ *
+ */
+static void scic_sds_controller_sdma_completion(
+ struct scic_sds_controller *this_controller,
+ u32 completion_entry)
+{
+ u32 index;
+ struct scic_sds_request *io_request;
+ struct scic_sds_remote_device *device;
+
+ index = SCU_GET_COMPLETION_INDEX(completion_entry);
+
+ switch (scu_get_command_request_type(completion_entry)) {
+ case SCU_CONTEXT_COMMAND_REQUEST_TYPE_POST_TC:
+ case SCU_CONTEXT_COMMAND_REQUEST_TYPE_DUMP_TC:
+ io_request = this_controller->io_request_table[index];
+ dev_warn(scic_to_dev(this_controller),
+ "%s: SCIC SDS Completion type SDMA %x for io request "
+ "%p\n",
+ __func__,
+ completion_entry,
+ io_request);
+ /* @todo For a post TC operation we need to fail the IO
+ * request
+ */
+ break;
+
+ case SCU_CONTEXT_COMMAND_REQUEST_TYPE_DUMP_RNC:
+ case SCU_CONTEXT_COMMAND_REQUEST_TYPE_OTHER_RNC:
+ case SCU_CONTEXT_COMMAND_REQUEST_TYPE_POST_RNC:
+ device = this_controller->device_table[index];
+ dev_warn(scic_to_dev(this_controller),
+ "%s: SCIC SDS Completion type SDMA %x for remote "
+ "device %p\n",
+ __func__,
+ completion_entry,
+ device);
+ /* @todo For a port RNC operation we need to fail the
+ * device
+ */
+ break;
+
+ default:
+ dev_warn(scic_to_dev(this_controller),
+ "%s: SCIC SDS Completion unknown SDMA completion "
+ "type %x\n",
+ __func__,
+ completion_entry);
+ break;
+
+ }
+}
+
+/**
+ *
+ * @this_controller:
+ * @completion_entry:
+ *
+ * This method processes an unsolicited frame message. This is called from
+ * within the controller completion handler. none
+ */
+static void scic_sds_controller_unsolicited_frame(
+ struct scic_sds_controller *this_controller,
+ u32 completion_entry)
+{
+ u32 index;
+ u32 frame_index;
+
+ struct scu_unsolicited_frame_header *frame_header;
+ struct scic_sds_phy *phy;
+ struct scic_sds_remote_device *device;
+
+ enum sci_status result = SCI_FAILURE;
+
+ frame_index = SCU_GET_FRAME_INDEX(completion_entry);
+
+ frame_header
+ = this_controller->uf_control.buffers.array[frame_index].header;
+ this_controller->uf_control.buffers.array[frame_index].state
+ = UNSOLICITED_FRAME_IN_USE;
+
+ if (SCU_GET_FRAME_ERROR(completion_entry)) {
+ /*
+ * / @todo If the IAF frame or SIGNATURE FIS frame has an error will
+ * / this cause a problem? We expect the phy initialization will
+ * / fail if there is an error in the frame. */
+ scic_sds_controller_release_frame(this_controller, frame_index);
+ return;
+ }
+
+ if (frame_header->is_address_frame) {
+ index = SCU_GET_PROTOCOL_ENGINE_INDEX(completion_entry);
+ phy = &this_controller->phy_table[index];
+ if (phy != NULL) {
+ result = scic_sds_phy_frame_handler(phy, frame_index);
+ }
+ } else {
+
+ index = SCU_GET_COMPLETION_INDEX(completion_entry);
+
+ if (index == SCIC_SDS_REMOTE_NODE_CONTEXT_INVALID_INDEX) {
+ /*
+ * This is a signature fis or a frame from a direct attached SATA
+ * device that has not yet been created. In either case forwared
+ * the frame to the PE and let it take care of the frame data. */
+ index = SCU_GET_PROTOCOL_ENGINE_INDEX(completion_entry);
+ phy = &this_controller->phy_table[index];
+ result = scic_sds_phy_frame_handler(phy, frame_index);
+ } else {
+ if (index < this_controller->remote_node_entries)
+ device = this_controller->device_table[index];
+ else
+ device = NULL;
+
+ if (device != NULL)
+ result = scic_sds_remote_device_frame_handler(device, frame_index);
+ else
+ scic_sds_controller_release_frame(this_controller, frame_index);
+ }
+ }
+
+ if (result != SCI_SUCCESS) {
+ /*
+ * / @todo Is there any reason to report some additional error message
+ * / when we get this failure notifiction? */
+ }
+}
+
+/**
+ * This method processes an event completion entry. This is called from within
+ * the controller completion handler.
+ * @this_controller:
+ * @completion_entry:
+ *
+ */
+static void scic_sds_controller_event_completion(
+ struct scic_sds_controller *this_controller,
+ u32 completion_entry)
+{
+ u32 index;
+ struct scic_sds_request *io_request;
+ struct scic_sds_remote_device *device;
+ struct scic_sds_phy *phy;
+
+ index = SCU_GET_COMPLETION_INDEX(completion_entry);
+
+ switch (scu_get_event_type(completion_entry)) {
+ case SCU_EVENT_TYPE_SMU_COMMAND_ERROR:
+ /* / @todo The driver did something wrong and we need to fix the condtion. */
+ dev_err(scic_to_dev(this_controller),
+ "%s: SCIC Controller 0x%p received SMU command error "
+ "0x%x\n",
+ __func__,
+ this_controller,
+ completion_entry);
+ break;
+
+ case SCU_EVENT_TYPE_SMU_PCQ_ERROR:
+ case SCU_EVENT_TYPE_SMU_ERROR:
+ case SCU_EVENT_TYPE_FATAL_MEMORY_ERROR:
+ /*
+ * / @todo This is a hardware failure and its likely that we want to
+ * / reset the controller. */
+ dev_err(scic_to_dev(this_controller),
+ "%s: SCIC Controller 0x%p received fatal controller "
+ "event 0x%x\n",
+ __func__,
+ this_controller,
+ completion_entry);
+ break;
+
+ case SCU_EVENT_TYPE_TRANSPORT_ERROR:
+ io_request = this_controller->io_request_table[index];
+ scic_sds_io_request_event_handler(io_request, completion_entry);
+ break;
+
+ case SCU_EVENT_TYPE_PTX_SCHEDULE_EVENT:
+ switch (scu_get_event_specifier(completion_entry)) {
+ case SCU_EVENT_SPECIFIC_SMP_RESPONSE_NO_PE:
+ case SCU_EVENT_SPECIFIC_TASK_TIMEOUT:
+ io_request = this_controller->io_request_table[index];
+ if (io_request != SCI_INVALID_HANDLE)
+ scic_sds_io_request_event_handler(io_request, completion_entry);
+ else
+ dev_warn(scic_to_dev(this_controller),
+ "%s: SCIC Controller 0x%p received "
+ "event 0x%x for io request object "
+ "that doesnt exist.\n",
+ __func__,
+ this_controller,
+ completion_entry);
+
+ break;
+
+ case SCU_EVENT_SPECIFIC_IT_NEXUS_TIMEOUT:
+ device = this_controller->device_table[index];
+ if (device != SCI_INVALID_HANDLE)
+ scic_sds_remote_device_event_handler(device, completion_entry);
+ else
+ dev_warn(scic_to_dev(this_controller),
+ "%s: SCIC Controller 0x%p received "
+ "event 0x%x for remote device object "
+ "that doesnt exist.\n",
+ __func__,
+ this_controller,
+ completion_entry);
+
+ break;
+ }
+ break;
+
+ case SCU_EVENT_TYPE_BROADCAST_CHANGE:
+ /*
+ * direct the broadcast change event to the phy first and then let
+ * the phy redirect the broadcast change to the port object */
+ case SCU_EVENT_TYPE_ERR_CNT_EVENT:
+ /*
+ * direct error counter event to the phy object since that is where
+ * we get the event notification. This is a type 4 event. */
+ case SCU_EVENT_TYPE_OSSP_EVENT:
+ index = SCU_GET_PROTOCOL_ENGINE_INDEX(completion_entry);
+ phy = &this_controller->phy_table[index];
+ scic_sds_phy_event_handler(phy, completion_entry);
+ break;
+
+ case SCU_EVENT_TYPE_RNC_SUSPEND_TX:
+ case SCU_EVENT_TYPE_RNC_SUSPEND_TX_RX:
+ case SCU_EVENT_TYPE_RNC_OPS_MISC:
+ if (index < this_controller->remote_node_entries) {
+ device = this_controller->device_table[index];
+
+ if (device != NULL)
+ scic_sds_remote_device_event_handler(device, completion_entry);
+ } else
+ dev_err(scic_to_dev(this_controller),
+ "%s: SCIC Controller 0x%p received event 0x%x "
+ "for remote device object 0x%0x that doesnt "
+ "exist.\n",
+ __func__,
+ this_controller,
+ completion_entry,
+ index);
+
+ break;
+
+ default:
+ dev_warn(scic_to_dev(this_controller),
+ "%s: SCIC Controller received unknown event code %x\n",
+ __func__,
+ completion_entry);
+ break;
+ }
+}
+
+/**
+ * This method is a private routine for processing the completion queue entries.
+ * @this_controller:
+ *
+ */
+static void scic_sds_controller_process_completions(
+ struct scic_sds_controller *this_controller)
+{
+ u32 completion_count = 0;
+ u32 completion_entry;
+ u32 get_index;
+ u32 get_cycle;
+ u32 event_index;
+ u32 event_cycle;
+
+ dev_dbg(scic_to_dev(this_controller),
+ "%s: completion queue begining get:0x%08x\n",
+ __func__,
+ this_controller->completion_queue_get);
+
+ /* Get the component parts of the completion queue */
+ get_index = NORMALIZE_GET_POINTER(this_controller->completion_queue_get);
+ get_cycle = SMU_CQGR_CYCLE_BIT & this_controller->completion_queue_get;
+
+ event_index = NORMALIZE_EVENT_POINTER(this_controller->completion_queue_get);
+ event_cycle = SMU_CQGR_EVENT_CYCLE_BIT & this_controller->completion_queue_get;
+
+ while (
+ NORMALIZE_GET_POINTER_CYCLE_BIT(get_cycle)
+ == COMPLETION_QUEUE_CYCLE_BIT(this_controller->completion_queue[get_index])
+ ) {
+ completion_count++;
+
+ completion_entry = this_controller->completion_queue[get_index];
+ INCREMENT_COMPLETION_QUEUE_GET(this_controller, get_index, get_cycle);
+
+ dev_dbg(scic_to_dev(this_controller),
+ "%s: completion queue entry:0x%08x\n",
+ __func__,
+ completion_entry);
+
+ switch (SCU_GET_COMPLETION_TYPE(completion_entry)) {
+ case SCU_COMPLETION_TYPE_TASK:
+ scic_sds_controller_task_completion(this_controller, completion_entry);
+ break;
+
+ case SCU_COMPLETION_TYPE_SDMA:
+ scic_sds_controller_sdma_completion(this_controller, completion_entry);
+ break;
+
+ case SCU_COMPLETION_TYPE_UFI:
+ scic_sds_controller_unsolicited_frame(this_controller, completion_entry);
+ break;
+
+ case SCU_COMPLETION_TYPE_EVENT:
+ INCREMENT_EVENT_QUEUE_GET(this_controller, event_index, event_cycle);
+ scic_sds_controller_event_completion(this_controller, completion_entry);
+ break;
+
+ case SCU_COMPLETION_TYPE_NOTIFY:
+ /*
+ * Presently we do the same thing with a notify event that we do with the
+ * other event codes. */
+ INCREMENT_EVENT_QUEUE_GET(this_controller, event_index, event_cycle);
+ scic_sds_controller_event_completion(this_controller, completion_entry);
+ break;
+
+ default:
+ dev_warn(scic_to_dev(this_controller),
+ "%s: SCIC Controller received unknown "
+ "completion type %x\n",
+ __func__,
+ completion_entry);
+ break;
+ }
+ }
+
+ /* Update the get register if we completed one or more entries */
+ if (completion_count > 0) {
+ this_controller->completion_queue_get =
+ SMU_CQGR_GEN_BIT(ENABLE)
+ | SMU_CQGR_GEN_BIT(EVENT_ENABLE)
+ | event_cycle | SMU_CQGR_GEN_VAL(EVENT_POINTER, event_index)
+ | get_cycle | SMU_CQGR_GEN_VAL(POINTER, get_index);
+
+ SMU_CQGR_WRITE(this_controller,
+ this_controller->completion_queue_get);
+ }
+
+ dev_dbg(scic_to_dev(this_controller),
+ "%s: completion queue ending get:0x%08x\n",
+ __func__,
+ this_controller->completion_queue_get);
+
+}
+
+/**
+ * This method is a private routine for processing the completion queue entries.
+ * @this_controller:
+ *
+ */
+static void scic_sds_controller_transitioned_process_completions(
+ struct scic_sds_controller *this_controller)
+{
+ u32 completion_count = 0;
+ u32 completion_entry;
+ u32 get_index;
+ u32 get_cycle;
+ u32 event_index;
+ u32 event_cycle;
+
+ dev_dbg(scic_to_dev(this_controller),
+ "%s: completion queue begining get:0x%08x\n",
+ __func__,
+ this_controller->completion_queue_get);
+
+ /* Get the component parts of the completion queue */
+ get_index = NORMALIZE_GET_POINTER(this_controller->completion_queue_get);
+ get_cycle = SMU_CQGR_CYCLE_BIT & this_controller->completion_queue_get;
+
+ event_index = NORMALIZE_EVENT_POINTER(this_controller->completion_queue_get);
+ event_cycle = SMU_CQGR_EVENT_CYCLE_BIT & this_controller->completion_queue_get;
+
+ while (
+ NORMALIZE_GET_POINTER_CYCLE_BIT(get_cycle)
+ == COMPLETION_QUEUE_CYCLE_BIT(
+ this_controller->completion_queue[get_index])
+ ) {
+ completion_count++;
+
+ completion_entry = this_controller->completion_queue[get_index];
+ INCREMENT_COMPLETION_QUEUE_GET(this_controller, get_index, get_cycle);
+
+ dev_dbg(scic_to_dev(this_controller),
+ "%s: completion queue entry:0x%08x\n",
+ __func__,
+ completion_entry);
+
+ switch (SCU_GET_COMPLETION_TYPE(completion_entry)) {
+ case SCU_COMPLETION_TYPE_TASK:
+ scic_sds_controller_task_completion(this_controller, completion_entry);
+ break;
+
+ case SCU_COMPLETION_TYPE_NOTIFY:
+ case SCU_COMPLETION_TYPE_EVENT:
+ /*
+ * Presently we do the same thing with a notify event that we
+ * do with the other event codes. */
+ INCREMENT_EVENT_QUEUE_GET(this_controller, event_index, event_cycle);
+ /* Fall-through */
+
+ case SCU_COMPLETION_TYPE_SDMA:
+ case SCU_COMPLETION_TYPE_UFI:
+ default:
+ dev_warn(scic_to_dev(this_controller),
+ "%s: SCIC Controller ignoring completion type "
+ "%x\n",
+ __func__,
+ completion_entry);
+ break;
+ }
+ }
+
+ /* Update the get register if we completed one or more entries */
+ if (completion_count > 0) {
+ this_controller->completion_queue_get =
+ SMU_CQGR_GEN_BIT(ENABLE)
+ | SMU_CQGR_GEN_BIT(EVENT_ENABLE)
+ | event_cycle | SMU_CQGR_GEN_VAL(EVENT_POINTER, event_index)
+ | get_cycle | SMU_CQGR_GEN_VAL(POINTER, get_index);
+
+ SMU_CQGR_WRITE(this_controller, this_controller->completion_queue_get);
+ }
+
+ dev_dbg(scic_to_dev(this_controller),
+ "%s: completion queue ending get:0x%08x\n",
+ __func__,
+ this_controller->completion_queue_get);
+}
+
+/*
+ * ****************************************************************************-
+ * * SCIC SDS Controller Interrupt and Completion functions
+ * ****************************************************************************- */
+
+/**
+ * This method provides standard (common) processing of interrupts for polling
+ * and legacy based interrupts.
+ * @controller:
+ * @interrupt_status:
+ *
+ * This method returns a boolean (bool) indication as to whether an completions
+ * are pending to be processed. true if an interrupt is to be processed false
+ * if no interrupt was pending
+ */
+static bool scic_sds_controller_standard_interrupt_handler(
+ struct scic_sds_controller *this_controller,
+ u32 interrupt_status)
+{
+ bool is_completion_needed = false;
+
+ if ((interrupt_status & SMU_ISR_QUEUE_ERROR) ||
+ ((interrupt_status & SMU_ISR_QUEUE_SUSPEND) &&
+ (!scic_sds_controller_completion_queue_has_entries(
+ this_controller)))) {
+ /*
+ * We have a fatal error on the read of the completion queue bar
+ * OR
+ * We have a fatal error there is nothing in the completion queue
+ * but we have a report from the hardware that the queue is full
+ * / @todo how do we request the a controller reset */
+ is_completion_needed = true;
+ this_controller->encountered_fatal_error = true;
+ }
+
+ if (scic_sds_controller_completion_queue_has_entries(this_controller)) {
+ is_completion_needed = true;
+ }
+
+ return is_completion_needed;
+}
+
+/**
+ * This is the method provided to handle polling for interrupts for the
+ * controller object.
+ *
+ * bool true if an interrupt is to be processed false if no interrupt was
+ * pending
+ */
+static bool scic_sds_controller_polling_interrupt_handler(
+ struct scic_sds_controller *scic)
+{
+ u32 interrupt_status;
+
+ /*
+ * In INTERRUPT_POLLING_MODE we exit the interrupt handler if the
+ * hardware indicates nothing is pending. Since we are not being
+ * called from a real interrupt, we don't want to confuse the hardware
+ * by servicing the completion queue before the hardware indicates it
+ * is ready. We'll simply wait for another polling interval and check
+ * again.
+ */
+ interrupt_status = SMU_ISR_READ(scic);
+ if ((interrupt_status &
+ (SMU_ISR_COMPLETION |
+ SMU_ISR_QUEUE_ERROR |
+ SMU_ISR_QUEUE_SUSPEND)) == 0) {
+ return false;
+ }
+
+ return scic_sds_controller_standard_interrupt_handler(
+ scic, interrupt_status);
+}
+
+/**
+ * This is the method provided to handle completions when interrupt polling is
+ * in use.
+ */
+static void scic_sds_controller_polling_completion_handler(
+ struct scic_sds_controller *scic)
+{
+ if (scic->encountered_fatal_error == true) {
+ dev_err(scic_to_dev(scic),
+ "%s: SCIC Controller has encountered a fatal error.\n",
+ __func__);
+
+ sci_base_state_machine_change_state(
+ scic_sds_controller_get_base_state_machine(scic),
+ SCI_BASE_CONTROLLER_STATE_FAILED);
+ } else if (scic_sds_controller_completion_queue_has_entries(scic)) {
+ if (scic->restrict_completions == false)
+ scic_sds_controller_process_completions(scic);
+ else
+ scic_sds_controller_transitioned_process_completions(
+ scic);
+ }
+
+ /*
+ * The interrupt handler does not adjust the CQ's
+ * get pointer. So, SCU's INTx pin stays asserted during the
+ * interrupt handler even though it tries to clear the interrupt
+ * source. Therefore, the completion handler must ensure that the
+ * interrupt source is cleared. Otherwise, we get a spurious
+ * interrupt for which the interrupt handler will not issue a
+ * corresponding completion event. Also, we unmask interrupts.
+ */
+ SMU_ISR_WRITE(
+ scic,
+ (u32)(SMU_ISR_COMPLETION | SMU_ISR_QUEUE_ERROR | SMU_ISR_QUEUE_SUSPEND)
+ );
+}
+
+/**
+ * This is the method provided to handle legacy interrupts for the controller
+ * object.
+ *
+ * bool true if an interrupt is processed false if no interrupt was processed
+ */
+static bool scic_sds_controller_legacy_interrupt_handler(
+ struct scic_sds_controller *scic)
+{
+ u32 interrupt_status;
+ bool is_completion_needed;
+
+ interrupt_status = SMU_ISR_READ(scic);
+ is_completion_needed = scic_sds_controller_standard_interrupt_handler(
+ scic, interrupt_status);
+
+ return is_completion_needed;
+}
+
+
+/**
+ * This is the method provided to handle legacy completions it is expected that
+ * the SCI User will call this completion handler anytime the interrupt
+ * handler reports that it has handled an interrupt.
+ */
+static void scic_sds_controller_legacy_completion_handler(
+ struct scic_sds_controller *scic)
+{
+ scic_sds_controller_polling_completion_handler(scic);
+ SMU_IMR_WRITE(scic, 0x00000000);
+}
+
+/**
+ * This is the method provided to handle an MSIX interrupt message when there
+ * is just a single MSIX message being provided by the hardware. This mode
+ * of operation is single vector mode.
+ *
+ * bool true if an interrupt is processed false if no interrupt was processed
+ */
+static bool scic_sds_controller_single_vector_interrupt_handler(
+ struct scic_sds_controller *scic)
+{
+ u32 interrupt_status;
+
+ /*
+ * Mask the interrupts
+ * There is a race in the hardware that could cause us not to be notified
+ * of an interrupt completion if we do not take this step. We will unmask
+ * the interrupts in the completion routine. */
+ SMU_IMR_WRITE(scic, 0xFFFFFFFF);
+
+ interrupt_status = SMU_ISR_READ(scic);
+ interrupt_status &= (SMU_ISR_QUEUE_ERROR | SMU_ISR_QUEUE_SUSPEND);
+
+ if ((interrupt_status == 0) &&
+ scic_sds_controller_completion_queue_has_entries(scic)) {
+ /*
+ * There is at least one completion queue entry to process so we can
+ * return a success and ignore for now the case of an error interrupt */
+ SMU_ISR_WRITE(scic, SMU_ISR_COMPLETION);
+ return true;
+ }
+
+ if (interrupt_status != 0) {
+ /*
+ * There is an error interrupt pending so let it through and handle
+ * in the callback */
+ return true;
+ }
+
+ /*
+ * Clear any offending interrupts since we could not find any to handle
+ * and unmask them all */
+ SMU_ISR_WRITE(scic, 0x00000000);
+ SMU_IMR_WRITE(scic, 0x00000000);
+
+ return false;
+}
+
+/**
+ * This is the method provided to handle completions for a single MSIX message.
+ */
+static void scic_sds_controller_single_vector_completion_handler(
+ struct scic_sds_controller *scic)
+{
+ u32 interrupt_status;
+
+ interrupt_status = SMU_ISR_READ(scic);
+ interrupt_status &= (SMU_ISR_QUEUE_ERROR | SMU_ISR_QUEUE_SUSPEND);
+
+ if (interrupt_status & SMU_ISR_QUEUE_ERROR) {
+ dev_err(scic_to_dev(scic),
+ "%s: SCIC Controller has encountered a fatal error.\n",
+ __func__);
+
+ /*
+ * We have a fatal condition and must reset the controller
+ * Leave the interrupt mask in place and get the controller reset */
+ sci_base_state_machine_change_state(
+ scic_sds_controller_get_base_state_machine(scic),
+ SCI_BASE_CONTROLLER_STATE_FAILED);
+ return;
+ }
+
+ if ((interrupt_status & SMU_ISR_QUEUE_SUSPEND) &&
+ !scic_sds_controller_completion_queue_has_entries(scic)) {
+ dev_err(scic_to_dev(scic),
+ "%s: SCIC Controller has encountered a fatal error.\n",
+ __func__);
+
+ /*
+ * We have a fatal condtion and must reset the controller
+ * Leave the interrupt mask in place and get the controller reset */
+ sci_base_state_machine_change_state(
+ scic_sds_controller_get_base_state_machine(scic),
+ SCI_BASE_CONTROLLER_STATE_FAILED);
+ return;
+ }
+
+ if (scic_sds_controller_completion_queue_has_entries(scic)) {
+ scic_sds_controller_process_completions(scic);
+
+ /*
+ * We dont care which interrupt got us to processing the completion queu
+ * so clear them both. */
+ SMU_ISR_WRITE(
+ scic,
+ (SMU_ISR_COMPLETION | SMU_ISR_QUEUE_SUSPEND));
+ }
+
+ SMU_IMR_WRITE(scic, 0x00000000);
+}
+
+/**
+ * This is the method provided to handle a MSIX message for a normal completion.
+ *
+ * bool true if an interrupt is processed false if no interrupt was processed
+ */
+static bool scic_sds_controller_normal_vector_interrupt_handler(
+ struct scic_sds_controller *scic)
+{
+ if (scic_sds_controller_completion_queue_has_entries(scic)) {
+ return true;
+ } else {
+ /*
+ * we have a spurious interrupt it could be that we have already
+ * emptied the completion queue from a previous interrupt */
+ SMU_ISR_WRITE(scic, SMU_ISR_COMPLETION);
+
+ /*
+ * There is a race in the hardware that could cause us not to be notified
+ * of an interrupt completion if we do not take this step. We will mask
+ * then unmask the interrupts so if there is another interrupt pending
+ * the clearing of the interrupt source we get the next interrupt message. */
+ SMU_IMR_WRITE(scic, 0xFF000000);
+ SMU_IMR_WRITE(scic, 0x00000000);
+ }
+
+ return false;
+}
+
+/**
+ * This is the method provided to handle the completions for a normal MSIX
+ * message.
+ */
+static void scic_sds_controller_normal_vector_completion_handler(
+ struct scic_sds_controller *scic)
+{
+ /* Empty out the completion queue */
+ if (scic_sds_controller_completion_queue_has_entries(scic))
+ scic_sds_controller_process_completions(scic);
+
+ /* Clear the interrupt and enable all interrupts again */
+ SMU_ISR_WRITE(scic, SMU_ISR_COMPLETION);
+ /* Could we write the value of SMU_ISR_COMPLETION? */
+ SMU_IMR_WRITE(scic, 0xFF000000);
+ SMU_IMR_WRITE(scic, 0x00000000);
+}
+
+/**
+ * This is the method provided to handle the error MSIX message interrupt.
+ * This is the normal operating mode for the hardware if MSIX is enabled.
+ *
+ * bool true if an interrupt is processed false if no interrupt was processed
+ */
+static bool scic_sds_controller_error_vector_interrupt_handler(
+ struct scic_sds_controller *scic)
+{
+ u32 interrupt_status;
+
+ interrupt_status = SMU_ISR_READ(scic);
+ interrupt_status &= (SMU_ISR_QUEUE_ERROR | SMU_ISR_QUEUE_SUSPEND);
+
+ if (interrupt_status != 0) {
+ /*
+ * There is an error interrupt pending so let it through and handle
+ * in the callback */
+ return true;
+ }
+
+ /*
+ * There is a race in the hardware that could cause us not to be notified
+ * of an interrupt completion if we do not take this step. We will mask
+ * then unmask the error interrupts so if there was another interrupt
+ * pending we will be notified.
+ * Could we write the value of (SMU_ISR_QUEUE_ERROR | SMU_ISR_QUEUE_SUSPEND)? */
+ SMU_IMR_WRITE(scic, 0x000000FF);
+ SMU_IMR_WRITE(scic, 0x00000000);
+
+ return false;
+}
+
+/**
+ * This is the method provided to handle the error completions when the
+ * hardware is using two MSIX messages.
+ */
+static void scic_sds_controller_error_vector_completion_handler(
+ struct scic_sds_controller *scic)
+{
+ u32 interrupt_status;
+
+ interrupt_status = SMU_ISR_READ(scic);
+
+ if ((interrupt_status & SMU_ISR_QUEUE_SUSPEND) &&
+ scic_sds_controller_completion_queue_has_entries(scic)) {
+
+ scic_sds_controller_process_completions(scic);
+ SMU_ISR_WRITE(scic, SMU_ISR_QUEUE_SUSPEND);
+
+ } else {
+ dev_err(scic_to_dev(scic),
+ "%s: SCIC Controller reports CRC error on completion "
+ "ISR %x\n",
+ __func__,
+ interrupt_status);
+
+ sci_base_state_machine_change_state(
+ scic_sds_controller_get_base_state_machine(scic),
+ SCI_BASE_CONTROLLER_STATE_FAILED);
+
+ return;
+ }
+
+ /*
+ * If we dont process any completions I am not sure that we want to do this.
+ * We are in the middle of a hardware fault and should probably be reset. */
+ SMU_IMR_WRITE(scic, 0x00000000);
+}
+
+
+/*
+ * ****************************************************************************-
+ * * SCIC SDS Controller External Methods
+ * ****************************************************************************- */
+
+/**
+ * This method returns the sizeof the SCIC SDS Controller Object
+ */
+u32 scic_sds_controller_get_object_size(void)
+{
+ return sizeof(struct scic_sds_controller);
+}
+
+
+void scic_sds_controller_link_up(
+ struct scic_sds_controller *scic,
+ struct scic_sds_port *sci_port,
+ struct scic_sds_phy *sci_phy)
+{
+ scic_sds_controller_phy_handler_t link_up;
+ u32 state;
+
+ state = scic->parent.state_machine.current_state_id;
+ link_up = scic_sds_controller_state_handler_table[state].link_up;
+
+ if (link_up)
+ link_up(scic, sci_port, sci_phy);
+ else
+ dev_warn(scic_to_dev(scic),
+ "%s: SCIC Controller linkup event from phy %d in "
+ "unexpected state %d\n",
+ __func__,
+ sci_phy->phy_index,
+ sci_base_state_machine_get_state(
+ scic_sds_controller_get_base_state_machine(
+ scic)));
+}
+
+
+void scic_sds_controller_link_down(
+ struct scic_sds_controller *scic,
+ struct scic_sds_port *sci_port,
+ struct scic_sds_phy *sci_phy)
+{
+ u32 state;
+ scic_sds_controller_phy_handler_t link_down;
+
+ state = scic->parent.state_machine.current_state_id;
+ link_down = scic_sds_controller_state_handler_table[state].link_down;
+
+ if (link_down)
+ link_down(scic, sci_port, sci_phy);
+ else
+ dev_warn(scic_to_dev(scic),
+ "%s: SCIC Controller linkdown event from phy %d in "
+ "unexpected state %d\n",
+ __func__,
+ sci_phy->phy_index,
+ sci_base_state_machine_get_state(
+ scic_sds_controller_get_base_state_machine(
+ scic)));
+}
+
+/**
+ * This method will write to the SCU PCP register the request value. The method
+ * is used to suspend/resume ports, devices, and phys.
+ * @this_controller:
+ *
+ *
+ */
+void scic_sds_controller_post_request(
+ struct scic_sds_controller *this_controller,
+ u32 request)
+{
+ dev_dbg(scic_to_dev(this_controller),
+ "%s: SCIC Controller 0x%p post request 0x%08x\n",
+ __func__,
+ this_controller,
+ request);
+
+ SMU_PCP_WRITE(this_controller, request);
+}
+
+/**
+ * This method will copy the soft copy of the task context into the physical
+ * memory accessible by the controller.
+ * @this_controller: This parameter specifies the controller for which to copy
+ * the task context.
+ * @this_request: This parameter specifies the request for which the task
+ * context is being copied.
+ *
+ * After this call is made the SCIC_SDS_IO_REQUEST object will always point to
+ * the physical memory version of the task context. Thus, all subsequent
+ * updates to the task context are performed in the TC table (i.e. DMAable
+ * memory). none
+ */
+void scic_sds_controller_copy_task_context(
+ struct scic_sds_controller *this_controller,
+ struct scic_sds_request *this_request)
+{
+ struct scu_task_context *task_context_buffer;
+
+ task_context_buffer = scic_sds_controller_get_task_context_buffer(
+ this_controller, this_request->io_tag
+ );
+
+ memcpy(
+ task_context_buffer,
+ this_request->task_context_buffer,
+ SCI_FIELD_OFFSET(struct scu_task_context, sgl_snapshot_ac)
+ );
+
+ /*
+ * Now that the soft copy of the TC has been copied into the TC
+ * table accessible by the silicon. Thus, any further changes to
+ * the TC (e.g. TC termination) occur in the appropriate location. */
+ this_request->task_context_buffer = task_context_buffer;
+}
+
+/**
+ * This method returns the task context buffer for the given io tag.
+ * @this_controller:
+ * @io_tag:
+ *
+ * struct scu_task_context*
+ */
+struct scu_task_context *scic_sds_controller_get_task_context_buffer(
+ struct scic_sds_controller *this_controller,
+ u16 io_tag
+ ) {
+ u16 task_index = scic_sds_io_tag_get_index(io_tag);
+
+ if (task_index < this_controller->task_context_entries) {
+ return &this_controller->task_context_table[task_index];
+ }
+
+ return NULL;
+}
+
+/**
+ * This method returnst the sequence value from the io tag value
+ * @this_controller:
+ * @io_tag:
+ *
+ * u16
+ */
+
+/**
+ * This method returns the IO request associated with the tag value
+ * @this_controller:
+ * @io_tag:
+ *
+ * SCIC_SDS_IO_REQUEST_T* NULL if there is no valid IO request at the tag value
+ */
+struct scic_sds_request *scic_sds_controller_get_io_request_from_tag(
+ struct scic_sds_controller *this_controller,
+ u16 io_tag
+ ) {
+ u16 task_index;
+ u16 task_sequence;
+
+ task_index = scic_sds_io_tag_get_index(io_tag);
+
+ if (task_index < this_controller->task_context_entries) {
+ if (this_controller->io_request_table[task_index] != SCI_INVALID_HANDLE) {
+ task_sequence = scic_sds_io_tag_get_sequence(io_tag);
+
+ if (task_sequence == this_controller->io_request_sequence[task_index]) {
+ return this_controller->io_request_table[task_index];
+ }
+ }
+ }
+
+ return SCI_INVALID_HANDLE;
+}
+
+/**
+ * This method allocates remote node index and the reserves the remote node
+ * context space for use. This method can fail if there are no more remote
+ * node index available.
+ * @this_controller: This is the controller object which contains the set of
+ * free remote node ids
+ * @the_devce: This is the device object which is requesting the a remote node
+ * id
+ * @node_id: This is the remote node id that is assinged to the device if one
+ * is available
+ *
+ * enum sci_status SCI_FAILURE_OUT_OF_RESOURCES if there are no available remote
+ * node index available.
+ */
+enum sci_status scic_sds_controller_allocate_remote_node_context(
+ struct scic_sds_controller *this_controller,
+ struct scic_sds_remote_device *the_device,
+ u16 *node_id)
+{
+ u16 node_index;
+ u32 remote_node_count = scic_sds_remote_device_node_count(the_device);
+
+ node_index = scic_sds_remote_node_table_allocate_remote_node(
+ &this_controller->available_remote_nodes, remote_node_count
+ );
+
+ if (node_index != SCIC_SDS_REMOTE_NODE_CONTEXT_INVALID_INDEX) {
+ this_controller->device_table[node_index] = the_device;
+
+ *node_id = node_index;
+
+ return SCI_SUCCESS;
+ }
+
+ return SCI_FAILURE_INSUFFICIENT_RESOURCES;
+}
+
+/**
+ * This method frees the remote node index back to the available pool. Once
+ * this is done the remote node context buffer is no longer valid and can
+ * not be used.
+ * @this_controller:
+ * @the_device:
+ * @node_id:
+ *
+ */
+void scic_sds_controller_free_remote_node_context(
+ struct scic_sds_controller *this_controller,
+ struct scic_sds_remote_device *the_device,
+ u16 node_id)
+{
+ u32 remote_node_count = scic_sds_remote_device_node_count(the_device);
+
+ if (this_controller->device_table[node_id] == the_device) {
+ this_controller->device_table[node_id] = SCI_INVALID_HANDLE;
+
+ scic_sds_remote_node_table_release_remote_node_index(
+ &this_controller->available_remote_nodes, remote_node_count, node_id
+ );
+ }
+}
+
+/**
+ * This method returns the union scu_remote_node_context for the specified remote
+ * node id.
+ * @this_controller:
+ * @node_id:
+ *
+ * union scu_remote_node_context*
+ */
+union scu_remote_node_context *scic_sds_controller_get_remote_node_context_buffer(
+ struct scic_sds_controller *this_controller,
+ u16 node_id
+ ) {
+ if (
+ (node_id < this_controller->remote_node_entries)
+ && (this_controller->device_table[node_id] != SCI_INVALID_HANDLE)
+ ) {
+ return &this_controller->remote_node_context_table[node_id];
+ }
+
+ return NULL;
+}
+
+/**
+ *
+ * @resposne_buffer: This is the buffer into which the D2H register FIS will be
+ * constructed.
+ * @frame_header: This is the frame header returned by the hardware.
+ * @frame_buffer: This is the frame buffer returned by the hardware.
+ *
+ * This method will combind the frame header and frame buffer to create a SATA
+ * D2H register FIS none
+ */
+void scic_sds_controller_copy_sata_response(
+ void *response_buffer,
+ void *frame_header,
+ void *frame_buffer)
+{
+ memcpy(
+ response_buffer,
+ frame_header,
+ sizeof(u32)
+ );
+
+ memcpy(
+ (char *)((char *)response_buffer + sizeof(u32)),
+ frame_buffer,
+ sizeof(struct sata_fis_reg_d2h) - sizeof(u32)
+ );
+}
+
+/**
+ * This method releases the frame once this is done the frame is available for
+ * re-use by the hardware. The data contained in the frame header and frame
+ * buffer is no longer valid. The UF queue get pointer is only updated if UF
+ * control indicates this is appropriate.
+ * @this_controller:
+ * @frame_index:
+ *
+ */
+void scic_sds_controller_release_frame(
+ struct scic_sds_controller *this_controller,
+ u32 frame_index)
+{
+ if (scic_sds_unsolicited_frame_control_release_frame(
+ &this_controller->uf_control, frame_index) == true)
+ SCU_UFQGP_WRITE(this_controller, this_controller->uf_control.get);
+}
+
+/**
+ * This method sets user parameters and OEM parameters to default values.
+ * Users can override these values utilizing the scic_user_parameters_set()
+ * and scic_oem_parameters_set() methods.
+ * @controller: This parameter specifies the controller for which to set the
+ * configuration parameters to their default values.
+ *
+ */
+static void scic_sds_controller_set_default_config_parameters(
+ struct scic_sds_controller *this_controller)
+{
+ u16 index;
+
+ /* Default to no SSC operation. */
+ this_controller->oem_parameters.sds1.controller.do_enable_ssc = false;
+
+ /* Initialize all of the port parameter information to narrow ports. */
+ for (index = 0; index < SCI_MAX_PORTS; index++) {
+ this_controller->oem_parameters.sds1.ports[index].phy_mask = 0;
+ }
+
+ /* Initialize all of the phy parameter information. */
+ for (index = 0; index < SCI_MAX_PHYS; index++) {
+ /*
+ * Default to 3G (i.e. Gen 2) for now. User can override if
+ * they choose. */
+ this_controller->user_parameters.sds1.phys[index].max_speed_generation = 2;
+
+ /*
+ * Previous Vitesse based expanders had a arbitration issue that
+ * is worked around by having the upper 32-bits of SAS address
+ * with a value greater then the Vitesse company identifier.
+ * Hence, usage of 0x5FCFFFFF. */
+ this_controller->oem_parameters.sds1.phys[index].sas_address.low
+ = 0x00000001;
+ this_controller->oem_parameters.sds1.phys[index].sas_address.high
+ = 0x5FCFFFFF;
+ }
+
+ this_controller->user_parameters.sds1.stp_inactivity_timeout = 5;
+ this_controller->user_parameters.sds1.ssp_inactivity_timeout = 5;
+ this_controller->user_parameters.sds1.stp_max_occupancy_timeout = 5;
+ this_controller->user_parameters.sds1.ssp_max_occupancy_timeout = 20;
+ this_controller->user_parameters.sds1.no_outbound_task_timeout = 5;
+
+}
+
+
+enum sci_status scic_controller_construct(struct scic_sds_controller *controller,
+ void __iomem *scu_base,
+ void __iomem *smu_base)
+{
+ u8 index;
+
+ sci_base_controller_construct(
+ &controller->parent,
+ scic_sds_controller_state_table,
+ controller->memory_descriptors,
+ ARRAY_SIZE(controller->memory_descriptors),
+ NULL
+ );
+
+ controller->scu_registers = scu_base;
+ controller->smu_registers = smu_base;
+
+ scic_sds_port_configuration_agent_construct(&controller->port_agent);
+
+ /* Construct the ports for this controller */
+ for (index = 0; index < SCI_MAX_PORTS; index++)
+ scic_sds_port_construct(&controller->port_table[index],
+ index, controller);
+ scic_sds_port_construct(&controller->port_table[index],
+ SCIC_SDS_DUMMY_PORT, controller);
+
+ /* Construct the phys for this controller */
+ for (index = 0; index < SCI_MAX_PHYS; index++) {
+ /* Add all the PHYs to the dummy port */
+ scic_sds_phy_construct(
+ &controller->phy_table[index],
+ &controller->port_table[SCI_MAX_PORTS],
+ index
+ );
+ }
+
+ controller->invalid_phy_mask = 0;
+
+ /* Set the default maximum values */
+ controller->completion_event_entries = SCU_EVENT_COUNT;
+ controller->completion_queue_entries = SCU_COMPLETION_QUEUE_COUNT;
+ controller->remote_node_entries = SCI_MAX_REMOTE_DEVICES;
+ controller->logical_port_entries = SCI_MAX_PORTS;
+ controller->task_context_entries = SCU_IO_REQUEST_COUNT;
+ controller->uf_control.buffers.count = SCU_UNSOLICITED_FRAME_COUNT;
+ controller->uf_control.address_table.count = SCU_UNSOLICITED_FRAME_COUNT;
+
+ /* Initialize the User and OEM parameters to default values. */
+ scic_sds_controller_set_default_config_parameters(controller);
+
+ return SCI_SUCCESS;
+}
+
+/* --------------------------------------------------------------------------- */
+
+enum sci_status scic_controller_initialize(
+ struct scic_sds_controller *scic)
+{
+ enum sci_status status = SCI_FAILURE_INVALID_STATE;
+ sci_base_controller_handler_t initialize;
+ u32 state;
+
+ state = scic->parent.state_machine.current_state_id;
+ initialize = scic_sds_controller_state_handler_table[state].base.initialize;
+
+ if (initialize)
+ status = initialize(&scic->parent);
+ else
+ dev_warn(scic_to_dev(scic),
+ "%s: SCIC Controller initialize operation requested "
+ "in invalid state %d\n",
+ __func__,
+ sci_base_state_machine_get_state(
+ scic_sds_controller_get_base_state_machine(
+ scic)));
+
+ return status;
+}
+
+/* --------------------------------------------------------------------------- */
+
+u32 scic_controller_get_suggested_start_timeout(
+ struct scic_sds_controller *sc)
+{
+ /* Validate the user supplied parameters. */
+ if (sc == SCI_INVALID_HANDLE)
+ return 0;
+
+ /*
+ * The suggested minimum timeout value for a controller start operation:
+ *
+ * Signature FIS Timeout
+ * + Phy Start Timeout
+ * + Number of Phy Spin Up Intervals
+ * ---------------------------------
+ * Number of milliseconds for the controller start operation.
+ *
+ * NOTE: The number of phy spin up intervals will be equivalent
+ * to the number of phys divided by the number phys allowed
+ * per interval - 1 (once OEM parameters are supported).
+ * Currently we assume only 1 phy per interval. */
+
+ return (SCIC_SDS_SIGNATURE_FIS_TIMEOUT
+ + SCIC_SDS_CONTROLLER_PHY_START_TIMEOUT
+ + ((SCI_MAX_PHYS - 1) * SCIC_SDS_CONTROLLER_POWER_CONTROL_INTERVAL));
+}
+
+/* --------------------------------------------------------------------------- */
+
+enum sci_status scic_controller_start(
+ struct scic_sds_controller *scic,
+ u32 timeout)
+{
+ enum sci_status status = SCI_FAILURE_INVALID_STATE;
+ sci_base_controller_timed_handler_t start;
+ u32 state;
+
+ state = scic->parent.state_machine.current_state_id;
+ start = scic_sds_controller_state_handler_table[state].base.start;
+
+ if (start)
+ status = start(&scic->parent, timeout);
+ else
+ dev_warn(scic_to_dev(scic),
+ "%s: SCIC Controller start operation requested in "
+ "invalid state %d\n",
+ __func__,
+ sci_base_state_machine_get_state(
+ scic_sds_controller_get_base_state_machine(
+ scic)));
+
+ return status;
+}
+
+/* --------------------------------------------------------------------------- */
+
+enum sci_status scic_controller_stop(
+ struct scic_sds_controller *scic,
+ u32 timeout)
+{
+ enum sci_status status = SCI_FAILURE_INVALID_STATE;
+ sci_base_controller_timed_handler_t stop;
+ u32 state;
+
+ state = scic->parent.state_machine.current_state_id;
+ stop = scic_sds_controller_state_handler_table[state].base.stop;
+
+ if (stop)
+ status = stop(&scic->parent, timeout);
+ else
+ dev_warn(scic_to_dev(scic),
+ "%s: SCIC Controller stop operation requested in "
+ "invalid state %d\n",
+ __func__,
+ sci_base_state_machine_get_state(
+ scic_sds_controller_get_base_state_machine(
+ scic)));
+
+ return status;
+}
+
+/* --------------------------------------------------------------------------- */
+
+enum sci_status scic_controller_reset(
+ struct scic_sds_controller *scic)
+{
+ enum sci_status status = SCI_FAILURE_INVALID_STATE;
+ sci_base_controller_handler_t reset;
+ u32 state;
+
+ state = scic->parent.state_machine.current_state_id;
+ reset = scic_sds_controller_state_handler_table[state].base.reset;
+
+ if (reset)
+ status = reset(&scic->parent);
+ else
+ dev_warn(scic_to_dev(scic),
+ "%s: SCIC Controller reset operation requested in "
+ "invalid state %d\n",
+ __func__,
+ sci_base_state_machine_get_state(
+ scic_sds_controller_get_base_state_machine(
+ scic)));
+
+ return status;
+}
+
+/* --------------------------------------------------------------------------- */
+
+enum sci_status scic_controller_get_handler_methods(
+ enum scic_interrupt_type interrupt_type,
+ u16 message_count,
+ struct scic_controller_handler_methods *handler_methods)
+{
+ enum sci_status status = SCI_FAILURE_UNSUPPORTED_MESSAGE_COUNT;
+
+ switch (interrupt_type) {
+ case SCIC_LEGACY_LINE_INTERRUPT_TYPE:
+ if (message_count == 0) {
+ handler_methods[0].interrupt_handler
+ = scic_sds_controller_legacy_interrupt_handler;
+ handler_methods[0].completion_handler
+ = scic_sds_controller_legacy_completion_handler;
+
+ status = SCI_SUCCESS;
+ }
+ break;
+
+ case SCIC_MSIX_INTERRUPT_TYPE:
+ if (message_count == 1) {
+ handler_methods[0].interrupt_handler
+ = scic_sds_controller_single_vector_interrupt_handler;
+ handler_methods[0].completion_handler
+ = scic_sds_controller_single_vector_completion_handler;
+
+ status = SCI_SUCCESS;
+ } else if (message_count == 2) {
+ handler_methods[0].interrupt_handler
+ = scic_sds_controller_normal_vector_interrupt_handler;
+ handler_methods[0].completion_handler
+ = scic_sds_controller_normal_vector_completion_handler;
+
+ handler_methods[1].interrupt_handler
+ = scic_sds_controller_error_vector_interrupt_handler;
+ handler_methods[1].completion_handler
+ = scic_sds_controller_error_vector_completion_handler;
+
+ status = SCI_SUCCESS;
+ }
+ break;
+
+ case SCIC_NO_INTERRUPTS:
+ if (message_count == 0) {
+
+ handler_methods[0].interrupt_handler
+ = scic_sds_controller_polling_interrupt_handler;
+ handler_methods[0].completion_handler
+ = scic_sds_controller_polling_completion_handler;
+
+ status = SCI_SUCCESS;
+ }
+ break;
+
+ default:
+ status = SCI_FAILURE_INVALID_PARAMETER_VALUE;
+ break;
+ }
+
+ return status;
+}
+
+/* --------------------------------------------------------------------------- */
+
+enum sci_io_status scic_controller_start_io(
+ struct scic_sds_controller *scic,
+ struct scic_sds_remote_device *remote_device,
+ struct scic_sds_request *io_request,
+ u16 io_tag)
+{
+ u32 state;
+ sci_base_controller_start_request_handler_t start_io;
+
+ state = scic->parent.state_machine.current_state_id;
+ start_io = scic_sds_controller_state_handler_table[state].base.start_io;
+
+ return start_io(&scic->parent,
+ (struct sci_base_remote_device *) remote_device,
+ (struct sci_base_request *)io_request, io_tag);
+}
+
+/* --------------------------------------------------------------------------- */
+
+enum sci_status scic_controller_terminate_request(
+ struct scic_sds_controller *scic,
+ struct scic_sds_remote_device *remote_device,
+ struct scic_sds_request *request)
+{
+ sci_base_controller_request_handler_t terminate_request;
+ u32 state;
+
+ state = scic->parent.state_machine.current_state_id;
+ terminate_request = scic_sds_controller_state_handler_table[state].terminate_request;
+
+ return terminate_request(&scic->parent,
+ (struct sci_base_remote_device *)remote_device,
+ (struct sci_base_request *)request);
+}
+
+/* --------------------------------------------------------------------------- */
+
+enum sci_status scic_controller_complete_io(
+ struct scic_sds_controller *scic,
+ struct scic_sds_remote_device *remote_device,
+ struct scic_sds_request *io_request)
+{
+ u32 state;
+ sci_base_controller_request_handler_t complete_io;
+
+ state = scic->parent.state_machine.current_state_id;
+ complete_io = scic_sds_controller_state_handler_table[state].base.complete_io;
+
+ return complete_io(&scic->parent,
+ (struct sci_base_remote_device *)remote_device,
+ (struct sci_base_request *)io_request);
+}
+
+/* --------------------------------------------------------------------------- */
+
+
+enum sci_task_status scic_controller_start_task(
+ struct scic_sds_controller *scic,
+ struct scic_sds_remote_device *remote_device,
+ struct scic_sds_request *task_request,
+ u16 task_tag)
+{
+ u32 state;
+ sci_base_controller_start_request_handler_t start_task;
+ enum sci_task_status status = SCI_TASK_FAILURE_INVALID_STATE;
+
+ state = scic->parent.state_machine.current_state_id;
+ start_task = scic_sds_controller_state_handler_table[state].base.start_task;
+
+ if (start_task)
+ status = start_task(&scic->parent,
+ (struct sci_base_remote_device *)remote_device,
+ (struct sci_base_request *)task_request,
+ task_tag);
+ else
+ dev_warn(scic_to_dev(scic),
+ "%s: SCIC Controller starting task from invalid "
+ "state\n",
+ __func__);
+
+ return status;
+}
+
+/* --------------------------------------------------------------------------- */
+
+enum sci_status scic_controller_complete_task(
+ struct scic_sds_controller *scic,
+ struct scic_sds_remote_device *remote_device,
+ struct scic_sds_request *task_request)
+{
+ u32 state;
+ sci_base_controller_request_handler_t complete_task;
+ enum sci_status status = SCI_FAILURE_INVALID_STATE;
+
+ state = scic->parent.state_machine.current_state_id;
+ complete_task = scic_sds_controller_state_handler_table[state].base.complete_task;
+
+ if (complete_task)
+ status = complete_task(&scic->parent,
+ (struct sci_base_remote_device *)remote_device,
+ (struct sci_base_request *)task_request);
+ else
+ dev_warn(scic_to_dev(scic),
+ "%s: SCIC Controller completing task from invalid "
+ "state\n",
+ __func__);
+
+ return status;
+}
+
+
+/* --------------------------------------------------------------------------- */
+
+enum sci_status scic_controller_get_port_handle(
+ struct scic_sds_controller *scic,
+ u8 port_index,
+ struct scic_sds_port **port_handle)
+{
+ if (port_index < scic->logical_port_entries) {
+ *port_handle = &scic->port_table[port_index];
+
+ return SCI_SUCCESS;
+ }
+
+ return SCI_FAILURE_INVALID_PORT;
+}
+
+/* --------------------------------------------------------------------------- */
+
+enum sci_status scic_controller_get_phy_handle(
+ struct scic_sds_controller *scic,
+ u8 phy_index,
+ struct scic_sds_phy **phy_handle)
+{
+ if (phy_index < ARRAY_SIZE(scic->phy_table)) {
+ *phy_handle = &scic->phy_table[phy_index];
+
+ return SCI_SUCCESS;
+ }
+
+ dev_err(scic_to_dev(scic),
+ "%s: Controller:0x%p PhyId:0x%x invalid phy index\n",
+ __func__, scic, phy_index);
+
+ return SCI_FAILURE_INVALID_PHY;
+}
+
+/* --------------------------------------------------------------------------- */
+
+u16 scic_controller_allocate_io_tag(
+ struct scic_sds_controller *scic)
+{
+ u16 task_context;
+ u16 sequence_count;
+
+ if (!sci_pool_empty(scic->tci_pool)) {
+ sci_pool_get(scic->tci_pool, task_context);
+
+ sequence_count = scic->io_request_sequence[task_context];
+
+ return scic_sds_io_tag_construct(sequence_count, task_context);
+ }
+
+ return SCI_CONTROLLER_INVALID_IO_TAG;
+}
+
+/* --------------------------------------------------------------------------- */
+
+enum sci_status scic_controller_free_io_tag(
+ struct scic_sds_controller *scic,
+ u16 io_tag)
+{
+ u16 sequence;
+ u16 index;
+
+ BUG_ON(io_tag == SCI_CONTROLLER_INVALID_IO_TAG);
+
+ sequence = scic_sds_io_tag_get_sequence(io_tag);
+ index = scic_sds_io_tag_get_index(io_tag);
+
+ if (!sci_pool_full(scic->tci_pool)) {
+ if (sequence == scic->io_request_sequence[index]) {
+ scic_sds_io_sequence_increment(
+ scic->io_request_sequence[index]);
+
+ sci_pool_put(scic->tci_pool, index);
+
+ return SCI_SUCCESS;
+ }
+ }
+
+ return SCI_FAILURE_INVALID_IO_TAG;
+}
+
+/* --------------------------------------------------------------------------- */
+
+void scic_controller_enable_interrupts(
+ struct scic_sds_controller *scic)
+{
+ BUG_ON(scic->smu_registers == NULL);
+ SMU_IMR_WRITE(scic, 0x00000000);
+}
+
+/* --------------------------------------------------------------------------- */
+
+void scic_controller_disable_interrupts(
+ struct scic_sds_controller *scic)
+{
+ BUG_ON(scic->smu_registers == NULL);
+ SMU_IMR_WRITE(scic, 0xffffffff);
+}
+
+/* --------------------------------------------------------------------------- */
+
+enum sci_status scic_controller_set_mode(
+ struct scic_sds_controller *scic,
+ enum sci_controller_mode operating_mode)
+{
+ enum sci_status status = SCI_SUCCESS;
+
+ if ((scic->parent.state_machine.current_state_id ==
+ SCI_BASE_CONTROLLER_STATE_INITIALIZING) ||
+ (scic->parent.state_machine.current_state_id ==
+ SCI_BASE_CONTROLLER_STATE_INITIALIZED)) {
+ switch (operating_mode) {
+ case SCI_MODE_SPEED:
+ scic->remote_node_entries = SCI_MAX_REMOTE_DEVICES;
+ scic->task_context_entries = SCU_IO_REQUEST_COUNT;
+ scic->uf_control.buffers.count =
+ SCU_UNSOLICITED_FRAME_COUNT;
+ scic->completion_event_entries = SCU_EVENT_COUNT;
+ scic->completion_queue_entries =
+ SCU_COMPLETION_QUEUE_COUNT;
+ scic_sds_controller_build_memory_descriptor_table(scic);
+ break;
+
+ case SCI_MODE_SIZE:
+ scic->remote_node_entries = SCI_MIN_REMOTE_DEVICES;
+ scic->task_context_entries = SCI_MIN_IO_REQUESTS;
+ scic->uf_control.buffers.count =
+ SCU_MIN_UNSOLICITED_FRAMES;
+ scic->completion_event_entries = SCU_MIN_EVENTS;
+ scic->completion_queue_entries =
+ SCU_MIN_COMPLETION_QUEUE_ENTRIES;
+ scic_sds_controller_build_memory_descriptor_table(scic);
+ break;
+
+ default:
+ status = SCI_FAILURE_INVALID_PARAMETER_VALUE;
+ break;
+ }
+ } else
+ status = SCI_FAILURE_INVALID_STATE;
+
+ return status;
+}
+
+/**
+ * scic_sds_controller_reset_hardware() -
+ *
+ * This method will reset the controller hardware.
+ */
+void scic_sds_controller_reset_hardware(
+ struct scic_sds_controller *scic)
+{
+ /* Disable interrupts so we dont take any spurious interrupts */
+ scic_controller_disable_interrupts(scic);
+
+ /* Reset the SCU */
+ SMU_SMUSRCR_WRITE(scic, 0xFFFFFFFF);
+
+ /* Delay for 1ms to before clearing the CQP and UFQPR. */
+ scic_cb_stall_execution(1000);
+
+ /* The write to the CQGR clears the CQP */
+ SMU_CQGR_WRITE(scic, 0x00000000);
+
+ /* The write to the UFQGP clears the UFQPR */
+ SCU_UFQGP_WRITE(scic, 0x00000000);
+}
+
+/* --------------------------------------------------------------------------- */
+
+enum sci_status scic_user_parameters_set(
+ struct scic_sds_controller *scic,
+ union scic_user_parameters *scic_parms)
+{
+ if (
+ (scic->parent.state_machine.current_state_id
+ == SCI_BASE_CONTROLLER_STATE_RESET)
+ || (scic->parent.state_machine.current_state_id
+ == SCI_BASE_CONTROLLER_STATE_INITIALIZING)
+ || (scic->parent.state_machine.current_state_id
+ == SCI_BASE_CONTROLLER_STATE_INITIALIZED)
+ ) {
+ u16 index;
+
+ /*
+ * Validate the user parameters. If they are not legal, then
+ * return a failure. */
+ for (index = 0; index < SCI_MAX_PHYS; index++) {
+ if (!
+ (scic_parms->sds1.phys[index].max_speed_generation
+ <= SCIC_SDS_PARM_MAX_SPEED
+ && scic_parms->sds1.phys[index].max_speed_generation
+ > SCIC_SDS_PARM_NO_SPEED
+ )
+ )
+ return SCI_FAILURE_INVALID_PARAMETER_VALUE;
+ }
+
+ memcpy(&scic->user_parameters, scic_parms, sizeof(*scic_parms));
+
+ return SCI_SUCCESS;
+ }
+
+ return SCI_FAILURE_INVALID_STATE;
+}
+
+/* --------------------------------------------------------------------------- */
+
+void scic_user_parameters_get(
+ struct scic_sds_controller *scic,
+ union scic_user_parameters *scic_parms)
+{
+ memcpy(scic_parms, (&scic->user_parameters), sizeof(*scic_parms));
+}
+
+/* --------------------------------------------------------------------------- */
+
+enum sci_status scic_oem_parameters_set(
+ struct scic_sds_controller *scic,
+ union scic_oem_parameters *scic_parms)
+{
+ if (
+ (scic->parent.state_machine.current_state_id
+ == SCI_BASE_CONTROLLER_STATE_RESET)
+ || (scic->parent.state_machine.current_state_id
+ == SCI_BASE_CONTROLLER_STATE_INITIALIZING)
+ || (scic->parent.state_machine.current_state_id
+ == SCI_BASE_CONTROLLER_STATE_INITIALIZED)
+ ) {
+ u16 index;
+
+ /*
+ * Validate the oem parameters. If they are not legal, then
+ * return a failure. */
+ for (index = 0; index < SCI_MAX_PORTS; index++) {
+ if (scic_parms->sds1.ports[index].phy_mask > SCIC_SDS_PARM_PHY_MASK_MAX) {
+ return SCI_FAILURE_INVALID_PARAMETER_VALUE;
+ }
+ }
+
+ for (index = 0; index < SCI_MAX_PHYS; index++) {
+ if (
+ scic_parms->sds1.phys[index].sas_address.high == 0
+ && scic_parms->sds1.phys[index].sas_address.low == 0
+ ) {
+ return SCI_FAILURE_INVALID_PARAMETER_VALUE;
+ }
+ }
+
+ memcpy(&scic->oem_parameters, scic_parms, sizeof(*scic_parms));
+ return SCI_SUCCESS;
+ }
+
+ return SCI_FAILURE_INVALID_STATE;
+}
+
+/* --------------------------------------------------------------------------- */
+
+void scic_oem_parameters_get(
+ struct scic_sds_controller *scic,
+ union scic_oem_parameters *scic_parms)
+{
+ memcpy(scic_parms, (&scic->oem_parameters), sizeof(*scic_parms));
+}
+
+/* --------------------------------------------------------------------------- */
+
+
+#define INTERRUPT_COALESCE_TIMEOUT_BASE_RANGE_LOWER_BOUND_NS 853
+#define INTERRUPT_COALESCE_TIMEOUT_BASE_RANGE_UPPER_BOUND_NS 1280
+#define INTERRUPT_COALESCE_TIMEOUT_MAX_US 2700000
+#define INTERRUPT_COALESCE_NUMBER_MAX 256
+#define INTERRUPT_COALESCE_TIMEOUT_ENCODE_MIN 7
+#define INTERRUPT_COALESCE_TIMEOUT_ENCODE_MAX 28
+
+enum sci_status scic_controller_set_interrupt_coalescence(
+ struct scic_sds_controller *scic_controller,
+ u32 coalesce_number,
+ u32 coalesce_timeout)
+{
+ u8 timeout_encode = 0;
+ u32 min = 0;
+ u32 max = 0;
+
+ /* Check if the input parameters fall in the range. */
+ if (coalesce_number > INTERRUPT_COALESCE_NUMBER_MAX)
+ return SCI_FAILURE_INVALID_PARAMETER_VALUE;
+
+ /*
+ * Defined encoding for interrupt coalescing timeout:
+ * Value Min Max Units
+ * ----- --- --- -----
+ * 0 - - Disabled
+ * 1 13.3 20.0 ns
+ * 2 26.7 40.0
+ * 3 53.3 80.0
+ * 4 106.7 160.0
+ * 5 213.3 320.0
+ * 6 426.7 640.0
+ * 7 853.3 1280.0
+ * 8 1.7 2.6 us
+ * 9 3.4 5.1
+ * 10 6.8 10.2
+ * 11 13.7 20.5
+ * 12 27.3 41.0
+ * 13 54.6 81.9
+ * 14 109.2 163.8
+ * 15 218.5 327.7
+ * 16 436.9 655.4
+ * 17 873.8 1310.7
+ * 18 1.7 2.6 ms
+ * 19 3.5 5.2
+ * 20 7.0 10.5
+ * 21 14.0 21.0
+ * 22 28.0 41.9
+ * 23 55.9 83.9
+ * 24 111.8 167.8
+ * 25 223.7 335.5
+ * 26 447.4 671.1
+ * 27 894.8 1342.2
+ * 28 1.8 2.7 s
+ * Others Undefined */
+
+ /*
+ * Use the table above to decide the encode of interrupt coalescing timeout
+ * value for register writing. */
+ if (coalesce_timeout == 0)
+ timeout_encode = 0;
+ else{
+ /* make the timeout value in unit of (10 ns). */
+ coalesce_timeout = coalesce_timeout * 100;
+ min = INTERRUPT_COALESCE_TIMEOUT_BASE_RANGE_LOWER_BOUND_NS / 10;
+ max = INTERRUPT_COALESCE_TIMEOUT_BASE_RANGE_UPPER_BOUND_NS / 10;
+
+ /* get the encode of timeout for register writing. */
+ for (timeout_encode = INTERRUPT_COALESCE_TIMEOUT_ENCODE_MIN;
+ timeout_encode <= INTERRUPT_COALESCE_TIMEOUT_ENCODE_MAX;
+ timeout_encode++) {
+ if (min <= coalesce_timeout && max > coalesce_timeout)
+ break;
+ else if (coalesce_timeout >= max && coalesce_timeout < min * 2
+ && coalesce_timeout <= INTERRUPT_COALESCE_TIMEOUT_MAX_US * 100) {
+ if ((coalesce_timeout - max) < (2 * min - coalesce_timeout))
+ break;
+ else{
+ timeout_encode++;
+ break;
+ }
+ } else {
+ max = max * 2;
+ min = min * 2;
+ }
+ }
+
+ if (timeout_encode == INTERRUPT_COALESCE_TIMEOUT_ENCODE_MAX + 1)
+ /* the value is out of range. */
+ return SCI_FAILURE_INVALID_PARAMETER_VALUE;
+ }
+
+ SMU_ICC_WRITE(
+ scic_controller,
+ (SMU_ICC_GEN_VAL(NUMBER, coalesce_number) |
+ SMU_ICC_GEN_VAL(TIMER, timeout_encode))
+ );
+
+ scic_controller->interrupt_coalesce_number = (u16)coalesce_number;
+ scic_controller->interrupt_coalesce_timeout = coalesce_timeout / 100;
+
+ return SCI_SUCCESS;
+}
+
+
+struct scic_sds_controller *scic_controller_alloc(struct device *dev)
+{
+ return devm_kzalloc(dev, sizeof(struct scic_sds_controller), GFP_KERNEL);
+}
+
+/*
+ * *****************************************************************************
+ * * DEFAULT STATE HANDLERS
+ * ***************************************************************************** */
+
+/**
+ *
+ * @controller: This is struct sci_base_controller object which is cast into a
+ * struct scic_sds_controller object.
+ * @remote_device: This is struct sci_base_remote_device which, if it was used, would
+ * be cast to a struct scic_sds_remote_device.
+ * @io_request: This is the struct sci_base_request which, if it was used, would be
+ * cast to a SCIC_SDS_IO_REQUEST.
+ * @io_tag: This is the IO tag to be assigned to the IO request or
+ * SCI_CONTROLLER_INVALID_IO_TAG.
+ *
+ * This method is called when the struct scic_sds_controller default start io/task
+ * handler is in place. - Issue a warning message enum sci_status
+ * SCI_FAILURE_INVALID_STATE
+ */
+static enum sci_status scic_sds_controller_default_start_operation_handler(
+ struct sci_base_controller *controller,
+ struct sci_base_remote_device *remote_device,
+ struct sci_base_request *io_request,
+ u16 io_tag)
+{
+ struct scic_sds_controller *this_controller;
+
+ this_controller = (struct scic_sds_controller *)controller;
+
+ dev_warn(scic_to_dev(this_controller),
+ "%s: SCIC Controller requested to start an io/task from "
+ "invalid state %d\n",
+ __func__,
+ sci_base_state_machine_get_state(
+ scic_sds_controller_get_base_state_machine(
+ this_controller)));
+
+ return SCI_FAILURE_INVALID_STATE;
+}
+
+/**
+ *
+ * @controller: This is struct sci_base_controller object which is cast into a
+ * struct scic_sds_controller object.
+ * @remote_device: This is struct sci_base_remote_device which, if it was used, would
+ * be cast to a struct scic_sds_remote_device.
+ * @io_request: This is the struct sci_base_request which, if it was used, would be
+ * cast to a SCIC_SDS_IO_REQUEST.
+ *
+ * This method is called when the struct scic_sds_controller default request handler
+ * is in place. - Issue a warning message enum sci_status SCI_FAILURE_INVALID_STATE
+ */
+static enum sci_status scic_sds_controller_default_request_handler(
+ struct sci_base_controller *controller,
+ struct sci_base_remote_device *remote_device,
+ struct sci_base_request *io_request)
+{
+ struct scic_sds_controller *this_controller;
+
+ this_controller = (struct scic_sds_controller *)controller;
+
+ dev_warn(scic_to_dev(this_controller),
+ "%s: SCIC Controller request operation from invalid state %d\n",
+ __func__,
+ sci_base_state_machine_get_state(
+ scic_sds_controller_get_base_state_machine(
+ this_controller)));
+
+ return SCI_FAILURE_INVALID_STATE;
+}
+
+/*
+ * *****************************************************************************
+ * * GENERAL (COMMON) STATE HANDLERS
+ * ***************************************************************************** */
+
+/**
+ *
+ * @controller: The struct sci_base_controller object which is cast into a
+ * struct scic_sds_controller object.
+ *
+ * This method is called when the struct scic_sds_controller is in the ready state
+ * reset handler is in place. - Transition to
+ * SCI_BASE_CONTROLLER_STATE_RESETTING enum sci_status SCI_SUCCESS
+ */
+static enum sci_status scic_sds_controller_general_reset_handler(
+ struct sci_base_controller *controller)
+{
+ struct scic_sds_controller *this_controller;
+
+ this_controller = (struct scic_sds_controller *)controller;
+
+ /*
+ * The reset operation is not a graceful cleanup just perform the state
+ * transition. */
+ sci_base_state_machine_change_state(
+ scic_sds_controller_get_base_state_machine(this_controller),
+ SCI_BASE_CONTROLLER_STATE_RESETTING
+ );
+
+ return SCI_SUCCESS;
+}
+
+/*
+ * *****************************************************************************
+ * * RESET STATE HANDLERS
+ * ***************************************************************************** */
+
+/**
+ *
+ * @controller: This is the struct sci_base_controller object which is cast into a
+ * struct scic_sds_controller object.
+ *
+ * This method is the struct scic_sds_controller initialize handler for the reset
+ * state. - Currently this function does nothing enum sci_status SCI_FAILURE This
+ * function is not yet implemented and is a valid request from the reset state.
+ */
+static enum sci_status scic_sds_controller_reset_state_initialize_handler(
+ struct sci_base_controller *controller)
+{
+ u32 index;
+ enum sci_status result = SCI_SUCCESS;
+ struct scic_sds_controller *this_controller;
+
+ this_controller = (struct scic_sds_controller *)controller;
+
+ sci_base_state_machine_change_state(
+ scic_sds_controller_get_base_state_machine(this_controller),
+ SCI_BASE_CONTROLLER_STATE_INITIALIZING
+ );
+
+ this_controller->timeout_timer = scic_cb_timer_create(
+ this_controller,
+ (void (*)(void *))scic_sds_controller_timeout_handler,
+ (void (*)(void *))controller);
+
+ scic_sds_controller_initialize_phy_startup(this_controller);
+
+ scic_sds_controller_initialize_power_control(this_controller);
+
+ /*
+ * There is nothing to do here for B0 since we do not have to
+ * program the AFE registers.
+ * / @todo The AFE settings are supposed to be correct for the B0 but
+ * / presently they seem to be wrong. */
+ scic_sds_controller_afe_initialization(this_controller);
+
+ if (SCI_SUCCESS == result) {
+ u32 status;
+ u32 terminate_loop;
+
+ /* Take the hardware out of reset */
+ SMU_SMUSRCR_WRITE(this_controller, 0x00000000);
+
+ /*
+ * / @todo Provide meaningfull error code for hardware failure
+ * result = SCI_FAILURE_CONTROLLER_HARDWARE; */
+ result = SCI_FAILURE;
+ terminate_loop = 100;
+
+ while (terminate_loop-- && (result != SCI_SUCCESS)) {
+ /* Loop until the hardware reports success */
+ scic_cb_stall_execution(SCU_CONTEXT_RAM_INIT_STALL_TIME);
+ status = SMU_SMUCSR_READ(this_controller);
+
+ if ((status & SCU_RAM_INIT_COMPLETED) == SCU_RAM_INIT_COMPLETED) {
+ result = SCI_SUCCESS;
+ }
+ }
+ }
+
+ if (result == SCI_SUCCESS) {
+ u32 max_supported_ports;
+ u32 max_supported_devices;
+ u32 max_supported_io_requests;
+ u32 device_context_capacity;
+
+ /*
+ * Determine what are the actaul device capacities that the
+ * hardware will support */
+ device_context_capacity = SMU_DCC_READ(this_controller);
+
+ max_supported_ports =
+ smu_dcc_get_max_ports(device_context_capacity);
+ max_supported_devices =
+ smu_dcc_get_max_remote_node_context(device_context_capacity);
+ max_supported_io_requests =
+ smu_dcc_get_max_task_context(device_context_capacity);
+
+ /* Make all PEs that are unassigned match up with the logical ports */
+ for (index = 0; index < max_supported_ports; index++) {
+ scu_register_write(
+ this_controller,
+ this_controller->scu_registers->peg0.ptsg.protocol_engine[index],
+ index
+ );
+ }
+
+ /* Record the smaller of the two capacity values */
+ this_controller->logical_port_entries =
+ min(max_supported_ports, this_controller->logical_port_entries);
+
+ this_controller->task_context_entries =
+ min(max_supported_io_requests, this_controller->task_context_entries);
+
+ this_controller->remote_node_entries =
+ min(max_supported_devices, this_controller->remote_node_entries);
+
+ /*
+ * Now that we have the correct hardware reported minimum values
+ * build the MDL for the controller. Default to a performance
+ * configuration. */
+ scic_controller_set_mode(this_controller, SCI_MODE_SPEED);
+ }
+
+ /* Initialize hardware PCI Relaxed ordering in DMA engines */
+ if (result == SCI_SUCCESS) {
+ u32 dma_configuration;
+
+ /* Configure the payload DMA */
+ dma_configuration = SCU_PDMACR_READ(this_controller);
+ dma_configuration |= SCU_PDMACR_GEN_BIT(PCI_RELAXED_ORDERING_ENABLE);
+ SCU_PDMACR_WRITE(this_controller, dma_configuration);
+
+ /* Configure the control DMA */
+ dma_configuration = SCU_CDMACR_READ(this_controller);
+ dma_configuration |= SCU_CDMACR_GEN_BIT(PCI_RELAXED_ORDERING_ENABLE);
+ SCU_CDMACR_WRITE(this_controller, dma_configuration);
+ }
+
+ /*
+ * Initialize the PHYs before the PORTs because the PHY registers
+ * are accessed during the port initialization. */
+ if (result == SCI_SUCCESS) {
+ /* Initialize the phys */
+ for (index = 0;
+ (result == SCI_SUCCESS) && (index < SCI_MAX_PHYS);
+ index++) {
+ result = scic_sds_phy_initialize(
+ &this_controller->phy_table[index],
+ &this_controller->scu_registers->peg0.pe[index].ll
+ );
+ }
+ }
+
+ if (result == SCI_SUCCESS) {
+ /* Initialize the logical ports */
+ for (index = 0;
+ (index < this_controller->logical_port_entries)
+ && (result == SCI_SUCCESS);
+ index++) {
+ result = scic_sds_port_initialize(
+ &this_controller->port_table[index],
+ &this_controller->scu_registers->peg0.pe[index].tl,
+ &this_controller->scu_registers->peg0.ptsg.port[index],
+ &this_controller->scu_registers->peg0.ptsg.protocol_engine,
+ &this_controller->scu_registers->peg0.viit[index]
+ );
+ }
+ }
+
+ if (SCI_SUCCESS == result) {
+ result = scic_sds_port_configuration_agent_initialize(
+ this_controller,
+ &this_controller->port_agent
+ );
+ }
+
+ /* Advance the controller state machine */
+ if (result == SCI_SUCCESS) {
+ sci_base_state_machine_change_state(
+ scic_sds_controller_get_base_state_machine(this_controller),
+ SCI_BASE_CONTROLLER_STATE_INITIALIZED
+ );
+ } else {
+ sci_base_state_machine_change_state(
+ scic_sds_controller_get_base_state_machine(this_controller),
+ SCI_BASE_CONTROLLER_STATE_FAILED
+ );
+ }
+
+ return result;
+}
+
+/*
+ * *****************************************************************************
+ * * INITIALIZED STATE HANDLERS
+ * ***************************************************************************** */
+
+/**
+ *
+ * @controller: This is the struct sci_base_controller object which is cast into a
+ * struct scic_sds_controller object.
+ * @timeout: This is the allowed time for the controller object to reach the
+ * started state.
+ *
+ * This method is the struct scic_sds_controller start handler for the initialized
+ * state. - Validate we have a good memory descriptor table - Initialze the
+ * physical memory before programming the hardware - Program the SCU hardware
+ * with the physical memory addresses passed in the memory descriptor table. -
+ * Initialzie the TCi pool - Initialize the RNi pool - Initialize the
+ * completion queue - Initialize the unsolicited frame data - Take the SCU port
+ * task scheduler out of reset - Start the first phy object. - Transition to
+ * SCI_BASE_CONTROLLER_STATE_STARTING. enum sci_status SCI_SUCCESS if all of the
+ * controller start operations complete
+ * SCI_FAILURE_UNSUPPORTED_INFORMATION_FIELD if one or more of the memory
+ * descriptor fields is invalid.
+ */
+static enum sci_status scic_sds_controller_initialized_state_start_handler(
+ struct sci_base_controller *controller,
+ u32 timeout)
+{
+ u16 index;
+ enum sci_status result;
+ struct scic_sds_controller *this_controller;
+
+ this_controller = (struct scic_sds_controller *)controller;
+
+ /* Make sure that the SCI User filled in the memory descriptor table correctly */
+ result = scic_sds_controller_validate_memory_descriptor_table(this_controller);
+
+ if (result == SCI_SUCCESS) {
+ /* The memory descriptor list looks good so program the hardware */
+ scic_sds_controller_ram_initialization(this_controller);
+ }
+
+ if (SCI_SUCCESS == result) {
+ /* Build the TCi free pool */
+ sci_pool_initialize(this_controller->tci_pool);
+ for (index = 0; index < this_controller->task_context_entries; index++) {
+ sci_pool_put(this_controller->tci_pool, index);
+ }
+
+ /* Build the RNi free pool */
+ scic_sds_remote_node_table_initialize(
+ &this_controller->available_remote_nodes,
+ this_controller->remote_node_entries
+ );
+ }
+
+ if (SCI_SUCCESS == result) {
+ /*
+ * Before anything else lets make sure we will not be interrupted
+ * by the hardware. */
+ scic_controller_disable_interrupts(this_controller);
+
+ /* Enable the port task scheduler */
+ scic_sds_controller_enable_port_task_scheduler(this_controller);
+
+ /* Assign all the task entries to this controller physical function */
+ scic_sds_controller_assign_task_entries(this_controller);
+
+ /* Now initialze the completion queue */
+ scic_sds_controller_initialize_completion_queue(this_controller);
+
+ /* Initialize the unsolicited frame queue for use */
+ scic_sds_controller_initialize_unsolicited_frame_queue(this_controller);
+ }
+
+ if (SCI_SUCCESS == result) {
+ scic_sds_controller_start_next_phy(this_controller);
+
+ scic_cb_timer_start(this_controller,
+ this_controller->timeout_timer,
+ timeout);
+
+ sci_base_state_machine_change_state(
+ scic_sds_controller_get_base_state_machine(this_controller),
+ SCI_BASE_CONTROLLER_STATE_STARTING
+ );
+ }
+
+ return result;
+}
+
+/*
+ * *****************************************************************************
+ * * INITIALIZED STATE HANDLERS
+ * ***************************************************************************** */
+
+/**
+ *
+ * @controller: This is struct scic_sds_controller which receives the link up
+ * notification.
+ * @port: This is struct scic_sds_port with which the phy is associated.
+ * @phy: This is the struct scic_sds_phy which has gone link up.
+ *
+ * This method is called when the struct scic_sds_controller is in the starting state
+ * link up handler is called. This method will perform the following: - Stop
+ * the phy timer - Start the next phy - Report the link up condition to the
+ * port object none
+ */
+static void scic_sds_controller_starting_state_link_up_handler(
+ struct scic_sds_controller *this_controller,
+ struct scic_sds_port *port,
+ struct scic_sds_phy *phy)
+{
+ scic_sds_controller_phy_timer_stop(this_controller);
+
+ this_controller->port_agent.link_up_handler(
+ this_controller, &this_controller->port_agent, port, phy
+ );
+ /* scic_sds_port_link_up(port, phy); */
+
+ scic_sds_controller_start_next_phy(this_controller);
+}
+
+/**
+ *
+ * @controller: This is struct scic_sds_controller which receives the link down
+ * notification.
+ * @port: This is struct scic_sds_port with which the phy is associated.
+ * @phy: This is the struct scic_sds_phy which has gone link down.
+ *
+ * This method is called when the struct scic_sds_controller is in the starting state
+ * link down handler is called. - Report the link down condition to the port
+ * object none
+ */
+static void scic_sds_controller_starting_state_link_down_handler(
+ struct scic_sds_controller *this_controller,
+ struct scic_sds_port *port,
+ struct scic_sds_phy *phy)
+{
+ this_controller->port_agent.link_down_handler(
+ this_controller, &this_controller->port_agent, port, phy
+ );
+ /* scic_sds_port_link_down(port, phy); */
+}
+
+/*
+ * *****************************************************************************
+ * * READY STATE HANDLERS
+ * ***************************************************************************** */
+
+/**
+ *
+ * @controller: The struct sci_base_controller object which is cast into a
+ * struct scic_sds_controller object.
+ * @timeout: The timeout for when the stop operation should report a failure.
+ *
+ * This method is called when the struct scic_sds_controller is in the ready state
+ * stop handler is called. - Start the timeout timer - Transition to
+ * SCI_BASE_CONTROLLER_STATE_STOPPING. enum sci_status SCI_SUCCESS
+ */
+static enum sci_status scic_sds_controller_ready_state_stop_handler(
+ struct sci_base_controller *controller,
+ u32 timeout)
+{
+ struct scic_sds_controller *this_controller;
+
+ this_controller = (struct scic_sds_controller *)controller;
+
+ scic_cb_timer_start(this_controller,
+ this_controller->timeout_timer,
+ timeout);
+
+ sci_base_state_machine_change_state(
+ scic_sds_controller_get_base_state_machine(this_controller),
+ SCI_BASE_CONTROLLER_STATE_STOPPING
+ );
+
+ return SCI_SUCCESS;
+}
+
+/**
+ *
+ * @controller: This is struct sci_base_controller object which is cast into a
+ * struct scic_sds_controller object.
+ * @remote_device: This is struct sci_base_remote_device which is cast to a
+ * struct scic_sds_remote_device object.
+ * @io_request: This is the struct sci_base_request which is cast to a
+ * SCIC_SDS_IO_REQUEST object.
+ * @io_tag: This is the IO tag to be assigned to the IO request or
+ * SCI_CONTROLLER_INVALID_IO_TAG.
+ *
+ * This method is called when the struct scic_sds_controller is in the ready state and
+ * the start io handler is called. - Start the io request on the remote device
+ * - if successful - assign the io_request to the io_request_table - post the
+ * request to the hardware enum sci_status SCI_SUCCESS if the start io operation
+ * succeeds SCI_FAILURE_INSUFFICIENT_RESOURCES if the IO tag could not be
+ * allocated for the io request. SCI_FAILURE_INVALID_STATE if one or more
+ * objects are not in a valid state to accept io requests. How does the io_tag
+ * parameter get assigned to the io request?
+ */
+static enum sci_status scic_sds_controller_ready_state_start_io_handler(
+ struct sci_base_controller *controller,
+ struct sci_base_remote_device *remote_device,
+ struct sci_base_request *io_request,
+ u16 io_tag)
+{
+ enum sci_status status;
+
+ struct scic_sds_controller *this_controller;
+ struct scic_sds_request *the_request;
+ struct scic_sds_remote_device *the_device;
+
+ this_controller = (struct scic_sds_controller *)controller;
+ the_request = (struct scic_sds_request *)io_request;
+ the_device = (struct scic_sds_remote_device *)remote_device;
+
+ status = scic_sds_remote_device_start_io(this_controller, the_device, the_request);
+
+ if (status == SCI_SUCCESS) {
+ this_controller->io_request_table[
+ scic_sds_io_tag_get_index(the_request->io_tag)] = the_request;
+
+ scic_sds_controller_post_request(
+ this_controller,
+ scic_sds_request_get_post_context(the_request)
+ );
+ }
+
+ return status;
+}
+
+/**
+ *
+ * @controller: This is struct sci_base_controller object which is cast into a
+ * struct scic_sds_controller object.
+ * @remote_device: This is struct sci_base_remote_device which is cast to a
+ * struct scic_sds_remote_device object.
+ * @io_request: This is the struct sci_base_request which is cast to a
+ * SCIC_SDS_IO_REQUEST object.
+ *
+ * This method is called when the struct scic_sds_controller is in the ready state and
+ * the complete io handler is called. - Complete the io request on the remote
+ * device - if successful - remove the io_request to the io_request_table
+ * enum sci_status SCI_SUCCESS if the start io operation succeeds
+ * SCI_FAILURE_INVALID_STATE if one or more objects are not in a valid state to
+ * accept io requests.
+ */
+static enum sci_status scic_sds_controller_ready_state_complete_io_handler(
+ struct sci_base_controller *controller,
+ struct sci_base_remote_device *remote_device,
+ struct sci_base_request *io_request)
+{
+ u16 index;
+ enum sci_status status;
+ struct scic_sds_controller *this_controller;
+ struct scic_sds_request *the_request;
+ struct scic_sds_remote_device *the_device;
+
+ this_controller = (struct scic_sds_controller *)controller;
+ the_request = (struct scic_sds_request *)io_request;
+ the_device = (struct scic_sds_remote_device *)remote_device;
+
+ status = scic_sds_remote_device_complete_io(
+ this_controller, the_device, the_request);
+
+ if (status == SCI_SUCCESS) {
+ index = scic_sds_io_tag_get_index(the_request->io_tag);
+ this_controller->io_request_table[index] = SCI_INVALID_HANDLE;
+ }
+
+ return status;
+}
+
+/**
+ *
+ * @controller: This is struct sci_base_controller object which is cast into a
+ * struct scic_sds_controller object.
+ * @remote_device: This is struct sci_base_remote_device which is cast to a
+ * struct scic_sds_remote_device object.
+ * @io_request: This is the struct sci_base_request which is cast to a
+ * SCIC_SDS_IO_REQUEST object.
+ *
+ * This method is called when the struct scic_sds_controller is in the ready state and
+ * the continue io handler is called. enum sci_status
+ */
+static enum sci_status scic_sds_controller_ready_state_continue_io_handler(
+ struct sci_base_controller *controller,
+ struct sci_base_remote_device *remote_device,
+ struct sci_base_request *io_request)
+{
+ struct scic_sds_controller *this_controller;
+ struct scic_sds_request *the_request;
+
+ the_request = (struct scic_sds_request *)io_request;
+ this_controller = (struct scic_sds_controller *)controller;
+
+ this_controller->io_request_table[
+ scic_sds_io_tag_get_index(the_request->io_tag)] = the_request;
+
+ scic_sds_controller_post_request(
+ this_controller,
+ scic_sds_request_get_post_context(the_request)
+ );
+
+ return SCI_SUCCESS;
+}
+
+/**
+ *
+ * @controller: This is struct sci_base_controller object which is cast into a
+ * struct scic_sds_controller object.
+ * @remote_device: This is struct sci_base_remote_device which is cast to a
+ * struct scic_sds_remote_device object.
+ * @io_request: This is the struct sci_base_request which is cast to a
+ * SCIC_SDS_IO_REQUEST object.
+ * @task_tag: This is the task tag to be assigned to the task request or
+ * SCI_CONTROLLER_INVALID_IO_TAG.
+ *
+ * This method is called when the struct scic_sds_controller is in the ready state and
+ * the start task handler is called. - The remote device is requested to start
+ * the task request - if successful - assign the task to the io_request_table -
+ * post the request to the SCU hardware enum sci_status SCI_SUCCESS if the start io
+ * operation succeeds SCI_FAILURE_INSUFFICIENT_RESOURCES if the IO tag could
+ * not be allocated for the io request. SCI_FAILURE_INVALID_STATE if one or
+ * more objects are not in a valid state to accept io requests. How does the io
+ * tag get assigned in this code path?
+ */
+static enum sci_status scic_sds_controller_ready_state_start_task_handler(
+ struct sci_base_controller *controller,
+ struct sci_base_remote_device *remote_device,
+ struct sci_base_request *io_request,
+ u16 task_tag)
+{
+ struct scic_sds_controller *this_controller = (struct scic_sds_controller *)
+ controller;
+ struct scic_sds_request *the_request = (struct scic_sds_request *)
+ io_request;
+ struct scic_sds_remote_device *the_device = (struct scic_sds_remote_device *)
+ remote_device;
+ enum sci_status status;
+
+ status = scic_sds_remote_device_start_task(
+ this_controller, the_device, the_request
+ );
+
+ if (status == SCI_SUCCESS) {
+ this_controller->io_request_table[
+ scic_sds_io_tag_get_index(the_request->io_tag)] = the_request;
+
+ scic_sds_controller_post_request(
+ this_controller,
+ scic_sds_request_get_post_context(the_request)
+ );
+ } else if (status == SCI_FAILURE_RESET_DEVICE_PARTIAL_SUCCESS) {
+ this_controller->io_request_table[
+ scic_sds_io_tag_get_index(the_request->io_tag)] = the_request;
+
+ /*
+ * We will let framework know this task request started successfully,
+ * although core is still woring on starting the request (to post tc when
+ * RNC is resumed.) */
+ status = SCI_SUCCESS;
+ }
+ return status;
+}
+
+/**
+ *
+ * @controller: This is struct sci_base_controller object which is cast into a
+ * struct scic_sds_controller object.
+ * @remote_device: This is struct sci_base_remote_device which is cast to a
+ * struct scic_sds_remote_device object.
+ * @io_request: This is the struct sci_base_request which is cast to a
+ * SCIC_SDS_IO_REQUEST object.
+ *
+ * This method is called when the struct scic_sds_controller is in the ready state and
+ * the terminate request handler is called. - call the io request terminate
+ * function - if successful - post the terminate request to the SCU hardware
+ * enum sci_status SCI_SUCCESS if the start io operation succeeds
+ * SCI_FAILURE_INVALID_STATE if one or more objects are not in a valid state to
+ * accept io requests.
+ */
+static enum sci_status scic_sds_controller_ready_state_terminate_request_handler(
+ struct sci_base_controller *controller,
+ struct sci_base_remote_device *remote_device,
+ struct sci_base_request *io_request)
+{
+ struct scic_sds_controller *this_controller = (struct scic_sds_controller *)
+ controller;
+ struct scic_sds_request *the_request = (struct scic_sds_request *)
+ io_request;
+ enum sci_status status;
+
+ status = scic_sds_io_request_terminate(the_request);
+ if (status == SCI_SUCCESS) {
+ /*
+ * Utilize the original post context command and or in the POST_TC_ABORT
+ * request sub-type. */
+ scic_sds_controller_post_request(
+ this_controller,
+ scic_sds_request_get_post_context(the_request)
+ | SCU_CONTEXT_COMMAND_REQUEST_POST_TC_ABORT
+ );
+ }
+
+ return status;
+}
+
+/**
+ *
+ * @controller: This is struct scic_sds_controller which receives the link up
+ * notification.
+ * @port: This is struct scic_sds_port with which the phy is associated.
+ * @phy: This is the struct scic_sds_phy which has gone link up.
+ *
+ * This method is called when the struct scic_sds_controller is in the starting state
+ * link up handler is called. This method will perform the following: - Stop
+ * the phy timer - Start the next phy - Report the link up condition to the
+ * port object none
+ */
+static void scic_sds_controller_ready_state_link_up_handler(
+ struct scic_sds_controller *this_controller,
+ struct scic_sds_port *port,
+ struct scic_sds_phy *phy)
+{
+ this_controller->port_agent.link_up_handler(
+ this_controller, &this_controller->port_agent, port, phy
+ );
+}
+
+/**
+ *
+ * @controller: This is struct scic_sds_controller which receives the link down
+ * notification.
+ * @port: This is struct scic_sds_port with which the phy is associated.
+ * @phy: This is the struct scic_sds_phy which has gone link down.
+ *
+ * This method is called when the struct scic_sds_controller is in the starting state
+ * link down handler is called. - Report the link down condition to the port
+ * object none
+ */
+static void scic_sds_controller_ready_state_link_down_handler(
+ struct scic_sds_controller *this_controller,
+ struct scic_sds_port *port,
+ struct scic_sds_phy *phy)
+{
+ this_controller->port_agent.link_down_handler(
+ this_controller, &this_controller->port_agent, port, phy
+ );
+}
+
+/*
+ * *****************************************************************************
+ * * STOPPING STATE HANDLERS
+ * ***************************************************************************** */
+
+/**
+ *
+ * @controller: This is struct sci_base_controller object which is cast into a
+ * struct scic_sds_controller object.
+ * @remote_device: This is struct sci_base_remote_device which is cast to a
+ * struct scic_sds_remote_device object.
+ * @io_request: This is the struct sci_base_request which is cast to a
+ * SCIC_SDS_IO_REQUEST object.
+ *
+ * This method is called when the struct scic_sds_controller is in a stopping state
+ * and the complete io handler is called. - This function is not yet
+ * implemented enum sci_status SCI_FAILURE
+ */
+static enum sci_status scic_sds_controller_stopping_state_complete_io_handler(
+ struct sci_base_controller *controller,
+ struct sci_base_remote_device *remote_device,
+ struct sci_base_request *io_request)
+{
+ struct scic_sds_controller *this_controller;
+
+ this_controller = (struct scic_sds_controller *)controller;
+
+ /* / @todo Implement this function */
+ return SCI_FAILURE;
+}
+
+/**
+ *
+ * @controller: This is struct sci_base_controller object which is cast into a
+ * struct scic_sds_controller object.
+ * @remote_device: This is struct sci_base_remote_device which is cast to a
+ * struct scic_sds_remote_device object.
+ * @io_request: This is the struct sci_base_request which is cast to a
+ * SCIC_SDS_IO_REQUEST object.
+ *
+ * This method is called when the struct scic_sds_controller is in a stopping state
+ * and the complete task handler is called. - This function is not yet
+ * implemented enum sci_status SCI_FAILURE
+ */
+
+/*
+ * *****************************************************************************
+ * * STOPPED STATE HANDLERS
+ * ***************************************************************************** */
+
+/*
+ * *****************************************************************************
+ * * FAILED STATE HANDLERS
+ * ***************************************************************************** */
+
+const struct scic_sds_controller_state_handler scic_sds_controller_state_handler_table[] = {
+ [SCI_BASE_CONTROLLER_STATE_INITIAL] = {
+ .base.start_io = scic_sds_controller_default_start_operation_handler,
+ .base.complete_io = scic_sds_controller_default_request_handler,
+ .base.continue_io = scic_sds_controller_default_request_handler,
+ .terminate_request = scic_sds_controller_default_request_handler,
+ },
+ [SCI_BASE_CONTROLLER_STATE_RESET] = {
+ .base.initialize = scic_sds_controller_reset_state_initialize_handler,
+ .base.start_io = scic_sds_controller_default_start_operation_handler,
+ .base.complete_io = scic_sds_controller_default_request_handler,
+ .base.continue_io = scic_sds_controller_default_request_handler,
+ .terminate_request = scic_sds_controller_default_request_handler,
+ },
+ [SCI_BASE_CONTROLLER_STATE_INITIALIZING] = {
+ .base.start_io = scic_sds_controller_default_start_operation_handler,
+ .base.complete_io = scic_sds_controller_default_request_handler,
+ .base.continue_io = scic_sds_controller_default_request_handler,
+ .terminate_request = scic_sds_controller_default_request_handler,
+ },
+ [SCI_BASE_CONTROLLER_STATE_INITIALIZED] = {
+ .base.start = scic_sds_controller_initialized_state_start_handler,
+ .base.start_io = scic_sds_controller_default_start_operation_handler,
+ .base.complete_io = scic_sds_controller_default_request_handler,
+ .base.continue_io = scic_sds_controller_default_request_handler,
+ .terminate_request = scic_sds_controller_default_request_handler,
+ },
+ [SCI_BASE_CONTROLLER_STATE_STARTING] = {
+ .base.start_io = scic_sds_controller_default_start_operation_handler,
+ .base.complete_io = scic_sds_controller_default_request_handler,
+ .base.continue_io = scic_sds_controller_default_request_handler,
+ .terminate_request = scic_sds_controller_default_request_handler,
+ .link_up = scic_sds_controller_starting_state_link_up_handler,
+ .link_down = scic_sds_controller_starting_state_link_down_handler
+ },
+ [SCI_BASE_CONTROLLER_STATE_READY] = {
+ .base.stop = scic_sds_controller_ready_state_stop_handler,
+ .base.reset = scic_sds_controller_general_reset_handler,
+ .base.start_io = scic_sds_controller_ready_state_start_io_handler,
+ .base.complete_io = scic_sds_controller_ready_state_complete_io_handler,
+ .base.continue_io = scic_sds_controller_ready_state_continue_io_handler,
+ .base.start_task = scic_sds_controller_ready_state_start_task_handler,
+ .base.complete_task = scic_sds_controller_ready_state_complete_io_handler,
+ .terminate_request = scic_sds_controller_ready_state_terminate_request_handler,
+ .link_up = scic_sds_controller_ready_state_link_up_handler,
+ .link_down = scic_sds_controller_ready_state_link_down_handler
+ },
+ [SCI_BASE_CONTROLLER_STATE_RESETTING] = {
+ .base.start_io = scic_sds_controller_default_start_operation_handler,
+ .base.complete_io = scic_sds_controller_default_request_handler,
+ .base.continue_io = scic_sds_controller_default_request_handler,
+ .terminate_request = scic_sds_controller_default_request_handler,
+ },
+ [SCI_BASE_CONTROLLER_STATE_STOPPING] = {
+ .base.start_io = scic_sds_controller_default_start_operation_handler,
+ .base.complete_io = scic_sds_controller_stopping_state_complete_io_handler,
+ .base.continue_io = scic_sds_controller_default_request_handler,
+ .terminate_request = scic_sds_controller_default_request_handler,
+ },
+ [SCI_BASE_CONTROLLER_STATE_STOPPED] = {
+ .base.reset = scic_sds_controller_general_reset_handler,
+ .base.start_io = scic_sds_controller_default_start_operation_handler,
+ .base.complete_io = scic_sds_controller_default_request_handler,
+ .base.continue_io = scic_sds_controller_default_request_handler,
+ .terminate_request = scic_sds_controller_default_request_handler,
+ },
+ [SCI_BASE_CONTROLLER_STATE_FAILED] = {
+ .base.reset = scic_sds_controller_general_reset_handler,
+ .base.start_io = scic_sds_controller_default_start_operation_handler,
+ .base.complete_io = scic_sds_controller_default_request_handler,
+ .base.continue_io = scic_sds_controller_default_request_handler,
+ .terminate_request = scic_sds_controller_default_request_handler,
+ },
+};
+
+/**
+ *
+ * @object: This is the struct sci_base_object which is cast to a struct scic_sds_controller
+ * object.
+ *
+ * This method implements the actions taken by the struct scic_sds_controller on entry
+ * to the SCI_BASE_CONTROLLER_STATE_INITIAL. - Set the state handlers to the
+ * controllers initial state. none This function should initialze the
+ * controller object.
+ */
+static void scic_sds_controller_initial_state_enter(
+ struct sci_base_object *object)
+{
+ struct scic_sds_controller *this_controller;
+
+ this_controller = (struct scic_sds_controller *)object;
+
+ sci_base_state_machine_change_state(
+ &this_controller->parent.state_machine, SCI_BASE_CONTROLLER_STATE_RESET);
+}
+
+/**
+ *
+ * @object: This is the struct sci_base_object which is cast to a struct scic_sds_controller
+ * object.
+ *
+ * This method implements the actions taken by the struct scic_sds_controller on exit
+ * from the SCI_BASE_CONTROLLER_STATE_STARTING. - This function stops the
+ * controller starting timeout timer. none
+ */
+static void scic_sds_controller_starting_state_exit(
+ struct sci_base_object *object)
+{
+ struct scic_sds_controller *scic = (struct scic_sds_controller *)object;
+
+ scic_cb_timer_stop(scic, scic->timeout_timer);
+}
+
+/**
+ *
+ * @object: This is the struct sci_base_object which is cast to a struct scic_sds_controller
+ * object.
+ *
+ * This method implements the actions taken by the struct scic_sds_controller on entry
+ * to the SCI_BASE_CONTROLLER_STATE_READY. - Set the state handlers to the
+ * controllers ready state. none
+ */
+static void scic_sds_controller_ready_state_enter(
+ struct sci_base_object *object)
+{
+ struct scic_sds_controller *this_controller;
+
+ this_controller = (struct scic_sds_controller *)object;
+
+ /* set the default interrupt coalescence number and timeout value. */
+ scic_controller_set_interrupt_coalescence(
+ this_controller, 0x10, 250);
+}
+
+/**
+ *
+ * @object: This is the struct sci_base_object which is cast to a struct scic_sds_controller
+ * object.
+ *
+ * This method implements the actions taken by the struct scic_sds_controller on exit
+ * from the SCI_BASE_CONTROLLER_STATE_READY. - This function does nothing. none
+ */
+static void scic_sds_controller_ready_state_exit(
+ struct sci_base_object *object)
+{
+ struct scic_sds_controller *this_controller;
+
+ this_controller = (struct scic_sds_controller *)object;
+
+ /* disable interrupt coalescence. */
+ scic_controller_set_interrupt_coalescence(this_controller, 0, 0);
+}
+
+/**
+ *
+ * @object: This is the struct sci_base_object which is cast to a struct scic_sds_controller
+ * object.
+ *
+ * This method implements the actions taken by the struct scic_sds_controller on entry
+ * to the SCI_BASE_CONTROLLER_STATE_READY. - Set the state handlers to the
+ * controllers ready state. - Stop the phys on this controller - Stop the ports
+ * on this controller - Stop all of the remote devices on this controller none
+ */
+static void scic_sds_controller_stopping_state_enter(
+ struct sci_base_object *object)
+{
+ struct scic_sds_controller *this_controller;
+
+ this_controller = (struct scic_sds_controller *)object;
+
+ /* Stop all of the components for this controller */
+ scic_sds_controller_stop_phys(this_controller);
+ scic_sds_controller_stop_ports(this_controller);
+ scic_sds_controller_stop_devices(this_controller);
+}
+
+/**
+ *
+ * @object: This is the struct sci_base_object which is cast to a struct scic_sds_controller
+ * object.
+ *
+ * This method implements the actions taken by the struct scic_sds_controller on exit
+ * from the SCI_BASE_CONTROLLER_STATE_STOPPING. - This function stops the
+ * controller stopping timeout timer. none
+ */
+static void scic_sds_controller_stopping_state_exit(
+ struct sci_base_object *object)
+{
+ struct scic_sds_controller *this_controller;
+
+ this_controller = (struct scic_sds_controller *)object;
+
+ scic_cb_timer_stop(this_controller, this_controller->timeout_timer);
+}
+
+/**
+ *
+ * @object: This is the struct sci_base_object which is cast to a struct scic_sds_controller
+ * object.
+ *
+ * This method implements the actions taken by the struct scic_sds_controller on entry
+ * to the SCI_BASE_CONTROLLER_STATE_RESETTING. - Set the state handlers to the
+ * controllers resetting state. - Write to the SCU hardware reset register to
+ * force a reset - Transition to the SCI_BASE_CONTROLLER_STATE_RESET none
+ */
+static void scic_sds_controller_resetting_state_enter(
+ struct sci_base_object *object)
+{
+ struct scic_sds_controller *this_controller;
+
+ this_controller = (struct scic_sds_controller *)object;
+
+ scic_sds_controller_reset_hardware(this_controller);
+
+ sci_base_state_machine_change_state(
+ scic_sds_controller_get_base_state_machine(this_controller),
+ SCI_BASE_CONTROLLER_STATE_RESET
+ );
+}
+
+/* --------------------------------------------------------------------------- */
+
+const struct sci_base_state scic_sds_controller_state_table[] = {
+ [SCI_BASE_CONTROLLER_STATE_INITIAL] = {
+ .enter_state = scic_sds_controller_initial_state_enter,
+ },
+ [SCI_BASE_CONTROLLER_STATE_RESET] = {},
+ [SCI_BASE_CONTROLLER_STATE_INITIALIZING] = {},
+ [SCI_BASE_CONTROLLER_STATE_INITIALIZED] = {},
+ [SCI_BASE_CONTROLLER_STATE_STARTING] = {
+ .exit_state = scic_sds_controller_starting_state_exit,
+ },
+ [SCI_BASE_CONTROLLER_STATE_READY] = {
+ .enter_state = scic_sds_controller_ready_state_enter,
+ .exit_state = scic_sds_controller_ready_state_exit,
+ },
+ [SCI_BASE_CONTROLLER_STATE_RESETTING] = {
+ .enter_state = scic_sds_controller_resetting_state_enter,
+ },
+ [SCI_BASE_CONTROLLER_STATE_STOPPING] = {
+ .enter_state = scic_sds_controller_stopping_state_enter,
+ .exit_state = scic_sds_controller_stopping_state_exit,
+ },
+ [SCI_BASE_CONTROLLER_STATE_STOPPED] = {},
+ [SCI_BASE_CONTROLLER_STATE_FAILED] = {}
+};
+
diff --git a/drivers/scsi/isci/core/scic_sds_controller.h b/drivers/scsi/isci/core/scic_sds_controller.h
new file mode 100644
index 000000000000..afa45f9874a4
--- /dev/null
+++ b/drivers/scsi/isci/core/scic_sds_controller.h
@@ -0,0 +1,706 @@
+/*
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Intel Corporation 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
+ * OWNER 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.
+ */
+
+#ifndef _SCIC_SDS_CONTROLLER_H_
+#define _SCIC_SDS_CONTROLLER_H_
+
+/**
+ * This file contains the structures, constants and prototypes used for the
+ * core controller object.
+ *
+ *
+ */
+
+#include "sci_pool.h"
+#include "sci_controller_constants.h"
+#include "sci_memory_descriptor_list.h"
+#include "sci_base_controller.h"
+#include "scic_config_parameters.h"
+#include "scic_sds_port.h"
+#include "scic_sds_phy.h"
+#include "scic_sds_remote_node_table.h"
+#include "scu_registers.h"
+#include "scu_constants.h"
+#include "scu_remote_node_context.h"
+#include "scu_task_context.h"
+#include "scu_unsolicited_frame.h"
+#include "scic_sds_unsolicited_frame_control.h"
+#include "scic_sds_port_configuration_agent.h"
+#include "scic_sds_pci.h"
+
+struct scic_sds_remote_device;
+struct scic_sds_request;
+struct scic_sds_controller;
+
+
+#define SCU_COMPLETION_RAM_ALIGNMENT (64)
+
+/**
+ * enum SCIC_SDS_CONTROLLER_MEMORY_DESCRIPTORS -
+ *
+ * This enumeration depects the types of MDEs that are going to be created for
+ * the controller object.
+ */
+enum SCIC_SDS_CONTROLLER_MEMORY_DESCRIPTORS {
+ /**
+ * Completion queue MDE entry
+ */
+ SCU_MDE_COMPLETION_QUEUE,
+
+ /**
+ * Remote node context MDE entry
+ */
+ SCU_MDE_REMOTE_NODE_CONTEXT,
+
+ /**
+ * Task context MDE entry
+ */
+ SCU_MDE_TASK_CONTEXT,
+
+ /**
+ * Unsolicited frame buffer MDE entrys this is the start of the unsolicited
+ * frame buffer entries.
+ */
+ SCU_MDE_UF_BUFFER,
+
+ SCU_MAX_MDES
+};
+
+/**
+ *
+ *
+ * Allowed PORT configuration modes APC Automatic PORT configuration mode is
+ * defined by the OEM configuration parameters providing no PHY_MASK parameters
+ * for any PORT. i.e. There are no phys assigned to any of the ports at start.
+ * MPC Manual PORT configuration mode is defined by the OEM configuration
+ * parameters providing a PHY_MASK value for any PORT. It is assumed that any
+ * PORT with no PHY_MASK is an invalid port and not all PHYs must be assigned.
+ * A PORT_PHY mask that assigns just a single PHY to a port and no other PHYs
+ * being assigned is sufficient to declare manual PORT configuration.
+ */
+enum SCIC_PORT_CONFIGURATION_MODE {
+ SCIC_PORT_MANUAL_CONFIGURATION_MODE,
+ SCIC_PORT_AUTOMATIC_CONFIGURATION_MODE
+};
+
+/**
+ * struct scic_power_control -
+ *
+ * This structure defines the fields for managing power control for direct
+ * attached disk devices.
+ */
+struct scic_power_control {
+ /**
+ * This field is set when the power control timer is running and cleared when
+ * it is not.
+ */
+ bool timer_started;
+
+ /**
+ * This field is the handle to the driver timer object. This timer is used to
+ * control when the directed attached disks can consume power.
+ */
+ void *timer;
+
+ /**
+ * This field is used to keep track of how many phys are put into the
+ * requesters field.
+ */
+ u8 phys_waiting;
+
+ /**
+ * This field is an array of phys that we are waiting on. The phys are direct
+ * mapped into requesters via struct scic_sds_phy.phy_index
+ */
+ struct scic_sds_phy *requesters[SCI_MAX_PHYS];
+
+};
+
+/**
+ * struct scic_sds_controller -
+ *
+ * This structure represents the SCU contoller object.
+ */
+struct scic_sds_controller {
+ /**
+ * The struct sci_base_controller is the parent object for the struct scic_sds_controller
+ * object.
+ */
+ struct sci_base_controller parent;
+
+ /**
+ * This field is the driver timer object handler used to time the controller
+ * object start and stop requests.
+ */
+ void *timeout_timer;
+
+ /**
+ * This field contains the user parameters to be utilized for this
+ * core controller object.
+ */
+ union scic_user_parameters user_parameters;
+
+ /**
+ * This field contains the OEM parameters to be utilized for this
+ * core controller object.
+ */
+ union scic_oem_parameters oem_parameters;
+
+ /**
+ * This field contains the port configuration agent for this controller.
+ */
+ struct scic_sds_port_configuration_agent port_agent;
+
+ /**
+ * This field is the array of port objects that are controlled by this
+ * controller object. There is one dummy port object also contained within
+ * this controller object.
+ */
+ struct scic_sds_port port_table[SCI_MAX_PORTS + 1];
+
+ /**
+ * This field is the array of phy objects that are controlled by this
+ * controller object.
+ */
+ struct scic_sds_phy phy_table[SCI_MAX_PHYS];
+
+ /**
+ * This field is the array of device objects that are currently constructed
+ * for this controller object. This table is used as a fast lookup of device
+ * objects that need to handle device completion notifications from the
+ * hardware. The table is RNi based.
+ */
+ struct scic_sds_remote_device *device_table[SCI_MAX_REMOTE_DEVICES];
+
+ /**
+ * This field is the array of IO request objects that are currently active for
+ * this controller object. This table is used as a fast lookup of the io
+ * request object that need to handle completion queue notifications. The
+ * table is TCi based.
+ */
+ struct scic_sds_request *io_request_table[SCI_MAX_IO_REQUESTS];
+
+ /**
+ * This field is the free RNi data structure
+ */
+ struct scic_remote_node_table available_remote_nodes;
+
+ /**
+ * This field is the TCi pool used to manage the task context index.
+ */
+ SCI_POOL_CREATE(tci_pool, u16, SCI_MAX_IO_REQUESTS);
+
+ /**
+ * This filed is the struct scic_power_control data used to controll when direct
+ * attached devices can consume power.
+ */
+ struct scic_power_control power_control;
+
+ /**
+ * This field is the array of sequence values for the IO Tag fields. Even
+ * though only 4 bits of the field is used for the sequence the sequence is 16
+ * bits in size so the sequence can be bitwise or'd with the TCi to build the
+ * IO Tag value.
+ */
+ u16 io_request_sequence[SCI_MAX_IO_REQUESTS];
+
+ /**
+ * This field in the array of sequence values for the RNi. These are used
+ * to control io request build to io request start operations. The sequence
+ * value is recorded into an io request when it is built and is checked on
+ * the io request start operation to make sure that there was not a device
+ * hot plug between the build and start operation.
+ */
+ u8 remote_device_sequence[SCI_MAX_REMOTE_DEVICES];
+
+ /**
+ * This field is a pointer to the memory allocated by the driver for the task
+ * context table. This data is shared between the hardware and software.
+ */
+ struct scu_task_context *task_context_table;
+
+ /**
+ * This field is a pointer to the memory allocated by the driver for the
+ * remote node context table. This table is shared between the hardware and
+ * software.
+ */
+ union scu_remote_node_context *remote_node_context_table;
+
+ /**
+ * This field is the array of physical memory requiremets for this controller
+ * object.
+ */
+ struct sci_physical_memory_descriptor memory_descriptors[SCU_MAX_MDES];
+
+ /**
+ * This field is a pointer to the completion queue. This memory is
+ * written to by the hardware and read by the software.
+ */
+ u32 *completion_queue;
+
+ /**
+ * This field is the software copy of the completion queue get pointer. The
+ * controller object writes this value to the hardware after processing the
+ * completion entries.
+ */
+ u32 completion_queue_get;
+
+ /**
+ * This field is the minimum of the number of hardware supported port entries
+ * and the software requested port entries.
+ */
+ u32 logical_port_entries;
+
+ /**
+ * This field is the minimum number of hardware supported completion queue
+ * entries and the software requested completion queue entries.
+ */
+ u32 completion_queue_entries;
+
+ /**
+ * This field is the minimum number of hardware supported event entries and
+ * the software requested event entries.
+ */
+ u32 completion_event_entries;
+
+ /**
+ * This field is the minimum number of devices supported by the hardware and
+ * the number of devices requested by the software.
+ */
+ u32 remote_node_entries;
+
+ /**
+ * This field is the minimum number of IO requests supported by the hardware
+ * and the number of IO requests requested by the software.
+ */
+ u32 task_context_entries;
+
+ /**
+ * This object contains all of the unsolicited frame specific
+ * data utilized by the core controller.
+ */
+ struct scic_sds_unsolicited_frame_control uf_control;
+
+ /**
+ * This field records the fact that the controller has encountered a fatal
+ * error and must be reset.
+ */
+ bool encountered_fatal_error;
+
+ /**
+ * This field specifies that the controller should ignore
+ * completion processing for non-fastpath events. This will
+ * cause the completions to be thrown away.
+ */
+ bool restrict_completions;
+
+ /* Phy Startup Data */
+ /**
+ * This field is the driver timer handle for controller phy request startup.
+ * On controller start the controller will start each PHY individually in
+ * order of phy index.
+ */
+ void *phy_startup_timer;
+
+ /**
+ * This field is set when the phy_startup_timer is running and is cleared when
+ * the phy_startup_timer is stopped.
+ */
+ bool phy_startup_timer_pending;
+
+ /**
+ * This field is the index of the next phy start. It is initialized to 0 and
+ * increments for each phy index that is started.
+ */
+ u32 next_phy_to_start;
+
+ /**
+ * This field controlls the invalid link up notifications to the SCI_USER. If
+ * an invalid_link_up notification is reported a bit for the PHY index is set
+ * so further notifications are not made. Once the PHY object reports link up
+ * and is made part of a port then this bit for the PHY index is cleared.
+ */
+ u8 invalid_phy_mask;
+
+ /*
+ * This field saves the current interrupt coalescing number of the controller.
+ */
+ u16 interrupt_coalesce_number;
+
+ /*
+ * This field saves the current interrupt coalescing timeout value in microseconds.
+ */
+ u32 interrupt_coalesce_timeout;
+
+ /**
+ * This field is a pointer to the memory mapped register space for the
+ * struct smu_registers.
+ */
+ struct smu_registers __iomem *smu_registers;
+
+ /**
+ * This field is a pointer to the memory mapped register space for the
+ * struct scu_registers.
+ */
+ struct scu_registers __iomem *scu_registers;
+
+};
+
+typedef void (*scic_sds_controller_phy_handler_t)(struct scic_sds_controller *,
+ struct scic_sds_port *,
+ struct scic_sds_phy *);
+/**
+ * struct scic_sds_controller_state_handler -
+ *
+ * This structure contains the SDS core specific definition for the state
+ * handlers.
+ */
+struct scic_sds_controller_state_handler {
+ struct sci_base_controller_state_handler base;
+
+ sci_base_controller_request_handler_t terminate_request;
+ scic_sds_controller_phy_handler_t link_up;
+ scic_sds_controller_phy_handler_t link_down;
+};
+
+extern const struct scic_sds_controller_state_handler
+ scic_sds_controller_state_handler_table[];
+extern const struct sci_base_state scic_sds_controller_state_table[];
+
+/**
+ * INCREMENT_QUEUE_GET() -
+ *
+ * This macro will increment the specified index to and if the index wraps to 0
+ * it will toggel the cycle bit.
+ */
+#define INCREMENT_QUEUE_GET(index, cycle, entry_count, bit_toggle) \
+ { \
+ if ((index) + 1 == entry_count) { \
+ (index) = 0; \
+ (cycle) = (cycle) ^ (bit_toggle); \
+ } else { \
+ index = index + 1; \
+ } \
+ }
+
+/**
+ * scic_sds_controller_get_base_state_machine() -
+ *
+ * This is a helper macro that gets the base state machine for the controller
+ * object
+ */
+#define scic_sds_controller_get_base_state_machine(this_controller) \
+ (&(this_controller)->parent.state_machine)
+
+/**
+ * scic_sds_controller_get_port_configuration_agent() -
+ *
+ * This is a helper macro to get the port configuration agent from the
+ * controller object.
+ */
+#define scic_sds_controller_get_port_configuration_agent(controller) \
+ (&(controller)->port_agent)
+
+/**
+ * smu_register_write() -
+ *
+ * This macro writes to the smu_register for this controller
+ */
+#define smu_register_write(controller, reg, value) \
+ scic_sds_pci_write_smu_dword((controller), &(reg), (value))
+
+/**
+ * smu_register_read() -
+ *
+ * This macro reads the smu_register for this controller
+ */
+#define smu_register_read(controller, reg) \
+ scic_sds_pci_read_smu_dword((controller), &(reg))
+
+/**
+ * scu_register_write() -
+ *
+ * This mcaro writes the scu_register for this controller
+ */
+#define scu_register_write(controller, reg, value) \
+ scic_sds_pci_write_scu_dword((controller), &(reg), (value))
+
+/**
+ * scu_register_read() -
+ *
+ * This macro reads the scu_register for this controller
+ */
+#define scu_register_read(controller, reg) \
+ scic_sds_pci_read_scu_dword((controller), &(reg))
+
+/**
+ * scic_sds_controller_get_protocol_engine_group() -
+ *
+ * This macro returns the protocol engine group for this controller object.
+ * Presently we only support protocol engine group 0 so just return that
+ */
+#define scic_sds_controller_get_protocol_engine_group(controller) 0
+
+/**
+ * scic_sds_io_tag_construct() -
+ *
+ * This macro constructs an IO tag from the sequence and index values.
+ */
+#define scic_sds_io_tag_construct(sequence, task_index) \
+ ((sequence) << 12 | (task_index))
+
+/**
+ * scic_sds_io_tag_get_sequence() -
+ *
+ * This macro returns the IO sequence from the IO tag value.
+ */
+#define scic_sds_io_tag_get_sequence(io_tag) \
+ (((io_tag) & 0xF000) >> 12)
+
+/**
+ * scic_sds_io_tag_get_index() -
+ *
+ * This macro returns the TCi from the io tag value
+ */
+#define scic_sds_io_tag_get_index(io_tag) \
+ ((io_tag) & 0x0FFF)
+
+/**
+ * scic_sds_io_sequence_increment() -
+ *
+ * This is a helper macro to increment the io sequence count. We may find in
+ * the future that it will be faster to store the sequence count in such a way
+ * as we dont perform the shift operation to build io tag values so therefore
+ * need a way to incrment them correctly
+ */
+#define scic_sds_io_sequence_increment(value) \
+ ((value) = (((value) + 1) & 0x000F))
+
+#define scic_sds_remote_device_node_count(device) \
+ (\
+ (\
+ (device)->target_protocols.u.bits.attached_stp_target \
+ && ((device)->is_direct_attached != true) \
+ ) \
+ ? SCU_STP_REMOTE_NODE_COUNT : SCU_SSP_REMOTE_NODE_COUNT \
+ )
+
+/**
+ * scic_sds_controller_set_invalid_phy() -
+ *
+ * This macro will set the bit in the invalid phy mask for this controller
+ * object. This is used to control messages reported for invalid link up
+ * notifications.
+ */
+#define scic_sds_controller_set_invalid_phy(controller, phy) \
+ ((controller)->invalid_phy_mask |= (1 << (phy)->phy_index))
+
+/**
+ * scic_sds_controller_clear_invalid_phy() -
+ *
+ * This macro will clear the bit in the invalid phy mask for this controller
+ * object. This is used to control messages reported for invalid link up
+ * notifications.
+ */
+#define scic_sds_controller_clear_invalid_phy(controller, phy) \
+ ((controller)->invalid_phy_mask &= ~(1 << (phy)->phy_index))
+
+/* --------------------------------------------------------------------------- */
+
+u32 scic_sds_controller_get_object_size(void);
+
+/* --------------------------------------------------------------------------- */
+
+
+/* --------------------------------------------------------------------------- */
+
+enum SCIC_PORT_CONFIGURATION_MODE scic_sds_controller_get_port_configuration_mode(
+ struct scic_sds_controller *this_controller);
+
+/* --------------------------------------------------------------------------- */
+
+void scic_sds_controller_post_request(
+ struct scic_sds_controller *this_controller,
+ u32 request);
+
+/* --------------------------------------------------------------------------- */
+
+void scic_sds_controller_release_frame(
+ struct scic_sds_controller *this_controller,
+ u32 frame_index);
+
+void scic_sds_controller_copy_sata_response(
+ void *response_buffer,
+ void *frame_header,
+ void *frame_buffer);
+
+/* --------------------------------------------------------------------------- */
+
+enum sci_status scic_sds_controller_allocate_remote_node_context(
+ struct scic_sds_controller *this_controller,
+ struct scic_sds_remote_device *the_device,
+ u16 *node_id);
+
+void scic_sds_controller_free_remote_node_context(
+ struct scic_sds_controller *this_controller,
+ struct scic_sds_remote_device *the_device,
+ u16 node_id);
+
+union scu_remote_node_context *scic_sds_controller_get_remote_node_context_buffer(
+ struct scic_sds_controller *this_controller,
+ u16 node_id);
+
+/* --------------------------------------------------------------------------- */
+
+struct scic_sds_request *scic_sds_controller_get_io_request_from_tag(
+ struct scic_sds_controller *this_controller,
+ u16 io_tag);
+
+
+struct scu_task_context *scic_sds_controller_get_task_context_buffer(
+ struct scic_sds_controller *this_controller,
+ u16 io_tag);
+
+/*
+ * *****************************************************************************
+ * * CORE CONTROLLER POWER CONTROL METHODS
+ * ***************************************************************************** */
+
+
+void scic_sds_controller_power_control_queue_insert(
+ struct scic_sds_controller *this_controller,
+ struct scic_sds_phy *the_phy);
+
+void scic_sds_controller_power_control_queue_remove(
+ struct scic_sds_controller *this_controller,
+ struct scic_sds_phy *the_phy);
+
+/*
+ * *****************************************************************************
+ * * CORE CONTROLLER PHY MESSAGE PROCESSING
+ * ***************************************************************************** */
+
+void scic_sds_controller_link_up(
+ struct scic_sds_controller *this_controller,
+ struct scic_sds_port *the_port,
+ struct scic_sds_phy *the_phy);
+
+void scic_sds_controller_link_down(
+ struct scic_sds_controller *this_controller,
+ struct scic_sds_port *the_port,
+ struct scic_sds_phy *the_phy);
+
+/*
+ * *****************************************************************************
+ * * CORE CONTROLLER PRIVATE METHODS
+ * ***************************************************************************** */
+
+enum sci_status scic_sds_controller_validate_memory_descriptor_table(
+ struct scic_sds_controller *this_controller);
+
+void scic_sds_controller_ram_initialization(
+ struct scic_sds_controller *this_controller);
+
+void scic_sds_controller_assign_task_entries(
+ struct scic_sds_controller *this_controller);
+
+void scic_sds_controller_afe_initialization(
+ struct scic_sds_controller *this_controller);
+
+void scic_sds_controller_enable_port_task_scheduler(
+ struct scic_sds_controller *this_controller);
+
+void scic_sds_controller_initialize_completion_queue(
+ struct scic_sds_controller *this_controller);
+
+void scic_sds_controller_initialize_unsolicited_frame_queue(
+ struct scic_sds_controller *this_controller);
+
+void scic_sds_controller_phy_timer_stop(
+ struct scic_sds_controller *this_controller);
+
+enum sci_status scic_sds_controller_start_next_phy(
+ struct scic_sds_controller *this_controller);
+
+enum sci_status scic_sds_controller_stop_phys(
+ struct scic_sds_controller *this_controller);
+
+enum sci_status scic_sds_controller_stop_ports(
+ struct scic_sds_controller *this_controller);
+
+enum sci_status scic_sds_controller_stop_devices(
+ struct scic_sds_controller *this_controller);
+
+void scic_sds_controller_copy_task_context(
+ struct scic_sds_controller *this_controller,
+ struct scic_sds_request *this_request);
+
+void scic_sds_controller_timeout_handler(
+ struct scic_sds_controller *controller);
+
+void scic_sds_controller_initialize_power_control(
+ struct scic_sds_controller *this_controller);
+
+void scic_sds_controller_register_setup(
+ struct scic_sds_controller *this_controller);
+
+void scic_sds_controller_reset_hardware(
+ struct scic_sds_controller *this_controller);
+
+
+void scic_sds_controller_initialize_phy_startup(
+ struct scic_sds_controller *this_controller);
+
+#endif /* _SCIC_SDS_CONTROLLER_H_ */
diff --git a/drivers/scsi/isci/core/scic_sds_controller_registers.h b/drivers/scsi/isci/core/scic_sds_controller_registers.h
new file mode 100644
index 000000000000..b7bec92ee59c
--- /dev/null
+++ b/drivers/scsi/isci/core/scic_sds_controller_registers.h
@@ -0,0 +1,463 @@
+/*
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Intel Corporation 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
+ * OWNER 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.
+ */
+
+#ifndef _SCIC_SDS_CONTROLLER_REGISTERS_H_
+#define _SCIC_SDS_CONTROLLER_REGISTERS_H_
+
+/**
+ * This file contains macros used to perform the register reads/writes to the
+ * SCU hardware.
+ *
+ *
+ */
+
+#include "scu_registers.h"
+#include "scic_sds_controller.h"
+
+/**
+ * scic_sds_controller_smu_register_read() -
+ *
+ * SMU_REGISTER_ACCESS_MACROS
+ */
+#define scic_sds_controller_smu_register_read(controller, reg) \
+ smu_register_read(\
+ (controller), \
+ (controller)->smu_registers->reg \
+ )
+
+#define scic_sds_controller_smu_register_write(controller, reg, value) \
+ smu_register_write(\
+ (controller), \
+ (controller)->smu_registers->reg, \
+ (value) \
+ )
+
+/**
+ * scu_afe_register_write() -
+ *
+ * AFE_REGISTER_ACCESS_MACROS
+ */
+#define scu_afe_register_write(controller, reg, value) \
+ scu_register_write(\
+ (controller), \
+ (controller)->scu_registers->afe.reg, \
+ (value) \
+ )
+
+#define scu_afe_txreg_write(controller, phy, reg, value) \
+ scu_register_write(\
+ (controller), \
+ (controller)->scu_registers->afe.scu_afe_xcvr[phy].reg,\
+ (value) \
+ )
+
+#define scu_afe_register_read(controller, reg) \
+ scu_register_read(\
+ (controller), \
+ (controller)->scu_registers->afe.reg \
+ )
+
+/**
+ * scu_controller_viit_register_write() -
+ *
+ * VIIT_REGISTER_ACCESS_MACROS
+ */
+#define scu_controller_viit_register_write(controller, index, reg, value) \
+ scu_register_write(\
+ (controller), \
+ (controller)->scu_registers->peg0.viit[index].reg, \
+ value \
+ )
+
+/*
+ * *****************************************************************************
+ * * SMU REGISTERS
+ * ***************************************************************************** */
+
+/**
+ * SMU_PCP_WRITE() -
+ *
+ * struct smu_registers
+ */
+#define SMU_PCP_WRITE(controller, value) \
+ scic_sds_controller_smu_register_write(\
+ controller, post_context_port, value \
+ )
+
+#define SMU_TCR_READ(controller, value) \
+ scic_sds_controller_smu_register_read(\
+ controller, task_context_range \
+ )
+
+#define SMU_TCR_WRITE(controller, value) \
+ scic_sds_controller_smu_register_write(\
+ controller, task_context_range, value \
+ )
+
+#define SMU_HTTBAR_WRITE(controller, address) \
+ { \
+ scic_sds_controller_smu_register_write(\
+ controller, \
+ host_task_table_lower, \
+ lower_32_bits(address) \
+ ); \
+ scic_sds_controller_smu_register_write(\
+ controller, \
+ host_task_table_upper, \
+ upper_32_bits(address) \
+ ); \
+ }
+
+#define SMU_CQBAR_WRITE(controller, address) \
+ { \
+ scic_sds_controller_smu_register_write(\
+ controller, \
+ completion_queue_lower, \
+ lower_32_bits(address) \
+ ); \
+ scic_sds_controller_smu_register_write(\
+ controller, \
+ completion_queue_upper, \
+ upper_32_bits(address) \
+ ); \
+ }
+
+#define SMU_CQGR_WRITE(controller, value) \
+ scic_sds_controller_smu_register_write(\
+ controller, completion_queue_get, value \
+ )
+
+#define SMU_CQGR_READ(controller, value) \
+ scic_sds_controller_smu_register_read(\
+ controller, completion_queue_get \
+ )
+
+#define SMU_CQPR_WRITE(controller, value) \
+ scic_sds_controller_smu_register_write(\
+ controller, completion_queue_put, value \
+ )
+
+#define SMU_RNCBAR_WRITE(controller, address) \
+ { \
+ scic_sds_controller_smu_register_write(\
+ controller, \
+ remote_node_context_lower, \
+ lower_32_bits(address) \
+ ); \
+ scic_sds_controller_smu_register_write(\
+ controller, \
+ remote_node_context_upper, \
+ upper_32_bits(address) \
+ ); \
+ }
+
+#define SMU_AMR_READ(controller) \
+ scic_sds_controller_smu_register_read(\
+ controller, address_modifier \
+ )
+
+#define SMU_IMR_READ(controller) \
+ scic_sds_controller_smu_register_read(\
+ controller, interrupt_mask \
+ )
+
+#define SMU_IMR_WRITE(controller, mask) \
+ scic_sds_controller_smu_register_write(\
+ controller, interrupt_mask, mask \
+ )
+
+#define SMU_ISR_READ(controller) \
+ scic_sds_controller_smu_register_read(\
+ controller, interrupt_status \
+ )
+
+#define SMU_ISR_WRITE(controller, status) \
+ scic_sds_controller_smu_register_write(\
+ controller, interrupt_status, status \
+ )
+
+#define SMU_ICC_READ(controller) \
+ scic_sds_controller_smu_register_read(\
+ controller, interrupt_coalesce_control \
+ )
+
+#define SMU_ICC_WRITE(controller, value) \
+ scic_sds_controller_smu_register_write(\
+ controller, interrupt_coalesce_control, value \
+ )
+
+#define SMU_CQC_WRITE(controller, value) \
+ scic_sds_controller_smu_register_write(\
+ controller, completion_queue_control, value \
+ )
+
+#define SMU_SMUSRCR_WRITE(controller, value) \
+ scic_sds_controller_smu_register_write(\
+ controller, soft_reset_control, value \
+ )
+
+#define SMU_TCA_WRITE(controller, index, value) \
+ scic_sds_controller_smu_register_write(\
+ controller, task_context_assignment[index], value \
+ )
+
+#define SMU_TCA_READ(controller, index) \
+ scic_sds_controller_smu_register_read(\
+ controller, task_context_assignment[index] \
+ )
+
+#define SMU_DCC_READ(controller) \
+ scic_sds_controller_smu_register_read(\
+ controller, device_context_capacity \
+ )
+
+#define SMU_DFC_READ(controller) \
+ scic_sds_controller_smu_register_read(\
+ controller, device_function_capacity \
+ )
+
+#define SMU_SMUCSR_READ(controller) \
+ scic_sds_controller_smu_register_read(\
+ controller, control_status \
+ )
+
+#define SMU_CQPR_READ(controller) \
+ scic_sds_controller_smu_register_read(\
+ controller, completion_queue_put \
+ )
+
+
+/**
+ * scic_sds_controller_scu_register_read() -
+ *
+ * SCU_REGISTER_ACCESS_MACROS
+ */
+#define scic_sds_controller_scu_register_read(controller, reg) \
+ scu_register_read(\
+ (controller), \
+ (controller)->scu_registers->reg \
+ )
+
+#define scic_sds_controller_scu_register_write(controller, reg, value) \
+ scu_register_write(\
+ (controller), \
+ (controller)->scu_registers->reg, \
+ (value) \
+ )
+
+
+/*
+ * ****************************************************************************
+ * * SCU SDMA REGISTERS
+ * **************************************************************************** */
+
+/**
+ * scu_sdma_register_read() -
+ *
+ * SCU_SDMA_REGISTER_ACCESS_MACROS
+ */
+#define scu_sdma_register_read(controller, reg) \
+ scu_register_read(\
+ (controller), \
+ (controller)->scu_registers->sdma.reg \
+ )
+
+#define scu_sdma_register_write(controller, reg, value) \
+ scu_register_write(\
+ (controller), \
+ (controller)->scu_registers->sdma.reg, \
+ (value) \
+ )
+
+/**
+ * SCU_PUFATHAR_WRITE() -
+ *
+ * struct scu_sdma_registers
+ */
+#define SCU_PUFATHAR_WRITE(controller, address) \
+ { \
+ scu_sdma_register_write(\
+ controller, \
+ uf_address_table_lower, \
+ lower_32_bits(address) \
+ ); \
+ scu_sdma_register_write(\
+ controller, \
+ uf_address_table_upper, \
+ upper_32_bits(address) \
+ ); \
+ }
+
+#define SCU_UFHBAR_WRITE(controller, address) \
+ { \
+ scu_sdma_register_write(\
+ controller, \
+ uf_header_base_address_lower, \
+ lower_32_bits(address) \
+ ); \
+ scu_sdma_register_write(\
+ controller, \
+ uf_header_base_address_upper, \
+ upper_32_bits(address) \
+ ); \
+ }
+
+#define SCU_UFQC_READ(controller) \
+ scu_sdma_register_read(\
+ controller, \
+ unsolicited_frame_queue_control \
+ )
+
+#define SCU_UFQC_WRITE(controller, value) \
+ scu_sdma_register_write(\
+ controller, \
+ unsolicited_frame_queue_control, \
+ value \
+ )
+
+#define SCU_UFQPP_READ(controller) \
+ scu_sdma_register_read(\
+ controller, \
+ unsolicited_frame_put_pointer \
+ )
+
+#define SCU_UFQPP_WRITE(controller, value) \
+ scu_sdma_register_write(\
+ controller, \
+ unsolicited_frame_put_pointer, \
+ value \
+ )
+
+#define SCU_UFQGP_WRITE(controller, value) \
+ scu_sdma_register_write(\
+ controller, \
+ unsolicited_frame_get_pointer, \
+ value \
+ )
+
+#define SCU_PDMACR_READ(controller) \
+ scu_sdma_register_read(\
+ controller, \
+ pdma_configuration \
+ )
+
+#define SCU_PDMACR_WRITE(controller, value) \
+ scu_sdma_register_write(\
+ controller, \
+ pdma_configuration, \
+ value \
+ )
+
+#define SCU_CDMACR_READ(controller) \
+ scu_sdma_register_read(\
+ controller, \
+ cdma_configuration \
+ )
+
+#define SCU_CDMACR_WRITE(controller, value) \
+ scu_sdma_register_write(\
+ controller, \
+ cdma_configuration, \
+ value \
+ )
+
+/*
+ * *****************************************************************************
+ * * SCU Port Task Scheduler Group Registers
+ * ***************************************************************************** */
+
+/**
+ * scu_ptsg_register_read() -
+ *
+ * SCU_PTSG_REGISTER_ACCESS_MACROS
+ */
+#define scu_ptsg_register_read(controller, reg) \
+ scu_register_read(\
+ (controller), \
+ (controller)->scu_registers->peg0.ptsg.reg \
+ )
+
+#define scu_ptsg_register_write(controller, reg, value) \
+ scu_register_write(\
+ (controller), \
+ (controller)->scu_registers->peg0.ptsg.reg, \
+ (value) \
+ )
+
+/**
+ * SCU_PTSGCR_READ() -
+ *
+ * SCU_PTSG_REGISTERS
+ */
+#define SCU_PTSGCR_READ(controller) \
+ scu_ptsg_register_read(\
+ (controller), \
+ control \
+ )
+
+#define SCU_PTSGCR_WRITE(controller, value) \
+ scu_ptsg_register_write(\
+ (controller), \
+ control, \
+ value \
+ )
+
+#define SCU_PTSGRTC_READ(controller) \
+ scu_ptsg_register_read(\
+ contoller, \
+ real_time_clock \
+ )
+
+#endif /* _SCIC_SDS_CONTROLLER_REGISTERS_H_ */
diff --git a/drivers/scsi/isci/core/scic_sds_pci.h b/drivers/scsi/isci/core/scic_sds_pci.h
new file mode 100644
index 000000000000..21326777acc6
--- /dev/null
+++ b/drivers/scsi/isci/core/scic_sds_pci.h
@@ -0,0 +1,95 @@
+/*
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Intel Corporation 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
+ * OWNER 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.
+ */
+
+#ifndef _SCIC_SDS_PCI_H_
+#define _SCIC_SDS_PCI_H_
+
+/**
+ * This file contains the prototypes/macros utilized in writing out PCI data
+ * for the SCI core.
+ *
+ *
+ */
+
+#include <asm/io.h>
+#include "sci_types.h"
+
+struct scic_sds_controller;
+
+void scic_sds_pci_bar_initialization(struct scic_sds_controller *scic);
+
+/* for debug we separate scu and smu accesses and require a controller */
+static inline u32 scic_sds_pci_read_smu_dword(struct scic_sds_controller *scic, void __iomem *addr)
+{
+ return readl(addr);
+}
+
+static inline void scic_sds_pci_write_smu_dword(struct scic_sds_controller *scic, void __iomem *addr, u32 value)
+{
+ writel(value, addr);
+}
+
+static inline u32 scic_sds_pci_read_scu_dword(struct scic_sds_controller *scic, void __iomem *addr)
+{
+ return readl(addr);
+}
+
+static inline void scic_sds_pci_write_scu_dword(struct scic_sds_controller *scic, void __iomem *addr, u32 value)
+{
+ writel(value, addr);
+}
+
+
+#endif /* _SCIC_SDS_PCI_H_ */
diff --git a/drivers/scsi/isci/core/scic_sds_phy.c b/drivers/scsi/isci/core/scic_sds_phy.c
new file mode 100644
index 000000000000..7d012b571b5b
--- /dev/null
+++ b/drivers/scsi/isci/core/scic_sds_phy.c
@@ -0,0 +1,2807 @@
+/*
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Intel Corporation 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
+ * OWNER 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.
+ */
+
+#include "intel_ata.h"
+#include "intel_sata.h"
+#include "sci_base_state.h"
+#include "sci_base_state_machine.h"
+#include "scic_phy.h"
+#include "scic_sds_controller.h"
+#include "scic_sds_phy.h"
+#include "scic_sds_phy_registers.h"
+#include "scic_sds_port.h"
+#include "scic_user_callback.h"
+#include "sci_environment.h"
+#include "sci_util.h"
+#include "scu_event_codes.h"
+
+#define SCIC_SDS_PHY_MIN_TIMER_COUNT (SCI_MAX_PHYS)
+#define SCIC_SDS_PHY_MAX_TIMER_COUNT (SCI_MAX_PHYS)
+
+/* Maximum arbitration wait time in micro-seconds */
+#define SCIC_SDS_PHY_MAX_ARBITRATION_WAIT_TIME (700)
+
+/*
+ * *****************************************************************************
+ * * SCIC SDS PHY Internal Methods
+ * ***************************************************************************** */
+
+/**
+ * This method will initialize the phy link layer registers
+ * @this_phy:
+ * @link_layer_registers:
+ *
+ * enum sci_status
+ */
+static enum sci_status scic_sds_phy_link_layer_initialization(
+ struct scic_sds_phy *this_phy,
+ struct scu_link_layer_registers *link_layer_registers)
+{
+ u32 phy_configuration;
+ struct sas_capabilities phy_capabilities;
+ u32 parity_check = 0;
+ u32 parity_count = 0;
+ u32 link_layer_control;
+
+ this_phy->link_layer_registers = link_layer_registers;
+
+ /* Set our IDENTIFY frame data */
+ #define SCI_END_DEVICE 0x01
+
+ SCU_SAS_TIID_WRITE(
+ this_phy,
+ (SCU_SAS_TIID_GEN_BIT(SMP_INITIATOR)
+ | SCU_SAS_TIID_GEN_BIT(SSP_INITIATOR)
+ | SCU_SAS_TIID_GEN_BIT(STP_INITIATOR)
+ | SCU_SAS_TIID_GEN_BIT(DA_SATA_HOST)
+ | SCU_SAS_TIID_GEN_VAL(DEVICE_TYPE, SCI_END_DEVICE))
+ );
+
+ /* Write the device SAS Address */
+ SCU_SAS_TIDNH_WRITE(this_phy, 0xFEDCBA98);
+ SCU_SAS_TIDNL_WRITE(this_phy, this_phy->phy_index);
+
+ /* Write the source SAS Address */
+ SCU_SAS_TISSAH_WRITE(
+ this_phy,
+ this_phy->owning_port->owning_controller->oem_parameters.sds1.phys[
+ this_phy->phy_index].sas_address.high
+ );
+ SCU_SAS_TISSAL_WRITE(
+ this_phy,
+ this_phy->owning_port->owning_controller->oem_parameters.sds1.phys[
+ this_phy->phy_index].sas_address.low
+ );
+
+ /* Clear and Set the PHY Identifier */
+ SCU_SAS_TIPID_WRITE(this_phy, 0x00000000);
+ SCU_SAS_TIPID_WRITE(this_phy, SCU_SAS_TIPID_GEN_VALUE(ID, this_phy->phy_index));
+
+ /* Change the initial state of the phy configuration register */
+ phy_configuration = SCU_SAS_PCFG_READ(this_phy);
+
+ /* Hold OOB state machine in reset */
+ phy_configuration |= SCU_SAS_PCFG_GEN_BIT(OOB_RESET);
+ SCU_SAS_PCFG_WRITE(this_phy, phy_configuration);
+
+ /* Configure the SNW capabilities */
+ phy_capabilities.u.all = 0;
+ phy_capabilities.u.bits.start = 1;
+ phy_capabilities.u.bits.gen3_without_ssc_supported = 1;
+ phy_capabilities.u.bits.gen2_without_ssc_supported = 1;
+ phy_capabilities.u.bits.gen1_without_ssc_supported = 1;
+ if (this_phy->owning_port->owning_controller->oem_parameters.sds1.
+ controller.do_enable_ssc == true) {
+ phy_capabilities.u.bits.gen3_with_ssc_supported = 1;
+ phy_capabilities.u.bits.gen2_with_ssc_supported = 1;
+ phy_capabilities.u.bits.gen1_with_ssc_supported = 1;
+ }
+
+ /*
+ * The SAS specification indicates that the phy_capabilities that
+ * are transmitted shall have an even parity. Calculate the parity. */
+ parity_check = phy_capabilities.u.all;
+ while (parity_check != 0) {
+ if (parity_check & 0x1)
+ parity_count++;
+ parity_check >>= 1;
+ }
+
+ /*
+ * If parity indicates there are an odd number of bits set, then
+ * set the parity bit to 1 in the phy capabilities. */
+ if ((parity_count % 2) != 0)
+ phy_capabilities.u.bits.parity = 1;
+
+ SCU_SAS_PHYCAP_WRITE(this_phy, phy_capabilities.u.all);
+
+ /* Set the enable spinup period but disable the ability to send notify enable spinup */
+ SCU_SAS_ENSPINUP_WRITE(this_phy, SCU_ENSPINUP_GEN_VAL(COUNT, 0x33));
+
+#if defined(CONFIG_PBG_HBA_A0) || defined(CONFIG_PBG_HBA_A2) || defined(CONFIG_PBG_HBA_BETA)
+ /* / @todo Provide a way to write this register correctly */
+ scu_link_layer_register_write(this_phy, afe_lookup_table_control, 0x02108421);
+#else
+ /* / @todo Provide a way to write this register correctly */
+ scu_link_layer_register_write(this_phy, afe_lookup_table_control, 0x0e739ce7);
+#endif
+
+ link_layer_control = SCU_SAS_LLCTL_GEN_VAL(
+ NO_OUTBOUND_TASK_TIMEOUT,
+ (u8)this_phy->owning_port->owning_controller->
+ user_parameters.sds1.no_outbound_task_timeout
+ );
+
+/* #define COMPILED_MAX_LINK_RATE SCU_SAS_LINK_LAYER_CONTROL_MAX_LINK_RATE_GEN1 */
+/* #define COMPILED_MAX_LINK_RATE SCU_SAS_LINK_LAYER_CONTROL_MAX_LINK_RATE_GEN2 */
+#define COMPILED_MAX_LINK_RATE SCU_SAS_LINK_LAYER_CONTROL_MAX_LINK_RATE_GEN3
+
+ if (this_phy->owning_port->owning_controller->user_parameters.sds1.
+ phys[this_phy->phy_index].max_speed_generation == SCIC_SDS_PARM_GEN3_SPEED) {
+ link_layer_control |= SCU_SAS_LLCTL_GEN_VAL(
+ MAX_LINK_RATE, COMPILED_MAX_LINK_RATE
+ );
+ } else if (this_phy->owning_port->owning_controller->user_parameters.sds1.
+ phys[this_phy->phy_index].max_speed_generation == SCIC_SDS_PARM_GEN2_SPEED) {
+ link_layer_control |= SCU_SAS_LLCTL_GEN_VAL(
+ MAX_LINK_RATE,
+ min(
+ SCU_SAS_LINK_LAYER_CONTROL_MAX_LINK_RATE_GEN2,
+ COMPILED_MAX_LINK_RATE)
+ );
+ } else {
+ link_layer_control |= SCU_SAS_LLCTL_GEN_VAL(
+ MAX_LINK_RATE,
+ min(
+ SCU_SAS_LINK_LAYER_CONTROL_MAX_LINK_RATE_GEN1,
+ COMPILED_MAX_LINK_RATE)
+ );
+ }
+
+ scu_link_layer_register_write(
+ this_phy, link_layer_control, link_layer_control
+ );
+
+ /*
+ * Program the max ARB time for the PHY to 700us so we inter-operate with
+ * the PMC expander which shuts down PHYs if the expander PHY generates too
+ * many breaks. This time value will guarantee that the initiator PHY will
+ * generate the break. */
+#if defined(CONFIG_PBG_HBA_A0) || defined(CONFIG_PBG_HBA_A2)
+ scu_link_layer_register_write(
+ this_phy,
+ maximum_arbitration_wait_timer_timeout,
+ SCIC_SDS_PHY_MAX_ARBITRATION_WAIT_TIME
+ );
+#endif /* defined(CONFIG_PBG_HBA_A0) || defined(CONFIG_PBG_HBA_A2) */
+
+ /*
+ * Set the link layer hang detection to 500ms (0x1F4) from its default
+ * value of 128ms. Max value is 511 ms. */
+ scu_link_layer_register_write(
+ this_phy, link_layer_hang_detection_timeout, 0x1F4
+ );
+
+ /* We can exit the initial state to the stopped state */
+ sci_base_state_machine_change_state(
+ scic_sds_phy_get_base_state_machine(this_phy),
+ SCI_BASE_PHY_STATE_STOPPED
+ );
+
+ return SCI_SUCCESS;
+}
+
+/**
+ * This function will handle the sata SIGNATURE FIS timeout condition. It will
+ * restart the starting substate machine since we dont know what has actually
+ * happening.
+ */
+static void scic_sds_phy_sata_timeout(void *phy)
+{
+ struct scic_sds_phy *sci_phy = phy;
+
+ dev_dbg(sciphy_to_dev(sci_phy),
+ "%s: SCIC SDS Phy 0x%p did not receive signature fis before "
+ "timeout.\n",
+ __func__,
+ sci_phy);
+
+ sci_base_state_machine_stop(
+ scic_sds_phy_get_starting_substate_machine(sci_phy));
+
+ sci_base_state_machine_change_state(
+ scic_sds_phy_get_base_state_machine(sci_phy),
+ SCI_BASE_PHY_STATE_STARTING
+ );
+}
+
+/*
+ * *****************************************************************************
+ * * SCIC SDS PHY External Methods
+ * ***************************************************************************** */
+
+/**
+ * This method returns the object size for a phy object.
+ *
+ * u32
+ */
+
+/**
+ * This method returns the minimum number of timers required for a phy object.
+ *
+ * u32
+ */
+
+/**
+ * This method returns the maximum number of timers required for a phy object.
+ *
+ * u32
+ */
+
+#ifdef SCIC_DEBUG_ENABLED
+/**
+ * scic_sds_phy_observe_state_change() -
+ * @our_observer:
+ *
+ * Debug code to record the state transitions in the phy
+ */
+void scic_sds_phy_observe_state_change(
+ struct sci_base_observer *our_observer,
+ struct sci_base_subject *the_subject)
+{
+ struct scic_sds_phy *this_phy;
+ struct sci_base_state_machine *the_state_machine;
+
+ u8 transition_requestor;
+ u32 base_state_id;
+ u32 starting_substate_id;
+
+ the_state_machine = (struct sci_base_state_machine *)the_subject;
+ this_phy = (struct scic_sds_phy *)the_state_machine->state_machine_owner;
+
+ if (the_state_machine == &this_phy->parent.state_machine) {
+ transition_requestor = 0x01;
+ } else if (the_state_machine == &this_phy->starting_substate_machine) {
+ transition_requestor = 0x02;
+ } else {
+ transition_requestor = 0xFF;
+ }
+
+ base_state_id =
+ sci_base_state_machine_get_state(&this_phy->parent.state_machine);
+ starting_substate_id =
+ sci_base_state_machine_get_state(&this_phy->starting_substate_machine);
+
+ this_phy->state_record.state_transition_table[
+ this_phy->state_record.index++] = ((transition_requestor << 24)
+ | ((u8)base_state_id << 8)
+ | ((u8)starting_substate_id));
+
+ this_phy->state_record.index =
+ this_phy->state_record.index & (MAX_STATE_TRANSITION_RECORD - 1);
+
+}
+#endif /* SCIC_DEBUG_ENABLED */
+
+#ifdef SCIC_DEBUG_ENABLED
+/**
+ * scic_sds_phy_initialize_state_recording() -
+ *
+ * This method initializes the state record debug information for the phy
+ * object. The state machines for the phy object must be constructed before
+ * this function is called.
+ */
+void scic_sds_phy_initialize_state_recording(
+ struct scic_sds_phy *this_phy)
+{
+ this_phy->state_record.index = 0;
+
+ sci_base_observer_initialize(
+ &this_phy->state_record.base_state_observer,
+ scic_sds_phy_observe_state_change,
+ &this_phy->parent.state_machine.parent
+ );
+
+ sci_base_observer_initialize(
+ &this_phy->state_record.starting_state_observer,
+ scic_sds_phy_observe_state_change,
+ &this_phy->starting_substate_machine.parent
+ );
+}
+#endif /* SCIC_DEBUG_ENABLED */
+
+/**
+ * This method will construct the struct scic_sds_phy object
+ * @this_phy:
+ * @owning_port:
+ * @phy_index:
+ *
+ */
+void scic_sds_phy_construct(
+ struct scic_sds_phy *this_phy,
+ struct scic_sds_port *owning_port,
+ u8 phy_index)
+{
+ /*
+ * Call the base constructor first
+ */
+ sci_base_phy_construct(
+ &this_phy->parent,
+ scic_sds_phy_state_table
+ );
+
+ /* Copy the rest of the input data to our locals */
+ this_phy->owning_port = owning_port;
+ this_phy->phy_index = phy_index;
+ this_phy->bcn_received_while_port_unassigned = false;
+ this_phy->protocol = SCIC_SDS_PHY_PROTOCOL_UNKNOWN;
+ this_phy->link_layer_registers = NULL;
+ this_phy->max_negotiated_speed = SCI_SAS_NO_LINK_RATE;
+
+ /* Clear out the identification buffer data */
+ memset(&this_phy->phy_type, 0, sizeof(this_phy->phy_type));
+
+ /* Initialize the the substate machines */
+ sci_base_state_machine_construct(
+ &this_phy->starting_substate_machine,
+ &this_phy->parent.parent,
+ scic_sds_phy_starting_substates,
+ SCIC_SDS_PHY_STARTING_SUBSTATE_INITIAL
+ );
+
+ #ifdef SCIC_DEBUG_ENABLED
+ scic_sds_phy_initialize_state_recording(this_phy);
+ #endif /* SCIC_DEBUG_ENABLED */
+}
+
+/**
+ * This method returns the port currently containing this phy. If the phy is
+ * currently contained by the dummy port, then the phy is considered to not
+ * be part of a port.
+ * @this_phy: This parameter specifies the phy for which to retrieve the
+ * containing port.
+ *
+ * This method returns a handle to a port that contains the supplied phy.
+ * SCI_INVALID_HANDLE This value is returned if the phy is not part of a real
+ * port (i.e. it's contained in the dummy port). !SCI_INVALID_HANDLE All other
+ * values indicate a handle/pointer to the port containing the phy.
+ */
+struct scic_sds_port *scic_sds_phy_get_port(
+ struct scic_sds_phy *this_phy)
+{
+ if (scic_sds_port_get_index(this_phy->owning_port) == SCIC_SDS_DUMMY_PORT)
+ return SCI_INVALID_HANDLE;
+
+ return this_phy->owning_port;
+}
+
+/**
+ * This method will assign a port to the phy object.
+ * @out]: this_phy This parameter specifies the phy for which to assign a port
+ * object.
+ *
+ *
+ */
+void scic_sds_phy_set_port(
+ struct scic_sds_phy *this_phy,
+ struct scic_sds_port *the_port)
+{
+ this_phy->owning_port = the_port;
+
+ if (this_phy->bcn_received_while_port_unassigned) {
+ this_phy->bcn_received_while_port_unassigned = false;
+ scic_sds_port_broadcast_change_received(this_phy->owning_port, this_phy);
+ }
+}
+
+/**
+ * This method will initialize the constructed phy
+ * @sci_phy:
+ * @link_layer_registers:
+ *
+ * enum sci_status
+ */
+enum sci_status scic_sds_phy_initialize(
+ struct scic_sds_phy *sci_phy,
+ struct scu_link_layer_registers *link_layer_registers)
+{
+ /* Create the SIGNATURE FIS Timeout timer for this phy */
+ sci_phy->sata_timeout_timer = scic_cb_timer_create(
+ scic_sds_phy_get_controller(sci_phy),
+ scic_sds_phy_sata_timeout,
+ sci_phy
+ );
+
+ /* Perofrm the initialization of the PE hardware */
+ scic_sds_phy_link_layer_initialization(sci_phy, link_layer_registers);
+
+ /*
+ * There is nothing that needs to be done in this state just
+ * transition to the stopped state. */
+ sci_base_state_machine_change_state(
+ scic_sds_phy_get_base_state_machine(sci_phy),
+ SCI_BASE_PHY_STATE_STOPPED
+ );
+
+ return SCI_SUCCESS;
+}
+
+
+/**
+ *
+ * @this_phy: The phy object to be suspended.
+ *
+ * This function will perform the register reads/writes to suspend the SCU
+ * hardware protocol engine. none
+ */
+void scic_sds_phy_suspend(
+ struct scic_sds_phy *this_phy)
+{
+ u32 scu_sas_pcfg_value;
+
+ scu_sas_pcfg_value = SCU_SAS_PCFG_READ(this_phy);
+
+ scu_sas_pcfg_value |= SCU_SAS_PCFG_GEN_BIT(SUSPEND_PROTOCOL_ENGINE);
+
+ SCU_SAS_PCFG_WRITE(this_phy, scu_sas_pcfg_value);
+}
+
+/**
+ *
+ * @this_phy: The phy object to resume.
+ *
+ * This function will perform the register reads/writes required to resume the
+ * SCU hardware protocol engine. none
+ */
+void scic_sds_phy_resume(
+ struct scic_sds_phy *this_phy)
+{
+ u32 scu_sas_pcfg_value;
+
+ scu_sas_pcfg_value = SCU_SAS_PCFG_READ(this_phy);
+
+ scu_sas_pcfg_value &= ~SCU_SAS_PCFG_GEN_BIT(SUSPEND_PROTOCOL_ENGINE);
+
+ SCU_SAS_PCFG_WRITE(this_phy, scu_sas_pcfg_value);
+}
+
+/**
+ * This method returns the local sas address assigned to this phy.
+ * @this_phy: This parameter specifies the phy for which to retrieve the local
+ * SAS address.
+ * @sas_address: This parameter specifies the location into which to copy the
+ * local SAS address.
+ *
+ */
+void scic_sds_phy_get_sas_address(
+ struct scic_sds_phy *this_phy,
+ struct sci_sas_address *sas_address)
+{
+ sas_address->high = SCU_SAS_TISSAH_READ(this_phy);
+ sas_address->low = SCU_SAS_TISSAL_READ(this_phy);
+}
+
+/**
+ * This method returns the remote end-point (i.e. attached) sas address
+ * assigned to this phy.
+ * @this_phy: This parameter specifies the phy for which to retrieve the remote
+ * end-point SAS address.
+ * @sas_address: This parameter specifies the location into which to copy the
+ * remote end-point SAS address.
+ *
+ */
+void scic_sds_phy_get_attached_sas_address(
+ struct scic_sds_phy *this_phy,
+ struct sci_sas_address *sas_address)
+{
+ sas_address->high
+ = this_phy->phy_type.sas.identify_address_frame_buffer.sas_address.high;
+ sas_address->low
+ = this_phy->phy_type.sas.identify_address_frame_buffer.sas_address.low;
+}
+
+/**
+ * This method returns the supported protocols assigned to this phy
+ * @this_phy:
+ *
+ *
+ */
+void scic_sds_phy_get_protocols(
+ struct scic_sds_phy *this_phy,
+ struct sci_sas_identify_address_frame_protocols *protocols)
+{
+ protocols->u.all = (u16)(SCU_SAS_TIID_READ(this_phy) & 0x0000FFFF);
+}
+
+/**
+ *
+ * @this_phy: The parameter is the phy object for which the attached phy
+ * protcols are to be returned.
+ *
+ * This method returns the supported protocols for the attached phy. If this
+ * is a SAS phy the protocols are returned from the identify address frame. If
+ * this is a SATA phy then protocols are made up and the target phy is an STP
+ * target phy. The caller will get the entire set of bits for the protocol
+ * value.
+ */
+void scic_sds_phy_get_attached_phy_protocols(
+ struct scic_sds_phy *this_phy,
+ struct sci_sas_identify_address_frame_protocols *protocols)
+{
+ protocols->u.all = 0;
+
+ if (this_phy->protocol == SCIC_SDS_PHY_PROTOCOL_SAS) {
+ protocols->u.all =
+ this_phy->phy_type.sas.identify_address_frame_buffer.protocols.u.all;
+ } else if (this_phy->protocol == SCIC_SDS_PHY_PROTOCOL_SATA) {
+ protocols->u.bits.stp_target = 1;
+ }
+}
+
+/*
+ * *****************************************************************************
+ * * SCIC SDS PHY Handler Redirects
+ * ***************************************************************************** */
+
+/**
+ * This method will attempt to start the phy object. This request is only valid
+ * when the phy is in the stopped state
+ * @this_phy:
+ *
+ * enum sci_status
+ */
+enum sci_status scic_sds_phy_start(
+ struct scic_sds_phy *this_phy)
+{
+ return this_phy->state_handlers->parent.start_handler(&this_phy->parent);
+}
+
+/**
+ * This method will attempt to stop the phy object.
+ * @this_phy:
+ *
+ * enum sci_status SCI_SUCCESS if the phy is going to stop SCI_INVALID_STATE if the
+ * phy is not in a valid state to stop
+ */
+enum sci_status scic_sds_phy_stop(
+ struct scic_sds_phy *this_phy)
+{
+ return this_phy->state_handlers->parent.stop_handler(&this_phy->parent);
+}
+
+/**
+ * This method will attempt to reset the phy. This request is only valid when
+ * the phy is in an ready state
+ * @this_phy:
+ *
+ * enum sci_status
+ */
+enum sci_status scic_sds_phy_reset(
+ struct scic_sds_phy *this_phy)
+{
+ return this_phy->state_handlers->parent.reset_handler(
+ &this_phy->parent
+ );
+}
+
+/**
+ * This method will process the event code received.
+ * @this_phy:
+ * @event_code:
+ *
+ * enum sci_status
+ */
+enum sci_status scic_sds_phy_event_handler(
+ struct scic_sds_phy *this_phy,
+ u32 event_code)
+{
+ return this_phy->state_handlers->event_handler(this_phy, event_code);
+}
+
+/**
+ * This method will process the frame index received.
+ * @this_phy:
+ * @frame_index:
+ *
+ * enum sci_status
+ */
+enum sci_status scic_sds_phy_frame_handler(
+ struct scic_sds_phy *this_phy,
+ u32 frame_index)
+{
+ return this_phy->state_handlers->frame_handler(this_phy, frame_index);
+}
+
+/**
+ * This method will give the phy permission to consume power
+ * @this_phy:
+ *
+ * enum sci_status
+ */
+enum sci_status scic_sds_phy_consume_power_handler(
+ struct scic_sds_phy *this_phy)
+{
+ return this_phy->state_handlers->consume_power_handler(this_phy);
+}
+
+/*
+ * *****************************************************************************
+ * * SCIC PHY Public Methods
+ * ***************************************************************************** */
+
+
+enum sci_status scic_sas_phy_get_properties(
+ struct scic_sds_phy *sci_phy,
+ struct scic_sas_phy_properties *properties)
+{
+ if (sci_phy->protocol == SCIC_SDS_PHY_PROTOCOL_SAS) {
+ memcpy(
+ &properties->received_iaf,
+ &sci_phy->phy_type.sas.identify_address_frame_buffer,
+ sizeof(struct sci_sas_identify_address_frame)
+ );
+
+ properties->received_capabilities.u.all
+ = SCU_SAS_RECPHYCAP_READ(sci_phy);
+
+ return SCI_SUCCESS;
+ }
+
+ return SCI_FAILURE;
+}
+
+
+enum sci_status scic_sata_phy_get_properties(
+ struct scic_sds_phy *sci_phy,
+ struct scic_sata_phy_properties *properties)
+{
+ if (sci_phy->protocol == SCIC_SDS_PHY_PROTOCOL_SATA) {
+ memcpy(
+ &properties->signature_fis,
+ &sci_phy->phy_type.sata.signature_fis_buffer,
+ sizeof(struct sata_fis_reg_d2h)
+ );
+
+ /* / @todo add support for port selectors. */
+ properties->is_port_selector_present = false;
+
+ return SCI_SUCCESS;
+ }
+
+ return SCI_FAILURE;
+}
+
+/*
+ * *****************************************************************************
+ * * SCIC SDS PHY HELPER FUNCTIONS
+ * ***************************************************************************** */
+
+
+/**
+ *
+ * @this_phy: The phy object that received SAS PHY DETECTED.
+ *
+ * This method continues the link training for the phy as if it were a SAS PHY
+ * instead of a SATA PHY. This is done because the completion queue had a SAS
+ * PHY DETECTED event when the state machine was expecting a SATA PHY event.
+ * none
+ */
+static void scic_sds_phy_start_sas_link_training(
+ struct scic_sds_phy *this_phy)
+{
+ u32 phy_control;
+
+ phy_control = SCU_SAS_PCFG_READ(this_phy);
+ phy_control |= SCU_SAS_PCFG_GEN_BIT(SATA_SPINUP_HOLD);
+ SCU_SAS_PCFG_WRITE(this_phy, phy_control);
+
+ sci_base_state_machine_change_state(
+ &this_phy->starting_substate_machine,
+ SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_SAS_SPEED_EN
+ );
+
+ this_phy->protocol = SCIC_SDS_PHY_PROTOCOL_SAS;
+}
+
+/**
+ *
+ * @this_phy: The phy object that received a SATA SPINUP HOLD event
+ *
+ * This method continues the link training for the phy as if it were a SATA PHY
+ * instead of a SAS PHY. This is done because the completion queue had a SATA
+ * SPINUP HOLD event when the state machine was expecting a SAS PHY event. none
+ */
+static void scic_sds_phy_start_sata_link_training(
+ struct scic_sds_phy *this_phy)
+{
+ sci_base_state_machine_change_state(
+ &this_phy->starting_substate_machine,
+ SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_SATA_POWER
+ );
+
+ this_phy->protocol = SCIC_SDS_PHY_PROTOCOL_SATA;
+}
+
+/**
+ * This method performs processing common to all protocols upon completion of
+ * link training.
+ * @this_phy: This parameter specifies the phy object for which link training
+ * has completed.
+ * @max_link_rate: This parameter specifies the maximum link rate to be
+ * associated with this phy.
+ * @next_state: This parameter specifies the next state for the phy's starting
+ * sub-state machine.
+ *
+ */
+static void scic_sds_phy_complete_link_training(
+ struct scic_sds_phy *this_phy,
+ enum sci_sas_link_rate max_link_rate,
+ u32 next_state)
+{
+ this_phy->max_negotiated_speed = max_link_rate;
+
+ sci_base_state_machine_change_state(
+ scic_sds_phy_get_starting_substate_machine(this_phy), next_state
+ );
+}
+
+/**
+ *
+ * @this_phy: The struct scic_sds_phy object to restart.
+ *
+ * This method restarts the struct scic_sds_phy objects base state machine in the
+ * starting state from any starting substate. none
+ */
+static void scic_sds_phy_restart_starting_state(
+ struct scic_sds_phy *this_phy)
+{
+ /* Stop the current substate machine */
+ sci_base_state_machine_stop(
+ scic_sds_phy_get_starting_substate_machine(this_phy)
+ );
+
+ /* Re-enter the base state machine starting state */
+ sci_base_state_machine_change_state(
+ scic_sds_phy_get_base_state_machine(this_phy),
+ SCI_BASE_PHY_STATE_STARTING
+ );
+}
+
+/*
+ * *****************************************************************************
+ * * SCIC SDS PHY EVENT_HANDLERS
+ * ***************************************************************************** */
+
+/**
+ *
+ * @phy: This struct scic_sds_phy object which has received an event.
+ * @event_code: This is the event code which the phy object is to decode.
+ *
+ * This method is called when an event notification is received for the phy
+ * object when in the state SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_SPEED_EN. -
+ * decode the event - sas phy detected causes a state transition to the wait
+ * for speed event notification. - any other events log a warning message and
+ * set a failure status enum sci_status SCI_SUCCESS on any valid event notification
+ * SCI_FAILURE on any unexpected event notifation
+ */
+static enum sci_status scic_sds_phy_starting_substate_await_ossp_event_handler(
+ struct scic_sds_phy *this_phy,
+ u32 event_code)
+{
+ u32 result = SCI_SUCCESS;
+
+ switch (scu_get_event_code(event_code)) {
+ case SCU_EVENT_SAS_PHY_DETECTED:
+ scic_sds_phy_start_sas_link_training(this_phy);
+ this_phy->is_in_link_training = true;
+ break;
+
+ case SCU_EVENT_SATA_SPINUP_HOLD:
+ scic_sds_phy_start_sata_link_training(this_phy);
+ this_phy->is_in_link_training = true;
+ break;
+
+ default:
+ dev_warn(sciphy_to_dev(this_phy),
+ "%s: PHY starting substate machine received "
+ "unexpected event_code %x\n",
+ __func__,
+ event_code);
+
+ result = SCI_FAILURE;
+ break;
+ }
+
+ return result;
+}
+
+/**
+ *
+ * @phy: This struct scic_sds_phy object which has received an event.
+ * @event_code: This is the event code which the phy object is to decode.
+ *
+ * This method is called when an event notification is received for the phy
+ * object when in the state SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_SPEED_EN. -
+ * decode the event - sas phy detected returns us back to this state. - speed
+ * event detected causes a state transition to the wait for iaf. - identify
+ * timeout is an un-expected event and the state machine is restarted. - link
+ * failure events restart the starting state machine - any other events log a
+ * warning message and set a failure status enum sci_status SCI_SUCCESS on any valid
+ * event notification SCI_FAILURE on any unexpected event notifation
+ */
+static enum sci_status scic_sds_phy_starting_substate_await_sas_phy_speed_event_handler(
+ struct scic_sds_phy *this_phy,
+ u32 event_code)
+{
+ u32 result = SCI_SUCCESS;
+
+ switch (scu_get_event_code(event_code)) {
+ case SCU_EVENT_SAS_PHY_DETECTED:
+ /*
+ * Why is this being reported again by the controller?
+ * We would re-enter this state so just stay here */
+ break;
+
+ case SCU_EVENT_SAS_15:
+ case SCU_EVENT_SAS_15_SSC:
+ scic_sds_phy_complete_link_training(
+ this_phy, SCI_SAS_150_GB, SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_IAF_UF
+ );
+ break;
+
+ case SCU_EVENT_SAS_30:
+ case SCU_EVENT_SAS_30_SSC:
+ scic_sds_phy_complete_link_training(
+ this_phy, SCI_SAS_300_GB, SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_IAF_UF
+ );
+ break;
+
+ case SCU_EVENT_SAS_60:
+ case SCU_EVENT_SAS_60_SSC:
+ scic_sds_phy_complete_link_training(
+ this_phy, SCI_SAS_600_GB, SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_IAF_UF
+ );
+ break;
+
+ case SCU_EVENT_SATA_SPINUP_HOLD:
+ /*
+ * We were doing SAS PHY link training and received a SATA PHY event
+ * continue OOB/SN as if this were a SATA PHY */
+ scic_sds_phy_start_sata_link_training(this_phy);
+ break;
+
+ case SCU_EVENT_LINK_FAILURE:
+ /* Link failure change state back to the starting state */
+ scic_sds_phy_restart_starting_state(this_phy);
+ break;
+
+ default:
+ dev_warn(sciphy_to_dev(this_phy),
+ "%s: PHY starting substate machine received "
+ "unexpected event_code %x\n",
+ __func__,
+ event_code);
+
+ result = SCI_FAILURE;
+ break;
+ }
+
+ return result;
+}
+
+/**
+ *
+ * @phy: This struct scic_sds_phy object which has received an event.
+ * @event_code: This is the event code which the phy object is to decode.
+ *
+ * This method is called when an event notification is received for the phy
+ * object when in the state SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_IAF_UF. -
+ * decode the event - sas phy detected event backs up the state machine to the
+ * await speed notification. - identify timeout is an un-expected event and the
+ * state machine is restarted. - link failure events restart the starting state
+ * machine - any other events log a warning message and set a failure status
+ * enum sci_status SCI_SUCCESS on any valid event notification SCI_FAILURE on any
+ * unexpected event notifation
+ */
+static enum sci_status scic_sds_phy_starting_substate_await_iaf_uf_event_handler(
+ struct scic_sds_phy *this_phy,
+ u32 event_code)
+{
+ u32 result = SCI_SUCCESS;
+
+ switch (scu_get_event_code(event_code)) {
+ case SCU_EVENT_SAS_PHY_DETECTED:
+ /* Backup the state machine */
+ scic_sds_phy_start_sas_link_training(this_phy);
+ break;
+
+ case SCU_EVENT_SATA_SPINUP_HOLD:
+ /*
+ * We were doing SAS PHY link training and received a SATA PHY event
+ * continue OOB/SN as if this were a SATA PHY */
+ scic_sds_phy_start_sata_link_training(this_phy);
+ break;
+
+ case SCU_EVENT_RECEIVED_IDENTIFY_TIMEOUT:
+ case SCU_EVENT_LINK_FAILURE:
+ case SCU_EVENT_HARD_RESET_RECEIVED:
+ /* Start the oob/sn state machine over again */
+ scic_sds_phy_restart_starting_state(this_phy);
+ break;
+
+ default:
+ dev_warn(sciphy_to_dev(this_phy),
+ "%s: PHY starting substate machine received "
+ "unexpected event_code %x\n",
+ __func__,
+ event_code);
+
+ result = SCI_FAILURE;
+ break;
+ }
+
+ return result;
+}
+
+/**
+ *
+ * @phy: This struct scic_sds_phy object which has received an event.
+ * @event_code: This is the event code which the phy object is to decode.
+ *
+ * This method is called when an event notification is received for the phy
+ * object when in the state SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_POWER. -
+ * decode the event - link failure events restart the starting state machine -
+ * any other events log a warning message and set a failure status enum sci_status
+ * SCI_SUCCESS on a link failure event SCI_FAILURE on any unexpected event
+ * notifation
+ */
+static enum sci_status scic_sds_phy_starting_substate_await_sas_power_event_handler(
+ struct scic_sds_phy *this_phy,
+ u32 event_code)
+{
+ u32 result = SCI_SUCCESS;
+
+ switch (scu_get_event_code(event_code)) {
+ case SCU_EVENT_LINK_FAILURE:
+ /* Link failure change state back to the starting state */
+ scic_sds_phy_restart_starting_state(this_phy);
+ break;
+
+ default:
+ dev_warn(sciphy_to_dev(this_phy),
+ "%s: PHY starting substate machine received unexpected "
+ "event_code %x\n",
+ __func__,
+ event_code);
+
+ result = SCI_FAILURE;
+ break;
+ }
+
+ return result;
+}
+
+/**
+ *
+ * @phy: This struct scic_sds_phy object which has received an event.
+ * @event_code: This is the event code which the phy object is to decode.
+ *
+ * This method is called when an event notification is received for the phy
+ * object when in the state SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_SATA_POWER. -
+ * decode the event - link failure events restart the starting state machine -
+ * sata spinup hold events are ignored since they are expected - any other
+ * events log a warning message and set a failure status enum sci_status SCI_SUCCESS
+ * on a link failure event SCI_FAILURE on any unexpected event notifation
+ */
+static enum sci_status scic_sds_phy_starting_substate_await_sata_power_event_handler(
+ struct scic_sds_phy *this_phy,
+ u32 event_code)
+{
+ u32 result = SCI_SUCCESS;
+
+ switch (scu_get_event_code(event_code)) {
+ case SCU_EVENT_LINK_FAILURE:
+ /* Link failure change state back to the starting state */
+ scic_sds_phy_restart_starting_state(this_phy);
+ break;
+
+ case SCU_EVENT_SATA_SPINUP_HOLD:
+ /* These events are received every 10ms and are expected while in this state */
+ break;
+
+ case SCU_EVENT_SAS_PHY_DETECTED:
+ /*
+ * There has been a change in the phy type before OOB/SN for the
+ * SATA finished start down the SAS link traning path. */
+ scic_sds_phy_start_sas_link_training(this_phy);
+ break;
+
+ default:
+ dev_warn(sciphy_to_dev(this_phy),
+ "%s: PHY starting substate machine received "
+ "unexpected event_code %x\n",
+ __func__,
+ event_code);
+
+ result = SCI_FAILURE;
+ break;
+ }
+
+ return result;
+}
+
+/**
+ *
+ * @phy: This struct scic_sds_phy object which has received an event.
+ * @event_code: This is the event code which the phy object is to decode.
+ *
+ * This method is called when an event notification is received for the phy
+ * object when in the state SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_SATA_PHY_EN. -
+ * decode the event - link failure events restart the starting state machine -
+ * sata spinup hold events are ignored since they are expected - sata phy
+ * detected event change to the wait speed event - any other events log a
+ * warning message and set a failure status enum sci_status SCI_SUCCESS on a link
+ * failure event SCI_FAILURE on any unexpected event notifation
+ */
+static enum sci_status scic_sds_phy_starting_substate_await_sata_phy_event_handler(
+ struct scic_sds_phy *this_phy,
+ u32 event_code)
+{
+ u32 result = SCI_SUCCESS;
+
+ switch (scu_get_event_code(event_code)) {
+ case SCU_EVENT_LINK_FAILURE:
+ /* Link failure change state back to the starting state */
+ scic_sds_phy_restart_starting_state(this_phy);
+ break;
+
+ case SCU_EVENT_SATA_SPINUP_HOLD:
+ /*
+ * These events might be received since we dont know how many may be in
+ * the completion queue while waiting for power */
+ break;
+
+ case SCU_EVENT_SATA_PHY_DETECTED:
+ this_phy->protocol = SCIC_SDS_PHY_PROTOCOL_SATA;
+
+ /* We have received the SATA PHY notification change state */
+ sci_base_state_machine_change_state(
+ scic_sds_phy_get_starting_substate_machine(this_phy),
+ SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_SATA_SPEED_EN
+ );
+ break;
+
+ case SCU_EVENT_SAS_PHY_DETECTED:
+ /*
+ * There has been a change in the phy type before OOB/SN for the
+ * SATA finished start down the SAS link traning path. */
+ scic_sds_phy_start_sas_link_training(this_phy);
+ break;
+
+ default:
+ dev_warn(sciphy_to_dev(this_phy),
+ "%s: PHY starting substate machine received "
+ "unexpected event_code %x\n",
+ __func__,
+ event_code);
+
+ result = SCI_FAILURE;
+ break;
+ }
+
+ return result;
+}
+
+/**
+ *
+ * @phy: This struct scic_sds_phy object which has received an event.
+ * @event_code: This is the event code which the phy object is to decode.
+ *
+ * This method is called when an event notification is received for the phy
+ * object when in the state SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_SATA_SPEED_EN.
+ * - decode the event - sata phy detected returns us back to this state. -
+ * speed event detected causes a state transition to the wait for signature. -
+ * link failure events restart the starting state machine - any other events
+ * log a warning message and set a failure status enum sci_status SCI_SUCCESS on any
+ * valid event notification SCI_FAILURE on any unexpected event notifation
+ */
+static enum sci_status scic_sds_phy_starting_substate_await_sata_speed_event_handler(
+ struct scic_sds_phy *this_phy,
+ u32 event_code)
+{
+ u32 result = SCI_SUCCESS;
+
+ switch (scu_get_event_code(event_code)) {
+ case SCU_EVENT_SATA_PHY_DETECTED:
+ /*
+ * The hardware reports multiple SATA PHY detected events
+ * ignore the extras */
+ break;
+
+ case SCU_EVENT_SATA_15:
+ case SCU_EVENT_SATA_15_SSC:
+ scic_sds_phy_complete_link_training(
+ this_phy,
+ SCI_SAS_150_GB,
+ SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_SIG_FIS_UF
+ );
+ break;
+
+ case SCU_EVENT_SATA_30:
+ case SCU_EVENT_SATA_30_SSC:
+ scic_sds_phy_complete_link_training(
+ this_phy,
+ SCI_SAS_300_GB,
+ SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_SIG_FIS_UF
+ );
+ break;
+
+ case SCU_EVENT_SATA_60:
+ case SCU_EVENT_SATA_60_SSC:
+ scic_sds_phy_complete_link_training(
+ this_phy,
+ SCI_SAS_600_GB,
+ SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_SIG_FIS_UF
+ );
+ break;
+
+ case SCU_EVENT_LINK_FAILURE:
+ /* Link failure change state back to the starting state */
+ scic_sds_phy_restart_starting_state(this_phy);
+ break;
+
+ case SCU_EVENT_SAS_PHY_DETECTED:
+ /*
+ * There has been a change in the phy type before OOB/SN for the
+ * SATA finished start down the SAS link traning path. */
+ scic_sds_phy_start_sas_link_training(this_phy);
+ break;
+
+ default:
+ dev_warn(sciphy_to_dev(this_phy),
+ "%s: PHY starting substate machine received "
+ "unexpected event_code %x\n",
+ __func__,
+ event_code);
+
+ result = SCI_FAILURE;
+ break;
+ }
+
+ return result;
+}
+
+/**
+ *
+ * @phy: This struct scic_sds_phy object which has received an event.
+ * @event_code: This is the event code which the phy object is to decode.
+ *
+ * This method is called when an event notification is received for the phy
+ * object when in the state SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_SIG_FIS_UF. -
+ * decode the event - sas phy detected event backs up the state machine to the
+ * await speed notification. - identify timeout is an un-expected event and the
+ * state machine is restarted. - link failure events restart the starting state
+ * machine - any other events log a warning message and set a failure status
+ * enum sci_status SCI_SUCCESS on any valid event notification SCI_FAILURE on any
+ * unexpected event notifation
+ */
+static enum sci_status scic_sds_phy_starting_substate_await_sig_fis_event_handler(
+ struct scic_sds_phy *this_phy,
+ u32 event_code)
+{
+ u32 result = SCI_SUCCESS;
+
+ switch (scu_get_event_code(event_code)) {
+ case SCU_EVENT_SATA_PHY_DETECTED:
+ /* Backup the state machine */
+ sci_base_state_machine_change_state(
+ scic_sds_phy_get_starting_substate_machine(this_phy),
+ SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_SATA_SPEED_EN
+ );
+ break;
+
+ case SCU_EVENT_LINK_FAILURE:
+ /* Link failure change state back to the starting state */
+ scic_sds_phy_restart_starting_state(this_phy);
+ break;
+
+ default:
+ dev_warn(sciphy_to_dev(this_phy),
+ "%s: PHY starting substate machine received "
+ "unexpected event_code %x\n",
+ __func__,
+ event_code);
+
+ result = SCI_FAILURE;
+ break;
+ }
+
+ return result;
+}
+
+
+/*
+ * *****************************************************************************
+ * * SCIC SDS PHY FRAME_HANDLERS
+ * ***************************************************************************** */
+
+/**
+ *
+ * @phy: This is struct scic_sds_phy object which is being requested to decode the
+ * frame data.
+ * @frame_index: This is the index of the unsolicited frame which was received
+ * for this phy.
+ *
+ * This method decodes the unsolicited frame when the struct scic_sds_phy is in the
+ * SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_IAF_UF. - Get the UF Header - If the UF
+ * is an IAF - Copy IAF data to local phy object IAF data buffer. - Change
+ * starting substate to wait power. - else - log warning message of unexpected
+ * unsolicted frame - release frame buffer enum sci_status SCI_SUCCESS
+ */
+static enum sci_status scic_sds_phy_starting_substate_await_iaf_uf_frame_handler(
+ struct scic_sds_phy *this_phy,
+ u32 frame_index)
+{
+ enum sci_status result;
+ u32 *frame_words;
+ struct sci_sas_identify_address_frame *identify_frame;
+
+ result = scic_sds_unsolicited_frame_control_get_header(
+ &(scic_sds_phy_get_controller(this_phy)->uf_control),
+ frame_index,
+ (void **)&frame_words);
+
+ if (result != SCI_SUCCESS) {
+ return result;
+ }
+
+ frame_words[0] = SCIC_SWAP_DWORD(frame_words[0]);
+ identify_frame = (struct sci_sas_identify_address_frame *)frame_words;
+
+ if (identify_frame->address_frame_type == 0) {
+ /*
+ * Byte swap the rest of the frame so we can make
+ * a copy of the buffer */
+ frame_words[1] = SCIC_SWAP_DWORD(frame_words[1]);
+ frame_words[2] = SCIC_SWAP_DWORD(frame_words[2]);
+ frame_words[3] = SCIC_SWAP_DWORD(frame_words[3]);
+ frame_words[4] = SCIC_SWAP_DWORD(frame_words[4]);
+ frame_words[5] = SCIC_SWAP_DWORD(frame_words[5]);
+
+ memcpy(
+ &this_phy->phy_type.sas.identify_address_frame_buffer,
+ identify_frame,
+ sizeof(struct sci_sas_identify_address_frame)
+ );
+
+ if (identify_frame->protocols.u.bits.smp_target) {
+ /*
+ * We got the IAF for an expander PHY go to the final state since
+ * there are no power requirements for expander phys. */
+ sci_base_state_machine_change_state(
+ scic_sds_phy_get_starting_substate_machine(this_phy),
+ SCIC_SDS_PHY_STARTING_SUBSTATE_FINAL
+ );
+ } else {
+ /* We got the IAF we can now go to the await spinup semaphore state */
+ sci_base_state_machine_change_state(
+ scic_sds_phy_get_starting_substate_machine(this_phy),
+ SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_SAS_POWER
+ );
+ }
+
+ result = SCI_SUCCESS;
+ } else
+ dev_warn(sciphy_to_dev(this_phy),
+ "%s: PHY starting substate machine received "
+ "unexpected frame id %x\n",
+ __func__,
+ frame_index);
+
+ /* Regardless of the result release this frame since we are done with it */
+ scic_sds_controller_release_frame(
+ scic_sds_phy_get_controller(this_phy), frame_index
+ );
+
+ return result;
+}
+
+/**
+ *
+ * @phy: This is struct scic_sds_phy object which is being requested to decode the
+ * frame data.
+ * @frame_index: This is the index of the unsolicited frame which was received
+ * for this phy.
+ *
+ * This method decodes the unsolicited frame when the struct scic_sds_phy is in the
+ * SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_SIG_FIS_UF. - Get the UF Header - If
+ * the UF is an SIGNATURE FIS - Copy IAF data to local phy object SIGNATURE FIS
+ * data buffer. - else - log warning message of unexpected unsolicted frame -
+ * release frame buffer enum sci_status SCI_SUCCESS Must decode the SIGNATURE FIS
+ * data
+ */
+static enum sci_status scic_sds_phy_starting_substate_await_sig_fis_frame_handler(
+ struct scic_sds_phy *this_phy,
+ u32 frame_index)
+{
+ enum sci_status result;
+ u32 *frame_words;
+ struct sata_fis_header *fis_frame_header;
+ u32 *fis_frame_data;
+
+ result = scic_sds_unsolicited_frame_control_get_header(
+ &(scic_sds_phy_get_controller(this_phy)->uf_control),
+ frame_index,
+ (void **)&frame_words);
+
+ if (result != SCI_SUCCESS) {
+ return result;
+ }
+
+ fis_frame_header = (struct sata_fis_header *)frame_words;
+
+ if (
+ (fis_frame_header->fis_type == SATA_FIS_TYPE_REGD2H)
+ && !(fis_frame_header->status & ATA_STATUS_REG_BSY_BIT)
+ ) {
+ scic_sds_unsolicited_frame_control_get_buffer(
+ &(scic_sds_phy_get_controller(this_phy)->uf_control),
+ frame_index,
+ (void **)&fis_frame_data
+ );
+
+ scic_sds_controller_copy_sata_response(
+ &this_phy->phy_type.sata.signature_fis_buffer,
+ frame_words,
+ fis_frame_data
+ );
+
+ /* We got the IAF we can now go to the await spinup semaphore state */
+ sci_base_state_machine_change_state(
+ scic_sds_phy_get_starting_substate_machine(this_phy),
+ SCIC_SDS_PHY_STARTING_SUBSTATE_FINAL
+ );
+
+ result = SCI_SUCCESS;
+ } else
+ dev_warn(sciphy_to_dev(this_phy),
+ "%s: PHY starting substate machine received "
+ "unexpected frame id %x\n",
+ __func__,
+ frame_index);
+
+ /* Regardless of the result release this frame since we are done with it */
+ scic_sds_controller_release_frame(
+ scic_sds_phy_get_controller(this_phy), frame_index
+ );
+
+ return result;
+}
+
+/*
+ * *****************************************************************************
+ * * SCIC SDS PHY POWER_HANDLERS
+ * ***************************************************************************** */
+
+/**
+ *
+ * @phy: This is the struct sci_base_phy object which is cast into a struct scic_sds_phy
+ * object.
+ *
+ * This method is called by the struct scic_sds_controller when the phy object is
+ * granted power. - The notify enable spinups are turned on for this phy object
+ * - The phy state machine is transitioned to the
+ * SCIC_SDS_PHY_STARTING_SUBSTATE_FINAL. enum sci_status SCI_SUCCESS
+ */
+static enum sci_status scic_sds_phy_starting_substate_await_sas_power_consume_power_handler(
+ struct scic_sds_phy *this_phy)
+{
+ u32 enable_spinup;
+
+ enable_spinup = SCU_SAS_ENSPINUP_READ(this_phy);
+ enable_spinup |= SCU_ENSPINUP_GEN_BIT(ENABLE);
+ SCU_SAS_ENSPINUP_WRITE(this_phy, enable_spinup);
+
+ /* Change state to the final state this substate machine has run to completion */
+ sci_base_state_machine_change_state(
+ scic_sds_phy_get_starting_substate_machine(this_phy),
+ SCIC_SDS_PHY_STARTING_SUBSTATE_FINAL
+ );
+
+ return SCI_SUCCESS;
+}
+
+/**
+ *
+ * @phy: This is the struct sci_base_phy object which is cast into a struct scic_sds_phy
+ * object.
+ *
+ * This method is called by the struct scic_sds_controller when the phy object is
+ * granted power. - The phy state machine is transitioned to the
+ * SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_SATA_PHY_EN. enum sci_status SCI_SUCCESS
+ */
+static enum sci_status scic_sds_phy_starting_substate_await_sata_power_consume_power_handler(
+ struct scic_sds_phy *this_phy)
+{
+ u32 scu_sas_pcfg_value;
+
+ /* Release the spinup hold state and reset the OOB state machine */
+ scu_sas_pcfg_value = SCU_SAS_PCFG_READ(this_phy);
+ scu_sas_pcfg_value &=
+ ~(SCU_SAS_PCFG_GEN_BIT(SATA_SPINUP_HOLD) | SCU_SAS_PCFG_GEN_BIT(OOB_ENABLE));
+ scu_sas_pcfg_value |= SCU_SAS_PCFG_GEN_BIT(OOB_RESET);
+ SCU_SAS_PCFG_WRITE(this_phy, scu_sas_pcfg_value);
+
+ /* Now restart the OOB operation */
+ scu_sas_pcfg_value &= ~SCU_SAS_PCFG_GEN_BIT(OOB_RESET);
+ scu_sas_pcfg_value |= SCU_SAS_PCFG_GEN_BIT(OOB_ENABLE);
+ SCU_SAS_PCFG_WRITE(this_phy, scu_sas_pcfg_value);
+
+ /* Change state to the final state this substate machine has run to completion */
+ sci_base_state_machine_change_state(
+ scic_sds_phy_get_starting_substate_machine(this_phy),
+ SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_SATA_PHY_EN
+ );
+
+ return SCI_SUCCESS;
+}
+
+/* --------------------------------------------------------------------------- */
+
+struct scic_sds_phy_state_handler
+scic_sds_phy_starting_substate_handler_table[SCIC_SDS_PHY_STARTING_MAX_SUBSTATES] =
+{
+ /* SCIC_SDS_PHY_STARTING_SUBSTATE_INITIAL */
+ {
+ {
+ scic_sds_phy_default_start_handler,
+ scic_sds_phy_default_stop_handler,
+ scic_sds_phy_default_reset_handler,
+ scic_sds_phy_default_destroy_handler
+ },
+ scic_sds_phy_default_frame_handler,
+ scic_sds_phy_default_event_handler,
+ scic_sds_phy_default_consume_power_handler
+ },
+ /* SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_OSSP_EN */
+ {
+ {
+ scic_sds_phy_default_start_handler,
+ scic_sds_phy_default_stop_handler,
+ scic_sds_phy_default_reset_handler,
+ scic_sds_phy_default_destroy_handler
+ },
+ scic_sds_phy_default_frame_handler,
+ scic_sds_phy_starting_substate_await_ossp_event_handler,
+ scic_sds_phy_default_consume_power_handler
+ },
+ /* SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_SAS_SPEED_EN */
+ {
+ {
+ scic_sds_phy_default_start_handler,
+ scic_sds_phy_default_stop_handler,
+ scic_sds_phy_default_reset_handler,
+ scic_sds_phy_default_destroy_handler
+ },
+ scic_sds_phy_default_frame_handler,
+ scic_sds_phy_starting_substate_await_sas_phy_speed_event_handler,
+ scic_sds_phy_default_consume_power_handler
+ },
+ /* SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_IAF_UF */
+ {
+ {
+ scic_sds_phy_default_start_handler,
+ scic_sds_phy_default_stop_handler,
+ scic_sds_phy_default_reset_handler,
+ scic_sds_phy_default_destroy_handler
+ },
+ scic_sds_phy_starting_substate_await_iaf_uf_frame_handler,
+ scic_sds_phy_starting_substate_await_iaf_uf_event_handler,
+ scic_sds_phy_default_consume_power_handler
+ },
+ /* SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_SAS_POWER */
+ {
+ {
+ scic_sds_phy_default_start_handler,
+ scic_sds_phy_default_stop_handler,
+ scic_sds_phy_default_reset_handler,
+ scic_sds_phy_default_destroy_handler
+ },
+ scic_sds_phy_default_frame_handler,
+ scic_sds_phy_starting_substate_await_sas_power_event_handler,
+ scic_sds_phy_starting_substate_await_sas_power_consume_power_handler
+ },
+ /* SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_SATA_POWER, */
+ {
+ {
+ scic_sds_phy_default_start_handler,
+ scic_sds_phy_default_stop_handler,
+ scic_sds_phy_default_reset_handler,
+ scic_sds_phy_default_destroy_handler
+ },
+ scic_sds_phy_default_frame_handler,
+ scic_sds_phy_starting_substate_await_sata_power_event_handler,
+ scic_sds_phy_starting_substate_await_sata_power_consume_power_handler
+ },
+ /* SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_SATA_PHY_EN, */
+ {
+ {
+ scic_sds_phy_default_start_handler,
+ scic_sds_phy_default_stop_handler,
+ scic_sds_phy_default_reset_handler,
+ scic_sds_phy_default_destroy_handler
+ },
+ scic_sds_phy_default_frame_handler,
+ scic_sds_phy_starting_substate_await_sata_phy_event_handler,
+ scic_sds_phy_default_consume_power_handler
+ },
+ /* SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_SATA_SPEED_EN, */
+ {
+ {
+ scic_sds_phy_default_start_handler,
+ scic_sds_phy_default_stop_handler,
+ scic_sds_phy_default_reset_handler,
+ scic_sds_phy_default_destroy_handler
+ },
+ scic_sds_phy_default_frame_handler,
+ scic_sds_phy_starting_substate_await_sata_speed_event_handler,
+ scic_sds_phy_default_consume_power_handler
+ },
+ /* SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_SIG_FIS_UF, */
+ {
+ {
+ scic_sds_phy_default_start_handler,
+ scic_sds_phy_default_stop_handler,
+ scic_sds_phy_default_reset_handler,
+ scic_sds_phy_default_destroy_handler
+ },
+ scic_sds_phy_starting_substate_await_sig_fis_frame_handler,
+ scic_sds_phy_starting_substate_await_sig_fis_event_handler,
+ scic_sds_phy_default_consume_power_handler
+ },
+ /* SCIC_SDS_PHY_STARTING_SUBSTATE_FINAL */
+ {
+ {
+ scic_sds_phy_default_start_handler,
+ scic_sds_phy_default_stop_handler,
+ scic_sds_phy_default_reset_handler,
+ scic_sds_phy_default_destroy_handler
+ },
+ scic_sds_phy_default_frame_handler,
+ scic_sds_phy_default_event_handler,
+ scic_sds_phy_default_consume_power_handler
+ }
+};
+
+/**
+ * scic_sds_phy_set_starting_substate_handlers() -
+ *
+ * This macro sets the starting substate handlers by state_id
+ */
+#define scic_sds_phy_set_starting_substate_handlers(phy, state_id) \
+ scic_sds_phy_set_state_handlers(\
+ (phy), \
+ &scic_sds_phy_starting_substate_handler_table[(state_id)] \
+ )
+
+/*
+ * ****************************************************************************
+ * * PHY STARTING SUBSTATE METHODS
+ * **************************************************************************** */
+
+/**
+ *
+ * @object: This is the struct sci_base_object which is cast to a struct scic_sds_phy object.
+ *
+ * This method will perform the actions required by the struct scic_sds_phy on
+ * entering the SCIC_SDS_PHY_STARTING_SUBSTATE_INITIAL. - The initial state
+ * handlers are put in place for the struct scic_sds_phy object. - The state is
+ * changed to the wait phy type event notification. none
+ */
+static void scic_sds_phy_starting_initial_substate_enter(
+ struct sci_base_object *object)
+{
+ struct scic_sds_phy *this_phy;
+
+ this_phy = (struct scic_sds_phy *)object;
+
+ scic_sds_phy_set_starting_substate_handlers(
+ this_phy, SCIC_SDS_PHY_STARTING_SUBSTATE_INITIAL);
+
+ /* This is just an temporary state go off to the starting state */
+ sci_base_state_machine_change_state(
+ scic_sds_phy_get_starting_substate_machine(this_phy),
+ SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_OSSP_EN
+ );
+}
+
+/**
+ *
+ * @object: This is the struct sci_base_object which is cast to a struct scic_sds_phy object.
+ *
+ * This method will perform the actions required by the struct scic_sds_phy on
+ * entering the SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_PHY_TYPE_EN. - Set the
+ * struct scic_sds_phy object state handlers for this state. none
+ */
+static void scic_sds_phy_starting_await_ossp_en_substate_enter(
+ struct sci_base_object *object)
+{
+ struct scic_sds_phy *this_phy;
+
+ this_phy = (struct scic_sds_phy *)object;
+
+ scic_sds_phy_set_starting_substate_handlers(
+ this_phy, SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_OSSP_EN
+ );
+}
+
+/**
+ *
+ * @object: This is the struct sci_base_object which is cast to a struct scic_sds_phy object.
+ *
+ * This method will perform the actions required by the struct scic_sds_phy on
+ * entering the SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_SPEED_EN. - Set the
+ * struct scic_sds_phy object state handlers for this state. none
+ */
+static void scic_sds_phy_starting_await_sas_speed_en_substate_enter(
+ struct sci_base_object *object)
+{
+ struct scic_sds_phy *this_phy;
+
+ this_phy = (struct scic_sds_phy *)object;
+
+ scic_sds_phy_set_starting_substate_handlers(
+ this_phy, SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_SAS_SPEED_EN
+ );
+}
+
+/**
+ *
+ * @object: This is the struct sci_base_object which is cast to a struct scic_sds_phy object.
+ *
+ * This method will perform the actions required by the struct scic_sds_phy on
+ * entering the SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_IAF_UF. - Set the
+ * struct scic_sds_phy object state handlers for this state. none
+ */
+static void scic_sds_phy_starting_await_iaf_uf_substate_enter(
+ struct sci_base_object *object)
+{
+ struct scic_sds_phy *this_phy;
+
+ this_phy = (struct scic_sds_phy *)object;
+
+ scic_sds_phy_set_starting_substate_handlers(
+ this_phy, SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_IAF_UF
+ );
+}
+
+/**
+ *
+ * @object: This is the struct sci_base_object which is cast to a struct scic_sds_phy object.
+ *
+ * This method will perform the actions required by the struct scic_sds_phy on
+ * entering the SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_SAS_POWER. - Set the
+ * struct scic_sds_phy object state handlers for this state. - Add this phy object to
+ * the power control queue none
+ */
+static void scic_sds_phy_starting_await_sas_power_substate_enter(
+ struct sci_base_object *object)
+{
+ struct scic_sds_phy *this_phy;
+
+ this_phy = (struct scic_sds_phy *)object;
+
+ scic_sds_phy_set_starting_substate_handlers(
+ this_phy, SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_SAS_POWER
+ );
+
+ scic_sds_controller_power_control_queue_insert(
+ scic_sds_phy_get_controller(this_phy),
+ this_phy
+ );
+}
+
+/**
+ *
+ * @object: This is the struct sci_base_object which is cast to a struct scic_sds_phy object.
+ *
+ * This method will perform the actions required by the struct scic_sds_phy on exiting
+ * the SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_SAS_POWER. - Remove the
+ * struct scic_sds_phy object from the power control queue. none
+ */
+static void scic_sds_phy_starting_await_sas_power_substate_exit(
+ struct sci_base_object *object)
+{
+ struct scic_sds_phy *this_phy;
+
+ this_phy = (struct scic_sds_phy *)object;
+
+ scic_sds_controller_power_control_queue_remove(
+ scic_sds_phy_get_controller(this_phy), this_phy
+ );
+}
+
+/**
+ *
+ * @object: This is the struct sci_base_object which is cast to a struct scic_sds_phy object.
+ *
+ * This method will perform the actions required by the struct scic_sds_phy on
+ * entering the SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_SATA_POWER. - Set the
+ * struct scic_sds_phy object state handlers for this state. - Add this phy object to
+ * the power control queue none
+ */
+static void scic_sds_phy_starting_await_sata_power_substate_enter(
+ struct sci_base_object *object)
+{
+ struct scic_sds_phy *this_phy;
+
+ this_phy = (struct scic_sds_phy *)object;
+
+ scic_sds_phy_set_starting_substate_handlers(
+ this_phy, SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_SATA_POWER
+ );
+
+ scic_sds_controller_power_control_queue_insert(
+ scic_sds_phy_get_controller(this_phy),
+ this_phy
+ );
+}
+
+/**
+ *
+ * @object: This is the struct sci_base_object which is cast to a struct scic_sds_phy object.
+ *
+ * This method will perform the actions required by the struct scic_sds_phy on exiting
+ * the SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_SATA_POWER. - Remove the
+ * struct scic_sds_phy object from the power control queue. none
+ */
+static void scic_sds_phy_starting_await_sata_power_substate_exit(
+ struct sci_base_object *object)
+{
+ struct scic_sds_phy *this_phy;
+
+ this_phy = (struct scic_sds_phy *)object;
+
+ scic_sds_controller_power_control_queue_remove(
+ scic_sds_phy_get_controller(this_phy),
+ this_phy
+ );
+}
+
+/**
+ *
+ * @object: This is the struct sci_base_object which is cast to a struct scic_sds_phy object.
+ *
+ * This method will perform the actions required by the struct scic_sds_phy on
+ * entering the SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_SATA_PHY_EN. - Set the
+ * struct scic_sds_phy object state handlers for this state. none
+ */
+static void scic_sds_phy_starting_await_sata_phy_substate_enter(
+ struct sci_base_object *object)
+{
+ struct scic_sds_phy *this_phy;
+
+ this_phy = (struct scic_sds_phy *)object;
+
+ scic_sds_phy_set_starting_substate_handlers(
+ this_phy, SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_SATA_PHY_EN
+ );
+
+ scic_cb_timer_start(
+ scic_sds_phy_get_controller(this_phy),
+ this_phy->sata_timeout_timer,
+ SCIC_SDS_SATA_LINK_TRAINING_TIMEOUT
+ );
+}
+
+/**
+ *
+ * @object: This is the struct sci_base_object which is cast to a struct scic_sds_phy object.
+ *
+ * This method will perform the actions required by the struct scic_sds_phy on exiting
+ * the SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_SATA_SPEED_EN. - stop the timer
+ * that was started on entry to await sata phy event notification none
+ */
+static void scic_sds_phy_starting_await_sata_phy_substate_exit(
+ struct sci_base_object *object)
+{
+ struct scic_sds_phy *this_phy;
+
+ this_phy = (struct scic_sds_phy *)object;
+
+ scic_cb_timer_stop(
+ scic_sds_phy_get_controller(this_phy),
+ this_phy->sata_timeout_timer
+ );
+}
+
+/**
+ *
+ * @object: This is the struct sci_base_object which is cast to a struct scic_sds_phy object.
+ *
+ * This method will perform the actions required by the struct scic_sds_phy on
+ * entering the SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_SATA_SPEED_EN. - Set the
+ * struct scic_sds_phy object state handlers for this state. none
+ */
+static void scic_sds_phy_starting_await_sata_speed_substate_enter(
+ struct sci_base_object *object)
+{
+ struct scic_sds_phy *this_phy;
+
+ this_phy = (struct scic_sds_phy *)object;
+
+ scic_sds_phy_set_starting_substate_handlers(
+ this_phy, SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_SATA_SPEED_EN
+ );
+
+ scic_cb_timer_start(
+ scic_sds_phy_get_controller(this_phy),
+ this_phy->sata_timeout_timer,
+ SCIC_SDS_SATA_LINK_TRAINING_TIMEOUT
+ );
+}
+
+/**
+ *
+ * @object: This is the struct sci_base_object which is cast to a struct scic_sds_phy object.
+ *
+ * This method will perform the actions required by the struct scic_sds_phy on exiting
+ * the SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_SATA_SPEED_EN. - stop the timer
+ * that was started on entry to await sata phy event notification none
+ */
+static void scic_sds_phy_starting_await_sata_speed_substate_exit(
+ struct sci_base_object *object)
+{
+ struct scic_sds_phy *this_phy;
+
+ this_phy = (struct scic_sds_phy *)object;
+
+ scic_cb_timer_stop(
+ scic_sds_phy_get_controller(this_phy),
+ this_phy->sata_timeout_timer
+ );
+}
+
+/**
+ *
+ * @object: This is the struct sci_base_object which is cast to a struct scic_sds_phy object.
+ *
+ * This method will perform the actions required by the struct scic_sds_phy on
+ * entering the SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_SIG_FIS_UF. - Set the
+ * struct scic_sds_phy object state handlers for this state. - Start the SIGNATURE FIS
+ * timeout timer none
+ */
+static void scic_sds_phy_starting_await_sig_fis_uf_substate_enter(
+ struct sci_base_object *object)
+{
+ bool continue_to_ready_state;
+ struct scic_sds_phy *this_phy;
+
+ this_phy = (struct scic_sds_phy *)object;
+
+ scic_sds_phy_set_starting_substate_handlers(
+ this_phy, SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_SIG_FIS_UF
+ );
+
+ continue_to_ready_state = scic_sds_port_link_detected(
+ this_phy->owning_port,
+ this_phy
+ );
+
+ if (continue_to_ready_state) {
+ /*
+ * Clear the PE suspend condition so we can actually receive SIG FIS
+ * The hardware will not respond to the XRDY until the PE suspend
+ * condition is cleared. */
+ scic_sds_phy_resume(this_phy);
+
+ scic_cb_timer_start(
+ scic_sds_phy_get_controller(this_phy),
+ this_phy->sata_timeout_timer,
+ SCIC_SDS_SIGNATURE_FIS_TIMEOUT
+ );
+ } else {
+ this_phy->is_in_link_training = false;
+ }
+}
+
+/**
+ *
+ * @object: This is the struct sci_base_object which is cast to a struct scic_sds_phy object.
+ *
+ * This method will perform the actions required by the struct scic_sds_phy on exiting
+ * the SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_SIG_FIS_UF. - Stop the SIGNATURE
+ * FIS timeout timer. none
+ */
+static void scic_sds_phy_starting_await_sig_fis_uf_substate_exit(
+ struct sci_base_object *object)
+{
+ struct scic_sds_phy *this_phy;
+
+ this_phy = (struct scic_sds_phy *)object;
+
+ scic_cb_timer_stop(
+ scic_sds_phy_get_controller(this_phy),
+ this_phy->sata_timeout_timer
+ );
+}
+
+/**
+ *
+ * @object: This is the struct sci_base_object which is cast to a struct scic_sds_phy object.
+ *
+ * This method will perform the actions required by the struct scic_sds_phy on
+ * entering the SCIC_SDS_PHY_STARTING_SUBSTATE_FINAL. - Set the struct scic_sds_phy
+ * object state handlers for this state. - Change base state machine to the
+ * ready state. none
+ */
+static void scic_sds_phy_starting_final_substate_enter(
+ struct sci_base_object *object)
+{
+ struct scic_sds_phy *this_phy;
+
+ this_phy = (struct scic_sds_phy *)object;
+
+ scic_sds_phy_set_starting_substate_handlers(
+ this_phy, SCIC_SDS_PHY_STARTING_SUBSTATE_FINAL
+ );
+
+ /*
+ * State machine has run to completion so exit out and change
+ * the base state machine to the ready state */
+ sci_base_state_machine_change_state(
+ scic_sds_phy_get_base_state_machine(this_phy),
+ SCI_BASE_PHY_STATE_READY);
+}
+
+/* --------------------------------------------------------------------------- */
+
+const struct sci_base_state scic_sds_phy_starting_substates[] = {
+ [SCIC_SDS_PHY_STARTING_SUBSTATE_INITIAL] = {
+ .enter_state = scic_sds_phy_starting_initial_substate_enter,
+ },
+ [SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_OSSP_EN] = {
+ .enter_state = scic_sds_phy_starting_await_ossp_en_substate_enter,
+ },
+ [SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_SAS_SPEED_EN] = {
+ .enter_state = scic_sds_phy_starting_await_sas_speed_en_substate_enter,
+ },
+ [SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_IAF_UF] = {
+ .enter_state = scic_sds_phy_starting_await_iaf_uf_substate_enter,
+ },
+ [SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_SAS_POWER] = {
+ .enter_state = scic_sds_phy_starting_await_sas_power_substate_enter,
+ .exit_state = scic_sds_phy_starting_await_sas_power_substate_exit,
+ },
+ [SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_SATA_POWER] = {
+ .enter_state = scic_sds_phy_starting_await_sata_power_substate_enter,
+ .exit_state = scic_sds_phy_starting_await_sata_power_substate_exit
+ },
+ [SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_SATA_PHY_EN] = {
+ .enter_state = scic_sds_phy_starting_await_sata_phy_substate_enter,
+ .exit_state = scic_sds_phy_starting_await_sata_phy_substate_exit
+ },
+ [SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_SATA_SPEED_EN] = {
+ .enter_state = scic_sds_phy_starting_await_sata_speed_substate_enter,
+ .exit_state = scic_sds_phy_starting_await_sata_speed_substate_exit
+ },
+ [SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_SIG_FIS_UF] = {
+ .enter_state = scic_sds_phy_starting_await_sig_fis_uf_substate_enter,
+ .exit_state = scic_sds_phy_starting_await_sig_fis_uf_substate_exit
+ },
+ [SCIC_SDS_PHY_STARTING_SUBSTATE_FINAL] = {
+ .enter_state = scic_sds_phy_starting_final_substate_enter,
+ }
+};
+
+/*
+ * ***************************************************************************
+ * * DEFAULT HANDLERS
+ * *************************************************************************** */
+
+/**
+ *
+ * @phy: This is the struct sci_base_phy object which is cast into a struct scic_sds_phy
+ * object.
+ *
+ * This is the default method for phy a start request. It will report a
+ * warning and exit. enum sci_status SCI_FAILURE_INVALID_STATE
+ */
+enum sci_status scic_sds_phy_default_start_handler(
+ struct sci_base_phy *phy)
+{
+ struct scic_sds_phy *this_phy;
+
+ this_phy = (struct scic_sds_phy *)phy;
+
+ dev_warn(sciphy_to_dev(this_phy),
+ "%s: SCIC Phy 0x%p requested to start from invalid "
+ "state %d\n",
+ __func__,
+ this_phy,
+ sci_base_state_machine_get_state(
+ &this_phy->parent.state_machine));
+
+ return SCI_FAILURE_INVALID_STATE;
+
+}
+
+/**
+ *
+ * @phy: This is the struct sci_base_phy object which is cast into a struct scic_sds_phy
+ * object.
+ *
+ * This is the default method for phy a stop request. It will report a warning
+ * and exit. enum sci_status SCI_FAILURE_INVALID_STATE
+ */
+enum sci_status scic_sds_phy_default_stop_handler(
+ struct sci_base_phy *phy)
+{
+ struct scic_sds_phy *this_phy;
+
+ this_phy = (struct scic_sds_phy *)phy;
+
+ dev_warn(sciphy_to_dev(this_phy),
+ "%s: SCIC Phy 0x%p requested to stop from invalid "
+ "state %d\n",
+ __func__,
+ this_phy,
+ sci_base_state_machine_get_state(
+ &this_phy->parent.state_machine));
+
+ return SCI_FAILURE_INVALID_STATE;
+}
+
+/**
+ *
+ * @phy: This is the struct sci_base_phy object which is cast into a struct scic_sds_phy
+ * object.
+ *
+ * This is the default method for phy a reset request. It will report a
+ * warning and exit. enum sci_status SCI_FAILURE_INVALID_STATE
+ */
+enum sci_status scic_sds_phy_default_reset_handler(
+ struct sci_base_phy *phy)
+{
+ struct scic_sds_phy *this_phy;
+
+ this_phy = (struct scic_sds_phy *)phy;
+
+ dev_warn(sciphy_to_dev(this_phy),
+ "%s: SCIC Phy 0x%p requested to reset from invalid state "
+ "%d\n",
+ __func__,
+ this_phy,
+ sci_base_state_machine_get_state(
+ &this_phy->parent.state_machine));
+
+ return SCI_FAILURE_INVALID_STATE;
+}
+
+/**
+ *
+ * @phy: This is the struct sci_base_phy object which is cast into a struct scic_sds_phy
+ * object.
+ *
+ * This is the default method for phy a destruct request. It will report a
+ * warning and exit. enum sci_status SCI_FAILURE_INVALID_STATE
+ */
+enum sci_status scic_sds_phy_default_destroy_handler(
+ struct sci_base_phy *phy)
+{
+ struct scic_sds_phy *this_phy;
+
+ this_phy = (struct scic_sds_phy *)phy;
+
+ /* / @todo Implement something for the default */
+ dev_warn(sciphy_to_dev(this_phy),
+ "%s: SCIC Phy 0x%p requested to destroy from invalid "
+ "state %d\n",
+ __func__,
+ this_phy,
+ sci_base_state_machine_get_state(
+ &this_phy->parent.state_machine));
+
+ return SCI_FAILURE_INVALID_STATE;
+}
+
+/**
+ *
+ * @phy: This is the struct sci_base_phy object which is cast into a struct scic_sds_phy
+ * object.
+ * @frame_index: This is the frame index that was received from the SCU
+ * hardware.
+ *
+ * This is the default method for a phy frame handling request. It will report
+ * a warning, release the frame and exit. enum sci_status SCI_FAILURE_INVALID_STATE
+ */
+enum sci_status scic_sds_phy_default_frame_handler(
+ struct scic_sds_phy *this_phy,
+ u32 frame_index)
+{
+ dev_warn(sciphy_to_dev(this_phy),
+ "%s: SCIC Phy 0x%p received unexpected frame data %d "
+ "while in state %d\n",
+ __func__,
+ this_phy,
+ frame_index,
+ sci_base_state_machine_get_state(
+ &this_phy->parent.state_machine));
+
+ scic_sds_controller_release_frame(
+ scic_sds_phy_get_controller(this_phy), frame_index);
+
+ return SCI_FAILURE_INVALID_STATE;
+}
+
+/**
+ *
+ * @phy: This is the struct sci_base_phy object which is cast into a struct scic_sds_phy
+ * object.
+ * @event_code: This is the event code that was received from the SCU hardware.
+ *
+ * This is the default method for a phy event handler. It will report a
+ * warning and exit. enum sci_status SCI_FAILURE_INVALID_STATE
+ */
+enum sci_status scic_sds_phy_default_event_handler(
+ struct scic_sds_phy *this_phy,
+ u32 event_code)
+{
+ dev_warn(sciphy_to_dev(this_phy),
+ "%s: SCIC Phy 0x%p received unexpected event status %x "
+ "while in state %d\n",
+ __func__,
+ this_phy,
+ event_code,
+ sci_base_state_machine_get_state(
+ &this_phy->parent.state_machine));
+
+ return SCI_FAILURE_INVALID_STATE;
+}
+
+/**
+ *
+ * @phy: This is the struct sci_base_phy object which is cast into a struct scic_sds_phy
+ * object.
+ *
+ * This is the default method for a phy consume power handler. It will report
+ * a warning and exit. enum sci_status SCI_FAILURE_INVALID_STATE
+ */
+enum sci_status scic_sds_phy_default_consume_power_handler(
+ struct scic_sds_phy *this_phy)
+{
+ dev_warn(sciphy_to_dev(this_phy),
+ "%s: SCIC Phy 0x%p given unexpected permission to consume "
+ "power while in state %d\n",
+ __func__,
+ this_phy,
+ sci_base_state_machine_get_state(
+ &this_phy->parent.state_machine));
+
+ return SCI_FAILURE_INVALID_STATE;
+}
+
+/*
+ * ******************************************************************************
+ * * PHY STOPPED STATE HANDLERS
+ * ****************************************************************************** */
+
+/**
+ *
+ * @phy: This is the struct sci_base_phy object which is cast into a struct scic_sds_phy
+ * object.
+ *
+ * This method takes the struct scic_sds_phy from a stopped state and attempts to
+ * start it. - The phy state machine is transitioned to the
+ * SCI_BASE_PHY_STATE_STARTING. enum sci_status SCI_SUCCESS
+ */
+static enum sci_status scic_sds_phy_stopped_state_start_handler(
+ struct sci_base_phy *phy)
+{
+ struct scic_sds_phy *this_phy;
+
+ this_phy = (struct scic_sds_phy *)phy;
+
+ sci_base_state_machine_change_state(
+ scic_sds_phy_get_base_state_machine(this_phy),
+ SCI_BASE_PHY_STATE_STARTING
+ );
+
+ return SCI_SUCCESS;
+}
+
+/**
+ *
+ * @phy: This is the struct sci_base_phy object which is cast into a struct scic_sds_phy
+ * object.
+ *
+ * This method takes the struct scic_sds_phy from a stopped state and destroys it. -
+ * This function takes no action. Shouldnt this function transition the
+ * struct sci_base_phy::state_machine to the SCI_BASE_PHY_STATE_FINAL? enum sci_status
+ * SCI_SUCCESS
+ */
+static enum sci_status scic_sds_phy_stopped_state_destroy_handler(
+ struct sci_base_phy *phy)
+{
+ struct scic_sds_phy *this_phy;
+
+ this_phy = (struct scic_sds_phy *)phy;
+
+ /* / @todo what do we actually need to do here? */
+ return SCI_SUCCESS;
+}
+
+/*
+ * ******************************************************************************
+ * * PHY STARTING STATE HANDLERS
+ * ****************************************************************************** */
+
+/* All of these state handlers are mapped to the starting sub-state machine */
+
+/*
+ * ******************************************************************************
+ * * PHY READY STATE HANDLERS
+ * ****************************************************************************** */
+
+/**
+ *
+ * @phy: This is the struct sci_base_phy object which is cast into a struct scic_sds_phy
+ * object.
+ *
+ * This method takes the struct scic_sds_phy from a ready state and attempts to stop
+ * it. - The phy state machine is transitioned to the
+ * SCI_BASE_PHY_STATE_STOPPED. enum sci_status SCI_SUCCESS
+ */
+static enum sci_status scic_sds_phy_ready_state_stop_handler(
+ struct sci_base_phy *phy)
+{
+ struct scic_sds_phy *this_phy;
+
+ this_phy = (struct scic_sds_phy *)phy;
+
+ sci_base_state_machine_change_state(
+ scic_sds_phy_get_base_state_machine(this_phy),
+ SCI_BASE_PHY_STATE_STOPPED
+ );
+
+ return SCI_SUCCESS;
+}
+
+/**
+ *
+ * @phy: This is the struct sci_base_phy object which is cast into a struct scic_sds_phy
+ * object.
+ *
+ * This method takes the struct scic_sds_phy from a ready state and attempts to reset
+ * it. - The phy state machine is transitioned to the
+ * SCI_BASE_PHY_STATE_STARTING. enum sci_status SCI_SUCCESS
+ */
+static enum sci_status scic_sds_phy_ready_state_reset_handler(
+ struct sci_base_phy *phy)
+{
+ struct scic_sds_phy *this_phy;
+
+ this_phy = (struct scic_sds_phy *)phy;
+
+ sci_base_state_machine_change_state(
+ scic_sds_phy_get_base_state_machine(this_phy),
+ SCI_BASE_PHY_STATE_RESETTING
+ );
+
+ return SCI_SUCCESS;
+}
+
+/**
+ *
+ * @phy: This is the struct scic_sds_phy object which has received the event.
+ *
+ * This method request the struct scic_sds_phy handle the received event. The only
+ * event that we are interested in while in the ready state is the link failure
+ * event. - decoded event is a link failure - transition the struct scic_sds_phy back
+ * to the SCI_BASE_PHY_STATE_STARTING state. - any other event recived will
+ * report a warning message enum sci_status SCI_SUCCESS if the event received is a
+ * link failure SCI_FAILURE_INVALID_STATE for any other event received.
+ */
+static enum sci_status scic_sds_phy_ready_state_event_handler(
+ struct scic_sds_phy *this_phy,
+ u32 event_code)
+{
+ enum sci_status result = SCI_FAILURE;
+
+ switch (scu_get_event_code(event_code)) {
+ case SCU_EVENT_LINK_FAILURE:
+ /* Link failure change state back to the starting state */
+ sci_base_state_machine_change_state(
+ scic_sds_phy_get_base_state_machine(this_phy),
+ SCI_BASE_PHY_STATE_STARTING
+ );
+
+ result = SCI_SUCCESS;
+ break;
+
+ case SCU_EVENT_BROADCAST_CHANGE:
+ /* Broadcast change received. Notify the port. */
+ if (scic_sds_phy_get_port(this_phy) != SCI_INVALID_HANDLE)
+ scic_sds_port_broadcast_change_received(this_phy->owning_port, this_phy);
+ else
+ this_phy->bcn_received_while_port_unassigned = true;
+ break;
+
+ default:
+ dev_warn(sciphy_to_dev(this_phy),
+ "%sP SCIC PHY 0x%p ready state machine received "
+ "unexpected event_code %x\n",
+ __func__,
+ this_phy,
+ event_code);
+
+ result = SCI_FAILURE_INVALID_STATE;
+ break;
+ }
+
+ return result;
+}
+
+/* --------------------------------------------------------------------------- */
+
+/**
+ *
+ * @this_phy: This is the struct scic_sds_phy object which is receiving the event.
+ * @event_code: This is the event code to be processed.
+ *
+ * This is the resetting state event handler. enum sci_status
+ * SCI_FAILURE_INVALID_STATE
+ */
+static enum sci_status scic_sds_phy_resetting_state_event_handler(
+ struct scic_sds_phy *this_phy,
+ u32 event_code)
+{
+ enum sci_status result = SCI_FAILURE;
+
+ switch (scu_get_event_code(event_code)) {
+ case SCU_EVENT_HARD_RESET_TRANSMITTED:
+ /* Link failure change state back to the starting state */
+ sci_base_state_machine_change_state(
+ scic_sds_phy_get_base_state_machine(this_phy),
+ SCI_BASE_PHY_STATE_STARTING
+ );
+
+ result = SCI_SUCCESS;
+ break;
+
+ default:
+ dev_warn(sciphy_to_dev(this_phy),
+ "%s: SCIC PHY 0x%p resetting state machine received "
+ "unexpected event_code %x\n",
+ __func__,
+ this_phy,
+ event_code);
+
+ result = SCI_FAILURE_INVALID_STATE;
+ break;
+ }
+
+ return result;
+}
+
+/* --------------------------------------------------------------------------- */
+
+struct scic_sds_phy_state_handler
+scic_sds_phy_state_handler_table[SCI_BASE_PHY_MAX_STATES] =
+{
+ /* SCI_BASE_PHY_STATE_INITIAL */
+ {
+ {
+ scic_sds_phy_default_start_handler,
+ scic_sds_phy_default_stop_handler,
+ scic_sds_phy_default_reset_handler,
+ scic_sds_phy_default_destroy_handler
+ },
+ scic_sds_phy_default_frame_handler,
+ scic_sds_phy_default_event_handler,
+ scic_sds_phy_default_consume_power_handler
+ },
+ /* SCI_BASE_PHY_STATE_STOPPED */
+ {
+ {
+ scic_sds_phy_stopped_state_start_handler,
+ scic_sds_phy_default_stop_handler,
+ scic_sds_phy_default_reset_handler,
+ scic_sds_phy_stopped_state_destroy_handler
+ },
+ scic_sds_phy_default_frame_handler,
+ scic_sds_phy_default_event_handler,
+ scic_sds_phy_default_consume_power_handler
+ },
+ /* SCI_BASE_PHY_STATE_STARTING */
+ {
+ {
+ scic_sds_phy_default_start_handler,
+ scic_sds_phy_default_stop_handler,
+ scic_sds_phy_default_reset_handler,
+ scic_sds_phy_default_destroy_handler
+ },
+ scic_sds_phy_default_frame_handler,
+ scic_sds_phy_default_event_handler,
+ scic_sds_phy_default_consume_power_handler
+ },
+ /* SCI_BASE_PHY_STATE_READY */
+ {
+ {
+ scic_sds_phy_default_start_handler,
+ scic_sds_phy_ready_state_stop_handler,
+ scic_sds_phy_ready_state_reset_handler,
+ scic_sds_phy_default_destroy_handler
+ },
+ scic_sds_phy_default_frame_handler,
+ scic_sds_phy_ready_state_event_handler,
+ scic_sds_phy_default_consume_power_handler
+ },
+ /* SCI_BASE_PHY_STATE_RESETTING */
+ {
+ {
+ scic_sds_phy_default_start_handler,
+ scic_sds_phy_default_stop_handler,
+ scic_sds_phy_default_reset_handler,
+ scic_sds_phy_default_destroy_handler
+ },
+ scic_sds_phy_default_frame_handler,
+ scic_sds_phy_resetting_state_event_handler,
+ scic_sds_phy_default_consume_power_handler
+ },
+ /* SCI_BASE_PHY_STATE_FINAL */
+ {
+ {
+ scic_sds_phy_default_start_handler,
+ scic_sds_phy_default_stop_handler,
+ scic_sds_phy_default_reset_handler,
+ scic_sds_phy_default_destroy_handler
+ },
+ scic_sds_phy_default_frame_handler,
+ scic_sds_phy_default_event_handler,
+ scic_sds_phy_default_consume_power_handler
+ }
+};
+
+/*
+ * ****************************************************************************
+ * * PHY STATE PRIVATE METHODS
+ * **************************************************************************** */
+
+/**
+ *
+ * @this_phy: This is the struct scic_sds_phy object to stop.
+ *
+ * This method will stop the struct scic_sds_phy object. This does not reset the
+ * protocol engine it just suspends it and places it in a state where it will
+ * not cause the end device to power up. none
+ */
+static void scu_link_layer_stop_protocol_engine(
+ struct scic_sds_phy *this_phy)
+{
+ u32 scu_sas_pcfg_value;
+ u32 enable_spinup_value;
+
+ /* Suspend the protocol engine and place it in a sata spinup hold state */
+ scu_sas_pcfg_value = SCU_SAS_PCFG_READ(this_phy);
+ scu_sas_pcfg_value |= (
+ SCU_SAS_PCFG_GEN_BIT(OOB_RESET)
+ | SCU_SAS_PCFG_GEN_BIT(SUSPEND_PROTOCOL_ENGINE)
+ | SCU_SAS_PCFG_GEN_BIT(SATA_SPINUP_HOLD)
+ );
+ SCU_SAS_PCFG_WRITE(this_phy, scu_sas_pcfg_value);
+
+ /* Disable the notify enable spinup primitives */
+ enable_spinup_value = SCU_SAS_ENSPINUP_READ(this_phy);
+ enable_spinup_value &= ~SCU_ENSPINUP_GEN_BIT(ENABLE);
+ SCU_SAS_ENSPINUP_WRITE(this_phy, enable_spinup_value);
+}
+
+/**
+ *
+ *
+ * This method will start the OOB/SN state machine for this struct scic_sds_phy object.
+ */
+static void scu_link_layer_start_oob(
+ struct scic_sds_phy *this_phy)
+{
+ u32 scu_sas_pcfg_value;
+
+ scu_sas_pcfg_value = SCU_SAS_PCFG_READ(this_phy);
+ scu_sas_pcfg_value |= SCU_SAS_PCFG_GEN_BIT(OOB_ENABLE);
+ scu_sas_pcfg_value &=
+ ~(SCU_SAS_PCFG_GEN_BIT(OOB_RESET) | SCU_SAS_PCFG_GEN_BIT(HARD_RESET));
+
+ SCU_SAS_PCFG_WRITE(this_phy, scu_sas_pcfg_value);
+}
+
+/**
+ *
+ *
+ * This method will transmit a hard reset request on the specified phy. The SCU
+ * hardware requires that we reset the OOB state machine and set the hard reset
+ * bit in the phy configuration register. We then must start OOB over with the
+ * hard reset bit set.
+ */
+static void scu_link_layer_tx_hard_reset(
+ struct scic_sds_phy *this_phy)
+{
+ u32 phy_configuration_value;
+
+ /*
+ * SAS Phys must wait for the HARD_RESET_TX event notification to transition
+ * to the starting state. */
+ phy_configuration_value = SCU_SAS_PCFG_READ(this_phy);
+ phy_configuration_value |=
+ (SCU_SAS_PCFG_GEN_BIT(HARD_RESET) | SCU_SAS_PCFG_GEN_BIT(OOB_RESET));
+ SCU_SAS_PCFG_WRITE(this_phy, phy_configuration_value);
+
+ /* Now take the OOB state machine out of reset */
+ phy_configuration_value |= SCU_SAS_PCFG_GEN_BIT(OOB_ENABLE);
+ phy_configuration_value &= ~SCU_SAS_PCFG_GEN_BIT(OOB_RESET);
+ SCU_SAS_PCFG_WRITE(this_phy, phy_configuration_value);
+}
+
+/*
+ * ****************************************************************************
+ * * PHY BASE STATE METHODS
+ * **************************************************************************** */
+
+/**
+ *
+ * @object: This is the struct sci_base_object which is cast to a struct scic_sds_phy object.
+ *
+ * This method will perform the actions required by the struct scic_sds_phy on
+ * entering the SCI_BASE_PHY_STATE_INITIAL. - This function sets the state
+ * handlers for the phy object base state machine initial state. none
+ */
+static void scic_sds_phy_initial_state_enter(
+ struct sci_base_object *object)
+{
+ struct scic_sds_phy *this_phy;
+
+ this_phy = (struct scic_sds_phy *)object;
+
+ scic_sds_phy_set_base_state_handlers(this_phy, SCI_BASE_PHY_STATE_STOPPED);
+}
+
+/**
+ *
+ * @object: This is the struct sci_base_object which is cast to a struct scic_sds_phy object.
+ *
+ * This method will perform the actions required by the struct scic_sds_phy on
+ * entering the SCI_BASE_PHY_STATE_INITIAL. - This function sets the state
+ * handlers for the phy object base state machine initial state. - The SCU
+ * hardware is requested to stop the protocol engine. none
+ */
+static void scic_sds_phy_stopped_state_enter(
+ struct sci_base_object *object)
+{
+ struct scic_sds_phy *this_phy;
+
+ this_phy = (struct scic_sds_phy *)object;
+
+ /* / @todo We need to get to the controller to place this PE in a reset state */
+
+ scic_sds_phy_set_base_state_handlers(this_phy, SCI_BASE_PHY_STATE_STOPPED);
+
+ scu_link_layer_stop_protocol_engine(this_phy);
+}
+
+/**
+ *
+ * @object: This is the struct sci_base_object which is cast to a struct scic_sds_phy object.
+ *
+ * This method will perform the actions required by the struct scic_sds_phy on
+ * entering the SCI_BASE_PHY_STATE_STARTING. - This function sets the state
+ * handlers for the phy object base state machine starting state. - The SCU
+ * hardware is requested to start OOB/SN on this protocl engine. - The phy
+ * starting substate machine is started. - If the previous state was the ready
+ * state then the struct scic_sds_controller is informed that the phy has gone link
+ * down. none
+ */
+static void scic_sds_phy_starting_state_enter(
+ struct sci_base_object *object)
+{
+ struct scic_sds_phy *this_phy;
+
+ this_phy = (struct scic_sds_phy *)object;
+
+ scic_sds_phy_set_base_state_handlers(this_phy, SCI_BASE_PHY_STATE_STARTING);
+
+ scu_link_layer_stop_protocol_engine(this_phy);
+ scu_link_layer_start_oob(this_phy);
+
+ /* We don't know what kind of phy we are going to be just yet */
+ this_phy->protocol = SCIC_SDS_PHY_PROTOCOL_UNKNOWN;
+ this_phy->bcn_received_while_port_unassigned = false;
+
+ /* Change over to the starting substate machine to continue */
+ sci_base_state_machine_start(&this_phy->starting_substate_machine);
+
+ if (this_phy->parent.state_machine.previous_state_id
+ == SCI_BASE_PHY_STATE_READY) {
+ scic_sds_controller_link_down(
+ scic_sds_phy_get_controller(this_phy),
+ scic_sds_phy_get_port(this_phy),
+ this_phy
+ );
+ }
+}
+
+/**
+ *
+ * @object: This is the struct sci_base_object which is cast to a struct scic_sds_phy object.
+ *
+ * This method will perform the actions required by the struct scic_sds_phy on
+ * entering the SCI_BASE_PHY_STATE_READY. - This function sets the state
+ * handlers for the phy object base state machine ready state. - The SCU
+ * hardware protocol engine is resumed. - The struct scic_sds_controller is informed
+ * that the phy object has gone link up. none
+ */
+static void scic_sds_phy_ready_state_enter(
+ struct sci_base_object *object)
+{
+ struct scic_sds_phy *this_phy;
+
+ this_phy = (struct scic_sds_phy *)object;
+
+ scic_sds_phy_set_base_state_handlers(this_phy, SCI_BASE_PHY_STATE_READY);
+
+ scic_sds_controller_link_up(
+ scic_sds_phy_get_controller(this_phy),
+ scic_sds_phy_get_port(this_phy),
+ this_phy
+ );
+}
+
+/**
+ *
+ * @object: This is the struct sci_base_object which is cast to a struct scic_sds_phy object.
+ *
+ * This method will perform the actions required by the struct scic_sds_phy on exiting
+ * the SCI_BASE_PHY_STATE_INITIAL. This function suspends the SCU hardware
+ * protocol engine represented by this struct scic_sds_phy object. none
+ */
+static void scic_sds_phy_ready_state_exit(
+ struct sci_base_object *object)
+{
+ struct scic_sds_phy *this_phy;
+
+ this_phy = (struct scic_sds_phy *)object;
+
+ scic_sds_phy_suspend(this_phy);
+}
+
+/**
+ *
+ * @object: This is the struct sci_base_object which is cast to a struct scic_sds_phy object.
+ *
+ * This method will perform the actions required by the struct scic_sds_phy on
+ * entering the SCI_BASE_PHY_STATE_RESETTING. - This function sets the state
+ * handlers for the phy object base state machine resetting state. none
+ */
+static void scic_sds_phy_resetting_state_enter(
+ struct sci_base_object *object)
+{
+ struct scic_sds_phy *this_phy;
+
+ this_phy = (struct scic_sds_phy *)object;
+
+ scic_sds_phy_set_base_state_handlers(this_phy, SCI_BASE_PHY_STATE_RESETTING);
+
+ /*
+ * The phy is being reset, therefore deactivate it from the port.
+ * In the resetting state we don't notify the user regarding
+ * link up and link down notifications. */
+ scic_sds_port_deactivate_phy(this_phy->owning_port, this_phy, false);
+
+ if (this_phy->protocol == SCIC_SDS_PHY_PROTOCOL_SAS) {
+ scu_link_layer_tx_hard_reset(this_phy);
+ } else {
+ /*
+ * The SCU does not need to have a descrete reset state so just go back to
+ * the starting state. */
+ sci_base_state_machine_change_state(
+ &this_phy->parent.state_machine,
+ SCI_BASE_PHY_STATE_STARTING
+ );
+ }
+}
+
+/**
+ *
+ * @object: This is the struct sci_base_object which is cast to a struct scic_sds_phy object.
+ *
+ * This method will perform the actions required by the struct scic_sds_phy on
+ * entering the SCI_BASE_PHY_STATE_FINAL. - This function sets the state
+ * handlers for the phy object base state machine final state. none
+ */
+static void scic_sds_phy_final_state_enter(
+ struct sci_base_object *object)
+{
+ struct scic_sds_phy *this_phy;
+
+ this_phy = (struct scic_sds_phy *)object;
+
+ scic_sds_phy_set_base_state_handlers(this_phy, SCI_BASE_PHY_STATE_FINAL);
+
+ /* Nothing to do here */
+}
+
+/* --------------------------------------------------------------------------- */
+
+const struct sci_base_state scic_sds_phy_state_table[] = {
+ [SCI_BASE_PHY_STATE_INITIAL] = {
+ .enter_state = scic_sds_phy_initial_state_enter,
+ },
+ [SCI_BASE_PHY_STATE_STOPPED] = {
+ .enter_state = scic_sds_phy_stopped_state_enter,
+ },
+ [SCI_BASE_PHY_STATE_STARTING] = {
+ .enter_state = scic_sds_phy_starting_state_enter,
+ },
+ [SCI_BASE_PHY_STATE_READY] = {
+ .enter_state = scic_sds_phy_ready_state_enter,
+ .exit_state = scic_sds_phy_ready_state_exit,
+ },
+ [SCI_BASE_PHY_STATE_RESETTING] = {
+ .enter_state = scic_sds_phy_resetting_state_enter,
+ },
+ [SCI_BASE_PHY_STATE_FINAL] = {
+ .enter_state = scic_sds_phy_final_state_enter,
+ },
+};
+
diff --git a/drivers/scsi/isci/core/scic_sds_phy.h b/drivers/scsi/isci/core/scic_sds_phy.h
new file mode 100644
index 000000000000..d9691b30e457
--- /dev/null
+++ b/drivers/scsi/isci/core/scic_sds_phy.h
@@ -0,0 +1,491 @@
+/*
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Intel Corporation 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
+ * OWNER 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.
+ */
+
+#ifndef _SCIC_SDS_PHY_H_
+#define _SCIC_SDS_PHY_H_
+
+/**
+ * This file contains the structures, constants and prototypes for the
+ * struct scic_sds_phy object.
+ *
+ *
+ */
+
+#include "intel_sata.h"
+#include "intel_sas.h"
+#include "sci_base_phy.h"
+#include "scu_registers.h"
+
+struct scic_sds_port;
+/**
+ *
+ *
+ * This is the timeout value for the SATA phy to wait for a SIGNATURE FIS
+ * before restarting the starting state machine. Technically, the old parallel
+ * ATA specification required up to 30 seconds for a device to issue its
+ * signature FIS as a result of a soft reset. Now we see that devices respond
+ * generally within 15 seconds, but we'll use 25 for now.
+ */
+#define SCIC_SDS_SIGNATURE_FIS_TIMEOUT 25000
+
+/**
+ *
+ *
+ * This is the timeout for the SATA OOB/SN because the hardware does not
+ * recognize a hot plug after OOB signal but before the SN signals. We need to
+ * make sure after a hotplug timeout if we have not received the speed event
+ * notification from the hardware that we restart the hardware OOB state
+ * machine.
+ */
+#define SCIC_SDS_SATA_LINK_TRAINING_TIMEOUT 250
+
+/**
+ * enum SCIC_SDS_PHY_STARTING_SUBSTATES -
+ *
+ *
+ */
+enum SCIC_SDS_PHY_STARTING_SUBSTATES {
+ /**
+ * Initial state
+ */
+ SCIC_SDS_PHY_STARTING_SUBSTATE_INITIAL,
+
+ /**
+ * Wait state for the hardware OSSP event type notification
+ */
+ SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_OSSP_EN,
+
+ /**
+ * Wait state for the PHY speed notification
+ */
+ SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_SAS_SPEED_EN,
+
+ /**
+ * Wait state for the IAF Unsolicited frame notification
+ */
+ SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_IAF_UF,
+
+ /**
+ * Wait state for the request to consume power
+ */
+ SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_SAS_POWER,
+
+ /**
+ * Wait state for request to consume power
+ */
+ SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_SATA_POWER,
+
+ /**
+ * Wait state for the SATA PHY notification
+ */
+ SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_SATA_PHY_EN,
+
+ /**
+ * Wait for the SATA PHY speed notification
+ */
+ SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_SATA_SPEED_EN,
+
+ /**
+ * Wait state for the SIGNATURE FIS unsolicited frame notification
+ */
+ SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_SIG_FIS_UF,
+
+ /**
+ * Exit state for this state machine
+ */
+ SCIC_SDS_PHY_STARTING_SUBSTATE_FINAL,
+
+ /**
+ * Maximum number of substates for the STARTING state machine
+ */
+ SCIC_SDS_PHY_STARTING_MAX_SUBSTATES
+};
+
+struct scic_sds_port;
+struct scic_sds_controller;
+
+#ifdef SCIC_DEBUG_ENABLED
+#define MAX_STATE_TRANSITION_RECORD (256)
+
+/**
+ *
+ *
+ * Debug code to record the state transitions for the phy object
+ */
+struct scic_sds_phy_state_record {
+ struct sci_base_observer base_state_observer;
+ struct sci_base_observer starting_state_observer;
+
+ u16 index;
+
+ u32 state_transition_table[MAX_STATE_TRANSITION_RECORD];
+
+};
+#endif /* SCIC_DEBUG_ENABLED */
+
+/**
+ * This enumeration provides a named phy type for the state machine
+ *
+ *
+ */
+enum SCIC_SDS_PHY_PROTOCOL {
+ /**
+ * This is an unknown phy type since there is either nothing on the other
+ * end or we have not detected the phy type as yet.
+ */
+ SCIC_SDS_PHY_PROTOCOL_UNKNOWN,
+
+ /**
+ * This is a SAS PHY
+ */
+ SCIC_SDS_PHY_PROTOCOL_SAS,
+
+ /**
+ * This is a SATA PHY
+ */
+ SCIC_SDS_PHY_PROTOCOL_SATA,
+
+ SCIC_SDS_MAX_PHY_PROTOCOLS
+};
+
+/**
+ * struct scic_sds_phy - This structure contains or references all of the data
+ * necessary to represent the core phy object and SCU harware protocol
+ * engine.
+ *
+ *
+ */
+struct scic_sds_phy {
+ struct sci_base_phy parent;
+
+ /**
+ * This field specifies the port object that owns/contains this phy.
+ */
+ struct scic_sds_port *owning_port;
+
+ /**
+ * This field indicates whether the phy supports 1.5 Gb/s, 3.0 Gb/s,
+ * or 6.0 Gb/s operation.
+ */
+ enum sci_sas_link_rate max_negotiated_speed;
+
+ /**
+ * This member specifies the protocol being utilized on this phy. This
+ * field contains a legitamite value once the PHY has link trained with
+ * a remote phy.
+ */
+ enum SCIC_SDS_PHY_PROTOCOL protocol;
+
+ /**
+ * This field specifies the index with which this phy is associated (0-3).
+ */
+ u8 phy_index;
+
+ /**
+ * This member indicates if this particular PHY has received a BCN while
+ * it had no port assignement. This BCN will be reported once the phy is
+ * assigned to a port.
+ */
+ bool bcn_received_while_port_unassigned;
+
+ /**
+ * This field indicates if this PHY is currently in the process of
+ * link training (i.e. it has started OOB, but has yet to perform
+ * IAF exchange/Signature FIS reception).
+ */
+ bool is_in_link_training;
+
+ union {
+ struct {
+ struct sci_sas_identify_address_frame identify_address_frame_buffer;
+
+ } sas;
+
+ struct {
+ struct sata_fis_reg_d2h signature_fis_buffer;
+
+ } sata;
+
+ } phy_type;
+
+ /**
+ * This field contains a reference to the timer utilized in detecting
+ * when a signature FIS timeout has occurred. The signature FIS is the
+ * first FIS sent by an attached SATA device after OOB/SN.
+ */
+ void *sata_timeout_timer;
+
+ struct scic_sds_phy_state_handler *state_handlers;
+
+ struct sci_base_state_machine starting_substate_machine;
+
+ #ifdef SCIC_DEBUG_ENABLED
+ struct scic_sds_phy_state_record state_record;
+ #endif /* SCIC_DEBUG_ENABLED */
+
+ /**
+ * This field points to the link layer register set within the SCU.
+ */
+ struct scu_link_layer_registers *link_layer_registers;
+
+};
+
+
+typedef enum sci_status (*SCIC_SDS_PHY_EVENT_HANDLER_T)(struct scic_sds_phy *, u32);
+typedef enum sci_status (*SCIC_SDS_PHY_FRAME_HANDLER_T)(struct scic_sds_phy *, u32);
+typedef enum sci_status (*SCIC_SDS_PHY_POWER_HANDLER_T)(struct scic_sds_phy *);
+
+/**
+ * struct scic_sds_phy_state_handler -
+ *
+ *
+ */
+struct scic_sds_phy_state_handler {
+ /**
+ * This is the struct sci_base_phy object state handlers.
+ */
+ struct sci_base_phy_state_handler parent;
+
+ /**
+ * The state handler for unsolicited frames received from the SCU hardware.
+ */
+ SCIC_SDS_PHY_FRAME_HANDLER_T frame_handler;
+
+ /**
+ * The state handler for events received from the SCU hardware.
+ */
+ SCIC_SDS_PHY_EVENT_HANDLER_T event_handler;
+
+ /**
+ * The state handler for staggered spinup.
+ */
+ SCIC_SDS_PHY_POWER_HANDLER_T consume_power_handler;
+
+};
+
+extern struct scic_sds_phy_state_handler scic_sds_phy_state_handler_table[];
+extern const struct sci_base_state scic_sds_phy_state_table[];
+extern const struct sci_base_state scic_sds_phy_starting_substates[];
+extern struct scic_sds_phy_state_handler
+ scic_sds_phy_starting_substate_handler_table[];
+
+
+/**
+ * scic_sds_phy_get_index() -
+ *
+ * This macro returns the phy index for the specified phy
+ */
+#define scic_sds_phy_get_index(phy) \
+ ((phy)->phy_index)
+
+/**
+ * scic_sds_phy_get_controller() - This macro returns the controller for this
+ * phy
+ *
+ *
+ */
+#define scic_sds_phy_get_controller(phy) \
+ (scic_sds_port_get_controller((phy)->owning_port))
+
+/**
+ * scic_sds_phy_get_base_state_machine() - This macro returns the state machine
+ * for the base phy
+ *
+ *
+ */
+#define scic_sds_phy_get_base_state_machine(phy) \
+ (&(phy)->parent.state_machine)
+
+/**
+ * scic_sds_phy_get_starting_substate_machine() - This macro returns the
+ * starting substate machine for this phy
+ *
+ *
+ */
+#define scic_sds_phy_get_starting_substate_machine(phy) \
+ (&(phy)->starting_substate_machine)
+
+/**
+ * scic_sds_phy_set_state_handlers() - This macro sets the state handlers for
+ * this phy object
+ *
+ *
+ */
+#define scic_sds_phy_set_state_handlers(phy, handlers) \
+ ((phy)->state_handlers = (handlers))
+
+/**
+ * scic_sds_phy_set_base_state_handlers() -
+ *
+ * This macro set the base state handlers for the phy object.
+ */
+#define scic_sds_phy_set_base_state_handlers(phy, state_id) \
+ scic_sds_phy_set_state_handlers(\
+ (phy), \
+ &scic_sds_phy_state_handler_table[(state_id)] \
+ )
+
+/**
+ * scic_sds_phy_is_ready() -
+ *
+ * This macro returns true if the current base state for this phy is
+ * SCI_BASE_PHY_STATE_READY
+ */
+#define scic_sds_phy_is_ready(phy) \
+ (\
+ SCI_BASE_PHY_STATE_READY \
+ == sci_base_state_machine_get_state(\
+ scic_sds_phy_get_base_state_machine(phy) \
+ ) \
+ )
+
+/* --------------------------------------------------------------------------- */
+
+
+
+
+/* --------------------------------------------------------------------------- */
+
+void scic_sds_phy_construct(
+ struct scic_sds_phy *this_phy,
+ struct scic_sds_port *owning_port,
+ u8 phy_index);
+
+struct scic_sds_port *scic_sds_phy_get_port(
+ struct scic_sds_phy *this_phy);
+
+void scic_sds_phy_set_port(
+ struct scic_sds_phy *this_phy,
+ struct scic_sds_port *owning_port);
+
+enum sci_status scic_sds_phy_initialize(
+ struct scic_sds_phy *this_phy,
+ struct scu_link_layer_registers *link_layer_registers);
+
+enum sci_status scic_sds_phy_start(
+ struct scic_sds_phy *this_phy);
+
+enum sci_status scic_sds_phy_stop(
+ struct scic_sds_phy *this_phy);
+
+enum sci_status scic_sds_phy_reset(
+ struct scic_sds_phy *this_phy);
+
+/* --------------------------------------------------------------------------- */
+
+void scic_sds_phy_suspend(
+ struct scic_sds_phy *this_phy);
+
+void scic_sds_phy_resume(
+ struct scic_sds_phy *this_phy);
+
+/* --------------------------------------------------------------------------- */
+
+enum sci_status scic_sds_phy_event_handler(
+ struct scic_sds_phy *this_phy,
+ u32 event_code);
+
+enum sci_status scic_sds_phy_frame_handler(
+ struct scic_sds_phy *this_phy,
+ u32 frame_index);
+
+enum sci_status scic_sds_phy_consume_power_handler(
+ struct scic_sds_phy *this_phy);
+
+void scic_sds_phy_get_sas_address(
+ struct scic_sds_phy *this_phy,
+ struct sci_sas_address *sas_address);
+
+void scic_sds_phy_get_attached_sas_address(
+ struct scic_sds_phy *this_phy,
+ struct sci_sas_address *sas_address);
+
+void scic_sds_phy_get_protocols(
+ struct scic_sds_phy *this_phy,
+ struct sci_sas_identify_address_frame_protocols *protocols);
+
+void scic_sds_phy_get_attached_phy_protocols(
+ struct scic_sds_phy *this_phy,
+ struct sci_sas_identify_address_frame_protocols *protocols);
+
+/*
+ * ****************************************************************************-
+ * * SCIC SDS PHY Handler Methods
+ * ****************************************************************************- */
+
+enum sci_status scic_sds_phy_default_start_handler(
+ struct sci_base_phy *phy);
+
+enum sci_status scic_sds_phy_default_stop_handler(
+ struct sci_base_phy *phy);
+
+enum sci_status scic_sds_phy_default_reset_handler(
+ struct sci_base_phy *phy);
+
+enum sci_status scic_sds_phy_default_destroy_handler(
+ struct sci_base_phy *phy);
+
+enum sci_status scic_sds_phy_default_frame_handler(
+ struct scic_sds_phy *phy,
+ u32 frame_index);
+
+enum sci_status scic_sds_phy_default_event_handler(
+ struct scic_sds_phy *phy,
+ u32 evnet_code);
+
+enum sci_status scic_sds_phy_default_consume_power_handler(
+ struct scic_sds_phy *phy);
+
+#endif /* _SCIC_SDS_PHY_H_ */
diff --git a/drivers/scsi/isci/core/scic_sds_phy_registers.h b/drivers/scsi/isci/core/scic_sds_phy_registers.h
new file mode 100644
index 000000000000..7883819035da
--- /dev/null
+++ b/drivers/scsi/isci/core/scic_sds_phy_registers.h
@@ -0,0 +1,187 @@
+/*
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Intel Corporation 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
+ * OWNER 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.
+ */
+
+#ifndef _SCIC_SDS_PHY_REGISTERS_H_
+#define _SCIC_SDS_PHY_REGISTERS_H_
+
+/**
+ * This file contains the macros used by the phy object to read/write to the
+ * SCU link layer registers.
+ *
+ *
+ */
+
+#include "scic_sds_controller.h"
+
+/*
+ * *****************************************************************************
+ * * SCU LINK LAYER REGISTER OPERATIONS
+ * ***************************************************************************** */
+
+/**
+ * scu_link_layer_register_read() -
+ *
+ * THis macro requests the SCU register write for the specified link layer
+ * register.
+ */
+#define scu_link_layer_register_read(phy, reg) \
+ scu_register_read(\
+ scic_sds_phy_get_controller(phy), \
+ (phy)->link_layer_registers->reg \
+ )
+
+/**
+ * scu_link_layer_register_write() -
+ *
+ * This macro requests the SCU register read for the specified link layer
+ * register.
+ */
+#define scu_link_layer_register_write(phy, reg, value) \
+ scu_register_write(\
+ scic_sds_phy_get_controller(phy), \
+ (phy)->link_layer_registers->reg, \
+ (value) \
+ )
+
+/*
+ * *****************************************************************************
+ * * SCU LINK LAYER REGISTERS
+ * ***************************************************************************** */
+
+/* / This macro reads from the SAS Identify Frame PHY Identifier register */
+#define SCU_SAS_TIPID_READ(phy) \
+ scu_link_layer_register_read(phy, identify_frame_phy_id)
+
+/* / This macro writes to the SAS Identify Frame PHY Identifier register */
+#define SCU_SAS_TIPID_WRITE(phy, value) \
+ scu_link_layer_register_write(phy, identify_frame_phy_id, value)
+
+/* / This macro reads from the SAS Identification register */
+#define SCU_SAS_TIID_READ(phy) \
+ scu_link_layer_register_read(phy, transmit_identification)
+
+/* / This macro writes to the SAS Identification register */
+#define SCU_SAS_TIID_WRITE(phy, value) \
+ scu_link_layer_register_write(phy, transmit_identification, value)
+
+/* / This macro reads the SAS Device Name High register */
+#define SCU_SAS_TIDNH_READ(phy) \
+ scu_link_layer_register_read(phy, sas_device_name_high)
+
+/* / This macro writes the SAS Device Name High register */
+#define SCU_SAS_TIDNH_WRITE(phy, value) \
+ scu_link_layer_register_write(phy, sas_device_name_high, value)
+
+/* / This macro reads the SAS Device Name Low register */
+#define SCU_SAS_TIDNL_READ(phy) \
+ scu_link_layer_register_read(phy, sas_device_name_low)
+
+/* / This macro writes the SAS Device Name Low register */
+#define SCU_SAS_TIDNL_WRITE(phy, value) \
+ scu_link_layer_register_write(phy, sas_device_name_low, value)
+
+/* / This macro reads the Source SAS Address High register */
+#define SCU_SAS_TISSAH_READ(phy) \
+ scu_link_layer_register_read(phy, source_sas_address_high)
+
+/* / This macro writes the Source SAS Address High register */
+#define SCU_SAS_TISSAH_WRITE(phy, value) \
+ scu_link_layer_register_write(phy, source_sas_address_high, value)
+
+/* / This macro reads the Source SAS Address Low register */
+#define SCU_SAS_TISSAL_READ(phy) \
+ scu_link_layer_register_read(phy, source_sas_address_low)
+
+/* / This macro writes the Source SAS Address Low register */
+#define SCU_SAS_TISSAL_WRITE(phy, value) \
+ scu_link_layer_register_write(phy, source_sas_address_low, value)
+
+/* / This macro reads the PHY Configuration register */
+#define SCU_SAS_PCFG_READ(phy) \
+ scu_link_layer_register_read(phy, phy_configuration);
+
+/* / This macro writes the PHY Configuration register */
+#define SCU_SAS_PCFG_WRITE(phy, value) \
+ scu_link_layer_register_write(phy, phy_configuration, value)
+
+/* / This macro reads the PHY Enable Spinup register */
+#define SCU_SAS_ENSPINUP_READ(phy) \
+ scu_link_layer_register_read(phy, notify_enable_spinup_control)
+
+/* / This macro writes the PHY Enable Spinup register */
+#define SCU_SAS_ENSPINUP_WRITE(phy, value) \
+ scu_link_layer_register_write(phy, notify_enable_spinup_control, value)
+
+/* / This macro reads the PHY Capacity register */
+#define SCU_SAS_PHYCAP_READ(phy) \
+ scu_link_layer_register_read(phy, phy_capabilities)
+
+/* / This macro writes the PHY Capacity register */
+#define SCU_SAS_PHYCAP_WRITE(phy, value) \
+ scu_link_layer_register_write(phy, phy_capabilities, value)
+
+/* / This macro reads the Recieved PHY Capacity register */
+#define SCU_SAS_RECPHYCAP_READ(phy) \
+ scu_link_layer_register_read(phy, receive_phycap)
+
+/* / This macro reads the link layer control register */
+#define SCU_SAS_LLCTL_READ(phy) \
+ scu_link_layer_register_read(phy, link_layer_control);
+
+/* / This macro writes the link layer control register */
+#define SCU_SAS_LLCTL_WRITE(phy, value) \
+ scu_link_layer_register_write(phy, link_layer_control, value);
+
+#endif /* _SCIC_SDS_PHY_REGISTERS_H_ */
diff --git a/drivers/scsi/isci/core/scic_sds_port.c b/drivers/scsi/isci/core/scic_sds_port.c
new file mode 100644
index 000000000000..1af38505840c
--- /dev/null
+++ b/drivers/scsi/isci/core/scic_sds_port.c
@@ -0,0 +1,2757 @@
+/*
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Intel Corporation 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
+ * OWNER 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.
+ */
+
+#include "intel_sas.h"
+#include "sci_base_port.h"
+#include "scic_controller.h"
+#include "scic_phy.h"
+#include "scic_port.h"
+#include "scic_sds_controller.h"
+#include "scic_sds_phy.h"
+#include "scic_sds_phy_registers.h"
+#include "scic_sds_port.h"
+#include "scic_sds_port_registers.h"
+#include "scic_sds_remote_device.h"
+#include "scic_sds_remote_node_context.h"
+#include "scic_sds_request.h"
+#include "scic_user_callback.h"
+#include "sci_environment.h"
+
+
+static void scic_sds_port_invalid_link_up(
+ struct scic_sds_port *this_port,
+ struct scic_sds_phy *phy);
+static void scic_sds_port_timeout_handler(
+ void *port);
+#define SCIC_SDS_PORT_MIN_TIMER_COUNT (SCI_MAX_PORTS)
+#define SCIC_SDS_PORT_MAX_TIMER_COUNT (SCI_MAX_PORTS)
+
+#define SCIC_SDS_PORT_HARD_RESET_TIMEOUT (1000)
+
+void sci_base_port_construct(
+ struct sci_base_port *base_port,
+ const struct sci_base_state *state_table)
+{
+ base_port->parent.private = NULL;
+ sci_base_state_machine_construct(
+ &base_port->state_machine,
+ &base_port->parent,
+ state_table,
+ SCI_BASE_PORT_STATE_STOPPED
+ );
+
+ sci_base_state_machine_start(
+ &base_port->state_machine
+ );
+}
+
+/**
+ *
+ * @this_port: This is the port object to which the phy is being assigned.
+ * @phy_index: This is the phy index that is being assigned to the port.
+ *
+ * This method will return a true value if the specified phy can be assigned to
+ * this port The following is a list of phys for each port that are allowed: -
+ * Port 0 - 3 2 1 0 - Port 1 - 1 - Port 2 - 3 2 - Port 3 - 3 This method
+ * doesn't preclude all configurations. It merely ensures that a phy is part
+ * of the allowable set of phy identifiers for that port. For example, one
+ * could assign phy 3 to port 0 and no other phys. Please refer to
+ * scic_sds_port_is_phy_mask_valid() for information regarding whether the
+ * phy_mask for a port can be supported. bool true if this is a valid phy
+ * assignment for the port false if this is not a valid phy assignment for the
+ * port
+ */
+bool scic_sds_port_is_valid_phy_assignment(
+ struct scic_sds_port *this_port,
+ u32 phy_index)
+{
+ /* Initialize to invalid value. */
+ u32 existing_phy_index = SCI_MAX_PHYS;
+ u32 index;
+
+ if ((this_port->physical_port_index == 1) && (phy_index != 1)) {
+ return false;
+ }
+
+ if (this_port->physical_port_index == 3 && phy_index != 3) {
+ return false;
+ }
+
+ if (
+ (this_port->physical_port_index == 2)
+ && ((phy_index == 0) || (phy_index == 1))
+ ) {
+ return false;
+ }
+
+ for (index = 0; index < SCI_MAX_PHYS; index++) {
+ if ((this_port->phy_table[index] != NULL)
+ && (index != phy_index)) {
+ existing_phy_index = index;
+ }
+ }
+
+ /*
+ * Ensure that all of the phys in the port are capable of
+ * operating at the same maximum link rate. */
+ if (
+ (existing_phy_index < SCI_MAX_PHYS)
+ && (this_port->owning_controller->user_parameters.sds1.phys[
+ phy_index].max_speed_generation !=
+ this_port->owning_controller->user_parameters.sds1.phys[
+ existing_phy_index].max_speed_generation)
+ )
+ return false;
+
+ return true;
+}
+
+/**
+ * This method requests a list (mask) of the phys contained in the supplied SAS
+ * port.
+ * @this_port: a handle corresponding to the SAS port for which to return the
+ * phy mask.
+ *
+ * Return a bit mask indicating which phys are a part of this port. Each bit
+ * corresponds to a phy identifier (e.g. bit 0 = phy id 0).
+ */
+u32 scic_sds_port_get_phys(struct scic_sds_port *this_port)
+{
+ u32 index;
+ u32 mask;
+
+ mask = 0;
+
+ for (index = 0; index < SCI_MAX_PHYS; index++) {
+ if (this_port->phy_table[index] != NULL) {
+ mask |= (1 << index);
+ }
+ }
+
+ return mask;
+}
+
+/**
+ *
+ * @this_port: This is the port object for which to determine if the phy mask
+ * can be supported.
+ *
+ * This method will return a true value if the port's phy mask can be supported
+ * by the SCU. The following is a list of valid PHY mask configurations for
+ * each port: - Port 0 - [[3 2] 1] 0 - Port 1 - [1] - Port 2 - [[3] 2]
+ * - Port 3 - [3] This method returns a boolean indication specifying if the
+ * phy mask can be supported. true if this is a valid phy assignment for the
+ * port false if this is not a valid phy assignment for the port
+ */
+bool scic_sds_port_is_phy_mask_valid(
+ struct scic_sds_port *this_port,
+ u32 phy_mask)
+{
+ if (this_port->physical_port_index == 0) {
+ if (((phy_mask & 0x0F) == 0x0F)
+ || ((phy_mask & 0x03) == 0x03)
+ || ((phy_mask & 0x01) == 0x01)
+ || (phy_mask == 0))
+ return true;
+ } else if (this_port->physical_port_index == 1) {
+ if (((phy_mask & 0x02) == 0x02)
+ || (phy_mask == 0))
+ return true;
+ } else if (this_port->physical_port_index == 2) {
+ if (((phy_mask & 0x0C) == 0x0C)
+ || ((phy_mask & 0x04) == 0x04)
+ || (phy_mask == 0))
+ return true;
+ } else if (this_port->physical_port_index == 3) {
+ if (((phy_mask & 0x08) == 0x08)
+ || (phy_mask == 0))
+ return true;
+ }
+
+ return false;
+}
+
+/**
+ *
+ * @this_port: This parameter specifies the port from which to return a
+ * connected phy.
+ *
+ * This method retrieves a currently active (i.e. connected) phy contained in
+ * the port. Currently, the lowest order phy that is connected is returned.
+ * This method returns a pointer to a SCIS_SDS_PHY object. NULL This value is
+ * returned if there are no currently active (i.e. connected to a remote end
+ * point) phys contained in the port. All other values specify a struct scic_sds_phy
+ * object that is active in the port.
+ */
+static struct scic_sds_phy *scic_sds_port_get_a_connected_phy(
+ struct scic_sds_port *this_port
+ ) {
+ u32 index;
+ struct scic_sds_phy *phy;
+
+ for (index = 0; index < SCI_MAX_PHYS; index++) {
+ /*
+ * Ensure that the phy is both part of the port and currently
+ * connected to the remote end-point. */
+ phy = this_port->phy_table[index];
+ if (
+ (phy != NULL)
+ && scic_sds_port_active_phy(this_port, phy)
+ ) {
+ return phy;
+ }
+ }
+
+ return NULL;
+}
+
+/**
+ * scic_sds_port_set_phy() -
+ * @out]: port The port object to which the phy assignement is being made.
+ * @out]: phy The phy which is being assigned to the port.
+ *
+ * This method attempts to make the assignment of the phy to the port. If
+ * successful the phy is assigned to the ports phy table. bool true if the phy
+ * assignment can be made. false if the phy assignement can not be made. This
+ * is a functional test that only fails if the phy is currently assigned to a
+ * different port.
+ */
+enum sci_status scic_sds_port_set_phy(
+ struct scic_sds_port *port,
+ struct scic_sds_phy *phy)
+{
+ /*
+ * Check to see if we can add this phy to a port
+ * that means that the phy is not part of a port and that the port does
+ * not already have a phy assinged to the phy index. */
+ if (
+ (port->phy_table[phy->phy_index] == SCI_INVALID_HANDLE)
+ && (scic_sds_phy_get_port(phy) == SCI_INVALID_HANDLE)
+ && scic_sds_port_is_valid_phy_assignment(port, phy->phy_index)
+ ) {
+ /*
+ * Phy is being added in the stopped state so we are in MPC mode
+ * make logical port index = physical port index */
+ port->logical_port_index = port->physical_port_index;
+ port->phy_table[phy->phy_index] = phy;
+ scic_sds_phy_set_port(phy, port);
+
+ return SCI_SUCCESS;
+ }
+
+ return SCI_FAILURE;
+}
+
+/**
+ * scic_sds_port_clear_phy() -
+ * @out]: port The port from which the phy is being cleared.
+ * @out]: phy The phy being cleared from the port.
+ *
+ * This method will clear the phy assigned to this port. This method fails if
+ * this phy is not currently assinged to this port. bool true if the phy is
+ * removed from the port. false if this phy is not assined to this port.
+ */
+enum sci_status scic_sds_port_clear_phy(
+ struct scic_sds_port *port,
+ struct scic_sds_phy *phy)
+{
+ /* Make sure that this phy is part of this port */
+ if (
+ (port->phy_table[phy->phy_index] == phy)
+ && (scic_sds_phy_get_port(phy) == port)
+ ) {
+ /* Yep it is assigned to this port so remove it */
+ scic_sds_phy_set_port(
+ phy,
+ &scic_sds_port_get_controller(port)->port_table[SCI_MAX_PORTS]
+ );
+
+ port->phy_table[phy->phy_index] = SCI_INVALID_HANDLE;
+
+ return SCI_SUCCESS;
+ }
+
+ return SCI_FAILURE;
+}
+
+/**
+ * scic_sds_port_add_phy() -
+ * @this_port: This parameter specifies the port in which the phy will be added.
+ * @the_phy: This parameter is the phy which is to be added to the port.
+ *
+ * This method will add a PHY to the selected port. This method returns an
+ * enum sci_status. SCI_SUCCESS the phy has been added to the port. Any other status
+ * is failre to add the phy to the port.
+ */
+enum sci_status scic_sds_port_add_phy(
+ struct scic_sds_port *this_port,
+ struct scic_sds_phy *the_phy)
+{
+ return this_port->state_handlers->parent.add_phy_handler(
+ &this_port->parent, &the_phy->parent);
+}
+
+
+/**
+ * scic_sds_port_remove_phy() -
+ * @this_port: This parameter specifies the port in which the phy will be added.
+ * @the_phy: This parameter is the phy which is to be added to the port.
+ *
+ * This method will remove the PHY from the selected PORT. This method returns
+ * an enum sci_status. SCI_SUCCESS the phy has been removed from the port. Any other
+ * status is failre to add the phy to the port.
+ */
+enum sci_status scic_sds_port_remove_phy(
+ struct scic_sds_port *this_port,
+ struct scic_sds_phy *the_phy)
+{
+ return this_port->state_handlers->parent.remove_phy_handler(
+ &this_port->parent, &the_phy->parent);
+}
+
+/**
+ * This method requests the SAS address for the supplied SAS port from the SCI
+ * implementation.
+ * @this_port: a handle corresponding to the SAS port for which to return the
+ * SAS address.
+ * @sas_address: This parameter specifies a pointer to a SAS address structure
+ * into which the core will copy the SAS address for the port.
+ *
+ */
+void scic_sds_port_get_sas_address(
+ struct scic_sds_port *this_port,
+ struct sci_sas_address *sas_address)
+{
+ u32 index;
+
+ sas_address->high = 0;
+ sas_address->low = 0;
+
+ for (index = 0; index < SCI_MAX_PHYS; index++) {
+ if (this_port->phy_table[index] != NULL) {
+ scic_sds_phy_get_sas_address(this_port->phy_table[index], sas_address);
+ }
+ }
+}
+
+/**
+ * This method will indicate which protocols are supported by this port.
+ * @this_port: a handle corresponding to the SAS port for which to return the
+ * supported protocols.
+ * @protocols: This parameter specifies a pointer to an IAF protocol field
+ * structure into which the core will copy the protocol values for the port.
+ * The values are returned as part of a bit mask in order to allow for
+ * multi-protocol support.
+ *
+ */
+static void scic_sds_port_get_protocols(
+ struct scic_sds_port *this_port,
+ struct sci_sas_identify_address_frame_protocols *protocols)
+{
+ u8 index;
+
+ protocols->u.all = 0;
+
+ for (index = 0; index < SCI_MAX_PHYS; index++) {
+ if (this_port->phy_table[index] != NULL) {
+ scic_sds_phy_get_protocols(this_port->phy_table[index], protocols);
+ }
+ }
+}
+
+/**
+ * This method requests the SAS address for the device directly attached to
+ * this SAS port.
+ * @this_port: a handle corresponding to the SAS port for which to return the
+ * SAS address.
+ * @sas_address: This parameter specifies a pointer to a SAS address structure
+ * into which the core will copy the SAS address for the device directly
+ * attached to the port.
+ *
+ */
+void scic_sds_port_get_attached_sas_address(
+ struct scic_sds_port *this_port,
+ struct sci_sas_address *sas_address)
+{
+ struct sci_sas_identify_address_frame_protocols protocols;
+ struct scic_sds_phy *phy;
+
+ /*
+ * Ensure that the phy is both part of the port and currently
+ * connected to the remote end-point. */
+ phy = scic_sds_port_get_a_connected_phy(this_port);
+ if (phy != NULL) {
+ scic_sds_phy_get_attached_phy_protocols(phy, &protocols);
+
+ if (!protocols.u.bits.stp_target) {
+ scic_sds_phy_get_attached_sas_address(phy, sas_address);
+ } else {
+ scic_sds_phy_get_sas_address(phy, sas_address);
+ sas_address->low += phy->phy_index;
+ }
+ } else {
+ sas_address->high = 0;
+ sas_address->low = 0;
+ }
+}
+
+/**
+ * This method will indicate which protocols are supported by this remote
+ * device.
+ * @this_port: a handle corresponding to the SAS port for which to return the
+ * supported protocols.
+ * @protocols: This parameter specifies a pointer to an IAF protocol field
+ * structure into which the core will copy the protocol values for the port.
+ * The values are returned as part of a bit mask in order to allow for
+ * multi-protocol support.
+ *
+ */
+void scic_sds_port_get_attached_protocols(
+ struct scic_sds_port *this_port,
+ struct sci_sas_identify_address_frame_protocols *protocols)
+{
+ struct scic_sds_phy *phy;
+
+ /*
+ * Ensure that the phy is both part of the port and currently
+ * connected to the remote end-point. */
+ phy = scic_sds_port_get_a_connected_phy(this_port);
+ if (phy != NULL)
+ scic_sds_phy_get_attached_phy_protocols(phy, protocols);
+ else
+ protocols->u.all = 0;
+}
+
+/**
+ * This method returns the amount of memory requred for a port object.
+ *
+ * u32
+ */
+
+/**
+ * This method returns the minimum number of timers required for all port
+ * objects.
+ *
+ * u32
+ */
+
+/**
+ * This method returns the maximum number of timers required for all port
+ * objects.
+ *
+ * u32
+ */
+
+/**
+ *
+ * @this_port:
+ * @port_index:
+ *
+ *
+ */
+void scic_sds_port_construct(
+ struct scic_sds_port *this_port,
+ u8 port_index,
+ struct scic_sds_controller *owning_controller)
+{
+ u32 index;
+
+ sci_base_port_construct(
+ &this_port->parent,
+ scic_sds_port_state_table
+ );
+
+ sci_base_state_machine_construct(
+ scic_sds_port_get_ready_substate_machine(this_port),
+ &this_port->parent.parent,
+ scic_sds_port_ready_substate_table,
+ SCIC_SDS_PORT_READY_SUBSTATE_WAITING
+ );
+
+ this_port->logical_port_index = SCIC_SDS_DUMMY_PORT;
+ this_port->physical_port_index = port_index;
+ this_port->active_phy_mask = 0;
+
+ this_port->owning_controller = owning_controller;
+
+ this_port->started_request_count = 0;
+ this_port->assigned_device_count = 0;
+
+ this_port->timer_handle = SCI_INVALID_HANDLE;
+
+ this_port->transport_layer_registers = NULL;
+ this_port->port_task_scheduler_registers = NULL;
+
+ for (index = 0; index < SCI_MAX_PHYS; index++) {
+ this_port->phy_table[index] = NULL;
+ }
+}
+
+/**
+ * This method performs initialization of the supplied port. Initialization
+ * includes: - state machine initialization - member variable initialization
+ * - configuring the phy_mask
+ * @this_port:
+ * @transport_layer_registers:
+ * @port_task_scheduler_registers:
+ * @port_configuration_regsiter:
+ *
+ * enum sci_status SCI_FAILURE_UNSUPPORTED_PORT_CONFIGURATION This value is returned
+ * if the phy being added to the port
+ */
+enum sci_status scic_sds_port_initialize(
+ struct scic_sds_port *this_port,
+ void *transport_layer_registers,
+ void *port_task_scheduler_registers,
+ void *port_configuration_regsiter,
+ void *viit_registers)
+{
+ u32 tl_control;
+
+ this_port->transport_layer_registers = transport_layer_registers;
+ this_port->port_task_scheduler_registers = port_task_scheduler_registers;
+ this_port->port_pe_configuration_register = port_configuration_regsiter;
+ this_port->viit_registers = viit_registers;
+
+ scic_sds_port_set_direct_attached_device_id(
+ this_port,
+ SCIC_SDS_REMOTE_NODE_CONTEXT_INVALID_INDEX
+ );
+
+ /*
+ * Hardware team recommends that we enable the STP prefetch
+ * for all ports */
+ tl_control = SCU_TLCR_READ(this_port);
+ tl_control |= SCU_TLCR_GEN_BIT(STP_WRITE_DATA_PREFETCH);
+ SCU_TLCR_WRITE(this_port, tl_control);
+
+ /*
+ * If this is not the dummy port make the assignment of
+ * the timer and start the state machine */
+ if (this_port->physical_port_index != SCI_MAX_PORTS) {
+ /* / @todo should we create the timer at create time? */
+ this_port->timer_handle = scic_cb_timer_create(
+ scic_sds_port_get_controller(this_port),
+ scic_sds_port_timeout_handler,
+ this_port
+ );
+
+ } else {
+ /*
+ * Force the dummy port into a condition where it rejects all requests
+ * as its in an invalid state for any operation.
+ * / @todo should we set a set of specical handlers for the dummy port? */
+ scic_sds_port_set_base_state_handlers(
+ this_port, SCI_BASE_PORT_STATE_STOPPED
+ );
+ }
+
+ return SCI_SUCCESS;
+}
+
+/**
+ *
+ * @this_port: This is the struct scic_sds_port object for which has a phy that has
+ * gone link up.
+ * @the_phy: This is the struct scic_sds_phy object that has gone link up.
+ * @do_notify_user: This parameter specifies whether to inform the user (via
+ * scic_cb_port_link_up()) as to the fact that a new phy as become ready.
+ *
+ * This method is the a general link up handler for the struct scic_sds_port object.
+ * This function will determine if this struct scic_sds_phy can be assigned to this
+ * struct scic_sds_port object. If the struct scic_sds_phy object can is not a valid PHY for
+ * this port then the function will notify the SCIC_USER. A PHY can only be
+ * part of a port if it's attached SAS ADDRESS is the same as all other PHYs in
+ * the same port. none
+ */
+void scic_sds_port_general_link_up_handler(
+ struct scic_sds_port *this_port,
+ struct scic_sds_phy *the_phy,
+ bool do_notify_user)
+{
+ struct sci_sas_address port_sas_address;
+ struct sci_sas_address phy_sas_address;
+
+ scic_sds_port_get_attached_sas_address(this_port, &port_sas_address);
+ scic_sds_phy_get_attached_sas_address(the_phy, &phy_sas_address);
+
+ /*
+ * If the SAS address of the new phy matches the SAS address of
+ * other phys in the port OR this is the first phy in the port,
+ * then activate the phy and allow it to be used for operations
+ * in this port. */
+ if (
+ (
+ (phy_sas_address.high == port_sas_address.high)
+ && (phy_sas_address.low == port_sas_address.low)
+ )
+ || (this_port->active_phy_mask == 0)
+ ) {
+ scic_sds_port_activate_phy(this_port, the_phy, do_notify_user);
+
+ if (this_port->parent.state_machine.current_state_id
+ == SCI_BASE_PORT_STATE_RESETTING) {
+ sci_base_state_machine_change_state(
+ &this_port->parent.state_machine, SCI_BASE_PORT_STATE_READY
+ );
+ }
+ } else {
+ scic_sds_port_invalid_link_up(this_port, the_phy);
+ }
+}
+
+
+enum sci_status scic_port_start(struct scic_sds_port *port)
+{
+ return port->state_handlers->parent.start_handler(&port->parent);
+}
+
+
+enum sci_status scic_port_stop(struct scic_sds_port *port)
+{
+ return port->state_handlers->parent.stop_handler(&port->parent);
+}
+
+
+enum sci_status scic_port_get_properties(
+ struct scic_sds_port *port,
+ struct scic_port_properties *prop)
+{
+ if ((port == SCI_INVALID_HANDLE) ||
+ (port->logical_port_index == SCIC_SDS_DUMMY_PORT))
+ return SCI_FAILURE_INVALID_PORT;
+
+ prop->index = port->logical_port_index;
+ prop->phy_mask = scic_sds_port_get_phys(port);
+ scic_sds_port_get_sas_address(port, &prop->local.sas_address);
+ scic_sds_port_get_protocols(port, &prop->local.protocols);
+ scic_sds_port_get_attached_sas_address(port, &prop->remote.sas_address);
+ scic_sds_port_get_attached_protocols(port, &prop->remote.protocols);
+
+ return SCI_SUCCESS;
+}
+
+
+enum sci_status scic_port_hard_reset(
+ struct scic_sds_port *port,
+ u32 reset_timeout)
+{
+ return port->state_handlers->parent.reset_handler(
+ &port->parent, reset_timeout);
+}
+
+/**
+ *
+ * @this_port: The port for which the direct attached device id is to be
+ * assigned.
+ *
+ * This method assigns the direct attached device ID for this port.
+ */
+void scic_sds_port_set_direct_attached_device_id(
+ struct scic_sds_port *this_port,
+ u32 device_id)
+{
+ u32 tl_control;
+
+ SCU_STPTLDARNI_WRITE(this_port, device_id);
+
+ /*
+ * The read should guarntee that the first write gets posted
+ * before the next write */
+ tl_control = SCU_TLCR_READ(this_port);
+ tl_control |= SCU_TLCR_GEN_BIT(CLEAR_TCI_NCQ_MAPPING_TABLE);
+ SCU_TLCR_WRITE(this_port, tl_control);
+}
+
+
+/**
+ *
+ * @this_port: This is the port on which the phy should be enabled.
+ * @the_phy: This is the specific phy which to enable.
+ * @do_notify_user: This parameter specifies whether to inform the user (via
+ * scic_cb_port_link_up()) as to the fact that a new phy as become ready.
+ *
+ * This method will activate the phy in the port. Activation includes: - adding
+ * the phy to the port - enabling the Protocol Engine in the silicon. -
+ * notifying the user that the link is up. none
+ */
+void scic_sds_port_activate_phy(
+ struct scic_sds_port *this_port,
+ struct scic_sds_phy *the_phy,
+ bool do_notify_user)
+{
+ struct scic_sds_controller *controller;
+ struct sci_sas_identify_address_frame_protocols protocols;
+
+ controller = scic_sds_port_get_controller(this_port);
+ scic_sds_phy_get_attached_phy_protocols(the_phy, &protocols);
+
+ /* If this is sata port then the phy has already been resumed */
+ if (!protocols.u.bits.stp_target) {
+ scic_sds_phy_resume(the_phy);
+ }
+
+ this_port->active_phy_mask |= 1 << the_phy->phy_index;
+
+ scic_sds_controller_clear_invalid_phy(controller, the_phy);
+
+ if (do_notify_user == true)
+ scic_cb_port_link_up(this_port->owning_controller, this_port, the_phy);
+}
+
+/**
+ *
+ * @this_port: This is the port on which the phy should be deactivated.
+ * @the_phy: This is the specific phy that is no longer active in the port.
+ * @do_notify_user: This parameter specifies whether to inform the user (via
+ * scic_cb_port_link_down()) as to the fact that a new phy as become ready.
+ *
+ * This method will deactivate the supplied phy in the port. none
+ */
+void scic_sds_port_deactivate_phy(
+ struct scic_sds_port *this_port,
+ struct scic_sds_phy *the_phy,
+ bool do_notify_user)
+{
+ this_port->active_phy_mask &= ~(1 << the_phy->phy_index);
+
+ the_phy->max_negotiated_speed = SCI_SAS_NO_LINK_RATE;
+
+ /* Re-assign the phy back to the LP as if it were a narrow port */
+ SCU_PCSPExCR_WRITE(this_port, the_phy->phy_index, the_phy->phy_index);
+
+ if (do_notify_user == true)
+ scic_cb_port_link_down(this_port->owning_controller, this_port, the_phy);
+}
+
+/**
+ *
+ * @this_port: This is the port on which the phy should be disabled.
+ * @the_phy: This is the specific phy which to disabled.
+ *
+ * This method will disable the phy and report that the phy is not valid for
+ * this port object. None
+ */
+static void scic_sds_port_invalid_link_up(
+ struct scic_sds_port *this_port,
+ struct scic_sds_phy *the_phy)
+{
+ struct scic_sds_controller *controller = scic_sds_port_get_controller(this_port);
+
+ /*
+ * Check to see if we have alreay reported this link as bad and if not go
+ * ahead and tell the SCI_USER that we have discovered an invalid link. */
+ if ((controller->invalid_phy_mask & (1 << the_phy->phy_index)) == 0) {
+ scic_sds_controller_set_invalid_phy(controller, the_phy);
+
+ scic_cb_port_invalid_link_up(controller, this_port, the_phy);
+ }
+}
+
+/**
+ * This method returns false if the port only has a single phy object assigned.
+ * If there are no phys or more than one phy then the method will return
+ * true.
+ * @this_port: The port for which the wide port condition is to be checked.
+ *
+ * bool true Is returned if this is a wide ported port. false Is returned if
+ * this is a narrow port.
+ */
+static bool scic_sds_port_is_wide(struct scic_sds_port *this_port)
+{
+ u32 index;
+ u32 phy_count = 0;
+
+ for (index = 0; index < SCI_MAX_PHYS; index++) {
+ if (this_port->phy_table[index] != NULL) {
+ phy_count++;
+ }
+ }
+
+ return phy_count != 1;
+}
+
+/**
+ * This method is called by the PHY object when the link is detected. if the
+ * port wants the PHY to continue on to the link up state then the port
+ * layer must return true. If the port object returns false the phy object
+ * must halt its attempt to go link up.
+ * @this_port: The port associated with the phy object.
+ * @the_phy: The phy object that is trying to go link up.
+ *
+ * true if the phy object can continue to the link up condition. true Is
+ * returned if this phy can continue to the ready state. false Is returned if
+ * can not continue on to the ready state. This notification is in place for
+ * wide ports and direct attached phys. Since there are no wide ported SATA
+ * devices this could become an invalid port configuration.
+ */
+bool scic_sds_port_link_detected(
+ struct scic_sds_port *this_port,
+ struct scic_sds_phy *the_phy)
+{
+ struct sci_sas_identify_address_frame_protocols protocols;
+
+ scic_sds_phy_get_attached_phy_protocols(the_phy, &protocols);
+
+ if (
+ (this_port->logical_port_index != SCIC_SDS_DUMMY_PORT)
+ && (protocols.u.bits.stp_target)
+ && scic_sds_port_is_wide(this_port)
+ ) {
+ scic_sds_port_invalid_link_up(this_port, the_phy);
+
+ return false;
+ }
+
+ return true;
+}
+
+/**
+ * This method is the entry point for the phy to inform the port that it is now
+ * in a ready state
+ * @this_port:
+ *
+ *
+ */
+void scic_sds_port_link_up(
+ struct scic_sds_port *this_port,
+ struct scic_sds_phy *the_phy)
+{
+ the_phy->is_in_link_training = false;
+
+ this_port->state_handlers->link_up_handler(this_port, the_phy);
+}
+
+/**
+ * This method is the entry point for the phy to inform the port that it is no
+ * longer in a ready state
+ * @this_port:
+ *
+ *
+ */
+void scic_sds_port_link_down(
+ struct scic_sds_port *this_port,
+ struct scic_sds_phy *the_phy)
+{
+ this_port->state_handlers->link_down_handler(this_port, the_phy);
+}
+
+/**
+ * This method is called to start an IO request on this port.
+ * @this_port:
+ * @the_device:
+ * @the_io_request:
+ *
+ * enum sci_status
+ */
+enum sci_status scic_sds_port_start_io(
+ struct scic_sds_port *this_port,
+ struct scic_sds_remote_device *the_device,
+ struct scic_sds_request *the_io_request)
+{
+ return this_port->state_handlers->start_io_handler(
+ this_port, the_device, the_io_request);
+}
+
+/**
+ * This method is called to complete an IO request to the port.
+ * @this_port:
+ * @the_device:
+ * @the_io_request:
+ *
+ * enum sci_status
+ */
+enum sci_status scic_sds_port_complete_io(
+ struct scic_sds_port *this_port,
+ struct scic_sds_remote_device *the_device,
+ struct scic_sds_request *the_io_request)
+{
+ return this_port->state_handlers->complete_io_handler(
+ this_port, the_device, the_io_request);
+}
+
+/**
+ * This method is provided to timeout requests for port operations. Mostly its
+ * for the port reset operation.
+ *
+ *
+ */
+static void scic_sds_port_timeout_handler(void *port)
+{
+ struct scic_sds_port *this_port = port;
+ u32 current_state;
+
+ current_state = sci_base_state_machine_get_state(
+ &this_port->parent.state_machine);
+
+ if (current_state == SCI_BASE_PORT_STATE_RESETTING) {
+ /*
+ * if the port is still in the resetting state then the timeout fired
+ * before the reset completed. */
+ sci_base_state_machine_change_state(
+ &this_port->parent.state_machine,
+ SCI_BASE_PORT_STATE_FAILED
+ );
+ } else if (current_state == SCI_BASE_PORT_STATE_STOPPED) {
+ /*
+ * if the port is stopped then the start request failed
+ * In this case stay in the stopped state. */
+ dev_err(sciport_to_dev(this_port),
+ "%s: SCIC Port 0x%p failed to stop before tiemout.\n",
+ __func__,
+ this_port);
+ } else if (current_state == SCI_BASE_PORT_STATE_STOPPING) {
+ /* if the port is still stopping then the stop has not completed */
+ scic_cb_port_stop_complete(
+ scic_sds_port_get_controller(this_port),
+ port,
+ SCI_FAILURE_TIMEOUT
+ );
+ } else {
+ /*
+ * The port is in the ready state and we have a timer reporting a timeout
+ * this should not happen. */
+ dev_err(sciport_to_dev(this_port),
+ "%s: SCIC Port 0x%p is processing a timeout operation "
+ "in state %d.\n",
+ __func__,
+ this_port,
+ current_state);
+ }
+}
+
+/* --------------------------------------------------------------------------- */
+
+#ifdef SCIC_DEBUG_ENABLED
+void scic_sds_port_decrement_request_count(struct scic_sds_port *this_port)
+{
+ if (this_port->started_request_count == 0)
+ dev_warn(sciport_to_dev(this_port),
+ __func__,
+ "%s: SCIC Port object requested to decrement started "
+ "io count past zero.\n");
+ else
+ this_port->started_request_count--;
+}
+#endif
+
+/**
+ * This function updates the hardwares VIIT entry for this port.
+ *
+ *
+ */
+void scic_sds_port_update_viit_entry(struct scic_sds_port *this_port)
+{
+ struct sci_sas_address sas_address;
+
+ scic_sds_port_get_sas_address(this_port, &sas_address);
+
+ scu_port_viit_register_write(
+ this_port, initiator_sas_address_hi, sas_address.high);
+
+ scu_port_viit_register_write(
+ this_port, initiator_sas_address_lo, sas_address.low);
+
+ /* This value get cleared just in case its not already cleared */
+ scu_port_viit_register_write(
+ this_port, reserved, 0);
+
+ /* We are required to update the status register last */
+ scu_port_viit_register_write(
+ this_port, status, (
+ SCU_VIIT_ENTRY_ID_VIIT
+ | SCU_VIIT_IPPT_INITIATOR
+ | ((1 << this_port->physical_port_index) << SCU_VIIT_ENTRY_LPVIE_SHIFT)
+ | SCU_VIIT_STATUS_ALL_VALID
+ )
+ );
+}
+
+/**
+ * This method returns the maximum allowed speed for data transfers on this
+ * port. This maximum allowed speed evaluates to the maximum speed of the
+ * slowest phy in the port.
+ * @this_port: This parameter specifies the port for which to retrieve the
+ * maximum allowed speed.
+ *
+ * This method returns the maximum negotiated speed of the slowest phy in the
+ * port.
+ */
+enum sci_sas_link_rate scic_sds_port_get_max_allowed_speed(
+ struct scic_sds_port *this_port)
+{
+ u16 index = 0;
+ enum sci_sas_link_rate max_allowed_speed = SCI_SAS_600_GB;
+ struct scic_sds_phy *phy = NULL;
+
+ /*
+ * Loop through all of the phys in this port and find the phy with the
+ * lowest maximum link rate. */
+ for (index = 0; index < SCI_MAX_PHYS; index++) {
+ phy = this_port->phy_table[index];
+ if (
+ (phy != NULL)
+ && (scic_sds_port_active_phy(this_port, phy) == true)
+ && (phy->max_negotiated_speed < max_allowed_speed)
+ )
+ max_allowed_speed = phy->max_negotiated_speed;
+ }
+
+ return max_allowed_speed;
+}
+
+
+/**
+ * This method passes the event to core user.
+ * @this_port: The port that a BCN happens.
+ * @this_phy: The phy that receives BCN.
+ *
+ */
+void scic_sds_port_broadcast_change_received(
+ struct scic_sds_port *this_port,
+ struct scic_sds_phy *this_phy)
+{
+ /* notify the user. */
+ scic_cb_port_bc_change_primitive_received(
+ this_port->owning_controller, this_port, this_phy
+ );
+}
+
+
+/**
+ * This API methhod enables the broadcast change notification from underneath
+ * hardware.
+ * @this_port: The port that a BCN had been disabled from.
+ *
+ */
+void scic_port_enable_broadcast_change_notification(
+ struct scic_sds_port *port)
+{
+ struct scic_sds_phy *phy;
+ u32 register_value;
+ u8 index;
+
+ /* Loop through all of the phys to enable BCN. */
+ for (index = 0; index < SCI_MAX_PHYS; index++) {
+ phy = port->phy_table[index];
+ if (phy != NULL) {
+ register_value = SCU_SAS_LLCTL_READ(phy);
+
+ /* clear the bit by writing 1. */
+ SCU_SAS_LLCTL_WRITE(phy, register_value);
+ }
+ }
+}
+
+/*
+ * ****************************************************************************
+ * * READY SUBSTATE HANDLERS
+ * **************************************************************************** */
+
+/**
+ *
+ * @port: This is the struct sci_base_port object which is cast into a struct scic_sds_port
+ * object.
+ *
+ * This method is the general ready state stop handler for the struct scic_sds_port
+ * object. This function will transition the ready substate machine to its
+ * final state. enum sci_status SCI_SUCCESS
+ */
+static enum sci_status scic_sds_port_ready_substate_stop_handler(
+ struct sci_base_port *port)
+{
+ struct scic_sds_port *this_port = (struct scic_sds_port *)port;
+
+ sci_base_state_machine_change_state(
+ &this_port->parent.state_machine,
+ SCI_BASE_PORT_STATE_STOPPING
+ );
+
+ return SCI_SUCCESS;
+}
+
+/**
+ *
+ * @port: This is the struct sci_base_port object which is cast into a struct scic_sds_port
+ * object.
+ * @device: This is the struct sci_base_remote_device object which is not used in this
+ * function.
+ * @io_request: This is the struct sci_base_request object which is not used in this
+ * function.
+ *
+ * This method is the general ready substate complete io handler for the
+ * struct scic_sds_port object. This function decrments the outstanding request count
+ * for this port object. enum sci_status SCI_SUCCESS
+ */
+static enum sci_status scic_sds_port_ready_substate_complete_io_handler(
+ struct scic_sds_port *port,
+ struct scic_sds_remote_device *device,
+ struct scic_sds_request *io_request)
+{
+ struct scic_sds_port *this_port = (struct scic_sds_port *)port;
+
+ scic_sds_port_decrement_request_count(this_port);
+
+ return SCI_SUCCESS;
+}
+
+static enum sci_status scic_sds_port_ready_substate_add_phy_handler(
+ struct sci_base_port *port,
+ struct sci_base_phy *phy)
+{
+ struct scic_sds_port *this_port = (struct scic_sds_port *)port;
+ struct scic_sds_phy *this_phy = (struct scic_sds_phy *)phy;
+ enum sci_status status;
+
+ status = scic_sds_port_set_phy(this_port, this_phy);
+
+ if (status == SCI_SUCCESS) {
+ scic_sds_port_general_link_up_handler(this_port, this_phy, true);
+
+ this_port->not_ready_reason = SCIC_PORT_NOT_READY_RECONFIGURING;
+
+ sci_base_state_machine_change_state(
+ &this_port->ready_substate_machine,
+ SCIC_SDS_PORT_READY_SUBSTATE_CONFIGURING
+ );
+ }
+
+ return status;
+}
+
+
+static enum sci_status scic_sds_port_ready_substate_remove_phy_handler(
+ struct sci_base_port *port,
+ struct sci_base_phy *phy)
+{
+ struct scic_sds_port *this_port = (struct scic_sds_port *)port;
+ struct scic_sds_phy *this_phy = (struct scic_sds_phy *)phy;
+ enum sci_status status;
+
+ status = scic_sds_port_clear_phy(this_port, this_phy);
+
+ if (status == SCI_SUCCESS) {
+ scic_sds_port_deactivate_phy(this_port, this_phy, true);
+
+ this_port->not_ready_reason = SCIC_PORT_NOT_READY_RECONFIGURING;
+
+ sci_base_state_machine_change_state(
+ &this_port->ready_substate_machine,
+ SCIC_SDS_PORT_READY_SUBSTATE_CONFIGURING
+ );
+ }
+
+ return status;
+}
+
+/*
+ * ****************************************************************************
+ * * READY SUBSTATE WAITING HANDLERS
+ * **************************************************************************** */
+
+/**
+ *
+ * @this_port: This is the struct scic_sds_port object that which has a phy that has
+ * gone link up.
+ * @the_phy: This is the struct scic_sds_phy object that has gone link up.
+ *
+ * This method is the ready waiting substate link up handler for the
+ * struct scic_sds_port object. This methos will report the link up condition for
+ * this port and will transition to the ready operational substate. none
+ */
+static void scic_sds_port_ready_waiting_substate_link_up_handler(
+ struct scic_sds_port *this_port,
+ struct scic_sds_phy *the_phy)
+{
+ /*
+ * Since this is the first phy going link up for the port we can just enable
+ * it and continue. */
+ scic_sds_port_activate_phy(this_port, the_phy, true);
+
+ sci_base_state_machine_change_state(
+ &this_port->ready_substate_machine,
+ SCIC_SDS_PORT_READY_SUBSTATE_OPERATIONAL
+ );
+}
+
+/**
+ *
+ * @port: This is the struct sci_base_port object which is cast into a struct scic_sds_port
+ * object.
+ * @device: This is the struct sci_base_remote_device object which is not used in this
+ * request.
+ * @io_request: This is the struct sci_base_request object which is not used in this
+ * function.
+ *
+ * This method is the ready waiting substate start io handler for the
+ * struct scic_sds_port object. The port object can not accept new requests so the
+ * request is failed. enum sci_status SCI_FAILURE_INVALID_STATE
+ */
+static enum sci_status scic_sds_port_ready_waiting_substate_start_io_handler(
+ struct scic_sds_port *port,
+ struct scic_sds_remote_device *device,
+ struct scic_sds_request *io_request)
+{
+ return SCI_FAILURE_INVALID_STATE;
+}
+
+/*
+ * ****************************************************************************
+ * * READY SUBSTATE OPERATIONAL HANDLERS
+ * **************************************************************************** */
+
+/**
+ *
+ * @port: This is the struct sci_base_port object which is cast into a struct scic_sds_port
+ * object.
+ * @timeout: This is the timeout for the reset request to complete.
+ *
+ * This method will casue the port to reset. enum sci_status SCI_SUCCESS
+ */
+static enum sci_status scic_sds_port_ready_operational_substate_reset_handler(
+ struct sci_base_port *port,
+ u32 timeout)
+{
+ enum sci_status status = SCI_FAILURE_INVALID_PHY;
+ u32 phy_index;
+ struct scic_sds_port *this_port = (struct scic_sds_port *)port;
+ struct scic_sds_phy *selected_phy = SCI_INVALID_HANDLE;
+
+
+ /* Select a phy on which we can send the hard reset request. */
+ for (
+ phy_index = 0;
+ (phy_index < SCI_MAX_PHYS)
+ && (selected_phy == SCI_INVALID_HANDLE);
+ phy_index++
+ ) {
+ selected_phy = this_port->phy_table[phy_index];
+
+ if (
+ (selected_phy != SCI_INVALID_HANDLE)
+ && !scic_sds_port_active_phy(this_port, selected_phy)
+ ) {
+ /* We found a phy but it is not ready select different phy */
+ selected_phy = SCI_INVALID_HANDLE;
+ }
+ }
+
+ /* If we have a phy then go ahead and start the reset procedure */
+ if (selected_phy != SCI_INVALID_HANDLE) {
+ status = scic_sds_phy_reset(selected_phy);
+
+ if (status == SCI_SUCCESS) {
+ scic_cb_timer_start(
+ scic_sds_port_get_controller(this_port),
+ this_port->timer_handle,
+ timeout
+ );
+
+ this_port->not_ready_reason = SCIC_PORT_NOT_READY_HARD_RESET_REQUESTED;
+
+ sci_base_state_machine_change_state(
+ &this_port->parent.state_machine,
+ SCI_BASE_PORT_STATE_RESETTING
+ );
+ }
+ }
+
+ return status;
+}
+
+/**
+ * scic_sds_port_ready_operational_substate_link_up_handler() -
+ * @this_port: This is the struct scic_sds_port object that which has a phy that has
+ * gone link up.
+ * @the_phy: This is the struct scic_sds_phy object that has gone link up.
+ *
+ * This method is the ready operational substate link up handler for the
+ * struct scic_sds_port object. This function notifies the SCI User that the phy has
+ * gone link up. none
+ */
+static void scic_sds_port_ready_operational_substate_link_up_handler(
+ struct scic_sds_port *this_port,
+ struct scic_sds_phy *the_phy)
+{
+ scic_sds_port_general_link_up_handler(this_port, the_phy, true);
+}
+
+/**
+ * scic_sds_port_ready_operational_substate_link_down_handler() -
+ * @this_port: This is the struct scic_sds_port object that which has a phy that has
+ * gone link down.
+ * @the_phy: This is the struct scic_sds_phy object that has gone link down.
+ *
+ * This method is the ready operational substate link down handler for the
+ * struct scic_sds_port object. This function notifies the SCI User that the phy has
+ * gone link down and if this is the last phy in the port the port will change
+ * state to the ready waiting substate. none
+ */
+static void scic_sds_port_ready_operational_substate_link_down_handler(
+ struct scic_sds_port *this_port,
+ struct scic_sds_phy *the_phy)
+{
+ scic_sds_port_deactivate_phy(this_port, the_phy, true);
+
+ /*
+ * If there are no active phys left in the port, then transition
+ * the port to the WAITING state until such time as a phy goes
+ * link up. */
+ if (this_port->active_phy_mask == 0) {
+ sci_base_state_machine_change_state(
+ scic_sds_port_get_ready_substate_machine(this_port),
+ SCIC_SDS_PORT_READY_SUBSTATE_WAITING
+ );
+ }
+}
+
+/**
+ *
+ * @port: This is the struct sci_base_port object which is cast into a struct scic_sds_port
+ * object.
+ * @device: This is the struct sci_base_remote_device object which is not used in this
+ * function.
+ * @io_request: This is the struct sci_base_request object which is not used in this
+ * function.
+ *
+ * This method is the ready operational substate start io handler for the
+ * struct scic_sds_port object. This function incremetns the outstanding request
+ * count for this port object. enum sci_status SCI_SUCCESS
+ */
+static enum sci_status scic_sds_port_ready_operational_substate_start_io_handler(
+ struct scic_sds_port *port,
+ struct scic_sds_remote_device *device,
+ struct scic_sds_request *io_request)
+{
+ struct scic_sds_port *this_port = (struct scic_sds_port *)port;
+
+ scic_sds_port_increment_request_count(this_port);
+
+ return SCI_SUCCESS;
+}
+
+/*
+ * ****************************************************************************
+ * * READY SUBSTATE OPERATIONAL HANDLERS
+ * **************************************************************************** */
+
+/**
+ * scic_sds_port_ready_configuring_substate_add_phy_handler() -
+ * @port: This is the struct sci_base_port object which is cast into a struct scic_sds_port
+ * object.
+ *
+ * This is the default method for a port add phy request. It will report a
+ * warning and exit. enum sci_status SCI_FAILURE_INVALID_STATE
+ */
+static enum sci_status scic_sds_port_ready_configuring_substate_add_phy_handler(
+ struct sci_base_port *port,
+ struct sci_base_phy *phy)
+{
+ struct scic_sds_port *this_port = (struct scic_sds_port *)port;
+ struct scic_sds_phy *this_phy = (struct scic_sds_phy *)phy;
+ enum sci_status status;
+
+ status = scic_sds_port_set_phy(this_port, this_phy);
+
+ if (status == SCI_SUCCESS) {
+ scic_sds_port_general_link_up_handler(this_port, this_phy, true);
+
+ /*
+ * Re-enter the configuring state since this may be the last phy in
+ * the port. */
+ sci_base_state_machine_change_state(
+ &this_port->ready_substate_machine,
+ SCIC_SDS_PORT_READY_SUBSTATE_CONFIGURING
+ );
+ }
+
+ return status;
+}
+
+/**
+ * scic_sds_port_ready_configuring_substate_remove_phy_handler() -
+ * @port: This is the struct sci_base_port object which is cast into a struct scic_sds_port
+ * object.
+ *
+ * This is the default method for a port remove phy request. It will report a
+ * warning and exit. enum sci_status SCI_FAILURE_INVALID_STATE
+ */
+static enum sci_status scic_sds_port_ready_configuring_substate_remove_phy_handler(
+ struct sci_base_port *port,
+ struct sci_base_phy *phy)
+{
+ struct scic_sds_port *this_port = (struct scic_sds_port *)port;
+ struct scic_sds_phy *this_phy = (struct scic_sds_phy *)phy;
+ enum sci_status status;
+
+ status = scic_sds_port_clear_phy(this_port, this_phy);
+
+ if (status == SCI_SUCCESS) {
+ scic_sds_port_deactivate_phy(this_port, this_phy, true);
+
+ /*
+ * Re-enter the configuring state since this may be the last phy in
+ * the port. */
+ sci_base_state_machine_change_state(
+ &this_port->ready_substate_machine,
+ SCIC_SDS_PORT_READY_SUBSTATE_CONFIGURING
+ );
+ }
+
+ return status;
+}
+
+/**
+ * scic_sds_port_ready_configuring_substate_complete_io_handler() -
+ * @port: This is the port that is being requested to complete the io request.
+ * @device: This is the device on which the io is completing.
+ *
+ * This method will decrement the outstanding request count for this port. If
+ * the request count goes to 0 then the port can be reprogrammed with its new
+ * phy data.
+ */
+static enum sci_status scic_sds_port_ready_configuring_substate_complete_io_handler(
+ struct scic_sds_port *port,
+ struct scic_sds_remote_device *device,
+ struct scic_sds_request *io_request)
+{
+ scic_sds_port_decrement_request_count(port);
+
+ if (port->started_request_count == 0) {
+ sci_base_state_machine_change_state(
+ &port->ready_substate_machine,
+ SCIC_SDS_PORT_READY_SUBSTATE_OPERATIONAL
+ );
+ }
+
+ return SCI_SUCCESS;
+}
+
+/* --------------------------------------------------------------------------- */
+
+struct scic_sds_port_state_handler
+scic_sds_port_ready_substate_handler_table[SCIC_SDS_PORT_READY_MAX_SUBSTATES] =
+{
+ /* SCIC_SDS_PORT_READY_SUBSTATE_WAITING */
+ {
+ {
+ scic_sds_port_default_start_handler,
+ scic_sds_port_ready_substate_stop_handler,
+ scic_sds_port_default_destruct_handler,
+ scic_sds_port_default_reset_handler,
+ scic_sds_port_ready_substate_add_phy_handler,
+ scic_sds_port_default_remove_phy_handler
+ },
+ scic_sds_port_default_frame_handler,
+ scic_sds_port_default_event_handler,
+ scic_sds_port_ready_waiting_substate_link_up_handler,
+ scic_sds_port_default_link_down_handler,
+ scic_sds_port_ready_waiting_substate_start_io_handler,
+ scic_sds_port_ready_substate_complete_io_handler,
+ },
+ /* SCIC_SDS_PORT_READY_SUBSTATE_OPERATIONAL */
+ {
+ {
+ scic_sds_port_default_start_handler,
+ scic_sds_port_ready_substate_stop_handler,
+ scic_sds_port_default_destruct_handler,
+ scic_sds_port_ready_operational_substate_reset_handler,
+ scic_sds_port_ready_substate_add_phy_handler,
+ scic_sds_port_ready_substate_remove_phy_handler
+ },
+ scic_sds_port_default_frame_handler,
+ scic_sds_port_default_event_handler,
+ scic_sds_port_ready_operational_substate_link_up_handler,
+ scic_sds_port_ready_operational_substate_link_down_handler,
+ scic_sds_port_ready_operational_substate_start_io_handler,
+ scic_sds_port_ready_substate_complete_io_handler
+ },
+ /* SCIC_SDS_PORT_READY_SUBSTATE_CONFIGURING */
+ {
+ {
+ scic_sds_port_default_start_handler,
+ scic_sds_port_ready_substate_stop_handler,
+ scic_sds_port_default_destruct_handler,
+ scic_sds_port_default_reset_handler,
+ scic_sds_port_ready_configuring_substate_add_phy_handler,
+ scic_sds_port_ready_configuring_substate_remove_phy_handler
+ },
+ scic_sds_port_default_frame_handler,
+ scic_sds_port_default_event_handler,
+ scic_sds_port_default_link_up_handler,
+ scic_sds_port_default_link_down_handler,
+ scic_sds_port_default_start_io_handler,
+ scic_sds_port_ready_configuring_substate_complete_io_handler
+ }
+};
+
+
+/**
+ * scic_sds_port_set_ready_state_handlers() -
+ *
+ * This macro sets the port ready substate handlers.
+ */
+#define scic_sds_port_set_ready_state_handlers(port, state_id) \
+ scic_sds_port_set_state_handlers(\
+ port, &scic_sds_port_ready_substate_handler_table[(state_id)] \
+ )
+
+/*
+ * ******************************************************************************
+ * * PORT STATE PRIVATE METHODS
+ * ****************************************************************************** */
+
+/**
+ *
+ * @this_port: This is the struct scic_sds_port object to suspend.
+ *
+ * This method will susped the port task scheduler for this port object. none
+ */
+static void scic_sds_port_suspend_port_task_scheduler(
+ struct scic_sds_port *this_port)
+{
+ u32 pts_control_value;
+ u32 tl_control_value;
+
+ pts_control_value = scu_port_task_scheduler_read(this_port, control);
+ tl_control_value = scu_transport_layer_read(this_port, control);
+
+ pts_control_value |= SCU_PTSxCR_GEN_BIT(SUSPEND);
+ tl_control_value |= SCU_TLCR_GEN_BIT(CLEAR_TCI_NCQ_MAPPING_TABLE);
+
+ scu_port_task_scheduler_write(this_port, control, pts_control_value);
+ scu_transport_layer_write(this_port, control, tl_control_value);
+}
+
+/**
+ *
+ * @this_port: This is the struct scic_sds_port object to resume.
+ *
+ * This method will resume the port task scheduler for this port object. none
+ */
+static void scic_sds_port_resume_port_task_scheduler(
+ struct scic_sds_port *this_port)
+{
+ u32 pts_control_value;
+
+ pts_control_value = scu_port_task_scheduler_read(this_port, control);
+
+ pts_control_value &= ~SCU_PTSxCR_GEN_BIT(SUSPEND);
+
+ scu_port_task_scheduler_write(this_port, control, pts_control_value);
+}
+
+/*
+ * ******************************************************************************
+ * * PORT READY SUBSTATE METHODS
+ * ****************************************************************************** */
+
+/**
+ *
+ * @object: This is the struct sci_base_object which is cast to a struct scic_sds_port object.
+ *
+ * This method will perform the actions required by the struct scic_sds_port on
+ * entering the SCIC_SDS_PORT_READY_SUBSTATE_WAITING. This function checks the
+ * port for any ready phys. If there is at least one phy in a ready state then
+ * the port transitions to the ready operational substate. none
+ */
+static void scic_sds_port_ready_substate_waiting_enter(
+ struct sci_base_object *object)
+{
+ struct scic_sds_port *this_port = (struct scic_sds_port *)object;
+
+ scic_sds_port_set_ready_state_handlers(
+ this_port, SCIC_SDS_PORT_READY_SUBSTATE_WAITING
+ );
+
+ scic_sds_port_suspend_port_task_scheduler(this_port);
+
+ this_port->not_ready_reason = SCIC_PORT_NOT_READY_NO_ACTIVE_PHYS;
+
+ if (this_port->active_phy_mask != 0) {
+ /* At least one of the phys on the port is ready */
+ sci_base_state_machine_change_state(
+ &this_port->ready_substate_machine,
+ SCIC_SDS_PORT_READY_SUBSTATE_OPERATIONAL
+ );
+ }
+}
+
+/**
+ *
+ * @object: This is the struct sci_base_object which is cast to a struct scic_sds_port object.
+ *
+ * This method will perform the actions required by the struct scic_sds_port on
+ * entering the SCIC_SDS_PORT_READY_SUBSTATE_OPERATIONAL. This function sets
+ * the state handlers for the port object, notifies the SCI User that the port
+ * is ready, and resumes port operations. none
+ */
+static void scic_sds_port_ready_substate_operational_enter(
+ struct sci_base_object *object)
+{
+ u32 index;
+ struct scic_sds_port *this_port = (struct scic_sds_port *)object;
+
+ scic_sds_port_set_ready_state_handlers(
+ this_port, SCIC_SDS_PORT_READY_SUBSTATE_OPERATIONAL
+ );
+
+ scic_cb_port_ready(
+ scic_sds_port_get_controller(this_port), this_port
+ );
+
+ for (index = 0; index < SCI_MAX_PHYS; index++) {
+ if (this_port->phy_table[index] != NULL) {
+ scic_sds_port_write_phy_assignment(
+ this_port, this_port->phy_table[index]
+ );
+ }
+ }
+
+ scic_sds_port_update_viit_entry(this_port);
+
+ scic_sds_port_resume_port_task_scheduler(this_port);
+}
+
+/**
+ *
+ * @object: This is the struct sci_base_object which is cast to a struct scic_sds_port object.
+ *
+ * This method will perform the actions required by the struct scic_sds_port on
+ * exiting the SCIC_SDS_PORT_READY_SUBSTATE_OPERATIONAL. This function reports
+ * the port not ready and suspends the port task scheduler. none
+ */
+static void scic_sds_port_ready_substate_operational_exit(
+ struct sci_base_object *object)
+{
+ struct scic_sds_port *this_port = (struct scic_sds_port *)object;
+
+ scic_cb_port_not_ready(
+ scic_sds_port_get_controller(this_port),
+ this_port,
+ this_port->not_ready_reason
+ );
+}
+
+/*
+ * ******************************************************************************
+ * * PORT READY CONFIGURING METHODS
+ * ****************************************************************************** */
+
+/**
+ * scic_sds_port_ready_substate_configuring_enter() -
+ * @object: This is the struct sci_base_object which is cast to a struct scic_sds_port object.
+ *
+ * This method will perform the actions required by the struct scic_sds_port on
+ * exiting the SCIC_SDS_PORT_READY_SUBSTATE_OPERATIONAL. This function reports
+ * the port not ready and suspends the port task scheduler. none
+ */
+static void scic_sds_port_ready_substate_configuring_enter(
+ struct sci_base_object *object)
+{
+ struct scic_sds_port *this_port = (struct scic_sds_port *)object;
+
+ scic_sds_port_set_ready_state_handlers(
+ this_port, SCIC_SDS_PORT_READY_SUBSTATE_CONFIGURING
+ );
+
+ if (this_port->active_phy_mask == 0) {
+ scic_cb_port_not_ready(
+ scic_sds_port_get_controller(this_port),
+ this_port,
+ SCIC_PORT_NOT_READY_NO_ACTIVE_PHYS
+ );
+
+ sci_base_state_machine_change_state(
+ &this_port->ready_substate_machine,
+ SCIC_SDS_PORT_READY_SUBSTATE_WAITING
+ );
+ } else if (this_port->started_request_count == 0) {
+ sci_base_state_machine_change_state(
+ &this_port->ready_substate_machine,
+ SCIC_SDS_PORT_READY_SUBSTATE_OPERATIONAL
+ );
+ }
+}
+
+static void scic_sds_port_ready_substate_configuring_exit(
+ struct sci_base_object *object)
+{
+ struct scic_sds_port *this_port = (struct scic_sds_port *)object;
+
+ scic_sds_port_suspend_port_task_scheduler(this_port);
+}
+
+/* --------------------------------------------------------------------------- */
+
+const struct sci_base_state scic_sds_port_ready_substate_table[] = {
+ [SCIC_SDS_PORT_READY_SUBSTATE_WAITING] = {
+ .enter_state = scic_sds_port_ready_substate_waiting_enter,
+ },
+ [SCIC_SDS_PORT_READY_SUBSTATE_OPERATIONAL] = {
+ .enter_state = scic_sds_port_ready_substate_operational_enter,
+ .exit_state = scic_sds_port_ready_substate_operational_exit
+ },
+ [SCIC_SDS_PORT_READY_SUBSTATE_CONFIGURING] = {
+ .enter_state = scic_sds_port_ready_substate_configuring_enter,
+ .exit_state = scic_sds_port_ready_substate_configuring_exit
+ },
+};
+
+/*
+ * ***************************************************************************
+ * * DEFAULT HANDLERS
+ * *************************************************************************** */
+
+/**
+ *
+ * @port: This is the struct sci_base_port object which is cast into a struct scic_sds_port
+ * object.
+ *
+ * This is the default method for port a start request. It will report a
+ * warning and exit. enum sci_status SCI_FAILURE_INVALID_STATE
+ */
+enum sci_status scic_sds_port_default_start_handler(
+ struct sci_base_port *port)
+{
+ struct scic_sds_port *sci_port = (struct scic_sds_port *)port;
+
+ dev_warn(sciport_to_dev(sci_port),
+ "%s: SCIC Port 0x%p requested to start while in invalid "
+ "state %d\n",
+ __func__,
+ port,
+ sci_base_state_machine_get_state(
+ scic_sds_port_get_base_state_machine(
+ (struct scic_sds_port *)port)));
+
+ return SCI_FAILURE_INVALID_STATE;
+}
+
+/**
+ *
+ * @port: This is the struct sci_base_port object which is cast into a struct scic_sds_port
+ * object.
+ *
+ * This is the default method for a port stop request. It will report a
+ * warning and exit. enum sci_status SCI_FAILURE_INVALID_STATE
+ */
+static enum sci_status scic_sds_port_default_stop_handler(
+ struct sci_base_port *port)
+{
+ struct scic_sds_port *sci_port = (struct scic_sds_port *)port;
+
+ dev_warn(sciport_to_dev(sci_port),
+ "%s: SCIC Port 0x%p requested to stop while in invalid "
+ "state %d\n",
+ __func__,
+ port,
+ sci_base_state_machine_get_state(
+ scic_sds_port_get_base_state_machine(
+ (struct scic_sds_port *)port)));
+
+ return SCI_FAILURE_INVALID_STATE;
+}
+
+/**
+ *
+ * @port: This is the struct sci_base_port object which is cast into a struct scic_sds_port
+ * object.
+ *
+ * This is the default method for a port destruct request. It will report a
+ * warning and exit. enum sci_status SCI_FAILURE_INVALID_STATE
+ */
+enum sci_status scic_sds_port_default_destruct_handler(
+ struct sci_base_port *port)
+{
+ struct scic_sds_port *sci_port = (struct scic_sds_port *)port;
+
+ dev_warn(sciport_to_dev(sci_port),
+ "%s: SCIC Port 0x%p requested to destruct while in invalid "
+ "state %d\n",
+ __func__,
+ port,
+ sci_base_state_machine_get_state(
+ scic_sds_port_get_base_state_machine(
+ (struct scic_sds_port *)port)));
+
+ return SCI_FAILURE_INVALID_STATE;
+}
+
+/**
+ *
+ * @port: This is the struct sci_base_port object which is cast into a struct scic_sds_port
+ * object.
+ * @timeout: This is the timeout for the reset request to complete.
+ *
+ * This is the default method for a port reset request. It will report a
+ * warning and exit. enum sci_status SCI_FAILURE_INVALID_STATE
+ */
+enum sci_status scic_sds_port_default_reset_handler(
+ struct sci_base_port *port,
+ u32 timeout)
+{
+ struct scic_sds_port *sci_port = (struct scic_sds_port *)port;
+
+ dev_warn(sciport_to_dev(sci_port),
+ "%s: SCIC Port 0x%p requested to reset while in invalid "
+ "state %d\n",
+ __func__,
+ port,
+ sci_base_state_machine_get_state(
+ scic_sds_port_get_base_state_machine(
+ (struct scic_sds_port *)port)));
+
+ return SCI_FAILURE_INVALID_STATE;
+}
+
+/**
+ *
+ * @port: This is the struct sci_base_port object which is cast into a struct scic_sds_port
+ * object.
+ *
+ * This is the default method for a port add phy request. It will report a
+ * warning and exit. enum sci_status SCI_FAILURE_INVALID_STATE
+ */
+static enum sci_status scic_sds_port_default_add_phy_handler(
+ struct sci_base_port *port,
+ struct sci_base_phy *phy)
+{
+ struct scic_sds_port *sci_port = (struct scic_sds_port *)port;
+
+ dev_warn(sciport_to_dev(sci_port),
+ "%s: SCIC Port 0x%p requested to add phy 0x%p while in "
+ "invalid state %d\n",
+ __func__,
+ port,
+ phy,
+ sci_base_state_machine_get_state(
+ scic_sds_port_get_base_state_machine(
+ (struct scic_sds_port *)port)));
+
+ return SCI_FAILURE_INVALID_STATE;
+}
+
+/**
+ *
+ * @port: This is the struct sci_base_port object which is cast into a struct scic_sds_port
+ * object.
+ *
+ * This is the default method for a port remove phy request. It will report a
+ * warning and exit. enum sci_status SCI_FAILURE_INVALID_STATE
+ */
+enum sci_status scic_sds_port_default_remove_phy_handler(
+ struct sci_base_port *port,
+ struct sci_base_phy *phy)
+{
+ struct scic_sds_port *sci_port = (struct scic_sds_port *)port;
+
+ dev_warn(sciport_to_dev(sci_port),
+ "%s: SCIC Port 0x%p requested to remove phy 0x%p while in "
+ "invalid state %d\n",
+ __func__,
+ port,
+ phy,
+ sci_base_state_machine_get_state(
+ scic_sds_port_get_base_state_machine(
+ (struct scic_sds_port *)port)));
+
+ return SCI_FAILURE_INVALID_STATE;
+}
+
+/**
+ *
+ * @port: This is the struct sci_base_port object which is cast into a struct scic_sds_port
+ * object.
+ *
+ * This is the default method for a port unsolicited frame request. It will
+ * report a warning and exit. enum sci_status SCI_FAILURE_INVALID_STATE Is it even
+ * possible to receive an unsolicited frame directed to a port object? It
+ * seems possible if we implementing virtual functions but until then?
+ */
+enum sci_status scic_sds_port_default_frame_handler(
+ struct scic_sds_port *port,
+ u32 frame_index)
+{
+ dev_warn(sciport_to_dev(port),
+ "%s: SCIC Port 0x%p requested to process frame %d while in "
+ "invalid state %d\n",
+ __func__,
+ port,
+ frame_index,
+ sci_base_state_machine_get_state(
+ scic_sds_port_get_base_state_machine(port)));
+
+ scic_sds_controller_release_frame(
+ scic_sds_port_get_controller(port), frame_index
+ );
+
+ return SCI_FAILURE_INVALID_STATE;
+}
+
+/**
+ *
+ * @port: This is the struct sci_base_port object which is cast into a struct scic_sds_port
+ * object.
+ *
+ * This is the default method for a port event request. It will report a
+ * warning and exit. enum sci_status SCI_FAILURE_INVALID_STATE
+ */
+enum sci_status scic_sds_port_default_event_handler(
+ struct scic_sds_port *port,
+ u32 event_code)
+{
+ dev_warn(sciport_to_dev(port),
+ "%s: SCIC Port 0x%p requested to process event 0x%x while "
+ "in invalid state %d\n",
+ __func__,
+ port,
+ event_code,
+ sci_base_state_machine_get_state(
+ scic_sds_port_get_base_state_machine(
+ (struct scic_sds_port *)port)));
+
+ return SCI_FAILURE_INVALID_STATE;
+}
+
+/**
+ *
+ * @port: This is the struct sci_base_port object which is cast into a struct scic_sds_port
+ * object.
+ *
+ * This is the default method for a port link up notification. It will report
+ * a warning and exit. enum sci_status SCI_FAILURE_INVALID_STATE
+ */
+void scic_sds_port_default_link_up_handler(
+ struct scic_sds_port *this_port,
+ struct scic_sds_phy *phy)
+{
+ dev_warn(sciport_to_dev(this_port),
+ "%s: SCIC Port 0x%p received link_up notification from phy "
+ "0x%p while in invalid state %d\n",
+ __func__,
+ this_port,
+ phy,
+ sci_base_state_machine_get_state(
+ scic_sds_port_get_base_state_machine(this_port)));
+}
+
+/**
+ *
+ * @port: This is the struct sci_base_port object which is cast into a struct scic_sds_port
+ * object.
+ *
+ * This is the default method for a port link down notification. It will
+ * report a warning and exit. enum sci_status SCI_FAILURE_INVALID_STATE
+ */
+void scic_sds_port_default_link_down_handler(
+ struct scic_sds_port *this_port,
+ struct scic_sds_phy *phy)
+{
+ dev_warn(sciport_to_dev(this_port),
+ "%s: SCIC Port 0x%p received link down notification from "
+ "phy 0x%p while in invalid state %d\n",
+ __func__,
+ this_port,
+ phy,
+ sci_base_state_machine_get_state(
+ scic_sds_port_get_base_state_machine(this_port)));
+}
+
+/**
+ *
+ * @port: This is the struct sci_base_port object which is cast into a struct scic_sds_port
+ * object.
+ *
+ * This is the default method for a port start io request. It will report a
+ * warning and exit. enum sci_status SCI_FAILURE_INVALID_STATE
+ */
+enum sci_status scic_sds_port_default_start_io_handler(
+ struct scic_sds_port *this_port,
+ struct scic_sds_remote_device *device,
+ struct scic_sds_request *io_request)
+{
+ dev_warn(sciport_to_dev(this_port),
+ "%s: SCIC Port 0x%p requested to start io request 0x%p "
+ "while in invalid state %d\n",
+ __func__,
+ this_port,
+ io_request,
+ sci_base_state_machine_get_state(
+ scic_sds_port_get_base_state_machine(this_port)));
+
+ return SCI_FAILURE_INVALID_STATE;
+}
+
+/**
+ *
+ * @port: This is the struct sci_base_port object which is cast into a struct scic_sds_port
+ * object.
+ *
+ * This is the default method for a port complete io request. It will report a
+ * warning and exit. enum sci_status SCI_FAILURE_INVALID_STATE
+ */
+static enum sci_status scic_sds_port_default_complete_io_handler(
+ struct scic_sds_port *this_port,
+ struct scic_sds_remote_device *device,
+ struct scic_sds_request *io_request)
+{
+ dev_warn(sciport_to_dev(this_port),
+ "%s: SCIC Port 0x%p requested to complete io request 0x%p "
+ "while in invalid state %d\n",
+ __func__,
+ this_port,
+ io_request,
+ sci_base_state_machine_get_state(
+ scic_sds_port_get_base_state_machine(this_port)));
+
+ return SCI_FAILURE_INVALID_STATE;
+}
+
+/*
+ * ****************************************************************************
+ * * GENERAL STATE HANDLERS
+ * **************************************************************************** */
+
+/**
+ *
+ * @port: This is the struct scic_sds_port object on which the io request count will
+ * be decremented.
+ * @device: This is the struct scic_sds_remote_device object to which the io request
+ * is being directed. This parameter is not required to complete this
+ * operation.
+ * @io_request: This is the request that is being completed on this port
+ * object. This parameter is not required to complete this operation.
+ *
+ * This is a general complete io request handler for the struct scic_sds_port object.
+ * enum sci_status SCI_SUCCESS
+ */
+static enum sci_status scic_sds_port_general_complete_io_handler(
+ struct scic_sds_port *port,
+ struct scic_sds_remote_device *device,
+ struct scic_sds_request *io_request)
+{
+ struct scic_sds_port *this_port = (struct scic_sds_port *)port;
+
+ scic_sds_port_decrement_request_count(this_port);
+
+ return SCI_SUCCESS;
+}
+
+/*
+ * ****************************************************************************
+ * * STOPPED STATE HANDLERS
+ * **************************************************************************** */
+
+/**
+ *
+ * @port: This is the struct sci_base_port object which is cast into a struct scic_sds_port
+ * object.
+ *
+ * This method takes the struct scic_sds_port from a stopped state and attempts to
+ * start it. To start a port it must have no assiged devices and it must have
+ * at least one phy assigned to it. If those conditions are met then the port
+ * can transition to the ready state. enum sci_status
+ * SCI_FAILURE_UNSUPPORTED_PORT_CONFIGURATION This struct scic_sds_port object could
+ * not be started because the port configuration is not valid. SCI_SUCCESS the
+ * start request is successful and the struct scic_sds_port object has transitioned to
+ * the SCI_BASE_PORT_STATE_READY.
+ */
+static enum sci_status scic_sds_port_stopped_state_start_handler(
+ struct sci_base_port *port)
+{
+ u32 phy_mask;
+ struct scic_sds_port *this_port = (struct scic_sds_port *)port;
+
+ if (this_port->assigned_device_count > 0) {
+ /*
+ * / @todo This is a start failure operation because there are still
+ * / devices assigned to this port. There must be no devices
+ * / assigned to a port on a start operation. */
+ return SCI_FAILURE_UNSUPPORTED_PORT_CONFIGURATION;
+ }
+
+ phy_mask = scic_sds_port_get_phys(this_port);
+
+ /*
+ * There are one or more phys assigned to this port. Make sure
+ * the port's phy mask is in fact legal and supported by the
+ * silicon. */
+ if (scic_sds_port_is_phy_mask_valid(this_port, phy_mask) == true) {
+ sci_base_state_machine_change_state(
+ scic_sds_port_get_base_state_machine(this_port),
+ SCI_BASE_PORT_STATE_READY
+ );
+
+ return SCI_SUCCESS;
+ }
+
+ return SCI_FAILURE_UNSUPPORTED_PORT_CONFIGURATION;
+}
+
+/**
+ *
+ * @port: This is the struct sci_base_port object which is cast into a struct scic_sds_port
+ * object.
+ *
+ * This method takes the struct scic_sds_port that is in a stopped state and handles a
+ * stop request. This function takes no action. enum sci_status SCI_SUCCESS the
+ * stop request is successful as the struct scic_sds_port object is already stopped.
+ */
+static enum sci_status scic_sds_port_stopped_state_stop_handler(
+ struct sci_base_port *port)
+{
+ /* We are already stopped so there is nothing to do here */
+ return SCI_SUCCESS;
+}
+
+/**
+ *
+ * @port: This is the struct sci_base_port object which is cast into a struct scic_sds_port
+ * object.
+ *
+ * This method takes the struct scic_sds_port that is in a stopped state and handles
+ * the destruct request. The stopped state is the only state in which the
+ * struct scic_sds_port can be destroyed. This function causes the port object to
+ * transition to the SCI_BASE_PORT_STATE_FINAL. enum sci_status SCI_SUCCESS
+ */
+static enum sci_status scic_sds_port_stopped_state_destruct_handler(
+ struct sci_base_port *port)
+{
+ struct scic_sds_port *this_port = (struct scic_sds_port *)port;
+
+ sci_base_state_machine_stop(&this_port->parent.state_machine);
+
+ return SCI_SUCCESS;
+}
+
+/**
+ *
+ * @port: This is the struct sci_base_port object which is cast into a struct scic_sds_port
+ * object.
+ * @phy: This is the struct sci_base_phy object which is cast into a struct scic_sds_phy
+ * object.
+ *
+ * This method takes the struct scic_sds_port that is in a stopped state and handles
+ * the add phy request. In MPC mode the only time a phy can be added to a port
+ * is in the SCI_BASE_PORT_STATE_STOPPED. enum sci_status
+ * SCI_FAILURE_UNSUPPORTED_PORT_CONFIGURATION is returned when the phy can not
+ * be added to the port. SCI_SUCCESS if the phy is added to the port.
+ */
+static enum sci_status scic_sds_port_stopped_state_add_phy_handler(
+ struct sci_base_port *port,
+ struct sci_base_phy *phy)
+{
+ struct scic_sds_port *this_port = (struct scic_sds_port *)port;
+ struct scic_sds_phy *this_phy = (struct scic_sds_phy *)phy;
+ struct sci_sas_address port_sas_address;
+
+ /* Read the port assigned SAS Address if there is one */
+ scic_sds_port_get_sas_address(this_port, &port_sas_address);
+
+ if (port_sas_address.high != 0 && port_sas_address.low != 0) {
+ struct sci_sas_address phy_sas_address;
+
+ /*
+ * Make sure that the PHY SAS Address matches the SAS Address
+ * for this port. */
+ scic_sds_phy_get_sas_address(this_phy, &phy_sas_address);
+
+ if (
+ (port_sas_address.high != phy_sas_address.high)
+ || (port_sas_address.low != phy_sas_address.low)
+ ) {
+ return SCI_FAILURE_UNSUPPORTED_PORT_CONFIGURATION;
+ }
+ }
+
+ return scic_sds_port_set_phy(this_port, this_phy);
+}
+
+
+/**
+ *
+ * @port: This is the struct sci_base_port object which is cast into a struct scic_sds_port
+ * object.
+ * @phy: This is the struct sci_base_phy object which is cast into a struct scic_sds_phy
+ * object.
+ *
+ * This method takes the struct scic_sds_port that is in a stopped state and handles
+ * the remove phy request. In MPC mode the only time a phy can be removed from
+ * a port is in the SCI_BASE_PORT_STATE_STOPPED. enum sci_status
+ * SCI_FAILURE_UNSUPPORTED_PORT_CONFIGURATION is returned when the phy can not
+ * be added to the port. SCI_SUCCESS if the phy is added to the port.
+ */
+static enum sci_status scic_sds_port_stopped_state_remove_phy_handler(
+ struct sci_base_port *port,
+ struct sci_base_phy *phy)
+{
+ struct scic_sds_port *this_port = (struct scic_sds_port *)port;
+ struct scic_sds_phy *this_phy = (struct scic_sds_phy *)phy;
+
+ return scic_sds_port_clear_phy(this_port, this_phy);
+}
+
+/*
+ * ****************************************************************************
+ * * READY STATE HANDLERS
+ * **************************************************************************** */
+
+/*
+ * ****************************************************************************
+ * * RESETTING STATE HANDLERS
+ * **************************************************************************** */
+
+/*
+ * ****************************************************************************
+ * * STOPPING STATE HANDLERS
+ * **************************************************************************** */
+
+/**
+ *
+ * @port: This is the struct scic_sds_port object on which the io request count will
+ * be decremented.
+ * @device: This is the struct scic_sds_remote_device object to which the io request
+ * is being directed. This parameter is not required to complete this
+ * operation.
+ * @io_request: This is the request that is being completed on this port
+ * object. This parameter is not required to complete this operation.
+ *
+ * This method takes the struct scic_sds_port that is in a stopping state and handles
+ * the complete io request. Should the request count reach 0 then the port
+ * object will transition to the stopped state. enum sci_status SCI_SUCCESS
+ */
+static enum sci_status scic_sds_port_stopping_state_complete_io_handler(
+ struct scic_sds_port *port,
+ struct scic_sds_remote_device *device,
+ struct scic_sds_request *io_request)
+{
+ struct scic_sds_port *this_port = (struct scic_sds_port *)port;
+
+ scic_sds_port_decrement_request_count(this_port);
+
+ if (this_port->started_request_count == 0) {
+ sci_base_state_machine_change_state(
+ scic_sds_port_get_base_state_machine(this_port),
+ SCI_BASE_PORT_STATE_STOPPED
+ );
+ }
+
+ return SCI_SUCCESS;
+}
+
+/*
+ * ****************************************************************************
+ * * RESETTING STATE HANDLERS
+ * **************************************************************************** */
+
+/**
+ *
+ * @port: This is the port object which is being requested to stop.
+ *
+ * This method will stop a failed port. This causes a transition to the
+ * stopping state. enum sci_status SCI_SUCCESS
+ */
+static enum sci_status scic_sds_port_reset_state_stop_handler(
+ struct sci_base_port *port)
+{
+ struct scic_sds_port *this_port = (struct scic_sds_port *)port;
+
+ sci_base_state_machine_change_state(
+ &this_port->parent.state_machine,
+ SCI_BASE_PORT_STATE_STOPPING
+ );
+
+ return SCI_SUCCESS;
+}
+
+/**
+ *
+ * @port: This is the struct sci_base_port object which is cast into a struct scic_sds_port
+ * object.
+ *
+ * This method will transition a failed port to its ready state. The port
+ * failed because a hard reset request timed out but at some time later one or
+ * more phys in the port became ready. enum sci_status SCI_SUCCESS
+ */
+static void scic_sds_port_reset_state_link_up_handler(
+ struct scic_sds_port *this_port,
+ struct scic_sds_phy *phy)
+{
+ /*
+ * / @todo We should make sure that the phy that has gone link up is the same
+ * / one on which we sent the reset. It is possible that the phy on
+ * / which we sent the reset is not the one that has gone link up and we
+ * / want to make sure that phy being reset comes back. Consider the
+ * / case where a reset is sent but before the hardware processes the
+ * / reset it get a link up on the port because of a hot plug event.
+ * / because of the reset request this phy will go link down almost
+ * / immediately. */
+
+ /*
+ * In the resetting state we don't notify the user regarding
+ * link up and link down notifications. */
+ scic_sds_port_general_link_up_handler(this_port, phy, false);
+}
+
+/**
+ *
+ * @port: This is the struct sci_base_port object which is cast into a struct scic_sds_port
+ * object.
+ *
+ * This method process link down notifications that occur during a port reset
+ * operation. Link downs can occur during the reset operation. enum sci_status
+ * SCI_SUCCESS
+ */
+static void scic_sds_port_reset_state_link_down_handler(
+ struct scic_sds_port *this_port,
+ struct scic_sds_phy *phy)
+{
+ /*
+ * In the resetting state we don't notify the user regarding
+ * link up and link down notifications. */
+ scic_sds_port_deactivate_phy(this_port, phy, false);
+}
+
+/* --------------------------------------------------------------------------- */
+
+struct scic_sds_port_state_handler
+scic_sds_port_state_handler_table[SCI_BASE_PORT_MAX_STATES] =
+{
+ /* SCI_BASE_PORT_STATE_STOPPED */
+ {
+ {
+ scic_sds_port_stopped_state_start_handler,
+ scic_sds_port_stopped_state_stop_handler,
+ scic_sds_port_stopped_state_destruct_handler,
+ scic_sds_port_default_reset_handler,
+ scic_sds_port_stopped_state_add_phy_handler,
+ scic_sds_port_stopped_state_remove_phy_handler
+ },
+ scic_sds_port_default_frame_handler,
+ scic_sds_port_default_event_handler,
+ scic_sds_port_default_link_up_handler,
+ scic_sds_port_default_link_down_handler,
+ scic_sds_port_default_start_io_handler,
+ scic_sds_port_default_complete_io_handler
+ },
+ /* SCI_BASE_PORT_STATE_STOPPING */
+ {
+ {
+ scic_sds_port_default_start_handler,
+ scic_sds_port_default_stop_handler,
+ scic_sds_port_default_destruct_handler,
+ scic_sds_port_default_reset_handler,
+ scic_sds_port_default_add_phy_handler,
+ scic_sds_port_default_remove_phy_handler
+ },
+ scic_sds_port_default_frame_handler,
+ scic_sds_port_default_event_handler,
+ scic_sds_port_default_link_up_handler,
+ scic_sds_port_default_link_down_handler,
+ scic_sds_port_default_start_io_handler,
+ scic_sds_port_stopping_state_complete_io_handler
+ },
+ /* SCI_BASE_PORT_STATE_READY */
+ {
+ {
+ scic_sds_port_default_start_handler,
+ scic_sds_port_default_stop_handler,
+ scic_sds_port_default_destruct_handler,
+ scic_sds_port_default_reset_handler,
+ scic_sds_port_default_add_phy_handler,
+ scic_sds_port_default_remove_phy_handler
+ },
+ scic_sds_port_default_frame_handler,
+ scic_sds_port_default_event_handler,
+ scic_sds_port_default_link_up_handler,
+ scic_sds_port_default_link_down_handler,
+ scic_sds_port_default_start_io_handler,
+ scic_sds_port_general_complete_io_handler
+ },
+ /* SCI_BASE_PORT_STATE_RESETTING */
+ {
+ {
+ scic_sds_port_default_start_handler,
+ scic_sds_port_reset_state_stop_handler,
+ scic_sds_port_default_destruct_handler,
+ scic_sds_port_default_reset_handler,
+ scic_sds_port_default_add_phy_handler,
+ scic_sds_port_default_remove_phy_handler
+ },
+ scic_sds_port_default_frame_handler,
+ scic_sds_port_default_event_handler,
+ scic_sds_port_reset_state_link_up_handler,
+ scic_sds_port_reset_state_link_down_handler,
+ scic_sds_port_default_start_io_handler,
+ scic_sds_port_general_complete_io_handler
+ },
+ /* SCI_BASE_PORT_STATE_FAILED */
+ {
+ {
+ scic_sds_port_default_start_handler,
+ scic_sds_port_default_stop_handler,
+ scic_sds_port_default_destruct_handler,
+ scic_sds_port_default_reset_handler,
+ scic_sds_port_default_add_phy_handler,
+ scic_sds_port_default_remove_phy_handler
+ },
+ scic_sds_port_default_frame_handler,
+ scic_sds_port_default_event_handler,
+ scic_sds_port_default_link_up_handler,
+ scic_sds_port_default_link_down_handler,
+ scic_sds_port_default_start_io_handler,
+ scic_sds_port_general_complete_io_handler
+ }
+};
+
+/*
+ * ******************************************************************************
+ * * PORT STATE PRIVATE METHODS
+ * ****************************************************************************** */
+
+/**
+ *
+ * @this_port: This is the port object which to suspend.
+ *
+ * This method will enable the SCU Port Task Scheduler for this port object but
+ * will leave the port task scheduler in a suspended state. none
+ */
+static void scic_sds_port_enable_port_task_scheduler(
+ struct scic_sds_port *this_port)
+{
+ u32 pts_control_value;
+
+ pts_control_value = scu_port_task_scheduler_read(this_port, control);
+
+ pts_control_value |= SCU_PTSxCR_GEN_BIT(ENABLE) | SCU_PTSxCR_GEN_BIT(SUSPEND);
+
+ scu_port_task_scheduler_write(this_port, control, pts_control_value);
+}
+
+/**
+ *
+ * @this_port: This is the port object which to resume.
+ *
+ * This method will disable the SCU port task scheduler for this port object.
+ * none
+ */
+static void scic_sds_port_disable_port_task_scheduler(
+ struct scic_sds_port *this_port)
+{
+ u32 pts_control_value;
+
+ pts_control_value = scu_port_task_scheduler_read(this_port, control);
+
+ pts_control_value &= ~(SCU_PTSxCR_GEN_BIT(ENABLE)
+ | SCU_PTSxCR_GEN_BIT(SUSPEND));
+
+ scu_port_task_scheduler_write(this_port, control, pts_control_value);
+}
+
+/*
+ * ******************************************************************************
+ * * PORT STATE METHODS
+ * ****************************************************************************** */
+
+/**
+ *
+ * @object: This is the struct sci_base_object which is cast to a struct scic_sds_port object.
+ *
+ * This method will perform the actions required by the struct scic_sds_port on
+ * entering the SCI_BASE_PORT_STATE_STOPPED. This function sets the stopped
+ * state handlers for the struct scic_sds_port object and disables the port task
+ * scheduler in the hardware. none
+ */
+static void scic_sds_port_stopped_state_enter(
+ struct sci_base_object *object)
+{
+ struct scic_sds_port *this_port;
+
+ this_port = (struct scic_sds_port *)object;
+
+ scic_sds_port_set_base_state_handlers(
+ this_port, SCI_BASE_PORT_STATE_STOPPED
+ );
+
+ if (
+ SCI_BASE_PORT_STATE_STOPPING
+ == this_port->parent.state_machine.previous_state_id
+ ) {
+ /*
+ * If we enter this state becasuse of a request to stop
+ * the port then we want to disable the hardwares port
+ * task scheduler. */
+ scic_sds_port_disable_port_task_scheduler(this_port);
+ }
+}
+
+/**
+ *
+ * @object: This is the struct sci_base_object which is cast to a struct scic_sds_port object.
+ *
+ * This method will perform the actions required by the struct scic_sds_port on
+ * exiting the SCI_BASE_STATE_STOPPED. This function enables the SCU hardware
+ * port task scheduler. none
+ */
+static void scic_sds_port_stopped_state_exit(
+ struct sci_base_object *object)
+{
+ struct scic_sds_port *this_port;
+
+ this_port = (struct scic_sds_port *)object;
+
+ /* Enable and suspend the port task scheduler */
+ scic_sds_port_enable_port_task_scheduler(this_port);
+}
+
+/**
+ *
+ * @object: This is the struct sci_base_object which is cast to a struct scic_sds_port object.
+ *
+ * This method will perform the actions required by the struct scic_sds_port on
+ * entering the SCI_BASE_PORT_STATE_READY. This function sets the ready state
+ * handlers for the struct scic_sds_port object, reports the port object as not ready
+ * and starts the ready substate machine. none
+ */
+static void scic_sds_port_ready_state_enter(
+ struct sci_base_object *object)
+{
+ struct scic_sds_port *this_port;
+
+ this_port = (struct scic_sds_port *)object;
+
+ /* Put the ready state handlers in place though they will not be there long */
+ scic_sds_port_set_base_state_handlers(
+ this_port, SCI_BASE_PORT_STATE_READY
+ );
+
+ if (
+ SCI_BASE_PORT_STATE_RESETTING
+ == this_port->parent.state_machine.previous_state_id
+ ) {
+ scic_cb_port_hard_reset_complete(
+ scic_sds_port_get_controller(this_port),
+ this_port,
+ SCI_SUCCESS
+ );
+ } else {
+ /* Notify the caller that the port is not yet ready */
+ scic_cb_port_not_ready(
+ scic_sds_port_get_controller(this_port),
+ this_port,
+ SCIC_PORT_NOT_READY_NO_ACTIVE_PHYS
+ );
+ }
+
+ /* Start the ready substate machine */
+ sci_base_state_machine_start(
+ scic_sds_port_get_ready_substate_machine(this_port)
+ );
+}
+
+/**
+ *
+ * @object: This is the struct sci_base_object which is cast to a struct scic_sds_port object.
+ *
+ * This method will perform the actions required by the struct scic_sds_port on
+ * exiting the SCI_BASE_STATE_READY. This function does nothing. none
+ */
+static void scic_sds_port_ready_state_exit(
+ struct sci_base_object *object)
+{
+ struct scic_sds_port *this_port;
+
+ this_port = (struct scic_sds_port *)object;
+
+ sci_base_state_machine_stop(&this_port->ready_substate_machine);
+}
+
+/**
+ *
+ * @object: This is the struct sci_base_object which is cast to a struct scic_sds_port object.
+ *
+ * This method will perform the actions required by the struct scic_sds_port on
+ * entering the SCI_BASE_PORT_STATE_RESETTING. This function sets the resetting
+ * state handlers for the struct scic_sds_port object. none
+ */
+static void scic_sds_port_resetting_state_enter(
+ struct sci_base_object *object)
+{
+ struct scic_sds_port *this_port;
+
+ this_port = (struct scic_sds_port *)object;
+
+ scic_sds_port_set_base_state_handlers(
+ this_port, SCI_BASE_PORT_STATE_RESETTING
+ );
+
+ scic_sds_port_set_direct_attached_device_id(
+ this_port,
+ SCIC_SDS_REMOTE_NODE_CONTEXT_INVALID_INDEX
+ );
+}
+
+/**
+ *
+ * @object: This is the struct sci_base_object which is cast to a struct scic_sds_port object.
+ *
+ * This method will perform the actions required by the struct scic_sds_port on
+ * exiting the SCI_BASE_STATE_RESETTING. This function does nothing. none
+ */
+static void scic_sds_port_resetting_state_exit(
+ struct sci_base_object *object)
+{
+ struct scic_sds_port *this_port;
+
+ this_port = (struct scic_sds_port *)object;
+
+ scic_cb_timer_stop(
+ scic_sds_port_get_controller(this_port),
+ this_port->timer_handle
+ );
+}
+
+/**
+ *
+ * @object: This is the struct sci_base_object which is cast to a struct scic_sds_port object.
+ *
+ * This method will perform the actions required by the struct scic_sds_port on
+ * entering the SCI_BASE_PORT_STATE_STOPPING. This function sets the stopping
+ * state handlers for the struct scic_sds_port object. none
+ */
+static void scic_sds_port_stopping_state_enter(
+ struct sci_base_object *object)
+{
+ struct scic_sds_port *this_port;
+
+ this_port = (struct scic_sds_port *)object;
+
+ scic_sds_port_set_base_state_handlers(
+ this_port, SCI_BASE_PORT_STATE_STOPPING
+ );
+}
+
+/**
+ *
+ * @object: This is the struct sci_base_object which is cast to a struct scic_sds_port object.
+ *
+ * This method will perform the actions required by the struct scic_sds_port on
+ * exiting the SCI_BASE_STATE_STOPPING. This function does nothing. none
+ */
+static void scic_sds_port_stopping_state_exit(
+ struct sci_base_object *object)
+{
+ struct scic_sds_port *this_port;
+
+ this_port = (struct scic_sds_port *)object;
+
+ scic_cb_timer_stop(
+ scic_sds_port_get_controller(this_port),
+ this_port->timer_handle
+ );
+}
+
+/**
+ *
+ * @object: This is the struct sci_base_object which is cast to a struct scic_sds_port object.
+ *
+ * This method will perform the actions required by the struct scic_sds_port on
+ * entering the SCI_BASE_PORT_STATE_STOPPING. This function sets the stopping
+ * state handlers for the struct scic_sds_port object. none
+ */
+static void scic_sds_port_failed_state_enter(
+ struct sci_base_object *object)
+{
+ struct scic_sds_port *this_port;
+
+ this_port = (struct scic_sds_port *)object;
+
+ scic_sds_port_set_base_state_handlers(
+ this_port,
+ SCI_BASE_PORT_STATE_FAILED
+ );
+
+ scic_cb_port_hard_reset_complete(
+ scic_sds_port_get_controller(this_port),
+ this_port,
+ SCI_FAILURE_TIMEOUT
+ );
+}
+
+/* --------------------------------------------------------------------------- */
+
+const struct sci_base_state scic_sds_port_state_table[] = {
+ [SCI_BASE_PORT_STATE_STOPPED] = {
+ .enter_state = scic_sds_port_stopped_state_enter,
+ .exit_state = scic_sds_port_stopped_state_exit
+ },
+ [SCI_BASE_PORT_STATE_STOPPING] = {
+ .enter_state = scic_sds_port_stopping_state_enter,
+ .exit_state = scic_sds_port_stopping_state_exit
+ },
+ [SCI_BASE_PORT_STATE_READY] = {
+ .enter_state = scic_sds_port_ready_state_enter,
+ .exit_state = scic_sds_port_ready_state_exit
+ },
+ [SCI_BASE_PORT_STATE_RESETTING] = {
+ .enter_state = scic_sds_port_resetting_state_enter,
+ .exit_state = scic_sds_port_resetting_state_exit
+ },
+ [SCI_BASE_PORT_STATE_FAILED] = {
+ .enter_state = scic_sds_port_failed_state_enter,
+ }
+};
+
diff --git a/drivers/scsi/isci/core/scic_sds_port.h b/drivers/scsi/isci/core/scic_sds_port.h
new file mode 100644
index 000000000000..bbb9de5228ed
--- /dev/null
+++ b/drivers/scsi/isci/core/scic_sds_port.h
@@ -0,0 +1,514 @@
+/*
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Intel Corporation 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
+ * OWNER 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.
+ */
+
+#ifndef _SCIC_SDS_PORT_H_
+#define _SCIC_SDS_PORT_H_
+
+/**
+ * This file contains the structures, constants and prototypes for the
+ * struct scic_sds_port object.
+ *
+ *
+ */
+
+#include "sci_controller_constants.h"
+#include "intel_sas.h"
+#include "sci_base_port.h"
+#include "sci_base_phy.h"
+#include "scu_registers.h"
+
+#define SCIC_SDS_DUMMY_PORT 0xFF
+
+/**
+ * enum SCIC_SDS_PORT_READY_SUBSTATES -
+ *
+ * This enumeration depicts all of the states for the core port ready substate
+ * machine.
+ */
+enum SCIC_SDS_PORT_READY_SUBSTATES {
+ /**
+ * The substate where the port is started and ready but has no active phys.
+ */
+ SCIC_SDS_PORT_READY_SUBSTATE_WAITING,
+
+ /**
+ * The substate where the port is started and ready and there is at least one
+ * phy operational.
+ */
+ SCIC_SDS_PORT_READY_SUBSTATE_OPERATIONAL,
+
+ /**
+ * The substate where the port is started and there was an add/remove phy
+ * event. This state is only used in Automatic Port Configuration Mode (APC)
+ */
+ SCIC_SDS_PORT_READY_SUBSTATE_CONFIGURING,
+
+ SCIC_SDS_PORT_READY_MAX_SUBSTATES
+};
+
+struct scic_sds_controller;
+struct scic_sds_phy;
+struct scic_sds_remote_device;
+struct scic_sds_request;
+
+/**
+ * struct scic_sds_port -
+ *
+ * The core port object provides the the abstraction for an SCU port.
+ */
+struct scic_sds_port {
+ /**
+ * This field is the oommon base port object.
+ */
+ struct sci_base_port parent;
+
+ /**
+ * This field is the port index that is reported to the SCI USER. This allows
+ * the actual hardware physical port to change without the SCI USER getting a
+ * different answer for the get port index.
+ */
+ u8 logical_port_index;
+
+ /**
+ * This field is the port index used to program the SCU hardware.
+ */
+ u8 physical_port_index;
+
+ /**
+ * This field contains the active phy mask for the port. This mask is used in
+ * conjunction with the phy state to determine which phy to select for some
+ * port operations.
+ */
+ u8 active_phy_mask;
+
+ /**
+ * This field contains the count of the io requests started on this port
+ * object. It is used to control controller shutdown.
+ */
+ u32 started_request_count;
+
+ /**
+ * This field contains the number of devices assigned to this port. It is
+ * used to control port start requests.
+ */
+ u32 assigned_device_count;
+
+ /**
+ * This field contains the reason for the port not going ready. It is
+ * assigned in the state handlers and used in the state transition.
+ */
+ u32 not_ready_reason;
+
+ /**
+ * This field is the table of phys assigned to the port.
+ */
+ struct scic_sds_phy *phy_table[SCI_MAX_PHYS];
+
+ /**
+ * This field is a pointer back to the controller that owns this port object.
+ */
+ struct scic_sds_controller *owning_controller;
+
+ /**
+ * This field contains the port start/stop timer handle.
+ */
+ void *timer_handle;
+
+ /**
+ * This field points to the current set of state handlers for this port
+ * object. These state handlers are assigned at each enter state of the state
+ * machine.
+ */
+ struct scic_sds_port_state_handler *state_handlers;
+
+ /**
+ * This field is the ready substate machine for the port.
+ */
+ struct sci_base_state_machine ready_substate_machine;
+
+ /* / Memory mapped hardware register space */
+ /**
+ * This field is the pointer to the transport layer register for the SCU
+ * hardware.
+ */
+ struct scu_transport_layer_registers *transport_layer_registers;
+
+ /**
+ * This field is the pointer to the port task scheduler registers for the SCU
+ * hardware.
+ */
+ struct scu_port_task_scheduler_registers *port_task_scheduler_registers;
+
+ /**
+ * This field is identical for all port objects and points to the port task
+ * scheduler group PE configuration registers. It is used to assign PEs to a
+ * port.
+ */
+ SCU_PORT_PE_CONFIGURATION_REGISTER_T *port_pe_configuration_register;
+
+ /**
+ * This field is the VIIT register space for ths port object.
+ */
+ struct scu_viit_entry *viit_registers;
+
+};
+
+
+typedef enum sci_status (*SCIC_SDS_PORT_EVENT_HANDLER_T)(struct scic_sds_port *, u32);
+
+typedef enum sci_status (*SCIC_SDS_PORT_FRAME_HANDLER_T)(struct scic_sds_port *, u32);
+
+typedef void (*SCIC_SDS_PORT_LINK_HANDLER_T)(struct scic_sds_port *, struct scic_sds_phy *);
+
+typedef enum sci_status (*SCIC_SDS_PORT_IO_REQUEST_HANDLER_T)(
+ struct scic_sds_port *,
+ struct scic_sds_remote_device *,
+ struct scic_sds_request *);
+
+struct scic_sds_port_state_handler {
+ struct sci_base_port_state_handler parent;
+
+ SCIC_SDS_PORT_FRAME_HANDLER_T frame_handler;
+ SCIC_SDS_PORT_EVENT_HANDLER_T event_handler;
+
+ SCIC_SDS_PORT_LINK_HANDLER_T link_up_handler;
+ SCIC_SDS_PORT_LINK_HANDLER_T link_down_handler;
+
+ SCIC_SDS_PORT_IO_REQUEST_HANDLER_T start_io_handler;
+ SCIC_SDS_PORT_IO_REQUEST_HANDLER_T complete_io_handler;
+
+};
+
+extern const struct sci_base_state scic_sds_port_state_table[];
+extern const struct sci_base_state scic_sds_port_ready_substate_table[];
+
+extern struct scic_sds_port_state_handler scic_sds_port_state_handler_table[];
+extern struct scic_sds_port_state_handler scic_sds_port_ready_substate_handler_table[];
+
+/**
+ * scic_sds_port_get_controller() -
+ *
+ * Helper macro to get the owning controller of this port
+ */
+#define scic_sds_port_get_controller(this_port) \
+ ((this_port)->owning_controller)
+
+/**
+ * scic_sds_port_get_base_state_machine() -
+ *
+ * Helper macro to get the base state machine for this port
+ */
+#define scic_sds_port_get_base_state_machine(this_port) \
+ (&(this_port)->parent.state_machine)
+
+/**
+ * scic_sds_port_set_base_state_handlers() -
+ *
+ * This macro will change the state handlers to those of the specified state id
+ */
+#define scic_sds_port_set_base_state_handlers(this_port, state_id) \
+ scic_sds_port_set_state_handlers(\
+ (this_port), &scic_sds_port_state_handler_table[(state_id)])
+
+/**
+ * scic_sds_port_get_ready_substate_machine() -
+ *
+ * Helper macro to get the ready substate machine for this port
+ */
+#define scic_sds_port_get_ready_substate_machine(this_port) \
+ (&(this_port)->ready_substate_machine)
+
+/**
+ * scic_sds_port_set_state_handlers() -
+ *
+ * Helper macro to set the port object state handlers
+ */
+#define scic_sds_port_set_state_handlers(this_port, handlers) \
+ ((this_port)->state_handlers = (handlers))
+
+/**
+ * scic_sds_port_get_index() -
+ *
+ * This macro returns the physical port index for this port object
+ */
+#define scic_sds_port_get_index(this_port) \
+ ((this_port)->physical_port_index)
+
+/**
+ * scic_sds_port_increment_request_count() -
+ *
+ * Helper macro to increment the started request count
+ */
+#define scic_sds_port_increment_request_count(this_port) \
+ ((this_port)->started_request_count++)
+
+#ifdef SCIC_DEBUG_ENABLED
+/**
+ * scic_sds_port_decrement_request_count() - This method decrements the started
+ * io request count. The method will not decrment the started io request
+ * count below 0 and will log a debug message if this is attempted.
+ *
+ *
+ */
+void scic_sds_port_decrement_request_count(
+ struct scic_sds_port *this_port);
+#else
+/**
+ * scic_sds_port_decrement_request_count() -
+ *
+ * Helper macro to decrement the started io request count. The macro will not
+ * decrement the started io request count below 0.
+ */
+#define scic_sds_port_decrement_request_count(this_port) \
+ (\
+ (this_port)->started_request_count = (\
+ ((this_port)->started_request_count == 0) ? \
+ (this_port)->started_request_count : \
+ ((this_port)->started_request_count - 1) \
+ ) \
+ )
+#endif
+
+/**
+ * scic_sds_port_write_phy_assignment() -
+ *
+ * Helper macro to write the phys port assignment
+ */
+#define scic_sds_port_write_phy_assignment(port, phy) \
+ SCU_PCSPExCR_WRITE(\
+ (port), \
+ (phy)->phy_index, \
+ (port)->physical_port_index \
+ )
+
+/**
+ * scic_sds_port_read_phy_assignment() -
+ *
+ * Helper macro to read the phys port assignment
+ */
+#define scic_sds_port_read_phy_assignment(port, phy) \
+ SCU_PCSPExCR_READ(\
+ (port), \
+ (phy)->phy_index \
+ )
+
+#define scic_sds_port_active_phy(port, phy) \
+ (((port)->active_phy_mask & (1 << (phy)->phy_index)) != 0)
+
+/* --------------------------------------------------------------------------- */
+
+
+
+
+/* --------------------------------------------------------------------------- */
+
+/* --------------------------------------------------------------------------- */
+
+void scic_sds_port_construct(
+ struct scic_sds_port *this_port,
+ u8 port_index,
+ struct scic_sds_controller *owning_controller);
+
+enum sci_status scic_sds_port_initialize(
+ struct scic_sds_port *this_port,
+ void *transport_layer_registers,
+ void *port_task_scheduler_registers,
+ void *port_configuration_regsiter,
+ void *viit_registers);
+
+/* --------------------------------------------------------------------------- */
+
+enum sci_status scic_sds_port_add_phy(
+ struct scic_sds_port *this_port,
+ struct scic_sds_phy *the_phy);
+
+enum sci_status scic_sds_port_remove_phy(
+ struct scic_sds_port *this_port,
+ struct scic_sds_phy *the_phy);
+
+void scic_sds_port_set_direct_attached_device_id(
+ struct scic_sds_port *this_port,
+ u32 device_id);
+
+void scic_sds_port_activate_phy(
+ struct scic_sds_port *this_port,
+ struct scic_sds_phy *phy,
+ bool do_notify_user);
+
+void scic_sds_port_deactivate_phy(
+ struct scic_sds_port *this_port,
+ struct scic_sds_phy *phy,
+ bool do_notify_user);
+
+
+
+void scic_sds_port_general_link_up_handler(
+ struct scic_sds_port *this_port,
+ struct scic_sds_phy *the_phy,
+ bool do_notify_user);
+
+bool scic_sds_port_link_detected(
+ struct scic_sds_port *this_port,
+ struct scic_sds_phy *phy);
+
+void scic_sds_port_link_up(
+ struct scic_sds_port *this_port,
+ struct scic_sds_phy *phy);
+
+void scic_sds_port_link_down(
+ struct scic_sds_port *this_port,
+ struct scic_sds_phy *phy);
+
+/* --------------------------------------------------------------------------- */
+
+
+/* --------------------------------------------------------------------------- */
+
+enum sci_status scic_sds_port_start_io(
+ struct scic_sds_port *this_port,
+ struct scic_sds_remote_device *the_device,
+ struct scic_sds_request *the_io_request);
+
+enum sci_status scic_sds_port_complete_io(
+ struct scic_sds_port *this_port,
+ struct scic_sds_remote_device *the_device,
+ struct scic_sds_request *the_io_request);
+
+/* --------------------------------------------------------------------------- */
+
+void scic_sds_port_update_viit_entry(
+ struct scic_sds_port *this_port);
+
+/* --------------------------------------------------------------------------- */
+
+enum sci_status scic_sds_port_default_start_handler(
+ struct sci_base_port *port);
+
+
+enum sci_status scic_sds_port_default_destruct_handler(
+ struct sci_base_port *port);
+
+enum sci_status scic_sds_port_default_reset_handler(
+ struct sci_base_port *port,
+ u32 timeout);
+
+
+enum sci_status scic_sds_port_default_remove_phy_handler(
+ struct sci_base_port *port,
+ struct sci_base_phy *phy);
+
+enum sci_status scic_sds_port_default_frame_handler(
+ struct scic_sds_port *port,
+ u32 frame_index);
+
+enum sci_status scic_sds_port_default_event_handler(
+ struct scic_sds_port *port,
+ u32 event_code);
+
+void scic_sds_port_default_link_up_handler(
+ struct scic_sds_port *this_port,
+ struct scic_sds_phy *phy);
+
+void scic_sds_port_default_link_down_handler(
+ struct scic_sds_port *this_port,
+ struct scic_sds_phy *phy);
+
+enum sci_status scic_sds_port_default_start_io_handler(
+ struct scic_sds_port *port,
+ struct scic_sds_remote_device *device,
+ struct scic_sds_request *io_request);
+
+
+enum sci_sas_link_rate scic_sds_port_get_max_allowed_speed(
+ struct scic_sds_port *this_port);
+
+void scic_sds_port_broadcast_change_received(
+ struct scic_sds_port *this_port,
+ struct scic_sds_phy *this_phy);
+
+bool scic_sds_port_is_valid_phy_assignment(
+ struct scic_sds_port *this_port,
+ u32 phy_index);
+
+bool scic_sds_port_is_phy_mask_valid(
+ struct scic_sds_port *this_port,
+ u32 phy_mask);
+
+u32 scic_sds_port_get_phys(
+ struct scic_sds_port *this_port);
+
+void scic_sds_port_get_sas_address(
+ struct scic_sds_port *this_port,
+ struct sci_sas_address *sas_address);
+
+void scic_sds_port_get_attached_sas_address(
+ struct scic_sds_port *this_port,
+ struct sci_sas_address *sas_address);
+
+void scic_sds_port_get_attached_protocols(
+ struct scic_sds_port *this_port,
+ struct sci_sas_identify_address_frame_protocols *protocols);
+
+enum sci_status scic_sds_port_set_phy(
+ struct scic_sds_port *port,
+ struct scic_sds_phy *phy);
+
+enum sci_status scic_sds_port_clear_phy(
+ struct scic_sds_port *port,
+ struct scic_sds_phy *phy);
+
+
+
+#endif /* _SCIC_SDS_PORT_H_ */
diff --git a/drivers/scsi/isci/core/scic_sds_port_configuration_agent.c b/drivers/scsi/isci/core/scic_sds_port_configuration_agent.c
new file mode 100644
index 000000000000..37d4469162a7
--- /dev/null
+++ b/drivers/scsi/isci/core/scic_sds_port_configuration_agent.c
@@ -0,0 +1,851 @@
+/*
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Intel Corporation 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
+ * OWNER 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.
+ */
+
+/**
+ * This file contains the implementation for the public and protected methods
+ * for the port configuration agent.
+ *
+ *
+ */
+
+#include "sci_environment.h"
+#include "scic_controller.h"
+#include "scic_sds_controller.h"
+#include "scic_sds_port_configuration_agent.h"
+
+#define SCIC_SDS_MPC_RECONFIGURATION_TIMEOUT (10)
+#define SCIC_SDS_APC_RECONFIGURATION_TIMEOUT (10)
+#define SCIC_SDS_APC_WAIT_LINK_UP_NOTIFICATION (100)
+
+enum SCIC_SDS_APC_ACTIVITY {
+ SCIC_SDS_APC_SKIP_PHY,
+ SCIC_SDS_APC_ADD_PHY,
+ SCIC_SDS_APC_START_TIMER,
+
+ SCIC_SDS_APC_ACTIVITY_MAX
+};
+
+/*
+ * ******************************************************************************
+ * General port configuration agent routines
+ * ****************************************************************************** */
+
+/**
+ *
+ * @address_one: A SAS Address to be compared.
+ * @address_two: A SAS Address to be compared.
+ *
+ * Compare the two SAS Address and if SAS Address One is greater than SAS
+ * Address Two then return > 0 else if SAS Address One is less than SAS Address
+ * Two return < 0 Otherwise they are the same return 0 A signed value of x > 0
+ * > y where x is returned for Address One > Address Two y is returned for
+ * Address One < Address Two 0 is returned ofr Address One = Address Two
+ */
+static s32 sci_sas_address_compare(
+ struct sci_sas_address address_one,
+ struct sci_sas_address address_two)
+{
+ if (address_one.high > address_two.high) {
+ return 1;
+ } else if (address_one.high < address_two.high) {
+ return -1;
+ } else if (address_one.low > address_two.low) {
+ return 1;
+ } else if (address_one.low < address_two.low) {
+ return -1;
+ }
+
+ /* The two SAS Address must be identical */
+ return 0;
+}
+
+/**
+ *
+ * @controller: The controller object used for the port search.
+ * @phy: The phy object to match.
+ *
+ * This routine will find a matching port for the phy. This means that the
+ * port and phy both have the same broadcast sas address and same received sas
+ * address. The port address or the SCI_INVALID_HANDLE if there is no matching
+ * port. port address if the port can be found to match the phy.
+ * SCI_INVALID_HANDLE if there is no matching port for the phy.
+ */
+static struct scic_sds_port *scic_sds_port_configuration_agent_find_port(
+ struct scic_sds_controller *controller,
+ struct scic_sds_phy *phy)
+{
+ u8 port_index;
+ struct scic_sds_port *port_handle;
+ struct sci_sas_address port_sas_address;
+ struct sci_sas_address port_attached_device_address;
+ struct sci_sas_address phy_sas_address;
+ struct sci_sas_address phy_attached_device_address;
+
+ /*
+ * Since this phy can be a member of a wide port check to see if one or
+ * more phys match the sent and received SAS address as this phy in which
+ * case it should participate in the same port. */
+ scic_sds_phy_get_sas_address(phy, &phy_sas_address);
+ scic_sds_phy_get_attached_sas_address(phy, &phy_attached_device_address);
+
+ for (port_index = 0; port_index < SCI_MAX_PORTS; port_index++) {
+ if (scic_controller_get_port_handle(controller, port_index, &port_handle) == SCI_SUCCESS) {
+ struct scic_sds_port *port = (struct scic_sds_port *)port_handle;
+
+ scic_sds_port_get_sas_address(port, &port_sas_address);
+ scic_sds_port_get_attached_sas_address(port, &port_attached_device_address);
+
+ if (
+ (sci_sas_address_compare(port_sas_address, phy_sas_address) == 0)
+ && (sci_sas_address_compare(port_attached_device_address, phy_attached_device_address) == 0)
+ ) {
+ return port;
+ }
+ }
+ }
+
+ return SCI_INVALID_HANDLE;
+}
+
+/**
+ *
+ * @controller: This is the controller object that contains the port agent
+ * @port_agent: This is the port configruation agent for the controller.
+ *
+ * This routine will validate the port configuration is correct for the SCU
+ * hardware. The SCU hardware allows for port configurations as follows. LP0
+ * -> (PE0), (PE0, PE1), (PE0, PE1, PE2, PE3) LP1 -> (PE1) LP2 -> (PE2), (PE2,
+ * PE3) LP3 -> (PE3) enum sci_status SCI_SUCCESS the port configuration is valid for
+ * this port configuration agent. SCI_FAILURE_UNSUPPORTED_PORT_CONFIGURATION
+ * the port configuration is not valid for this port configuration agent.
+ */
+static enum sci_status scic_sds_port_configuration_agent_validate_ports(
+ struct scic_sds_controller *controller,
+ struct scic_sds_port_configuration_agent *port_agent)
+{
+ struct sci_sas_address first_address;
+ struct sci_sas_address second_address;
+
+ /*
+ * Sanity check the max ranges for all the phys the max index
+ * is always equal to the port range index */
+ if (
+ (port_agent->phy_valid_port_range[0].max_index != 0)
+ || (port_agent->phy_valid_port_range[1].max_index != 1)
+ || (port_agent->phy_valid_port_range[2].max_index != 2)
+ || (port_agent->phy_valid_port_range[3].max_index != 3)
+ ) {
+ return SCI_FAILURE_UNSUPPORTED_PORT_CONFIGURATION;
+ }
+
+ /*
+ * This is a request to configure a single x4 port or at least attempt
+ * to make all the phys into a single port */
+ if (
+ (port_agent->phy_valid_port_range[0].min_index == 0)
+ && (port_agent->phy_valid_port_range[1].min_index == 0)
+ && (port_agent->phy_valid_port_range[2].min_index == 0)
+ && (port_agent->phy_valid_port_range[3].min_index == 0)
+ ) {
+ return SCI_SUCCESS;
+ }
+
+ /*
+ * This is a degenerate case where phy 1 and phy 2 are assigned
+ * to the same port this is explicitly disallowed by the hardware
+ * unless they are part of the same x4 port and this condition was
+ * already checked above. */
+ if (port_agent->phy_valid_port_range[2].min_index == 1) {
+ return SCI_FAILURE_UNSUPPORTED_PORT_CONFIGURATION;
+ }
+
+ /*
+ * PE0 and PE3 can never have the same SAS Address unless they
+ * are part of the same x4 wide port and we have already checked
+ * for this condition. */
+ scic_sds_phy_get_sas_address(&controller->phy_table[0], &first_address);
+ scic_sds_phy_get_sas_address(&controller->phy_table[3], &second_address);
+
+ if (sci_sas_address_compare(first_address, second_address) == 0) {
+ return SCI_FAILURE_UNSUPPORTED_PORT_CONFIGURATION;
+ }
+
+ /*
+ * PE0 and PE1 are configured into a 2x1 ports make sure that the
+ * SAS Address for PE0 and PE2 are different since they can not be
+ * part of the same port. */
+ if (
+ (port_agent->phy_valid_port_range[0].min_index == 0)
+ && (port_agent->phy_valid_port_range[1].min_index == 1)
+ ) {
+ scic_sds_phy_get_sas_address(&controller->phy_table[0], &first_address);
+ scic_sds_phy_get_sas_address(&controller->phy_table[2], &second_address);
+
+ if (sci_sas_address_compare(first_address, second_address) == 0) {
+ return SCI_FAILURE_UNSUPPORTED_PORT_CONFIGURATION;
+ }
+ }
+
+ /*
+ * PE2 and PE3 are configured into a 2x1 ports make sure that the
+ * SAS Address for PE1 and PE3 are different since they can not be
+ * part of the same port. */
+ if (
+ (port_agent->phy_valid_port_range[2].min_index == 2)
+ && (port_agent->phy_valid_port_range[3].min_index == 3)
+ ) {
+ scic_sds_phy_get_sas_address(&controller->phy_table[1], &first_address);
+ scic_sds_phy_get_sas_address(&controller->phy_table[3], &second_address);
+
+ if (sci_sas_address_compare(first_address, second_address) == 0) {
+ return SCI_FAILURE_UNSUPPORTED_PORT_CONFIGURATION;
+ }
+ }
+
+ return SCI_SUCCESS;
+}
+
+/*
+ * ******************************************************************************
+ * Manual port configuration agent routines
+ * ****************************************************************************** */
+
+/**
+ *
+ *
+ * This routine will verify that all of the phys in the same port are using the
+ * same SAS address.
+ */
+static enum sci_status scic_sds_mpc_agent_validate_phy_configuration(
+ struct scic_sds_controller *controller,
+ struct scic_sds_port_configuration_agent *port_agent)
+{
+ u32 phy_mask;
+ u32 assigned_phy_mask;
+ struct sci_sas_address sas_address;
+ struct sci_sas_address phy_assigned_address;
+ u8 port_index;
+ u8 phy_index;
+
+ assigned_phy_mask = 0;
+ sas_address.high = 0;
+ sas_address.low = 0;
+
+ for (port_index = 0; port_index < SCI_MAX_PORTS; port_index++) {
+ phy_mask = controller->oem_parameters.sds1.ports[port_index].phy_mask;
+
+ if (phy_mask != 0) {
+ /*
+ * Make sure that one or more of the phys were not already assinged to
+ * a different port. */
+ if ((phy_mask & ~assigned_phy_mask) == 0) {
+ return SCI_FAILURE_UNSUPPORTED_PORT_CONFIGURATION;
+ }
+
+ /* Find the starting phy index for this round through the loop */
+ for (phy_index = 0; phy_index < SCI_MAX_PHYS; phy_index++) {
+ if ((1 << phy_index) & phy_mask) {
+ scic_sds_phy_get_sas_address(
+ &controller->phy_table[phy_index], &sas_address
+ );
+
+ /*
+ * The phy_index can be used as the starting point for the
+ * port range since the hardware starts all logical ports
+ * the same as the PE index. */
+ port_agent->phy_valid_port_range[phy_index].min_index = port_index;
+ port_agent->phy_valid_port_range[phy_index].max_index = phy_index;
+
+ if (phy_index != port_index) {
+ return SCI_FAILURE_UNSUPPORTED_PORT_CONFIGURATION;
+ }
+
+ break;
+ }
+ }
+
+ /*
+ * See how many additional phys are being added to this logical port.
+ * Note: We have not moved the current phy_index so we will actually
+ * compare the startting phy with itself.
+ * This is expected and required to add the phy to the port. */
+ while (phy_index < SCI_MAX_PHYS) {
+ if ((1 << phy_index) & phy_mask) {
+ scic_sds_phy_get_sas_address(
+ &controller->phy_table[phy_index], &phy_assigned_address
+ );
+
+ if (sci_sas_address_compare(sas_address, phy_assigned_address) != 0) {
+ /*
+ * The phy mask specified that this phy is part of the same port
+ * as the starting phy and it is not so fail this configuration */
+ return SCI_FAILURE_UNSUPPORTED_PORT_CONFIGURATION;
+ }
+
+ port_agent->phy_valid_port_range[phy_index].min_index = port_index;
+ port_agent->phy_valid_port_range[phy_index].max_index = phy_index;
+
+ scic_sds_port_add_phy(
+ &controller->port_table[port_index],
+ &controller->phy_table[phy_index]
+ );
+
+ assigned_phy_mask |= (1 << phy_index);
+ }
+
+ phy_index++;
+ }
+ }
+ }
+
+ return scic_sds_port_configuration_agent_validate_ports(controller, port_agent);
+}
+
+/**
+ *
+ *
+ * This timer routine is used to allow the SCI User to rediscover or change
+ * device objects before a new series of link up notifications because a link
+ * down has allowed a better port configuration.
+ */
+static void scic_sds_mpc_agent_timeout_handler(
+ void *object)
+{
+ u8 index;
+ struct scic_sds_controller *controller = (struct scic_sds_controller *)object;
+ struct scic_sds_port_configuration_agent *port_agent = &controller->port_agent;
+ u16 configure_phy_mask;
+
+ port_agent->timer_pending = false;
+
+ /* Find the mask of phys that are reported read but as yet unconfigured into a port */
+ configure_phy_mask = ~port_agent->phy_configured_mask & port_agent->phy_ready_mask;
+
+ for (index = 0; index < SCI_MAX_PHYS; index++) {
+ if (configure_phy_mask & (1 << index)) {
+ port_agent->link_up_handler(
+ controller,
+ port_agent,
+ scic_sds_phy_get_port(&controller->phy_table[index]),
+ &controller->phy_table[index]
+ );
+ }
+ }
+}
+
+/**
+ *
+ * @controller: This is the controller object that receives the link up
+ * notification.
+ * @port: This is the port object associated with the phy. If the is no
+ * associated port this is an SCI_INVALID_HANDLE.
+ * @phy: This is the phy object which has gone ready.
+ *
+ * This method handles the manual port configuration link up notifications.
+ * Since all ports and phys are associate at initialization time we just turn
+ * around and notifiy the port object that there is a link up. If this PHY is
+ * not associated with a port there is no action taken. Is it possible to get a
+ * link up notification from a phy that has no assocoated port?
+ */
+static void scic_sds_mpc_agent_link_up(
+ struct scic_sds_controller *controller,
+ struct scic_sds_port_configuration_agent *port_agent,
+ struct scic_sds_port *port,
+ struct scic_sds_phy *phy)
+{
+ /*
+ * If the port has an invalid handle then the phy was not assigned to
+ * a port. This is because the phy was not given the same SAS Address
+ * as the other PHYs in the port. */
+ if (port != SCI_INVALID_HANDLE) {
+ port_agent->phy_ready_mask |= (1 << scic_sds_phy_get_index(phy));
+
+ scic_sds_port_link_up(port, phy);
+
+ if ((port->active_phy_mask & (1 << scic_sds_phy_get_index(phy))) != 0) {
+ port_agent->phy_configured_mask |= (1 << scic_sds_phy_get_index(phy));
+ }
+ }
+}
+
+/**
+ *
+ * @controller: This is the controller object that receives the link down
+ * notification.
+ * @port: This is the port object associated with the phy. If the is no
+ * associated port this is an SCI_INVALID_HANDLE. The port is an invalid
+ * handle only if the phy was never port of this port. This happens when
+ * the phy is not broadcasting the same SAS address as the other phys in the
+ * assigned port.
+ * @phy: This is the phy object which has gone link down.
+ *
+ * This method handles the manual port configuration link down notifications.
+ * Since all ports and phys are associated at initialization time we just turn
+ * around and notifiy the port object of the link down event. If this PHY is
+ * not associated with a port there is no action taken. Is it possible to get a
+ * link down notification from a phy that has no assocoated port?
+ */
+static void scic_sds_mpc_agent_link_down(
+ struct scic_sds_controller *controller,
+ struct scic_sds_port_configuration_agent *port_agent,
+ struct scic_sds_port *port,
+ struct scic_sds_phy *phy)
+{
+ if (port != SCI_INVALID_HANDLE) {
+ /*
+ * If we can form a new port from the remainder of the phys then we want
+ * to start the timer to allow the SCI User to cleanup old devices and
+ * rediscover the port before rebuilding the port with the phys that
+ * remain in the ready state. */
+ port_agent->phy_ready_mask &= ~(1 << scic_sds_phy_get_index(phy));
+ port_agent->phy_configured_mask &= ~(1 << scic_sds_phy_get_index(phy));
+
+ /*
+ * Check to see if there are more phys waiting to be configured into a port.
+ * If there are allow the SCI User to tear down this port, if necessary, and
+ * then reconstruc the port after the timeout. */
+ if (
+ (port_agent->phy_configured_mask == 0x0000)
+ && (port_agent->phy_ready_mask != 0x0000)
+ && !port_agent->timer_pending
+ ) {
+ port_agent->timer_pending = true;
+
+ scic_cb_timer_start(
+ controller,
+ port_agent->timer,
+ SCIC_SDS_MPC_RECONFIGURATION_TIMEOUT
+ );
+ }
+
+ scic_sds_port_link_down(port, phy);
+ }
+}
+
+/*
+ * ******************************************************************************
+ * Automatic port configuration agent routines
+ * ****************************************************************************** */
+
+/**
+ *
+ *
+ * This routine will verify that the phys are assigned a valid SAS address for
+ * automatic port configuration mode.
+ */
+static enum sci_status scic_sds_apc_agent_validate_phy_configuration(
+ struct scic_sds_controller *controller,
+ struct scic_sds_port_configuration_agent *port_agent)
+{
+ u8 phy_index;
+ u8 port_index;
+ struct sci_sas_address sas_address;
+ struct sci_sas_address phy_assigned_address;
+
+ phy_index = 0;
+
+ while (phy_index < SCI_MAX_PHYS) {
+ port_index = phy_index;
+
+ /* Get the assigned SAS Address for the first PHY on the controller. */
+ scic_sds_phy_get_sas_address(
+ &controller->phy_table[phy_index], &sas_address
+ );
+
+ while (++phy_index < SCI_MAX_PHYS) {
+ scic_sds_phy_get_sas_address(
+ &controller->phy_table[phy_index], &phy_assigned_address
+ );
+
+ /* Verify each of the SAS address are all the same for every PHY */
+ if (sci_sas_address_compare(sas_address, phy_assigned_address) == 0) {
+ port_agent->phy_valid_port_range[phy_index].min_index = port_index;
+ port_agent->phy_valid_port_range[phy_index].max_index = phy_index;
+ } else {
+ port_agent->phy_valid_port_range[phy_index].min_index = phy_index;
+ port_agent->phy_valid_port_range[phy_index].max_index = phy_index;
+ break;
+ }
+ }
+ }
+
+ return scic_sds_port_configuration_agent_validate_ports(controller, port_agent);
+}
+
+/**
+ *
+ * @controller: This is the controller that to which the port agent is assigned.
+ * @port_agent: This is the port agent that is requesting the timer start
+ * operation.
+ * @phy: This is the phy that has caused the timer operation to be scheduled.
+ *
+ * This routine will restart the automatic port configuration timeout timer for
+ * the next time period. This could be caused by either a link down event or a
+ * link up event where we can not yet tell to which port a phy belongs.
+ */
+static void scic_sds_apc_agent_start_timer(
+ struct scic_sds_controller *controller,
+ struct scic_sds_port_configuration_agent *port_agent,
+ struct scic_sds_phy *phy,
+ u32 timeout)
+{
+ if (port_agent->timer_pending) {
+ scic_cb_timer_stop(controller, port_agent->timer);
+ }
+
+ port_agent->timer_pending = true;
+
+ scic_cb_timer_start(controller, port_agent->timer, timeout);
+}
+
+/**
+ *
+ * @controller: This is the controller object that receives the link up
+ * notification.
+ * @phy: This is the phy object which has gone link up.
+ *
+ * This method handles the automatic port configuration for link up
+ * notifications.
+ */
+static void scic_sds_apc_agent_configure_ports(
+ struct scic_sds_controller *controller,
+ struct scic_sds_port_configuration_agent *port_agent,
+ struct scic_sds_phy *phy,
+ bool start_timer)
+{
+ u8 port_index;
+ enum sci_status status;
+ struct scic_sds_port *port;
+ struct scic_sds_port *port_handle;
+ enum SCIC_SDS_APC_ACTIVITY apc_activity = SCIC_SDS_APC_SKIP_PHY;
+
+ port = scic_sds_port_configuration_agent_find_port(controller, phy);
+
+ if (port != SCI_INVALID_HANDLE) {
+ if (scic_sds_port_is_valid_phy_assignment(port, phy->phy_index))
+ apc_activity = SCIC_SDS_APC_ADD_PHY;
+ else
+ apc_activity = SCIC_SDS_APC_SKIP_PHY;
+ } else {
+ /*
+ * There is no matching Port for this PHY so lets search through the
+ * Ports and see if we can add the PHY to its own port or maybe start
+ * the timer and wait to see if a wider port can be made.
+ *
+ * Note the break when we reach the condition of the port id == phy id */
+ for (
+ port_index = port_agent->phy_valid_port_range[phy->phy_index].min_index;
+ port_index <= port_agent->phy_valid_port_range[phy->phy_index].max_index;
+ port_index++
+ ) {
+ scic_controller_get_port_handle(controller, port_index, &port_handle);
+
+ port = (struct scic_sds_port *)port_handle;
+
+ /* First we must make sure that this PHY can be added to this Port. */
+ if (scic_sds_port_is_valid_phy_assignment(port, phy->phy_index)) {
+ /*
+ * Port contains a PHY with a greater PHY ID than the current
+ * PHY that has gone link up. This phy can not be part of any
+ * port so skip it and move on. */
+ if (port->active_phy_mask > (1 << phy->phy_index)) {
+ apc_activity = SCIC_SDS_APC_SKIP_PHY;
+ break;
+ }
+
+ /*
+ * We have reached the end of our Port list and have not found
+ * any reason why we should not either add the PHY to the port
+ * or wait for more phys to become active. */
+ if (port->physical_port_index == phy->phy_index) {
+ /*
+ * The Port either has no active PHYs.
+ * Consider that if the port had any active PHYs we would have
+ * or active PHYs with
+ * a lower PHY Id than this PHY. */
+ if (apc_activity != SCIC_SDS_APC_START_TIMER) {
+ apc_activity = SCIC_SDS_APC_ADD_PHY;
+ }
+
+ break;
+ }
+
+ /*
+ * The current Port has no active PHYs and this PHY could be part
+ * of this Port. Since we dont know as yet setup to start the
+ * timer and see if there is a better configuration. */
+ if (port->active_phy_mask == 0) {
+ apc_activity = SCIC_SDS_APC_START_TIMER;
+ }
+ } else if (port->active_phy_mask != 0) {
+ /*
+ * The Port has an active phy and the current Phy can not
+ * participate in this port so skip the PHY and see if
+ * there is a better configuration. */
+ apc_activity = SCIC_SDS_APC_SKIP_PHY;
+ }
+ }
+ }
+
+ /*
+ * Check to see if the start timer operations should instead map to an
+ * add phy operation. This is caused because we have been waiting to
+ * add a phy to a port but could not becuase the automatic port
+ * configuration engine had a choice of possible ports for the phy.
+ * Since we have gone through a timeout we are going to restrict the
+ * choice to the smallest possible port. */
+ if (
+ (start_timer == false)
+ && (apc_activity == SCIC_SDS_APC_START_TIMER)
+ ) {
+ apc_activity = SCIC_SDS_APC_ADD_PHY;
+ }
+
+ switch (apc_activity) {
+ case SCIC_SDS_APC_ADD_PHY:
+ status = scic_sds_port_add_phy(port, phy);
+
+ if (status == SCI_SUCCESS) {
+ port_agent->phy_configured_mask |= (1 << phy->phy_index);
+ }
+ break;
+
+ case SCIC_SDS_APC_START_TIMER:
+ scic_sds_apc_agent_start_timer(
+ controller, port_agent, phy, SCIC_SDS_APC_WAIT_LINK_UP_NOTIFICATION
+ );
+ break;
+
+ case SCIC_SDS_APC_SKIP_PHY:
+ default:
+ /* do nothing the PHY can not be made part of a port at this time. */
+ break;
+ }
+}
+
+/**
+ *
+ * @controller: This is the controller object that receives the link up
+ * notification.
+ * @port: This is the port object associated with the phy. If the is no
+ * associated port this is an SCI_INVALID_HANDLE.
+ * @phy: This is the phy object which has gone link up.
+ *
+ * This method handles the automatic port configuration for link up
+ * notifications. Is it possible to get a link down notification from a phy
+ * that has no assocoated port?
+ */
+static void scic_sds_apc_agent_link_up(
+ struct scic_sds_controller *controller,
+ struct scic_sds_port_configuration_agent *port_agent,
+ struct scic_sds_port *port,
+ struct scic_sds_phy *phy)
+{
+ BUG_ON(port != SCI_INVALID_HANDLE);
+
+ port_agent->phy_ready_mask |= (1 << scic_sds_phy_get_index(phy));
+
+ scic_sds_apc_agent_configure_ports(controller, port_agent, phy, true);
+}
+
+/**
+ *
+ * @controller: This is the controller object that receives the link down
+ * notification.
+ * @port: This is the port object associated with the phy. If the is no
+ * associated port this is an SCI_INVALID_HANDLE.
+ * @phy: This is the phy object which has gone link down.
+ *
+ * This method handles the automatic port configuration link down
+ * notifications. not associated with a port there is no action taken. Is it
+ * possible to get a link down notification from a phy that has no assocoated
+ * port?
+ */
+static void scic_sds_apc_agent_link_down(
+ struct scic_sds_controller *controller,
+ struct scic_sds_port_configuration_agent *port_agent,
+ struct scic_sds_port *port,
+ struct scic_sds_phy *phy)
+{
+ port_agent->phy_ready_mask &= ~(1 << scic_sds_phy_get_index(phy));
+
+ if (port != SCI_INVALID_HANDLE) {
+ if (port_agent->phy_configured_mask & (1 << phy->phy_index)) {
+ enum sci_status status;
+
+ status = scic_sds_port_remove_phy(port, phy);
+
+ if (status == SCI_SUCCESS) {
+ port_agent->phy_configured_mask &= ~(1 << phy->phy_index);
+ }
+ }
+ }
+}
+
+/**
+ *
+ *
+ * This routine will try to configure the phys into ports when the timer fires.
+ */
+static void scic_sds_apc_agent_timeout_handler(
+ void *object)
+{
+ u32 index;
+ struct scic_sds_port_configuration_agent *port_agent;
+ struct scic_sds_controller *controller = (struct scic_sds_controller *)object;
+ u16 configure_phy_mask;
+
+ port_agent = scic_sds_controller_get_port_configuration_agent(controller);
+
+ port_agent->timer_pending = false;
+
+ configure_phy_mask = ~port_agent->phy_configured_mask & port_agent->phy_ready_mask;
+
+ if (configure_phy_mask != 0x00) {
+ for (index = 0; index < SCI_MAX_PHYS; index++) {
+ if (configure_phy_mask & (1 << index)) {
+ scic_sds_apc_agent_configure_ports(
+ controller, port_agent, &controller->phy_table[index], false
+ );
+ }
+ }
+ }
+}
+
+/*
+ * ******************************************************************************
+ * Public port configuration agent routines
+ * ****************************************************************************** */
+
+/**
+ *
+ *
+ * This method will construct the port configuration agent for operation. This
+ * call is universal for both manual port configuration and automatic port
+ * configuration modes.
+ */
+void scic_sds_port_configuration_agent_construct(
+ struct scic_sds_port_configuration_agent *port_agent)
+{
+ u32 index;
+
+ port_agent->phy_configured_mask = 0x00;
+ port_agent->phy_ready_mask = 0x00;
+
+ port_agent->link_up_handler = NULL;
+ port_agent->link_down_handler = NULL;
+
+ port_agent->timer_pending = false;
+ port_agent->timer = NULL;
+
+ for (index = 0; index < SCI_MAX_PORTS; index++) {
+ port_agent->phy_valid_port_range[index].min_index = 0;
+ port_agent->phy_valid_port_range[index].max_index = 0;
+ }
+}
+
+/**
+ *
+ * @controller: This is the controller object for which the port agent is being
+ * initialized.
+ *
+ * This method will construct the port configuration agent for this controller.
+ */
+enum sci_status scic_sds_port_configuration_agent_initialize(
+ struct scic_sds_controller *controller,
+ struct scic_sds_port_configuration_agent *port_agent)
+{
+ enum sci_status status = SCI_SUCCESS;
+ enum SCIC_PORT_CONFIGURATION_MODE mode;
+
+ mode = scic_sds_controller_get_port_configuration_mode(controller);
+
+ if (mode == SCIC_PORT_MANUAL_CONFIGURATION_MODE) {
+ status = scic_sds_mpc_agent_validate_phy_configuration(controller, port_agent);
+
+ port_agent->link_up_handler = scic_sds_mpc_agent_link_up;
+ port_agent->link_down_handler = scic_sds_mpc_agent_link_down;
+
+ port_agent->timer = scic_cb_timer_create(
+ controller,
+ scic_sds_mpc_agent_timeout_handler,
+ controller
+ );
+ } else {
+ status = scic_sds_apc_agent_validate_phy_configuration(controller, port_agent);
+
+ port_agent->link_up_handler = scic_sds_apc_agent_link_up;
+ port_agent->link_down_handler = scic_sds_apc_agent_link_down;
+
+ port_agent->timer = scic_cb_timer_create(
+ controller,
+ scic_sds_apc_agent_timeout_handler,
+ controller
+ );
+ }
+
+ /* Make sure we have actually gotten a timer */
+ if ((status == SCI_SUCCESS) && (port_agent->timer == NULL)) {
+ dev_err(scic_to_dev(controller),
+ "%s: Controller 0x%p automatic port configuration "
+ "agent could not get timer.\n",
+ __func__,
+ controller);
+
+ status = SCI_FAILURE;
+ }
+
+ return status;
+}
diff --git a/drivers/scsi/isci/core/scic_sds_port_configuration_agent.h b/drivers/scsi/isci/core/scic_sds_port_configuration_agent.h
new file mode 100644
index 000000000000..4146735ffc32
--- /dev/null
+++ b/drivers/scsi/isci/core/scic_sds_port_configuration_agent.h
@@ -0,0 +1,108 @@
+/*
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Intel Corporation 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
+ * OWNER 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.
+ */
+
+#ifndef _SCIC_SDS_PORT_CONFIGURATION_AGENT_H_
+#define _SCIC_SDS_PORT_CONFIGURATION_AGENT_H_
+
+/**
+ * This file contains the structures, constants and prototypes used for the
+ * core controller automatic port configuration engine.
+ *
+ *
+ */
+
+#include "scic_sds_port.h"
+#include "scic_sds_phy.h"
+
+struct scic_sds_controller;
+struct scic_sds_port_configuration_agent;
+struct scic_sds_port;
+struct scic_sds_phy;
+
+typedef void (*SCIC_SDS_PORT_CONFIGURATION_AGENT_PHY_HANDLER_T)(
+ struct scic_sds_controller *,
+ struct scic_sds_port_configuration_agent *,
+ struct scic_sds_port *,
+ struct scic_sds_phy *
+ );
+
+struct SCIC_SDS_PORT_RANGE {
+ u8 min_index;
+ u8 max_index;
+};
+
+struct scic_sds_port_configuration_agent {
+ u16 phy_configured_mask;
+ u16 phy_ready_mask;
+
+ struct SCIC_SDS_PORT_RANGE phy_valid_port_range[SCI_MAX_PHYS];
+
+ bool timer_pending;
+
+ SCIC_SDS_PORT_CONFIGURATION_AGENT_PHY_HANDLER_T link_up_handler;
+ SCIC_SDS_PORT_CONFIGURATION_AGENT_PHY_HANDLER_T link_down_handler;
+
+ void *timer;
+
+};
+
+void scic_sds_port_configuration_agent_construct(
+ struct scic_sds_port_configuration_agent *port_agent);
+
+enum sci_status scic_sds_port_configuration_agent_initialize(
+ struct scic_sds_controller *controller,
+ struct scic_sds_port_configuration_agent *port_agent);
+
+#endif /* _SCIC_SDS_PORT_CONFIGURATION_AGENT_H_ */
diff --git a/drivers/scsi/isci/core/scic_sds_port_registers.h b/drivers/scsi/isci/core/scic_sds_port_registers.h
new file mode 100644
index 000000000000..cf8bc073b952
--- /dev/null
+++ b/drivers/scsi/isci/core/scic_sds_port_registers.h
@@ -0,0 +1,223 @@
+/*
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Intel Corporation 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
+ * OWNER 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.
+ */
+
+#ifndef _SCIC_SDS_PORT_REGISTERS_H_
+#define _SCIC_SDS_PORT_REGISTERS_H_
+
+/**
+ * This file contains a set of macros that assist in reading the SCU hardware
+ * registers.
+ *
+ *
+ */
+
+/**
+ * scu_transport_layer_read() -
+ *
+ * Macro to read the transport layer register associated with this port object.
+ */
+#define scu_transport_layer_read(port, reg) \
+ scu_register_read(\
+ scic_sds_port_get_controller(port), \
+ (port)->transport_layer_registers->reg \
+ )
+
+/**
+ * scu_transport_layer_write() -
+ *
+ * Macro to write the transport layer register associated with this port object.
+ */
+#define scu_transport_layer_write(port, reg, value) \
+ scu_register_write(\
+ scic_sds_port_get_controller(port), \
+ (port)->transport_layer_registers->reg, \
+ (value) \
+ )
+
+/**
+ * scu_port_task_scheduler_read() -
+ *
+ * Macro to read the port task scheduler register associated with this port
+ * object
+ */
+#define scu_port_task_scheduler_read(port, reg) \
+ scu_register_read(\
+ scic_sds_port_get_controller(port), \
+ (port)->port_task_scheduler_registers->reg \
+ )
+
+/**
+ * scu_port_task_scheduler_write() -
+ *
+ * Macro to write the port task scheduler register associated with this port
+ * object
+ */
+#define scu_port_task_scheduler_write(port, reg, value) \
+ scu_register_write(\
+ scic_sds_port_get_controller(port), \
+ (port)->port_task_scheduler_registers->reg, \
+ (value) \
+ )
+
+#define scu_port_viit_register_write(port, reg, value) \
+ scu_register_write(\
+ scic_sds_port_get_controller(port), \
+ (port)->viit_registers->reg, \
+ (value) \
+ )
+
+/*
+ * ****************************************************************************
+ * * Transport Layer registers controlled by the port object
+ * **************************************************************************** */
+
+/**
+ * SCU_TLCR_READ() -
+ *
+ * This macro reads the Transport layer control register
+ */
+#define SCU_TLCR_READ(port) \
+ scu_transport_layer_read(port, control)
+
+/**
+ * SCU_TLCR_WRITE() -
+ *
+ * This macro writes the Transport layer control register
+ */
+#define SCU_TLCR_WRITE(port, value) \
+ scu_transport_layer_write(port, control, value)
+
+/**
+ * SCU_TLADTR_READ() -
+ *
+ * This macro reads the Transport layer address translation register
+ */
+#define SCU_TLADTR_READ(port) \
+ scu_transport_layer_read(port, address_translation)
+
+/**
+ * SCU_TLADTR_WRITE() -
+ *
+ * This macro writes the Transport layer address translation register
+ */
+#define SCU_TLADTR_WRITE(port) \
+ scu_transport_layer_write(port, address_translation, value)
+
+/**
+ * SCU_STPTLDARNI_WRITE() -
+ *
+ * This macro writes the STP Transport Layer Direct Attached RNi register.
+ */
+#define SCU_STPTLDARNI_WRITE(port, index) \
+ scu_transport_layer_write(port, stp_rni, index)
+
+/**
+ * SCU_STPTLDARNI_READ() -
+ *
+ * This macro reads the STP Transport Layer Direct Attached RNi register.
+ */
+#define SCU_STPTLDARNI_READ(port) \
+ scu_transport_layer_read(port, stp_rni)
+
+/*
+ * ****************************************************************************
+ * * Port Task Scheduler registers controlled by the port object
+ * **************************************************************************** */
+
+/**
+ * SCU_PTSxCR_READ() -
+ *
+ * Macro to read the port task scheduler control register
+ */
+#define SCU_PTSxCR_READ(port) \
+ scu_port_task_scheduler_read(port, control)
+
+/**
+ * SCU_PTSxCR_WRITE() -
+ *
+ * Macro to write the port task scheduler control regsister
+ */
+#define SCU_PTSxCR_WRITE(port, value) \
+ scu_port_task_scheduler_write(port, control, value)
+
+/*
+ * ****************************************************************************
+ * * Port PE Configuration registers
+ * **************************************************************************** */
+
+/**
+ * SCU_PCSPExCR_WRITE() -
+ *
+ * Macro to write the PE Port Configuration Register
+ */
+#define SCU_PCSPExCR_WRITE(port, phy_id, value) \
+ scu_register_write(\
+ scic_sds_port_get_controller(port), \
+ (port)->port_pe_configuration_register[phy_id], \
+ (value) \
+ )
+
+/**
+ * SCU_PCSPExCR_READ() -
+ *
+ * Macro to read the PE Port Configuration Regsiter
+ */
+#define SCU_PCSPExCR_READ(port, phy_id) \
+ scu_register_read(\
+ scic_sds_port_get_controller(port), \
+ (port)->port_pe_configuration_register[phy_id] \
+ )
+
+#endif /* _SCIC_SDS_PORT_REGISTERS_H_ */
diff --git a/drivers/scsi/isci/core/scic_sds_remote_device.c b/drivers/scsi/isci/core/scic_sds_remote_device.c
new file mode 100644
index 000000000000..21f03bc7d797
--- /dev/null
+++ b/drivers/scsi/isci/core/scic_sds_remote_device.c
@@ -0,0 +1,2252 @@
+/*
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Intel Corporation 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
+ * OWNER 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.
+ */
+
+/**
+ * This file contains the implementation of remote device methods.
+ *
+ *
+ */
+
+#include "intel_sas.h"
+#include "sci_util.h"
+#include "sci_environment.h"
+#include "scic_port.h"
+#include "scic_phy.h"
+#include "scic_remote_device.h"
+#include "scic_sds_port.h"
+#include "scic_sds_phy.h"
+#include "scic_sds_remote_device.h"
+#include "scic_sds_request.h"
+#include "scic_sds_controller.h"
+
+#define SCIC_SDS_REMOTE_DEVICE_RESET_TIMEOUT (1000)
+
+/*
+ * *****************************************************************************
+ * * CORE REMOTE DEVICE PRIVATE METHODS
+ * ***************************************************************************** */
+
+/*
+ * *****************************************************************************
+ * * CORE REMOTE DEVICE PUBLIC METHODS
+ * ***************************************************************************** */
+
+u32 scic_remote_device_get_object_size(void)
+{
+ return sizeof(struct scic_sds_remote_device)
+ + sizeof(struct scic_sds_remote_node_context);
+}
+
+/* --------------------------------------------------------------------------- */
+
+void scic_remote_device_construct(struct scic_sds_port *sci_port,
+ struct scic_sds_remote_device *sci_dev)
+{
+ sci_dev->owning_port = sci_port;
+ sci_dev->started_request_count = 0;
+ sci_dev->rnc = (struct scic_sds_remote_node_context *) &sci_dev[1];
+
+ sci_base_remote_device_construct(
+ &sci_dev->parent,
+ scic_sds_remote_device_state_table
+ );
+
+ scic_sds_remote_node_context_construct(
+ sci_dev,
+ sci_dev->rnc,
+ SCIC_SDS_REMOTE_NODE_CONTEXT_INVALID_INDEX
+ );
+
+ sci_object_set_association(sci_dev->rnc, sci_dev);
+}
+
+
+enum sci_status scic_remote_device_da_construct(
+ struct scic_sds_remote_device *sci_dev)
+{
+ enum sci_status status;
+ u16 remote_node_index;
+ struct sci_sas_identify_address_frame_protocols protocols;
+
+ /*
+ * This information is request to determine how many remote node context
+ * entries will be needed to store the remote node.
+ */
+ scic_sds_port_get_attached_protocols(sci_dev->owning_port, &protocols);
+ sci_dev->target_protocols.u.all = protocols.u.all;
+ sci_dev->is_direct_attached = true;
+#if !defined(DISABLE_ATAPI)
+ sci_dev->is_atapi = scic_sds_remote_device_is_atapi(sci_dev);
+#endif
+
+ status = scic_sds_controller_allocate_remote_node_context(
+ sci_dev->owning_port->owning_controller,
+ sci_dev,
+ &remote_node_index);
+
+ if (status == SCI_SUCCESS) {
+ scic_sds_remote_node_context_set_remote_node_index(
+ sci_dev->rnc, remote_node_index);
+
+ scic_sds_port_get_attached_sas_address(
+ sci_dev->owning_port, &sci_dev->device_address);
+
+ if (sci_dev->target_protocols.u.bits.attached_ssp_target) {
+ sci_dev->has_ready_substate_machine = false;
+ } else if (sci_dev->target_protocols.u.bits.attached_stp_target) {
+ sci_dev->has_ready_substate_machine = true;
+
+ sci_base_state_machine_construct(
+ &sci_dev->ready_substate_machine,
+ &sci_dev->parent.parent,
+ scic_sds_stp_remote_device_ready_substate_table,
+ SCIC_SDS_STP_REMOTE_DEVICE_READY_SUBSTATE_IDLE);
+ } else if (sci_dev->target_protocols.u.bits.attached_smp_target) {
+ sci_dev->has_ready_substate_machine = true;
+
+ /* add the SMP ready substate machine construction here */
+ sci_base_state_machine_construct(
+ &sci_dev->ready_substate_machine,
+ &sci_dev->parent.parent,
+ scic_sds_smp_remote_device_ready_substate_table,
+ SCIC_SDS_SMP_REMOTE_DEVICE_READY_SUBSTATE_IDLE);
+ }
+
+ sci_dev->connection_rate = scic_sds_port_get_max_allowed_speed(
+ sci_dev->owning_port);
+
+ /* / @todo Should I assign the port width by reading all of the phys on the port? */
+ sci_dev->device_port_width = 1;
+ }
+
+ return status;
+}
+
+
+static void scic_sds_remote_device_get_info_from_smp_discover_response(
+ struct scic_sds_remote_device *this_device,
+ struct smp_response_discover *discover_response)
+{
+ /* decode discover_response to set sas_address to this_device. */
+ this_device->device_address.high =
+ discover_response->attached_sas_address.high;
+
+ this_device->device_address.low =
+ discover_response->attached_sas_address.low;
+
+ this_device->target_protocols.u.all = discover_response->protocols.u.all;
+}
+
+
+enum sci_status scic_remote_device_ea_construct(
+ struct scic_sds_remote_device *sci_dev,
+ struct smp_response_discover *discover_response)
+{
+ enum sci_status status;
+ struct scic_sds_controller *the_controller;
+
+ the_controller = scic_sds_port_get_controller(sci_dev->owning_port);
+
+ scic_sds_remote_device_get_info_from_smp_discover_response(
+ sci_dev, discover_response);
+
+ status = scic_sds_controller_allocate_remote_node_context(
+ the_controller, sci_dev, &sci_dev->rnc->remote_node_index);
+
+ if (status == SCI_SUCCESS) {
+ if (sci_dev->target_protocols.u.bits.attached_ssp_target) {
+ sci_dev->has_ready_substate_machine = false;
+ } else if (sci_dev->target_protocols.u.bits.attached_smp_target) {
+ sci_dev->has_ready_substate_machine = true;
+
+ /* add the SMP ready substate machine construction here */
+ sci_base_state_machine_construct(
+ &sci_dev->ready_substate_machine,
+ &sci_dev->parent.parent,
+ scic_sds_smp_remote_device_ready_substate_table,
+ SCIC_SDS_SMP_REMOTE_DEVICE_READY_SUBSTATE_IDLE);
+ } else if (sci_dev->target_protocols.u.bits.attached_stp_target) {
+ sci_dev->has_ready_substate_machine = true;
+
+ sci_base_state_machine_construct(
+ &sci_dev->ready_substate_machine,
+ &sci_dev->parent.parent,
+ scic_sds_stp_remote_device_ready_substate_table,
+ SCIC_SDS_STP_REMOTE_DEVICE_READY_SUBSTATE_IDLE);
+ }
+
+ /*
+ * For SAS-2 the physical link rate is actually a logical link
+ * rate that incorporates multiplexing. The SCU doesn't
+ * incorporate multiplexing and for the purposes of the
+ * connection the logical link rate is that same as the
+ * physical. Furthermore, the SAS-2 and SAS-1.1 fields overlay
+ * one another, so this code works for both situations. */
+ sci_dev->connection_rate = min_t(u16,
+ scic_sds_port_get_max_allowed_speed(sci_dev->owning_port),
+ discover_response->u2.sas1_1.negotiated_physical_link_rate
+ );
+
+ /* / @todo Should I assign the port width by reading all of the phys on the port? */
+ sci_dev->device_port_width = 1;
+ }
+
+ return status;
+}
+
+enum sci_status scic_remote_device_destruct(
+ struct scic_sds_remote_device *sci_dev)
+{
+ return sci_dev->state_handlers->parent.destruct_handler(&sci_dev->parent);
+}
+
+
+enum sci_status scic_remote_device_start(
+ struct scic_sds_remote_device *sci_dev,
+ u32 timeout)
+{
+ return sci_dev->state_handlers->parent.start_handler(&sci_dev->parent);
+}
+
+
+enum sci_status scic_remote_device_stop(
+ struct scic_sds_remote_device *sci_dev,
+ u32 timeout)
+{
+ return sci_dev->state_handlers->parent.stop_handler(&sci_dev->parent);
+}
+
+
+enum sci_status scic_remote_device_reset(
+ struct scic_sds_remote_device *sci_dev)
+{
+ return sci_dev->state_handlers->parent.reset_handler(&sci_dev->parent);
+}
+
+
+enum sci_status scic_remote_device_reset_complete(
+ struct scic_sds_remote_device *sci_dev)
+{
+ return sci_dev->state_handlers->parent.reset_complete_handler(&sci_dev->parent);
+}
+
+
+enum sci_sas_link_rate scic_remote_device_get_connection_rate(
+ struct scic_sds_remote_device *sci_dev)
+{
+ return sci_dev->connection_rate;
+}
+
+
+void scic_remote_device_get_protocols(
+ struct scic_sds_remote_device *sci_dev,
+ struct smp_discover_response_protocols *pr)
+{
+ pr->u.all = sci_dev->target_protocols.u.all;
+}
+
+#if !defined(DISABLE_ATAPI)
+bool scic_remote_device_is_atapi(struct scic_sds_remote_device *sci_dev)
+{
+ return sci_dev->is_atapi;
+}
+#endif
+
+
+/*
+ * *****************************************************************************
+ * * SCU DRIVER STANDARD (SDS) REMOTE DEVICE IMPLEMENTATIONS
+ * ***************************************************************************** */
+
+/**
+ *
+ *
+ * Remote device timer requirements
+ */
+#define SCIC_SDS_REMOTE_DEVICE_MINIMUM_TIMER_COUNT (0)
+#define SCIC_SDS_REMOTE_DEVICE_MAXIMUM_TIMER_COUNT (SCI_MAX_REMOTE_DEVICES)
+
+
+/**
+ *
+ * @this_device: The remote device for which the suspend is being requested.
+ *
+ * This method invokes the remote device suspend state handler. enum sci_status
+ */
+enum sci_status scic_sds_remote_device_suspend(
+ struct scic_sds_remote_device *this_device,
+ u32 suspend_type)
+{
+ return this_device->state_handlers->suspend_handler(this_device, suspend_type);
+}
+
+/**
+ *
+ * @this_device: The remote device for which the resume is being requested.
+ *
+ * This method invokes the remote device resume state handler. enum sci_status
+ */
+enum sci_status scic_sds_remote_device_resume(
+ struct scic_sds_remote_device *this_device)
+{
+ return this_device->state_handlers->resume_handler(this_device);
+}
+
+/**
+ *
+ * @this_device: The remote device for which the event handling is being
+ * requested.
+ * @frame_index: This is the frame index that is being processed.
+ *
+ * This method invokes the frame handler for the remote device state machine
+ * enum sci_status
+ */
+enum sci_status scic_sds_remote_device_frame_handler(
+ struct scic_sds_remote_device *this_device,
+ u32 frame_index)
+{
+ return this_device->state_handlers->frame_handler(this_device, frame_index);
+}
+
+/**
+ *
+ * @this_device: The remote device for which the event handling is being
+ * requested.
+ * @event_code: This is the event code that is to be processed.
+ *
+ * This method invokes the remote device event handler. enum sci_status
+ */
+enum sci_status scic_sds_remote_device_event_handler(
+ struct scic_sds_remote_device *this_device,
+ u32 event_code)
+{
+ return this_device->state_handlers->event_handler(this_device, event_code);
+}
+
+/**
+ *
+ * @controller: The controller that is starting the io request.
+ * @this_device: The remote device for which the start io handling is being
+ * requested.
+ * @io_request: The io request that is being started.
+ *
+ * This method invokes the remote device start io handler. enum sci_status
+ */
+enum sci_status scic_sds_remote_device_start_io(
+ struct scic_sds_controller *controller,
+ struct scic_sds_remote_device *this_device,
+ struct scic_sds_request *io_request)
+{
+ return this_device->state_handlers->parent.start_io_handler(
+ &this_device->parent, &io_request->parent);
+}
+
+/**
+ *
+ * @controller: The controller that is completing the io request.
+ * @this_device: The remote device for which the complete io handling is being
+ * requested.
+ * @io_request: The io request that is being completed.
+ *
+ * This method invokes the remote device complete io handler. enum sci_status
+ */
+enum sci_status scic_sds_remote_device_complete_io(
+ struct scic_sds_controller *controller,
+ struct scic_sds_remote_device *this_device,
+ struct scic_sds_request *io_request)
+{
+ return this_device->state_handlers->parent.complete_io_handler(
+ &this_device->parent, &io_request->parent);
+}
+
+/**
+ *
+ * @controller: The controller that is starting the task request.
+ * @this_device: The remote device for which the start task handling is being
+ * requested.
+ * @io_request: The task request that is being started.
+ *
+ * This method invokes the remote device start task handler. enum sci_status
+ */
+enum sci_status scic_sds_remote_device_start_task(
+ struct scic_sds_controller *controller,
+ struct scic_sds_remote_device *this_device,
+ struct scic_sds_request *io_request)
+{
+ return this_device->state_handlers->parent.start_task_handler(
+ &this_device->parent, &io_request->parent);
+}
+
+/**
+ *
+ * @controller: The controller that is completing the task request.
+ * @this_device: The remote device for which the complete task handling is
+ * being requested.
+ * @io_request: The task request that is being completed.
+ *
+ * This method invokes the remote device complete task handler. enum sci_status
+ */
+
+/**
+ *
+ * @this_device:
+ * @request:
+ *
+ * This method takes the request and bulids an appropriate SCU context for the
+ * request and then requests the controller to post the request. none
+ */
+void scic_sds_remote_device_post_request(
+ struct scic_sds_remote_device *this_device,
+ u32 request)
+{
+ u32 context;
+
+ context = scic_sds_remote_device_build_command_context(this_device, request);
+
+ scic_sds_controller_post_request(
+ scic_sds_remote_device_get_controller(this_device),
+ context
+ );
+}
+
+#if !defined(DISABLE_ATAPI)
+/**
+ *
+ * @this_device: The device to be checked.
+ *
+ * This method check the signature fis of a stp device to decide whether a
+ * device is atapi or not. true if a device is atapi device. False if a device
+ * is not atapi.
+ */
+bool scic_sds_remote_device_is_atapi(
+ struct scic_sds_remote_device *this_device)
+{
+ if (!this_device->target_protocols.u.bits.attached_stp_target)
+ return false;
+ else if (this_device->is_direct_attached) {
+ struct scic_sds_phy *phy;
+ struct scic_sata_phy_properties properties;
+ struct sata_fis_reg_d2h *signature_fis;
+ phy = scic_sds_port_get_a_connected_phy(this_device->owning_port);
+ scic_sata_phy_get_properties(phy, &properties);
+
+ /* decode the signature fis. */
+ signature_fis = &(properties.signature_fis);
+
+ if ((signature_fis->sector_count == 0x01)
+ && (signature_fis->lba_low == 0x01)
+ && (signature_fis->lba_mid == 0x14)
+ && (signature_fis->lba_high == 0xEB)
+ && ((signature_fis->device & 0x5F) == 0x00)
+ ) {
+ /* An ATA device supporting the PACKET command set. */
+ return true;
+ } else
+ return false;
+ } else {
+ /* Expander supported ATAPI device is not currently supported. */
+ return false;
+ }
+}
+#endif
+/*
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Intel Corporation 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
+ * OWNER 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.
+ */
+
+/**
+ * This file contains the state handlers for the struct scic_sds_remote_device for the
+ * base state machine.
+ *
+ *
+ */
+
+#include "sci_environment.h"
+#include "scic_user_callback.h"
+#include "scic_controller.h"
+#include "scic_sds_remote_device.h"
+#include "scic_sds_controller.h"
+#include "scic_sds_port.h"
+#include "scic_sds_request.h"
+#include "scic_sds_remote_node_context.h"
+#include "scu_event_codes.h"
+
+/*
+ * *****************************************************************************
+ * * PROTECTED METHODS
+ * ***************************************************************************** */
+
+/**
+ *
+ * @user_parameter: This is cast to a remote device object.
+ *
+ * This method is called once the remote node context is ready to be freed.
+ * The remote device can now report that its stop operation is complete. none
+ */
+static void scic_sds_cb_remote_device_rnc_destruct_complete(
+ void *user_parameter)
+{
+ struct scic_sds_remote_device *this_device;
+
+ this_device = (struct scic_sds_remote_device *)user_parameter;
+
+ BUG_ON(this_device->started_request_count != 0);
+
+ sci_base_state_machine_change_state(
+ scic_sds_remote_device_get_base_state_machine(this_device),
+ SCI_BASE_REMOTE_DEVICE_STATE_STOPPED
+ );
+}
+
+/**
+ *
+ * @user_parameter: This is cast to a remote device object.
+ *
+ * This method is called once the remote node context has transisitioned to a
+ * ready state. This is the indication that the remote device object can also
+ * transition to ready. none
+ */
+static void scic_sds_remote_device_resume_complete_handler(
+ void *user_parameter)
+{
+ struct scic_sds_remote_device *this_device;
+
+ this_device = (struct scic_sds_remote_device *)user_parameter;
+
+ if (
+ sci_base_state_machine_get_state(&this_device->parent.state_machine)
+ != SCI_BASE_REMOTE_DEVICE_STATE_READY
+ ) {
+ sci_base_state_machine_change_state(
+ &this_device->parent.state_machine,
+ SCI_BASE_REMOTE_DEVICE_STATE_READY
+ );
+ }
+}
+
+/**
+ *
+ * @device: This parameter specifies the device for which the request is being
+ * started.
+ * @request: This parameter specifies the request being started.
+ * @status: This parameter specifies the current start operation status.
+ *
+ * This method will perform the STP request start processing common to IO
+ * requests and task requests of all types. none
+ */
+void scic_sds_remote_device_start_request(
+ struct scic_sds_remote_device *this_device,
+ struct scic_sds_request *the_request,
+ enum sci_status status)
+{
+ /* We still have a fault in starting the io complete it on the port */
+ if (status == SCI_SUCCESS)
+ scic_sds_remote_device_increment_request_count(this_device);
+ else{
+ this_device->owning_port->state_handlers->complete_io_handler(
+ this_device->owning_port, this_device, the_request
+ );
+ }
+}
+
+
+/**
+ *
+ * @request: This parameter specifies the request being continued.
+ *
+ * This method will continue to post tc for a STP request. This method usually
+ * serves as a callback when RNC gets resumed during a task management
+ * sequence. none
+ */
+void scic_sds_remote_device_continue_request(
+ struct scic_sds_remote_device *this_device)
+{
+ /* we need to check if this request is still valid to continue. */
+ if (this_device->working_request != NULL) {
+ struct scic_sds_request *this_request = this_device->working_request;
+ struct scic_sds_controller *scic = this_request->owning_controller;
+ u32 state = scic->parent.state_machine.current_state_id;
+ sci_base_controller_request_handler_t continue_io;
+
+ continue_io = scic_sds_controller_state_handler_table[state].base.continue_io;
+ continue_io(&scic->parent, &this_request->target_device->parent,
+ &this_request->parent);
+ }
+}
+
+/**
+ *
+ * @user_parameter: This is cast to a remote device object.
+ *
+ * This method is called once the remote node context has reached a suspended
+ * state. The remote device can now report that its suspend operation is
+ * complete. none
+ */
+
+/**
+ * This method will terminate all of the IO requests in the controllers IO
+ * request table that were targeted for this device.
+ * @this_device: This parameter specifies the remote device for which to
+ * attempt to terminate all requests.
+ *
+ * This method returns an indication as to whether all requests were
+ * successfully terminated. If a single request fails to be terminated, then
+ * this method will return the failure.
+ */
+static enum sci_status scic_sds_remote_device_terminate_requests(
+ struct scic_sds_remote_device *this_device)
+{
+ enum sci_status status = SCI_SUCCESS;
+ enum sci_status terminate_status = SCI_SUCCESS;
+ struct scic_sds_request *the_request;
+ u32 index;
+ u32 request_count = this_device->started_request_count;
+
+ for (index = 0;
+ (index < SCI_MAX_IO_REQUESTS) && (request_count > 0);
+ index++) {
+ the_request = this_device->owning_port->owning_controller->io_request_table[index];
+
+ if ((the_request != NULL) && (the_request->target_device == this_device)) {
+ terminate_status = scic_controller_terminate_request(
+ this_device->owning_port->owning_controller,
+ this_device,
+ the_request
+ );
+
+ if (terminate_status != SCI_SUCCESS)
+ status = terminate_status;
+
+ request_count--;
+ }
+ }
+
+ return status;
+}
+
+/*
+ * *****************************************************************************
+ * * DEFAULT STATE HANDLERS
+ * ***************************************************************************** */
+
+/**
+ *
+ * @device: The struct sci_base_remote_device which is then cast into a
+ * struct scic_sds_remote_device.
+ *
+ * This method is the default start handler. It logs a warning and returns a
+ * failure. enum sci_status SCI_FAILURE_INVALID_STATE
+ */
+enum sci_status scic_sds_remote_device_default_start_handler(
+ struct sci_base_remote_device *device)
+{
+ struct scic_sds_remote_device *sds_device =
+ (struct scic_sds_remote_device *)device;
+
+ dev_warn(scirdev_to_dev(sds_device),
+ "%s: SCIC Remote Device requested to start while in wrong "
+ "state %d\n",
+ __func__,
+ sci_base_state_machine_get_state(
+ scic_sds_remote_device_get_base_state_machine(
+ sds_device)));
+
+ return SCI_FAILURE_INVALID_STATE;
+}
+
+/**
+ *
+ * @device: The struct sci_base_remote_device which is then cast into a
+ * struct scic_sds_remote_device.
+ *
+ * This method is the default stop handler. It logs a warning and returns a
+ * failure. enum sci_status SCI_FAILURE_INVALID_STATE
+ */
+static enum sci_status scic_sds_remote_device_default_stop_handler(
+ struct sci_base_remote_device *device)
+{
+ struct scic_sds_remote_device *sds_device =
+ (struct scic_sds_remote_device *)device;
+
+ dev_warn(scirdev_to_dev(sds_device),
+ "%s: SCIC Remote Device requested to stop while in wrong "
+ "state %d\n",
+ __func__,
+ sci_base_state_machine_get_state(
+ scic_sds_remote_device_get_base_state_machine(
+ sds_device)));
+
+ return SCI_FAILURE_INVALID_STATE;
+}
+
+/**
+ *
+ * @device: The struct sci_base_remote_device which is then cast into a
+ * struct scic_sds_remote_device.
+ *
+ * This method is the default fail handler. It logs a warning and returns a
+ * failure. enum sci_status SCI_FAILURE_INVALID_STATE
+ */
+enum sci_status scic_sds_remote_device_default_fail_handler(
+ struct sci_base_remote_device *device)
+{
+ struct scic_sds_remote_device *sds_device =
+ (struct scic_sds_remote_device *)device;
+
+ dev_warn(scirdev_to_dev(sds_device),
+ "%s: SCIC Remote Device requested to fail while in wrong "
+ "state %d\n",
+ __func__,
+ sci_base_state_machine_get_state(
+ scic_sds_remote_device_get_base_state_machine(
+ sds_device)));
+
+ return SCI_FAILURE_INVALID_STATE;
+}
+
+/**
+ *
+ * @device: The struct sci_base_remote_device which is then cast into a
+ * struct scic_sds_remote_device.
+ *
+ * This method is the default destruct handler. It logs a warning and returns
+ * a failure. enum sci_status SCI_FAILURE_INVALID_STATE
+ */
+enum sci_status scic_sds_remote_device_default_destruct_handler(
+ struct sci_base_remote_device *device)
+{
+ struct scic_sds_remote_device *sds_device =
+ (struct scic_sds_remote_device *)device;
+
+ dev_warn(scirdev_to_dev(sds_device),
+ "%s: SCIC Remote Device requested to destroy while in "
+ "wrong state %d\n",
+ __func__,
+ sci_base_state_machine_get_state(
+ scic_sds_remote_device_get_base_state_machine(
+ sds_device)));
+
+ return SCI_FAILURE_INVALID_STATE;
+}
+
+/**
+ *
+ * @device: The struct sci_base_remote_device which is then cast into a
+ * struct scic_sds_remote_device.
+ *
+ * This method is the default reset handler. It logs a warning and returns a
+ * failure. enum sci_status SCI_FAILURE_INVALID_STATE
+ */
+enum sci_status scic_sds_remote_device_default_reset_handler(
+ struct sci_base_remote_device *device)
+{
+ struct scic_sds_remote_device *sds_device =
+ (struct scic_sds_remote_device *)device;
+
+ dev_warn(scirdev_to_dev(sds_device),
+ "%s: SCIC Remote Device requested to reset while in wrong "
+ "state %d\n",
+ __func__,
+ sci_base_state_machine_get_state(
+ scic_sds_remote_device_get_base_state_machine(
+ sds_device)));
+
+ return SCI_FAILURE_INVALID_STATE;
+}
+
+/**
+ *
+ * @device: The struct sci_base_remote_device which is then cast into a
+ * struct scic_sds_remote_device.
+ *
+ * This method is the default reset complete handler. It logs a warning and
+ * returns a failure. enum sci_status SCI_FAILURE_INVALID_STATE
+ */
+enum sci_status scic_sds_remote_device_default_reset_complete_handler(
+ struct sci_base_remote_device *device)
+{
+ struct scic_sds_remote_device *sds_device =
+ (struct scic_sds_remote_device *)device;
+
+ dev_warn(scirdev_to_dev(sds_device),
+ "%s: SCIC Remote Device requested to complete reset while "
+ "in wrong state %d\n",
+ __func__,
+ sci_base_state_machine_get_state(
+ scic_sds_remote_device_get_base_state_machine(
+ sds_device)));
+
+ return SCI_FAILURE_INVALID_STATE;
+}
+
+/**
+ *
+ * @device: The struct sci_base_remote_device which is then cast into a
+ * struct scic_sds_remote_device.
+ *
+ * This method is the default suspend handler. It logs a warning and returns a
+ * failure. enum sci_status SCI_FAILURE_INVALID_STATE
+ */
+enum sci_status scic_sds_remote_device_default_suspend_handler(
+ struct scic_sds_remote_device *this_device,
+ u32 suspend_type)
+{
+ dev_warn(scirdev_to_dev(this_device),
+ "%s: SCIC Remote Device 0x%p requested to suspend %d while "
+ "in wrong state %d\n",
+ __func__,
+ this_device,
+ suspend_type,
+ sci_base_state_machine_get_state(
+ scic_sds_remote_device_get_base_state_machine(
+ this_device)));
+
+ return SCI_FAILURE_INVALID_STATE;
+}
+
+/**
+ *
+ * @device: The struct sci_base_remote_device which is then cast into a
+ * struct scic_sds_remote_device.
+ *
+ * This method is the default resume handler. It logs a warning and returns a
+ * failure. enum sci_status SCI_FAILURE_INVALID_STATE
+ */
+enum sci_status scic_sds_remote_device_default_resume_handler(
+ struct scic_sds_remote_device *this_device)
+{
+ dev_warn(scirdev_to_dev(this_device),
+ "%s: SCIC Remote Device requested to resume while in "
+ "wrong state %d\n",
+ __func__,
+ sci_base_state_machine_get_state(
+ scic_sds_remote_device_get_base_state_machine(
+ this_device)));
+
+ return SCI_FAILURE_INVALID_STATE;
+}
+
+/**
+ *
+ * @device: The struct sci_base_remote_device which is then cast into a
+ * struct scic_sds_remote_device.
+ * @event_code: The event code that the struct scic_sds_controller wants the device
+ * object to process.
+ *
+ * This method is the default event handler. It will call the RNC state
+ * machine handler for any RNC events otherwise it will log a warning and
+ * returns a failure. enum sci_status SCI_FAILURE_INVALID_STATE
+ */
+static enum sci_status scic_sds_remote_device_core_event_handler(
+ struct scic_sds_remote_device *this_device,
+ u32 event_code,
+ bool is_ready_state)
+{
+ enum sci_status status;
+
+ switch (scu_get_event_type(event_code)) {
+ case SCU_EVENT_TYPE_RNC_OPS_MISC:
+ case SCU_EVENT_TYPE_RNC_SUSPEND_TX:
+ case SCU_EVENT_TYPE_RNC_SUSPEND_TX_RX:
+ status = scic_sds_remote_node_context_event_handler(this_device->rnc, event_code);
+ break;
+ case SCU_EVENT_TYPE_PTX_SCHEDULE_EVENT:
+
+ if (scu_get_event_code(event_code) == SCU_EVENT_IT_NEXUS_TIMEOUT) {
+ status = SCI_SUCCESS;
+
+ /* Suspend the associated RNC */
+ scic_sds_remote_node_context_suspend(this_device->rnc,
+ SCI_SOFTWARE_SUSPENSION,
+ NULL, NULL);
+
+ dev_dbg(scirdev_to_dev(this_device),
+ "%s: device: %p event code: %x: %s\n",
+ __func__, this_device, event_code,
+ (is_ready_state)
+ ? "I_T_Nexus_Timeout event"
+ : "I_T_Nexus_Timeout event in wrong state");
+
+ break;
+ }
+ /* Else, fall through and treat as unhandled... */
+
+ default:
+ dev_dbg(scirdev_to_dev(this_device),
+ "%s: device: %p event code: %x: %s\n",
+ __func__, this_device, event_code,
+ (is_ready_state)
+ ? "unexpected event"
+ : "unexpected event in wrong state");
+ status = SCI_FAILURE_INVALID_STATE;
+ break;
+ }
+
+ return status;
+}
+/**
+ *
+ * @device: The struct sci_base_remote_device which is then cast into a
+ * struct scic_sds_remote_device.
+ * @event_code: The event code that the struct scic_sds_controller wants the device
+ * object to process.
+ *
+ * This method is the default event handler. It will call the RNC state
+ * machine handler for any RNC events otherwise it will log a warning and
+ * returns a failure. enum sci_status SCI_FAILURE_INVALID_STATE
+ */
+static enum sci_status scic_sds_remote_device_default_event_handler(
+ struct scic_sds_remote_device *this_device,
+ u32 event_code)
+{
+ return scic_sds_remote_device_core_event_handler(this_device,
+ event_code,
+ false);
+}
+
+/**
+ *
+ * @device: The struct sci_base_remote_device which is then cast into a
+ * struct scic_sds_remote_device.
+ * @frame_index: The frame index for which the struct scic_sds_controller wants this
+ * device object to process.
+ *
+ * This method is the default unsolicited frame handler. It logs a warning,
+ * releases the frame and returns a failure. enum sci_status
+ * SCI_FAILURE_INVALID_STATE
+ */
+enum sci_status scic_sds_remote_device_default_frame_handler(
+ struct scic_sds_remote_device *this_device,
+ u32 frame_index)
+{
+ dev_warn(scirdev_to_dev(this_device),
+ "%s: SCIC Remote Device requested to handle frame %x "
+ "while in wrong state %d\n",
+ __func__,
+ frame_index,
+ sci_base_state_machine_get_state(
+ &this_device->parent.state_machine));
+
+ /* Return the frame back to the controller */
+ scic_sds_controller_release_frame(
+ scic_sds_remote_device_get_controller(this_device), frame_index
+ );
+
+ return SCI_FAILURE_INVALID_STATE;
+}
+
+/**
+ *
+ * @device: The struct sci_base_remote_device which is then cast into a
+ * struct scic_sds_remote_device.
+ * @request: The struct sci_base_request which is then cast into a SCIC_SDS_IO_REQUEST
+ * to start.
+ *
+ * This method is the default start io handler. It logs a warning and returns
+ * a failure. enum sci_status SCI_FAILURE_INVALID_STATE
+ */
+enum sci_status scic_sds_remote_device_default_start_request_handler(
+ struct sci_base_remote_device *device,
+ struct sci_base_request *request)
+{
+ struct scic_sds_remote_device *sds_device =
+ (struct scic_sds_remote_device *)device;
+
+ dev_warn(scirdev_to_dev(sds_device),
+ "%s: SCIC Remote Device requested to start io request %p "
+ "while in wrong state %d\n",
+ __func__,
+ request,
+ sci_base_state_machine_get_state(
+ scic_sds_remote_device_get_base_state_machine(
+ (struct scic_sds_remote_device *)device)));
+
+ return SCI_FAILURE_INVALID_STATE;
+}
+
+/**
+ *
+ * @device: The struct sci_base_remote_device which is then cast into a
+ * struct scic_sds_remote_device.
+ * @request: The struct sci_base_request which is then cast into a SCIC_SDS_IO_REQUEST
+ * to complete.
+ *
+ * This method is the default complete io handler. It logs a warning and
+ * returns a failure. enum sci_status SCI_FAILURE_INVALID_STATE
+ */
+enum sci_status scic_sds_remote_device_default_complete_request_handler(
+ struct sci_base_remote_device *device,
+ struct sci_base_request *request)
+{
+ struct scic_sds_remote_device *sds_device =
+ (struct scic_sds_remote_device *)device;
+
+ dev_warn(scirdev_to_dev(sds_device),
+ "%s: SCIC Remote Device requested to complete io_request %p "
+ "while in wrong state %d\n",
+ __func__,
+ request,
+ sci_base_state_machine_get_state(
+ scic_sds_remote_device_get_base_state_machine(
+ sds_device)));
+
+ return SCI_FAILURE_INVALID_STATE;
+}
+
+/**
+ *
+ * @device: The struct sci_base_remote_device which is then cast into a
+ * struct scic_sds_remote_device.
+ * @request: The struct sci_base_request which is then cast into a SCIC_SDS_IO_REQUEST
+ * to continue.
+ *
+ * This method is the default continue io handler. It logs a warning and
+ * returns a failure. enum sci_status SCI_FAILURE_INVALID_STATE
+ */
+enum sci_status scic_sds_remote_device_default_continue_request_handler(
+ struct sci_base_remote_device *device,
+ struct sci_base_request *request)
+{
+ struct scic_sds_remote_device *sds_device =
+ (struct scic_sds_remote_device *)device;
+
+ dev_warn(scirdev_to_dev(sds_device),
+ "%s: SCIC Remote Device requested to continue io request %p "
+ "while in wrong state %d\n",
+ __func__,
+ request,
+ sci_base_state_machine_get_state(
+ scic_sds_remote_device_get_base_state_machine(
+ sds_device)));
+
+ return SCI_FAILURE_INVALID_STATE;
+}
+
+/**
+ *
+ * @device: The struct sci_base_remote_device which is then cast into a
+ * struct scic_sds_remote_device.
+ * @request: The struct sci_base_request which is then cast into a SCIC_SDS_IO_REQUEST
+ * to complete.
+ *
+ * This method is the default complete task handler. It logs a warning and
+ * returns a failure. enum sci_status SCI_FAILURE_INVALID_STATE
+ */
+
+/*
+ * *****************************************************************************
+ * * NORMAL STATE HANDLERS
+ * ***************************************************************************** */
+
+/**
+ *
+ * @device: The struct sci_base_remote_device which is then cast into a
+ * struct scic_sds_remote_device.
+ * @frame_index: The frame index for which the struct scic_sds_controller wants this
+ * device object to process.
+ *
+ * This method is a general ssp frame handler. In most cases the device object
+ * needs to route the unsolicited frame processing to the io request object.
+ * This method decodes the tag for the io request object and routes the
+ * unsolicited frame to that object. enum sci_status SCI_FAILURE_INVALID_STATE
+ */
+enum sci_status scic_sds_remote_device_general_frame_handler(
+ struct scic_sds_remote_device *this_device,
+ u32 frame_index)
+{
+ enum sci_status result;
+ struct sci_ssp_frame_header *frame_header;
+ struct scic_sds_request *io_request;
+
+ result = scic_sds_unsolicited_frame_control_get_header(
+ &(scic_sds_remote_device_get_controller(this_device)->uf_control),
+ frame_index,
+ (void **)&frame_header
+ );
+
+ if (SCI_SUCCESS == result) {
+ io_request = scic_sds_controller_get_io_request_from_tag(
+ scic_sds_remote_device_get_controller(this_device), frame_header->tag);
+
+ if ((io_request == SCI_INVALID_HANDLE)
+ || (io_request->target_device != this_device)) {
+ /*
+ * We could not map this tag to a valid IO request
+ * Just toss the frame and continue */
+ scic_sds_controller_release_frame(
+ scic_sds_remote_device_get_controller(this_device), frame_index
+ );
+ } else {
+ /* The IO request is now in charge of releasing the frame */
+ result = io_request->state_handlers->frame_handler(
+ io_request, frame_index);
+ }
+ }
+
+ return result;
+}
+
+/**
+ *
+ * @[in]: this_device This is the device object that is receiving the event.
+ * @[in]: event_code The event code to process.
+ *
+ * This is a common method for handling events reported to the remote device
+ * from the controller object. enum sci_status
+ */
+enum sci_status scic_sds_remote_device_general_event_handler(
+ struct scic_sds_remote_device *this_device,
+ u32 event_code)
+{
+ return scic_sds_remote_device_core_event_handler(this_device,
+ event_code,
+ true);
+}
+
+/*
+ * *****************************************************************************
+ * * STOPPED STATE HANDLERS
+ * ***************************************************************************** */
+
+/**
+ *
+ * @device:
+ *
+ * This method takes the struct scic_sds_remote_device from a stopped state and
+ * attempts to start it. The RNC buffer for the device is constructed and the
+ * device state machine is transitioned to the
+ * SCIC_BASE_REMOTE_DEVICE_STATE_STARTING. enum sci_status SCI_SUCCESS if there is
+ * an RNC buffer available to construct the remote device.
+ * SCI_FAILURE_INSUFFICIENT_RESOURCES if there is no RNC buffer available in
+ * which to construct the remote device.
+ */
+static enum sci_status scic_sds_remote_device_stopped_state_start_handler(
+ struct sci_base_remote_device *device)
+{
+ enum sci_status status;
+ struct scic_sds_remote_device *this_device = (struct scic_sds_remote_device *)device;
+
+ status = scic_sds_remote_node_context_resume(
+ this_device->rnc,
+ scic_sds_remote_device_resume_complete_handler,
+ this_device
+ );
+
+ if (status == SCI_SUCCESS) {
+ sci_base_state_machine_change_state(
+ scic_sds_remote_device_get_base_state_machine(this_device),
+ SCI_BASE_REMOTE_DEVICE_STATE_STARTING
+ );
+ }
+
+ return status;
+}
+
+/**
+ *
+ * @this_device: The struct sci_base_remote_device which is cast into a
+ * struct scic_sds_remote_device.
+ *
+ * This method will stop a struct scic_sds_remote_device that is already in a stopped
+ * state. This is not considered an error since the device is already stopped.
+ * enum sci_status SCI_SUCCESS
+ */
+static enum sci_status scic_sds_remote_device_stopped_state_stop_handler(
+ struct sci_base_remote_device *this_device)
+{
+ return SCI_SUCCESS;
+}
+
+/**
+ *
+ * @this_device: The struct sci_base_remote_device which is cast into a
+ * struct scic_sds_remote_device.
+ *
+ * This method will destruct a struct scic_sds_remote_device that is in a stopped
+ * state. This is the only state from which a destruct request will succeed.
+ * The RNi for this struct scic_sds_remote_device is returned to the free pool and the
+ * device object transitions to the SCI_BASE_REMOTE_DEVICE_STATE_FINAL.
+ * enum sci_status SCI_SUCCESS
+ */
+static enum sci_status scic_sds_remote_device_stopped_state_destruct_handler(
+ struct sci_base_remote_device *device)
+{
+ struct scic_sds_remote_device *this_device = (struct scic_sds_remote_device *)device;
+
+ scic_sds_controller_free_remote_node_context(
+ scic_sds_remote_device_get_controller(this_device),
+ this_device,
+ this_device->rnc->remote_node_index
+ );
+
+ scic_sds_remote_node_context_set_remote_node_index(
+ this_device->rnc,
+ SCIC_SDS_REMOTE_NODE_CONTEXT_INVALID_INDEX
+ );
+
+ scic_sds_port_set_direct_attached_device_id(
+ this_device->owning_port,
+ SCIC_SDS_REMOTE_NODE_CONTEXT_INVALID_INDEX
+ );
+
+ sci_base_state_machine_change_state(
+ scic_sds_remote_device_get_base_state_machine(this_device),
+ SCI_BASE_REMOTE_DEVICE_STATE_FINAL
+ );
+
+ return SCI_SUCCESS;
+}
+
+/*
+ * *****************************************************************************
+ * * STARTING STATE HANDLERS
+ * ***************************************************************************** */
+
+static enum sci_status scic_sds_remote_device_starting_state_stop_handler(
+ struct sci_base_remote_device *device)
+{
+ struct scic_sds_remote_device *this_device = (struct scic_sds_remote_device *)device;
+
+ /*
+ * This device has not yet started so there had better be no IO requests
+ */
+ BUG_ON(this_device->started_request_count != 0);
+
+ /*
+ * Destroy the remote node context
+ */
+ scic_sds_remote_node_context_destruct(
+ this_device->rnc,
+ scic_sds_cb_remote_device_rnc_destruct_complete,
+ this_device
+ );
+
+ /*
+ * Transition to the stopping state and wait for the remote node to
+ * complete being posted and invalidated.
+ */
+ sci_base_state_machine_change_state(
+ scic_sds_remote_device_get_base_state_machine(this_device),
+ SCI_BASE_REMOTE_DEVICE_STATE_STOPPING
+ );
+
+ return SCI_SUCCESS;
+}
+
+/*
+ * *****************************************************************************
+ * * INITIALIZING STATE HANDLERS
+ * ***************************************************************************** */
+
+/* There is nothing to do here for SSP devices */
+
+/*
+ * *****************************************************************************
+ * * READY STATE HANDLERS
+ * ***************************************************************************** */
+
+/**
+ *
+ * @this_device: The struct scic_sds_remote_device object to be suspended.
+ *
+ * This method is the resume handler for the struct scic_sds_remote_device object. It
+ * will post an RNC resume to the SCU hardware. enum sci_status SCI_SUCCESS
+ */
+
+/**
+ *
+ * @device: The struct sci_base_remote_device object which is cast to a
+ * struct scic_sds_remote_device object.
+ *
+ * This method is the default stop handler for the struct scic_sds_remote_device ready
+ * substate machine. It will stop the current substate machine and transition
+ * the base state machine to SCI_BASE_REMOTE_DEVICE_STATE_STOPPING. enum sci_status
+ * SCI_SUCCESS
+ */
+enum sci_status scic_sds_remote_device_ready_state_stop_handler(
+ struct sci_base_remote_device *device)
+{
+ struct scic_sds_remote_device *this_device = (struct scic_sds_remote_device *)device;
+ enum sci_status status = SCI_SUCCESS;
+
+ /* Request the parent state machine to transition to the stopping state */
+ sci_base_state_machine_change_state(
+ scic_sds_remote_device_get_base_state_machine(this_device),
+ SCI_BASE_REMOTE_DEVICE_STATE_STOPPING
+ );
+
+ if (this_device->started_request_count == 0) {
+ scic_sds_remote_node_context_destruct(
+ this_device->rnc,
+ scic_sds_cb_remote_device_rnc_destruct_complete,
+ this_device
+ );
+ } else
+ status = scic_sds_remote_device_terminate_requests(this_device);
+
+ return status;
+}
+
+/**
+ *
+ * @device: The struct sci_base_remote_device object which is cast to a
+ * struct scic_sds_remote_device object.
+ *
+ * This is the ready state device reset handler enum sci_status
+ */
+enum sci_status scic_sds_remote_device_ready_state_reset_handler(
+ struct sci_base_remote_device *device)
+{
+ struct scic_sds_remote_device *this_device = (struct scic_sds_remote_device *)device;
+
+ /* Request the parent state machine to transition to the stopping state */
+ sci_base_state_machine_change_state(
+ scic_sds_remote_device_get_base_state_machine(this_device),
+ SCI_BASE_REMOTE_DEVICE_STATE_RESETTING
+ );
+
+ return SCI_SUCCESS;
+}
+
+/**
+ *
+ * @device: The struct sci_base_remote_device object which is cast to a
+ * struct scic_sds_remote_device object.
+ *
+ * This is the default fail handler for the struct scic_sds_remote_device ready
+ * substate machine. It will stop the current ready substate and transition
+ * the remote device object to the SCI_BASE_REMOTE_DEVICE_STATE_FAILED.
+ * enum sci_status SCI_SUCCESS
+ */
+
+/**
+ *
+ * @device: The struct sci_base_remote_device which is cast to a
+ * struct scic_sds_remote_device for which the request is to be started.
+ * @request: The struct sci_base_request which is cast to a SCIC_SDS_IO_REQUEST that
+ * is to be started.
+ *
+ * This method will attempt to start a task request for this device object. The
+ * remote device object will issue the start request for the task and if
+ * successful it will start the request for the port object then increment its
+ * own requet count. enum sci_status SCI_SUCCESS if the task request is started for
+ * this device object. SCI_FAILURE_INSUFFICIENT_RESOURCES if the io request
+ * object could not get the resources to start.
+ */
+static enum sci_status scic_sds_remote_device_ready_state_start_task_handler(
+ struct sci_base_remote_device *device,
+ struct sci_base_request *request)
+{
+ enum sci_status result;
+ struct scic_sds_remote_device *this_device = (struct scic_sds_remote_device *)device;
+ struct scic_sds_request *task_request = (struct scic_sds_request *)request;
+
+ /* See if the port is in a state where we can start the IO request */
+ result = scic_sds_port_start_io(
+ scic_sds_remote_device_get_port(this_device), this_device, task_request);
+
+ if (result == SCI_SUCCESS) {
+ result = scic_sds_remote_node_context_start_task(
+ this_device->rnc, task_request
+ );
+
+ if (result == SCI_SUCCESS) {
+ result = scic_sds_request_start(task_request);
+ }
+
+ scic_sds_remote_device_start_request(this_device, task_request, result);
+ }
+
+ return result;
+}
+
+/**
+ *
+ * @device: The struct sci_base_remote_device which is cast to a
+ * struct scic_sds_remote_device for which the request is to be started.
+ * @request: The struct sci_base_request which is cast to a SCIC_SDS_IO_REQUEST that
+ * is to be started.
+ *
+ * This method will attempt to start an io request for this device object. The
+ * remote device object will issue the start request for the io and if
+ * successful it will start the request for the port object then increment its
+ * own requet count. enum sci_status SCI_SUCCESS if the io request is started for
+ * this device object. SCI_FAILURE_INSUFFICIENT_RESOURCES if the io request
+ * object could not get the resources to start.
+ */
+static enum sci_status scic_sds_remote_device_ready_state_start_io_handler(
+ struct sci_base_remote_device *device,
+ struct sci_base_request *request)
+{
+ enum sci_status result;
+ struct scic_sds_remote_device *this_device = (struct scic_sds_remote_device *)device;
+ struct scic_sds_request *io_request = (struct scic_sds_request *)request;
+
+ /* See if the port is in a state where we can start the IO request */
+ result = scic_sds_port_start_io(
+ scic_sds_remote_device_get_port(this_device), this_device, io_request);
+
+ if (result == SCI_SUCCESS) {
+ result = scic_sds_remote_node_context_start_io(
+ this_device->rnc, io_request
+ );
+
+ if (result == SCI_SUCCESS) {
+ result = scic_sds_request_start(io_request);
+ }
+
+ scic_sds_remote_device_start_request(this_device, io_request, result);
+ }
+
+ return result;
+}
+
+/**
+ *
+ * @device: The struct sci_base_remote_device which is cast to a
+ * struct scic_sds_remote_device for which the request is to be completed.
+ * @request: The struct sci_base_request which is cast to a SCIC_SDS_IO_REQUEST that
+ * is to be completed.
+ *
+ * This method will complete the request for the remote device object. The
+ * method will call the completion handler for the request object and if
+ * successful it will complete the request on the port object then decrement
+ * its own started_request_count. enum sci_status
+ */
+static enum sci_status scic_sds_remote_device_ready_state_complete_request_handler(
+ struct sci_base_remote_device *device,
+ struct sci_base_request *request)
+{
+ enum sci_status result;
+ struct scic_sds_remote_device *this_device = (struct scic_sds_remote_device *)device;
+ struct scic_sds_request *the_request = (struct scic_sds_request *)request;
+
+ result = scic_sds_request_complete(the_request);
+
+ if (result == SCI_SUCCESS) {
+ /* See if the port is in a state where we can start the IO request */
+ result = scic_sds_port_complete_io(
+ scic_sds_remote_device_get_port(this_device), this_device, the_request);
+
+ if (result == SCI_SUCCESS) {
+ scic_sds_remote_device_decrement_request_count(this_device);
+ }
+ }
+
+ return result;
+}
+
+/*
+ * *****************************************************************************
+ * * STOPPING STATE HANDLERS
+ * ***************************************************************************** */
+
+/**
+ *
+ * @this_device: The struct sci_base_remote_device which is cast into a
+ * struct scic_sds_remote_device.
+ *
+ * This method will stop a struct scic_sds_remote_device that is already in the
+ * SCI_BASE_REMOTE_DEVICE_STATE_STOPPING state. This is not considered an error
+ * since we allow a stop request on a device that is alreay stopping or
+ * stopped. enum sci_status SCI_SUCCESS
+ */
+static enum sci_status scic_sds_remote_device_stopping_state_stop_handler(
+ struct sci_base_remote_device *device)
+{
+ /*
+ * All requests should have been terminated, but if there is an
+ * attempt to stop a device already in the stopping state, then
+ * try again to terminate. */
+ return scic_sds_remote_device_terminate_requests(
+ (struct scic_sds_remote_device *)device);
+}
+
+
+/**
+ *
+ * @device: The device object for which the request is completing.
+ * @request: The task request that is being completed.
+ *
+ * This method completes requests for this struct scic_sds_remote_device while it is
+ * in the SCI_BASE_REMOTE_DEVICE_STATE_STOPPING state. This method calls the
+ * complete method for the request object and if that is successful the port
+ * object is called to complete the task request. Then the device object itself
+ * completes the task request. If struct scic_sds_remote_device started_request_count
+ * goes to 0 and the invalidate RNC request has completed the device object can
+ * transition to the SCI_BASE_REMOTE_DEVICE_STATE_STOPPED. enum sci_status
+ */
+static enum sci_status scic_sds_remote_device_stopping_state_complete_request_handler(
+ struct sci_base_remote_device *device,
+ struct sci_base_request *request)
+{
+ enum sci_status status = SCI_SUCCESS;
+ struct scic_sds_request *this_request = (struct scic_sds_request *)request;
+ struct scic_sds_remote_device *this_device = (struct scic_sds_remote_device *)device;
+
+ status = scic_sds_request_complete(this_request);
+ if (status == SCI_SUCCESS) {
+ status = scic_sds_port_complete_io(
+ scic_sds_remote_device_get_port(this_device),
+ this_device,
+ this_request
+ );
+
+ if (status == SCI_SUCCESS) {
+ scic_sds_remote_device_decrement_request_count(this_device);
+
+ if (scic_sds_remote_device_get_request_count(this_device) == 0) {
+ scic_sds_remote_node_context_destruct(
+ this_device->rnc,
+ scic_sds_cb_remote_device_rnc_destruct_complete,
+ this_device
+ );
+ }
+ }
+ }
+
+ return status;
+}
+
+/*
+ * *****************************************************************************
+ * * RESETTING STATE HANDLERS
+ * ***************************************************************************** */
+
+/**
+ *
+ * @device: The struct sci_base_remote_device which is to be cast into a
+ * struct scic_sds_remote_device object.
+ *
+ * This method will complete the reset operation when the device is in the
+ * resetting state. enum sci_status
+ */
+static enum sci_status scic_sds_remote_device_resetting_state_reset_complete_handler(
+ struct sci_base_remote_device *device)
+{
+ struct scic_sds_remote_device *this_device = (struct scic_sds_remote_device *)device;
+
+ sci_base_state_machine_change_state(
+ &this_device->parent.state_machine,
+ SCI_BASE_REMOTE_DEVICE_STATE_READY
+ );
+
+ return SCI_SUCCESS;
+}
+
+/**
+ *
+ * @device: The struct sci_base_remote_device which is to be cast into a
+ * struct scic_sds_remote_device object.
+ *
+ * This method will stop the remote device while in the resetting state.
+ * enum sci_status
+ */
+static enum sci_status scic_sds_remote_device_resetting_state_stop_handler(
+ struct sci_base_remote_device *device)
+{
+ struct scic_sds_remote_device *this_device = (struct scic_sds_remote_device *)device;
+
+ sci_base_state_machine_change_state(
+ &this_device->parent.state_machine,
+ SCI_BASE_REMOTE_DEVICE_STATE_STOPPING
+ );
+
+ return SCI_SUCCESS;
+}
+
+/**
+ *
+ * @device: The device object for which the request is completing.
+ * @request: The task request that is being completed.
+ *
+ * This method completes requests for this struct scic_sds_remote_device while it is
+ * in the SCI_BASE_REMOTE_DEVICE_STATE_RESETTING state. This method calls the
+ * complete method for the request object and if that is successful the port
+ * object is called to complete the task request. Then the device object itself
+ * completes the task request. enum sci_status
+ */
+static enum sci_status scic_sds_remote_device_resetting_state_complete_request_handler(
+ struct sci_base_remote_device *device,
+ struct sci_base_request *request)
+{
+ enum sci_status status = SCI_SUCCESS;
+ struct scic_sds_request *this_request = (struct scic_sds_request *)request;
+ struct scic_sds_remote_device *this_device = (struct scic_sds_remote_device *)device;
+
+ status = scic_sds_request_complete(this_request);
+
+ if (status == SCI_SUCCESS) {
+ status = scic_sds_port_complete_io(
+ scic_sds_remote_device_get_port(this_device), this_device, this_request);
+
+ if (status == SCI_SUCCESS) {
+ scic_sds_remote_device_decrement_request_count(this_device);
+ }
+ }
+
+ return status;
+}
+
+/*
+ * *****************************************************************************
+ * * FAILED STATE HANDLERS
+ * ***************************************************************************** */
+
+/**
+ *
+ * @device: The struct sci_base_remote_device which is to be cast into a
+ * struct scic_sds_remote_device object.
+ *
+ * This method handles the remove request for a failed struct scic_sds_remote_device
+ * object. The method will transition the device object to the
+ * SCIC_BASE_REMOTE_DEVICE_STATE_STOPPING. enum sci_status SCI_SUCCESS
+ */
+
+/* --------------------------------------------------------------------------- */
+
+struct scic_sds_remote_device_state_handler
+scic_sds_remote_device_state_handler_table[SCI_BASE_REMOTE_DEVICE_MAX_STATES] =
+{
+ /* SCI_BASE_REMOTE_DEVICE_STATE_INITIAL */
+ {
+ {
+ scic_sds_remote_device_default_start_handler,
+ scic_sds_remote_device_default_stop_handler,
+ scic_sds_remote_device_default_fail_handler,
+ scic_sds_remote_device_default_destruct_handler,
+ scic_sds_remote_device_default_reset_handler,
+ scic_sds_remote_device_default_reset_complete_handler,
+ scic_sds_remote_device_default_start_request_handler,
+ scic_sds_remote_device_default_complete_request_handler,
+ scic_sds_remote_device_default_continue_request_handler,
+ scic_sds_remote_device_default_start_request_handler,
+ scic_sds_remote_device_default_complete_request_handler
+ },
+ scic_sds_remote_device_default_suspend_handler,
+ scic_sds_remote_device_default_resume_handler,
+ scic_sds_remote_device_default_event_handler,
+ scic_sds_remote_device_default_frame_handler
+ },
+ /* SCI_BASE_REMOTE_DEVICE_STATE_STOPPED */
+ {
+ {
+ scic_sds_remote_device_stopped_state_start_handler,
+ scic_sds_remote_device_stopped_state_stop_handler,
+ scic_sds_remote_device_default_fail_handler,
+ scic_sds_remote_device_stopped_state_destruct_handler,
+ scic_sds_remote_device_default_reset_handler,
+ scic_sds_remote_device_default_reset_complete_handler,
+ scic_sds_remote_device_default_start_request_handler,
+ scic_sds_remote_device_default_complete_request_handler,
+ scic_sds_remote_device_default_continue_request_handler,
+ scic_sds_remote_device_default_start_request_handler,
+ scic_sds_remote_device_default_complete_request_handler
+ },
+ scic_sds_remote_device_default_suspend_handler,
+ scic_sds_remote_device_default_resume_handler,
+ scic_sds_remote_device_default_event_handler,
+ scic_sds_remote_device_default_frame_handler
+ },
+ /* SCI_BASE_REMOTE_DEVICE_STATE_STARTING */
+ {
+ {
+ scic_sds_remote_device_default_start_handler,
+ scic_sds_remote_device_starting_state_stop_handler,
+ scic_sds_remote_device_default_fail_handler,
+ scic_sds_remote_device_default_destruct_handler,
+ scic_sds_remote_device_default_reset_handler,
+ scic_sds_remote_device_default_reset_complete_handler,
+ scic_sds_remote_device_default_start_request_handler,
+ scic_sds_remote_device_default_complete_request_handler,
+ scic_sds_remote_device_default_continue_request_handler,
+ scic_sds_remote_device_default_start_request_handler,
+ scic_sds_remote_device_default_complete_request_handler
+ },
+ scic_sds_remote_device_default_suspend_handler,
+ scic_sds_remote_device_default_resume_handler,
+ scic_sds_remote_device_general_event_handler,
+ scic_sds_remote_device_default_frame_handler
+ },
+ /* SCI_BASE_REMOTE_DEVICE_STATE_READY */
+ {
+ {
+ scic_sds_remote_device_default_start_handler,
+ scic_sds_remote_device_ready_state_stop_handler,
+ scic_sds_remote_device_default_fail_handler,
+ scic_sds_remote_device_default_destruct_handler,
+ scic_sds_remote_device_ready_state_reset_handler,
+ scic_sds_remote_device_default_reset_complete_handler,
+ scic_sds_remote_device_ready_state_start_io_handler,
+ scic_sds_remote_device_ready_state_complete_request_handler,
+ scic_sds_remote_device_default_continue_request_handler,
+ scic_sds_remote_device_ready_state_start_task_handler,
+ scic_sds_remote_device_ready_state_complete_request_handler
+ },
+ scic_sds_remote_device_default_suspend_handler,
+ scic_sds_remote_device_default_resume_handler,
+ scic_sds_remote_device_general_event_handler,
+ scic_sds_remote_device_general_frame_handler,
+ },
+ /* SCI_BASE_REMOTE_DEVICE_STATE_STOPPING */
+ {
+ {
+ scic_sds_remote_device_default_start_handler,
+ scic_sds_remote_device_stopping_state_stop_handler,
+ scic_sds_remote_device_default_fail_handler,
+ scic_sds_remote_device_default_destruct_handler,
+ scic_sds_remote_device_default_reset_handler,
+ scic_sds_remote_device_default_reset_complete_handler,
+ scic_sds_remote_device_default_start_request_handler,
+ scic_sds_remote_device_stopping_state_complete_request_handler,
+ scic_sds_remote_device_default_continue_request_handler,
+ scic_sds_remote_device_default_start_request_handler,
+ scic_sds_remote_device_stopping_state_complete_request_handler
+ },
+ scic_sds_remote_device_default_suspend_handler,
+ scic_sds_remote_device_default_resume_handler,
+ scic_sds_remote_device_general_event_handler,
+ scic_sds_remote_device_general_frame_handler
+ },
+ /* SCI_BASE_REMOTE_DEVICE_STATE_FAILED */
+ {
+ {
+ scic_sds_remote_device_default_start_handler,
+ scic_sds_remote_device_default_stop_handler,
+ scic_sds_remote_device_default_fail_handler,
+ scic_sds_remote_device_default_destruct_handler,
+ scic_sds_remote_device_default_reset_handler,
+ scic_sds_remote_device_default_reset_complete_handler,
+ scic_sds_remote_device_default_start_request_handler,
+ scic_sds_remote_device_default_complete_request_handler,
+ scic_sds_remote_device_default_continue_request_handler,
+ scic_sds_remote_device_default_start_request_handler,
+ scic_sds_remote_device_default_complete_request_handler
+ },
+ scic_sds_remote_device_default_suspend_handler,
+ scic_sds_remote_device_default_resume_handler,
+ scic_sds_remote_device_default_event_handler,
+ scic_sds_remote_device_general_frame_handler
+ },
+ /* SCI_BASE_REMOTE_DEVICE_STATE_RESETTING */
+ {
+ {
+ scic_sds_remote_device_default_start_handler,
+ scic_sds_remote_device_resetting_state_stop_handler,
+ scic_sds_remote_device_default_fail_handler,
+ scic_sds_remote_device_default_destruct_handler,
+ scic_sds_remote_device_default_reset_handler,
+ scic_sds_remote_device_resetting_state_reset_complete_handler,
+ scic_sds_remote_device_default_start_request_handler,
+ scic_sds_remote_device_resetting_state_complete_request_handler,
+ scic_sds_remote_device_default_continue_request_handler,
+ scic_sds_remote_device_default_start_request_handler,
+ scic_sds_remote_device_resetting_state_complete_request_handler
+ },
+ scic_sds_remote_device_default_suspend_handler,
+ scic_sds_remote_device_default_resume_handler,
+ scic_sds_remote_device_default_event_handler,
+ scic_sds_remote_device_general_frame_handler
+ },
+ /* SCI_BASE_REMOTE_DEVICE_STATE_FINAL */
+ {
+ {
+ scic_sds_remote_device_default_start_handler,
+ scic_sds_remote_device_default_stop_handler,
+ scic_sds_remote_device_default_fail_handler,
+ scic_sds_remote_device_default_destruct_handler,
+ scic_sds_remote_device_default_reset_handler,
+ scic_sds_remote_device_default_reset_complete_handler,
+ scic_sds_remote_device_default_start_request_handler,
+ scic_sds_remote_device_default_complete_request_handler,
+ scic_sds_remote_device_default_continue_request_handler,
+ scic_sds_remote_device_default_start_request_handler,
+ scic_sds_remote_device_default_complete_request_handler
+ },
+ scic_sds_remote_device_default_suspend_handler,
+ scic_sds_remote_device_default_resume_handler,
+ scic_sds_remote_device_default_event_handler,
+ scic_sds_remote_device_default_frame_handler
+ }
+};
+
+/*
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Intel Corporation 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
+ * OWNER 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.
+ */
+
+/**
+ * This file contains the operations that are taken on the enter and exit state
+ * transitions for the struct sci_base_remote_device state machine.
+ *
+ *
+ */
+
+#include "scic_remote_device.h"
+#include "scic_user_callback.h"
+#include "scic_sds_controller.h"
+#include "scic_sds_remote_device.h"
+#include "scic_sds_request.h"
+#include "scic_sds_controller.h"
+#include "scic_sds_port.h"
+
+/**
+ *
+ * @object: This is the struct sci_base_object that is cast into a
+ * struct scic_sds_remote_device.
+ *
+ * This is the enter method for the SCI_BASE_REMOTE_DEVICE_STATE_INITIAL it
+ * immediatly transitions the remote device object to the stopped state. none
+ */
+static void scic_sds_remote_device_initial_state_enter(
+ struct sci_base_object *object)
+{
+ struct scic_sds_remote_device *this_device = (struct scic_sds_remote_device *)object;
+
+ SET_STATE_HANDLER(
+ this_device,
+ scic_sds_remote_device_state_handler_table,
+ SCI_BASE_REMOTE_DEVICE_STATE_INITIAL
+ );
+
+ /* Initial state is a transitional state to the stopped state */
+ sci_base_state_machine_change_state(
+ scic_sds_remote_device_get_base_state_machine(this_device),
+ SCI_BASE_REMOTE_DEVICE_STATE_STOPPED
+ );
+}
+
+/**
+ *
+ * @object: This is the struct sci_base_object that is cast into a
+ * struct scic_sds_remote_device.
+ *
+ * This is the enter method for the SCI_BASE_REMOTE_DEVICE_STATE_INITIAL it
+ * sets the stopped state handlers and if this state is entered from the
+ * SCI_BASE_REMOTE_DEVICE_STATE_STOPPING then the SCI User is informed that the
+ * device stop is complete. none
+ */
+static void scic_sds_remote_device_stopped_state_enter(
+ struct sci_base_object *object)
+{
+ struct scic_sds_remote_device *this_device = (struct scic_sds_remote_device *)object;
+
+ SET_STATE_HANDLER(
+ this_device,
+ scic_sds_remote_device_state_handler_table,
+ SCI_BASE_REMOTE_DEVICE_STATE_STOPPED
+ );
+
+ /*
+ * If we are entering from the stopping state let the SCI User know that
+ * the stop operation has completed. */
+ if (this_device->parent.state_machine.previous_state_id
+ == SCI_BASE_REMOTE_DEVICE_STATE_STOPPING) {
+ scic_cb_remote_device_stop_complete(
+ scic_sds_remote_device_get_controller(this_device),
+ this_device,
+ SCI_SUCCESS
+ );
+ }
+}
+
+/**
+ *
+ * @object: This is the struct sci_base_object that is cast into a
+ * struct scic_sds_remote_device.
+ *
+ * This is the enter method for the SCI_BASE_REMOTE_DEVICE_STATE_STARTING it
+ * sets the starting state handlers, sets the device not ready, and posts the
+ * remote node context to the hardware. none
+ */
+static void scic_sds_remote_device_starting_state_enter(
+ struct sci_base_object *object)
+{
+ struct scic_sds_controller *the_controller;
+ struct scic_sds_remote_device *this_device = (struct scic_sds_remote_device *)object;
+
+ the_controller = scic_sds_remote_device_get_controller(this_device);
+
+ SET_STATE_HANDLER(
+ this_device,
+ scic_sds_remote_device_state_handler_table,
+ SCI_BASE_REMOTE_DEVICE_STATE_STARTING
+ );
+
+ scic_cb_remote_device_not_ready(
+ the_controller,
+ this_device,
+ SCIC_REMOTE_DEVICE_NOT_READY_START_REQUESTED
+ );
+}
+
+/**
+ *
+ * @object: This is the struct sci_base_object that is cast into a
+ * struct scic_sds_remote_device.
+ *
+ * This is the exit method for the SCI_BASE_REMOTE_DEVICE_STATE_STARTING it
+ * reports that the device start is complete. none
+ */
+static void scic_sds_remote_device_starting_state_exit(
+ struct sci_base_object *object)
+{
+ struct scic_sds_remote_device *this_device = (struct scic_sds_remote_device *)object;
+
+ /*
+ * / @todo Check the device object for the proper return code for this
+ * / callback */
+ scic_cb_remote_device_start_complete(
+ scic_sds_remote_device_get_controller(this_device),
+ this_device,
+ SCI_SUCCESS
+ );
+}
+
+/**
+ *
+ * @object: This is the struct sci_base_object that is cast into a
+ * struct scic_sds_remote_device.
+ *
+ * This is the enter method for the SCI_BASE_REMOTE_DEVICE_STATE_READY it sets
+ * the ready state handlers, and starts the ready substate machine. none
+ */
+static void scic_sds_remote_device_ready_state_enter(
+ struct sci_base_object *object)
+{
+ struct scic_sds_controller *the_controller;
+ struct scic_sds_remote_device *this_device = (struct scic_sds_remote_device *)object;
+
+ the_controller = scic_sds_remote_device_get_controller(this_device);
+
+ SET_STATE_HANDLER(
+ this_device,
+ scic_sds_remote_device_state_handler_table,
+ SCI_BASE_REMOTE_DEVICE_STATE_READY
+ );
+
+ the_controller->remote_device_sequence[this_device->rnc->remote_node_index]++;
+
+ if (this_device->has_ready_substate_machine) {
+ sci_base_state_machine_start(&this_device->ready_substate_machine);
+ } else {
+ scic_cb_remote_device_ready(the_controller, this_device);
+ }
+}
+
+/**
+ *
+ * @object: This is the struct sci_base_object that is cast into a
+ * struct scic_sds_remote_device.
+ *
+ * This is the exit method for the SCI_BASE_REMOTE_DEVICE_STATE_READY it does
+ * nothing. none
+ */
+static void scic_sds_remote_device_ready_state_exit(
+ struct sci_base_object *object)
+{
+ struct scic_sds_controller *the_controller;
+ struct scic_sds_remote_device *this_device = (struct scic_sds_remote_device *)object;
+
+ the_controller = scic_sds_remote_device_get_controller(this_device);
+
+ if (this_device->has_ready_substate_machine) {
+ sci_base_state_machine_stop(&this_device->ready_substate_machine);
+ } else {
+ scic_cb_remote_device_not_ready(
+ the_controller,
+ this_device,
+ SCIC_REMOTE_DEVICE_NOT_READY_STOP_REQUESTED
+ );
+ }
+}
+
+/**
+ *
+ * @object: This is the struct sci_base_object that is cast into a
+ * struct scic_sds_remote_device.
+ *
+ * This is the enter method for the SCI_BASE_REMOTE_DEVICE_STATE_STOPPING it
+ * sets the stopping state handlers and posts an RNC invalidate request to the
+ * SCU hardware. none
+ */
+static void scic_sds_remote_device_stopping_state_enter(
+ struct sci_base_object *object)
+{
+ struct scic_sds_remote_device *this_device = (struct scic_sds_remote_device *)object;
+
+ SET_STATE_HANDLER(
+ this_device,
+ scic_sds_remote_device_state_handler_table,
+ SCI_BASE_REMOTE_DEVICE_STATE_STOPPING
+ );
+}
+
+/**
+ *
+ * @object: This is the struct sci_base_object that is cast into a
+ * struct scic_sds_remote_device.
+ *
+ * This is the enter method for the SCI_BASE_REMOTE_DEVICE_STATE_FAILED it sets
+ * the stopping state handlers. none
+ */
+static void scic_sds_remote_device_failed_state_enter(
+ struct sci_base_object *object)
+{
+ struct scic_sds_remote_device *this_device = (struct scic_sds_remote_device *)object;
+
+ SET_STATE_HANDLER(
+ this_device,
+ scic_sds_remote_device_state_handler_table,
+ SCI_BASE_REMOTE_DEVICE_STATE_FAILED
+ );
+}
+
+/**
+ *
+ * @object: This is the struct sci_base_object that is cast into a
+ * struct scic_sds_remote_device.
+ *
+ * This is the enter method for the SCI_BASE_REMOTE_DEVICE_STATE_RESETTING it
+ * sets the resetting state handlers. none
+ */
+static void scic_sds_remote_device_resetting_state_enter(
+ struct sci_base_object *object)
+{
+ struct scic_sds_remote_device *this_device = (struct scic_sds_remote_device *)object;
+
+ SET_STATE_HANDLER(
+ this_device,
+ scic_sds_remote_device_state_handler_table,
+ SCI_BASE_REMOTE_DEVICE_STATE_RESETTING
+ );
+
+ scic_sds_remote_node_context_suspend(
+ this_device->rnc, SCI_SOFTWARE_SUSPENSION, NULL, NULL);
+}
+
+/**
+ *
+ * @object: This is the struct sci_base_object that is cast into a
+ * struct scic_sds_remote_device.
+ *
+ * This is the exit method for the SCI_BASE_REMOTE_DEVICE_STATE_RESETTING it
+ * does nothing. none
+ */
+static void scic_sds_remote_device_resetting_state_exit(
+ struct sci_base_object *object)
+{
+ struct scic_sds_remote_device *this_device = (struct scic_sds_remote_device *)object;
+
+ scic_sds_port_set_direct_attached_device_id(
+ scic_sds_remote_device_get_port(this_device),
+ this_device->rnc->remote_node_index
+ );
+
+ scic_sds_remote_node_context_resume(this_device->rnc, NULL, NULL);
+}
+
+/**
+ *
+ * @object: This is the struct sci_base_object that is cast into a
+ * struct scic_sds_remote_device.
+ *
+ * This is the enter method for the SCI_BASE_REMOTE_DEVICE_STATE_FINAL it sets
+ * the final state handlers. none
+ */
+static void scic_sds_remote_device_final_state_enter(
+ struct sci_base_object *object)
+{
+ struct scic_sds_remote_device *this_device = (struct scic_sds_remote_device *)object;
+
+ SET_STATE_HANDLER(
+ this_device,
+ scic_sds_remote_device_state_handler_table,
+ SCI_BASE_REMOTE_DEVICE_STATE_FINAL
+ );
+}
+
+/* --------------------------------------------------------------------------- */
+
+const struct sci_base_state scic_sds_remote_device_state_table[] = {
+ [SCI_BASE_REMOTE_DEVICE_STATE_INITIAL] = {
+ .enter_state = scic_sds_remote_device_initial_state_enter,
+ },
+ [SCI_BASE_REMOTE_DEVICE_STATE_STOPPED] = {
+ .enter_state = scic_sds_remote_device_stopped_state_enter,
+ },
+ [SCI_BASE_REMOTE_DEVICE_STATE_STARTING] = {
+ .enter_state = scic_sds_remote_device_starting_state_enter,
+ .exit_state = scic_sds_remote_device_starting_state_exit
+ },
+ [SCI_BASE_REMOTE_DEVICE_STATE_READY] = {
+ .enter_state = scic_sds_remote_device_ready_state_enter,
+ .exit_state = scic_sds_remote_device_ready_state_exit
+ },
+ [SCI_BASE_REMOTE_DEVICE_STATE_STOPPING] = {
+ .enter_state = scic_sds_remote_device_stopping_state_enter,
+ },
+ [SCI_BASE_REMOTE_DEVICE_STATE_FAILED] = {
+ .enter_state = scic_sds_remote_device_failed_state_enter,
+ },
+ [SCI_BASE_REMOTE_DEVICE_STATE_RESETTING] = {
+ .enter_state = scic_sds_remote_device_resetting_state_enter,
+ .exit_state = scic_sds_remote_device_resetting_state_exit
+ },
+ [SCI_BASE_REMOTE_DEVICE_STATE_FINAL] = {
+ .enter_state = scic_sds_remote_device_final_state_enter,
+ },
+};
+
diff --git a/drivers/scsi/isci/core/scic_sds_remote_device.h b/drivers/scsi/isci/core/scic_sds_remote_device.h
new file mode 100644
index 000000000000..44185a2738ec
--- /dev/null
+++ b/drivers/scsi/isci/core/scic_sds_remote_device.h
@@ -0,0 +1,602 @@
+/*
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Intel Corporation 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
+ * OWNER 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.
+ */
+
+#ifndef _SCIC_SDS_REMOTE_DEVICE_H_
+#define _SCIC_SDS_REMOTE_DEVICE_H_
+
+/**
+ * This file contains the structures, constants, and prototypes for the
+ * struct scic_sds_remote_device object.
+ *
+ *
+ */
+
+#include "intel_sas.h"
+#include "sci_base_remote_device.h"
+#include "sci_base_request.h"
+#include "scu_remote_node_context.h"
+#include "scic_sds_remote_node_context.h"
+
+struct scic_sds_controller;
+struct scic_sds_port;
+struct scic_sds_request;
+struct scic_sds_remote_device_state_handler;
+
+/**
+ * enum SCIC_SDS_SSP_REMOTE_DEVICE_READY_SUBSTATES -
+ *
+ * This is the enumeration of the ready substates for the
+ * struct scic_sds_remote_device.
+ */
+enum SCIC_SDS_SSP_REMOTE_DEVICE_READY_SUBSTATES {
+ /**
+ * This is the initial state for the remote device ready substate.
+ */
+ SCIC_SDS_SSP_REMOTE_DEVICE_READY_SUBSTATE_INITIAL,
+
+ /**
+ * This is the ready operational substate for the remote device. This is the
+ * normal operational state for a remote device.
+ */
+ SCIC_SDS_SSP_REMOTE_DEVICE_READY_SUBSTATE_OPERATIONAL,
+
+ /**
+ * This is the suspended state for the remote device. This is the state that
+ * the device is placed in when a RNC suspend is received by the SCU hardware.
+ */
+ SCIC_SDS_SSP_REMOTE_DEVICE_READY_SUBSTATE_SUSPENDED,
+
+ /**
+ * This is the final state that the device is placed in before a change to the
+ * base state machine.
+ */
+ SCIC_SDS_SSP_REMOTE_DEVICE_READY_SUBSTATE_FINAL,
+
+ SCIC_SDS_SSP_REMOTE_DEVICE_READY_MAX_SUBSTATES
+};
+
+/**
+ * enum SCIC_SDS_STP_REMOTE_DEVICE_READY_SUBSTATES -
+ *
+ * This is the enumeration for the struct scic_sds_remote_device ready substates for
+ * the STP remote device.
+ */
+enum SCIC_SDS_STP_REMOTE_DEVICE_READY_SUBSTATES {
+ /**
+ * This is the idle substate for the stp remote device. When there are no
+ * active IO for the device it is is in this state.
+ */
+ SCIC_SDS_STP_REMOTE_DEVICE_READY_SUBSTATE_IDLE,
+
+ /**
+ * This is the command state for for the STP remote device. This state is
+ * entered when the device is processing a non-NCQ command. The device object
+ * will fail any new start IO requests until this command is complete.
+ */
+ SCIC_SDS_STP_REMOTE_DEVICE_READY_SUBSTATE_CMD,
+
+ /**
+ * This is the NCQ state for the STP remote device. This state is entered
+ * when the device is processing an NCQ reuqest. It will remain in this state
+ * so long as there is one or more NCQ requests being processed.
+ */
+ SCIC_SDS_STP_REMOTE_DEVICE_READY_SUBSTATE_NCQ,
+
+ /**
+ * This is the NCQ error state for the STP remote device. This state is
+ * entered when an SDB error FIS is received by the device object while in the
+ * NCQ state. The device object will only accept a READ LOG command while in
+ * this state.
+ */
+ SCIC_SDS_STP_REMOTE_DEVICE_READY_SUBSTATE_NCQ_ERROR,
+
+#if !defined(DISABLE_ATAPI)
+ /**
+ * This is the ATAPI error state for the STP ATAPI remote device. This state is
+ * entered when ATAPI device sends error status FIS without data while the device
+ * object is in CMD state. A suspension event is expected in this state. The device
+ * object will resume right away.
+ */
+ SCIC_SDS_STP_REMOTE_DEVICE_READY_SUBSTATE_ATAPI_ERROR,
+#endif
+
+ /**
+ * This is the READY substate indicates the device is waiting for the RESET task
+ * coming to be recovered from certain hardware specific error.
+ */
+ SCIC_SDS_STP_REMOTE_DEVICE_READY_SUBSTATE_AWAIT_RESET,
+
+ SCIC_SDS_STP_REMOTE_DEVICE_READY_MAX_SUBSTATES
+};
+
+
+/**
+ * enum SCIC_SDS_SMP_REMOTE_DEVICE_READY_SUBSTATES -
+ *
+ * This is the enumeration of the ready substates for the SMP REMOTE DEVICE.
+ */
+
+enum SCIC_SDS_SMP_REMOTE_DEVICE_READY_SUBSTATES {
+ /**
+ * This is the ready operational substate for the remote device. This is the
+ * normal operational state for a remote device.
+ */
+ SCIC_SDS_SMP_REMOTE_DEVICE_READY_SUBSTATE_IDLE,
+
+ /**
+ * This is the suspended state for the remote device. This is the state that
+ * the device is placed in when a RNC suspend is received by the SCU hardware.
+ */
+ SCIC_SDS_SMP_REMOTE_DEVICE_READY_SUBSTATE_CMD,
+
+ SCIC_SDS_SMP_REMOTE_DEVICE_READY_MAX_SUBSTATES
+};
+
+
+
+
+/**
+ * struct scic_sds_remote_device - This structure contains the data for an SCU
+ * implementation of the SCU Core device data.
+ *
+ *
+ */
+struct scic_sds_remote_device {
+ /**
+ * This field is the common base for all remote device objects.
+ */
+ struct sci_base_remote_device parent;
+
+ /**
+ * This field is the programmed device port width. This value is written to
+ * the RCN data structure to tell the SCU how many open connections this
+ * device can have.
+ */
+ u32 device_port_width;
+
+ /**
+ * This field is the programmed connection rate for this remote device. It is
+ * used to program the TC with the maximum allowed connection rate.
+ */
+ enum sci_sas_link_rate connection_rate;
+
+ /**
+ * This field contains the allowed target protocols for this remote device.
+ */
+ struct smp_discover_response_protocols target_protocols;
+
+ /**
+ * This field contains the device SAS address.
+ */
+ struct sci_sas_address device_address;
+
+ /**
+ * This filed is assinged the value of true if the device is directly attached
+ * to the port.
+ */
+ bool is_direct_attached;
+
+#if !defined(DISABLE_ATAPI)
+ /**
+ * This filed is assinged the value of true if the device is an ATAPI device.
+ */
+ bool is_atapi;
+#endif
+
+ /**
+ * This filed contains a pointer back to the port to which this device is
+ * assigned.
+ */
+ struct scic_sds_port *owning_port;
+
+ /**
+ * This field contains the SCU silicon remote node context specific
+ * information.
+ */
+ struct scic_sds_remote_node_context *rnc;
+
+ /**
+ * This field contains the stated request count for the remote device. The
+ * device can not reach the SCI_BASE_REMOTE_DEVICE_STATE_STOPPED until all
+ * requests are complete and the rnc_posted value is false.
+ */
+ u32 started_request_count;
+
+ /**
+ * This field contains a pointer to the working request object. It is only
+ * used only for SATA requests since the unsolicited frames we get from the
+ * hardware have no Tag value to look up the io request object.
+ */
+ struct scic_sds_request *working_request;
+
+ /**
+ * This field contains the reason for the remote device going not_ready. It is
+ * assigned in the state handlers and used in the state transition.
+ */
+ u32 not_ready_reason;
+
+ /**
+ * This field is true if this remote device has an initialzied ready substate
+ * machine. SSP devices do not have a ready substate machine and STP devices
+ * have a ready substate machine.
+ */
+ bool has_ready_substate_machine;
+
+ /**
+ * This field contains the state machine for the ready substate machine for
+ * this struct scic_sds_remote_device object.
+ */
+ struct sci_base_state_machine ready_substate_machine;
+
+ /**
+ * This field maintains the set of state handlers for the remote device
+ * object. These are changed each time the remote device enters a new state.
+ */
+ struct scic_sds_remote_device_state_handler *state_handlers;
+};
+
+
+typedef enum sci_status (*SCIC_SDS_REMOTE_DEVICE_HANDLER_T)(
+ struct scic_sds_remote_device *this_device);
+
+typedef enum sci_status (*SCIC_SDS_REMOTE_DEVICE_SUSPEND_HANDLER_T)(
+ struct scic_sds_remote_device *this_device,
+ u32 suspend_type);
+
+typedef enum sci_status (*SCIC_SDS_REMOTE_DEVICE_RESUME_HANDLER_T)(
+ struct scic_sds_remote_device *this_device);
+
+typedef enum sci_status (*SCIC_SDS_REMOTE_DEVICE_FRAME_HANDLER_T)(
+ struct scic_sds_remote_device *this_device,
+ u32 frame_index);
+
+typedef enum sci_status (*SCIC_SDS_REMOTE_DEVICE_EVENT_HANDLER_T)(
+ struct scic_sds_remote_device *this_device,
+ u32 event_code);
+
+typedef void (*SCIC_SDS_REMOTE_DEVICE_READY_NOT_READY_HANDLER_T)(
+ struct scic_sds_remote_device *this_device);
+
+/**
+ * struct scic_sds_remote_device_state_handler - This structure conains the
+ * state handlers that are needed to process requests for the SCU remote
+ * device objects.
+ *
+ *
+ */
+struct scic_sds_remote_device_state_handler {
+ struct sci_base_remote_device_state_handler parent;
+
+ SCIC_SDS_REMOTE_DEVICE_SUSPEND_HANDLER_T suspend_handler;
+ SCIC_SDS_REMOTE_DEVICE_RESUME_HANDLER_T resume_handler;
+
+ SCIC_SDS_REMOTE_DEVICE_EVENT_HANDLER_T event_handler;
+ SCIC_SDS_REMOTE_DEVICE_FRAME_HANDLER_T frame_handler;
+
+};
+
+
+extern const struct sci_base_state scic_sds_remote_device_state_table[];
+extern const struct sci_base_state scic_sds_ssp_remote_device_ready_substate_table[];
+extern const struct sci_base_state scic_sds_stp_remote_device_ready_substate_table[];
+extern const struct sci_base_state scic_sds_smp_remote_device_ready_substate_table[];
+
+extern struct scic_sds_remote_device_state_handler
+ scic_sds_remote_device_state_handler_table[];
+extern struct scic_sds_remote_device_state_handler
+ scic_sds_ssp_remote_device_ready_substate_handler_table[];
+extern struct scic_sds_remote_device_state_handler
+ scic_sds_stp_remote_device_ready_substate_handler_table[];
+extern struct scic_sds_remote_device_state_handler
+ scic_sds_smp_remote_device_ready_substate_handler_table[];
+
+/**
+ * scic_sds_remote_device_increment_request_count() -
+ *
+ * This macro incrments the request count for this device
+ */
+#define scic_sds_remote_device_increment_request_count(this_device) \
+ ((this_device)->started_request_count++)
+
+/**
+ * scic_sds_remote_device_decrement_request_count() -
+ *
+ * This macro decrements the request count for this device. This count will
+ * never decrment past 0.
+ */
+#define scic_sds_remote_device_decrement_request_count(this_device) \
+ ((this_device)->started_request_count > 0 ? \
+ (this_device)->started_request_count-- : 0)
+
+/**
+ * scic_sds_remote_device_get_request_count() -
+ *
+ * This is a helper macro to return the current device request count.
+ */
+#define scic_sds_remote_device_get_request_count(this_device) \
+ ((this_device)->started_request_count)
+
+/**
+ * scic_sds_remote_device_get_port() -
+ *
+ * This macro returns the owning port of this remote device obejct.
+ */
+#define scic_sds_remote_device_get_port(this_device) \
+ ((this_device)->owning_port)
+
+/**
+ * scic_sds_remote_device_get_controller() -
+ *
+ * This macro returns the controller object that contains this device object
+ */
+#define scic_sds_remote_device_get_controller(this_device) \
+ scic_sds_port_get_controller(scic_sds_remote_device_get_port(this_device))
+
+/**
+ * scic_sds_remote_device_set_state_handlers() -
+ *
+ * This macro sets the remote device state handlers pointer and is set on entry
+ * to each device state.
+ */
+#define scic_sds_remote_device_set_state_handlers(this_device, handlers) \
+ ((this_device)->state_handlers = (handlers))
+
+/**
+ * scic_sds_remote_device_get_base_state_machine() -
+ *
+ * This macro returns the base sate machine object for the remote device.
+ */
+#define scic_sds_remote_device_get_base_state_machine(this_device) \
+ (&(this_device)->parent.state_machine)
+
+/**
+ * scic_sds_remote_device_get_ready_substate_machine() -
+ *
+ * This macro returns the remote device ready substate machine
+ */
+#define scic_sds_remote_device_get_ready_substate_machine(this_device) \
+ (&(this_device)->ready_substate_machine)
+
+/**
+ * scic_sds_remote_device_get_port() -
+ *
+ * This macro returns the owning port of this device
+ */
+#define scic_sds_remote_device_get_port(this_device) \
+ ((this_device)->owning_port)
+
+/**
+ * scic_sds_remote_device_get_sequence() -
+ *
+ * This macro returns the remote device sequence value
+ */
+#define scic_sds_remote_device_get_sequence(this_device) \
+ (\
+ scic_sds_remote_device_get_controller(this_device)-> \
+ remote_device_sequence[(this_device)->rnc->remote_node_index] \
+ )
+
+/**
+ * scic_sds_remote_device_get_controller_peg() -
+ *
+ * This macro returns the controllers protocol engine group
+ */
+#define scic_sds_remote_device_get_controller_peg(this_device) \
+ (\
+ scic_sds_controller_get_protocol_engine_group(\
+ scic_sds_port_get_controller(\
+ scic_sds_remote_device_get_port(this_device) \
+ ) \
+ ) \
+ )
+
+/**
+ * scic_sds_remote_device_get_port_index() -
+ *
+ * This macro returns the port index for the devices owning port
+ */
+#define scic_sds_remote_device_get_port_index(this_device) \
+ (scic_sds_port_get_index(scic_sds_remote_device_get_port(this_device)))
+
+/**
+ * scic_sds_remote_device_get_index() -
+ *
+ * This macro returns the remote node index for this device object
+ */
+#define scic_sds_remote_device_get_index(this_device) \
+ ((this_device)->rnc->remote_node_index)
+
+/**
+ * scic_sds_remote_device_build_command_context() -
+ *
+ * This macro builds a remote device context for the SCU post request operation
+ */
+#define scic_sds_remote_device_build_command_context(device, command) \
+ ((command) \
+ | (scic_sds_remote_device_get_controller_peg((device)) << SCU_CONTEXT_COMMAND_PROTOCOL_ENGINE_GROUP_SHIFT) \
+ | (scic_sds_remote_device_get_port_index((device)) << SCU_CONTEXT_COMMAND_LOGICAL_PORT_SHIFT) \
+ | (scic_sds_remote_device_get_index((device))) \
+ )
+
+/**
+ * scic_sds_remote_device_set_working_request() -
+ *
+ * This macro makes the working request assingment for the remote device
+ * object. To clear the working request use this macro with a NULL request
+ * object.
+ */
+#define scic_sds_remote_device_set_working_request(device, request) \
+ ((device)->working_request = (request))
+
+/* --------------------------------------------------------------------------- */
+
+
+
+enum sci_status scic_sds_remote_device_frame_handler(
+ struct scic_sds_remote_device *this_device,
+ u32 frame_index);
+
+enum sci_status scic_sds_remote_device_event_handler(
+ struct scic_sds_remote_device *this_device,
+ u32 event_code);
+
+enum sci_status scic_sds_remote_device_start_io(
+ struct scic_sds_controller *controller,
+ struct scic_sds_remote_device *this_device,
+ struct scic_sds_request *io_request);
+
+enum sci_status scic_sds_remote_device_complete_io(
+ struct scic_sds_controller *controller,
+ struct scic_sds_remote_device *this_device,
+ struct scic_sds_request *io_request);
+
+enum sci_status scic_sds_remote_device_resume(
+ struct scic_sds_remote_device *this_device);
+
+enum sci_status scic_sds_remote_device_suspend(
+ struct scic_sds_remote_device *this_device,
+ u32 suspend_type);
+
+enum sci_status scic_sds_remote_device_start_task(
+ struct scic_sds_controller *controller,
+ struct scic_sds_remote_device *this_device,
+ struct scic_sds_request *io_request);
+
+void scic_sds_remote_device_post_request(
+ struct scic_sds_remote_device *this_device,
+ u32 request);
+
+#if !defined(DISABLE_ATAPI)
+bool scic_sds_remote_device_is_atapi(
+ struct scic_sds_remote_device *this_device);
+#else /* !defined(DISABLE_ATAPI) */
+#define scic_sds_remote_device_is_atapi(this_device) false
+#endif /* !defined(DISABLE_ATAPI) */
+
+/* --------------------------------------------------------------------------- */
+
+/* --------------------------------------------------------------------------- */
+
+void scic_sds_remote_device_start_request(
+ struct scic_sds_remote_device *this_device,
+ struct scic_sds_request *the_request,
+ enum sci_status status);
+
+void scic_sds_remote_device_continue_request(
+ struct scic_sds_remote_device *this_device);
+
+enum sci_status scic_sds_remote_device_default_start_handler(
+ struct sci_base_remote_device *this_device);
+
+
+enum sci_status scic_sds_remote_device_default_fail_handler(
+ struct sci_base_remote_device *this_device);
+
+enum sci_status scic_sds_remote_device_default_destruct_handler(
+ struct sci_base_remote_device *this_device);
+
+enum sci_status scic_sds_remote_device_default_reset_handler(
+ struct sci_base_remote_device *device);
+
+enum sci_status scic_sds_remote_device_default_reset_complete_handler(
+ struct sci_base_remote_device *device);
+
+enum sci_status scic_sds_remote_device_default_start_request_handler(
+ struct sci_base_remote_device *device,
+ struct sci_base_request *request);
+
+enum sci_status scic_sds_remote_device_default_complete_request_handler(
+ struct sci_base_remote_device *device,
+ struct sci_base_request *request);
+
+enum sci_status scic_sds_remote_device_default_continue_request_handler(
+ struct sci_base_remote_device *device,
+ struct sci_base_request *request);
+
+enum sci_status scic_sds_remote_device_default_suspend_handler(
+ struct scic_sds_remote_device *this_device,
+ u32 suspend_type);
+
+enum sci_status scic_sds_remote_device_default_resume_handler(
+ struct scic_sds_remote_device *this_device);
+
+
+enum sci_status scic_sds_remote_device_default_frame_handler(
+ struct scic_sds_remote_device *this_device,
+ u32 frame_index);
+
+/* --------------------------------------------------------------------------- */
+
+enum sci_status scic_sds_remote_device_ready_state_stop_handler(
+ struct sci_base_remote_device *device);
+
+enum sci_status scic_sds_remote_device_ready_state_reset_handler(
+ struct sci_base_remote_device *device);
+
+enum sci_status scic_sds_remote_device_general_frame_handler(
+ struct scic_sds_remote_device *this_device,
+ u32 frame_index);
+
+enum sci_status scic_sds_remote_device_general_event_handler(
+ struct scic_sds_remote_device *this_device,
+ u32 event_code);
+
+enum sci_status scic_sds_ssp_remote_device_ready_suspended_substate_resume_handler(
+ struct scic_sds_remote_device *this_device);
+
+/* --------------------------------------------------------------------------- */
+
+
+#endif /* _SCIC_SDS_REMOTE_DEVICE_H_ */
diff --git a/drivers/scsi/isci/core/scic_sds_remote_node_context.c b/drivers/scsi/isci/core/scic_sds_remote_node_context.c
new file mode 100644
index 000000000000..79fe9a8cd1ed
--- /dev/null
+++ b/drivers/scsi/isci/core/scic_sds_remote_node_context.c
@@ -0,0 +1,1244 @@
+/*
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Intel Corporation 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
+ * OWNER 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.
+ */
+
+#include "sci_base_state_machine.h"
+#include "scic_remote_device.h"
+#include "scic_sds_controller.h"
+#include "scic_sds_port.h"
+#include "scic_sds_remote_device.h"
+#include "scic_sds_remote_node_context.h"
+#include "sci_environment.h"
+#include "sci_util.h"
+#include "scu_event_codes.h"
+#include "scu_task_context.h"
+
+void scic_sds_remote_node_context_construct(
+ struct scic_sds_remote_device *device,
+ struct scic_sds_remote_node_context *rnc,
+ u16 remote_node_index)
+{
+ memset(rnc, 0, sizeof(struct scic_sds_remote_node_context));
+
+ rnc->remote_node_index = remote_node_index;
+ rnc->device = device;
+ rnc->destination_state = SCIC_SDS_REMOTE_NODE_DESTINATION_STATE_UNSPECIFIED;
+
+ sci_base_state_machine_construct(
+ &rnc->state_machine,
+ &rnc->parent,
+ scic_sds_remote_node_context_state_table,
+ SCIC_SDS_REMOTE_NODE_CONTEXT_INITIAL_STATE
+ );
+
+ sci_base_state_machine_start(&rnc->state_machine);
+}
+
+/**
+ *
+ * @this_rnc: The RNC for which the is posted request is being made.
+ *
+ * This method will return true if the RNC is not in the initial state. In all
+ * other states the RNC is considered active and this will return true. The
+ * destroy request of the state machine drives the RNC back to the initial
+ * state. If the state machine changes then this routine will also have to be
+ * changed. bool true if the state machine is not in the initial state false if
+ * the state machine is in the initial state
+ */
+
+/**
+ *
+ * @this_rnc: The state of the remote node context object to check.
+ *
+ * This method will return true if the remote node context is in a READY state
+ * otherwise it will return false bool true if the remote node context is in
+ * the ready state. false if the remote node context is not in the ready state.
+ */
+bool scic_sds_remote_node_context_is_ready(
+ struct scic_sds_remote_node_context *this_rnc)
+{
+ u32 current_state = sci_base_state_machine_get_state(&this_rnc->state_machine);
+
+ if (current_state == SCIC_SDS_REMOTE_NODE_CONTEXT_READY_STATE) {
+ return true;
+ }
+
+ return false;
+}
+
+/**
+ *
+ * @this_device: The remote device to use to construct the RNC buffer.
+ * @rnc: The buffer into which the remote device data will be copied.
+ *
+ * This method will construct the RNC buffer for this remote device object. none
+ */
+void scic_sds_remote_node_context_construct_buffer(
+ struct scic_sds_remote_node_context *this_rnc)
+{
+ union scu_remote_node_context *rnc;
+ struct scic_sds_controller *the_controller;
+
+ the_controller = scic_sds_remote_device_get_controller(this_rnc->device);
+
+ rnc = scic_sds_controller_get_remote_node_context_buffer(
+ the_controller, this_rnc->remote_node_index);
+
+ memset(
+ rnc,
+ 0x00,
+ sizeof(union scu_remote_node_context)
+ * scic_sds_remote_device_node_count(this_rnc->device)
+ );
+
+ rnc->ssp.remote_node_index = this_rnc->remote_node_index;
+ rnc->ssp.remote_node_port_width = this_rnc->device->device_port_width;
+ rnc->ssp.logical_port_index =
+ scic_sds_remote_device_get_port_index(this_rnc->device);
+
+ rnc->ssp.remote_sas_address_hi = SCIC_SWAP_DWORD(this_rnc->device->device_address.high);
+ rnc->ssp.remote_sas_address_lo = SCIC_SWAP_DWORD(this_rnc->device->device_address.low);
+
+ rnc->ssp.nexus_loss_timer_enable = true;
+ rnc->ssp.check_bit = false;
+ rnc->ssp.is_valid = false;
+ rnc->ssp.is_remote_node_context = true;
+ rnc->ssp.function_number = 0;
+
+ rnc->ssp.arbitration_wait_time = 0;
+
+
+ if (
+ this_rnc->device->target_protocols.u.bits.attached_sata_device
+ || this_rnc->device->target_protocols.u.bits.attached_stp_target
+ ) {
+ rnc->ssp.connection_occupancy_timeout =
+ the_controller->user_parameters.sds1.stp_max_occupancy_timeout;
+ rnc->ssp.connection_inactivity_timeout =
+ the_controller->user_parameters.sds1.stp_inactivity_timeout;
+ } else {
+ rnc->ssp.connection_occupancy_timeout =
+ the_controller->user_parameters.sds1.ssp_max_occupancy_timeout;
+ rnc->ssp.connection_inactivity_timeout =
+ the_controller->user_parameters.sds1.ssp_inactivity_timeout;
+ }
+
+ rnc->ssp.initial_arbitration_wait_time = 0;
+
+ /* Open Address Frame Parameters */
+ rnc->ssp.oaf_connection_rate = this_rnc->device->connection_rate;
+ rnc->ssp.oaf_features = 0;
+ rnc->ssp.oaf_source_zone_group = 0;
+ rnc->ssp.oaf_more_compatibility_features = 0;
+}
+
+/**
+ *
+ * @this_rnc:
+ * @the_callback:
+ * @callback_parameter:
+ *
+ * This method will setup the remote node context object so it will transition
+ * to its ready state. If the remote node context is already setup to
+ * transition to its final state then this function does nothing. none
+ */
+static void scic_sds_remote_node_context_setup_to_resume(
+ struct scic_sds_remote_node_context *this_rnc,
+ SCICS_SDS_REMOTE_NODE_CONTEXT_CALLBACK the_callback,
+ void *callback_parameter)
+{
+ if (this_rnc->destination_state != SCIC_SDS_REMOTE_NODE_DESTINATION_STATE_FINAL) {
+ this_rnc->destination_state = SCIC_SDS_REMOTE_NODE_DESTINATION_STATE_READY;
+ this_rnc->user_callback = the_callback;
+ this_rnc->user_cookie = callback_parameter;
+ }
+}
+
+/**
+ *
+ * @this_rnc:
+ * @the_callback:
+ * @callback_parameter:
+ *
+ * This method will setup the remote node context object so it will transistion
+ * to its final state. none
+ */
+static void scic_sds_remote_node_context_setup_to_destory(
+ struct scic_sds_remote_node_context *this_rnc,
+ SCICS_SDS_REMOTE_NODE_CONTEXT_CALLBACK the_callback,
+ void *callback_parameter)
+{
+ this_rnc->destination_state = SCIC_SDS_REMOTE_NODE_DESTINATION_STATE_FINAL;
+ this_rnc->user_callback = the_callback;
+ this_rnc->user_cookie = callback_parameter;
+}
+
+/**
+ *
+ * @this_rnc:
+ * @the_callback:
+ *
+ * This method will continue to resume a remote node context. This is used in
+ * the states where a resume is requested while a resume is in progress.
+ */
+static enum sci_status scic_sds_remote_node_context_continue_to_resume_handler(
+ struct scic_sds_remote_node_context *this_rnc,
+ SCICS_SDS_REMOTE_NODE_CONTEXT_CALLBACK the_callback,
+ void *callback_parameter)
+{
+ if (this_rnc->destination_state == SCIC_SDS_REMOTE_NODE_DESTINATION_STATE_READY) {
+ this_rnc->user_callback = the_callback;
+ this_rnc->user_cookie = callback_parameter;
+
+ return SCI_SUCCESS;
+ }
+
+ return SCI_FAILURE_INVALID_STATE;
+}
+
+/* --------------------------------------------------------------------------- */
+
+static enum sci_status scic_sds_remote_node_context_default_destruct_handler(
+ struct scic_sds_remote_node_context *this_rnc,
+ SCICS_SDS_REMOTE_NODE_CONTEXT_CALLBACK the_callback,
+ void *callback_parameter)
+{
+ dev_warn(scirdev_to_dev(this_rnc->device),
+ "%s: SCIC Remote Node Context 0x%p requested to stop while "
+ "in unexpected state %d\n",
+ __func__,
+ this_rnc,
+ sci_base_state_machine_get_state(&this_rnc->state_machine));
+
+ /*
+ * We have decided that the destruct request on the remote node context can not fail
+ * since it is either in the initial/destroyed state or is can be destroyed. */
+ return SCI_SUCCESS;
+}
+
+static enum sci_status scic_sds_remote_node_context_default_suspend_handler(
+ struct scic_sds_remote_node_context *this_rnc,
+ u32 suspend_type,
+ SCICS_SDS_REMOTE_NODE_CONTEXT_CALLBACK the_callback,
+ void *callback_parameter)
+{
+ dev_warn(scirdev_to_dev(this_rnc->device),
+ "%s: SCIC Remote Node Context 0x%p requested to suspend "
+ "while in wrong state %d\n",
+ __func__,
+ this_rnc,
+ sci_base_state_machine_get_state(&this_rnc->state_machine));
+
+ return SCI_FAILURE_INVALID_STATE;
+}
+
+static enum sci_status scic_sds_remote_node_context_default_resume_handler(
+ struct scic_sds_remote_node_context *this_rnc,
+ SCICS_SDS_REMOTE_NODE_CONTEXT_CALLBACK the_callback,
+ void *callback_parameter)
+{
+ dev_warn(scirdev_to_dev(this_rnc->device),
+ "%s: SCIC Remote Node Context 0x%p requested to resume "
+ "while in wrong state %d\n",
+ __func__,
+ this_rnc,
+ sci_base_state_machine_get_state(&this_rnc->state_machine));
+
+ return SCI_FAILURE_INVALID_STATE;
+}
+
+static enum sci_status scic_sds_remote_node_context_default_start_io_handler(
+ struct scic_sds_remote_node_context *this_rnc,
+ struct scic_sds_request *the_request)
+{
+ dev_warn(scirdev_to_dev(this_rnc->device),
+ "%s: SCIC Remote Node Context 0x%p requested to start io "
+ "0x%p while in wrong state %d\n",
+ __func__,
+ this_rnc,
+ the_request,
+ sci_base_state_machine_get_state(&this_rnc->state_machine));
+
+ return SCI_FAILURE_REMOTE_DEVICE_RESET_REQUIRED;
+}
+
+static enum sci_status scic_sds_remote_node_context_default_start_task_handler(
+ struct scic_sds_remote_node_context *this_rnc,
+ struct scic_sds_request *the_request)
+{
+ dev_warn(scirdev_to_dev(this_rnc->device),
+ "%s: SCIC Remote Node Context 0x%p requested to start "
+ "task 0x%p while in wrong state %d\n",
+ __func__,
+ this_rnc,
+ the_request,
+ sci_base_state_machine_get_state(&this_rnc->state_machine));
+
+ return SCI_FAILURE;
+}
+
+static enum sci_status scic_sds_remote_node_context_default_event_handler(
+ struct scic_sds_remote_node_context *this_rnc,
+ u32 event_code)
+{
+ dev_warn(scirdev_to_dev(this_rnc->device),
+ "%s: SCIC Remote Node Context 0x%p requested to process "
+ "event 0x%x while in wrong state %d\n",
+ __func__,
+ this_rnc,
+ event_code,
+ sci_base_state_machine_get_state(&this_rnc->state_machine));
+
+ return SCI_FAILURE_INVALID_STATE;
+}
+
+/**
+ *
+ * @this_rnc: The rnc for which the task request is targeted.
+ * @the_request: The request which is going to be started.
+ *
+ * This method determines if the task request can be started by the SCU
+ * hardware. When the RNC is in the ready state any task can be started.
+ * enum sci_status SCI_SUCCESS
+ */
+static enum sci_status scic_sds_remote_node_context_success_start_task_handler(
+ struct scic_sds_remote_node_context *this_rnc,
+ struct scic_sds_request *the_request)
+{
+ return SCI_SUCCESS;
+}
+
+/**
+ *
+ * @this_rnc:
+ * @the_callback:
+ * @callback_parameter:
+ *
+ * This method handles destruct calls from the various state handlers. The
+ * remote node context can be requested to destroy from any state. If there was
+ * a user callback it is always replaced with the request to destroy user
+ * callback. enum sci_status
+ */
+static enum sci_status scic_sds_remote_node_context_general_destruct_handler(
+ struct scic_sds_remote_node_context *this_rnc,
+ SCICS_SDS_REMOTE_NODE_CONTEXT_CALLBACK the_callback,
+ void *callback_parameter)
+{
+ scic_sds_remote_node_context_setup_to_destory(
+ this_rnc, the_callback, callback_parameter
+ );
+
+ sci_base_state_machine_change_state(
+ &this_rnc->state_machine,
+ SCIC_SDS_REMOTE_NODE_CONTEXT_INVALIDATING_STATE
+ );
+
+ return SCI_SUCCESS;
+}
+
+/* --------------------------------------------------------------------------- */
+
+static enum sci_status scic_sds_remote_node_context_initial_state_resume_handler(
+ struct scic_sds_remote_node_context *this_rnc,
+ SCICS_SDS_REMOTE_NODE_CONTEXT_CALLBACK the_callback,
+ void *callback_parameter)
+{
+ if (this_rnc->remote_node_index != SCIC_SDS_REMOTE_NODE_CONTEXT_INVALID_INDEX) {
+ scic_sds_remote_node_context_setup_to_resume(
+ this_rnc, the_callback, callback_parameter
+ );
+
+ scic_sds_remote_node_context_construct_buffer(this_rnc);
+
+ sci_base_state_machine_change_state(
+ &this_rnc->state_machine,
+ SCIC_SDS_REMOTE_NODE_CONTEXT_POSTING_STATE
+ );
+
+ return SCI_SUCCESS;
+ }
+
+ return SCI_FAILURE_INVALID_STATE;
+}
+
+/* --------------------------------------------------------------------------- */
+
+static enum sci_status scic_sds_remote_node_context_posting_state_event_handler(
+ struct scic_sds_remote_node_context *this_rnc,
+ u32 event_code)
+{
+ enum sci_status status;
+
+ switch (scu_get_event_code(event_code)) {
+ case SCU_EVENT_POST_RNC_COMPLETE:
+ status = SCI_SUCCESS;
+
+ sci_base_state_machine_change_state(
+ &this_rnc->state_machine,
+ SCIC_SDS_REMOTE_NODE_CONTEXT_READY_STATE
+ );
+ break;
+
+ default:
+ status = SCI_FAILURE;
+ dev_warn(scirdev_to_dev(this_rnc->device),
+ "%s: SCIC Remote Node Context 0x%p requested to "
+ "process unexpected event 0x%x while in posting "
+ "state\n",
+ __func__,
+ this_rnc,
+ event_code);
+ break;
+ }
+
+ return status;
+}
+
+/* --------------------------------------------------------------------------- */
+
+static enum sci_status scic_sds_remote_node_context_invalidating_state_destruct_handler(
+ struct scic_sds_remote_node_context *this_rnc,
+ SCICS_SDS_REMOTE_NODE_CONTEXT_CALLBACK the_callback,
+ void *callback_parameter)
+{
+ scic_sds_remote_node_context_setup_to_destory(
+ this_rnc, the_callback, callback_parameter
+ );
+
+ return SCI_SUCCESS;
+}
+
+static enum sci_status scic_sds_remote_node_context_invalidating_state_event_handler(
+ struct scic_sds_remote_node_context *this_rnc,
+ u32 event_code)
+{
+ enum sci_status status;
+
+ if (scu_get_event_code(event_code) == SCU_EVENT_POST_RNC_INVALIDATE_COMPLETE) {
+ status = SCI_SUCCESS;
+
+ if (this_rnc->destination_state == SCIC_SDS_REMOTE_NODE_DESTINATION_STATE_FINAL) {
+ sci_base_state_machine_change_state(
+ &this_rnc->state_machine,
+ SCIC_SDS_REMOTE_NODE_CONTEXT_INITIAL_STATE
+ );
+ } else {
+ sci_base_state_machine_change_state(
+ &this_rnc->state_machine,
+ SCIC_SDS_REMOTE_NODE_CONTEXT_POSTING_STATE
+ );
+ }
+ } else {
+ switch (scu_get_event_type(event_code)) {
+ case SCU_EVENT_TYPE_RNC_SUSPEND_TX:
+ case SCU_EVENT_TYPE_RNC_SUSPEND_TX_RX:
+ /*
+ * We really dont care if the hardware is going to suspend
+ * the device since it's being invalidated anyway */
+ dev_dbg(scirdev_to_dev(this_rnc->device),
+ "%s: SCIC Remote Node Context 0x%p was "
+ "suspeneded by hardware while being "
+ "invalidated.\n",
+ __func__,
+ this_rnc);
+ status = SCI_SUCCESS;
+ break;
+
+ default:
+ dev_warn(scirdev_to_dev(this_rnc->device),
+ "%s: SCIC Remote Node Context 0x%p "
+ "requested to process event 0x%x while "
+ "in state %d.\n",
+ __func__,
+ this_rnc,
+ event_code,
+ sci_base_state_machine_get_state(
+ &this_rnc->state_machine));
+ status = SCI_FAILURE;
+ break;
+ }
+ }
+
+ return status;
+}
+
+/* --------------------------------------------------------------------------- */
+
+
+static enum sci_status scic_sds_remote_node_context_resuming_state_event_handler(
+ struct scic_sds_remote_node_context *this_rnc,
+ u32 event_code)
+{
+ enum sci_status status;
+
+ if (scu_get_event_code(event_code) == SCU_EVENT_POST_RCN_RELEASE) {
+ status = SCI_SUCCESS;
+
+ sci_base_state_machine_change_state(
+ &this_rnc->state_machine,
+ SCIC_SDS_REMOTE_NODE_CONTEXT_READY_STATE
+ );
+ } else {
+ switch (scu_get_event_type(event_code)) {
+ case SCU_EVENT_TYPE_RNC_SUSPEND_TX:
+ case SCU_EVENT_TYPE_RNC_SUSPEND_TX_RX:
+ /*
+ * We really dont care if the hardware is going to suspend
+ * the device since it's being resumed anyway */
+ dev_dbg(scirdev_to_dev(this_rnc->device),
+ "%s: SCIC Remote Node Context 0x%p was "
+ "suspeneded by hardware while being resumed.\n",
+ __func__,
+ this_rnc);
+ status = SCI_SUCCESS;
+ break;
+
+ default:
+ dev_warn(scirdev_to_dev(this_rnc->device),
+ "%s: SCIC Remote Node Context 0x%p requested "
+ "to process event 0x%x while in state %d.\n",
+ __func__,
+ this_rnc,
+ event_code,
+ sci_base_state_machine_get_state(
+ &this_rnc->state_machine));
+ status = SCI_FAILURE;
+ break;
+ }
+ }
+
+ return status;
+}
+
+/* --------------------------------------------------------------------------- */
+
+/**
+ *
+ * @this_rnc: The remote node context object being suspended.
+ * @the_callback: The callback when the suspension is complete.
+ * @callback_parameter: The parameter that is to be passed into the callback.
+ *
+ * This method will handle the suspend requests from the ready state.
+ * SCI_SUCCESS
+ */
+static enum sci_status scic_sds_remote_node_context_ready_state_suspend_handler(
+ struct scic_sds_remote_node_context *this_rnc,
+ u32 suspend_type,
+ SCICS_SDS_REMOTE_NODE_CONTEXT_CALLBACK the_callback,
+ void *callback_parameter)
+{
+ this_rnc->user_callback = the_callback;
+ this_rnc->user_cookie = callback_parameter;
+ this_rnc->suspension_code = suspend_type;
+
+ if (suspend_type == SCI_SOFTWARE_SUSPENSION) {
+ scic_sds_remote_device_post_request(
+ this_rnc->device,
+ SCU_CONTEXT_COMMAND_POST_RNC_SUSPEND_TX
+ );
+ }
+
+ sci_base_state_machine_change_state(
+ &this_rnc->state_machine,
+ SCIC_SDS_REMOTE_NODE_CONTEXT_AWAIT_SUSPENSION_STATE
+ );
+
+ return SCI_SUCCESS;
+}
+
+/**
+ *
+ * @this_rnc: The rnc for which the io request is targeted.
+ * @the_request: The request which is going to be started.
+ *
+ * This method determines if the io request can be started by the SCU hardware.
+ * When the RNC is in the ready state any io request can be started. enum sci_status
+ * SCI_SUCCESS
+ */
+static enum sci_status scic_sds_remote_node_context_ready_state_start_io_handler(
+ struct scic_sds_remote_node_context *this_rnc,
+ struct scic_sds_request *the_request)
+{
+ return SCI_SUCCESS;
+}
+
+
+static enum sci_status scic_sds_remote_node_context_ready_state_event_handler(
+ struct scic_sds_remote_node_context *this_rnc,
+ u32 event_code)
+{
+ enum sci_status status;
+
+ switch (scu_get_event_type(event_code)) {
+ case SCU_EVENT_TL_RNC_SUSPEND_TX:
+ sci_base_state_machine_change_state(
+ &this_rnc->state_machine,
+ SCIC_SDS_REMOTE_NODE_CONTEXT_TX_SUSPENDED_STATE
+ );
+
+ this_rnc->suspension_code = scu_get_event_specifier(event_code);
+ status = SCI_SUCCESS;
+ break;
+
+ case SCU_EVENT_TL_RNC_SUSPEND_TX_RX:
+ sci_base_state_machine_change_state(
+ &this_rnc->state_machine,
+ SCIC_SDS_REMOTE_NODE_CONTEXT_TX_RX_SUSPENDED_STATE
+ );
+
+ this_rnc->suspension_code = scu_get_event_specifier(event_code);
+ status = SCI_SUCCESS;
+ break;
+
+ default:
+ dev_warn(scirdev_to_dev(this_rnc->device),
+ "%s: SCIC Remote Node Context 0x%p requested to "
+ "process event 0x%x while in state %d.\n",
+ __func__,
+ this_rnc,
+ event_code,
+ sci_base_state_machine_get_state(
+ &this_rnc->state_machine));
+
+ status = SCI_FAILURE;
+ break;
+ }
+
+ return status;
+}
+
+/* --------------------------------------------------------------------------- */
+
+static enum sci_status scic_sds_remote_node_context_tx_suspended_state_resume_handler(
+ struct scic_sds_remote_node_context *this_rnc,
+ SCICS_SDS_REMOTE_NODE_CONTEXT_CALLBACK the_callback,
+ void *callback_parameter)
+{
+ enum sci_status status;
+ struct smp_discover_response_protocols protocols;
+
+ scic_sds_remote_node_context_setup_to_resume(
+ this_rnc, the_callback, callback_parameter
+ );
+
+ /* TODO: consider adding a resume action of NONE, INVALIDATE, WRITE_TLCR */
+
+ scic_remote_device_get_protocols(this_rnc->device, &protocols);
+
+ if (
+ (protocols.u.bits.attached_ssp_target == 1)
+ || (protocols.u.bits.attached_smp_target == 1)
+ ) {
+ sci_base_state_machine_change_state(
+ &this_rnc->state_machine,
+ SCIC_SDS_REMOTE_NODE_CONTEXT_RESUMING_STATE
+ );
+
+ status = SCI_SUCCESS;
+ } else if (protocols.u.bits.attached_stp_target == 1) {
+ if (this_rnc->device->is_direct_attached) {
+ /* @todo Fix this since I am being silly in writing to the STPTLDARNI register. */
+ scic_sds_port_set_direct_attached_device_id(
+ this_rnc->device->owning_port,
+ this_rnc->remote_node_index
+ );
+
+ sci_base_state_machine_change_state(
+ &this_rnc->state_machine,
+ SCIC_SDS_REMOTE_NODE_CONTEXT_RESUMING_STATE
+ );
+ } else {
+ sci_base_state_machine_change_state(
+ &this_rnc->state_machine,
+ SCIC_SDS_REMOTE_NODE_CONTEXT_INVALIDATING_STATE
+ );
+ }
+
+ status = SCI_SUCCESS;
+ } else {
+ status = SCI_FAILURE;
+ }
+
+ return status;
+}
+
+/**
+ *
+ * @this_rnc: The remote node context which is to receive the task request.
+ * @the_request: The task request to be transmitted to to the remote target
+ * device.
+ *
+ * This method will report a success or failure attempt to start a new task
+ * request to the hardware. Since all task requests are sent on the high
+ * priority queue they can be sent when the RCN is in a TX suspend state.
+ * enum sci_status SCI_SUCCESS
+ */
+static enum sci_status scic_sds_remote_node_context_suspended_start_task_handler(
+ struct scic_sds_remote_node_context *this_rnc,
+ struct scic_sds_request *the_request)
+{
+ scic_sds_remote_node_context_resume(this_rnc, NULL, NULL);
+
+ return SCI_SUCCESS;
+}
+
+/* --------------------------------------------------------------------------- */
+
+static enum sci_status scic_sds_remote_node_context_tx_rx_suspended_state_resume_handler(
+ struct scic_sds_remote_node_context *this_rnc,
+ SCICS_SDS_REMOTE_NODE_CONTEXT_CALLBACK the_callback,
+ void *callback_parameter)
+{
+ scic_sds_remote_node_context_setup_to_resume(
+ this_rnc, the_callback, callback_parameter
+ );
+
+ sci_base_state_machine_change_state(
+ &this_rnc->state_machine,
+ SCIC_SDS_REMOTE_NODE_CONTEXT_RESUMING_STATE
+ );
+
+ return SCI_FAILURE_INVALID_STATE;
+}
+
+/* --------------------------------------------------------------------------- */
+
+/**
+ *
+ *
+ *
+ */
+static enum sci_status scic_sds_remote_node_context_await_suspension_state_resume_handler(
+ struct scic_sds_remote_node_context *this_rnc,
+ SCICS_SDS_REMOTE_NODE_CONTEXT_CALLBACK the_callback,
+ void *callback_parameter)
+{
+ scic_sds_remote_node_context_setup_to_resume(
+ this_rnc, the_callback, callback_parameter
+ );
+
+ return SCI_SUCCESS;
+}
+
+/**
+ *
+ * @this_rnc: The remote node context which is to receive the task request.
+ * @the_request: The task request to be transmitted to to the remote target
+ * device.
+ *
+ * This method will report a success or failure attempt to start a new task
+ * request to the hardware. Since all task requests are sent on the high
+ * priority queue they can be sent when the RCN is in a TX suspend state.
+ * enum sci_status SCI_SUCCESS
+ */
+static enum sci_status scic_sds_remote_node_context_await_suspension_state_start_task_handler(
+ struct scic_sds_remote_node_context *this_rnc,
+ struct scic_sds_request *the_request)
+{
+ return SCI_SUCCESS;
+}
+
+static enum sci_status scic_sds_remote_node_context_await_suspension_state_event_handler(
+ struct scic_sds_remote_node_context *this_rnc,
+ u32 event_code)
+{
+ enum sci_status status;
+
+ switch (scu_get_event_type(event_code)) {
+ case SCU_EVENT_TL_RNC_SUSPEND_TX:
+ sci_base_state_machine_change_state(
+ &this_rnc->state_machine,
+ SCIC_SDS_REMOTE_NODE_CONTEXT_TX_SUSPENDED_STATE
+ );
+
+ this_rnc->suspension_code = scu_get_event_specifier(event_code);
+ status = SCI_SUCCESS;
+ break;
+
+ case SCU_EVENT_TL_RNC_SUSPEND_TX_RX:
+ sci_base_state_machine_change_state(
+ &this_rnc->state_machine,
+ SCIC_SDS_REMOTE_NODE_CONTEXT_TX_RX_SUSPENDED_STATE
+ );
+
+ this_rnc->suspension_code = scu_get_event_specifier(event_code);
+ status = SCI_SUCCESS;
+ break;
+
+ default:
+ dev_warn(scirdev_to_dev(this_rnc->device),
+ "%s: SCIC Remote Node Context 0x%p requested to "
+ "process event 0x%x while in state %d.\n",
+ __func__,
+ this_rnc,
+ event_code,
+ sci_base_state_machine_get_state(
+ &this_rnc->state_machine));
+
+ status = SCI_FAILURE;
+ break;
+ }
+
+ return status;
+}
+
+/* --------------------------------------------------------------------------- */
+
+struct scic_sds_remote_node_context_handlers
+scic_sds_remote_node_context_state_handler_table[
+ SCIC_SDS_REMOTE_NODE_CONTEXT_MAX_STATES] =
+{
+ /* SCIC_SDS_REMOTE_NODE_CONTEXT_INITIAL_STATE */
+ {
+ scic_sds_remote_node_context_default_destruct_handler,
+ scic_sds_remote_node_context_default_suspend_handler,
+ scic_sds_remote_node_context_initial_state_resume_handler,
+ scic_sds_remote_node_context_default_start_io_handler,
+ scic_sds_remote_node_context_default_start_task_handler,
+ scic_sds_remote_node_context_default_event_handler
+ },
+ /* SCIC_SDS_REMOTE_NODE_CONTEXT_POSTING_STATE */
+ {
+ scic_sds_remote_node_context_general_destruct_handler,
+ scic_sds_remote_node_context_default_suspend_handler,
+ scic_sds_remote_node_context_continue_to_resume_handler,
+ scic_sds_remote_node_context_default_start_io_handler,
+ scic_sds_remote_node_context_default_start_task_handler,
+ scic_sds_remote_node_context_posting_state_event_handler
+ },
+ /* SCIC_SDS_REMOTE_NODE_CONTEXT_INVALIDATING_STATE */
+ {
+ scic_sds_remote_node_context_invalidating_state_destruct_handler,
+ scic_sds_remote_node_context_default_suspend_handler,
+ scic_sds_remote_node_context_continue_to_resume_handler,
+ scic_sds_remote_node_context_default_start_io_handler,
+ scic_sds_remote_node_context_default_start_task_handler,
+ scic_sds_remote_node_context_invalidating_state_event_handler
+ },
+ /* SCIC_SDS_REMOTE_NODE_CONTEXT_RESUMING_STATE */
+ {
+ scic_sds_remote_node_context_general_destruct_handler,
+ scic_sds_remote_node_context_default_suspend_handler,
+ scic_sds_remote_node_context_continue_to_resume_handler,
+ scic_sds_remote_node_context_default_start_io_handler,
+ scic_sds_remote_node_context_success_start_task_handler,
+ scic_sds_remote_node_context_resuming_state_event_handler
+ },
+ /* SCIC_SDS_REMOTE_NODE_CONTEXT_READY_STATE */
+ {
+ scic_sds_remote_node_context_general_destruct_handler,
+ scic_sds_remote_node_context_ready_state_suspend_handler,
+ scic_sds_remote_node_context_default_resume_handler,
+ scic_sds_remote_node_context_ready_state_start_io_handler,
+ scic_sds_remote_node_context_success_start_task_handler,
+ scic_sds_remote_node_context_ready_state_event_handler
+ },
+ /* SCIC_SDS_REMOTE_NODE_CONTEXT_TX_SUSPENDED_STATE */
+ {
+ scic_sds_remote_node_context_general_destruct_handler,
+ scic_sds_remote_node_context_default_suspend_handler,
+ scic_sds_remote_node_context_tx_suspended_state_resume_handler,
+ scic_sds_remote_node_context_default_start_io_handler,
+ scic_sds_remote_node_context_suspended_start_task_handler,
+ scic_sds_remote_node_context_default_event_handler
+ },
+ /* SCIC_SDS_REMOTE_NODE_CONTEXT_TX_RX_SUSPENDED_STATE */
+ {
+ scic_sds_remote_node_context_general_destruct_handler,
+ scic_sds_remote_node_context_default_suspend_handler,
+ scic_sds_remote_node_context_tx_rx_suspended_state_resume_handler,
+ scic_sds_remote_node_context_default_start_io_handler,
+ scic_sds_remote_node_context_suspended_start_task_handler,
+ scic_sds_remote_node_context_default_event_handler
+ },
+ /* SCIC_SDS_REMOTE_NODE_CONTEXT_AWAIT_SUSPENSION_STATE */
+ {
+ scic_sds_remote_node_context_general_destruct_handler,
+ scic_sds_remote_node_context_default_suspend_handler,
+ scic_sds_remote_node_context_await_suspension_state_resume_handler,
+ scic_sds_remote_node_context_default_start_io_handler,
+ scic_sds_remote_node_context_await_suspension_state_start_task_handler,
+ scic_sds_remote_node_context_await_suspension_state_event_handler
+ }
+};
+
+/*
+ * *****************************************************************************
+ * * REMOTE NODE CONTEXT PRIVATE METHODS
+ * ***************************************************************************** */
+
+/**
+ *
+ *
+ * This method just calls the user callback function and then resets the
+ * callback.
+ */
+static void scic_sds_remote_node_context_notify_user(
+ struct scic_sds_remote_node_context *rnc)
+{
+ if (rnc->user_callback != NULL) {
+ (*rnc->user_callback)(rnc->user_cookie);
+
+ rnc->user_callback = NULL;
+ rnc->user_cookie = NULL;
+ }
+}
+
+/**
+ *
+ *
+ * This method will continue the remote node context state machine by
+ * requesting to resume the remote node context state machine from its current
+ * state.
+ */
+static void scic_sds_remote_node_context_continue_state_transitions(
+ struct scic_sds_remote_node_context *rnc)
+{
+ if (rnc->destination_state == SCIC_SDS_REMOTE_NODE_DESTINATION_STATE_READY) {
+ rnc->state_handlers->resume_handler(
+ rnc, rnc->user_callback, rnc->user_cookie
+ );
+ }
+}
+
+/**
+ *
+ * @this_rnc: The remote node context object that is to be validated.
+ *
+ * This method will mark the rnc buffer as being valid and post the request to
+ * the hardware. none
+ */
+static void scic_sds_remote_node_context_validate_context_buffer(
+ struct scic_sds_remote_node_context *this_rnc)
+{
+ union scu_remote_node_context *rnc_buffer;
+
+ rnc_buffer = scic_sds_controller_get_remote_node_context_buffer(
+ scic_sds_remote_device_get_controller(this_rnc->device),
+ this_rnc->remote_node_index
+ );
+
+ rnc_buffer->ssp.is_valid = true;
+
+ if (
+ !this_rnc->device->is_direct_attached
+ && this_rnc->device->target_protocols.u.bits.attached_stp_target
+ ) {
+ scic_sds_remote_device_post_request(
+ this_rnc->device,
+ SCU_CONTEXT_COMMAND_POST_RNC_96
+ );
+ } else {
+ scic_sds_remote_device_post_request(
+ this_rnc->device,
+ SCU_CONTEXT_COMMAND_POST_RNC_32
+ );
+
+ if (this_rnc->device->is_direct_attached) {
+ scic_sds_port_set_direct_attached_device_id(
+ this_rnc->device->owning_port,
+ this_rnc->remote_node_index
+ );
+ }
+ }
+}
+
+/**
+ *
+ * @this_rnc: The remote node context object that is to be invalidated.
+ *
+ * This method will update the RNC buffer and post the invalidate request. none
+ */
+static void scic_sds_remote_node_context_invalidate_context_buffer(
+ struct scic_sds_remote_node_context *this_rnc)
+{
+ union scu_remote_node_context *rnc_buffer;
+
+ rnc_buffer = scic_sds_controller_get_remote_node_context_buffer(
+ scic_sds_remote_device_get_controller(this_rnc->device),
+ this_rnc->remote_node_index
+ );
+
+ rnc_buffer->ssp.is_valid = false;
+
+ scic_sds_remote_device_post_request(
+ this_rnc->device,
+ SCU_CONTEXT_COMMAND_POST_RNC_INVALIDATE
+ );
+
+ if (this_rnc->device->is_direct_attached) {
+ scic_sds_port_set_direct_attached_device_id(
+ this_rnc->device->owning_port,
+ SCIC_SDS_REMOTE_NODE_CONTEXT_INVALID_INDEX
+ );
+ }
+}
+
+/*
+ * *****************************************************************************
+ * * REMOTE NODE CONTEXT STATE ENTER AND EXIT METHODS
+ * ***************************************************************************** */
+
+/**
+ *
+ *
+ *
+ */
+static void scic_sds_remote_node_context_initial_state_enter(
+ struct sci_base_object *object)
+{
+ struct scic_sds_remote_node_context *rnc;
+
+ rnc = (struct scic_sds_remote_node_context *)object;
+
+ SET_STATE_HANDLER(
+ rnc,
+ scic_sds_remote_node_context_state_handler_table,
+ SCIC_SDS_REMOTE_NODE_CONTEXT_INITIAL_STATE
+ );
+
+ /*
+ * Check to see if we have gotten back to the initial state because someone
+ * requested to destroy the remote node context object. */
+ if (
+ rnc->state_machine.previous_state_id
+ == SCIC_SDS_REMOTE_NODE_CONTEXT_INVALIDATING_STATE
+ ) {
+ rnc->destination_state = SCIC_SDS_REMOTE_NODE_DESTINATION_STATE_UNSPECIFIED;
+
+ scic_sds_remote_node_context_notify_user(rnc);
+ }
+}
+
+/**
+ *
+ *
+ *
+ */
+static void scic_sds_remote_node_context_posting_state_enter(
+ struct sci_base_object *object)
+{
+ struct scic_sds_remote_node_context *this_rnc;
+
+ this_rnc = (struct scic_sds_remote_node_context *)object;
+
+ SET_STATE_HANDLER(
+ this_rnc,
+ scic_sds_remote_node_context_state_handler_table,
+ SCIC_SDS_REMOTE_NODE_CONTEXT_POSTING_STATE
+ );
+
+ scic_sds_remote_node_context_validate_context_buffer(this_rnc);
+}
+
+/**
+ *
+ *
+ *
+ */
+static void scic_sds_remote_node_context_invalidating_state_enter(
+ struct sci_base_object *object)
+{
+ struct scic_sds_remote_node_context *rnc;
+
+ rnc = (struct scic_sds_remote_node_context *)object;
+
+ SET_STATE_HANDLER(
+ rnc,
+ scic_sds_remote_node_context_state_handler_table,
+ SCIC_SDS_REMOTE_NODE_CONTEXT_INVALIDATING_STATE
+ );
+
+ scic_sds_remote_node_context_invalidate_context_buffer(rnc);
+}
+
+/**
+ *
+ *
+ *
+ */
+static void scic_sds_remote_node_context_resuming_state_enter(
+ struct sci_base_object *object)
+{
+ struct scic_sds_remote_node_context *rnc;
+
+ rnc = (struct scic_sds_remote_node_context *)object;
+
+ SET_STATE_HANDLER(
+ rnc,
+ scic_sds_remote_node_context_state_handler_table,
+ SCIC_SDS_REMOTE_NODE_CONTEXT_RESUMING_STATE
+ );
+
+ scic_sds_remote_device_post_request(
+ rnc->device,
+ SCU_CONTEXT_COMMAND_POST_RNC_RESUME
+ );
+}
+
+/**
+ *
+ *
+ *
+ */
+static void scic_sds_remote_node_context_ready_state_enter(
+ struct sci_base_object *object)
+{
+ struct scic_sds_remote_node_context *rnc;
+
+ rnc = (struct scic_sds_remote_node_context *)object;
+
+ SET_STATE_HANDLER(
+ rnc,
+ scic_sds_remote_node_context_state_handler_table,
+ SCIC_SDS_REMOTE_NODE_CONTEXT_READY_STATE
+ );
+
+ rnc->destination_state = SCIC_SDS_REMOTE_NODE_DESTINATION_STATE_UNSPECIFIED;
+
+ if (rnc->user_callback != NULL) {
+ scic_sds_remote_node_context_notify_user(rnc);
+ }
+}
+
+/**
+ *
+ *
+ *
+ */
+static void scic_sds_remote_node_context_tx_suspended_state_enter(
+ struct sci_base_object *object)
+{
+ struct scic_sds_remote_node_context *rnc;
+
+ rnc = (struct scic_sds_remote_node_context *)object;
+
+ SET_STATE_HANDLER(
+ rnc,
+ scic_sds_remote_node_context_state_handler_table,
+ SCIC_SDS_REMOTE_NODE_CONTEXT_TX_SUSPENDED_STATE
+ );
+
+ scic_sds_remote_node_context_continue_state_transitions(rnc);
+}
+
+/**
+ *
+ *
+ *
+ */
+static void scic_sds_remote_node_context_tx_rx_suspended_state_enter(
+ struct sci_base_object *object)
+{
+ struct scic_sds_remote_node_context *rnc;
+
+ rnc = (struct scic_sds_remote_node_context *)object;
+
+ SET_STATE_HANDLER(
+ rnc,
+ scic_sds_remote_node_context_state_handler_table,
+ SCIC_SDS_REMOTE_NODE_CONTEXT_TX_RX_SUSPENDED_STATE
+ );
+
+ scic_sds_remote_node_context_continue_state_transitions(rnc);
+}
+
+/**
+ *
+ *
+ *
+ */
+static void scic_sds_remote_node_context_await_suspension_state_enter(
+ struct sci_base_object *object)
+{
+ struct scic_sds_remote_node_context *rnc;
+
+ rnc = (struct scic_sds_remote_node_context *)object;
+
+ SET_STATE_HANDLER(
+ rnc,
+ scic_sds_remote_node_context_state_handler_table,
+ SCIC_SDS_REMOTE_NODE_CONTEXT_AWAIT_SUSPENSION_STATE
+ );
+}
+
+/* --------------------------------------------------------------------------- */
+
+const struct sci_base_state scic_sds_remote_node_context_state_table[] = {
+ [SCIC_SDS_REMOTE_NODE_CONTEXT_INITIAL_STATE] = {
+ .enter_state = scic_sds_remote_node_context_initial_state_enter,
+ },
+ [SCIC_SDS_REMOTE_NODE_CONTEXT_POSTING_STATE] = {
+ .enter_state = scic_sds_remote_node_context_posting_state_enter,
+ },
+ [SCIC_SDS_REMOTE_NODE_CONTEXT_INVALIDATING_STATE] = {
+ .enter_state = scic_sds_remote_node_context_invalidating_state_enter,
+ },
+ [SCIC_SDS_REMOTE_NODE_CONTEXT_RESUMING_STATE] = {
+ .enter_state = scic_sds_remote_node_context_resuming_state_enter,
+ },
+ [SCIC_SDS_REMOTE_NODE_CONTEXT_READY_STATE] = {
+ .enter_state = scic_sds_remote_node_context_ready_state_enter,
+ },
+ [SCIC_SDS_REMOTE_NODE_CONTEXT_TX_SUSPENDED_STATE] = {
+ .enter_state = scic_sds_remote_node_context_tx_suspended_state_enter,
+ },
+ [SCIC_SDS_REMOTE_NODE_CONTEXT_TX_RX_SUSPENDED_STATE] = {
+ .enter_state = scic_sds_remote_node_context_tx_rx_suspended_state_enter,
+ },
+ [SCIC_SDS_REMOTE_NODE_CONTEXT_AWAIT_SUSPENSION_STATE] = {
+ .enter_state = scic_sds_remote_node_context_await_suspension_state_enter,
+ },
+};
+
diff --git a/drivers/scsi/isci/core/scic_sds_remote_node_context.h b/drivers/scsi/isci/core/scic_sds_remote_node_context.h
new file mode 100644
index 000000000000..59eacf8f400c
--- /dev/null
+++ b/drivers/scsi/isci/core/scic_sds_remote_node_context.h
@@ -0,0 +1,342 @@
+/*
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Intel Corporation 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
+ * OWNER 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.
+ */
+
+#ifndef _SCIC_SDS_REMOTE_NODE_CONTEXT_H_
+#define _SCIC_SDS_REMOTE_NODE_CONTEXT_H_
+
+/**
+ * This file contains the structures, constants, and prototypes associated with
+ * the remote node context in the silicon. It exists to model and manage
+ * the remote node context in the silicon.
+ *
+ *
+ */
+
+#include "sci_types.h"
+#include "sci_base_state.h"
+#include "sci_base_state_machine.h"
+
+/* --------------------------------------------------------------------------- */
+
+/**
+ *
+ *
+ * This constant represents an invalid remote device id, it is used to program
+ * the STPDARNI register so the driver knows when it has received a SIGNATURE
+ * FIS from the SCU.
+ */
+#define SCIC_SDS_REMOTE_NODE_CONTEXT_INVALID_INDEX 0x0FFF
+
+#define SCU_HARDWARE_SUSPENSION (0)
+#define SCI_SOFTWARE_SUSPENSION (1)
+
+struct scic_sds_request;
+struct scic_sds_remote_device;
+struct scic_sds_remote_node_context;
+
+typedef void (*SCICS_SDS_REMOTE_NODE_CONTEXT_CALLBACK)(void *);
+
+typedef enum sci_status (*SCIC_SDS_REMOTE_NODE_CONTEXT_OPERATION)(
+ struct scic_sds_remote_node_context *this_rnc,
+ SCICS_SDS_REMOTE_NODE_CONTEXT_CALLBACK the_callback,
+ void *callback_parameter
+ );
+
+typedef enum sci_status (*SCIC_SDS_REMOTE_NODE_CONTEXT_SUSPEND_OPERATION)(
+ struct scic_sds_remote_node_context *this_rnc,
+ u32 suspension_type,
+ SCICS_SDS_REMOTE_NODE_CONTEXT_CALLBACK the_callback,
+ void *callback_parameter
+ );
+
+typedef enum sci_status (*SCIC_SDS_REMOTE_NODE_CONTEXT_IO_REQUEST)(
+ struct scic_sds_remote_node_context *this_rnc,
+ struct scic_sds_request *the_request
+ );
+
+typedef enum sci_status (*SCIC_SDS_REMOTE_NODE_CONTEXT_EVENT_HANDLER)(
+ struct scic_sds_remote_node_context *this_rnc,
+ u32 event_code
+ );
+
+/* --------------------------------------------------------------------------- */
+
+struct scic_sds_remote_node_context_handlers {
+ /**
+ * This handle is invoked to stop the RNC. The callback is invoked when after
+ * the hardware notification that the RNC has been invalidated.
+ */
+ SCIC_SDS_REMOTE_NODE_CONTEXT_OPERATION destruct_handler;
+
+ /**
+ * This handler is invoked when there is a request to suspend the RNC. The
+ * callback is invoked after the hardware notification that the remote node is
+ * suspended.
+ */
+ SCIC_SDS_REMOTE_NODE_CONTEXT_SUSPEND_OPERATION suspend_handler;
+
+ /**
+ * This handler is invoked when there is a request to resume the RNC. The
+ * callback is invoked when after the RNC has reached the ready state.
+ */
+ SCIC_SDS_REMOTE_NODE_CONTEXT_OPERATION resume_handler;
+
+ /**
+ * This handler is invoked when there is a request to start an io request
+ * operation.
+ */
+ SCIC_SDS_REMOTE_NODE_CONTEXT_IO_REQUEST start_io_handler;
+
+ /**
+ * This handler is invoked when there is a request to start a task request
+ * operation.
+ */
+ SCIC_SDS_REMOTE_NODE_CONTEXT_IO_REQUEST start_task_handler;
+
+ /**
+ * This handler is invoked where there is an RNC event that must be processed.
+ */
+ SCIC_SDS_REMOTE_NODE_CONTEXT_EVENT_HANDLER event_handler;
+
+};
+
+/* --------------------------------------------------------------------------- */
+
+/**
+ *
+ *
+ * This is the enumeration of the remote node context states.
+ */
+enum scis_sds_remote_node_context_states {
+ /**
+ * This state is the initial state for a remote node context. On a resume
+ * request the remote node context will transition to the posting state.
+ */
+ SCIC_SDS_REMOTE_NODE_CONTEXT_INITIAL_STATE,
+
+ /**
+ * This is a transition state that posts the RNi to the hardware. Once the RNC
+ * is posted the remote node context will be made ready.
+ */
+ SCIC_SDS_REMOTE_NODE_CONTEXT_POSTING_STATE,
+
+ /**
+ * This is a transition state that will post an RNC invalidate to the
+ * hardware. Once the invalidate is complete the remote node context will
+ * transition to the posting state.
+ */
+ SCIC_SDS_REMOTE_NODE_CONTEXT_INVALIDATING_STATE,
+
+ /**
+ * This is a transition state that will post an RNC resume to the hardare.
+ * Once the event notification of resume complete is received the remote node
+ * context will transition to the ready state.
+ */
+ SCIC_SDS_REMOTE_NODE_CONTEXT_RESUMING_STATE,
+
+ /**
+ * This is the state that the remote node context must be in to accept io
+ * request operations.
+ */
+ SCIC_SDS_REMOTE_NODE_CONTEXT_READY_STATE,
+
+ /**
+ * This is the state that the remote node context transitions to when it gets
+ * a TX suspend notification from the hardware.
+ */
+ SCIC_SDS_REMOTE_NODE_CONTEXT_TX_SUSPENDED_STATE,
+
+ /**
+ * This is the state that the remote node context transitions to when it gets
+ * a TX RX suspend notification from the hardware.
+ */
+ SCIC_SDS_REMOTE_NODE_CONTEXT_TX_RX_SUSPENDED_STATE,
+
+ /**
+ * This state is a wait state for the remote node context that waits for a
+ * suspend notification from the hardware. This state is entered when either
+ * there is a request to supend the remote node context or when there is a TC
+ * completion where the remote node will be suspended by the hardware.
+ */
+ SCIC_SDS_REMOTE_NODE_CONTEXT_AWAIT_SUSPENSION_STATE,
+
+ SCIC_SDS_REMOTE_NODE_CONTEXT_MAX_STATES
+
+};
+
+/**
+ *
+ *
+ * This enumeration is used to define the end destination state for the remote
+ * node context.
+ */
+enum SCIC_SDS_REMOTE_NODE_CONTEXT_DESTINATION_STATE {
+ SCIC_SDS_REMOTE_NODE_DESTINATION_STATE_UNSPECIFIED,
+ SCIC_SDS_REMOTE_NODE_DESTINATION_STATE_READY,
+ SCIC_SDS_REMOTE_NODE_DESTINATION_STATE_FINAL
+};
+
+/**
+ * struct scic_sds_remote_node_context - This structure contains the data
+ * associated with the remote node context object. The remote node context
+ * (RNC) object models the the remote device information necessary to manage
+ * the silicon RNC.
+ *
+ *
+ */
+struct scic_sds_remote_node_context {
+ /*
+ * parent object
+ */
+ struct sci_base_object parent;
+
+ /**
+ * This pointer simply points to the remote device object containing
+ * this RNC.
+ *
+ * @todo Consider making the device pointer the associated object of the
+ * the parent object.
+ */
+ struct scic_sds_remote_device *device;
+
+ /**
+ * This field indicates the remote node index (RNI) associated with
+ * this RNC.
+ */
+ u16 remote_node_index;
+
+ /**
+ * This field is the recored suspension code or the reason for the remote node
+ * context suspension.
+ */
+ u32 suspension_code;
+
+ /**
+ * This field is true if the remote node context is resuming from its current
+ * state. This can cause an automatic resume on receiving a suspension
+ * notification.
+ */
+ enum SCIC_SDS_REMOTE_NODE_CONTEXT_DESTINATION_STATE destination_state;
+
+ /**
+ * This field contains the callback function that the user requested to be
+ * called when the requested state transition is complete.
+ */
+ SCICS_SDS_REMOTE_NODE_CONTEXT_CALLBACK user_callback;
+
+ /**
+ * This field contains the parameter that is called when the user requested
+ * state transition is completed.
+ */
+ void *user_cookie;
+
+ /**
+ * This field contains the data for the object's state machine.
+ */
+ struct sci_base_state_machine state_machine;
+
+ struct scic_sds_remote_node_context_handlers *state_handlers;
+};
+
+/* --------------------------------------------------------------------------- */
+
+extern const struct sci_base_state scic_sds_remote_node_context_state_table[];
+
+extern struct scic_sds_remote_node_context_handlers
+ scic_sds_remote_node_context_state_handler_table[
+ SCIC_SDS_REMOTE_NODE_CONTEXT_MAX_STATES];
+
+/* --------------------------------------------------------------------------- */
+
+void scic_sds_remote_node_context_construct(
+ struct scic_sds_remote_device *device,
+ struct scic_sds_remote_node_context *rnc,
+ u16 remote_node_index);
+
+void scic_sds_remote_node_context_construct_buffer(
+ struct scic_sds_remote_node_context *rnc);
+
+
+bool scic_sds_remote_node_context_is_ready(
+ struct scic_sds_remote_node_context *this_rnc);
+
+#define scic_sds_remote_node_context_set_remote_node_index(rnc, rni) \
+ ((rnc)->remote_node_index = (rni))
+
+#define scic_sds_remote_node_context_get_remote_node_index(rcn) \
+ ((rnc)->remote_node_index)
+
+#define scic_sds_remote_node_context_event_handler(rnc, event_code) \
+ ((rnc)->state_handlers->event_handler(rnc, event_code))
+
+#define scic_sds_remote_node_context_resume(rnc, callback, parameter) \
+ ((rnc)->state_handlers->resume_handler(rnc, callback, parameter))
+
+#define scic_sds_remote_node_context_suspend(rnc, suspend_type, callback, parameter) \
+ ((rnc)->state_handlers->suspend_handler(rnc, suspend_type, callback, parameter))
+
+#define scic_sds_remote_node_context_destruct(rnc, callback, parameter) \
+ ((rnc)->state_handlers->destruct_handler(rnc, callback, parameter))
+
+#define scic_sds_remote_node_context_start_io(rnc, request) \
+ ((rnc)->state_handlers->start_io_handler(rnc, request))
+
+#define scic_sds_remote_node_context_start_task(rnc, task) \
+ ((rnc)->state_handlers->start_task_handler(rnc, task))
+
+/* --------------------------------------------------------------------------- */
+
+#endif /* _SCIC_SDS_REMOTE_NODE_CONTEXT_H_ */
+
diff --git a/drivers/scsi/isci/core/scic_sds_remote_node_table.c b/drivers/scsi/isci/core/scic_sds_remote_node_table.c
new file mode 100644
index 000000000000..77919a2cf652
--- /dev/null
+++ b/drivers/scsi/isci/core/scic_sds_remote_node_table.c
@@ -0,0 +1,600 @@
+/*
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Intel Corporation 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
+ * OWNER 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.
+ */
+
+/**
+ * This file contains the implementation of the SCIC_SDS_REMOTE_NODE_TABLE
+ * public, protected, and private methods.
+ *
+ *
+ */
+#include "sci_util.h"
+#include "sci_environment.h"
+#include "scic_sds_remote_node_table.h"
+#include "scic_sds_remote_node_context.h"
+
+/**
+ *
+ * @remote_node_table: This is the remote node index table from which the
+ * selection will be made.
+ * @group_table_index: This is the index to the group table from which to
+ * search for an available selection.
+ *
+ * This routine will find the bit position in absolute bit terms of the next 32
+ * + bit position. If there are available bits in the first u32 then it is
+ * just bit position. u32 This is the absolute bit position for an available
+ * group.
+ */
+static u32 scic_sds_remote_node_table_get_group_index(
+ struct scic_remote_node_table *remote_node_table,
+ u32 group_table_index)
+{
+ u32 dword_index;
+ u32 *group_table;
+ u32 bit_index;
+
+ group_table = remote_node_table->remote_node_groups[group_table_index];
+
+ for (dword_index = 0; dword_index < remote_node_table->group_array_size; dword_index++) {
+ if (group_table[dword_index] != 0) {
+ for (bit_index = 0; bit_index < 32; bit_index++) {
+ if ((group_table[dword_index] & (1 << bit_index)) != 0) {
+ return (dword_index * 32) + bit_index;
+ }
+ }
+ }
+ }
+
+ return SCIC_SDS_REMOTE_NODE_TABLE_INVALID_INDEX;
+}
+
+/**
+ *
+ * @out]: remote_node_table This the remote node table in which to clear the
+ * selector.
+ * @set_index: This is the remote node selector in which the change will be
+ * made.
+ * @group_index: This is the bit index in the table to be modified.
+ *
+ * This method will clear the group index entry in the specified group index
+ * table. none
+ */
+static void scic_sds_remote_node_table_clear_group_index(
+ struct scic_remote_node_table *remote_node_table,
+ u32 group_table_index,
+ u32 group_index)
+{
+ u32 dword_index;
+ u32 bit_index;
+ u32 *group_table;
+
+ BUG_ON(group_table_index >= SCU_STP_REMOTE_NODE_COUNT);
+ BUG_ON(group_index >= (u32)(remote_node_table->group_array_size * 32));
+
+ dword_index = group_index / 32;
+ bit_index = group_index % 32;
+ group_table = remote_node_table->remote_node_groups[group_table_index];
+
+ group_table[dword_index] = group_table[dword_index] & ~(1 << bit_index);
+}
+
+/**
+ *
+ * @out]: remote_node_table This the remote node table in which to set the
+ * selector.
+ * @group_table_index: This is the remote node selector in which the change
+ * will be made.
+ * @group_index: This is the bit position in the table to be modified.
+ *
+ * This method will set the group index bit entry in the specified gropu index
+ * table. none
+ */
+static void scic_sds_remote_node_table_set_group_index(
+ struct scic_remote_node_table *remote_node_table,
+ u32 group_table_index,
+ u32 group_index)
+{
+ u32 dword_index;
+ u32 bit_index;
+ u32 *group_table;
+
+ BUG_ON(group_table_index >= SCU_STP_REMOTE_NODE_COUNT);
+ BUG_ON(group_index >= (u32)(remote_node_table->group_array_size * 32));
+
+ dword_index = group_index / 32;
+ bit_index = group_index % 32;
+ group_table = remote_node_table->remote_node_groups[group_table_index];
+
+ group_table[dword_index] = group_table[dword_index] | (1 << bit_index);
+}
+
+/**
+ *
+ * @out]: remote_node_table This is the remote node table in which to modify
+ * the remote node availability.
+ * @remote_node_index: This is the remote node index that is being returned to
+ * the table.
+ *
+ * This method will set the remote to available in the remote node allocation
+ * table. none
+ */
+static void scic_sds_remote_node_table_set_node_index(
+ struct scic_remote_node_table *remote_node_table,
+ u32 remote_node_index)
+{
+ u32 dword_location;
+ u32 dword_remainder;
+ u32 slot_normalized;
+ u32 slot_position;
+
+ BUG_ON(
+ (remote_node_table->available_nodes_array_size * SCIC_SDS_REMOTE_NODE_SETS_PER_DWORD)
+ <= (remote_node_index / SCU_STP_REMOTE_NODE_COUNT)
+ );
+
+ dword_location = remote_node_index / SCIC_SDS_REMOTE_NODES_PER_DWORD;
+ dword_remainder = remote_node_index % SCIC_SDS_REMOTE_NODES_PER_DWORD;
+ slot_normalized = (dword_remainder / SCU_STP_REMOTE_NODE_COUNT) * sizeof(u32);
+ slot_position = remote_node_index % SCU_STP_REMOTE_NODE_COUNT;
+
+ remote_node_table->available_remote_nodes[dword_location] |=
+ 1 << (slot_normalized + slot_position);
+}
+
+/**
+ *
+ * @out]: remote_node_table This is the remote node table from which to clear
+ * the available remote node bit.
+ * @remote_node_index: This is the remote node index which is to be cleared
+ * from the table.
+ *
+ * This method clears the remote node index from the table of available remote
+ * nodes. none
+ */
+static void scic_sds_remote_node_table_clear_node_index(
+ struct scic_remote_node_table *remote_node_table,
+ u32 remote_node_index)
+{
+ u32 dword_location;
+ u32 dword_remainder;
+ u32 slot_position;
+ u32 slot_normalized;
+
+ BUG_ON(
+ (remote_node_table->available_nodes_array_size * SCIC_SDS_REMOTE_NODE_SETS_PER_DWORD)
+ <= (remote_node_index / SCU_STP_REMOTE_NODE_COUNT)
+ );
+
+ dword_location = remote_node_index / SCIC_SDS_REMOTE_NODES_PER_DWORD;
+ dword_remainder = remote_node_index % SCIC_SDS_REMOTE_NODES_PER_DWORD;
+ slot_normalized = (dword_remainder / SCU_STP_REMOTE_NODE_COUNT) * sizeof(u32);
+ slot_position = remote_node_index % SCU_STP_REMOTE_NODE_COUNT;
+
+ remote_node_table->available_remote_nodes[dword_location] &=
+ ~(1 << (slot_normalized + slot_position));
+}
+
+/**
+ *
+ * @out]: remote_node_table The remote node table from which the slot will be
+ * cleared.
+ * @group_index: The index for the slot that is to be cleared.
+ *
+ * This method clears the entire table slot at the specified slot index. none
+ */
+static void scic_sds_remote_node_table_clear_group(
+ struct scic_remote_node_table *remote_node_table,
+ u32 group_index)
+{
+ u32 dword_location;
+ u32 dword_remainder;
+ u32 dword_value;
+
+ BUG_ON(
+ (remote_node_table->available_nodes_array_size * SCIC_SDS_REMOTE_NODE_SETS_PER_DWORD)
+ <= (group_index / SCU_STP_REMOTE_NODE_COUNT)
+ );
+
+ dword_location = group_index / SCIC_SDS_REMOTE_NODE_SETS_PER_DWORD;
+ dword_remainder = group_index % SCIC_SDS_REMOTE_NODE_SETS_PER_DWORD;
+
+ dword_value = remote_node_table->available_remote_nodes[dword_location];
+ dword_value &= ~(SCIC_SDS_REMOTE_NODE_TABLE_FULL_SLOT_VALUE << (dword_remainder * 4));
+ remote_node_table->available_remote_nodes[dword_location] = dword_value;
+}
+
+/**
+ *
+ * @remote_node_table:
+ *
+ * THis method sets an entire remote node group in the remote node table.
+ */
+static void scic_sds_remote_node_table_set_group(
+ struct scic_remote_node_table *remote_node_table,
+ u32 group_index)
+{
+ u32 dword_location;
+ u32 dword_remainder;
+ u32 dword_value;
+
+ BUG_ON(
+ (remote_node_table->available_nodes_array_size * SCIC_SDS_REMOTE_NODE_SETS_PER_DWORD)
+ <= (group_index / SCU_STP_REMOTE_NODE_COUNT)
+ );
+
+ dword_location = group_index / SCIC_SDS_REMOTE_NODE_SETS_PER_DWORD;
+ dword_remainder = group_index % SCIC_SDS_REMOTE_NODE_SETS_PER_DWORD;
+
+ dword_value = remote_node_table->available_remote_nodes[dword_location];
+ dword_value |= (SCIC_SDS_REMOTE_NODE_TABLE_FULL_SLOT_VALUE << (dword_remainder * 4));
+ remote_node_table->available_remote_nodes[dword_location] = dword_value;
+}
+
+/**
+ *
+ * @remote_node_table: This is the remote node table that for which the group
+ * value is to be returned.
+ * @group_index: This is the group index to use to find the group value.
+ *
+ * This method will return the group value for the specified group index. The
+ * bit values at the specified remote node group index.
+ */
+static u8 scic_sds_remote_node_table_get_group_value(
+ struct scic_remote_node_table *remote_node_table,
+ u32 group_index)
+{
+ u32 dword_location;
+ u32 dword_remainder;
+ u32 dword_value;
+
+ dword_location = group_index / SCIC_SDS_REMOTE_NODE_SETS_PER_DWORD;
+ dword_remainder = group_index % SCIC_SDS_REMOTE_NODE_SETS_PER_DWORD;
+
+ dword_value = remote_node_table->available_remote_nodes[dword_location];
+ dword_value &= (SCIC_SDS_REMOTE_NODE_TABLE_FULL_SLOT_VALUE << (dword_remainder * 4));
+ dword_value = dword_value >> (dword_remainder * 4);
+
+ return (u8)dword_value;
+}
+
+/**
+ *
+ * @out]: remote_node_table The remote that which is to be initialized.
+ * @remote_node_entries: The number of entries to put in the table.
+ *
+ * This method will initialize the remote node table for use. none
+ */
+void scic_sds_remote_node_table_initialize(
+ struct scic_remote_node_table *remote_node_table,
+ u32 remote_node_entries)
+{
+ u32 index;
+
+ /*
+ * Initialize the raw data we could improve the speed by only initializing
+ * those entries that we are actually going to be used */
+ memset(
+ remote_node_table->available_remote_nodes,
+ 0x00,
+ sizeof(remote_node_table->available_remote_nodes)
+ );
+
+ memset(
+ remote_node_table->remote_node_groups,
+ 0x00,
+ sizeof(remote_node_table->remote_node_groups)
+ );
+
+ /* Initialize the available remote node sets */
+ remote_node_table->available_nodes_array_size = (u16)
+ (remote_node_entries / SCIC_SDS_REMOTE_NODES_PER_DWORD)
+ + ((remote_node_entries % SCIC_SDS_REMOTE_NODES_PER_DWORD) != 0);
+
+
+ /* Initialize each full DWORD to a FULL SET of remote nodes */
+ for (index = 0; index < remote_node_entries; index++) {
+ scic_sds_remote_node_table_set_node_index(remote_node_table, index);
+ }
+
+ remote_node_table->group_array_size = (u16)
+ (remote_node_entries / (SCU_STP_REMOTE_NODE_COUNT * 32))
+ + ((remote_node_entries % (SCU_STP_REMOTE_NODE_COUNT * 32)) != 0);
+
+ for (index = 0; index < (remote_node_entries / SCU_STP_REMOTE_NODE_COUNT); index++) {
+ /*
+ * These are all guaranteed to be full slot values so fill them in the
+ * available sets of 3 remote nodes */
+ scic_sds_remote_node_table_set_group_index(remote_node_table, 2, index);
+ }
+
+ /* Now fill in any remainders that we may find */
+ if ((remote_node_entries % SCU_STP_REMOTE_NODE_COUNT) == 2) {
+ scic_sds_remote_node_table_set_group_index(remote_node_table, 1, index);
+ } else if ((remote_node_entries % SCU_STP_REMOTE_NODE_COUNT) == 1) {
+ scic_sds_remote_node_table_set_group_index(remote_node_table, 0, index);
+ }
+}
+
+/**
+ *
+ * @out]: remote_node_table The remote node table from which to allocate a
+ * remote node.
+ * @table_index: The group index that is to be used for the search.
+ *
+ * This method will allocate a single RNi from the remote node table. The
+ * table index will determine from which remote node group table to search.
+ * This search may fail and another group node table can be specified. The
+ * function is designed to allow a serach of the available single remote node
+ * group up to the triple remote node group. If an entry is found in the
+ * specified table the remote node is removed and the remote node groups are
+ * updated. The RNi value or an invalid remote node context if an RNi can not
+ * be found.
+ */
+static u16 scic_sds_remote_node_table_allocate_single_remote_node(
+ struct scic_remote_node_table *remote_node_table,
+ u32 group_table_index)
+{
+ u8 index;
+ u8 group_value;
+ u32 group_index;
+ u16 remote_node_index = SCIC_SDS_REMOTE_NODE_CONTEXT_INVALID_INDEX;
+
+ group_index = scic_sds_remote_node_table_get_group_index(
+ remote_node_table, group_table_index);
+
+ /* We could not find an available slot in the table selector 0 */
+ if (group_index != SCIC_SDS_REMOTE_NODE_TABLE_INVALID_INDEX) {
+ group_value = scic_sds_remote_node_table_get_group_value(
+ remote_node_table, group_index);
+
+ for (index = 0; index < SCU_STP_REMOTE_NODE_COUNT; index++) {
+ if (((1 << index) & group_value) != 0) {
+ /* We have selected a bit now clear it */
+ remote_node_index = (u16)(group_index * SCU_STP_REMOTE_NODE_COUNT
+ + index);
+
+ scic_sds_remote_node_table_clear_group_index(
+ remote_node_table, group_table_index, group_index
+ );
+
+ scic_sds_remote_node_table_clear_node_index(
+ remote_node_table, remote_node_index
+ );
+
+ if (group_table_index > 0) {
+ scic_sds_remote_node_table_set_group_index(
+ remote_node_table, group_table_index - 1, group_index
+ );
+ }
+
+ break;
+ }
+ }
+ }
+
+ return remote_node_index;
+}
+
+/**
+ *
+ * @remote_node_table: This is the remote node table from which to allocate the
+ * remote node entries.
+ * @group_table_index: THis is the group table index which must equal two (2)
+ * for this operation.
+ *
+ * This method will allocate three consecutive remote node context entries. If
+ * there are no remaining triple entries the function will return a failure.
+ * The remote node index that represents three consecutive remote node entries
+ * or an invalid remote node context if none can be found.
+ */
+static u16 scic_sds_remote_node_table_allocate_triple_remote_node(
+ struct scic_remote_node_table *remote_node_table,
+ u32 group_table_index)
+{
+ u32 group_index;
+ u16 remote_node_index = SCIC_SDS_REMOTE_NODE_CONTEXT_INVALID_INDEX;
+
+ group_index = scic_sds_remote_node_table_get_group_index(
+ remote_node_table, group_table_index);
+
+ if (group_index != SCIC_SDS_REMOTE_NODE_TABLE_INVALID_INDEX) {
+ remote_node_index = (u16)group_index * SCU_STP_REMOTE_NODE_COUNT;
+
+ scic_sds_remote_node_table_clear_group_index(
+ remote_node_table, group_table_index, group_index
+ );
+
+ scic_sds_remote_node_table_clear_group(
+ remote_node_table, group_index
+ );
+ }
+
+ return remote_node_index;
+}
+
+/**
+ *
+ * @remote_node_table: This is the remote node table from which the remote node
+ * allocation is to take place.
+ * @remote_node_count: This is ther remote node count which is one of
+ * SCU_SSP_REMOTE_NODE_COUNT(1) or SCU_STP_REMOTE_NODE_COUNT(3).
+ *
+ * This method will allocate a remote node that mataches the remote node count
+ * specified by the caller. Valid values for remote node count is
+ * SCU_SSP_REMOTE_NODE_COUNT(1) or SCU_STP_REMOTE_NODE_COUNT(3). u16 This is
+ * the remote node index that is returned or an invalid remote node context.
+ */
+u16 scic_sds_remote_node_table_allocate_remote_node(
+ struct scic_remote_node_table *remote_node_table,
+ u32 remote_node_count)
+{
+ u16 remote_node_index = SCIC_SDS_REMOTE_NODE_CONTEXT_INVALID_INDEX;
+
+ if (remote_node_count == SCU_SSP_REMOTE_NODE_COUNT) {
+ remote_node_index =
+ scic_sds_remote_node_table_allocate_single_remote_node(
+ remote_node_table, 0);
+
+ if (remote_node_index == SCIC_SDS_REMOTE_NODE_CONTEXT_INVALID_INDEX) {
+ remote_node_index =
+ scic_sds_remote_node_table_allocate_single_remote_node(
+ remote_node_table, 1);
+ }
+
+ if (remote_node_index == SCIC_SDS_REMOTE_NODE_CONTEXT_INVALID_INDEX) {
+ remote_node_index =
+ scic_sds_remote_node_table_allocate_single_remote_node(
+ remote_node_table, 2);
+ }
+ } else if (remote_node_count == SCU_STP_REMOTE_NODE_COUNT) {
+ remote_node_index =
+ scic_sds_remote_node_table_allocate_triple_remote_node(
+ remote_node_table, 2);
+ }
+
+ return remote_node_index;
+}
+
+/**
+ *
+ * @remote_node_table:
+ *
+ * This method will free a single remote node index back to the remote node
+ * table. This routine will update the remote node groups
+ */
+static void scic_sds_remote_node_table_release_single_remote_node(
+ struct scic_remote_node_table *remote_node_table,
+ u16 remote_node_index)
+{
+ u32 group_index;
+ u8 group_value;
+
+ group_index = remote_node_index / SCU_STP_REMOTE_NODE_COUNT;
+
+ group_value = scic_sds_remote_node_table_get_group_value(remote_node_table, group_index);
+
+ /*
+ * Assert that we are not trying to add an entry to a slot that is already
+ * full. */
+ BUG_ON(group_value == SCIC_SDS_REMOTE_NODE_TABLE_FULL_SLOT_VALUE);
+
+ if (group_value == 0x00) {
+ /*
+ * There are no entries in this slot so it must be added to the single
+ * slot table. */
+ scic_sds_remote_node_table_set_group_index(remote_node_table, 0, group_index);
+ } else if ((group_value & (group_value - 1)) == 0) {
+ /*
+ * There is only one entry in this slot so it must be moved from the
+ * single slot table to the dual slot table */
+ scic_sds_remote_node_table_clear_group_index(remote_node_table, 0, group_index);
+ scic_sds_remote_node_table_set_group_index(remote_node_table, 1, group_index);
+ } else {
+ /*
+ * There are two entries in the slot so it must be moved from the dual
+ * slot table to the tripple slot table. */
+ scic_sds_remote_node_table_clear_group_index(remote_node_table, 1, group_index);
+ scic_sds_remote_node_table_set_group_index(remote_node_table, 2, group_index);
+ }
+
+ scic_sds_remote_node_table_set_node_index(remote_node_table, remote_node_index);
+}
+
+/**
+ *
+ * @remote_node_table: This is the remote node table to which the remote node
+ * index is to be freed.
+ *
+ * This method will release a group of three consecutive remote nodes back to
+ * the free remote nodes.
+ */
+static void scic_sds_remote_node_table_release_triple_remote_node(
+ struct scic_remote_node_table *remote_node_table,
+ u16 remote_node_index)
+{
+ u32 group_index;
+
+ group_index = remote_node_index / SCU_STP_REMOTE_NODE_COUNT;
+
+ scic_sds_remote_node_table_set_group_index(
+ remote_node_table, 2, group_index
+ );
+
+ scic_sds_remote_node_table_set_group(remote_node_table, group_index);
+}
+
+/**
+ *
+ * @remote_node_table: The remote node table to which the remote node index is
+ * to be freed.
+ * @remote_node_count: This is the count of consecutive remote nodes that are
+ * to be freed.
+ *
+ * This method will release the remote node index back into the remote node
+ * table free pool.
+ */
+void scic_sds_remote_node_table_release_remote_node_index(
+ struct scic_remote_node_table *remote_node_table,
+ u32 remote_node_count,
+ u16 remote_node_index)
+{
+ if (remote_node_count == SCU_SSP_REMOTE_NODE_COUNT) {
+ scic_sds_remote_node_table_release_single_remote_node(
+ remote_node_table, remote_node_index);
+ } else if (remote_node_count == SCU_STP_REMOTE_NODE_COUNT) {
+ scic_sds_remote_node_table_release_triple_remote_node(
+ remote_node_table, remote_node_index);
+ }
+}
+
diff --git a/drivers/scsi/isci/core/scic_sds_remote_node_table.h b/drivers/scsi/isci/core/scic_sds_remote_node_table.h
new file mode 100644
index 000000000000..6ee5fbab25dd
--- /dev/null
+++ b/drivers/scsi/isci/core/scic_sds_remote_node_table.h
@@ -0,0 +1,196 @@
+/*
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Intel Corporation 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
+ * OWNER 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.
+ */
+
+#ifndef _SCIC_SDS_REMOTE_NODE_TABLE_H_
+#define _SCIC_SDS_REMOTE_NODE_TABLE_H_
+
+/**
+ * This file contains the structures, constants and prototypes used for the
+ * remote node table.
+ *
+ *
+ */
+
+#include "sci_types.h"
+#include "sci_controller_constants.h"
+
+/**
+ *
+ *
+ * Remote node sets are sets of remote node index in the remtoe node table The
+ * SCU hardware requires that STP remote node entries take three consecutive
+ * remote node index so the table is arranged in sets of three. The bits are
+ * used as 0111 0111 to make a byte and the bits define the set of three remote
+ * nodes to use as a sequence.
+ */
+#define SCIC_SDS_REMOTE_NODE_SETS_PER_BYTE 2
+
+/**
+ *
+ *
+ * Since the remote node table is organized as DWORDS take the remote node sets
+ * in bytes and represent them in DWORDs. The lowest ordered bits are the ones
+ * used in case full DWORD is not being used. i.e. 0000 0000 0000 0000 0111
+ * 0111 0111 0111 // if only a single WORD is in use in the DWORD.
+ */
+#define SCIC_SDS_REMOTE_NODE_SETS_PER_DWORD \
+ (sizeof(u32) * SCIC_SDS_REMOTE_NODE_SETS_PER_BYTE)
+/**
+ *
+ *
+ * This is a count of the numeber of remote nodes that can be represented in a
+ * byte
+ */
+#define SCIC_SDS_REMOTE_NODES_PER_BYTE \
+ (SCU_STP_REMOTE_NODE_COUNT * SCIC_SDS_REMOTE_NODE_SETS_PER_BYTE)
+
+/**
+ *
+ *
+ * This is a count of the number of remote nodes that can be represented in a
+ * DWROD
+ */
+#define SCIC_SDS_REMOTE_NODES_PER_DWORD \
+ (sizeof(u32) * SCIC_SDS_REMOTE_NODES_PER_BYTE)
+
+/**
+ *
+ *
+ * This is the number of bits in a remote node group
+ */
+#define SCIC_SDS_REMOTE_NODES_BITS_PER_GROUP 4
+
+#define SCIC_SDS_REMOTE_NODE_TABLE_INVALID_INDEX (0xFFFFFFFF)
+#define SCIC_SDS_REMOTE_NODE_TABLE_FULL_SLOT_VALUE (0x07)
+#define SCIC_SDS_REMOTE_NODE_TABLE_EMPTY_SLOT_VALUE (0x00)
+
+/**
+ *
+ *
+ * Expander attached sata remote node count
+ */
+#define SCU_STP_REMOTE_NODE_COUNT 3
+
+/**
+ *
+ *
+ * Expander or direct attached ssp remote node count
+ */
+#define SCU_SSP_REMOTE_NODE_COUNT 1
+
+/**
+ *
+ *
+ * Direct attached STP remote node count
+ */
+#define SCU_SATA_REMOTE_NODE_COUNT 1
+
+/**
+ * struct scic_remote_node_table -
+ *
+ *
+ */
+struct scic_remote_node_table {
+ /**
+ * This field contains the array size in dwords
+ */
+ u16 available_nodes_array_size;
+
+ /**
+ * This field contains the array size of the
+ */
+ u16 group_array_size;
+
+ /**
+ * This field is the array of available remote node entries in bits.
+ * Because of the way STP remote node data is allocated on the SCU hardware
+ * the remote nodes must occupy three consecutive remote node context
+ * entries. For ease of allocation and de-allocation we have broken the
+ * sets of three into a single nibble. When the STP RNi is allocated all
+ * of the bits in the nibble are cleared. This math results in a table size
+ * of MAX_REMOTE_NODES / CONSECUTIVE RNi ENTRIES for STP / 2 entries per byte.
+ */
+ u32 available_remote_nodes[
+ (SCI_MAX_REMOTE_DEVICES / SCIC_SDS_REMOTE_NODES_PER_DWORD)
+ + ((SCI_MAX_REMOTE_DEVICES % SCIC_SDS_REMOTE_NODES_PER_DWORD) != 0)];
+
+ /**
+ * This field is the nibble selector for the above table. There are three
+ * possible selectors each for fast lookup when trying to find one, two or
+ * three remote node entries.
+ */
+ u32 remote_node_groups[
+ SCU_STP_REMOTE_NODE_COUNT][
+ (SCI_MAX_REMOTE_DEVICES / (32 * SCU_STP_REMOTE_NODE_COUNT))
+ + ((SCI_MAX_REMOTE_DEVICES % (32 * SCU_STP_REMOTE_NODE_COUNT)) != 0)];
+
+};
+
+/* --------------------------------------------------------------------------- */
+
+void scic_sds_remote_node_table_initialize(
+ struct scic_remote_node_table *remote_node_table,
+ u32 remote_node_entries);
+
+u16 scic_sds_remote_node_table_allocate_remote_node(
+ struct scic_remote_node_table *remote_node_table,
+ u32 remote_node_count);
+
+void scic_sds_remote_node_table_release_remote_node_index(
+ struct scic_remote_node_table *remote_node_table,
+ u32 remote_node_count,
+ u16 remote_node_index);
+
+#endif /* _SCIC_SDS_REMOTE_NODE_TABLE_H_ */
diff --git a/drivers/scsi/isci/core/scic_sds_request.c b/drivers/scsi/isci/core/scic_sds_request.c
new file mode 100644
index 000000000000..c696d246ea5a
--- /dev/null
+++ b/drivers/scsi/isci/core/scic_sds_request.c
@@ -0,0 +1,2179 @@
+/*
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Intel Corporation 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
+ * OWNER 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.
+ */
+
+
+#include "intel_sas.h"
+#include "intel_sata.h"
+#include "intel_sat.h"
+#include "sci_base_request.h"
+#include "scic_controller.h"
+#include "scic_io_request.h"
+#include "scic_remote_device.h"
+#include "scic_sds_controller.h"
+#include "scic_sds_controller_registers.h"
+#include "scic_sds_pci.h"
+#include "scic_sds_port.h"
+#include "scic_sds_remote_device.h"
+#include "scic_sds_request.h"
+#include "scic_sds_smp_request.h"
+#include "scic_sds_stp_request.h"
+#include "scic_sds_unsolicited_frame_control.h"
+#include "scic_user_callback.h"
+#include "sci_environment.h"
+#include "sci_types.h"
+#include "sci_util.h"
+#include "scu_completion_codes.h"
+#include "scu_constants.h"
+#include "scu_task_context.h"
+
+#if !defined(DISABLE_ATAPI)
+#include "scic_sds_stp_packet_request.h"
+#endif
+
+/*
+ * ****************************************************************************
+ * * SCIC SDS IO REQUEST CONSTANTS
+ * **************************************************************************** */
+
+/**
+ *
+ *
+ * We have no timer requirements for IO requests right now
+ */
+#define SCIC_SDS_IO_REQUEST_MINIMUM_TIMER_COUNT (0)
+#define SCIC_SDS_IO_REQUEST_MAXIMUM_TIMER_COUNT (0)
+
+/*
+ * ****************************************************************************
+ * * SCIC SDS IO REQUEST MACROS
+ * **************************************************************************** */
+
+/**
+ * scic_sds_request_get_user_request() -
+ *
+ * This is a helper macro to return the os handle for this request object.
+ */
+#define scic_sds_request_get_user_request(request) \
+ ((request)->user_request)
+
+
+/**
+ * scic_ssp_io_request_get_object_size() -
+ *
+ * This macro returns the sizeof memory required to store the an SSP IO
+ * request. This does not include the size of the SGL or SCU Task Context
+ * memory.
+ */
+#define scic_ssp_io_request_get_object_size() \
+ (\
+ sizeof(struct sci_ssp_command_iu) \
+ + sizeof(struct sci_ssp_response_iu) \
+ )
+
+/**
+ * scic_sds_ssp_request_get_command_buffer() -
+ *
+ * This macro returns the address of the ssp command buffer in the io request
+ * memory
+ */
+#define scic_sds_ssp_request_get_command_buffer(memory) \
+ ((struct sci_ssp_command_iu *)(\
+ ((char *)(memory)) + sizeof(struct scic_sds_request) \
+ ))
+
+/**
+ * scic_sds_ssp_request_get_response_buffer() -
+ *
+ * This macro returns the address of the ssp response buffer in the io request
+ * memory
+ */
+#define scic_sds_ssp_request_get_response_buffer(memory) \
+ ((struct sci_ssp_response_iu *)(\
+ ((char *)(scic_sds_ssp_request_get_command_buffer(memory))) \
+ + sizeof(struct sci_ssp_command_iu) \
+ ))
+
+/**
+ * scic_sds_ssp_request_get_task_context_buffer() -
+ *
+ * This macro returns the address of the task context buffer in the io request
+ * memory
+ */
+#define scic_sds_ssp_request_get_task_context_buffer(memory) \
+ ((struct scu_task_context *)(\
+ ((char *)(scic_sds_ssp_request_get_response_buffer(memory))) \
+ + sizeof(struct sci_ssp_response_iu) \
+ ))
+
+/**
+ * scic_sds_ssp_request_get_sgl_element_buffer() -
+ *
+ * This macro returns the address of the sgl elment pairs in the io request
+ * memory buffer
+ */
+#define scic_sds_ssp_request_get_sgl_element_buffer(memory) \
+ ((struct scu_sgl_element_pair *)(\
+ ((char *)(scic_sds_ssp_request_get_task_context_buffer(memory))) \
+ + sizeof(struct scu_task_context) \
+ ))
+
+
+/**
+ * scic_ssp_task_request_get_object_size() -
+ *
+ * This macro returns the sizeof of memory required to store an SSP Task
+ * request. This does not include the size of the SCU Task Context memory.
+ */
+#define scic_ssp_task_request_get_object_size() \
+ (\
+ sizeof(struct sci_ssp_task_iu) \
+ + sizeof(struct sci_ssp_response_iu) \
+ )
+
+/**
+ * scic_sds_ssp_task_request_get_command_buffer() -
+ *
+ * This macro returns the address of the ssp command buffer in the task request
+ * memory. Yes its the same as the above macro except for the name.
+ */
+#define scic_sds_ssp_task_request_get_command_buffer(memory) \
+ ((struct sci_ssp_task_iu *)(\
+ ((char *)(memory)) + sizeof(struct scic_sds_request) \
+ ))
+
+/**
+ * scic_sds_ssp_task_request_get_response_buffer() -
+ *
+ * This macro returns the address of the ssp response buffer in the task
+ * request memory.
+ */
+#define scic_sds_ssp_task_request_get_response_buffer(memory) \
+ ((struct sci_ssp_response_iu *)(\
+ ((char *)(scic_sds_ssp_task_request_get_command_buffer(memory))) \
+ + sizeof(struct sci_ssp_task_iu) \
+ ))
+
+/**
+ * scic_sds_ssp_task_request_get_task_context_buffer() -
+ *
+ * This macro returs the task context buffer for the SSP task request.
+ */
+#define scic_sds_ssp_task_request_get_task_context_buffer(memory) \
+ ((struct scu_task_context *)(\
+ ((char *)(scic_sds_ssp_task_request_get_response_buffer(memory))) \
+ + sizeof(struct sci_ssp_response_iu) \
+ ))
+
+
+
+/*
+ * ****************************************************************************
+ * * SCIC SDS IO REQUEST PRIVATE METHODS
+ * **************************************************************************** */
+
+/**
+ *
+ *
+ * This method returns the size required to store an SSP IO request object. u32
+ */
+static u32 scic_sds_ssp_request_get_object_size(void)
+{
+ return sizeof(struct scic_sds_request)
+ + scic_ssp_io_request_get_object_size()
+ + sizeof(struct scu_task_context)
+ + CACHE_LINE_SIZE
+ + sizeof(struct scu_sgl_element_pair) * SCU_MAX_SGL_ELEMENT_PAIRS;
+}
+
+/**
+ * This method returns the sgl element pair for the specificed sgl_pair index.
+ * @this_request: This parameter specifies the IO request for which to retrieve
+ * the Scatter-Gather List element pair.
+ * @sgl_pair_index: This parameter specifies the index into the SGL element
+ * pair to be retrieved.
+ *
+ * This method returns a pointer to an struct scu_sgl_element_pair.
+ */
+static struct scu_sgl_element_pair *scic_sds_request_get_sgl_element_pair(
+ struct scic_sds_request *this_request,
+ u32 sgl_pair_index
+ ) {
+ struct scu_task_context *task_context;
+
+ task_context = (struct scu_task_context *)this_request->task_context_buffer;
+
+ if (sgl_pair_index == 0) {
+ return &task_context->sgl_pair_ab;
+ } else if (sgl_pair_index == 1) {
+ return &task_context->sgl_pair_cd;
+ }
+
+ return &this_request->sgl_element_pair_buffer[sgl_pair_index - 2];
+}
+
+/**
+ * This function will build the SGL list for an IO request.
+ * @this_request: This parameter specifies the IO request for which to build
+ * the Scatter-Gather List.
+ *
+ */
+void scic_sds_request_build_sgl(
+ struct scic_sds_request *this_request)
+{
+ void *os_sge;
+ void *os_handle;
+ dma_addr_t physical_address;
+ u32 sgl_pair_index = 0;
+ struct scu_sgl_element_pair *scu_sgl_list = NULL;
+ struct scu_sgl_element_pair *previous_pair = NULL;
+
+ os_handle = scic_sds_request_get_user_request(this_request);
+ scic_cb_io_request_get_next_sge(os_handle, NULL, &os_sge);
+
+ while (os_sge != NULL) {
+ scu_sgl_list =
+ scic_sds_request_get_sgl_element_pair(this_request, sgl_pair_index);
+
+ SCU_SGL_COPY(os_handle, scu_sgl_list->A, os_sge);
+
+ scic_cb_io_request_get_next_sge(os_handle, os_sge, &os_sge);
+
+ if (os_sge != NULL) {
+ SCU_SGL_COPY(os_handle, scu_sgl_list->B, os_sge);
+
+ scic_cb_io_request_get_next_sge(os_handle, os_sge, &os_sge);
+ } else {
+ SCU_SGL_ZERO(scu_sgl_list->B);
+ }
+
+ if (previous_pair != NULL) {
+ scic_cb_io_request_get_physical_address(
+ scic_sds_request_get_controller(this_request),
+ this_request,
+ scu_sgl_list,
+ &physical_address
+ );
+
+ previous_pair->next_pair_upper =
+ upper_32_bits(physical_address);
+ previous_pair->next_pair_lower =
+ lower_32_bits(physical_address);
+ }
+
+ previous_pair = scu_sgl_list;
+ sgl_pair_index++;
+ }
+
+ if (scu_sgl_list != NULL) {
+ scu_sgl_list->next_pair_upper = 0;
+ scu_sgl_list->next_pair_lower = 0;
+ }
+}
+
+/**
+ * This method initializes common portions of the io request object. This
+ * includes construction of the struct sci_base_request parent.
+ * @the_controller: This parameter specifies the controller for which the
+ * request is being constructed.
+ * @the_target: This parameter specifies the remote device for which the
+ * request is being constructed.
+ * @io_tag: This parameter specifies the IO tag to be utilized for this
+ * request. This parameter can be set to SCI_CONTROLLER_INVALID_IO_TAG.
+ * @user_io_request_object: This parameter specifies the user request object
+ * for which the request is being constructed.
+ * @this_request: This parameter specifies the request being constructed.
+ *
+ */
+static void scic_sds_general_request_construct(
+ struct scic_sds_controller *the_controller,
+ struct scic_sds_remote_device *the_target,
+ u16 io_tag,
+ void *user_io_request_object,
+ struct scic_sds_request *this_request)
+{
+ sci_base_request_construct(
+ &this_request->parent,
+ scic_sds_request_state_table
+ );
+
+ this_request->io_tag = io_tag;
+ this_request->user_request = user_io_request_object;
+ this_request->owning_controller = the_controller;
+ this_request->target_device = the_target;
+ this_request->has_started_substate_machine = false;
+ this_request->protocol = SCIC_NO_PROTOCOL;
+ this_request->saved_rx_frame_index = SCU_INVALID_FRAME_INDEX;
+ this_request->device_sequence = scic_sds_remote_device_get_sequence(the_target);
+
+ this_request->sci_status = SCI_SUCCESS;
+ this_request->scu_status = 0;
+ this_request->post_context = 0xFFFFFFFF;
+
+ this_request->is_task_management_request = false;
+
+ if (io_tag == SCI_CONTROLLER_INVALID_IO_TAG) {
+ this_request->was_tag_assigned_by_user = false;
+ this_request->task_context_buffer = NULL;
+ } else {
+ this_request->was_tag_assigned_by_user = true;
+
+ this_request->task_context_buffer =
+ scic_sds_controller_get_task_context_buffer(
+ this_request->owning_controller, io_tag);
+ }
+}
+
+/**
+ * This method build the remainder of the IO request object.
+ * @this_request: This parameter specifies the request object being constructed.
+ *
+ * The scic_sds_general_request_construct() must be called before this call is
+ * valid. none
+ */
+static void scic_sds_ssp_io_request_assign_buffers(
+ struct scic_sds_request *this_request)
+{
+ this_request->command_buffer =
+ scic_sds_ssp_request_get_command_buffer(this_request);
+ this_request->response_buffer =
+ scic_sds_ssp_request_get_response_buffer(this_request);
+ this_request->sgl_element_pair_buffer =
+ scic_sds_ssp_request_get_sgl_element_buffer(this_request);
+ this_request->sgl_element_pair_buffer =
+ scic_sds_request_align_sgl_element_buffer(this_request->sgl_element_pair_buffer);
+
+ if (this_request->was_tag_assigned_by_user == false) {
+ this_request->task_context_buffer =
+ scic_sds_ssp_request_get_task_context_buffer(this_request);
+ this_request->task_context_buffer =
+ scic_sds_request_align_task_context_buffer(this_request->task_context_buffer);
+ }
+}
+
+/**
+ * This method constructs the SSP Command IU data for this io request object.
+ * @this_request: This parameter specifies the request object for which the SSP
+ * command information unit is being built.
+ *
+ */
+static void scic_sds_io_request_build_ssp_command_iu(
+ struct scic_sds_request *this_request)
+{
+ struct sci_ssp_command_iu *command_frame;
+ void *os_handle;
+ u32 cdb_length;
+ u32 *cdb_buffer;
+
+ command_frame =
+ (struct sci_ssp_command_iu *)this_request->command_buffer;
+
+ os_handle = scic_sds_request_get_user_request(this_request);
+
+ command_frame->lun_upper = 0;
+ command_frame->lun_lower = scic_cb_ssp_io_request_get_lun(os_handle);
+
+ ((u32 *)command_frame)[2] = 0;
+
+ cdb_length = scic_cb_ssp_io_request_get_cdb_length(os_handle);
+ cdb_buffer = (u32 *)scic_cb_ssp_io_request_get_cdb_address(os_handle);
+
+ if (cdb_length > 16) {
+ command_frame->additional_cdb_length = cdb_length - 16;
+ }
+
+ /* / @todo Is it ok to leave junk at the end of the cdb buffer? */
+ scic_word_copy_with_swap(
+ (u32 *)(&command_frame->cdb),
+ (u32 *)(cdb_buffer),
+ (cdb_length + 3) / sizeof(u32)
+ );
+
+ command_frame->enable_first_burst = 0;
+ command_frame->task_priority =
+ scic_cb_ssp_io_request_get_command_priority(os_handle);
+ command_frame->task_attribute =
+ scic_cb_ssp_io_request_get_task_attribute(os_handle);
+}
+
+
+/**
+ * This method constructs the SSP Task IU data for this io request object.
+ * @this_request:
+ *
+ */
+static void scic_sds_task_request_build_ssp_task_iu(
+ struct scic_sds_request *this_request)
+{
+ struct sci_ssp_task_iu *command_frame;
+ void *os_handle;
+
+ command_frame =
+ (struct sci_ssp_task_iu *)this_request->command_buffer;
+
+ os_handle = scic_sds_request_get_user_request(this_request);
+
+ command_frame->lun_upper = 0;
+ command_frame->lun_lower = scic_cb_ssp_task_request_get_lun(os_handle);
+
+ ((u32 *)command_frame)[2] = 0;
+
+ command_frame->task_function =
+ scic_cb_ssp_task_request_get_function(os_handle);
+ command_frame->task_tag =
+ scic_cb_ssp_task_request_get_io_tag_to_manage(os_handle);
+}
+
+
+/**
+ * This method is will fill in the SCU Task Context for any type of SSP request.
+ * @this_request:
+ * @task_context:
+ *
+ */
+static void scu_ssp_reqeust_construct_task_context(
+ struct scic_sds_request *this_request,
+ struct scu_task_context *task_context)
+{
+ dma_addr_t physical_address;
+ struct scic_sds_controller *owning_controller;
+ struct scic_sds_remote_device *target_device;
+ struct scic_sds_port *target_port;
+
+ owning_controller = scic_sds_request_get_controller(this_request);
+ target_device = scic_sds_request_get_device(this_request);
+ target_port = scic_sds_request_get_port(this_request);
+
+ /* Fill in the TC with the its required data */
+ task_context->abort = 0;
+ task_context->priority = 0;
+ task_context->initiator_request = 1;
+ task_context->connection_rate =
+ scic_remote_device_get_connection_rate(target_device);
+ task_context->protocol_engine_index =
+ scic_sds_controller_get_protocol_engine_group(owning_controller);
+ task_context->logical_port_index =
+ scic_sds_port_get_index(target_port);
+ task_context->protocol_type = SCU_TASK_CONTEXT_PROTOCOL_SSP;
+ task_context->valid = SCU_TASK_CONTEXT_VALID;
+ task_context->context_type = SCU_TASK_CONTEXT_TYPE;
+
+ task_context->remote_node_index =
+ scic_sds_remote_device_get_index(this_request->target_device);
+ task_context->command_code = 0;
+
+ task_context->link_layer_control = 0;
+ task_context->do_not_dma_ssp_good_response = 1;
+ task_context->strict_ordering = 0;
+ task_context->control_frame = 0;
+ task_context->timeout_enable = 0;
+ task_context->block_guard_enable = 0;
+
+ task_context->address_modifier = 0;
+
+ /* task_context->type.ssp.tag = this_request->io_tag; */
+ task_context->task_phase = 0x01;
+
+ if (this_request->was_tag_assigned_by_user) {
+ /* Build the task context now since we have already read the data */
+ this_request->post_context = (
+ SCU_CONTEXT_COMMAND_REQUEST_TYPE_POST_TC
+ | (
+ scic_sds_controller_get_protocol_engine_group(owning_controller)
+ << SCU_CONTEXT_COMMAND_PROTOCOL_ENGINE_GROUP_SHIFT
+ )
+ | (
+ scic_sds_port_get_index(target_port)
+ << SCU_CONTEXT_COMMAND_LOGICAL_PORT_SHIFT
+ )
+ | scic_sds_io_tag_get_index(this_request->io_tag)
+ );
+ } else {
+ /* Build the task context now since we have already read the data */
+ this_request->post_context = (
+ SCU_CONTEXT_COMMAND_REQUEST_TYPE_POST_TC
+ | (
+ scic_sds_controller_get_protocol_engine_group(owning_controller)
+ << SCU_CONTEXT_COMMAND_PROTOCOL_ENGINE_GROUP_SHIFT
+ )
+ | (
+ scic_sds_port_get_index(target_port)
+ << SCU_CONTEXT_COMMAND_LOGICAL_PORT_SHIFT
+ )
+ /* This is not assigned because we have to wait until we get a TCi */
+ );
+ }
+
+ /* Copy the physical address for the command buffer to the SCU Task Context */
+ scic_cb_io_request_get_physical_address(
+ scic_sds_request_get_controller(this_request),
+ this_request,
+ this_request->command_buffer,
+ &physical_address
+ );
+
+ task_context->command_iu_upper =
+ upper_32_bits(physical_address);
+ task_context->command_iu_lower =
+ lower_32_bits(physical_address);
+
+ /* Copy the physical address for the response buffer to the SCU Task Context */
+ scic_cb_io_request_get_physical_address(
+ scic_sds_request_get_controller(this_request),
+ this_request,
+ this_request->response_buffer,
+ &physical_address
+ );
+
+ task_context->response_iu_upper =
+ upper_32_bits(physical_address);
+ task_context->response_iu_lower =
+ lower_32_bits(physical_address);
+}
+
+/**
+ * This method is will fill in the SCU Task Context for a SSP IO request.
+ * @this_request:
+ *
+ */
+static void scu_ssp_io_request_construct_task_context(
+ struct scic_sds_request *this_request,
+ SCI_IO_REQUEST_DATA_DIRECTION data_direction,
+ u32 transfer_length_bytes)
+{
+ struct scu_task_context *task_context;
+
+ task_context = scic_sds_request_get_task_context(this_request);
+
+ scu_ssp_reqeust_construct_task_context(this_request, task_context);
+
+ task_context->ssp_command_iu_length = sizeof(struct sci_ssp_command_iu) / sizeof(u32);
+ task_context->type.ssp.frame_type = SCI_SAS_COMMAND_FRAME;
+
+ switch (data_direction) {
+ case SCI_IO_REQUEST_DATA_IN:
+ case SCI_IO_REQUEST_NO_DATA:
+ task_context->task_type = SCU_TASK_TYPE_IOREAD;
+ break;
+ case SCI_IO_REQUEST_DATA_OUT:
+ task_context->task_type = SCU_TASK_TYPE_IOWRITE;
+ break;
+ }
+
+ task_context->transfer_length_bytes = transfer_length_bytes;
+
+ if (task_context->transfer_length_bytes > 0) {
+ scic_sds_request_build_sgl(this_request);
+ }
+}
+
+
+/**
+ * This method will fill in the remainder of the io request object for SSP Task
+ * requests.
+ * @this_request:
+ *
+ */
+static void scic_sds_ssp_task_request_assign_buffers(
+ struct scic_sds_request *this_request)
+{
+ /* Assign all of the buffer pointers */
+ this_request->command_buffer =
+ scic_sds_ssp_task_request_get_command_buffer(this_request);
+ this_request->response_buffer =
+ scic_sds_ssp_task_request_get_response_buffer(this_request);
+ this_request->sgl_element_pair_buffer = NULL;
+
+ if (this_request->was_tag_assigned_by_user == false) {
+ this_request->task_context_buffer =
+ scic_sds_ssp_task_request_get_task_context_buffer(this_request);
+ this_request->task_context_buffer =
+ scic_sds_request_align_task_context_buffer(this_request->task_context_buffer);
+ }
+}
+
+/**
+ * This method will fill in the SCU Task Context for a SSP Task request. The
+ * following important settings are utilized: -# priority ==
+ * SCU_TASK_PRIORITY_HIGH. This ensures that the task request is issued
+ * ahead of other task destined for the same Remote Node. -# task_type ==
+ * SCU_TASK_TYPE_IOREAD. This simply indicates that a normal request type
+ * (i.e. non-raw frame) is being utilized to perform task management. -#
+ * control_frame == 1. This ensures that the proper endianess is set so
+ * that the bytes are transmitted in the right order for a task frame.
+ * @this_request: This parameter specifies the task request object being
+ * constructed.
+ *
+ */
+static void scu_ssp_task_request_construct_task_context(
+ struct scic_sds_request *this_request)
+{
+ struct scu_task_context *task_context;
+
+ task_context = scic_sds_request_get_task_context(this_request);
+
+ scu_ssp_reqeust_construct_task_context(this_request, task_context);
+
+ task_context->control_frame = 1;
+ task_context->priority = SCU_TASK_PRIORITY_HIGH;
+ task_context->task_type = SCU_TASK_TYPE_RAW_FRAME;
+ task_context->transfer_length_bytes = 0;
+ task_context->type.ssp.frame_type = SCI_SAS_TASK_FRAME;
+ task_context->ssp_command_iu_length = sizeof(struct sci_ssp_task_iu) / sizeof(u32);
+}
+
+
+/**
+ * This method constructs the SSP Command IU data for this ssp passthrough
+ * comand request object.
+ * @this_request: This parameter specifies the request object for which the SSP
+ * command information unit is being built.
+ *
+ * enum sci_status, returns invalid parameter is cdb > 16
+ */
+
+
+/**
+ * This method constructs the SATA request object.
+ * @this_request:
+ * @sat_protocol:
+ * @transfer_length:
+ * @data_direction:
+ * @copy_rx_frame:
+ *
+ * enum sci_status
+ */
+static enum sci_status scic_io_request_construct_sata(
+ struct scic_sds_request *this_request,
+ u8 sat_protocol,
+ u32 transfer_length,
+ SCI_IO_REQUEST_DATA_DIRECTION data_direction,
+ bool copy_rx_frame)
+{
+ enum sci_status status = SCI_SUCCESS;
+
+ switch (sat_protocol) {
+ case SAT_PROTOCOL_PIO_DATA_IN:
+ case SAT_PROTOCOL_PIO_DATA_OUT:
+ status = scic_sds_stp_pio_request_construct(this_request, sat_protocol, copy_rx_frame);
+ break;
+
+ case SAT_PROTOCOL_UDMA_DATA_IN:
+ case SAT_PROTOCOL_UDMA_DATA_OUT:
+ status = scic_sds_stp_udma_request_construct(this_request, transfer_length, data_direction);
+ break;
+
+ case SAT_PROTOCOL_ATA_HARD_RESET:
+ case SAT_PROTOCOL_SOFT_RESET:
+ status = scic_sds_stp_soft_reset_request_construct(this_request);
+ break;
+
+ case SAT_PROTOCOL_NON_DATA:
+ status = scic_sds_stp_non_data_request_construct(this_request);
+ break;
+
+ case SAT_PROTOCOL_FPDMA:
+ status = scic_sds_stp_ncq_request_construct(this_request, transfer_length, data_direction);
+ break;
+
+#if !defined(DISABLE_ATAPI)
+ case SAT_PROTOCOL_PACKET_NON_DATA:
+ case SAT_PROTOCOL_PACKET_DMA_DATA_IN:
+ case SAT_PROTOCOL_PACKET_DMA_DATA_OUT:
+ case SAT_PROTOCOL_PACKET_PIO_DATA_IN:
+ case SAT_PROTOCOL_PACKET_PIO_DATA_OUT:
+ status = scic_sds_stp_packet_request_construct(this_request);
+ break;
+#endif
+
+ case SAT_PROTOCOL_DMA_QUEUED:
+ case SAT_PROTOCOL_DMA:
+ case SAT_PROTOCOL_DEVICE_DIAGNOSTIC:
+ case SAT_PROTOCOL_DEVICE_RESET:
+ case SAT_PROTOCOL_RETURN_RESPONSE_INFO:
+ default:
+ dev_err(scic_to_dev(this_request->owning_controller),
+ "%s: SCIC IO Request 0x%p received un-handled "
+ "SAT Protocl %d.\n",
+ __func__, this_request, sat_protocol);
+
+ status = SCI_FAILURE;
+ break;
+ }
+
+ return status;
+}
+
+/*
+ * ****************************************************************************
+ * * SCIC Interface Implementation
+ * **************************************************************************** */
+
+
+
+
+/* --------------------------------------------------------------------------- */
+
+u32 scic_io_request_get_object_size(void)
+{
+ u32 ssp_request_size;
+ u32 stp_request_size;
+ u32 smp_request_size;
+
+ ssp_request_size = scic_sds_ssp_request_get_object_size();
+ stp_request_size = scic_sds_stp_request_get_object_size();
+ smp_request_size = scic_sds_smp_request_get_object_size();
+
+ return max(ssp_request_size, max(stp_request_size, smp_request_size));
+}
+
+/* --------------------------------------------------------------------------- */
+
+
+/* --------------------------------------------------------------------------- */
+
+
+/* --------------------------------------------------------------------------- */
+
+
+/* --------------------------------------------------------------------------- */
+
+enum sci_status scic_io_request_construct(
+ struct scic_sds_controller *scic_controller,
+ struct scic_sds_remote_device *scic_remote_device,
+ u16 io_tag,
+ void *user_io_request_object,
+ void *scic_io_request_memory,
+ struct scic_sds_request **new_scic_io_request_handle)
+{
+ enum sci_status status = SCI_SUCCESS;
+ struct scic_sds_request *this_request;
+ struct smp_discover_response_protocols device_protocol;
+
+ this_request = (struct scic_sds_request *)scic_io_request_memory;
+
+ /* Build the common part of the request */
+ scic_sds_general_request_construct(
+ (struct scic_sds_controller *)scic_controller,
+ (struct scic_sds_remote_device *)scic_remote_device,
+ io_tag,
+ user_io_request_object,
+ this_request
+ );
+
+ if (
+ scic_sds_remote_device_get_index((struct scic_sds_remote_device *)scic_remote_device)
+ == SCIC_SDS_REMOTE_NODE_CONTEXT_INVALID_INDEX
+ ) {
+ return SCI_FAILURE_INVALID_REMOTE_DEVICE;
+ }
+
+ scic_remote_device_get_protocols(scic_remote_device, &device_protocol);
+
+ if (device_protocol.u.bits.attached_ssp_target) {
+ scic_sds_ssp_io_request_assign_buffers(this_request);
+ } else if (device_protocol.u.bits.attached_stp_target) {
+ scic_sds_stp_request_assign_buffers(this_request);
+ memset(this_request->command_buffer, 0, sizeof(struct sata_fis_reg_h2d));
+ } else if (device_protocol.u.bits.attached_smp_target) {
+ scic_sds_smp_request_assign_buffers(this_request);
+ memset(this_request->command_buffer, 0, sizeof(struct smp_request));
+ } else {
+ status = SCI_FAILURE_UNSUPPORTED_PROTOCOL;
+ }
+
+ if (status == SCI_SUCCESS) {
+ memset(
+ this_request->task_context_buffer,
+ 0,
+ SCI_FIELD_OFFSET(struct scu_task_context, sgl_pair_ab)
+ );
+ *new_scic_io_request_handle = scic_io_request_memory;
+ }
+
+ return status;
+}
+
+/* --------------------------------------------------------------------------- */
+
+
+enum sci_status scic_task_request_construct(
+ struct scic_sds_controller *controller,
+ struct scic_sds_remote_device *remote_device,
+ u16 io_tag,
+ void *user_io_request_object,
+ void *scic_task_request_memory,
+ struct scic_sds_request **new_scic_task_request_handle)
+{
+ enum sci_status status = SCI_SUCCESS;
+ struct scic_sds_request *this_request = (struct scic_sds_request *)
+ scic_task_request_memory;
+ struct smp_discover_response_protocols device_protocol;
+
+ /* Build the common part of the request */
+ scic_sds_general_request_construct(
+ (struct scic_sds_controller *)controller,
+ (struct scic_sds_remote_device *)remote_device,
+ io_tag,
+ user_io_request_object,
+ this_request
+ );
+
+ scic_remote_device_get_protocols(remote_device, &device_protocol);
+
+ if (device_protocol.u.bits.attached_ssp_target) {
+ scic_sds_ssp_task_request_assign_buffers(this_request);
+
+ this_request->has_started_substate_machine = true;
+
+ /* Construct the started sub-state machine. */
+ sci_base_state_machine_construct(
+ &this_request->started_substate_machine,
+ &this_request->parent.parent,
+ scic_sds_io_request_started_task_mgmt_substate_table,
+ SCIC_SDS_IO_REQUEST_STARTED_TASK_MGMT_SUBSTATE_AWAIT_TC_COMPLETION
+ );
+ } else if (device_protocol.u.bits.attached_stp_target) {
+ scic_sds_stp_request_assign_buffers(this_request);
+ } else {
+ status = SCI_FAILURE_UNSUPPORTED_PROTOCOL;
+ }
+
+ if (status == SCI_SUCCESS) {
+ this_request->is_task_management_request = true;
+ memset(this_request->task_context_buffer, 0x00, sizeof(struct scu_task_context));
+ *new_scic_task_request_handle = scic_task_request_memory;
+ }
+
+ return status;
+}
+
+
+enum sci_status scic_io_request_construct_basic_ssp(
+ struct scic_sds_request *sci_req)
+{
+ void *os_handle;
+
+ sci_req->protocol = SCIC_SSP_PROTOCOL;
+
+ os_handle = scic_sds_request_get_user_request(sci_req);
+
+ scu_ssp_io_request_construct_task_context(
+ sci_req,
+ scic_cb_io_request_get_data_direction(os_handle),
+ scic_cb_io_request_get_transfer_length(os_handle)
+ );
+
+
+ scic_sds_io_request_build_ssp_command_iu(sci_req);
+
+ sci_base_state_machine_change_state(
+ &sci_req->parent.state_machine,
+ SCI_BASE_REQUEST_STATE_CONSTRUCTED
+ );
+
+ return SCI_SUCCESS;
+}
+
+
+enum sci_status scic_task_request_construct_ssp(
+ struct scic_sds_request *sci_req)
+{
+ /* Construct the SSP Task SCU Task Context */
+ scu_ssp_task_request_construct_task_context(sci_req);
+
+ /* Fill in the SSP Task IU */
+ scic_sds_task_request_build_ssp_task_iu(sci_req);
+
+ sci_base_state_machine_change_state(
+ &sci_req->parent.state_machine,
+ SCI_BASE_REQUEST_STATE_CONSTRUCTED
+ );
+
+ return SCI_SUCCESS;
+}
+
+
+enum sci_status scic_io_request_construct_basic_sata(
+ struct scic_sds_request *sci_req)
+{
+ enum sci_status status;
+ struct scic_sds_stp_request *this_stp_request;
+ u8 sat_protocol;
+ u32 transfer_length;
+ SCI_IO_REQUEST_DATA_DIRECTION data_direction;
+ bool copy_rx_frame = false;
+
+ this_stp_request = (struct scic_sds_stp_request *)sci_req;
+
+ sci_req->protocol = SCIC_STP_PROTOCOL;
+
+ transfer_length =
+ scic_cb_io_request_get_transfer_length(sci_req->user_request);
+ data_direction =
+ scic_cb_io_request_get_data_direction(sci_req->user_request);
+
+ sat_protocol = scic_cb_request_get_sat_protocol(sci_req->user_request);
+ copy_rx_frame = scic_cb_io_request_do_copy_rx_frames(this_stp_request->parent.user_request);
+
+ status = scic_io_request_construct_sata(
+ sci_req,
+ sat_protocol,
+ transfer_length,
+ data_direction,
+ copy_rx_frame
+ );
+
+ if (status == SCI_SUCCESS)
+ sci_base_state_machine_change_state(
+ &sci_req->parent.state_machine,
+ SCI_BASE_REQUEST_STATE_CONSTRUCTED
+ );
+
+ return status;
+}
+
+
+enum sci_status scic_task_request_construct_sata(
+ struct scic_sds_request *sci_req)
+{
+ enum sci_status status;
+ u8 sat_protocol = scic_cb_request_get_sat_protocol(sci_req->user_request);
+
+ switch (sat_protocol) {
+ case SAT_PROTOCOL_ATA_HARD_RESET:
+ case SAT_PROTOCOL_SOFT_RESET:
+ status = scic_sds_stp_soft_reset_request_construct(sci_req);
+ break;
+
+ default:
+ dev_err(scic_to_dev(sci_req->owning_controller),
+ "%s: SCIC IO Request 0x%p received un-handled SAT "
+ "Protocl %d.\n",
+ __func__,
+ sci_req,
+ sat_protocol);
+
+ status = SCI_FAILURE;
+ break;
+ }
+
+ if (status == SCI_SUCCESS)
+ sci_base_state_machine_change_state(
+ &sci_req->parent.state_machine,
+ SCI_BASE_REQUEST_STATE_CONSTRUCTED
+ );
+
+ return status;
+}
+
+
+u16 scic_io_request_get_io_tag(
+ struct scic_sds_request *sci_req)
+{
+ return sci_req->io_tag;
+}
+
+
+u32 scic_request_get_controller_status(
+ struct scic_sds_request *sci_req)
+{
+ return sci_req->scu_status;
+}
+
+
+void *scic_io_request_get_command_iu_address(
+ struct scic_sds_request *sci_req)
+{
+ return sci_req->command_buffer;
+}
+
+
+void *scic_io_request_get_response_iu_address(
+ struct scic_sds_request *sci_req)
+{
+ return sci_req->response_buffer;
+}
+
+
+#define SCU_TASK_CONTEXT_SRAM 0x200000
+u32 scic_io_request_get_number_of_bytes_transferred(
+ struct scic_sds_request *scic_sds_request)
+{
+ u32 ret_val = 0;
+
+ if (SMU_AMR_READ(scic_sds_request->owning_controller) == 0) {
+ /*
+ * get the bytes of data from the Address == BAR1 + 20002Ch + (256*TCi) where
+ * BAR1 is the scu_registers
+ * 0x20002C = 0x200000 + 0x2c
+ * = start of task context SRAM + offset of (type.ssp.data_offset)
+ * TCi is the io_tag of struct scic_sds_request */
+ ret_val = scic_sds_pci_read_scu_dword(
+ scic_sds_request->owning_controller,
+ (
+ (u8 *)scic_sds_request->owning_controller->scu_registers +
+ (SCU_TASK_CONTEXT_SRAM + SCI_FIELD_OFFSET(struct scu_task_context, type.ssp.data_offset)) +
+ ((sizeof(struct scu_task_context)) * scic_sds_io_tag_get_index(scic_sds_request->io_tag))
+ )
+ );
+ }
+
+ return ret_val;
+}
+
+
+/*
+ * ****************************************************************************
+ * * SCIC SDS Interface Implementation
+ * **************************************************************************** */
+
+/**
+ *
+ * @this_request: The SCIC_SDS_IO_REQUEST_T object for which the start
+ * operation is to be executed.
+ *
+ * This method invokes the base state start request handler for the
+ * SCIC_SDS_IO_REQUEST_T object. enum sci_status
+ */
+enum sci_status scic_sds_request_start(
+ struct scic_sds_request *this_request)
+{
+ if (
+ this_request->device_sequence
+ == scic_sds_remote_device_get_sequence(this_request->target_device)
+ ) {
+ return this_request->state_handlers->parent.start_handler(
+ &this_request->parent
+ );
+ }
+
+ return SCI_FAILURE;
+}
+
+/**
+ *
+ * @this_request: The SCIC_SDS_IO_REQUEST_T object for which the start
+ * operation is to be executed.
+ *
+ * This method invokes the base state terminate request handber for the
+ * SCIC_SDS_IO_REQUEST_T object. enum sci_status
+ */
+enum sci_status scic_sds_io_request_terminate(
+ struct scic_sds_request *this_request)
+{
+ return this_request->state_handlers->parent.abort_handler(
+ &this_request->parent);
+}
+
+/**
+ *
+ * @this_request: The SCIC_SDS_IO_REQUEST_T object for which the start
+ * operation is to be executed.
+ *
+ * This method invokes the base state request completion handler for the
+ * SCIC_SDS_IO_REQUEST_T object. enum sci_status
+ */
+enum sci_status scic_sds_io_request_complete(
+ struct scic_sds_request *this_request)
+{
+ return this_request->state_handlers->parent.complete_handler(
+ &this_request->parent);
+}
+
+/**
+ *
+ * @this_request: The SCIC_SDS_IO_REQUEST_T object for which the start
+ * operation is to be executed.
+ * @event_code: The event code returned by the hardware for the task reqeust.
+ *
+ * This method invokes the core state handler for the SCIC_SDS_IO_REQUEST_T
+ * object. enum sci_status
+ */
+enum sci_status scic_sds_io_request_event_handler(
+ struct scic_sds_request *this_request,
+ u32 event_code)
+{
+ return this_request->state_handlers->event_handler(this_request, event_code);
+}
+
+/**
+ *
+ * @this_request: The SCIC_SDS_IO_REQUEST_T object for which the start
+ * operation is to be executed.
+ * @frame_index: The frame index returned by the hardware for the reqeust
+ * object.
+ *
+ * This method invokes the core state frame handler for the
+ * SCIC_SDS_IO_REQUEST_T object. enum sci_status
+ */
+enum sci_status scic_sds_io_request_frame_handler(
+ struct scic_sds_request *this_request,
+ u32 frame_index)
+{
+ return this_request->state_handlers->frame_handler(this_request, frame_index);
+}
+
+/**
+ *
+ * @this_request: The SCIC_SDS_IO_REQUEST_T object for which the task start
+ * operation is to be executed.
+ *
+ * This method invokes the core state task complete handler for the
+ * SCIC_SDS_IO_REQUEST_T object. enum sci_status
+ */
+
+/*
+ * ****************************************************************************
+ * * SCIC SDS PROTECTED METHODS
+ * **************************************************************************** */
+
+/**
+ * This method copies response data for requests returning response data
+ * instead of sense data.
+ * @this_request: This parameter specifies the request object for which to copy
+ * the response data.
+ *
+ */
+void scic_sds_io_request_copy_response(
+ struct scic_sds_request *this_request)
+{
+ void *response_buffer;
+ u32 user_response_length;
+ u32 core_response_length;
+ struct sci_ssp_response_iu *ssp_response;
+
+ ssp_response = (struct sci_ssp_response_iu *)this_request->response_buffer;
+
+ response_buffer = scic_cb_ssp_task_request_get_response_data_address(
+ this_request->user_request
+ );
+
+ user_response_length = scic_cb_ssp_task_request_get_response_data_length(
+ this_request->user_request
+ );
+
+ core_response_length = sci_ssp_get_response_data_length(
+ ssp_response->response_data_length
+ );
+
+ user_response_length = min(user_response_length, core_response_length);
+
+ memcpy(response_buffer, ssp_response->data, user_response_length);
+}
+
+/*
+ * *****************************************************************************
+ * * DEFAULT STATE HANDLERS
+ * ***************************************************************************** */
+
+/**
+ * scic_sds_request_default_start_handler() -
+ * @request: This is the struct sci_base_request object that is cast to the
+ * SCIC_SDS_IO_REQUEST_T object for which the start operation is requested.
+ *
+ * This method is the default action to take when an SCIC_SDS_IO_REQUEST_T
+ * object receives a scic_sds_request_start() request. The default action is
+ * to log a warning and return a failure status. enum sci_status
+ * SCI_FAILURE_INVALID_STATE
+ */
+enum sci_status scic_sds_request_default_start_handler(
+ struct sci_base_request *request)
+{
+ struct scic_sds_request *scic_request =
+ (struct scic_sds_request *)request;
+
+ dev_warn(scic_to_dev(scic_request->owning_controller),
+ "%s: SCIC IO Request requested to start while in wrong "
+ "state %d\n",
+ __func__,
+ sci_base_state_machine_get_state(
+ &((struct scic_sds_request *)request)->parent.state_machine));
+
+ return SCI_FAILURE_INVALID_STATE;
+}
+
+static enum sci_status scic_sds_request_default_abort_handler(
+ struct sci_base_request *request)
+{
+ struct scic_sds_request *scic_request =
+ (struct scic_sds_request *)request;
+
+ dev_warn(scic_to_dev(scic_request->owning_controller),
+ "%s: SCIC IO Request requested to abort while in wrong "
+ "state %d\n",
+ __func__,
+ sci_base_state_machine_get_state(
+ &((struct scic_sds_request *)request)->parent.state_machine));
+
+ return SCI_FAILURE_INVALID_STATE;
+}
+
+/**
+ * scic_sds_request_default_complete_handler() -
+ * @request: This is the struct sci_base_request object that is cast to the
+ * SCIC_SDS_IO_REQUEST_T object for which the start operation is requested.
+ *
+ * This method is the default action to take when an SCIC_SDS_IO_REQUEST_T
+ * object receives a scic_sds_request_complete() request. The default action
+ * is to log a warning and return a failure status. enum sci_status
+ * SCI_FAILURE_INVALID_STATE
+ */
+enum sci_status scic_sds_request_default_complete_handler(
+ struct sci_base_request *request)
+{
+ struct scic_sds_request *scic_request =
+ (struct scic_sds_request *)request;
+
+ dev_warn(scic_to_dev(scic_request->owning_controller),
+ "%s: SCIC IO Request requested to complete while in wrong "
+ "state %d\n",
+ __func__,
+ sci_base_state_machine_get_state(
+ &((struct scic_sds_request *)request)->parent.state_machine));
+
+ return SCI_FAILURE_INVALID_STATE;
+}
+
+/**
+ * scic_sds_request_default_destruct_handler() -
+ * @request: This is the struct sci_base_request object that is cast to the
+ * SCIC_SDS_IO_REQUEST_T object for which the start operation is requested.
+ *
+ * This method is the default action to take when an SCIC_SDS_IO_REQUEST_T
+ * object receives a scic_sds_request_complete() request. The default action
+ * is to log a warning and return a failure status. enum sci_status
+ * SCI_FAILURE_INVALID_STATE
+ */
+enum sci_status scic_sds_request_default_destruct_handler(
+ struct sci_base_request *request)
+{
+ struct scic_sds_request *scic_request =
+ (struct scic_sds_request *)request;
+
+ dev_warn(scic_to_dev(scic_request->owning_controller),
+ "%s: SCIC IO Request requested to destroy while in wrong "
+ "state %d\n",
+ __func__,
+ sci_base_state_machine_get_state(
+ &((struct scic_sds_request *)request)->parent.state_machine));
+
+ return SCI_FAILURE_INVALID_STATE;
+}
+
+/**
+ * scic_sds_request_default_tc_completion_handler() -
+ * @request: This is the struct sci_base_request object that is cast to the
+ * SCIC_SDS_IO_REQUEST_T object for which the start operation is requested.
+ *
+ * This method is the default action to take when an SCIC_SDS_IO_REQUEST_T
+ * object receives a scic_sds_task_request_complete() request. The default
+ * action is to log a warning and return a failure status. enum sci_status
+ * SCI_FAILURE_INVALID_STATE
+ */
+enum sci_status scic_sds_request_default_tc_completion_handler(
+ struct scic_sds_request *this_request,
+ u32 completion_code)
+{
+ dev_warn(scic_to_dev(this_request->owning_controller),
+ "%s: SCIC IO Request given task completion notification %x "
+ "while in wrong state %d\n",
+ __func__,
+ completion_code,
+ sci_base_state_machine_get_state(
+ &this_request->parent.state_machine));
+
+ return SCI_FAILURE_INVALID_STATE;
+
+}
+
+/**
+ * scic_sds_request_default_event_handler() -
+ * @request: This is the struct sci_base_request object that is cast to the
+ * SCIC_SDS_IO_REQUEST_T object for which the start operation is requested.
+ *
+ * This method is the default action to take when an SCIC_SDS_IO_REQUEST_T
+ * object receives a scic_sds_request_event_handler() request. The default
+ * action is to log a warning and return a failure status. enum sci_status
+ * SCI_FAILURE_INVALID_STATE
+ */
+enum sci_status scic_sds_request_default_event_handler(
+ struct scic_sds_request *this_request,
+ u32 event_code)
+{
+ dev_warn(scic_to_dev(this_request->owning_controller),
+ "%s: SCIC IO Request given event code notification %x while "
+ "in wrong state %d\n",
+ __func__,
+ event_code,
+ sci_base_state_machine_get_state(
+ &this_request->parent.state_machine));
+
+ return SCI_FAILURE_INVALID_STATE;
+}
+
+/**
+ * scic_sds_request_default_frame_handler() -
+ * @request: This is the struct sci_base_request object that is cast to the
+ * SCIC_SDS_IO_REQUEST_T object for which the start operation is requested.
+ *
+ * This method is the default action to take when an SCIC_SDS_IO_REQUEST_T
+ * object receives a scic_sds_request_event_handler() request. The default
+ * action is to log a warning and return a failure status. enum sci_status
+ * SCI_FAILURE_INVALID_STATE
+ */
+enum sci_status scic_sds_request_default_frame_handler(
+ struct scic_sds_request *this_request,
+ u32 frame_index)
+{
+ dev_warn(scic_to_dev(this_request->owning_controller),
+ "%s: SCIC IO Request given unexpected frame %x while in "
+ "state %d\n",
+ __func__,
+ frame_index,
+ sci_base_state_machine_get_state(
+ &this_request->parent.state_machine));
+
+ scic_sds_controller_release_frame(
+ this_request->owning_controller, frame_index);
+
+ return SCI_FAILURE_INVALID_STATE;
+}
+
+/*
+ * *****************************************************************************
+ * * CONSTRUCTED STATE HANDLERS
+ * ***************************************************************************** */
+
+/**
+ * scic_sds_request_constructed_state_start_handler() -
+ * @request: This is the struct sci_base_request object that is cast to the
+ * SCIC_SDS_IO_REQUEST_T object for which the start operation is requested.
+ *
+ * This method implements the action taken when a constructed
+ * SCIC_SDS_IO_REQUEST_T object receives a scic_sds_request_start() request.
+ * This method will, if necessary, allocate a TCi for the io request object and
+ * then will, if necessary, copy the constructed TC data into the actual TC
+ * buffer. If everything is successful the post context field is updated with
+ * the TCi so the controller can post the request to the hardware. enum sci_status
+ * SCI_SUCCESS SCI_FAILURE_INSUFFICIENT_RESOURCES
+ */
+static enum sci_status scic_sds_request_constructed_state_start_handler(
+ struct sci_base_request *request)
+{
+ struct scu_task_context *task_context;
+ struct scic_sds_request *this_request = (struct scic_sds_request *)request;
+
+ if (this_request->io_tag == SCI_CONTROLLER_INVALID_IO_TAG) {
+ this_request->io_tag =
+ scic_controller_allocate_io_tag(this_request->owning_controller);
+ }
+
+ /* Record the IO Tag in the request */
+ if (this_request->io_tag != SCI_CONTROLLER_INVALID_IO_TAG) {
+ task_context = this_request->task_context_buffer;
+
+ task_context->task_index = scic_sds_io_tag_get_index(this_request->io_tag);
+
+ switch (task_context->protocol_type) {
+ case SCU_TASK_CONTEXT_PROTOCOL_SMP:
+ case SCU_TASK_CONTEXT_PROTOCOL_SSP:
+ /* SSP/SMP Frame */
+ task_context->type.ssp.tag = this_request->io_tag;
+ task_context->type.ssp.target_port_transfer_tag = 0xFFFF;
+ break;
+
+ case SCU_TASK_CONTEXT_PROTOCOL_STP:
+ /*
+ * STP/SATA Frame
+ * task_context->type.stp.ncq_tag = this_request->ncq_tag; */
+ break;
+
+ case SCU_TASK_CONTEXT_PROTOCOL_NONE:
+ /* / @todo When do we set no protocol type? */
+ break;
+
+ default:
+ /* This should never happen since we build the IO requests */
+ break;
+ }
+
+ /*
+ * Check to see if we need to copy the task context buffer
+ * or have been building into the task context buffer */
+ if (this_request->was_tag_assigned_by_user == false) {
+ scic_sds_controller_copy_task_context(
+ this_request->owning_controller, this_request
+ );
+ }
+
+ /* Add to the post_context the io tag value */
+ this_request->post_context |= scic_sds_io_tag_get_index(this_request->io_tag);
+
+ /* Everything is good go ahead and change state */
+ sci_base_state_machine_change_state(
+ &this_request->parent.state_machine,
+ SCI_BASE_REQUEST_STATE_STARTED
+ );
+
+ return SCI_SUCCESS;
+ }
+
+ return SCI_FAILURE_INSUFFICIENT_RESOURCES;
+}
+
+/**
+ * scic_sds_request_constructed_state_abort_handler() -
+ * @request: This is the struct sci_base_request object that is cast to the
+ * SCIC_SDS_IO_REQUEST_T object for which the start operation is requested.
+ *
+ * This method implements the action to be taken when an SCIC_SDS_IO_REQUEST_T
+ * object receives a scic_sds_request_terminate() request. Since the request
+ * has not yet been posted to the hardware the request transitions to the
+ * completed state. enum sci_status SCI_SUCCESS
+ */
+static enum sci_status scic_sds_request_constructed_state_abort_handler(
+ struct sci_base_request *request)
+{
+ struct scic_sds_request *this_request = (struct scic_sds_request *)request;
+
+ /*
+ * This request has been terminated by the user make sure that the correct
+ * status code is returned */
+ scic_sds_request_set_status(
+ this_request,
+ SCU_TASK_DONE_TASK_ABORT,
+ SCI_FAILURE_IO_TERMINATED
+ );
+
+ sci_base_state_machine_change_state(
+ &this_request->parent.state_machine,
+ SCI_BASE_REQUEST_STATE_COMPLETED
+ );
+
+ return SCI_SUCCESS;
+}
+
+/*
+ * *****************************************************************************
+ * * STARTED STATE HANDLERS
+ * ***************************************************************************** */
+
+/**
+ * scic_sds_request_started_state_abort_handler() -
+ * @request: This is the struct sci_base_request object that is cast to the
+ * SCIC_SDS_IO_REQUEST_T object for which the start operation is requested.
+ *
+ * This method implements the action to be taken when an SCIC_SDS_IO_REQUEST_T
+ * object receives a scic_sds_request_terminate() request. Since the request
+ * has been posted to the hardware the io request state is changed to the
+ * aborting state. enum sci_status SCI_SUCCESS
+ */
+enum sci_status scic_sds_request_started_state_abort_handler(
+ struct sci_base_request *request)
+{
+ struct scic_sds_request *this_request = (struct scic_sds_request *)request;
+
+ if (this_request->has_started_substate_machine) {
+ sci_base_state_machine_stop(&this_request->started_substate_machine);
+ }
+
+ sci_base_state_machine_change_state(
+ &this_request->parent.state_machine,
+ SCI_BASE_REQUEST_STATE_ABORTING
+ );
+
+ return SCI_SUCCESS;
+}
+
+/**
+ * scic_sds_request_started_state_tc_completion_handler() - This method process
+ * TC (task context) completions for normal IO request (i.e. Task/Abort
+ * Completions of type 0). This method will update the
+ * SCIC_SDS_IO_REQUEST_T::status field.
+ * @this_request: This parameter specifies the request for which a completion
+ * occurred.
+ * @completion_code: This parameter specifies the completion code received from
+ * the SCU.
+ *
+ */
+enum sci_status scic_sds_request_started_state_tc_completion_handler(
+ struct scic_sds_request *this_request,
+ u32 completion_code)
+{
+ u8 data_present;
+ struct sci_ssp_response_iu *response_buffer;
+
+ /**
+ * @todo Any SDMA return code of other than 0 is bad
+ * decode 0x003C0000 to determine SDMA status
+ */
+ switch (SCU_GET_COMPLETION_TL_STATUS(completion_code)) {
+ case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_GOOD):
+ scic_sds_request_set_status(
+ this_request, SCU_TASK_DONE_GOOD, SCI_SUCCESS
+ );
+ break;
+
+ case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_EARLY_RESP):
+ {
+ /*
+ * There are times when the SCU hardware will return an early response
+ * because the io request specified more data than is returned by the
+ * target device (mode pages, inquiry data, etc.). We must check the
+ * response stats to see if this is truly a failed request or a good
+ * request that just got completed early. */
+ struct sci_ssp_response_iu *response = (struct sci_ssp_response_iu *)
+ this_request->response_buffer;
+ scic_word_copy_with_swap(
+ this_request->response_buffer,
+ this_request->response_buffer,
+ sizeof(struct sci_ssp_response_iu) / sizeof(u32)
+ );
+
+ if (response->status == 0) {
+ scic_sds_request_set_status(
+ this_request, SCU_TASK_DONE_GOOD, SCI_SUCCESS_IO_DONE_EARLY
+ );
+ } else {
+ scic_sds_request_set_status(
+ this_request,
+ SCU_TASK_DONE_CHECK_RESPONSE,
+ SCI_FAILURE_IO_RESPONSE_VALID
+ );
+ }
+ }
+ break;
+
+ case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_CHECK_RESPONSE):
+ scic_word_copy_with_swap(
+ this_request->response_buffer,
+ this_request->response_buffer,
+ sizeof(struct sci_ssp_response_iu) / sizeof(u32)
+ );
+
+ scic_sds_request_set_status(
+ this_request,
+ SCU_TASK_DONE_CHECK_RESPONSE,
+ SCI_FAILURE_IO_RESPONSE_VALID
+ );
+ break;
+
+ case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_RESP_LEN_ERR):
+ /*
+ * / @todo With TASK_DONE_RESP_LEN_ERR is the response frame guaranteed
+ * / to be received before this completion status is posted? */
+ response_buffer =
+ (struct sci_ssp_response_iu *)this_request->response_buffer;
+ data_present =
+ response_buffer->data_present & SCI_SSP_RESPONSE_IU_DATA_PRESENT_MASK;
+
+ if ((data_present == 0x01) || (data_present == 0x02)) {
+ scic_sds_request_set_status(
+ this_request,
+ SCU_TASK_DONE_CHECK_RESPONSE,
+ SCI_FAILURE_IO_RESPONSE_VALID
+ );
+ } else {
+ scic_sds_request_set_status(
+ this_request, SCU_TASK_DONE_GOOD, SCI_SUCCESS
+ );
+ }
+ break;
+
+ /* only stp device gets suspended. */
+ case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_ACK_NAK_TO):
+ case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_LL_PERR):
+ case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_NAK_ERR):
+ case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_DATA_LEN_ERR):
+ case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_LL_ABORT_ERR):
+ case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_XR_WD_LEN):
+ case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_MAX_PLD_ERR):
+ case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_UNEXP_RESP):
+ case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_UNEXP_SDBFIS):
+ case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_REG_ERR):
+ case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_SDB_ERR):
+ if (this_request->protocol == SCIC_STP_PROTOCOL) {
+ scic_sds_request_set_status(
+ this_request,
+ SCU_GET_COMPLETION_TL_STATUS(completion_code) >> SCU_COMPLETION_TL_STATUS_SHIFT,
+ SCI_FAILURE_REMOTE_DEVICE_RESET_REQUIRED
+ );
+ } else {
+ scic_sds_request_set_status(
+ this_request,
+ SCU_GET_COMPLETION_TL_STATUS(completion_code) >> SCU_COMPLETION_TL_STATUS_SHIFT,
+ SCI_FAILURE_CONTROLLER_SPECIFIC_IO_ERR
+ );
+ }
+ break;
+
+ /* both stp/ssp device gets suspended */
+ case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_LF_ERR):
+ case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_OPEN_REJECT_WRONG_DESTINATION):
+ case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_OPEN_REJECT_RESERVED_ABANDON_1):
+ case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_OPEN_REJECT_RESERVED_ABANDON_2):
+ case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_OPEN_REJECT_RESERVED_ABANDON_3):
+ case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_OPEN_REJECT_BAD_DESTINATION):
+ case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_OPEN_REJECT_ZONE_VIOLATION):
+ case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_OPEN_REJECT_STP_RESOURCES_BUSY):
+ case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_OPEN_REJECT_PROTOCOL_NOT_SUPPORTED):
+ case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_OPEN_REJECT_CONNECTION_RATE_NOT_SUPPORTED):
+ scic_sds_request_set_status(
+ this_request,
+ SCU_GET_COMPLETION_TL_STATUS(completion_code) >> SCU_COMPLETION_TL_STATUS_SHIFT,
+ SCI_FAILURE_REMOTE_DEVICE_RESET_REQUIRED
+ );
+ break;
+
+ /* neither ssp nor stp gets suspended. */
+ case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_NAK_CMD_ERR):
+ case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_UNEXP_XR):
+ case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_XR_IU_LEN_ERR):
+ case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_SDMA_ERR):
+ case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_OFFSET_ERR):
+ case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_EXCESS_DATA):
+ case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_SMP_RESP_TO_ERR):
+ case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_SMP_UFI_ERR):
+ case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_SMP_FRM_TYPE_ERR):
+ case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_SMP_LL_RX_ERR):
+ case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_UNEXP_DATA):
+ case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_OPEN_FAIL):
+ case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_VIIT_ENTRY_NV):
+ case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_IIT_ENTRY_NV):
+ case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_RNCNV_OUTBOUND):
+ default:
+ scic_sds_request_set_status(
+ this_request,
+ SCU_GET_COMPLETION_TL_STATUS(completion_code) >> SCU_COMPLETION_TL_STATUS_SHIFT,
+ SCI_FAILURE_CONTROLLER_SPECIFIC_IO_ERR
+ );
+ break;
+ }
+
+ /**
+ * @todo This is probably wrong for ACK/NAK timeout conditions
+ */
+
+ /* In all cases we will treat this as the completion of the IO request. */
+ sci_base_state_machine_change_state(
+ &this_request->parent.state_machine,
+ SCI_BASE_REQUEST_STATE_COMPLETED
+ );
+
+ return SCI_SUCCESS;
+}
+
+/**
+ * scic_sds_request_started_state_frame_handler() -
+ * @request: This is the struct sci_base_request object that is cast to the
+ * SCIC_SDS_IO_REQUEST_T object for which the start operation is requested.
+ * @frame_index: This is the index of the unsolicited frame to be processed.
+ *
+ * This method implements the action to be taken when an SCIC_SDS_IO_REQUEST_T
+ * object receives a scic_sds_request_frame_handler() request. This method
+ * first determines the frame type received. If this is a response frame then
+ * the response data is copied to the io request response buffer for processing
+ * at completion time. If the frame type is not a response buffer an error is
+ * logged. enum sci_status SCI_SUCCESS SCI_FAILURE_INVALID_PARAMETER_VALUE
+ */
+static enum sci_status scic_sds_request_started_state_frame_handler(
+ struct scic_sds_request *this_request,
+ u32 frame_index)
+{
+ enum sci_status status;
+ struct sci_ssp_frame_header *frame_header;
+
+ /* / @todo If this is a response frame we must record that we received it */
+ status = scic_sds_unsolicited_frame_control_get_header(
+ &(scic_sds_request_get_controller(this_request)->uf_control),
+ frame_index,
+ (void **)&frame_header
+ );
+
+ if (frame_header->frame_type == SCI_SAS_RESPONSE_FRAME) {
+ struct sci_ssp_response_iu *response_buffer;
+
+ status = scic_sds_unsolicited_frame_control_get_buffer(
+ &(scic_sds_request_get_controller(this_request)->uf_control),
+ frame_index,
+ (void **)&response_buffer
+ );
+
+ scic_word_copy_with_swap(
+ this_request->response_buffer,
+ (u32 *)response_buffer,
+ sizeof(struct sci_ssp_response_iu)
+ );
+
+ response_buffer = (struct sci_ssp_response_iu *)this_request->response_buffer;
+
+ if ((response_buffer->data_present == 0x01) ||
+ (response_buffer->data_present == 0x02)) {
+ scic_sds_request_set_status(
+ this_request,
+ SCU_TASK_DONE_CHECK_RESPONSE,
+ SCI_FAILURE_CONTROLLER_SPECIFIC_IO_ERR
+ );
+ } else
+ scic_sds_request_set_status(
+ this_request, SCU_TASK_DONE_GOOD, SCI_SUCCESS
+ );
+ } else
+ /* This was not a response frame why did it get forwarded? */
+ dev_err(scic_to_dev(this_request->owning_controller),
+ "%s: SCIC IO Request 0x%p received unexpected "
+ "frame %d type 0x%02x\n",
+ __func__,
+ this_request,
+ frame_index,
+ frame_header->frame_type);
+
+ /*
+ * In any case we are done with this frame buffer return it to the
+ * controller */
+ scic_sds_controller_release_frame(
+ this_request->owning_controller, frame_index
+ );
+
+ return SCI_SUCCESS;
+}
+
+/*
+ * *****************************************************************************
+ * * COMPLETED STATE HANDLERS
+ * ***************************************************************************** */
+
+
+/**
+ * scic_sds_request_completed_state_complete_handler() -
+ * @request: This is the struct sci_base_request object that is cast to the
+ * SCIC_SDS_IO_REQUEST_T object for which the start operation is requested.
+ *
+ * This method implements the action to be taken when an SCIC_SDS_IO_REQUEST_T
+ * object receives a scic_sds_request_complete() request. This method frees up
+ * any io request resources that have been allocated and transitions the
+ * request to its final state. Consider stopping the state machine instead of
+ * transitioning to the final state? enum sci_status SCI_SUCCESS
+ */
+static enum sci_status scic_sds_request_completed_state_complete_handler(
+ struct sci_base_request *request)
+{
+ struct scic_sds_request *this_request = (struct scic_sds_request *)request;
+
+ if (this_request->was_tag_assigned_by_user != true) {
+ scic_controller_free_io_tag(
+ this_request->owning_controller, this_request->io_tag
+ );
+ }
+
+ if (this_request->saved_rx_frame_index != SCU_INVALID_FRAME_INDEX) {
+ scic_sds_controller_release_frame(
+ this_request->owning_controller, this_request->saved_rx_frame_index);
+ }
+
+ sci_base_state_machine_change_state(
+ &this_request->parent.state_machine,
+ SCI_BASE_REQUEST_STATE_FINAL
+ );
+
+ return SCI_SUCCESS;
+}
+
+/*
+ * *****************************************************************************
+ * * ABORTING STATE HANDLERS
+ * ***************************************************************************** */
+
+/**
+ * scic_sds_request_aborting_state_abort_handler() -
+ * @request: This is the struct sci_base_request object that is cast to the
+ * SCIC_SDS_IO_REQUEST_T object for which the start operation is requested.
+ *
+ * This method implements the action to be taken when an SCIC_SDS_IO_REQUEST_T
+ * object receives a scic_sds_request_terminate() request. This method is the
+ * io request aborting state abort handlers. On receipt of a multiple
+ * terminate requests the io request will transition to the completed state.
+ * This should not happen in normal operation. enum sci_status SCI_SUCCESS
+ */
+static enum sci_status scic_sds_request_aborting_state_abort_handler(
+ struct sci_base_request *request)
+{
+ struct scic_sds_request *this_request = (struct scic_sds_request *)request;
+
+ sci_base_state_machine_change_state(
+ &this_request->parent.state_machine,
+ SCI_BASE_REQUEST_STATE_COMPLETED
+ );
+
+ return SCI_SUCCESS;
+}
+
+/**
+ * scic_sds_request_aborting_state_tc_completion_handler() -
+ * @request: This is the struct sci_base_request object that is cast to the
+ * SCIC_SDS_IO_REQUEST_T object for which the start operation is requested.
+ *
+ * This method implements the action to be taken when an SCIC_SDS_IO_REQUEST_T
+ * object receives a scic_sds_request_task_completion() request. This method
+ * decodes the completion type waiting for the abort task complete
+ * notification. When the abort task complete is received the io request
+ * transitions to the completed state. enum sci_status SCI_SUCCESS
+ */
+static enum sci_status scic_sds_request_aborting_state_tc_completion_handler(
+ struct scic_sds_request *this_request,
+ u32 completion_code)
+{
+ switch (SCU_GET_COMPLETION_TL_STATUS(completion_code)) {
+ case (SCU_TASK_DONE_GOOD << SCU_COMPLETION_TL_STATUS_SHIFT):
+ case (SCU_TASK_DONE_TASK_ABORT << SCU_COMPLETION_TL_STATUS_SHIFT):
+ scic_sds_request_set_status(
+ this_request, SCU_TASK_DONE_TASK_ABORT, SCI_FAILURE_IO_TERMINATED
+ );
+
+ sci_base_state_machine_change_state(
+ &this_request->parent.state_machine,
+ SCI_BASE_REQUEST_STATE_COMPLETED
+ );
+ break;
+
+ default:
+ /*
+ * Unless we get some strange error wait for the task abort to complete
+ * TODO: Should there be a state change for this completion? */
+ break;
+ }
+
+ return SCI_SUCCESS;
+}
+
+/**
+ * scic_sds_request_aborting_state_frame_handler() -
+ * @request: This is the struct sci_base_request object that is cast to the
+ * SCIC_SDS_IO_REQUEST_T object for which the start operation is requested.
+ *
+ * This method implements the action to be taken when an SCIC_SDS_IO_REQUEST_T
+ * object receives a scic_sds_request_frame_handler() request. This method
+ * discards the unsolicited frame since we are waiting for the abort task
+ * completion. enum sci_status SCI_SUCCESS
+ */
+static enum sci_status scic_sds_request_aborting_state_frame_handler(
+ struct scic_sds_request *this_request,
+ u32 frame_index)
+{
+ /* TODO: Is it even possible to get an unsolicited frame in the aborting state? */
+
+ scic_sds_controller_release_frame(
+ this_request->owning_controller, frame_index);
+
+ return SCI_SUCCESS;
+}
+
+/* --------------------------------------------------------------------------- */
+
+const struct scic_sds_io_request_state_handler scic_sds_request_state_handler_table[] = {
+ [SCI_BASE_REQUEST_STATE_INITIAL] = {
+ .parent.start_handler = scic_sds_request_default_start_handler,
+ .parent.abort_handler = scic_sds_request_default_abort_handler,
+ .parent.complete_handler = scic_sds_request_default_complete_handler,
+ .parent.destruct_handler = scic_sds_request_default_destruct_handler,
+ .tc_completion_handler = scic_sds_request_default_tc_completion_handler,
+ .event_handler = scic_sds_request_default_event_handler,
+ .frame_handler = scic_sds_request_default_frame_handler,
+ },
+ [SCI_BASE_REQUEST_STATE_CONSTRUCTED] = {
+ .parent.start_handler = scic_sds_request_constructed_state_start_handler,
+ .parent.abort_handler = scic_sds_request_constructed_state_abort_handler,
+ .parent.complete_handler = scic_sds_request_default_complete_handler,
+ .parent.destruct_handler = scic_sds_request_default_destruct_handler,
+ .tc_completion_handler = scic_sds_request_default_tc_completion_handler,
+ .event_handler = scic_sds_request_default_event_handler,
+ .frame_handler = scic_sds_request_default_frame_handler,
+ },
+ [SCI_BASE_REQUEST_STATE_STARTED] = {
+ .parent.start_handler = scic_sds_request_default_start_handler,
+ .parent.abort_handler = scic_sds_request_started_state_abort_handler,
+ .parent.complete_handler = scic_sds_request_default_complete_handler,
+ .parent.destruct_handler = scic_sds_request_default_destruct_handler,
+ .tc_completion_handler = scic_sds_request_started_state_tc_completion_handler,
+ .event_handler = scic_sds_request_default_event_handler,
+ .frame_handler = scic_sds_request_started_state_frame_handler,
+ },
+ [SCI_BASE_REQUEST_STATE_COMPLETED] = {
+ .parent.start_handler = scic_sds_request_default_start_handler,
+ .parent.abort_handler = scic_sds_request_default_abort_handler,
+ .parent.complete_handler = scic_sds_request_completed_state_complete_handler,
+ .parent.destruct_handler = scic_sds_request_default_destruct_handler,
+ .tc_completion_handler = scic_sds_request_default_tc_completion_handler,
+ .event_handler = scic_sds_request_default_event_handler,
+ .frame_handler = scic_sds_request_default_frame_handler,
+ },
+ [SCI_BASE_REQUEST_STATE_ABORTING] = {
+ .parent.start_handler = scic_sds_request_default_start_handler,
+ .parent.abort_handler = scic_sds_request_aborting_state_abort_handler,
+ .parent.complete_handler = scic_sds_request_default_complete_handler,
+ .parent.destruct_handler = scic_sds_request_default_destruct_handler,
+ .tc_completion_handler = scic_sds_request_aborting_state_tc_completion_handler,
+ .event_handler = scic_sds_request_default_event_handler,
+ .frame_handler = scic_sds_request_aborting_state_frame_handler,
+ },
+ [SCI_BASE_REQUEST_STATE_FINAL] = {
+ .parent.start_handler = scic_sds_request_default_start_handler,
+ .parent.abort_handler = scic_sds_request_default_abort_handler,
+ .parent.complete_handler = scic_sds_request_default_complete_handler,
+ .parent.destruct_handler = scic_sds_request_default_destruct_handler,
+ .tc_completion_handler = scic_sds_request_default_tc_completion_handler,
+ .event_handler = scic_sds_request_default_event_handler,
+ .frame_handler = scic_sds_request_default_frame_handler,
+ },
+};
+
+/**
+ * scic_sds_request_initial_state_enter() -
+ * @object: This parameter specifies the base object for which the state
+ * transition is occurring.
+ *
+ * This method implements the actions taken when entering the
+ * SCI_BASE_REQUEST_STATE_INITIAL state. This state is entered when the initial
+ * base request is constructed. Entry into the initial state sets all handlers
+ * for the io request object to their default handlers. none
+ */
+static void scic_sds_request_initial_state_enter(
+ struct sci_base_object *object)
+{
+ struct scic_sds_request *this_request = (struct scic_sds_request *)object;
+
+ SET_STATE_HANDLER(
+ this_request,
+ scic_sds_request_state_handler_table,
+ SCI_BASE_REQUEST_STATE_INITIAL
+ );
+}
+
+/**
+ * scic_sds_request_constructed_state_enter() -
+ * @object: The io request object that is to enter the constructed state.
+ *
+ * This method implements the actions taken when entering the
+ * SCI_BASE_REQUEST_STATE_CONSTRUCTED state. The method sets the state handlers
+ * for the the constructed state. none
+ */
+static void scic_sds_request_constructed_state_enter(
+ struct sci_base_object *object)
+{
+ struct scic_sds_request *this_request = (struct scic_sds_request *)object;
+
+ SET_STATE_HANDLER(
+ this_request,
+ scic_sds_request_state_handler_table,
+ SCI_BASE_REQUEST_STATE_CONSTRUCTED
+ );
+}
+
+/**
+ * scic_sds_request_started_state_enter() -
+ * @object: This parameter specifies the base object for which the state
+ * transition is occuring. This is cast into a SCIC_SDS_IO_REQUEST object.
+ *
+ * This method implements the actions taken when entering the
+ * SCI_BASE_REQUEST_STATE_STARTED state. If the io request object type is a
+ * SCSI Task request we must enter the started substate machine. none
+ */
+static void scic_sds_request_started_state_enter(
+ struct sci_base_object *object)
+{
+ struct scic_sds_request *this_request = (struct scic_sds_request *)object;
+
+ SET_STATE_HANDLER(
+ this_request,
+ scic_sds_request_state_handler_table,
+ SCI_BASE_REQUEST_STATE_STARTED
+ );
+
+ /*
+ * Most of the request state machines have a started substate machine so
+ * start its execution on the entry to the started state. */
+ if (this_request->has_started_substate_machine == true)
+ sci_base_state_machine_start(&this_request->started_substate_machine);
+}
+
+/**
+ * scic_sds_request_started_state_exit() -
+ * @object: This parameter specifies the base object for which the state
+ * transition is occuring. This object is cast into a SCIC_SDS_IO_REQUEST
+ * object.
+ *
+ * This method implements the actions taken when exiting the
+ * SCI_BASE_REQUEST_STATE_STARTED state. For task requests the action will be
+ * to stop the started substate machine. none
+ */
+static void scic_sds_request_started_state_exit(
+ struct sci_base_object *object)
+{
+ struct scic_sds_request *this_request = (struct scic_sds_request *)object;
+
+ if (this_request->has_started_substate_machine == true)
+ sci_base_state_machine_stop(&this_request->started_substate_machine);
+}
+
+/**
+ * scic_sds_request_completed_state_enter() -
+ * @object: This parameter specifies the base object for which the state
+ * transition is occuring. This object is cast into a SCIC_SDS_IO_REQUEST
+ * object.
+ *
+ * This method implements the actions taken when entering the
+ * SCI_BASE_REQUEST_STATE_COMPLETED state. This state is entered when the
+ * SCIC_SDS_IO_REQUEST has completed. The method will decode the request
+ * completion status and convert it to an enum sci_status to return in the
+ * completion callback function. none
+ */
+static void scic_sds_request_completed_state_enter(
+ struct sci_base_object *object)
+{
+ struct scic_sds_request *this_request = (struct scic_sds_request *)object;
+
+ SET_STATE_HANDLER(
+ this_request,
+ scic_sds_request_state_handler_table,
+ SCI_BASE_REQUEST_STATE_COMPLETED
+ );
+
+ /* Tell the SCI_USER that the IO request is complete */
+ if (this_request->is_task_management_request == false) {
+ scic_cb_io_request_complete(
+ scic_sds_request_get_controller(this_request),
+ scic_sds_request_get_device(this_request),
+ this_request,
+ this_request->sci_status
+ );
+ } else {
+ scic_cb_task_request_complete(
+ scic_sds_request_get_controller(this_request),
+ scic_sds_request_get_device(this_request),
+ this_request,
+ this_request->sci_status
+ );
+ }
+}
+
+/**
+ * scic_sds_request_aborting_state_enter() -
+ * @object: This parameter specifies the base object for which the state
+ * transition is occuring. This object is cast into a SCIC_SDS_IO_REQUEST
+ * object.
+ *
+ * This method implements the actions taken when entering the
+ * SCI_BASE_REQUEST_STATE_ABORTING state. none
+ */
+static void scic_sds_request_aborting_state_enter(
+ struct sci_base_object *object)
+{
+ struct scic_sds_request *this_request = (struct scic_sds_request *)object;
+
+ /* Setting the abort bit in the Task Context is required by the silicon. */
+ this_request->task_context_buffer->abort = 1;
+
+ SET_STATE_HANDLER(
+ this_request,
+ scic_sds_request_state_handler_table,
+ SCI_BASE_REQUEST_STATE_ABORTING
+ );
+}
+
+/**
+ * scic_sds_request_final_state_enter() -
+ * @object: This parameter specifies the base object for which the state
+ * transition is occuring. This is cast into a SCIC_SDS_IO_REQUEST object.
+ *
+ * This method implements the actions taken when entering the
+ * SCI_BASE_REQUEST_STATE_FINAL state. The only action required is to put the
+ * state handlers in place. none
+ */
+static void scic_sds_request_final_state_enter(
+ struct sci_base_object *object)
+{
+ struct scic_sds_request *this_request = (struct scic_sds_request *)object;
+
+ SET_STATE_HANDLER(
+ this_request,
+ scic_sds_request_state_handler_table,
+ SCI_BASE_REQUEST_STATE_FINAL
+ );
+}
+
+/* --------------------------------------------------------------------------- */
+
+const struct sci_base_state scic_sds_request_state_table[] = {
+ [SCI_BASE_REQUEST_STATE_INITIAL] = {
+ .enter_state = scic_sds_request_initial_state_enter,
+ },
+ [SCI_BASE_REQUEST_STATE_CONSTRUCTED] = {
+ .enter_state = scic_sds_request_constructed_state_enter,
+ },
+ [SCI_BASE_REQUEST_STATE_STARTED] = {
+ .enter_state = scic_sds_request_started_state_enter,
+ .exit_state = scic_sds_request_started_state_exit
+ },
+ [SCI_BASE_REQUEST_STATE_COMPLETED] = {
+ .enter_state = scic_sds_request_completed_state_enter,
+ },
+ [SCI_BASE_REQUEST_STATE_ABORTING] = {
+ .enter_state = scic_sds_request_aborting_state_enter,
+ },
+ [SCI_BASE_REQUEST_STATE_FINAL] = {
+ .enter_state = scic_sds_request_final_state_enter,
+ },
+};
+
diff --git a/drivers/scsi/isci/core/scic_sds_request.h b/drivers/scsi/isci/core/scic_sds_request.h
new file mode 100644
index 000000000000..0691a7552a2a
--- /dev/null
+++ b/drivers/scsi/isci/core/scic_sds_request.h
@@ -0,0 +1,484 @@
+/*
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Intel Corporation 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
+ * OWNER 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.
+ */
+
+#ifndef _SCIC_SDS_IO_REQUEST_H_
+#define _SCIC_SDS_IO_REQUEST_H_
+
+/**
+ * This file contains the structures, constants and prototypes for the
+ * SCIC_SDS_IO_REQUEST object.
+ *
+ *
+ */
+
+#include "scic_io_request.h"
+
+#include "sci_base_request.h"
+#include "scu_task_context.h"
+#include "intel_sas.h"
+
+struct scic_sds_controller;
+struct scic_sds_remote_device;
+struct scic_sds_io_request_state_handler;
+
+/**
+ * enum _SCIC_SDS_IO_REQUEST_STARTED_TASK_MGMT_SUBSTATES - This enumeration
+ * depicts all of the substates for a task management request to be
+ * performed in the STARTED super-state.
+ *
+ *
+ */
+enum scic_sds_raw_request_started_task_mgmt_substates {
+ /**
+ * The AWAIT_TC_COMPLETION sub-state indicates that the started raw
+ * task management request is waiting for the transmission of the
+ * initial frame (i.e. command, task, etc.).
+ */
+ SCIC_SDS_IO_REQUEST_STARTED_TASK_MGMT_SUBSTATE_AWAIT_TC_COMPLETION,
+
+ /**
+ * This sub-state indicates that the started task management request
+ * is waiting for the reception of an unsolicited frame
+ * (i.e. response IU).
+ */
+ SCIC_SDS_IO_REQUEST_STARTED_TASK_MGMT_SUBSTATE_AWAIT_TC_RESPONSE,
+};
+
+
+/**
+ * enum _SCIC_SDS_SMP_REQUEST_STARTED_SUBSTATES - This enumeration depicts all
+ * of the substates for a SMP request to be performed in the STARTED
+ * super-state.
+ *
+ *
+ */
+enum scic_sds_smp_request_started_substates {
+ /**
+ * This sub-state indicates that the started task management request
+ * is waiting for the reception of an unsolicited frame
+ * (i.e. response IU).
+ */
+ SCIC_SDS_SMP_REQUEST_STARTED_SUBSTATE_AWAIT_RESPONSE,
+
+ /**
+ * The AWAIT_TC_COMPLETION sub-state indicates that the started SMP request is
+ * waiting for the transmission of the initial frame (i.e. command, task, etc.).
+ */
+ SCIC_SDS_SMP_REQUEST_STARTED_SUBSTATE_AWAIT_TC_COMPLETION,
+};
+
+/**
+ * struct SCIC_SDS_IO_REQUEST - This structure contains or references all of
+ * the data necessary to process a task management or normal IO request.
+ *
+ *
+ */
+struct scic_sds_request {
+ /**
+ * This field indictes the parent object of the request.
+ */
+ struct sci_base_request parent;
+
+ void *user_request;
+
+ /**
+ * This field simply points to the controller to which this IO request
+ * is associated.
+ */
+ struct scic_sds_controller *owning_controller;
+
+ /**
+ * This field simply points to the remote device to which this IO request
+ * is associated.
+ */
+ struct scic_sds_remote_device *target_device;
+
+ /**
+ * This field is utilized to determine if the SCI user is managing
+ * the IO tag for this request or if the core is managing it.
+ */
+ bool was_tag_assigned_by_user;
+
+ /**
+ * This field indicates the IO tag for this request. The IO tag is
+ * comprised of the task_index and a sequence count. The sequence count
+ * is utilized to help identify tasks from one life to another.
+ */
+ u16 io_tag;
+
+ /**
+ * This field specifies the protocol being utilized for this
+ * IO request.
+ */
+ SCIC_TRANSPORT_PROTOCOL protocol;
+
+ /**
+ * This field indicates the completion status taken from the SCUs
+ * completion code. It indicates the completion result for the SCU hardware.
+ */
+ u32 scu_status;
+
+ /**
+ * This field indicates the completion status returned to the SCI user. It
+ * indicates the users view of the io request completion.
+ */
+ u32 sci_status;
+
+ /**
+ * This field contains the value to be utilized when posting (e.g. Post_TC,
+ * Post_TC_Abort) this request to the silicon.
+ */
+ u32 post_context;
+
+ void *command_buffer;
+ void *response_buffer;
+ struct scu_task_context *task_context_buffer;
+ struct scu_sgl_element_pair *sgl_element_pair_buffer;
+
+ /**
+ * This field indicates if this request is a task management request or
+ * normal IO request.
+ */
+ bool is_task_management_request;
+
+ /**
+ * This field indicates that this request contains an initialized started
+ * substate machine.
+ */
+ bool has_started_substate_machine;
+
+ /**
+ * This field is a pointer to the stored rx frame data. It is used in STP
+ * internal requests and SMP response frames. If this field is non-NULL the
+ * saved frame must be released on IO request completion.
+ *
+ * @todo In the future do we want to keep a list of RX frame buffers?
+ */
+ u32 saved_rx_frame_index;
+
+ /**
+ * This field specifies the data necessary to manage the sub-state
+ * machine executed while in the SCI_BASE_REQUEST_STATE_STARTED state.
+ */
+ struct sci_base_state_machine started_substate_machine;
+
+ /**
+ * This field specifies the current state handlers in place for this
+ * IO Request object. This field is updated each time the request
+ * changes state.
+ */
+ const struct scic_sds_io_request_state_handler *state_handlers;
+
+ /**
+ * This field in the recorded device sequence for the io request. This is
+ * recorded during the build operation and is compared in the start
+ * operation. If the sequence is different then there was a change of
+ * devices from the build to start operations.
+ */
+ u8 device_sequence;
+
+};
+
+
+typedef enum sci_status
+(*scic_sds_io_request_frame_handler_t)(struct scic_sds_request *req, u32 frame);
+
+typedef enum sci_status
+(*scic_sds_io_request_event_handler_t)(struct scic_sds_request *req, u32 event);
+
+typedef enum sci_status
+(*scic_sds_io_request_task_completion_handler_t)(struct scic_sds_request *req, u32 completion_code);
+
+/**
+ * struct scic_sds_io_request_state_handler - This is the SDS core definition
+ * of the state handlers.
+ *
+ *
+ */
+struct scic_sds_io_request_state_handler {
+ struct sci_base_request_state_handler parent;
+
+ scic_sds_io_request_task_completion_handler_t tc_completion_handler;
+ scic_sds_io_request_event_handler_t event_handler;
+ scic_sds_io_request_frame_handler_t frame_handler;
+
+};
+
+extern const struct sci_base_state scic_sds_request_state_table[];
+extern const struct scic_sds_io_request_state_handler scic_sds_request_state_handler_table[];
+
+extern const struct sci_base_state scic_sds_io_request_started_task_mgmt_substate_table[];
+extern const struct scic_sds_io_request_state_handler scic_sds_ssp_task_request_started_substate_handler_table[];
+
+extern const struct sci_base_state scic_sds_smp_request_started_substate_table[];
+extern const struct scic_sds_io_request_state_handler scic_sds_smp_request_started_substate_handler_table[];
+
+/**
+ *
+ *
+ * This macro returns the maximum number of SGL element paris that we will
+ * support in a single IO request.
+ */
+#define SCU_MAX_SGL_ELEMENT_PAIRS ((SCU_IO_REQUEST_SGE_COUNT + 1) / 2)
+
+/**
+ * scic_sds_request_get_controller() -
+ *
+ * This macro will return the controller for this io request object
+ */
+#define scic_sds_request_get_controller(this_request) \
+ ((this_request)->owning_controller)
+
+/**
+ * scic_sds_request_get_device() -
+ *
+ * This macro will return the device for this io request object
+ */
+#define scic_sds_request_get_device(this_request) \
+ ((this_request)->target_device)
+
+/**
+ * scic_sds_request_get_port() -
+ *
+ * This macro will return the port for this io request object
+ */
+#define scic_sds_request_get_port(this_request) \
+ scic_sds_remote_device_get_port(scic_sds_request_get_device(this_request))
+
+/**
+ * scic_sds_request_get_post_context() -
+ *
+ * This macro returns the constructed post context result for the io request.
+ */
+#define scic_sds_request_get_post_context(this_request) \
+ ((this_request)->post_context)
+
+/**
+ * scic_sds_request_get_task_context() -
+ *
+ * This is a helper macro to return the os handle for this request object.
+ */
+#define scic_sds_request_get_task_context(request) \
+ ((request)->task_context_buffer)
+
+#define CACHE_LINE_SIZE (64)
+#define scic_sds_request_align_task_context_buffer(address) \
+ ((struct scu_task_context *)(\
+ (((unsigned long)(address)) + (CACHE_LINE_SIZE - 1)) \
+ & ~(CACHE_LINE_SIZE - 1) \
+ ))
+
+/**
+ * scic_sds_request_align_sgl_element_buffer() -
+ *
+ * This macro will align the memory address so that it is correct for the SCU
+ * hardware to DMA the SGL element pairs.
+ */
+#define scic_sds_request_align_sgl_element_buffer(address) \
+ ((struct scu_sgl_element_pair *)(\
+ ((char *)(address)) \
+ + (\
+ ((~(unsigned long)(address)) + 1) \
+ & (sizeof(struct scu_sgl_element_pair) - 1) \
+ ) \
+ ))
+
+/**
+ * scic_sds_request_set_status() -
+ *
+ * This macro will set the scu hardware status and sci request completion
+ * status for an io request.
+ */
+#define scic_sds_request_set_status(request, scu_status_code, sci_status_code) \
+ { \
+ (request)->scu_status = (scu_status_code); \
+ (request)->sci_status = (sci_status_code); \
+ }
+
+#define scic_sds_request_complete(a_request) \
+ ((a_request)->state_handlers->parent.complete_handler(&(a_request)->parent))
+
+
+
+
+/**
+ * scic_sds_io_request_tc_completion() -
+ *
+ * This macro invokes the core state task completion handler for the
+ * SCIC_SDS_IO_REQUEST_T object.
+ */
+#define scic_sds_io_request_tc_completion(this_request, completion_code) \
+ { \
+ if (this_request->parent.state_machine.current_state_id \
+ == SCI_BASE_REQUEST_STATE_STARTED \
+ && this_request->has_started_substate_machine \
+ == false) \
+ scic_sds_request_started_state_tc_completion_handler(this_request, completion_code); \
+ else \
+ this_request->state_handlers->tc_completion_handler(this_request, completion_code); \
+ }
+
+/**
+ * SCU_SGL_ZERO() -
+ *
+ * This macro zeros the hardware SGL element data
+ */
+#define SCU_SGL_ZERO(scu_sge) \
+ { \
+ (scu_sge).length = 0; \
+ (scu_sge).address_lower = 0; \
+ (scu_sge).address_upper = 0; \
+ (scu_sge).address_modifier = 0; \
+ }
+
+/**
+ * SCU_SGL_COPY() -
+ *
+ * This macro copys the SGL Element data from the host os to the hardware SGL
+ * elment data
+ */
+#define SCU_SGL_COPY(os_handle, scu_sge, os_sge) \
+ { \
+ (scu_sge).length = \
+ scic_cb_sge_get_length_field(os_handle, os_sge); \
+ (scu_sge).address_upper = \
+ upper_32_bits(scic_cb_sge_get_address_field(os_handle, os_sge)); \
+ (scu_sge).address_lower = \
+ lower_32_bits(scic_cb_sge_get_address_field(os_handle, os_sge)); \
+ (scu_sge).address_modifier = 0; \
+ }
+
+/*
+ * *****************************************************************************
+ * * CORE REQUEST PROTOTYPES
+ * ***************************************************************************** */
+
+void scic_sds_request_build_sgl(
+ struct scic_sds_request *this_request);
+
+
+
+void scic_sds_stp_request_assign_buffers(
+ struct scic_sds_request *this_request);
+
+void scic_sds_smp_request_assign_buffers(
+ struct scic_sds_request *this_request);
+
+/* --------------------------------------------------------------------------- */
+
+enum sci_status scic_sds_request_start(
+ struct scic_sds_request *this_request);
+
+enum sci_status scic_sds_io_request_terminate(
+ struct scic_sds_request *this_request);
+
+enum sci_status scic_sds_io_request_complete(
+ struct scic_sds_request *this_request);
+
+void scic_sds_io_request_copy_response(
+ struct scic_sds_request *this_request);
+
+enum sci_status scic_sds_io_request_event_handler(
+ struct scic_sds_request *this_request,
+ u32 event_code);
+
+enum sci_status scic_sds_io_request_frame_handler(
+ struct scic_sds_request *this_request,
+ u32 frame_index);
+
+
+enum sci_status scic_sds_task_request_terminate(
+ struct scic_sds_request *this_request);
+
+/*
+ * *****************************************************************************
+ * * DEFAULT STATE HANDLERS
+ * ***************************************************************************** */
+
+enum sci_status scic_sds_request_default_start_handler(
+ struct sci_base_request *this_request);
+
+
+enum sci_status scic_sds_request_default_complete_handler(
+ struct sci_base_request *this_request);
+
+enum sci_status scic_sds_request_default_destruct_handler(
+ struct sci_base_request *this_request);
+
+enum sci_status scic_sds_request_default_tc_completion_handler(
+ struct scic_sds_request *this_request,
+ u32 completion_code);
+
+enum sci_status scic_sds_request_default_event_handler(
+ struct scic_sds_request *this_request,
+ u32 event_code);
+
+enum sci_status scic_sds_request_default_frame_handler(
+ struct scic_sds_request *this_request,
+ u32 frame_index);
+
+/*
+ * *****************************************************************************
+ * * STARTED STATE HANDLERS
+ * ***************************************************************************** */
+
+enum sci_status scic_sds_request_started_state_abort_handler(
+ struct sci_base_request *this_request);
+
+enum sci_status scic_sds_request_started_state_tc_completion_handler(
+ struct scic_sds_request *this_request,
+ u32 completion_code);
+
+#endif /* _SCIC_SDS_IO_REQUEST_H_ */
diff --git a/drivers/scsi/isci/core/scic_sds_smp_remote_device.c b/drivers/scsi/isci/core/scic_sds_smp_remote_device.c
new file mode 100644
index 000000000000..7cf78d3212cc
--- /dev/null
+++ b/drivers/scsi/isci/core/scic_sds_smp_remote_device.c
@@ -0,0 +1,410 @@
+/*
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Intel Corporation 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
+ * OWNER 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.
+ */
+
+/**
+ * This file contains This file contains the ready substate handlers for a SMP
+ * device.
+ *
+ *
+ */
+
+#include "sci_environment.h"
+#include "scic_user_callback.h"
+#include "scic_sds_remote_device.h"
+#include "scic_sds_controller.h"
+#include "scic_sds_port.h"
+#include "scic_sds_request.h"
+#include "scu_event_codes.h"
+#include "scu_task_context.h"
+
+
+/*
+ * *****************************************************************************
+ * * SMP REMOTE DEVICE READY IDLE SUBSTATE HANDLERS
+ * ***************************************************************************** */
+
+/**
+ *
+ * @[in]: device The device the io is sent to.
+ * @[in]: request The io to start.
+ *
+ * This method will handle the start io operation for a SMP device that is in
+ * the idle state. enum sci_status
+ */
+static enum sci_status scic_sds_smp_remote_device_ready_idle_substate_start_io_handler(
+ struct sci_base_remote_device *device,
+ struct sci_base_request *request)
+{
+ enum sci_status status;
+ struct scic_sds_remote_device *this_device = (struct scic_sds_remote_device *)device;
+ struct scic_sds_request *io_request = (struct scic_sds_request *)request;
+
+ /* Will the port allow the io request to start? */
+ status = this_device->owning_port->state_handlers->start_io_handler(
+ this_device->owning_port,
+ this_device,
+ io_request
+ );
+
+ if (status == SCI_SUCCESS) {
+ status =
+ scic_sds_remote_node_context_start_io(this_device->rnc, io_request);
+
+ if (status == SCI_SUCCESS) {
+ status = scic_sds_request_start(io_request);
+ }
+
+ if (status == SCI_SUCCESS) {
+ this_device->working_request = io_request;
+
+ sci_base_state_machine_change_state(
+ &this_device->ready_substate_machine,
+ SCIC_SDS_SMP_REMOTE_DEVICE_READY_SUBSTATE_CMD
+ );
+ }
+
+ scic_sds_remote_device_start_request(this_device, io_request, status);
+ }
+
+ return status;
+}
+
+
+/*
+ * ******************************************************************************
+ * * SMP REMOTE DEVICE READY SUBSTATE CMD HANDLERS
+ * ****************************************************************************** */
+/**
+ *
+ * @device: This is the device object that is receiving the IO.
+ * @request: The io to start.
+ *
+ * This device is already handling a command it can not accept new commands
+ * until this one is complete. enum sci_status
+ */
+static enum sci_status scic_sds_smp_remote_device_ready_cmd_substate_start_io_handler(
+ struct sci_base_remote_device *device,
+ struct sci_base_request *request)
+{
+ return SCI_FAILURE_INVALID_STATE;
+}
+
+
+/**
+ * this is the complete_io_handler for smp device at ready cmd substate.
+ * @device: This is the device object that is receiving the IO.
+ * @request: The io to start.
+ *
+ * enum sci_status
+ */
+static enum sci_status scic_sds_smp_remote_device_ready_cmd_substate_complete_io_handler(
+ struct sci_base_remote_device *device,
+ struct sci_base_request *request)
+{
+ enum sci_status status;
+ struct scic_sds_remote_device *this_device;
+ struct scic_sds_request *the_request;
+
+ this_device = (struct scic_sds_remote_device *)device;
+ the_request = (struct scic_sds_request *)request;
+
+ status = scic_sds_io_request_complete(the_request);
+
+ if (status == SCI_SUCCESS) {
+ status = scic_sds_port_complete_io(
+ this_device->owning_port, this_device, the_request);
+
+ if (status == SCI_SUCCESS) {
+ scic_sds_remote_device_decrement_request_count(this_device);
+ sci_base_state_machine_change_state(
+ &this_device->ready_substate_machine,
+ SCIC_SDS_SMP_REMOTE_DEVICE_READY_SUBSTATE_IDLE
+ );
+ } else
+ dev_err(scirdev_to_dev(this_device),
+ "%s: SCIC SDS Remote Device 0x%p io request "
+ "0x%p could not be completd on the port 0x%p "
+ "failed with status %d.\n",
+ __func__,
+ this_device,
+ the_request,
+ this_device->owning_port,
+ status);
+ }
+
+ return status;
+}
+
+/**
+ * This is frame handler for smp device ready cmd substate.
+ * @this_device: This is the device object that is receiving the frame.
+ * @frame_index: The index for the frame received.
+ *
+ * enum sci_status
+ */
+static enum sci_status scic_sds_smp_remote_device_ready_cmd_substate_frame_handler(
+ struct scic_sds_remote_device *this_device,
+ u32 frame_index)
+{
+ enum sci_status status;
+
+ /*
+ * / The device does not process any UF received from the hardware while
+ * / in this state. All unsolicited frames are forwarded to the io request
+ * / object. */
+ status = scic_sds_io_request_frame_handler(
+ this_device->working_request,
+ frame_index
+ );
+
+ return status;
+}
+
+/* --------------------------------------------------------------------------- */
+
+struct scic_sds_remote_device_state_handler
+scic_sds_smp_remote_device_ready_substate_handler_table[
+ SCIC_SDS_SMP_REMOTE_DEVICE_READY_MAX_SUBSTATES] =
+{
+ /* SCIC_SDS_SMP_REMOTE_DEVICE_READY_SUBSTATE_IDLE */
+ {
+ {
+ scic_sds_remote_device_default_start_handler,
+ scic_sds_remote_device_ready_state_stop_handler,
+ scic_sds_remote_device_default_fail_handler,
+ scic_sds_remote_device_default_destruct_handler,
+ scic_sds_remote_device_default_reset_handler,
+ scic_sds_remote_device_default_reset_complete_handler,
+ scic_sds_smp_remote_device_ready_idle_substate_start_io_handler,
+ scic_sds_remote_device_default_complete_request_handler,
+ scic_sds_remote_device_default_continue_request_handler,
+ scic_sds_remote_device_default_start_request_handler,
+ scic_sds_remote_device_default_complete_request_handler
+ },
+ scic_sds_remote_device_default_suspend_handler,
+ scic_sds_remote_device_default_resume_handler,
+ scic_sds_remote_device_general_event_handler,
+ scic_sds_remote_device_default_frame_handler
+ },
+ /* SCIC_SDS_SMP_REMOTE_DEVICE_READY_SUBSTATE_CMD */
+ {
+ {
+ scic_sds_remote_device_default_start_handler,
+ scic_sds_remote_device_ready_state_stop_handler,
+ scic_sds_remote_device_default_fail_handler,
+ scic_sds_remote_device_default_destruct_handler,
+ scic_sds_remote_device_default_reset_handler,
+ scic_sds_remote_device_default_reset_complete_handler,
+ scic_sds_smp_remote_device_ready_cmd_substate_start_io_handler,
+ scic_sds_smp_remote_device_ready_cmd_substate_complete_io_handler,
+ scic_sds_remote_device_default_continue_request_handler,
+ scic_sds_remote_device_default_start_request_handler,
+ scic_sds_remote_device_default_complete_request_handler
+ },
+ scic_sds_remote_device_default_suspend_handler,
+ scic_sds_remote_device_default_resume_handler,
+ scic_sds_remote_device_general_event_handler,
+ scic_sds_smp_remote_device_ready_cmd_substate_frame_handler
+ }
+};
+/*
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Intel Corporation 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
+ * OWNER 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.
+ */
+
+/**
+ * This file contains the enter and exit functions for the
+ * struct scic_sds_remote_device ready substate machine.
+ *
+ *
+ */
+
+#include "scic_remote_device.h"
+#include "scic_user_callback.h"
+#include "scic_sds_remote_device.h"
+#include "scic_sds_controller.h"
+#include "scic_sds_port.h"
+#include "sci_util.h"
+#include "sci_environment.h"
+
+/**
+ *
+ * @object: This is the struct sci_base_object which is cast into a
+ * struct scic_sds_remote_device.
+ *
+ * This is the SCIC_SDS_SMP_REMOTE_DEVICE_READY_SUBSTATE_IDLE enter method.
+ * This method sets the ready cmd substate handlers and reports the device as
+ * ready. none
+ */
+static void scic_sds_smp_remote_device_ready_idle_substate_enter(
+ struct sci_base_object *object)
+{
+ struct scic_sds_remote_device *this_device = (struct scic_sds_remote_device *)object;
+
+ SET_STATE_HANDLER(
+ this_device,
+ scic_sds_smp_remote_device_ready_substate_handler_table,
+ SCIC_SDS_SMP_REMOTE_DEVICE_READY_SUBSTATE_IDLE
+ );
+
+ scic_cb_remote_device_ready(
+ scic_sds_remote_device_get_controller(this_device), this_device);
+}
+
+/**
+ *
+ * @object: This is the struct sci_base_object which is cast into a
+ * struct scic_sds_remote_device.
+ *
+ * This is the SCIC_SDS_SMP_REMOTE_DEVICE_READY_SUBSTATE_CMD enter method. This
+ * method sets the remote device objects ready cmd substate handlers, and
+ * notify core user that the device is not ready. none
+ */
+static void scic_sds_smp_remote_device_ready_cmd_substate_enter(
+ struct sci_base_object *object)
+{
+ struct scic_sds_remote_device *this_device = (struct scic_sds_remote_device *)object;
+
+ BUG_ON(this_device->working_request == NULL);
+
+ SET_STATE_HANDLER(
+ this_device,
+ scic_sds_smp_remote_device_ready_substate_handler_table,
+ SCIC_SDS_SMP_REMOTE_DEVICE_READY_SUBSTATE_CMD
+ );
+
+ scic_cb_remote_device_not_ready(
+ scic_sds_remote_device_get_controller(this_device),
+ this_device,
+ SCIC_REMOTE_DEVICE_NOT_READY_SMP_REQUEST_STARTED
+ );
+}
+
+/**
+ *
+ * @object: This is the struct sci_base_object which is cast into a
+ * struct scic_sds_remote_device.
+ *
+ * This is the SCIC_SDS_SSP_REMOTE_DEVICE_READY_SUBSTATE_CMD exit method. none
+ */
+static void scic_sds_smp_remote_device_ready_cmd_substate_exit(
+ struct sci_base_object *object)
+{
+ struct scic_sds_remote_device *this_device = (struct scic_sds_remote_device *)object;
+
+ this_device->working_request = NULL;
+}
+
+/* --------------------------------------------------------------------------- */
+
+const struct sci_base_state scic_sds_smp_remote_device_ready_substate_table[] = {
+ [SCIC_SDS_SMP_REMOTE_DEVICE_READY_SUBSTATE_IDLE] = {
+ .enter_state = scic_sds_smp_remote_device_ready_idle_substate_enter,
+ },
+ [SCIC_SDS_SMP_REMOTE_DEVICE_READY_SUBSTATE_CMD] = {
+ .enter_state = scic_sds_smp_remote_device_ready_cmd_substate_enter,
+ .exit_state = scic_sds_smp_remote_device_ready_cmd_substate_exit,
+ },
+};
diff --git a/drivers/scsi/isci/core/scic_sds_smp_request.c b/drivers/scsi/isci/core/scic_sds_smp_request.c
new file mode 100644
index 000000000000..949d23e7452a
--- /dev/null
+++ b/drivers/scsi/isci/core/scic_sds_smp_request.c
@@ -0,0 +1,669 @@
+/*
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Intel Corporation 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
+ * OWNER 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.
+ */
+
+#include "intel_sas.h"
+#include "sci_base_state_machine.h"
+#include "scic_controller.h"
+#include "scic_remote_device.h"
+#include "scic_sds_controller.h"
+#include "scic_sds_remote_device.h"
+#include "scic_sds_request.h"
+#include "scic_sds_smp_request.h"
+#include "sci_environment.h"
+#include "sci_util.h"
+#include "scu_completion_codes.h"
+#include "scu_task_context.h"
+
+static void scu_smp_request_construct_task_context(
+ struct scic_sds_request *this_request,
+ struct smp_request *smp_request);
+
+/**
+ *
+ *
+ * This method return the memory space required for STP PIO requests. u32
+ */
+u32 scic_sds_smp_request_get_object_size(void)
+{
+ return sizeof(struct scic_sds_request)
+ + sizeof(struct smp_request)
+ + sizeof(struct smp_response)
+ + sizeof(struct scu_task_context);
+}
+
+/**
+ * scic_sds_smp_request_get_command_buffer() -
+ *
+ * This macro returns the address of the smp command buffer in the smp request
+ * memory. No need to cast to SMP request type.
+ */
+#define scic_sds_smp_request_get_command_buffer(memory) \
+ (((char *)(memory)) + sizeof(struct scic_sds_request))
+
+/**
+ * scic_sds_smp_request_get_response_buffer() -
+ *
+ * This macro returns the address of the smp response buffer in the smp request
+ * memory.
+ */
+#define scic_sds_smp_request_get_response_buffer(memory) \
+ (((char *)(scic_sds_smp_request_get_command_buffer(memory))) \
+ + sizeof(struct smp_request))
+
+/**
+ * scic_sds_smp_request_get_task_context_buffer() -
+ *
+ * This macro returs the task context buffer for the SMP request.
+ */
+#define scic_sds_smp_request_get_task_context_buffer(memory) \
+ ((struct scu_task_context *)(\
+ ((char *)(scic_sds_smp_request_get_response_buffer(memory))) \
+ + sizeof(struct smp_response) \
+ ))
+
+
+
+/**
+ * This method build the remainder of the IO request object.
+ * @this_request: This parameter specifies the request object being constructed.
+ *
+ * The scic_sds_general_request_construct() must be called before this call is
+ * valid. none
+ */
+
+void scic_sds_smp_request_assign_buffers(
+ struct scic_sds_request *this_request)
+{
+ /* Assign all of the buffer pointers */
+ this_request->command_buffer =
+ scic_sds_smp_request_get_command_buffer(this_request);
+ this_request->response_buffer =
+ scic_sds_smp_request_get_response_buffer(this_request);
+ this_request->sgl_element_pair_buffer = NULL;
+
+ if (this_request->was_tag_assigned_by_user == false) {
+ this_request->task_context_buffer =
+ scic_sds_smp_request_get_task_context_buffer(this_request);
+ this_request->task_context_buffer =
+ scic_sds_request_align_task_context_buffer(this_request->task_context_buffer);
+ }
+
+}
+/**
+ * This method is called by the SCI user to build an SMP IO request.
+ *
+ * - The user must have previously called scic_io_request_construct() on the
+ * supplied IO request. Indicate if the controller successfully built the IO
+ * request. SCI_SUCCESS This value is returned if the IO request was
+ * successfully built. SCI_FAILURE_UNSUPPORTED_PROTOCOL This value is returned
+ * if the remote_device does not support the SMP protocol.
+ * SCI_FAILURE_INVALID_ASSOCIATION This value is returned if the user did not
+ * properly set the association between the SCIC IO request and the user's IO
+ * request. Please refer to the sci_object_set_association() routine for more
+ * information.
+ */
+enum sci_status scic_io_request_construct_smp(
+ struct scic_sds_request *sci_req)
+{
+ struct smp_request *smp_req = kmalloc(sizeof(*smp_req), GFP_KERNEL);
+
+ if (!smp_req)
+ return SCI_FAILURE_INSUFFICIENT_RESOURCES;
+
+ sci_req->protocol = SCIC_SMP_PROTOCOL;
+ sci_req->has_started_substate_machine = true;
+
+ /* Construct the started sub-state machine. */
+ sci_base_state_machine_construct(
+ &sci_req->started_substate_machine,
+ &sci_req->parent.parent,
+ scic_sds_smp_request_started_substate_table,
+ SCIC_SDS_SMP_REQUEST_STARTED_SUBSTATE_AWAIT_RESPONSE
+ );
+
+ /* Construct the SMP SCU Task Context */
+ memcpy(smp_req, sci_req->command_buffer, sizeof(*smp_req));
+
+ /*
+ * Look at the SMP requests' header fields; for certain SAS 1.x SMP
+ * functions under SAS 2.0, a zero request length really indicates
+ * a non-zero default length. */
+ if (smp_req->header.request_length == 0) {
+ switch (smp_req->header.function) {
+ case SMP_FUNCTION_DISCOVER:
+ case SMP_FUNCTION_REPORT_PHY_ERROR_LOG:
+ case SMP_FUNCTION_REPORT_PHY_SATA:
+ case SMP_FUNCTION_REPORT_ROUTE_INFORMATION:
+ smp_req->header.request_length = 2;
+ break;
+ case SMP_FUNCTION_CONFIGURE_ROUTE_INFORMATION:
+ case SMP_FUNCTION_PHY_CONTROL:
+ case SMP_FUNCTION_PHY_TEST:
+ smp_req->header.request_length = 9;
+ break;
+ /* Default - zero is a valid default for 2.0. */
+ }
+ }
+
+ scu_smp_request_construct_task_context(sci_req, smp_req);
+
+ sci_base_state_machine_change_state(
+ &sci_req->parent.state_machine,
+ SCI_BASE_REQUEST_STATE_CONSTRUCTED
+ );
+
+ kfree(smp_req);
+
+ return SCI_SUCCESS;
+}
+
+/**
+ * This method is called by the SCI user to build an SMP pass-through IO
+ * request.
+ * @scic_smp_request: This parameter specifies the handle to the io request
+ * object to be built.
+ * @passthru_cb: This parameter specifies the pointer to the callback structure
+ * that contains the function pointers
+ *
+ * - The user must have previously called scic_io_request_construct() on the
+ * supplied IO request. Indicate if the controller successfully built the IO
+ * request.
+ */
+
+/**
+ * This method will fill in the SCU Task Context for a SMP request. The
+ * following important settings are utilized: -# task_type ==
+ * SCU_TASK_TYPE_SMP. This simply indicates that a normal request type
+ * (i.e. non-raw frame) is being utilized to perform task management. -#
+ * control_frame == 1. This ensures that the proper endianess is set so
+ * that the bytes are transmitted in the right order for a smp request frame.
+ * @this_request: This parameter specifies the smp request object being
+ * constructed.
+ *
+ */
+static void scu_smp_request_construct_task_context(
+ struct scic_sds_request *this_request,
+ struct smp_request *smp_request)
+{
+ dma_addr_t physical_address;
+ struct scic_sds_controller *owning_controller;
+ struct scic_sds_remote_device *target_device;
+ struct scic_sds_port *target_port;
+ struct scu_task_context *task_context;
+
+ /* byte swap the smp request. */
+ scic_word_copy_with_swap(
+ this_request->command_buffer,
+ (u32 *)smp_request,
+ sizeof(struct smp_request) / sizeof(u32)
+ );
+
+ task_context = scic_sds_request_get_task_context(this_request);
+
+ owning_controller = scic_sds_request_get_controller(this_request);
+ target_device = scic_sds_request_get_device(this_request);
+ target_port = scic_sds_request_get_port(this_request);
+
+ /*
+ * Fill in the TC with the its required data
+ * 00h */
+ task_context->priority = 0;
+ task_context->initiator_request = 1;
+ task_context->connection_rate =
+ scic_remote_device_get_connection_rate(target_device);
+ task_context->protocol_engine_index =
+ scic_sds_controller_get_protocol_engine_group(owning_controller);
+ task_context->logical_port_index =
+ scic_sds_port_get_index(target_port);
+ task_context->protocol_type = SCU_TASK_CONTEXT_PROTOCOL_SMP;
+ task_context->abort = 0;
+ task_context->valid = SCU_TASK_CONTEXT_VALID;
+ task_context->context_type = SCU_TASK_CONTEXT_TYPE;
+
+ /* 04h */
+ task_context->remote_node_index = this_request->target_device->rnc->remote_node_index;
+ task_context->command_code = 0;
+ task_context->task_type = SCU_TASK_TYPE_SMP_REQUEST;
+
+ /* 08h */
+ task_context->link_layer_control = 0;
+ task_context->do_not_dma_ssp_good_response = 1;
+ task_context->strict_ordering = 0;
+ task_context->control_frame = 1;
+ task_context->timeout_enable = 0;
+ task_context->block_guard_enable = 0;
+
+ /* 0ch */
+ task_context->address_modifier = 0;
+
+ /* 10h */
+ task_context->ssp_command_iu_length = smp_request->header.request_length;
+
+ /* 14h */
+ task_context->transfer_length_bytes = 0;
+
+ /*
+ * 18h ~ 30h, protocol specific
+ * since commandIU has been build by framework at this point, we just
+ * copy the frist DWord from command IU to this location. */
+ memcpy((void *)(&task_context->type.smp), this_request->command_buffer, sizeof(u32));
+
+ /*
+ * 40h
+ * "For SMP you could program it to zero. We would prefer that way so that
+ * done code will be consistent." - Venki */
+ task_context->task_phase = 0;
+
+ if (this_request->was_tag_assigned_by_user) {
+ /* Build the task context now since we have already read the data */
+ this_request->post_context = (
+ SCU_CONTEXT_COMMAND_REQUEST_TYPE_POST_TC
+ | (
+ scic_sds_controller_get_protocol_engine_group(owning_controller)
+ << SCU_CONTEXT_COMMAND_PROTOCOL_ENGINE_GROUP_SHIFT
+ )
+ | (
+ scic_sds_port_get_index(target_port)
+ << SCU_CONTEXT_COMMAND_LOGICAL_PORT_SHIFT
+ )
+ | scic_sds_io_tag_get_index(this_request->io_tag)
+ );
+ } else {
+ /* Build the task context now since we have already read the data */
+ this_request->post_context = (
+ SCU_CONTEXT_COMMAND_REQUEST_TYPE_POST_TC
+ | (
+ scic_sds_controller_get_protocol_engine_group(owning_controller)
+ << SCU_CONTEXT_COMMAND_PROTOCOL_ENGINE_GROUP_SHIFT
+ )
+ | (
+ scic_sds_port_get_index(target_port)
+ << SCU_CONTEXT_COMMAND_LOGICAL_PORT_SHIFT
+ )
+ /* This is not assigned because we have to wait until we get a TCi */
+ );
+ }
+
+ /*
+ * Copy the physical address for the command buffer to the SCU Task Context
+ * command buffer should not contain command header. */
+ scic_cb_io_request_get_physical_address(
+ scic_sds_request_get_controller(this_request),
+ this_request,
+ ((char *)(this_request->command_buffer) + sizeof(u32)),
+ &physical_address
+ );
+
+ task_context->command_iu_upper =
+ upper_32_bits(physical_address);
+ task_context->command_iu_lower =
+ lower_32_bits(physical_address);
+
+
+ /* SMP response comes as UF, so no need to set response IU address. */
+ task_context->response_iu_upper = 0;
+ task_context->response_iu_lower = 0;
+}
+
+/**
+ * This method processes an unsolicited frame while the SMP request is waiting
+ * for a response frame. It will copy the response data, release the
+ * unsolicited frame, and transition the request to the
+ * SCI_BASE_REQUEST_STATE_COMPLETED state.
+ * @this_request: This parameter specifies the request for which the
+ * unsolicited frame was received.
+ * @frame_index: This parameter indicates the unsolicited frame index that
+ * should contain the response.
+ *
+ * This method returns an indication of whether the response frame was handled
+ * successfully or not. SCI_SUCCESS Currently this value is always returned and
+ * indicates successful processing of the TC response.
+ */
+static enum sci_status scic_sds_smp_request_await_response_frame_handler(
+ struct scic_sds_request *this_request,
+ u32 frame_index)
+{
+ enum sci_status status;
+ void *frame_header;
+ struct smp_response_header *this_frame_header;
+ u8 *user_smp_buffer = this_request->response_buffer;
+
+ status = scic_sds_unsolicited_frame_control_get_header(
+ &(scic_sds_request_get_controller(this_request)->uf_control),
+ frame_index,
+ &frame_header
+ );
+
+ /* byte swap the header. */
+ scic_word_copy_with_swap(
+ (u32 *)user_smp_buffer,
+ frame_header,
+ sizeof(struct smp_response_header) / sizeof(u32)
+ );
+ this_frame_header = (struct smp_response_header *)user_smp_buffer;
+
+ if (this_frame_header->smp_frame_type == SMP_FRAME_TYPE_RESPONSE) {
+ void *smp_response_buffer;
+
+ status = scic_sds_unsolicited_frame_control_get_buffer(
+ &(scic_sds_request_get_controller(this_request)->uf_control),
+ frame_index,
+ &smp_response_buffer
+ );
+
+ scic_word_copy_with_swap(
+ (u32 *)(user_smp_buffer + sizeof(struct smp_response_header)),
+ smp_response_buffer,
+ sizeof(union smp_response_body) / sizeof(u32)
+ );
+ if (this_frame_header->function == SMP_FUNCTION_DISCOVER) {
+ struct smp_response *this_smp_response;
+
+ this_smp_response = (struct smp_response *)user_smp_buffer;
+
+ /*
+ * Some expanders only report an attached SATA device, and
+ * not an STP target. Since the core depends on the STP
+ * target attribute to correctly build I/O, set the bit now
+ * if necessary. */
+ if (this_smp_response->response.discover.protocols.u.bits.attached_sata_device
+ && !this_smp_response->response.discover.protocols.u.bits.attached_stp_target) {
+ this_smp_response->response.discover.protocols.u.bits.attached_stp_target = 1;
+
+ dev_dbg(scic_to_dev(this_request->owning_controller),
+ "%s: scic_sds_smp_request_await_response_frame_handler(0x%p) Found SATA dev, setting STP bit.\n",
+ __func__, this_request);
+ }
+ }
+
+ /*
+ * Don't need to copy to user space. User instead will refer to
+ * core request's response buffer. */
+
+ /*
+ * copy the smp response to framework smp request's response buffer.
+ * scic_sds_smp_request_copy_response(this_request); */
+
+ scic_sds_request_set_status(
+ this_request, SCU_TASK_DONE_GOOD, SCI_SUCCESS
+ );
+
+ sci_base_state_machine_change_state(
+ &this_request->started_substate_machine,
+ SCIC_SDS_SMP_REQUEST_STARTED_SUBSTATE_AWAIT_TC_COMPLETION
+ );
+ } else {
+ /* This was not a response frame why did it get forwarded? */
+ dev_err(scic_to_dev(this_request->owning_controller),
+ "%s: SCIC SMP Request 0x%p received unexpected frame "
+ "%d type 0x%02x\n",
+ __func__,
+ this_request,
+ frame_index,
+ this_frame_header->smp_frame_type);
+
+ scic_sds_request_set_status(
+ this_request,
+ SCU_TASK_DONE_SMP_FRM_TYPE_ERR,
+ SCI_FAILURE_CONTROLLER_SPECIFIC_IO_ERR
+ );
+
+ sci_base_state_machine_change_state(
+ &this_request->parent.state_machine,
+ SCI_BASE_REQUEST_STATE_COMPLETED
+ );
+ }
+
+ scic_sds_controller_release_frame(
+ this_request->owning_controller, frame_index
+ );
+
+ return SCI_SUCCESS;
+}
+
+
+/**
+ * This method processes an abnormal TC completion while the SMP request is
+ * waiting for a response frame. It decides what happened to the IO based
+ * on TC completion status.
+ * @this_request: This parameter specifies the request for which the TC
+ * completion was received.
+ * @completion_code: This parameter indicates the completion status information
+ * for the TC.
+ *
+ * Indicate if the tc completion handler was successful. SCI_SUCCESS currently
+ * this method always returns success.
+ */
+static enum sci_status scic_sds_smp_request_await_response_tc_completion_handler(
+ struct scic_sds_request *this_request,
+ u32 completion_code)
+{
+ switch (SCU_GET_COMPLETION_TL_STATUS(completion_code)) {
+ case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_GOOD):
+ /*
+ * In the AWAIT RESPONSE state, any TC completion is unexpected.
+ * but if the TC has success status, we complete the IO anyway. */
+ scic_sds_request_set_status(
+ this_request, SCU_TASK_DONE_GOOD, SCI_SUCCESS
+ );
+
+ sci_base_state_machine_change_state(
+ &this_request->parent.state_machine,
+ SCI_BASE_REQUEST_STATE_COMPLETED
+ );
+ break;
+
+ case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_SMP_RESP_TO_ERR):
+ case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_SMP_UFI_ERR):
+ case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_SMP_FRM_TYPE_ERR):
+ case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_SMP_LL_RX_ERR):
+ /*
+ * These status has been seen in a specific LSI expander, which sometimes
+ * is not able to send smp response within 2 ms. This causes our hardware
+ * break the connection and set TC completion with one of these SMP_XXX_XX_ERR
+ * status. For these type of error, we ask scic user to retry the request. */
+ scic_sds_request_set_status(
+ this_request, SCU_TASK_DONE_SMP_RESP_TO_ERR, SCI_FAILURE_RETRY_REQUIRED
+ );
+
+ sci_base_state_machine_change_state(
+ &this_request->parent.state_machine,
+ SCI_BASE_REQUEST_STATE_COMPLETED
+ );
+ break;
+
+ default:
+ /*
+ * All other completion status cause the IO to be complete. If a NAK
+ * was received, then it is up to the user to retry the request. */
+ scic_sds_request_set_status(
+ this_request,
+ SCU_NORMALIZE_COMPLETION_STATUS(completion_code),
+ SCI_FAILURE_CONTROLLER_SPECIFIC_IO_ERR
+ );
+
+ sci_base_state_machine_change_state(
+ &this_request->parent.state_machine,
+ SCI_BASE_REQUEST_STATE_COMPLETED
+ );
+ break;
+ }
+
+ return SCI_SUCCESS;
+}
+
+
+/**
+ * This method processes the completions transport layer (TL) status to
+ * determine if the SMP request was sent successfully. If the SMP request
+ * was sent successfully, then the state for the SMP request transits to
+ * waiting for a response frame.
+ * @this_request: This parameter specifies the request for which the TC
+ * completion was received.
+ * @completion_code: This parameter indicates the completion status information
+ * for the TC.
+ *
+ * Indicate if the tc completion handler was successful. SCI_SUCCESS currently
+ * this method always returns success.
+ */
+static enum sci_status scic_sds_smp_request_await_tc_completion_tc_completion_handler(
+ struct scic_sds_request *this_request,
+ u32 completion_code)
+{
+ switch (SCU_GET_COMPLETION_TL_STATUS(completion_code)) {
+ case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_GOOD):
+ scic_sds_request_set_status(
+ this_request, SCU_TASK_DONE_GOOD, SCI_SUCCESS
+ );
+
+ sci_base_state_machine_change_state(
+ &this_request->parent.state_machine,
+ SCI_BASE_REQUEST_STATE_COMPLETED
+ );
+ break;
+
+ default:
+ /*
+ * All other completion status cause the IO to be complete. If a NAK
+ * was received, then it is up to the user to retry the request. */
+ scic_sds_request_set_status(
+ this_request,
+ SCU_NORMALIZE_COMPLETION_STATUS(completion_code),
+ SCI_FAILURE_CONTROLLER_SPECIFIC_IO_ERR
+ );
+
+ sci_base_state_machine_change_state(
+ &this_request->parent.state_machine,
+ SCI_BASE_REQUEST_STATE_COMPLETED
+ );
+ break;
+ }
+
+ return SCI_SUCCESS;
+}
+
+
+const struct scic_sds_io_request_state_handler scic_sds_smp_request_started_substate_handler_table[] = {
+ [SCIC_SDS_SMP_REQUEST_STARTED_SUBSTATE_AWAIT_RESPONSE] = {
+ .parent.start_handler = scic_sds_request_default_start_handler,
+ .parent.abort_handler = scic_sds_request_started_state_abort_handler,
+ .parent.complete_handler = scic_sds_request_default_complete_handler,
+ .parent.destruct_handler = scic_sds_request_default_destruct_handler,
+ .tc_completion_handler = scic_sds_smp_request_await_response_tc_completion_handler,
+ .event_handler = scic_sds_request_default_event_handler,
+ .frame_handler = scic_sds_smp_request_await_response_frame_handler,
+ },
+ [SCIC_SDS_SMP_REQUEST_STARTED_SUBSTATE_AWAIT_TC_COMPLETION] = {
+ .parent.start_handler = scic_sds_request_default_start_handler,
+ .parent.abort_handler = scic_sds_request_started_state_abort_handler,
+ .parent.complete_handler = scic_sds_request_default_complete_handler,
+ .parent.destruct_handler = scic_sds_request_default_destruct_handler,
+ .tc_completion_handler = scic_sds_smp_request_await_tc_completion_tc_completion_handler,
+ .event_handler = scic_sds_request_default_event_handler,
+ .frame_handler = scic_sds_request_default_frame_handler,
+ }
+};
+
+/**
+ * This method performs the actions required when entering the
+ * SCIC_SDS_SMP_REQUEST_STARTED_SUBSTATE_AWAIT_TC_RESPONSE sub-state. This
+ * includes setting the IO request state handlers for this sub-state.
+ * @object: This parameter specifies the request object for which the sub-state
+ * change is occuring.
+ *
+ * none.
+ */
+static void scic_sds_smp_request_started_await_response_substate_enter(
+ struct sci_base_object *object)
+{
+ struct scic_sds_request *this_request = (struct scic_sds_request *)object;
+
+ SET_STATE_HANDLER(
+ this_request,
+ scic_sds_smp_request_started_substate_handler_table,
+ SCIC_SDS_SMP_REQUEST_STARTED_SUBSTATE_AWAIT_RESPONSE
+ );
+}
+
+/**
+ * This method performs the actions required when entering the
+ * SCIC_SDS_SMP_REQUEST_STARTED_SUBSTATE_AWAIT_TC_COMPLETION sub-state.
+ * This includes setting the SMP request state handlers for this sub-state.
+ * @object: This parameter specifies the request object for which the sub-state
+ * change is occuring.
+ *
+ * none.
+ */
+static void scic_sds_smp_request_started_await_tc_completion_substate_enter(
+ struct sci_base_object *object)
+{
+ struct scic_sds_request *this_request = (struct scic_sds_request *)object;
+
+ SET_STATE_HANDLER(
+ this_request,
+ scic_sds_smp_request_started_substate_handler_table,
+ SCIC_SDS_SMP_REQUEST_STARTED_SUBSTATE_AWAIT_TC_COMPLETION
+ );
+}
+
+const struct sci_base_state scic_sds_smp_request_started_substate_table[] = {
+ [SCIC_SDS_SMP_REQUEST_STARTED_SUBSTATE_AWAIT_RESPONSE] = {
+ .enter_state = scic_sds_smp_request_started_await_response_substate_enter,
+ },
+ [SCIC_SDS_SMP_REQUEST_STARTED_SUBSTATE_AWAIT_TC_COMPLETION] = {
+ .enter_state = scic_sds_smp_request_started_await_tc_completion_substate_enter,
+ },
+};
+
diff --git a/drivers/scsi/isci/core/scic_sds_smp_request.h b/drivers/scsi/isci/core/scic_sds_smp_request.h
new file mode 100644
index 000000000000..b7c5b83b1989
--- /dev/null
+++ b/drivers/scsi/isci/core/scic_sds_smp_request.h
@@ -0,0 +1,70 @@
+/*
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Intel Corporation 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
+ * OWNER 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.
+ */
+#ifndef _SCIC_SDS_SMP_REQUEST_T_
+#define _SCIC_SDS_SMP_REQUEST_T_
+
+#include "intel_sas.h"
+#include "sci_types.h"
+#include "scic_sds_request.h"
+
+
+u32 scic_sds_smp_request_get_object_size(void);
+
+
+void scic_sds_smp_request_copy_response(
+ struct scic_sds_request *this_request);
+
+#endif /* _SCIC_SDS_SMP_REQUEST_T_ */
+
diff --git a/drivers/scsi/isci/core/scic_sds_ssp_request.c b/drivers/scsi/isci/core/scic_sds_ssp_request.c
new file mode 100644
index 000000000000..0d6441c5ce00
--- /dev/null
+++ b/drivers/scsi/isci/core/scic_sds_ssp_request.c
@@ -0,0 +1,340 @@
+/*
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Intel Corporation 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
+ * OWNER 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.
+ */
+
+/**
+ * This file contains the task management substate handlers for the
+ * SCIC_SDS_IO_REQUEST object.
+ *
+ *
+ */
+
+#include "intel_sas.h"
+#include "sci_environment.h"
+#include "scic_sds_request.h"
+#include "scic_controller.h"
+#include "scic_sds_controller.h"
+#include "scu_completion_codes.h"
+#include "scu_task_context.h"
+
+/**
+ * This method processes the completions transport layer (TL) status to
+ * determine if the RAW task management frame was sent successfully. If the
+ * raw frame was sent successfully, then the state for the task request
+ * transitions to waiting for a response frame.
+ * @this_request: This parameter specifies the request for which the TC
+ * completion was received.
+ * @completion_code: This parameter indicates the completion status information
+ * for the TC.
+ *
+ * Indicate if the tc completion handler was successful. SCI_SUCCESS currently
+ * this method always returns success.
+ */
+static enum sci_status scic_sds_ssp_task_request_await_tc_completion_tc_completion_handler(
+ struct scic_sds_request *this_request,
+ u32 completion_code)
+{
+ switch (SCU_GET_COMPLETION_TL_STATUS(completion_code)) {
+ case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_GOOD):
+ scic_sds_request_set_status(
+ this_request, SCU_TASK_DONE_GOOD, SCI_SUCCESS
+ );
+
+ sci_base_state_machine_change_state(
+ &this_request->started_substate_machine,
+ SCIC_SDS_IO_REQUEST_STARTED_TASK_MGMT_SUBSTATE_AWAIT_TC_RESPONSE
+ );
+ break;
+
+ case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_ACK_NAK_TO):
+ /*
+ * Currently, the decision is to simply allow the task request to
+ * timeout if the task IU wasn't received successfully.
+ * There is a potential for receiving multiple task responses if we
+ * decide to send the task IU again. */
+ dev_warn(scic_to_dev(this_request->owning_controller),
+ "%s: TaskRequest:0x%p CompletionCode:%x - "
+ "ACK/NAK timeout\n",
+ __func__,
+ this_request,
+ completion_code);
+
+ sci_base_state_machine_change_state(
+ &this_request->started_substate_machine,
+ SCIC_SDS_IO_REQUEST_STARTED_TASK_MGMT_SUBSTATE_AWAIT_TC_RESPONSE
+ );
+ break;
+
+ default:
+ /*
+ * All other completion status cause the IO to be complete. If a NAK
+ * was received, then it is up to the user to retry the request. */
+ scic_sds_request_set_status(
+ this_request,
+ SCU_NORMALIZE_COMPLETION_STATUS(completion_code),
+ SCI_FAILURE_CONTROLLER_SPECIFIC_IO_ERR
+ );
+
+ sci_base_state_machine_change_state(
+ &this_request->parent.state_machine,
+ SCI_BASE_REQUEST_STATE_COMPLETED
+ );
+ break;
+ }
+
+ return SCI_SUCCESS;
+}
+
+/**
+ * This method is responsible for processing a terminate/abort request for this
+ * TC while the request is waiting for the task management response
+ * unsolicited frame.
+ * @this_request: This parameter specifies the request for which the
+ * termination was requested.
+ *
+ * This method returns an indication as to whether the abort request was
+ * successfully handled. need to update to ensure the received UF doesn't cause
+ * damage to subsequent requests (i.e. put the extended tag in a holding
+ * pattern for this particular device).
+ */
+static enum sci_status scic_sds_ssp_task_request_await_tc_response_abort_handler(
+ struct sci_base_request *request)
+{
+ struct scic_sds_request *this_request = (struct scic_sds_request *)request;
+
+ sci_base_state_machine_change_state(
+ &this_request->parent.state_machine,
+ SCI_BASE_REQUEST_STATE_ABORTING
+ );
+
+ sci_base_state_machine_change_state(
+ &this_request->parent.state_machine,
+ SCI_BASE_REQUEST_STATE_COMPLETED
+ );
+
+ return SCI_SUCCESS;
+}
+
+/**
+ * This method processes an unsolicited frame while the task mgmt request is
+ * waiting for a response frame. It will copy the response data, release
+ * the unsolicited frame, and transition the request to the
+ * SCI_BASE_REQUEST_STATE_COMPLETED state.
+ * @this_request: This parameter specifies the request for which the
+ * unsolicited frame was received.
+ * @frame_index: This parameter indicates the unsolicited frame index that
+ * should contain the response.
+ *
+ * This method returns an indication of whether the TC response frame was
+ * handled successfully or not. SCI_SUCCESS Currently this value is always
+ * returned and indicates successful processing of the TC response. Should
+ * probably update to check frame type and make sure it is a response frame.
+ */
+static enum sci_status scic_sds_ssp_task_request_await_tc_response_frame_handler(
+ struct scic_sds_request *this_request,
+ u32 frame_index)
+{
+ scic_sds_io_request_copy_response(this_request);
+
+ sci_base_state_machine_change_state(
+ &this_request->parent.state_machine,
+ SCI_BASE_REQUEST_STATE_COMPLETED
+ );
+
+ scic_sds_controller_release_frame(
+ this_request->owning_controller, frame_index
+ );
+
+ return SCI_SUCCESS;
+}
+
+const struct scic_sds_io_request_state_handler scic_sds_ssp_task_request_started_substate_handler_table[] = {
+ [SCIC_SDS_IO_REQUEST_STARTED_TASK_MGMT_SUBSTATE_AWAIT_TC_COMPLETION] = {
+ .parent.start_handler = scic_sds_request_default_start_handler,
+ .parent.abort_handler = scic_sds_request_started_state_abort_handler,
+ .parent.complete_handler = scic_sds_request_default_complete_handler,
+ .parent.destruct_handler = scic_sds_request_default_destruct_handler,
+ .tc_completion_handler = scic_sds_ssp_task_request_await_tc_completion_tc_completion_handler,
+ .event_handler = scic_sds_request_default_event_handler,
+ .frame_handler = scic_sds_request_default_frame_handler,
+ },
+ [SCIC_SDS_IO_REQUEST_STARTED_TASK_MGMT_SUBSTATE_AWAIT_TC_RESPONSE] = {
+ .parent.start_handler = scic_sds_request_default_start_handler,
+ .parent.abort_handler = scic_sds_ssp_task_request_await_tc_response_abort_handler,
+ .parent.complete_handler = scic_sds_request_default_complete_handler,
+ .parent.destruct_handler = scic_sds_request_default_destruct_handler,
+ .tc_completion_handler = scic_sds_request_default_tc_completion_handler,
+ .event_handler = scic_sds_request_default_event_handler,
+ .frame_handler = scic_sds_ssp_task_request_await_tc_response_frame_handler,
+ }
+};
+
+/*
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Intel Corporation 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
+ * OWNER 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.
+ */
+
+/**
+ * This file contains the enter/exit methods associated with each of the task
+ * management raw request states. For more information on the task
+ * management request state machine please refer to scic_sds_io_request.h
+ *
+ *
+ */
+
+#include "scic_sds_request.h"
+#include "sci_base_state_machine.h"
+
+/**
+ * This method performs the actions required when entering the
+ * SCIC_SDS_IO_REQUEST_STARTED_TASK_MGMT_SUBSTATE_AWAIT_TC_COMPLETION
+ * sub-state. This includes setting the IO request state handlers for this
+ * sub-state.
+ * @object: This parameter specifies the request object for which the sub-state
+ * change is occuring.
+ *
+ * none.
+ */
+static void scic_sds_io_request_started_task_mgmt_await_tc_completion_substate_enter(
+ struct sci_base_object *object)
+{
+ struct scic_sds_request *this_request = (struct scic_sds_request *)object;
+
+ SET_STATE_HANDLER(
+ this_request,
+ scic_sds_ssp_task_request_started_substate_handler_table,
+ SCIC_SDS_IO_REQUEST_STARTED_TASK_MGMT_SUBSTATE_AWAIT_TC_COMPLETION
+ );
+}
+
+/**
+ * This method performs the actions required when entering the
+ * SCIC_SDS_IO_REQUEST_STARTED_SUBSTATE_AWAIT_TC_RESPONSE sub-state. This
+ * includes setting the IO request state handlers for this sub-state.
+ * @object: This parameter specifies the request object for which the sub-state
+ * change is occuring.
+ *
+ * none.
+ */
+static void scic_sds_io_request_started_task_mgmt_await_task_response_substate_enter(
+ struct sci_base_object *object)
+{
+ struct scic_sds_request *this_request = (struct scic_sds_request *)object;
+
+ SET_STATE_HANDLER(
+ this_request,
+ scic_sds_ssp_task_request_started_substate_handler_table,
+ SCIC_SDS_IO_REQUEST_STARTED_TASK_MGMT_SUBSTATE_AWAIT_TC_RESPONSE
+ );
+}
+
+const struct sci_base_state scic_sds_io_request_started_task_mgmt_substate_table[] = {
+ [SCIC_SDS_IO_REQUEST_STARTED_TASK_MGMT_SUBSTATE_AWAIT_TC_COMPLETION] = {
+ .enter_state = scic_sds_io_request_started_task_mgmt_await_tc_completion_substate_enter,
+ },
+ [SCIC_SDS_IO_REQUEST_STARTED_TASK_MGMT_SUBSTATE_AWAIT_TC_RESPONSE] = {
+ .enter_state = scic_sds_io_request_started_task_mgmt_await_task_response_substate_enter,
+ },
+};
+
diff --git a/drivers/scsi/isci/core/scic_sds_stp_packet_request.c b/drivers/scsi/isci/core/scic_sds_stp_packet_request.c
new file mode 100644
index 000000000000..f52a8e32b48f
--- /dev/null
+++ b/drivers/scsi/isci/core/scic_sds_stp_packet_request.c
@@ -0,0 +1,838 @@
+/*
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Intel Corporation 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
+ * OWNER 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.
+ */
+#if !defined(DISABLE_ATAPI)
+
+#include "intel_ata.h"
+#include "intel_sas.h"
+#include "intel_sata.h"
+#include "intel_sat.h"
+#include "sati_translator_sequence.h"
+#include "sci_base_state.h"
+#include "scic_controller.h"
+#include "scic_remote_device.h"
+#include "scic_sds_controller.h"
+#include "scic_sds_remote_device.h"
+#include "scic_sds_request.h"
+#include "scic_sds_stp_packet_request.h"
+#include "scic_user_callback.h"
+#include "sci_util.h"
+#include "scu_completion_codes.h"
+#include "scu_task_context.h"
+
+
+/**
+ * This method will fill in the SCU Task Context for a PACKET fis. And
+ * construct the request STARTED sub-state machine for Packet Protocol IO.
+ * @this_request: This parameter specifies the stp packet request object being
+ * constructed.
+ *
+ */
+enum sci_status scic_sds_stp_packet_request_construct(
+ struct scic_sds_request *this_request)
+{
+ struct sata_fis_reg_h2d *h2d_fis =
+ scic_stp_io_request_get_h2d_reg_address(
+ this_request
+ );
+
+ /*
+ * Work around, we currently only support PACKET DMA protocol, so we
+ * need to make change to Packet Fis features field. */
+ h2d_fis->features = h2d_fis->features | ATA_PACKET_FEATURE_DMA;
+
+ scic_sds_stp_non_ncq_request_construct(this_request);
+
+ /* Build the Packet Fis task context structure */
+ scu_stp_raw_request_construct_task_context(
+ (struct scic_sds_stp_request *)this_request,
+ this_request->task_context_buffer
+ );
+
+ sci_base_state_machine_construct(
+ &this_request->started_substate_machine,
+ &this_request->parent.parent,
+ scic_sds_stp_packet_request_started_substate_table,
+ SCIC_SDS_STP_PACKET_REQUEST_STARTED_PACKET_PHASE_AWAIT_TC_COMPLETION_SUBSTATE
+ );
+
+ return SCI_SUCCESS;
+}
+
+
+/**
+ * This method will fill in the SCU Task Context for a Packet request command
+ * phase in PACKET DMA DATA (IN/OUT) type. The following important settings
+ * are utilized: -# task_type == SCU_TASK_TYPE_PACKET_DMA. This simply
+ * indicates that a normal request type (i.e. non-raw frame) is being
+ * utilized to perform task management. -# control_frame == 1. This ensures
+ * that the proper endianess is set so that the bytes are transmitted in the
+ * right order for a smp request frame.
+ * @this_request: This parameter specifies the smp request object being
+ * constructed.
+ * @task_context: The task_context to be reconstruct for packet request command
+ * phase.
+ *
+ */
+void scu_stp_packet_request_command_phase_construct_task_context(
+ struct scic_sds_request *this_request,
+ struct scu_task_context *task_context)
+{
+ void *atapi_cdb;
+ u32 atapi_cdb_length;
+ struct scic_sds_stp_request *stp_request = (struct scic_sds_stp_request *)this_request;
+
+ /*
+ * reference: SSTL 1.13.4.2
+ * task_type, sata_direction */
+ if (scic_cb_io_request_get_data_direction(this_request->user_request)
+ == SCI_IO_REQUEST_DATA_OUT) {
+ task_context->task_type = SCU_TASK_TYPE_PACKET_DMA_OUT;
+ task_context->sata_direction = 0;
+ } else { /* todo: for NO_DATA command, we need to send out raw frame. */
+ task_context->task_type = SCU_TASK_TYPE_PACKET_DMA_IN;
+ task_context->sata_direction = 1;
+ }
+
+ /* sata header */
+ memset(&(task_context->type.stp), 0, sizeof(struct STP_TASK_CONTEXT));
+ task_context->type.stp.fis_type = SATA_FIS_TYPE_DATA;
+
+ /*
+ * Copy in the command IU with CDB so that the commandIU address doesn't
+ * change. */
+ memset(this_request->command_buffer, 0, sizeof(struct sata_fis_reg_h2d));
+
+ atapi_cdb =
+ scic_cb_stp_packet_io_request_get_cdb_address(this_request->user_request);
+
+ atapi_cdb_length =
+ scic_cb_stp_packet_io_request_get_cdb_length(this_request->user_request);
+
+ memcpy(((u8 *)this_request->command_buffer + sizeof(u32)), atapi_cdb, atapi_cdb_length);
+
+ atapi_cdb_length =
+ max(atapi_cdb_length, stp_request->type.packet.device_preferred_cdb_length);
+
+ task_context->ssp_command_iu_length =
+ ((atapi_cdb_length % 4) == 0) ?
+ (atapi_cdb_length / 4) : ((atapi_cdb_length / 4) + 1);
+
+ /* task phase is set to TX_CMD */
+ task_context->task_phase = 0x1;
+
+ /* retry counter */
+ task_context->stp_retry_count = 0;
+
+ if (scic_cb_request_is_initial_construction(this_request->user_request)) {
+ /* data transfer size. */
+ task_context->transfer_length_bytes =
+ scic_cb_io_request_get_transfer_length(this_request->user_request);
+
+ /* setup sgl */
+ scic_sds_request_build_sgl(this_request);
+ } else {
+ /* data transfer size, need to be 4 bytes aligned. */
+ task_context->transfer_length_bytes = (SCSI_FIXED_SENSE_DATA_BASE_LENGTH + 2);
+
+ scic_sds_stp_packet_internal_request_sense_build_sgl(this_request);
+ }
+}
+
+/**
+ * This method will fill in the SCU Task Context for a DATA fis containing CDB
+ * in Raw Frame type. The TC for previous Packet fis was already there, we
+ * only need to change the H2D fis content.
+ * @this_request: This parameter specifies the smp request object being
+ * constructed.
+ * @task_context: The task_context to be reconstruct for packet request command
+ * phase.
+ *
+ */
+void scu_stp_packet_request_command_phase_reconstruct_raw_frame_task_context(
+ struct scic_sds_request *this_request,
+ struct scu_task_context *task_context)
+{
+ void *atapi_cdb =
+ scic_cb_stp_packet_io_request_get_cdb_address(this_request->user_request);
+
+ u32 atapi_cdb_length =
+ scic_cb_stp_packet_io_request_get_cdb_length(this_request->user_request);
+
+ memset(this_request->command_buffer, 0, sizeof(struct sata_fis_reg_h2d));
+ memcpy(((u8 *)this_request->command_buffer + sizeof(u32)), atapi_cdb, atapi_cdb_length);
+
+ memset(&(task_context->type.stp), 0, sizeof(struct STP_TASK_CONTEXT));
+ task_context->type.stp.fis_type = SATA_FIS_TYPE_DATA;
+
+ /*
+ * Note the data send out has to be 4 bytes aligned. Or else out hardware will
+ * patch non-zero bytes and cause the target device unhappy. */
+ task_context->transfer_length_bytes = 12;
+}
+
+
+/*
+ * *@brief This methods decode the D2H status FIS and retrieve the sense data,
+ * then pass the sense data to user request.
+ *
+ ***@param[in] this_request The request receive D2H status FIS.
+ ***@param[in] status_fis The D2H status fis to be processed.
+ *
+ */
+enum sci_status scic_sds_stp_packet_request_process_status_fis(
+ struct scic_sds_request *this_request,
+ struct sata_fis_reg_d2h *status_fis)
+{
+ enum sci_status status = SCI_SUCCESS;
+
+ /* TODO: Process the error status fis, retrieve sense data. */
+ if (status_fis->status & ATA_STATUS_REG_ERROR_BIT)
+ status = SCI_FAILURE_IO_RESPONSE_VALID;
+
+ return status;
+}
+
+/*
+ * *@brief This methods builds sgl for internal REQUEST SENSE stp packet
+ * command using this request response buffer, only one sge is
+ * needed.
+ *
+ ***@param[in] this_request The request receive request sense data.
+ *
+ */
+void scic_sds_stp_packet_internal_request_sense_build_sgl(
+ struct scic_sds_request *this_request)
+{
+ void *sge;
+ struct scu_sgl_element_pair *scu_sgl_list = NULL;
+ struct scu_task_context *task_context;
+ dma_addr_t physical_address;
+
+ struct sci_ssp_response_iu *rsp_iu =
+ (struct sci_ssp_response_iu *)this_request->response_buffer;
+
+ sge = (void *)&rsp_iu->data[0];
+
+ task_context = (struct scu_task_context *)this_request->task_context_buffer;
+ scu_sgl_list = &task_context->sgl_pair_ab;
+
+ scic_cb_io_request_get_physical_address(
+ scic_sds_request_get_controller(this_request),
+ this_request,
+ ((char *)sge),
+ &physical_address
+ );
+
+ scu_sgl_list->A.address_upper = sci_cb_physical_address_upper(physical_address);
+ scu_sgl_list->A.address_lower = sci_cb_physical_address_lower(physical_address);
+ scu_sgl_list->A.length = task_context->transfer_length_bytes;
+ scu_sgl_list->A.address_modifier = 0;
+
+ SCU_SGL_ZERO(scu_sgl_list->B);
+}
+
+/**
+ * This method processes the completions transport layer (TL) status to
+ * determine if the Packet FIS was sent successfully. If the Packet FIS was
+ * sent successfully, then the state for the Packet request transits to
+ * waiting for a PIO SETUP frame.
+ * @this_request: This parameter specifies the request for which the TC
+ * completion was received.
+ * @completion_code: This parameter indicates the completion status information
+ * for the TC.
+ *
+ * Indicate if the tc completion handler was successful. SCI_SUCCESS currently
+ * this method always returns success.
+ */
+enum sci_status scic_sds_stp_packet_request_packet_phase_await_tc_completion_tc_completion_handler(
+ struct scic_sds_request *this_request,
+ u32 completion_code)
+{
+ enum sci_status status = SCI_SUCCESS;
+
+ switch (SCU_GET_COMPLETION_TL_STATUS(completion_code)) {
+ case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_GOOD):
+ scic_sds_request_set_status(
+ this_request, SCU_TASK_DONE_GOOD, SCI_SUCCESS
+ );
+
+ sci_base_state_machine_change_state(
+ &this_request->started_substate_machine,
+ SCIC_SDS_STP_PACKET_REQUEST_STARTED_PACKET_PHASE_AWAIT_PIO_SETUP_SUBSTATE
+ );
+ break;
+
+ default:
+ /*
+ * All other completion status cause the IO to be complete. If a NAK
+ * was received, then it is up to the user to retry the request. */
+ scic_sds_request_set_status(
+ this_request,
+ SCU_NORMALIZE_COMPLETION_STATUS(completion_code),
+ SCI_FAILURE_CONTROLLER_SPECIFIC_IO_ERR
+ );
+
+ sci_base_state_machine_change_state(
+ &this_request->parent.state_machine,
+ SCI_BASE_REQUEST_STATE_COMPLETED
+ );
+ break;
+ }
+
+ return status;
+}
+
+
+/**
+ * This method processes an unsolicited frame while the Packet request is
+ * waiting for a PIO SETUP FIS. It will release the unsolicited frame, and
+ * transition the request to the COMMAND_PHASE_AWAIT_TC_COMPLETION_SUBSTATE
+ * state.
+ * @this_request: This parameter specifies the request for which the
+ * unsolicited frame was received.
+ * @frame_index: This parameter indicates the unsolicited frame index that
+ * should contain the response.
+ *
+ * This method returns an indication of whether the pio setup frame was handled
+ * successfully or not. SCI_SUCCESS Currently this value is always returned and
+ * indicates successful processing of the TC response.
+ */
+enum sci_status scic_sds_stp_packet_request_packet_phase_await_pio_setup_frame_handler(
+ struct scic_sds_request *request,
+ u32 frame_index)
+{
+ enum sci_status status;
+ struct sata_fis_header *frame_header;
+ u32 *frame_buffer;
+ struct scic_sds_stp_request *this_request;
+
+ this_request = (struct scic_sds_stp_request *)request;
+
+ status = scic_sds_unsolicited_frame_control_get_header(
+ &(this_request->parent.owning_controller->uf_control),
+ frame_index,
+ (void **)&frame_header
+ );
+
+ if (status == SCI_SUCCESS) {
+ BUG_ON(frame_header->fis_type != SATA_FIS_TYPE_PIO_SETUP);
+
+ /*
+ * Get from the frame buffer the PIO Setup Data, although we don't need
+ * any info from this pio setup fis. */
+ scic_sds_unsolicited_frame_control_get_buffer(
+ &(this_request->parent.owning_controller->uf_control),
+ frame_index,
+ (void **)&frame_buffer
+ );
+
+ /*
+ * Get the data from the PIO Setup
+ * The SCU Hardware returns first word in the frame_header and the rest
+ * of the data is in the frame buffer so we need to back up one dword */
+ this_request->type.packet.device_preferred_cdb_length =
+ (u16)((struct sata_fis_pio_setup *)(&frame_buffer[-1]))->transfter_count;
+
+ /* Frame has been decoded return it to the controller */
+ scic_sds_controller_release_frame(
+ this_request->parent.owning_controller, frame_index
+ );
+
+ sci_base_state_machine_change_state(
+ &this_request->parent.started_substate_machine,
+ SCIC_SDS_STP_PACKET_REQUEST_STARTED_COMMAND_PHASE_AWAIT_TC_COMPLETION_SUBSTATE
+ );
+ } else
+ dev_err(scic_to_dev(request->owning_controller),
+ "%s: SCIC IO Request 0x%p could not get frame header "
+ "for frame index %d, status %x\n",
+ __func__, this_request, frame_index, status);
+
+ return status;
+}
+
+
+/**
+ * This method processes the completions transport layer (TL) status to
+ * determine if the PACKET command data FIS was sent successfully. If
+ * successfully, then the state for the packet request transits to COMPLETE
+ * state. If not successfuly, the request transits to
+ * COMMAND_PHASE_AWAIT_D2H_FIS_SUBSTATE.
+ * @this_request: This parameter specifies the request for which the TC
+ * completion was received.
+ * @completion_code: This parameter indicates the completion status information
+ * for the TC.
+ *
+ * Indicate if the tc completion handler was successful. SCI_SUCCESS currently
+ * this method always returns success.
+ */
+enum sci_status scic_sds_stp_packet_request_command_phase_await_tc_completion_tc_completion_handler(
+ struct scic_sds_request *this_request,
+ u32 completion_code)
+{
+ enum sci_status status = SCI_SUCCESS;
+ u8 sat_packet_protocol =
+ scic_cb_request_get_sat_protocol(this_request->user_request);
+
+ switch (SCU_GET_COMPLETION_TL_STATUS(completion_code)) {
+ case (SCU_TASK_DONE_GOOD << SCU_COMPLETION_TL_STATUS_SHIFT):
+ scic_sds_request_set_status(
+ this_request, SCU_TASK_DONE_GOOD, SCI_SUCCESS
+ );
+
+ if (sat_packet_protocol == SAT_PROTOCOL_PACKET_DMA_DATA_IN
+ || sat_packet_protocol == SAT_PROTOCOL_PACKET_DMA_DATA_OUT
+ )
+ sci_base_state_machine_change_state(
+ &this_request->parent.state_machine,
+ SCI_BASE_REQUEST_STATE_COMPLETED
+ );
+ else
+ sci_base_state_machine_change_state(
+ &this_request->started_substate_machine,
+ SCIC_SDS_STP_PACKET_REQUEST_STARTED_COMMAND_PHASE_AWAIT_D2H_FIS_SUBSTATE
+ );
+ break;
+
+ case (SCU_TASK_DONE_UNEXP_FIS << SCU_COMPLETION_TL_STATUS_SHIFT):
+ if (scic_io_request_get_number_of_bytes_transferred(this_request) <
+ scic_cb_io_request_get_transfer_length(this_request->user_request)) {
+ scic_sds_request_set_status(
+ this_request, SCU_TASK_DONE_GOOD, SCI_SUCCESS_IO_DONE_EARLY
+ );
+
+ sci_base_state_machine_change_state(
+ &this_request->parent.state_machine,
+ SCI_BASE_REQUEST_STATE_COMPLETED
+ );
+
+ status = this_request->sci_status;
+ }
+ break;
+
+ case (SCU_TASK_DONE_EXCESS_DATA << SCU_COMPLETION_TL_STATUS_SHIFT):
+ /* In this case, there is no UF coming after. compelte the IO now. */
+ scic_sds_request_set_status(
+ this_request, SCU_TASK_DONE_GOOD, SCI_SUCCESS
+ );
+
+ sci_base_state_machine_change_state(
+ &this_request->parent.state_machine,
+ SCI_BASE_REQUEST_STATE_COMPLETED
+ );
+
+ break;
+
+ default:
+ if (this_request->sci_status != SCI_SUCCESS) { /* The io status was set already. This means an UF for the status
+ * fis was received already.
+ */
+
+ /*
+ * A device suspension event is expected, we need to have the device
+ * coming out of suspension, then complete the IO. */
+ sci_base_state_machine_change_state(
+ &this_request->started_substate_machine,
+ SCIC_SDS_STP_PACKET_REQUEST_STARTED_COMPLETION_DELAY_SUBSTATE
+ );
+
+ /* change the device state to ATAPI_ERROR. */
+ sci_base_state_machine_change_state(
+ &this_request->target_device->ready_substate_machine,
+ SCIC_SDS_STP_REMOTE_DEVICE_READY_SUBSTATE_ATAPI_ERROR
+ );
+
+ status = this_request->sci_status;
+ } else { /* If receiving any non-sucess TC status, no UF received yet, then an UF for
+ * the status fis is coming after.
+ */
+ scic_sds_request_set_status(
+ this_request,
+ SCU_TASK_DONE_CHECK_RESPONSE,
+ SCI_FAILURE_IO_RESPONSE_VALID
+ );
+
+ sci_base_state_machine_change_state(
+ &this_request->started_substate_machine,
+ SCIC_SDS_STP_PACKET_REQUEST_STARTED_COMMAND_PHASE_AWAIT_D2H_FIS_SUBSTATE
+ );
+ }
+ break;
+ }
+
+ return status;
+}
+
+
+/**
+ * This method processes an unsolicited frame.
+ * @this_request: This parameter specifies the request for which the
+ * unsolicited frame was received.
+ * @frame_index: This parameter indicates the unsolicited frame index that
+ * should contain the response.
+ *
+ * This method returns an indication of whether the UF frame was handled
+ * successfully or not. SCI_SUCCESS Currently this value is always returned and
+ * indicates successful processing of the TC response.
+ */
+enum sci_status scic_sds_stp_packet_request_command_phase_common_frame_handler(
+ struct scic_sds_request *request,
+ u32 frame_index)
+{
+ enum sci_status status;
+ struct sata_fis_header *frame_header;
+ u32 *frame_buffer;
+ struct scic_sds_stp_request *this_request;
+
+ this_request = (struct scic_sds_stp_request *)request;
+
+ status = scic_sds_unsolicited_frame_control_get_header(
+ &(this_request->parent.owning_controller->uf_control),
+ frame_index,
+ (void **)&frame_header
+ );
+
+ if (status == SCI_SUCCESS) {
+ BUG_ON(frame_header->fis_type != SATA_FIS_TYPE_REGD2H);
+
+ /*
+ * Get from the frame buffer the PIO Setup Data, although we don't need
+ * any info from this pio setup fis. */
+ scic_sds_unsolicited_frame_control_get_buffer(
+ &(this_request->parent.owning_controller->uf_control),
+ frame_index,
+ (void **)&frame_buffer
+ );
+
+ scic_sds_controller_copy_sata_response(
+ &this_request->d2h_reg_fis, (u32 *)frame_header, frame_buffer
+ );
+
+ /* Frame has been decoded return it to the controller */
+ scic_sds_controller_release_frame(
+ this_request->parent.owning_controller, frame_index
+ );
+ }
+
+ return status;
+}
+
+/**
+ * This method processes an unsolicited frame while the packet request is
+ * expecting TC completion. It will process the FIS and construct sense data.
+ * @this_request: This parameter specifies the request for which the
+ * unsolicited frame was received.
+ * @frame_index: This parameter indicates the unsolicited frame index that
+ * should contain the response.
+ *
+ * This method returns an indication of whether the UF frame was handled
+ * successfully or not. SCI_SUCCESS Currently this value is always returned and
+ * indicates successful processing of the TC response.
+ */
+enum sci_status scic_sds_stp_packet_request_command_phase_await_tc_completion_frame_handler(
+ struct scic_sds_request *request,
+ u32 frame_index)
+{
+ struct scic_sds_stp_request *this_request = (struct scic_sds_stp_request *)request;
+
+ enum sci_status status =
+ scic_sds_stp_packet_request_command_phase_common_frame_handler(
+ request, frame_index);
+
+ if (status == SCI_SUCCESS) {
+ /* The command has completed with error status from target device. */
+ status = scic_sds_stp_packet_request_process_status_fis(
+ request, &this_request->d2h_reg_fis);
+
+ if (status != SCI_SUCCESS) {
+ scic_sds_request_set_status(
+ &this_request->parent,
+ SCU_TASK_DONE_CHECK_RESPONSE,
+ status
+ );
+ } else
+ scic_sds_request_set_status(
+ &this_request->parent, SCU_TASK_DONE_GOOD, SCI_SUCCESS
+ );
+ }
+
+ return status;
+}
+
+
+/**
+ * This method processes an unsolicited frame while the packet request is
+ * expecting TC completion. It will process the FIS and construct sense data.
+ * @this_request: This parameter specifies the request for which the
+ * unsolicited frame was received.
+ * @frame_index: This parameter indicates the unsolicited frame index that
+ * should contain the response.
+ *
+ * This method returns an indication of whether the UF frame was handled
+ * successfully or not. SCI_SUCCESS Currently this value is always returned and
+ * indicates successful processing of the TC response.
+ */
+enum sci_status scic_sds_stp_packet_request_command_phase_await_d2h_fis_frame_handler(
+ struct scic_sds_request *request,
+ u32 frame_index)
+{
+ enum sci_status status =
+ scic_sds_stp_packet_request_command_phase_common_frame_handler(
+ request, frame_index);
+
+ struct scic_sds_stp_request *this_request = (struct scic_sds_stp_request *)request;
+
+ if (status == SCI_SUCCESS) {
+ /* The command has completed with error status from target device. */
+ status = scic_sds_stp_packet_request_process_status_fis(
+ request, &this_request->d2h_reg_fis);
+
+ if (status != SCI_SUCCESS) {
+ scic_sds_request_set_status(
+ request,
+ SCU_TASK_DONE_CHECK_RESPONSE,
+ status
+ );
+ } else
+ scic_sds_request_set_status(
+ request, SCU_TASK_DONE_GOOD, SCI_SUCCESS
+ );
+
+ /*
+ * Always complete the NON_DATA command right away, no need to delay completion
+ * even an error status fis came from target device. */
+ sci_base_state_machine_change_state(
+ &request->parent.state_machine,
+ SCI_BASE_REQUEST_STATE_COMPLETED
+ );
+ }
+
+ return status;
+}
+
+enum sci_status scic_sds_stp_packet_request_started_completion_delay_complete_handler(
+ struct sci_base_request *request)
+{
+ struct scic_sds_request *this_request = (struct scic_sds_request *)request;
+
+ sci_base_state_machine_change_state(
+ &this_request->parent.state_machine,
+ SCI_BASE_REQUEST_STATE_COMPLETED
+ );
+
+ return this_request->sci_status;
+}
+
+/* --------------------------------------------------------------------------- */
+
+const struct scic_sds_io_request_state_handler scic_sds_stp_packet_request_started_substate_handler_table[] = {
+ [SCIC_SDS_STP_PACKET_REQUEST_STARTED_PACKET_PHASE_AWAIT_TC_COMPLETION_SUBSTATE] = {
+ .parent.start_handler = scic_sds_request_default_start_handler,
+ .parent.abort_handler = scic_sds_request_started_state_abort_handler,
+ .parent.complete_handler = scic_sds_request_default_complete_handler,
+ .parent.destruct_handler = scic_sds_request_default_destruct_handler
+ .tc_completion_handler = scic_sds_stp_packet_request_packet_phase_await_tc_completion_tc_completion_handler,
+ .event_handler = scic_sds_request_default_event_handler,
+ .frame_handler = scic_sds_request_default_frame_handler
+ },
+ [SCIC_SDS_STP_PACKET_REQUEST_STARTED_PACKET_PHASE_AWAIT_PIO_SETUP_SUBSTATE] = {
+ .parent.start_handler = scic_sds_request_default_start_handler,
+ .parent.abort_handler = scic_sds_request_started_state_abort_handler,
+ .parent.complete_handler = scic_sds_request_default_complete_handler,
+ .parent.destruct_handler = scic_sds_request_default_destruct_handler
+ .tc_completion_handler = scic_sds_request_default_tc_completion_handler,
+ .event_handler = scic_sds_request_default_event_handler,
+ .frame_handler = scic_sds_stp_packet_request_packet_phase_await_pio_setup_frame_handler
+ },
+ [SCIC_SDS_STP_PACKET_REQUEST_STARTED_COMMAND_PHASE_AWAIT_TC_COMPLETION_SUBSTATE] = {
+ .parent.start_handler = scic_sds_request_default_start_handler,
+ .parent.abort_handler = scic_sds_request_started_state_abort_handler,
+ .parent.complete_handler = scic_sds_request_default_complete_handler,
+ .parent.destruct_handler = scic_sds_request_default_destruct_handler
+ .tc_completion_handler = scic_sds_stp_packet_request_command_phase_await_tc_completion_tc_completion_handler,
+ .event_handler = scic_sds_request_default_event_handler,
+ .frame_handler = scic_sds_stp_packet_request_command_phase_await_tc_completion_frame_handler
+ },
+ [SCIC_SDS_STP_PACKET_REQUEST_STARTED_COMMAND_PHASE_AWAIT_D2H_FIS_SUBSTATE] = {
+ .parent.start_handler = scic_sds_request_default_start_handler,
+ .parent.abort_handler = scic_sds_request_started_state_abort_handler,
+ .parent.complete_handler = scic_sds_request_default_complete_handler,
+ .parent.destruct_handler = scic_sds_request_default_destruct_handler
+ .tc_completion_handler = scic_sds_request_default_tc_completion_handler,
+ .event_handler = scic_sds_request_default_event_handler,
+ .frame_handler = scic_sds_stp_packet_request_command_phase_await_d2h_fis_frame_handler
+ },
+ [SCIC_SDS_STP_PACKET_REQUEST_STARTED_COMPLETION_DELAY_SUBSTATE] = {
+ .parent.start_handler = scic_sds_request_default_start_handler,
+ .parent.abort_handler = scic_sds_request_started_state_abort_handler,
+ .parent.complete_handler = scic_sds_stp_packet_request_started_completion_delay_complete_handler,
+ .parent.destruct_handler = scic_sds_request_default_destruct_handler
+ .tc_completion_handler = scic_sds_request_default_tc_completion_handler,
+ .event_handler = scic_sds_request_default_event_handler,
+ .frame_handler = scic_sds_request_default_frame_handler
+ },
+};
+
+void scic_sds_stp_packet_request_started_packet_phase_await_tc_completion_enter(
+ struct sci_base_object *object)
+{
+ struct scic_sds_request *this_request = (struct scic_sds_request *)object;
+
+ SET_STATE_HANDLER(
+ this_request,
+ scic_sds_stp_packet_request_started_substate_handler_table,
+ SCIC_SDS_STP_PACKET_REQUEST_STARTED_PACKET_PHASE_AWAIT_TC_COMPLETION_SUBSTATE
+ );
+
+ scic_sds_remote_device_set_working_request(
+ this_request->target_device, this_request
+ );
+}
+
+void scic_sds_stp_packet_request_started_packet_phase_await_pio_setup_enter(
+ struct sci_base_object *object)
+{
+ struct scic_sds_request *this_request = (struct scic_sds_request *)object;
+
+ SET_STATE_HANDLER(
+ this_request,
+ scic_sds_stp_packet_request_started_substate_handler_table,
+ SCIC_SDS_STP_PACKET_REQUEST_STARTED_PACKET_PHASE_AWAIT_PIO_SETUP_SUBSTATE
+ );
+}
+
+void scic_sds_stp_packet_request_started_command_phase_await_tc_completion_enter(
+ struct sci_base_object *object)
+{
+ struct scic_sds_request *this_request = (struct scic_sds_request *)object;
+ u8 sat_packet_protocol =
+ scic_cb_request_get_sat_protocol(this_request->user_request);
+
+ struct scu_task_context *task_context;
+ enum sci_status status;
+
+ /*
+ * Recycle the TC and reconstruct it for sending out data fis containing
+ * CDB. */
+ task_context = scic_sds_controller_get_task_context_buffer(
+ this_request->owning_controller, this_request->io_tag);
+
+ if (sat_packet_protocol == SAT_PROTOCOL_PACKET_NON_DATA)
+ scu_stp_packet_request_command_phase_reconstruct_raw_frame_task_context(
+ this_request, task_context);
+ else
+ scu_stp_packet_request_command_phase_construct_task_context(
+ this_request, task_context);
+
+ /* send the new TC out. */
+ status = this_request->owning_controller->state_handlers->parent.continue_io_handler(
+ &this_request->owning_controller->parent,
+ &this_request->target_device->parent,
+ &this_request->parent
+ );
+
+ if (status == SCI_SUCCESS)
+ SET_STATE_HANDLER(
+ this_request,
+ scic_sds_stp_packet_request_started_substate_handler_table,
+ SCIC_SDS_STP_PACKET_REQUEST_STARTED_COMMAND_PHASE_AWAIT_TC_COMPLETION_SUBSTATE
+ );
+}
+
+void scic_sds_stp_packet_request_started_command_phase_await_d2h_fis_enter(
+ struct sci_base_object *object)
+{
+ struct scic_sds_request *this_request = (struct scic_sds_request *)object;
+
+ SET_STATE_HANDLER(
+ this_request,
+ scic_sds_stp_packet_request_started_substate_handler_table,
+ SCIC_SDS_STP_PACKET_REQUEST_STARTED_COMMAND_PHASE_AWAIT_D2H_FIS_SUBSTATE
+ );
+}
+
+void scic_sds_stp_packet_request_started_completion_delay_enter(
+ struct sci_base_object *object)
+{
+ struct scic_sds_request *this_request = (struct scic_sds_request *)object;
+
+ SET_STATE_HANDLER(
+ this_request,
+ scic_sds_stp_packet_request_started_substate_handler_table,
+ SCIC_SDS_STP_PACKET_REQUEST_STARTED_COMPLETION_DELAY_SUBSTATE
+ );
+}
+
+
+/* --------------------------------------------------------------------------- */
+const struct sci_base_state scic_sds_stp_packet_request_started_substate_table[] = {
+ [SCIC_SDS_STP_PACKET_REQUEST_STARTED_PACKET_PHASE_AWAIT_TC_COMPLETION_SUBSTATE] = {
+ .enter_state = scic_sds_stp_packet_request_started_packet_phase_await_tc_completion_enter,
+ },
+ [SCIC_SDS_STP_PACKET_REQUEST_STARTED_PACKET_PHASE_AWAIT_PIO_SETUP_SUBSTATE] = {
+ .enter_state = scic_sds_stp_packet_request_started_packet_phase_await_pio_setup_enter,
+ },
+ [SCIC_SDS_STP_PACKET_REQUEST_STARTED_COMMAND_PHASE_AWAIT_TC_COMPLETION_SUBSTATE] = {
+ .enter_state = scic_sds_stp_packet_request_started_command_phase_await_tc_completion_enter,
+ },
+ [SCIC_SDS_STP_PACKET_REQUEST_STARTED_COMMAND_PHASE_AWAIT_D2H_FIS_SUBSTATE] = {
+ .enter_state = scic_sds_stp_packet_request_started_command_phase_await_d2h_fis_enter,
+ },
+ [SCIC_SDS_STP_PACKET_REQUEST_STARTED_COMPLETION_DELAY_SUBSTATE] = {
+ .enter_state scic_sds_stp_packet_request_started_completion_delay_enter,
+ }
+};
+
+#endif /* !defined(DISABLE_ATAPI) */
diff --git a/drivers/scsi/isci/core/scic_sds_stp_packet_request.h b/drivers/scsi/isci/core/scic_sds_stp_packet_request.h
new file mode 100644
index 000000000000..fc18b3f6a13f
--- /dev/null
+++ b/drivers/scsi/isci/core/scic_sds_stp_packet_request.h
@@ -0,0 +1,154 @@
+/*
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Intel Corporation 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
+ * OWNER 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.
+ */
+#ifndef _SCIC_SDS_STP_PACKET_REQUEST_H_
+#define _SCIC_SDS_STP_PACKET_REQUEST_H_
+
+#include "intel_sas.h"
+#include "sci_types.h"
+#include "scic_sds_stp_request.h"
+
+/**
+ * This file contains the structures and constants for PACKET protocol requests.
+ *
+ *
+ */
+
+
+/**
+ *
+ *
+ * This is the enumeration of the SATA PIO DATA IN started substate machine.
+ */
+enum _SCIC_SDS_STP_PACKET_REQUEST_STARTED_SUBSTATES {
+ /**
+ * While in this state the IO request object is waiting for the TC completion
+ * notification for the H2D Register FIS
+ */
+ SCIC_SDS_STP_PACKET_REQUEST_STARTED_PACKET_PHASE_AWAIT_TC_COMPLETION_SUBSTATE,
+
+ /**
+ * While in this state the IO request object is waiting for either a PIO Setup.
+ */
+ SCIC_SDS_STP_PACKET_REQUEST_STARTED_PACKET_PHASE_AWAIT_PIO_SETUP_SUBSTATE,
+
+ /**
+ * While in this state the IO request object is waiting for TC completion for
+ * the Packet DMA DATA fis or Raw Frame.
+ */
+ SCIC_SDS_STP_PACKET_REQUEST_STARTED_COMMAND_PHASE_AWAIT_TC_COMPLETION_SUBSTATE,
+
+ /**
+ * The non-data IO transit to this state in this state after receiving TC
+ * completion. While in this state IO request object is waiting for D2H status
+ * frame as UF.
+ */
+ SCIC_SDS_STP_PACKET_REQUEST_STARTED_COMMAND_PHASE_AWAIT_D2H_FIS_SUBSTATE,
+
+ /**
+ * The IO transit to this state in this state if the previous TC completion status
+ * is not success and the atapi device is suspended due to target device failed the IO.
+ * While in this state IO request object is waiting for device coming out of the
+ * suspension state then complete the IO.
+ */
+ SCIC_SDS_STP_PACKET_REQUEST_STARTED_COMPLETION_DELAY_SUBSTATE,
+};
+
+
+
+#if !defined(DISABLE_ATAPI)
+extern const struct sci_base_state scic_sds_stp_packet_request_started_substate_table[];
+extern const struct scic_sds_io_request_state_handler scic_sds_stp_packet_request_started_substate_handler_table[];
+#endif /* !defined(DISABLE_ATAPI) */
+
+#if !defined(DISABLE_ATAPI)
+enum sci_status scic_sds_stp_packet_request_construct(
+ struct scic_sds_request *this_request);
+#else /* !defined(DISABLE_ATAPI) */
+#define scic_sds_stp_packet_request_construct(request) SCI_FAILURE
+#endif /* !defined(DISABLE_ATAPI) */
+
+#if !defined(DISABLE_ATAPI)
+void scu_stp_packet_request_command_phase_construct_task_context(
+ struct scic_sds_request *this_request,
+ struct scu_task_context *task_context);
+#else /* !defined(DISABLE_ATAPI) */
+#define scu_stp_packet_request_command_phase_construct_task_context(reqeust, tc)
+#endif /* !defined(DISABLE_ATAPI) */
+
+#if !defined(DISABLE_ATAPI)
+void scu_stp_packet_request_command_phase_reconstruct_raw_frame_task_context(
+ struct scic_sds_request *this_request,
+ struct scu_task_context *task_context);
+#else /* !defined(DISABLE_ATAPI) */
+#define scu_stp_packet_request_command_phase_reconstruct_raw_frame_task_context(reqeust, tc)
+#endif /* !defined(DISABLE_ATAPI) */
+
+#if !defined(DISABLE_ATAPI)
+enum sci_status scic_sds_stp_packet_request_process_status_fis(
+ struct scic_sds_request *this_request,
+ struct sata_fis_reg_d2h *status_fis);
+#else /* !defined(DISABLE_ATAPI) */
+#define scic_sds_stp_packet_request_process_status_fis(reqeust, fis) SCI_FAILURE
+#endif /* !defined(DISABLE_ATAPI) */
+
+#if !defined(DISABLE_ATAPI)
+void scic_sds_stp_packet_internal_request_sense_build_sgl(
+ struct scic_sds_request *this_request);
+#else /* !defined(DISABLE_ATAPI) */
+#define scic_sds_stp_packet_internal_request_sense_build_sgl(request)
+#endif /* !defined(DISABLE_ATAPI) */
+
+#endif /* _SCIC_SDS_STP_PACKET_REQUEST_H_ */
+
diff --git a/drivers/scsi/isci/core/scic_sds_stp_pio_request.h b/drivers/scsi/isci/core/scic_sds_stp_pio_request.h
new file mode 100644
index 000000000000..64bf40a6e1d2
--- /dev/null
+++ b/drivers/scsi/isci/core/scic_sds_stp_pio_request.h
@@ -0,0 +1,116 @@
+/*
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Intel Corporation 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
+ * OWNER 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.
+ */
+
+#ifndef _SCIC_SDS_SATA_PIO_REQUEST_H_
+#define _SCIC_SDS_SATA_PIO_REQUEST_H_
+
+#include "sci_base_state.h"
+#include "scic_sds_request.h"
+#include "scu_task_context.h"
+
+/**
+ * This file contains the structures and constants for SATA PIO requests.
+ *
+ *
+ */
+
+
+/**
+ *
+ *
+ * This is the enumeration of the SATA PIO DATA IN started substate machine.
+ */
+enum _SCIC_SDS_STP_REQUEST_STARTED_PIO_SUBSTATES {
+ /**
+ * While in this state the IO request object is waiting for the TC completion
+ * notification for the H2D Register FIS
+ */
+ SCIC_SDS_STP_REQUEST_STARTED_PIO_AWAIT_H2D_COMPLETION_SUBSTATE,
+
+ /**
+ * While in this state the IO request object is waiting for either a PIO Setup
+ * FIS or a D2H register FIS. The type of frame received is based on the
+ * result of the prior frame and line conditions.
+ */
+ SCIC_SDS_STP_REQUEST_STARTED_PIO_AWAIT_FRAME_SUBSTATE,
+
+ /**
+ * While in this state the IO request object is waiting for a DATA frame from
+ * the device.
+ */
+ SCIC_SDS_STP_REQUEST_STARTED_PIO_DATA_IN_AWAIT_DATA_SUBSTATE,
+
+ /**
+ * While in this state the IO request object is waiting to transmit the next data
+ * frame to the device.
+ */
+ SCIC_SDS_STP_REQUEST_STARTED_PIO_DATA_OUT_TRANSMIT_DATA_SUBSTATE,
+};
+
+
+/* --------------------------------------------------------------------------- */
+
+extern const struct scic_sds_io_request_state_handler scic_sds_stp_request_started_pio_substate_handler_table[];
+
+extern const struct sci_base_state scic_sds_stp_request_started_pio_substate_table[];
+
+/* --------------------------------------------------------------------------- */
+
+struct scic_sds_stp_request;
+
+struct scu_sgl_element *scic_sds_stp_request_pio_get_next_sgl(
+ struct scic_sds_stp_request *this_request);
+
+#endif /* _SCIC_SDS_SATA_PIO_REQUEST_H_ */
diff --git a/drivers/scsi/isci/core/scic_sds_stp_remote_device.c b/drivers/scsi/isci/core/scic_sds_stp_remote_device.c
new file mode 100644
index 000000000000..abe8f331a15c
--- /dev/null
+++ b/drivers/scsi/isci/core/scic_sds_stp_remote_device.c
@@ -0,0 +1,975 @@
+/*
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Intel Corporation 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
+ * OWNER 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.
+ */
+
+/**
+ * This file contains the ready substate handlers for an STP device.
+ *
+ *
+ */
+
+#include "intel_sat.h"
+#include "intel_ata.h"
+#include "intel_sata.h"
+#include "sci_environment.h"
+#include "scic_remote_device.h"
+#include "scic_user_callback.h"
+#include "scic_sds_controller.h"
+#include "scic_sds_port.h"
+#include "scic_sds_remote_device.h"
+#include "scic_sds_request.h"
+#include "scu_event_codes.h"
+
+/**
+ * This method will perform the STP request completion processing common to IO
+ * requests and task requests of all types
+ * @device: This parameter specifies the device for which the request is being
+ * completed.
+ * @request: This parameter specifies the request being completed.
+ *
+ * This method returns an indication as to whether the request processing
+ * completed successfully.
+ */
+static enum sci_status scic_sds_stp_remote_device_complete_request(
+ struct sci_base_remote_device *device,
+ struct sci_base_request *request)
+{
+ struct scic_sds_remote_device *this_device = (struct scic_sds_remote_device *)device;
+ struct scic_sds_request *the_request = (struct scic_sds_request *)request;
+ enum sci_status status;
+
+ status = scic_sds_io_request_complete(the_request);
+
+ if (status == SCI_SUCCESS) {
+ status = scic_sds_port_complete_io(
+ this_device->owning_port, this_device, the_request
+ );
+
+ if (status == SCI_SUCCESS) {
+ scic_sds_remote_device_decrement_request_count(this_device);
+ if (the_request->sci_status == SCI_FAILURE_REMOTE_DEVICE_RESET_REQUIRED) {
+ /*
+ * This request causes hardware error, device needs to be Lun Reset.
+ * So here we force the state machine to IDLE state so the rest IOs
+ * can reach RNC state handler, these IOs will be completed by RNC with
+ * status of "DEVICE_RESET_REQUIRED", instead of "INVALID STATE". */
+ sci_base_state_machine_change_state(
+ &this_device->ready_substate_machine,
+ SCIC_SDS_STP_REMOTE_DEVICE_READY_SUBSTATE_AWAIT_RESET
+ );
+ } else if (scic_sds_remote_device_get_request_count(this_device) == 0) {
+ sci_base_state_machine_change_state(
+ &this_device->ready_substate_machine,
+ SCIC_SDS_STP_REMOTE_DEVICE_READY_SUBSTATE_IDLE
+ );
+ }
+ }
+ }
+
+ if (status != SCI_SUCCESS)
+ dev_err(scirdev_to_dev(this_device),
+ "%s: Port:0x%p Device:0x%p Request:0x%p Status:0x%x "
+ "could not complete\n",
+ __func__,
+ this_device->owning_port,
+ this_device,
+ the_request,
+ status);
+
+ return status;
+}
+
+/*
+ * *****************************************************************************
+ * * STP REMOTE DEVICE READY COMMON SUBSTATE HANDLERS
+ * ***************************************************************************** */
+
+/**
+ * This is the READY NCQ substate handler to start task management request. In
+ * this routine, we suspend and resume the RNC.
+ * @device: The target device a task management request towards to.
+ * @request: The task request.
+ *
+ * enum sci_status Always return SCI_FAILURE_RESET_DEVICE_PARTIAL_SUCCESS status to
+ * let controller_start_task_handler know that the controller can't post TC for
+ * task request yet, instead, when RNC gets resumed, a controller_continue_task
+ * callback will be called.
+ */
+static enum sci_status scic_sds_stp_remote_device_ready_substate_start_request_handler(
+ struct sci_base_remote_device *device,
+ struct sci_base_request *request)
+{
+ enum sci_status status;
+ struct scic_sds_remote_device *this_device = (struct scic_sds_remote_device *)device;
+ struct scic_sds_request *this_request = (struct scic_sds_request *)request;
+
+ /* Will the port allow the io request to start? */
+ status = this_device->owning_port->state_handlers->start_io_handler(
+ this_device->owning_port,
+ this_device,
+ this_request
+ );
+
+ if (SCI_SUCCESS == status) {
+ status =
+ scic_sds_remote_node_context_start_task(this_device->rnc, this_request);
+
+ if (SCI_SUCCESS == status) {
+ status = this_request->state_handlers->parent.start_handler(request);
+ }
+
+ if (status == SCI_SUCCESS) {
+ /*
+ * / @note If the remote device state is not IDLE this will replace
+ * / the request that probably resulted in the task management
+ * / request. */
+ this_device->working_request = this_request;
+
+ sci_base_state_machine_change_state(
+ &this_device->ready_substate_machine,
+ SCIC_SDS_STP_REMOTE_DEVICE_READY_SUBSTATE_CMD
+ );
+
+ /*
+ * The remote node context must cleanup the TCi to NCQ mapping table.
+ * The only way to do this correctly is to either write to the TLCR
+ * register or to invalidate and repost the RNC. In either case the
+ * remote node context state machine will take the correct action when
+ * the remote node context is suspended and later resumed. */
+ scic_sds_remote_node_context_suspend(
+ this_device->rnc, SCI_SOFTWARE_SUSPENSION, NULL, NULL);
+
+ scic_sds_remote_node_context_resume(
+ this_device->rnc,
+ (SCICS_SDS_REMOTE_NODE_CONTEXT_CALLBACK)
+ scic_sds_remote_device_continue_request,
+ this_device);
+ }
+
+ scic_sds_remote_device_start_request(this_device, this_request, status);
+
+ /*
+ * We need to let the controller start request handler know that it can't
+ * post TC yet. We will provide a callback function to post TC when RNC gets
+ * resumed. */
+ return SCI_FAILURE_RESET_DEVICE_PARTIAL_SUCCESS;
+ }
+
+ return status;
+}
+
+/*
+ * *****************************************************************************
+ * * STP REMOTE DEVICE READY IDLE SUBSTATE HANDLERS
+ * ***************************************************************************** */
+
+/**
+ * This method will handle the start io operation for a sata device that is in
+ * the command idle state. - Evalute the type of IO request to be started -
+ * If its an NCQ request change to NCQ substate - If its any other command
+ * change to the CMD substate
+ * @device:
+ * @request:
+ *
+ * If this is a softreset we may want to have a different substate. enum sci_status
+ */
+static enum sci_status scic_sds_stp_remote_device_ready_idle_substate_start_io_handler(
+ struct sci_base_remote_device *device,
+ struct sci_base_request *request)
+{
+ enum sci_status status;
+ struct scic_sds_remote_device *this_device = (struct scic_sds_remote_device *)device;
+ struct scic_sds_request *io_request = (struct scic_sds_request *)request;
+
+
+ /* Will the port allow the io request to start? */
+ status = this_device->owning_port->state_handlers->start_io_handler(
+ this_device->owning_port,
+ this_device,
+ io_request
+ );
+
+ if (status == SCI_SUCCESS) {
+ status =
+ scic_sds_remote_node_context_start_io(this_device->rnc, io_request);
+
+ if (status == SCI_SUCCESS) {
+ status = io_request->state_handlers->parent.start_handler(request);
+ }
+
+ if (status == SCI_SUCCESS) {
+ if (
+ scic_cb_request_get_sat_protocol(io_request->user_request)
+ == SAT_PROTOCOL_FPDMA
+ ) {
+ sci_base_state_machine_change_state(
+ &this_device->ready_substate_machine,
+ SCIC_SDS_STP_REMOTE_DEVICE_READY_SUBSTATE_NCQ
+ );
+ } else {
+ this_device->working_request = io_request;
+
+ sci_base_state_machine_change_state(
+ &this_device->ready_substate_machine,
+ SCIC_SDS_STP_REMOTE_DEVICE_READY_SUBSTATE_CMD
+ );
+ }
+ }
+
+ scic_sds_remote_device_start_request(this_device, io_request, status);
+ }
+
+ return status;
+}
+
+
+/**
+ *
+ * @[in]: device The device received event.
+ * @[in]: event_code The event code.
+ *
+ * This method will handle the event for a sata device that is in the idle
+ * state. We pick up suspension events to handle specifically to this state. We
+ * resume the RNC right away. enum sci_status
+ */
+static enum sci_status scic_sds_stp_remote_device_ready_idle_substate_event_handler(
+ struct scic_sds_remote_device *this_device,
+ u32 event_code)
+{
+ enum sci_status status;
+
+ status = scic_sds_remote_device_general_event_handler(this_device, event_code);
+
+ if (status == SCI_SUCCESS) {
+ if (scu_get_event_type(event_code) == SCU_EVENT_TYPE_RNC_SUSPEND_TX
+ || scu_get_event_type(event_code) == SCU_EVENT_TYPE_RNC_SUSPEND_TX_RX) {
+ status = scic_sds_remote_node_context_resume(
+ this_device->rnc, NULL, NULL);
+ }
+ }
+
+ return status;
+}
+
+
+/*
+ * *****************************************************************************
+ * * STP REMOTE DEVICE READY NCQ SUBSTATE HANDLERS
+ * ***************************************************************************** */
+
+static enum sci_status scic_sds_stp_remote_device_ready_ncq_substate_start_io_handler(
+ struct sci_base_remote_device *device,
+ struct sci_base_request *request)
+{
+ enum sci_status status;
+ struct scic_sds_remote_device *this_device = (struct scic_sds_remote_device *)device;
+ struct scic_sds_request *io_request = (struct scic_sds_request *)request;
+
+ if (
+ scic_cb_request_get_sat_protocol(io_request->user_request)
+ == SAT_PROTOCOL_FPDMA
+ ) {
+ status = this_device->owning_port->state_handlers->start_io_handler(
+ this_device->owning_port,
+ this_device,
+ io_request
+ );
+
+ if (status == SCI_SUCCESS) {
+ status = scic_sds_remote_node_context_start_io(this_device->rnc, io_request);
+
+ if (status == SCI_SUCCESS) {
+ status = io_request->state_handlers->parent.start_handler(request);
+ }
+
+ scic_sds_remote_device_start_request(this_device, io_request, status);
+ }
+ } else {
+ status = SCI_FAILURE_INVALID_STATE;
+ }
+
+ return status;
+}
+
+
+/**
+ * This method will handle events received while the STP device is in the ready
+ * command substate.
+ * @this_device: This is the device object that is receiving the event.
+ * @event_code: The event code to process.
+ *
+ * enum sci_status
+ */
+
+static enum sci_status scic_sds_stp_remote_device_ready_ncq_substate_frame_handler(
+ struct scic_sds_remote_device *this_device,
+ u32 frame_index)
+{
+ enum sci_status status;
+ struct sata_fis_header *frame_header;
+
+ status = scic_sds_unsolicited_frame_control_get_header(
+ &(scic_sds_remote_device_get_controller(this_device)->uf_control),
+ frame_index,
+ (void **)&frame_header
+ );
+
+ if (status == SCI_SUCCESS) {
+ if (
+ (frame_header->fis_type == SATA_FIS_TYPE_SETDEVBITS)
+ && (frame_header->status & ATA_STATUS_REG_ERROR_BIT)
+ ) {
+ this_device->not_ready_reason =
+ SCIC_REMOTE_DEVICE_NOT_READY_SATA_SDB_ERROR_FIS_RECEIVED;
+
+ sci_base_state_machine_change_state(
+ &this_device->ready_substate_machine,
+ SCIC_SDS_STP_REMOTE_DEVICE_READY_SUBSTATE_NCQ_ERROR
+ );
+ } else {
+ status = SCI_FAILURE;
+ }
+
+ scic_sds_controller_release_frame(
+ scic_sds_remote_device_get_controller(this_device), frame_index
+ );
+ }
+
+ return status;
+}
+
+/*
+ * *****************************************************************************
+ * * STP REMOTE DEVICE READY CMD SUBSTATE HANDLERS
+ * ***************************************************************************** */
+
+/**
+ * This device is already handling a command it can not accept new commands
+ * until this one is complete.
+ * @device:
+ * @request:
+ *
+ * enum sci_status
+ */
+static enum sci_status scic_sds_stp_remote_device_ready_cmd_substate_start_io_handler(
+ struct sci_base_remote_device *device,
+ struct sci_base_request *request)
+{
+ return SCI_FAILURE_INVALID_STATE;
+}
+
+static enum sci_status scic_sds_stp_remote_device_ready_cmd_substate_suspend_handler(
+ struct scic_sds_remote_device *this_device,
+ u32 suspend_type)
+{
+ enum sci_status status;
+
+ status = scic_sds_remote_node_context_suspend(
+ this_device->rnc, suspend_type, NULL, NULL
+ );
+
+ return status;
+}
+
+static enum sci_status scic_sds_stp_remote_device_ready_cmd_substate_frame_handler(
+ struct scic_sds_remote_device *this_device,
+ u32 frame_index)
+{
+ enum sci_status status;
+
+ /*
+ * / The device doe not process any UF received from the hardware while
+ * / in this state. All unsolicited frames are forwarded to the io request
+ * / object. */
+ status = scic_sds_io_request_frame_handler(
+ this_device->working_request,
+ frame_index
+ );
+
+ return status;
+}
+
+
+/*
+ * *****************************************************************************
+ * * STP REMOTE DEVICE READY NCQ SUBSTATE HANDLERS
+ * ***************************************************************************** */
+
+/*
+ * *****************************************************************************
+ * * STP REMOTE DEVICE READY NCQ ERROR SUBSTATE HANDLERS
+ * ***************************************************************************** */
+
+/*
+ * *****************************************************************************
+ * * STP REMOTE DEVICE READY AWAIT RESET SUBSTATE HANDLERS
+ * ***************************************************************************** */
+static enum sci_status scic_sds_stp_remote_device_ready_await_reset_substate_start_io_handler(
+ struct sci_base_remote_device *device,
+ struct sci_base_request *request)
+{
+ return SCI_FAILURE_REMOTE_DEVICE_RESET_REQUIRED;
+}
+
+
+
+/**
+ * This method will perform the STP request (both io or task) completion
+ * processing for await reset state.
+ * @device: This parameter specifies the device for which the request is being
+ * completed.
+ * @request: This parameter specifies the request being completed.
+ *
+ * This method returns an indication as to whether the request processing
+ * completed successfully.
+ */
+static enum sci_status scic_sds_stp_remote_device_ready_await_reset_substate_complete_request_handler(
+ struct sci_base_remote_device *device,
+ struct sci_base_request *request)
+{
+ struct scic_sds_remote_device *this_device = (struct scic_sds_remote_device *)device;
+ struct scic_sds_request *the_request = (struct scic_sds_request *)request;
+ enum sci_status status;
+
+ status = scic_sds_io_request_complete(the_request);
+
+ if (status == SCI_SUCCESS) {
+ status = scic_sds_port_complete_io(
+ this_device->owning_port, this_device, the_request
+ );
+
+ if (status == SCI_SUCCESS)
+ scic_sds_remote_device_decrement_request_count(this_device);
+ }
+
+ if (status != SCI_SUCCESS)
+ dev_err(scirdev_to_dev(this_device),
+ "%s: Port:0x%p Device:0x%p Request:0x%p Status:0x%x "
+ "could not complete\n",
+ __func__,
+ this_device->owning_port,
+ this_device,
+ the_request,
+ status);
+
+ return status;
+}
+
+#if !defined(DISABLE_ATAPI)
+/*
+ * *****************************************************************************
+ * * STP REMOTE DEVICE READY ATAPI ERROR SUBSTATE HANDLERS
+ * ***************************************************************************** */
+
+/**
+ *
+ * @[in]: device The device received event.
+ * @[in]: event_code The event code.
+ *
+ * This method will handle the event for a ATAPI device that is in the ATAPI
+ * ERROR state. We pick up suspension events to handle specifically to this
+ * state. We resume the RNC right away. We then complete the outstanding IO to
+ * this device. enum sci_status
+ */
+enum sci_status scic_sds_stp_remote_device_ready_atapi_error_substate_event_handler(
+ struct scic_sds_remote_device *this_device,
+ u32 event_code)
+{
+ enum sci_status status;
+
+ status = scic_sds_remote_device_general_event_handler(this_device, event_code);
+
+ if (status == SCI_SUCCESS) {
+ if (scu_get_event_type(event_code) == SCU_EVENT_TYPE_RNC_SUSPEND_TX
+ || scu_get_event_type(event_code) == SCU_EVENT_TYPE_RNC_SUSPEND_TX_RX) {
+ status = scic_sds_remote_node_context_resume(
+ this_device->rnc,
+ this_device->working_request->state_handlers->parent.complete_handler,
+ (void *)this_device->working_request
+ );
+ }
+ }
+
+ return status;
+}
+#endif /* !defined(DISABLE_ATAPI) */
+
+/* --------------------------------------------------------------------------- */
+
+struct scic_sds_remote_device_state_handler
+scic_sds_stp_remote_device_ready_substate_handler_table[
+ SCIC_SDS_STP_REMOTE_DEVICE_READY_MAX_SUBSTATES] =
+{
+ /* SCIC_SDS_STP_REMOTE_DEVICE_READY_SUBSTATE_IDLE */
+ {
+ {
+ scic_sds_remote_device_default_start_handler,
+ scic_sds_remote_device_ready_state_stop_handler,
+ scic_sds_remote_device_default_fail_handler,
+ scic_sds_remote_device_default_destruct_handler,
+ scic_sds_remote_device_ready_state_reset_handler,
+ scic_sds_remote_device_default_reset_complete_handler,
+ scic_sds_stp_remote_device_ready_idle_substate_start_io_handler,
+ scic_sds_remote_device_default_complete_request_handler,
+ scic_sds_remote_device_default_continue_request_handler,
+ scic_sds_stp_remote_device_ready_substate_start_request_handler,
+ scic_sds_remote_device_default_complete_request_handler
+ },
+ scic_sds_remote_device_default_suspend_handler,
+ scic_sds_remote_device_default_resume_handler,
+ scic_sds_stp_remote_device_ready_idle_substate_event_handler,
+ scic_sds_remote_device_default_frame_handler
+ },
+ /* SCIC_SDS_STP_REMOTE_DEVICE_READY_SUBSTATE_CMD */
+ {
+ {
+ scic_sds_remote_device_default_start_handler,
+ scic_sds_remote_device_ready_state_stop_handler,
+ scic_sds_remote_device_default_fail_handler,
+ scic_sds_remote_device_default_destruct_handler,
+ scic_sds_remote_device_ready_state_reset_handler,
+ scic_sds_remote_device_default_reset_complete_handler,
+ scic_sds_stp_remote_device_ready_cmd_substate_start_io_handler,
+ scic_sds_stp_remote_device_complete_request,
+ scic_sds_remote_device_default_continue_request_handler,
+ scic_sds_stp_remote_device_ready_substate_start_request_handler,
+ scic_sds_stp_remote_device_complete_request,
+ },
+ scic_sds_stp_remote_device_ready_cmd_substate_suspend_handler,
+ scic_sds_remote_device_default_resume_handler,
+ scic_sds_remote_device_general_event_handler,
+ scic_sds_stp_remote_device_ready_cmd_substate_frame_handler
+ },
+ /* SCIC_SDS_STP_REMOTE_DEVICE_READY_SUBSTATE_NCQ */
+ {
+ {
+ scic_sds_remote_device_default_start_handler,
+ scic_sds_remote_device_ready_state_stop_handler,
+ scic_sds_remote_device_default_fail_handler,
+ scic_sds_remote_device_default_destruct_handler,
+ scic_sds_remote_device_ready_state_reset_handler,
+ scic_sds_remote_device_default_reset_complete_handler,
+ scic_sds_stp_remote_device_ready_ncq_substate_start_io_handler,
+ scic_sds_stp_remote_device_complete_request,
+ scic_sds_remote_device_default_continue_request_handler,
+ scic_sds_stp_remote_device_ready_substate_start_request_handler,
+ scic_sds_stp_remote_device_complete_request
+ },
+ scic_sds_remote_device_default_suspend_handler,
+ scic_sds_remote_device_default_resume_handler,
+ scic_sds_remote_device_general_event_handler,
+ scic_sds_stp_remote_device_ready_ncq_substate_frame_handler
+ },
+ /* SCIC_SDS_STP_REMOTE_DEVICE_READY_SUBSTATE_NCQ_ERROR */
+ {
+ {
+ scic_sds_remote_device_default_start_handler,
+ scic_sds_remote_device_ready_state_stop_handler,
+ scic_sds_remote_device_default_fail_handler,
+ scic_sds_remote_device_default_destruct_handler,
+ scic_sds_remote_device_ready_state_reset_handler,
+ scic_sds_remote_device_default_reset_complete_handler,
+ scic_sds_remote_device_default_start_request_handler,
+ scic_sds_stp_remote_device_complete_request,
+ scic_sds_remote_device_default_continue_request_handler,
+ scic_sds_stp_remote_device_ready_substate_start_request_handler,
+ scic_sds_stp_remote_device_complete_request
+ },
+ scic_sds_remote_device_default_suspend_handler,
+ scic_sds_remote_device_default_resume_handler,
+ scic_sds_remote_device_general_event_handler,
+ scic_sds_remote_device_general_frame_handler
+ },
+#if !defined(DISABLE_ATAPI)
+ /* SCIC_SDS_STP_REMOTE_DEVICE_READY_SUBSTATE_ATAPI_ERROR */
+ {
+ {
+ scic_sds_remote_device_default_start_handler,
+ scic_sds_remote_device_ready_state_stop_handler,
+ scic_sds_remote_device_default_fail_handler,
+ scic_sds_remote_device_default_destruct_handler,
+ scic_sds_remote_device_ready_state_reset_handler,
+ scic_sds_remote_device_default_reset_complete_handler,
+ scic_sds_remote_device_default_start_request_handler,
+ scic_sds_stp_remote_device_complete_request,
+ scic_sds_remote_device_default_continue_request_handler,
+ scic_sds_stp_remote_device_ready_substate_start_request_handler,
+ scic_sds_stp_remote_device_complete_request
+ },
+ scic_sds_remote_device_default_suspend_handler,
+ scic_sds_remote_device_default_resume_handler,
+ scic_sds_stp_remote_device_ready_atapi_error_substate_event_handler,
+ scic_sds_remote_device_general_frame_handler
+ },
+#endif
+ /* SCIC_SDS_STP_REMOTE_DEVICE_READY_SUBSTATE_AWAIT_RESET */
+ {
+ {
+ scic_sds_remote_device_default_start_handler,
+ scic_sds_remote_device_ready_state_stop_handler,
+ scic_sds_remote_device_default_fail_handler,
+ scic_sds_remote_device_default_destruct_handler,
+ scic_sds_remote_device_ready_state_reset_handler,
+ scic_sds_remote_device_default_reset_complete_handler,
+ scic_sds_stp_remote_device_ready_await_reset_substate_start_io_handler,
+ scic_sds_stp_remote_device_ready_await_reset_substate_complete_request_handler,
+ scic_sds_remote_device_default_continue_request_handler,
+ scic_sds_stp_remote_device_ready_substate_start_request_handler,
+ scic_sds_stp_remote_device_complete_request
+ },
+ scic_sds_remote_device_default_suspend_handler,
+ scic_sds_remote_device_default_resume_handler,
+ scic_sds_remote_device_general_event_handler,
+ scic_sds_remote_device_general_frame_handler
+ }
+};
+
+/*
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Intel Corporation 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
+ * OWNER 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.
+ */
+
+#include "sci_base_state.h"
+#include "scic_remote_device.h"
+#include "scic_user_callback.h"
+#include "scic_sds_controller.h"
+#include "scic_sds_port.h"
+#include "scic_sds_remote_device.h"
+#include "sci_util.h"
+#include "sci_environment.h"
+
+/*
+ * *****************************************************************************
+ * * STP REMOTE DEVICE READY SUBSTATE PRIVATE METHODS
+ * ***************************************************************************** */
+
+static void scic_sds_stp_remote_device_ready_idle_substate_resume_complete_handler(
+ void *user_cookie)
+{
+ struct scic_sds_remote_device *this_device;
+
+ this_device = (struct scic_sds_remote_device *)user_cookie;
+
+ /*
+ * For NCQ operation we do not issue a
+ * scic_cb_remote_device_not_ready(). As a result, avoid sending
+ * the ready notification. */
+ if (this_device->ready_substate_machine.previous_state_id
+ != SCIC_SDS_STP_REMOTE_DEVICE_READY_SUBSTATE_NCQ) {
+ scic_cb_remote_device_ready(
+ scic_sds_remote_device_get_controller(this_device), this_device
+ );
+ }
+}
+
+/*
+ * *****************************************************************************
+ * * STP REMOTE DEVICE READY IDLE SUBSTATE
+ * ***************************************************************************** */
+
+/**
+ *
+ * @device: This is the SCI base object which is cast into a
+ * struct scic_sds_remote_device object.
+ *
+ */
+static void scic_sds_stp_remote_device_ready_idle_substate_enter(
+ struct sci_base_object *device)
+{
+ struct scic_sds_remote_device *this_device;
+
+ this_device = (struct scic_sds_remote_device *)device;
+
+ SET_STATE_HANDLER(
+ this_device,
+ scic_sds_stp_remote_device_ready_substate_handler_table,
+ SCIC_SDS_STP_REMOTE_DEVICE_READY_SUBSTATE_IDLE
+ );
+
+ this_device->working_request = NULL;
+
+ if (scic_sds_remote_node_context_is_ready(this_device->rnc)) {
+ /*
+ * Since the RNC is ready, it's alright to finish completion
+ * processing (e.g. signal the remote device is ready). */
+ scic_sds_stp_remote_device_ready_idle_substate_resume_complete_handler(
+ this_device
+ );
+ } else {
+ scic_sds_remote_node_context_resume(
+ this_device->rnc,
+ scic_sds_stp_remote_device_ready_idle_substate_resume_complete_handler,
+ this_device
+ );
+ }
+}
+
+/*
+ * *****************************************************************************
+ * * STP REMOTE DEVICE READY CMD SUBSTATE
+ * ***************************************************************************** */
+
+/**
+ *
+ * @device: This is the SCI base object which is cast into a
+ * struct scic_sds_remote_device object.
+ *
+ */
+static void scic_sds_stp_remote_device_ready_cmd_substate_enter(
+ struct sci_base_object *device)
+{
+ struct scic_sds_remote_device *this_device;
+
+ this_device = (struct scic_sds_remote_device *)device;
+
+ BUG_ON(this_device->working_request == NULL);
+
+ SET_STATE_HANDLER(
+ this_device,
+ scic_sds_stp_remote_device_ready_substate_handler_table,
+ SCIC_SDS_STP_REMOTE_DEVICE_READY_SUBSTATE_CMD
+ );
+
+ scic_cb_remote_device_not_ready(
+ scic_sds_remote_device_get_controller(this_device),
+ this_device,
+ SCIC_REMOTE_DEVICE_NOT_READY_SATA_REQUEST_STARTED
+ );
+}
+
+/*
+ * *****************************************************************************
+ * * STP REMOTE DEVICE READY NCQ SUBSTATE
+ * ***************************************************************************** */
+
+/**
+ *
+ * @device: This is the SCI base object which is cast into a
+ * struct scic_sds_remote_device object.
+ *
+ */
+static void scic_sds_stp_remote_device_ready_ncq_substate_enter(
+ struct sci_base_object *device)
+{
+ struct scic_sds_remote_device *this_device;
+
+ this_device = (struct scic_sds_remote_device *)device;
+
+ SET_STATE_HANDLER(
+ this_device,
+ scic_sds_stp_remote_device_ready_substate_handler_table,
+ SCIC_SDS_STP_REMOTE_DEVICE_READY_SUBSTATE_NCQ
+ );
+}
+
+/*
+ * *****************************************************************************
+ * * STP REMOTE DEVICE READY NCQ ERROR SUBSTATE
+ * ***************************************************************************** */
+
+/**
+ *
+ * @device: This is the SCI base object which is cast into a
+ * struct scic_sds_remote_device object.
+ *
+ */
+static void scic_sds_stp_remote_device_ready_ncq_error_substate_enter(
+ struct sci_base_object *device)
+{
+ struct scic_sds_remote_device *this_device;
+
+ this_device = (struct scic_sds_remote_device *)device;
+
+ SET_STATE_HANDLER(
+ this_device,
+ scic_sds_stp_remote_device_ready_substate_handler_table,
+ SCIC_SDS_STP_REMOTE_DEVICE_READY_SUBSTATE_NCQ_ERROR
+ );
+
+ if (this_device->not_ready_reason ==
+ SCIC_REMOTE_DEVICE_NOT_READY_SATA_SDB_ERROR_FIS_RECEIVED) {
+ scic_cb_remote_device_not_ready(
+ scic_sds_remote_device_get_controller(this_device),
+ this_device,
+ this_device->not_ready_reason
+ );
+ }
+}
+
+/*
+ * *****************************************************************************
+ * * STP REMOTE DEVICE READY AWAIT RESET SUBSTATE
+ * ***************************************************************************** */
+
+/**
+ * The enter routine to READY AWAIT RESET substate.
+ * @device: This is the SCI base object which is cast into a
+ * struct scic_sds_remote_device object.
+ *
+ */
+static void scic_sds_stp_remote_device_ready_await_reset_substate_enter(
+ struct sci_base_object *device)
+{
+ struct scic_sds_remote_device *this_device;
+
+ this_device = (struct scic_sds_remote_device *)device;
+
+ SET_STATE_HANDLER(
+ this_device,
+ scic_sds_stp_remote_device_ready_substate_handler_table,
+ SCIC_SDS_STP_REMOTE_DEVICE_READY_SUBSTATE_AWAIT_RESET
+ );
+}
+
+#if !defined(DISABLE_ATAPI)
+/*
+ * *****************************************************************************
+ * * STP REMOTE DEVICE READY ATAPI ERROR SUBSTATE
+ * ***************************************************************************** */
+
+/**
+ * The enter routine to READY ATAPI ERROR substate.
+ * @device: This is the SCI base object which is cast into a
+ * struct scic_sds_remote_device object.
+ *
+ */
+void scic_sds_stp_remote_device_ready_atapi_error_substate_enter(
+ struct sci_base_object *device)
+{
+ struct scic_sds_remote_device *this_device;
+
+ this_device = (struct scic_sds_remote_device *)device;
+
+ SET_STATE_HANDLER(
+ this_device,
+ scic_sds_stp_remote_device_ready_substate_handler_table,
+ SCIC_SDS_STP_REMOTE_DEVICE_READY_SUBSTATE_ATAPI_ERROR
+ );
+}
+#endif /* !defined(DISABLE_ATAPI) */
+
+/* --------------------------------------------------------------------------- */
+
+const struct sci_base_state scic_sds_stp_remote_device_ready_substate_table[] = {
+ [SCIC_SDS_STP_REMOTE_DEVICE_READY_SUBSTATE_IDLE] = {
+ .enter_state = scic_sds_stp_remote_device_ready_idle_substate_enter,
+ },
+ [SCIC_SDS_STP_REMOTE_DEVICE_READY_SUBSTATE_CMD] = {
+ .enter_state = scic_sds_stp_remote_device_ready_cmd_substate_enter,
+ },
+ [SCIC_SDS_STP_REMOTE_DEVICE_READY_SUBSTATE_NCQ] = {
+ .enter_state = scic_sds_stp_remote_device_ready_ncq_substate_enter,
+ },
+ [SCIC_SDS_STP_REMOTE_DEVICE_READY_SUBSTATE_NCQ_ERROR] = {
+ .enter_state = scic_sds_stp_remote_device_ready_ncq_error_substate_enter,
+ },
+#if !defined(DISABLE_ATAPI)
+ [SCIC_SDS_STP_REMOTE_DEVICE_READY_SUBSTATE_ATAPI_ERROR] = {
+ .enter_state = scic_sds_stp_remote_device_ready_atapi_error_substate_enter,
+ },
+#endif
+ [SCIC_SDS_STP_REMOTE_DEVICE_READY_SUBSTATE_AWAIT_RESET] = {
+ .enter_state = scic_sds_stp_remote_device_ready_await_reset_substate_enter,
+ },
+};
diff --git a/drivers/scsi/isci/core/scic_sds_stp_request.c b/drivers/scsi/isci/core/scic_sds_stp_request.c
new file mode 100644
index 000000000000..c14f6f10edb1
--- /dev/null
+++ b/drivers/scsi/isci/core/scic_sds_stp_request.c
@@ -0,0 +1,2004 @@
+/*
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Intel Corporation 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
+ * OWNER 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.
+ */
+
+
+#include "intel_ata.h"
+#include "intel_sata.h"
+#include "intel_sat.h"
+#include "sci_base_state.h"
+#include "sci_base_state_machine.h"
+#include "scic_io_request.h"
+#include "scic_remote_device.h"
+#include "scic_sds_controller.h"
+#include "scic_sds_remote_device.h"
+#include "scic_sds_request.h"
+#include "scic_sds_stp_pio_request.h"
+#include "scic_sds_stp_request.h"
+#include "scic_sds_unsolicited_frame_control.h"
+#include "scic_user_callback.h"
+#include "sci_environment.h"
+#include "sci_types.h"
+#include "sci_util.h"
+#include "scu_completion_codes.h"
+#include "scu_event_codes.h"
+#include "scu_task_context.h"
+
+/**
+ * scic_sds_stp_request_get_h2d_reg_buffer() -
+ *
+ * This macro returns the address of the stp h2d reg fis buffer in the io
+ * request memory
+ */
+#define scic_sds_stp_request_get_h2d_reg_buffer(memory) \
+ ((struct sata_fis_reg_h2d *)(\
+ ((char *)(memory)) + sizeof(struct scic_sds_stp_request) \
+ ))
+
+/**
+ * scic_sds_stp_request_get_response_buffer() -
+ *
+ * This macro returns the address of the ssp response iu buffer in the io
+ * request memory
+ */
+#define scic_sds_stp_request_get_response_buffer(memory) \
+ ((struct sata_fis_reg_d2h *)(\
+ ((char *)(scic_sds_stp_request_get_h2d_reg_buffer(memory))) \
+ + sizeof(struct sata_fis_reg_h2d) \
+ ))
+
+/**
+ * scic_sds_stp_request_get_task_context_buffer() -
+ *
+ * This macro returns the address of the task context buffer in the io request
+ * memory
+ */
+#define scic_sds_stp_request_get_task_context_buffer(memory) \
+ ((struct scu_task_context *)(\
+ ((char *)(scic_sds_stp_request_get_response_buffer(memory))) \
+ + sizeof(struct sci_ssp_response_iu) \
+ ))
+
+/**
+ * scic_sds_stp_request_get_sgl_element_buffer() -
+ *
+ * This macro returns the address of the sgl elment pairs in the io request
+ * memory buffer
+ */
+#define scic_sds_stp_request_get_sgl_element_buffer(memory) \
+ ((struct scu_sgl_element_pair *)(\
+ ((char *)(scic_sds_stp_request_get_task_context_buffer(memory))) \
+ + sizeof(struct scu_task_context) \
+ ))
+
+/**
+ *
+ *
+ * This method return the memory space required for STP PIO requests. u32
+ */
+u32 scic_sds_stp_request_get_object_size(void)
+{
+ return sizeof(struct scic_sds_stp_request)
+ + sizeof(struct sata_fis_reg_h2d)
+ + sizeof(struct sata_fis_reg_d2h)
+ + sizeof(struct scu_task_context)
+ + sizeof(struct scu_sgl_element_pair) * SCU_MAX_SGL_ELEMENT_PAIRS;
+}
+
+/**
+ *
+ *
+ *
+ */
+void scic_sds_stp_request_assign_buffers(
+ struct scic_sds_request *request)
+{
+ struct scic_sds_stp_request *this_request = (struct scic_sds_stp_request *)request;
+
+ this_request->parent.command_buffer =
+ scic_sds_stp_request_get_h2d_reg_buffer(this_request);
+ this_request->parent.response_buffer =
+ scic_sds_stp_request_get_response_buffer(this_request);
+ this_request->parent.sgl_element_pair_buffer =
+ scic_sds_stp_request_get_sgl_element_buffer(this_request);
+ this_request->parent.sgl_element_pair_buffer =
+ scic_sds_request_align_sgl_element_buffer(this_request->parent.sgl_element_pair_buffer);
+
+ if (this_request->parent.was_tag_assigned_by_user == false) {
+ this_request->parent.task_context_buffer =
+ scic_sds_stp_request_get_task_context_buffer(this_request);
+ this_request->parent.task_context_buffer =
+ scic_sds_request_align_task_context_buffer(this_request->parent.task_context_buffer);
+ }
+}
+
+/**
+ * This method is will fill in the SCU Task Context for any type of SATA
+ * request. This is called from the various SATA constructors.
+ * @this_request: The general IO request object which is to be used in
+ * constructing the SCU task context.
+ * @task_context: The buffer pointer for the SCU task context which is being
+ * constructed.
+ *
+ * The general io request construction is complete. The buffer assignment for
+ * the command buffer is complete. none Revisit task context construction to
+ * determine what is common for SSP/SMP/STP task context structures.
+ */
+static void scu_sata_reqeust_construct_task_context(
+ struct scic_sds_request *this_request,
+ struct scu_task_context *task_context)
+{
+ dma_addr_t physical_address;
+ struct scic_sds_controller *owning_controller;
+ struct scic_sds_remote_device *target_device;
+ struct scic_sds_port *target_port;
+
+ owning_controller = scic_sds_request_get_controller(this_request);
+ target_device = scic_sds_request_get_device(this_request);
+ target_port = scic_sds_request_get_port(this_request);
+
+ /* Fill in the TC with the its required data */
+ task_context->abort = 0;
+ task_context->priority = SCU_TASK_PRIORITY_NORMAL;
+ task_context->initiator_request = 1;
+ task_context->connection_rate =
+ scic_remote_device_get_connection_rate(target_device);
+ task_context->protocol_engine_index =
+ scic_sds_controller_get_protocol_engine_group(owning_controller);
+ task_context->logical_port_index =
+ scic_sds_port_get_index(target_port);
+ task_context->protocol_type = SCU_TASK_CONTEXT_PROTOCOL_STP;
+ task_context->valid = SCU_TASK_CONTEXT_VALID;
+ task_context->context_type = SCU_TASK_CONTEXT_TYPE;
+
+ task_context->remote_node_index =
+ scic_sds_remote_device_get_index(this_request->target_device);
+ task_context->command_code = 0;
+
+ task_context->link_layer_control = 0;
+ task_context->do_not_dma_ssp_good_response = 1;
+ task_context->strict_ordering = 0;
+ task_context->control_frame = 0;
+ task_context->timeout_enable = 0;
+ task_context->block_guard_enable = 0;
+
+ task_context->address_modifier = 0;
+ task_context->task_phase = 0x01;
+
+ task_context->ssp_command_iu_length =
+ (sizeof(struct sata_fis_reg_h2d) - sizeof(u32)) / sizeof(u32);
+
+ /* Set the first word of the H2D REG FIS */
+ task_context->type.words[0] = *(u32 *)this_request->command_buffer;
+
+ if (this_request->was_tag_assigned_by_user) {
+ /* Build the task context now since we have already read the data */
+ this_request->post_context = (
+ SCU_CONTEXT_COMMAND_REQUEST_TYPE_POST_TC
+ | (
+ scic_sds_controller_get_protocol_engine_group(owning_controller)
+ << SCU_CONTEXT_COMMAND_PROTOCOL_ENGINE_GROUP_SHIFT
+ )
+ | (
+ scic_sds_port_get_index(target_port)
+ << SCU_CONTEXT_COMMAND_LOGICAL_PORT_SHIFT
+ )
+ | scic_sds_io_tag_get_index(this_request->io_tag)
+ );
+ } else {
+ /* Build the task context now since we have already read the data */
+ this_request->post_context = (
+ SCU_CONTEXT_COMMAND_REQUEST_TYPE_POST_TC
+ | (
+ scic_sds_controller_get_protocol_engine_group(owning_controller)
+ << SCU_CONTEXT_COMMAND_PROTOCOL_ENGINE_GROUP_SHIFT
+ )
+ | (
+ scic_sds_port_get_index(target_port)
+ << SCU_CONTEXT_COMMAND_LOGICAL_PORT_SHIFT
+ )
+ /* This is not assigned because we have to wait until we get a TCi */
+ );
+ }
+
+ /*
+ * Copy the physical address for the command buffer to the SCU Task Context
+ * We must offset the command buffer by 4 bytes because the first 4 bytes are
+ * transfered in the body of the TC */
+ scic_cb_io_request_get_physical_address(
+ scic_sds_request_get_controller(this_request),
+ this_request,
+ ((char *)this_request->command_buffer) + sizeof(u32),
+ &physical_address
+ );
+
+ task_context->command_iu_upper =
+ upper_32_bits(physical_address);
+ task_context->command_iu_lower =
+ lower_32_bits(physical_address);
+
+ /* SATA Requests do not have a response buffer */
+ task_context->response_iu_upper = 0;
+ task_context->response_iu_lower = 0;
+}
+
+/**
+ *
+ * @this_request:
+ *
+ * This method will perform any general sata request construction. What part of
+ * SATA IO request construction is general? none
+ */
+void scic_sds_stp_non_ncq_request_construct(
+ struct scic_sds_request *this_request)
+{
+ this_request->has_started_substate_machine = true;
+}
+
+/**
+ *
+ * @this_request: This parameter specifies the request to be constructed as an
+ * optimized request.
+ * @optimized_task_type: This parameter specifies whether the request is to be
+ * an UDMA request or a NCQ request. - A value of 0 indicates UDMA. - A
+ * value of 1 indicates NCQ.
+ *
+ * This method will perform request construction common to all types of STP
+ * requests that are optimized by the silicon (i.e. UDMA, NCQ). This method
+ * returns an indication as to whether the construction was successful.
+ */
+static void scic_sds_stp_optimized_request_construct(
+ struct scic_sds_request *this_request,
+ u8 optimized_task_type,
+ u32 transfer_length,
+ SCI_IO_REQUEST_DATA_DIRECTION data_direction)
+{
+ struct scu_task_context *task_context = this_request->task_context_buffer;
+
+ /* Build the STP task context structure */
+ scu_sata_reqeust_construct_task_context(this_request, task_context);
+
+ /* Copy over the SGL elements */
+ scic_sds_request_build_sgl(this_request);
+
+ /* Copy over the number of bytes to be transfered */
+ task_context->transfer_length_bytes = transfer_length;
+
+ if (data_direction == SCI_IO_REQUEST_DATA_OUT) {
+ /*
+ * The difference between the DMA IN and DMA OUT request task type
+ * values are consistent with the difference between FPDMA READ
+ * and FPDMA WRITE values. Add the supplied task type parameter
+ * to this difference to set the task type properly for this
+ * DATA OUT (WRITE) case. */
+ task_context->task_type = optimized_task_type + (SCU_TASK_TYPE_DMA_OUT
+ - SCU_TASK_TYPE_DMA_IN);
+ } else {
+ /*
+ * For the DATA IN (READ) case, simply save the supplied
+ * optimized task type. */
+ task_context->task_type = optimized_task_type;
+ }
+}
+
+/**
+ *
+ * @this_request: This parameter specifies the request to be constructed.
+ *
+ * This method will construct the STP UDMA request and its associated TC data.
+ * This method returns an indication as to whether the construction was
+ * successful. SCI_SUCCESS Currently this method always returns this value.
+ */
+enum sci_status scic_sds_stp_udma_request_construct(
+ struct scic_sds_request *this_request,
+ u32 transfer_length,
+ SCI_IO_REQUEST_DATA_DIRECTION data_direction)
+{
+ scic_sds_stp_non_ncq_request_construct(this_request);
+
+ scic_sds_stp_optimized_request_construct(
+ this_request,
+ SCU_TASK_TYPE_DMA_IN,
+ transfer_length,
+ data_direction
+ );
+
+ sci_base_state_machine_construct(
+ &this_request->started_substate_machine,
+ &this_request->parent.parent,
+ scic_sds_stp_request_started_udma_substate_table,
+ SCIC_SDS_STP_REQUEST_STARTED_UDMA_AWAIT_TC_COMPLETION_SUBSTATE
+ );
+
+ return SCI_SUCCESS;
+}
+
+/**
+ *
+ * @this_request: This parameter specifies the request to be constructed.
+ *
+ * This method will construct the STP UDMA request and its associated TC data.
+ * This method returns an indication as to whether the construction was
+ * successful. SCI_SUCCESS Currently this method always returns this value.
+ */
+enum sci_status scic_sds_stp_ncq_request_construct(
+ struct scic_sds_request *this_request,
+ u32 transfer_length,
+ SCI_IO_REQUEST_DATA_DIRECTION data_direction)
+{
+ scic_sds_stp_optimized_request_construct(
+ this_request,
+ SCU_TASK_TYPE_FPDMAQ_READ,
+ transfer_length,
+ data_direction
+ );
+ return SCI_SUCCESS;
+}
+
+/**
+ *
+ * @this_request: This parameter specifies the STP request object for which to
+ * construct a RAW command frame task context.
+ * @task_context: This parameter specifies the SCU specific task context buffer
+ * to construct.
+ *
+ * This method performs the operations common to all SATA/STP requests
+ * utilizing the raw frame method. none
+ */
+void scu_stp_raw_request_construct_task_context(
+ struct scic_sds_stp_request *this_request,
+ struct scu_task_context *task_context)
+{
+ scu_sata_reqeust_construct_task_context(&this_request->parent, task_context);
+
+ task_context->control_frame = 0;
+ task_context->priority = SCU_TASK_PRIORITY_NORMAL;
+ task_context->task_type = SCU_TASK_TYPE_SATA_RAW_FRAME;
+ task_context->type.stp.fis_type = SATA_FIS_TYPE_REGH2D;
+ task_context->transfer_length_bytes = sizeof(struct sata_fis_reg_h2d) - sizeof(u32);
+}
+
+/**
+ *
+ * @this_request: This parameter specifies the core request object to
+ * construction into an STP/SATA non-data request.
+ *
+ * This method will construct the STP Non-data request and its associated TC
+ * data. A non-data request essentially behaves like a 0 length read request
+ * in the SCU. This method currently always returns SCI_SUCCESS
+ */
+enum sci_status scic_sds_stp_non_data_request_construct(
+ struct scic_sds_request *this_request)
+{
+ scic_sds_stp_non_ncq_request_construct(this_request);
+
+ /* Build the STP task context structure */
+ scu_stp_raw_request_construct_task_context(
+ (struct scic_sds_stp_request *)this_request,
+ this_request->task_context_buffer
+ );
+
+ sci_base_state_machine_construct(
+ &this_request->started_substate_machine,
+ &this_request->parent.parent,
+ scic_sds_stp_request_started_non_data_substate_table,
+ SCIC_SDS_STP_REQUEST_STARTED_NON_DATA_AWAIT_H2D_COMPLETION_SUBSTATE
+ );
+
+ return SCI_SUCCESS;
+}
+
+
+enum sci_status scic_sds_stp_soft_reset_request_construct(
+ struct scic_sds_request *this_request)
+{
+ scic_sds_stp_non_ncq_request_construct(this_request);
+
+ /* Build the STP task context structure */
+ scu_stp_raw_request_construct_task_context(
+ (struct scic_sds_stp_request *)this_request,
+ this_request->task_context_buffer
+ );
+
+ sci_base_state_machine_construct(
+ &this_request->started_substate_machine,
+ &this_request->parent.parent,
+ scic_sds_stp_request_started_soft_reset_substate_table,
+ SCIC_SDS_STP_REQUEST_STARTED_SOFT_RESET_AWAIT_H2D_ASSERTED_COMPLETION_SUBSTATE
+ );
+
+ return SCI_SUCCESS;
+}
+
+
+void scic_stp_io_request_set_ncq_tag(
+ struct scic_sds_request *req,
+ u16 ncq_tag)
+{
+ /**
+ * @note This could be made to return an error to the user if the user
+ * attempts to set the NCQ tag in the wrong state.
+ */
+ req->task_context_buffer->type.stp.ncq_tag = ncq_tag;
+}
+
+
+void *scic_stp_io_request_get_h2d_reg_address(
+ struct scic_sds_request *req)
+{
+ return req->command_buffer;
+}
+
+
+void *scic_stp_io_request_get_d2h_reg_address(
+ struct scic_sds_request *req)
+{
+ return &((struct scic_sds_stp_request *)req)->d2h_reg_fis;
+}
+
+/**
+ *
+ * @this_request:
+ *
+ * Get the next SGL element from the request. - Check on which SGL element pair
+ * we are working - if working on SLG pair element A - advance to element B -
+ * else - check to see if there are more SGL element pairs for this IO request
+ * - if there are more SGL element pairs - advance to the next pair and return
+ * element A struct scu_sgl_element*
+ */
+struct scu_sgl_element *scic_sds_stp_request_pio_get_next_sgl(
+ struct scic_sds_stp_request *this_request
+ ) {
+ struct scu_sgl_element *current_sgl;
+
+ if (this_request->type.pio.request_current.sgl_set == SCU_SGL_ELEMENT_PAIR_A) {
+ if (
+ (this_request->type.pio.request_current.sgl_pair->B.address_lower == 0)
+ && (this_request->type.pio.request_current.sgl_pair->B.address_upper == 0)
+ ) {
+ current_sgl = NULL;
+ } else {
+ this_request->type.pio.request_current.sgl_set = SCU_SGL_ELEMENT_PAIR_B;
+ current_sgl = &(this_request->type.pio.request_current.sgl_pair->B);
+ }
+ } else {
+ if (
+ (this_request->type.pio.request_current.sgl_pair->next_pair_lower == 0)
+ && (this_request->type.pio.request_current.sgl_pair->next_pair_upper == 0)
+ ) {
+ current_sgl = NULL;
+ } else {
+ dma_addr_t physical_address;
+
+ sci_cb_make_physical_address(
+ physical_address,
+ this_request->type.pio.request_current.sgl_pair->next_pair_upper,
+ this_request->type.pio.request_current.sgl_pair->next_pair_lower
+ );
+
+ this_request->type.pio.request_current.sgl_pair =
+ (struct scu_sgl_element_pair *)scic_cb_get_virtual_address(
+ this_request->parent.owning_controller,
+ physical_address
+ );
+
+ this_request->type.pio.request_current.sgl_set = SCU_SGL_ELEMENT_PAIR_A;
+
+ current_sgl = &(this_request->type.pio.request_current.sgl_pair->A);
+ }
+ }
+
+ return current_sgl;
+}
+
+/**
+ *
+ * @scic_io_request: The core request object which is cast to a SATA PIO
+ * request object.
+ *
+ * This method will construct the SATA PIO request. This method returns an
+ * indication as to whether the construction was successful. SCI_SUCCESS
+ * Currently this method always returns this value.
+ */
+enum sci_status scic_sds_stp_pio_request_construct(
+ struct scic_sds_request *scic_io_request,
+ u8 sat_protocol,
+ bool copy_rx_frame)
+{
+ struct scic_sds_stp_request *this_request;
+
+ this_request = (struct scic_sds_stp_request *)scic_io_request;
+
+ scic_sds_stp_non_ncq_request_construct(&this_request->parent);
+
+ scu_stp_raw_request_construct_task_context(
+ this_request, this_request->parent.task_context_buffer
+ );
+
+ this_request->type.pio.current_transfer_bytes = 0;
+ this_request->type.pio.ending_error = 0;
+ this_request->type.pio.ending_status = 0;
+
+ this_request->type.pio.request_current.sgl_offset = 0;
+ this_request->type.pio.request_current.sgl_set = SCU_SGL_ELEMENT_PAIR_A;
+ this_request->type.pio.sat_protocol = sat_protocol;
+
+ if (copy_rx_frame) {
+ scic_sds_request_build_sgl(&this_request->parent);
+ /*
+ * Since the IO request copy of the TC contains the same data as
+ * the actual TC this pointer is vaild for either. */
+ this_request->type.pio.request_current.sgl_pair =
+ &this_request->parent.task_context_buffer->sgl_pair_ab;
+ } else {
+ /* The user does not want the data copied to the SGL buffer location */
+ this_request->type.pio.request_current.sgl_pair = NULL;
+ }
+
+ sci_base_state_machine_construct(
+ &this_request->parent.started_substate_machine,
+ &this_request->parent.parent.parent,
+ scic_sds_stp_request_started_pio_substate_table,
+ SCIC_SDS_STP_REQUEST_STARTED_PIO_AWAIT_H2D_COMPLETION_SUBSTATE
+ );
+
+ return SCI_SUCCESS;
+}
+
+/**
+ *
+ * @this_request:
+ * @completion_code:
+ *
+ * This method processes a TC completion. The expected TC completion is for
+ * the transmission of the H2D register FIS containing the SATA/STP non-data
+ * request. This method always successfully processes the TC completion.
+ * SCI_SUCCESS This value is always returned.
+ */
+static enum sci_status scic_sds_stp_request_non_data_await_h2d_tc_completion_handler(
+ struct scic_sds_request *this_request,
+ u32 completion_code)
+{
+ switch (SCU_GET_COMPLETION_TL_STATUS(completion_code)) {
+ case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_GOOD):
+ scic_sds_request_set_status(
+ this_request, SCU_TASK_DONE_GOOD, SCI_SUCCESS
+ );
+
+ sci_base_state_machine_change_state(
+ &this_request->started_substate_machine,
+ SCIC_SDS_STP_REQUEST_STARTED_NON_DATA_AWAIT_D2H_SUBSTATE
+ );
+ break;
+
+ default:
+ /*
+ * All other completion status cause the IO to be complete. If a NAK
+ * was received, then it is up to the user to retry the request. */
+ scic_sds_request_set_status(
+ this_request,
+ SCU_NORMALIZE_COMPLETION_STATUS(completion_code),
+ SCI_FAILURE_CONTROLLER_SPECIFIC_IO_ERR
+ );
+
+ sci_base_state_machine_change_state(
+ &this_request->parent.state_machine, SCI_BASE_REQUEST_STATE_COMPLETED
+ );
+ break;
+ }
+
+ return SCI_SUCCESS;
+}
+
+/**
+ *
+ * @request: This parameter specifies the request for which a frame has been
+ * received.
+ * @frame_index: This parameter specifies the index of the frame that has been
+ * received.
+ *
+ * This method processes frames received from the target while waiting for a
+ * device to host register FIS. If a non-register FIS is received during this
+ * time, it is treated as a protocol violation from an IO perspective. Indicate
+ * if the received frame was processed successfully.
+ */
+static enum sci_status scic_sds_stp_request_non_data_await_d2h_frame_handler(
+ struct scic_sds_request *request,
+ u32 frame_index)
+{
+ enum sci_status status;
+ struct sata_fis_header *frame_header;
+ u32 *frame_buffer;
+ struct scic_sds_stp_request *this_request = (struct scic_sds_stp_request *)request;
+
+ status = scic_sds_unsolicited_frame_control_get_header(
+ &(this_request->parent.owning_controller->uf_control),
+ frame_index,
+ (void **)&frame_header
+ );
+
+ if (status == SCI_SUCCESS) {
+ switch (frame_header->fis_type) {
+ case SATA_FIS_TYPE_REGD2H:
+ scic_sds_unsolicited_frame_control_get_buffer(
+ &(this_request->parent.owning_controller->uf_control),
+ frame_index,
+ (void **)&frame_buffer
+ );
+
+ scic_sds_controller_copy_sata_response(
+ &this_request->d2h_reg_fis, (u32 *)frame_header, frame_buffer
+ );
+
+ /* The command has completed with error */
+ scic_sds_request_set_status(
+ &this_request->parent,
+ SCU_TASK_DONE_CHECK_RESPONSE,
+ SCI_FAILURE_IO_RESPONSE_VALID
+ );
+ break;
+
+ default:
+ dev_warn(scic_to_dev(request->owning_controller),
+ "%s: IO Request:0x%p Frame Id:%d protocol "
+ "violation occurred\n",
+ __func__, this_request, frame_index);
+
+ scic_sds_request_set_status(
+ &this_request->parent,
+ SCU_TASK_DONE_UNEXP_FIS,
+ SCI_FAILURE_PROTOCOL_VIOLATION
+ );
+ break;
+ }
+
+ sci_base_state_machine_change_state(
+ &this_request->parent.parent.state_machine,
+ SCI_BASE_REQUEST_STATE_COMPLETED
+ );
+
+ /* Frame has been decoded return it to the controller */
+ scic_sds_controller_release_frame(
+ this_request->parent.owning_controller, frame_index
+ );
+ } else
+ dev_err(scic_to_dev(request->owning_controller),
+ "%s: SCIC IO Request 0x%p could not get frame header "
+ "for frame index %d, status %x\n",
+ __func__, this_request, frame_index, status);
+
+ return status;
+}
+
+/* --------------------------------------------------------------------------- */
+
+const struct scic_sds_io_request_state_handler scic_sds_stp_request_started_non_data_substate_handler_table[] = {
+ [SCIC_SDS_STP_REQUEST_STARTED_NON_DATA_AWAIT_H2D_COMPLETION_SUBSTATE] = {
+ .parent.start_handler = scic_sds_request_default_start_handler,
+ .parent.abort_handler = scic_sds_request_started_state_abort_handler,
+ .parent.complete_handler = scic_sds_request_default_complete_handler,
+ .parent.destruct_handler = scic_sds_request_default_destruct_handler,
+ .tc_completion_handler = scic_sds_stp_request_non_data_await_h2d_tc_completion_handler,
+ .event_handler = scic_sds_request_default_event_handler,
+ .frame_handler = scic_sds_request_default_frame_handler,
+ },
+ [SCIC_SDS_STP_REQUEST_STARTED_NON_DATA_AWAIT_D2H_SUBSTATE] = {
+ .parent.start_handler = scic_sds_request_default_start_handler,
+ .parent.abort_handler = scic_sds_request_started_state_abort_handler,
+ .parent.complete_handler = scic_sds_request_default_complete_handler,
+ .parent.destruct_handler = scic_sds_request_default_destruct_handler,
+ .tc_completion_handler = scic_sds_request_default_tc_completion_handler,
+ .event_handler = scic_sds_request_default_event_handler,
+ .frame_handler = scic_sds_stp_request_non_data_await_d2h_frame_handler,
+ }
+};
+
+static void scic_sds_stp_request_started_non_data_await_h2d_completion_enter(
+ struct sci_base_object *object)
+{
+ struct scic_sds_request *this_request = (struct scic_sds_request *)object;
+
+ SET_STATE_HANDLER(
+ this_request,
+ scic_sds_stp_request_started_non_data_substate_handler_table,
+ SCIC_SDS_STP_REQUEST_STARTED_NON_DATA_AWAIT_H2D_COMPLETION_SUBSTATE
+ );
+
+ scic_sds_remote_device_set_working_request(
+ this_request->target_device, this_request
+ );
+}
+
+static void scic_sds_stp_request_started_non_data_await_d2h_enter(
+ struct sci_base_object *object)
+{
+ struct scic_sds_request *this_request = (struct scic_sds_request *)object;
+
+ SET_STATE_HANDLER(
+ this_request,
+ scic_sds_stp_request_started_non_data_substate_handler_table,
+ SCIC_SDS_STP_REQUEST_STARTED_NON_DATA_AWAIT_D2H_SUBSTATE
+ );
+}
+
+/* --------------------------------------------------------------------------- */
+
+const struct sci_base_state scic_sds_stp_request_started_non_data_substate_table[] = {
+ [SCIC_SDS_STP_REQUEST_STARTED_NON_DATA_AWAIT_H2D_COMPLETION_SUBSTATE] = {
+ .enter_state = scic_sds_stp_request_started_non_data_await_h2d_completion_enter,
+ },
+ [SCIC_SDS_STP_REQUEST_STARTED_NON_DATA_AWAIT_D2H_SUBSTATE] = {
+ .enter_state = scic_sds_stp_request_started_non_data_await_d2h_enter,
+ },
+};
+
+#define SCU_MAX_FRAME_BUFFER_SIZE 0x400 /* 1K is the maximum SCU frame data payload */
+
+/**
+ *
+ * @this_request:
+ * @length:
+ *
+ * This function will transmit DATA_FIS from (current sgl + offset) for input
+ * parameter length. current sgl and offset is alreay stored in the IO request
+ * enum sci_status
+ */
+
+static enum sci_status scic_sds_stp_request_pio_data_out_trasmit_data_frame(
+ struct scic_sds_request *this_request,
+ u32 length)
+{
+ struct scic_sds_stp_request *this_sds_stp_request = (struct scic_sds_stp_request *)this_request;
+ sci_base_controller_request_handler_t continue_io;
+ struct scu_sgl_element *current_sgl;
+ struct scic_sds_controller *scic;
+ u32 state;
+
+ /*
+ * Recycle the TC and reconstruct it for sending out DATA FIS containing
+ * for the data from current_sgl+offset for the input length */
+ struct scu_task_context *task_context = scic_sds_controller_get_task_context_buffer(
+ this_request->owning_controller,
+ this_request->io_tag
+ );
+
+ if (this_sds_stp_request->type.pio.request_current.sgl_set == SCU_SGL_ELEMENT_PAIR_A)
+ current_sgl = &(this_sds_stp_request->type.pio.request_current.sgl_pair->A);
+ else
+ current_sgl = &(this_sds_stp_request->type.pio.request_current.sgl_pair->B);
+
+ /* update the TC */
+ task_context->command_iu_upper = current_sgl->address_upper;
+ task_context->command_iu_lower = current_sgl->address_lower;
+ task_context->transfer_length_bytes = length;
+ task_context->type.stp.fis_type = SATA_FIS_TYPE_DATA;
+
+ /* send the new TC out. */
+ scic = this_request->owning_controller;
+ state = scic->parent.state_machine.current_state_id;
+ continue_io = scic_sds_controller_state_handler_table[state].base.continue_io;
+ return continue_io(&scic->parent, &this_request->target_device->parent,
+ &this_request->parent);
+}
+
+/**
+ *
+ * @this_request:
+ *
+ * enum sci_status
+ */
+static enum sci_status scic_sds_stp_request_pio_data_out_transmit_data(
+ struct scic_sds_request *this_sds_request)
+{
+
+ struct scu_sgl_element *current_sgl;
+ u32 sgl_offset;
+ u32 remaining_bytes_in_current_sgl = 0;
+ enum sci_status status = SCI_SUCCESS;
+
+ struct scic_sds_stp_request *this_sds_stp_request = (struct scic_sds_stp_request *)this_sds_request;
+
+ sgl_offset = this_sds_stp_request->type.pio.request_current.sgl_offset;
+
+ if (this_sds_stp_request->type.pio.request_current.sgl_set == SCU_SGL_ELEMENT_PAIR_A) {
+ current_sgl = &(this_sds_stp_request->type.pio.request_current.sgl_pair->A);
+ remaining_bytes_in_current_sgl = this_sds_stp_request->type.pio.request_current.sgl_pair->A.length - sgl_offset;
+ } else {
+ current_sgl = &(this_sds_stp_request->type.pio.request_current.sgl_pair->B);
+ remaining_bytes_in_current_sgl = this_sds_stp_request->type.pio.request_current.sgl_pair->B.length - sgl_offset;
+ }
+
+
+ if (this_sds_stp_request->type.pio.pio_transfer_bytes > 0) {
+ if (this_sds_stp_request->type.pio.pio_transfer_bytes >= remaining_bytes_in_current_sgl) {
+ /* recycle the TC and send the H2D Data FIS from (current sgl + sgl_offset) and length = remaining_bytes_in_current_sgl */
+ status = scic_sds_stp_request_pio_data_out_trasmit_data_frame(this_sds_request, remaining_bytes_in_current_sgl);
+ if (status == SCI_SUCCESS) {
+ this_sds_stp_request->type.pio.pio_transfer_bytes -= remaining_bytes_in_current_sgl;
+
+ /* update the current sgl, sgl_offset and save for future */
+ current_sgl = scic_sds_stp_request_pio_get_next_sgl(this_sds_stp_request);
+ sgl_offset = 0;
+ }
+ } else if (this_sds_stp_request->type.pio.pio_transfer_bytes < remaining_bytes_in_current_sgl) {
+ /* recycle the TC and send the H2D Data FIS from (current sgl + sgl_offset) and length = type.pio.pio_transfer_bytes */
+ scic_sds_stp_request_pio_data_out_trasmit_data_frame(this_sds_request, this_sds_stp_request->type.pio.pio_transfer_bytes);
+
+ if (status == SCI_SUCCESS) {
+ /* Sgl offset will be adjusted and saved for future */
+ sgl_offset += this_sds_stp_request->type.pio.pio_transfer_bytes;
+ current_sgl->address_lower += this_sds_stp_request->type.pio.pio_transfer_bytes;
+ this_sds_stp_request->type.pio.pio_transfer_bytes = 0;
+ }
+ }
+ }
+
+ if (status == SCI_SUCCESS) {
+ this_sds_stp_request->type.pio.request_current.sgl_offset = sgl_offset;
+ }
+
+ return status;
+}
+
+/**
+ *
+ * @this_request: The request that is used for the SGL processing.
+ * @data_buffer: The buffer of data to be copied.
+ * @length: The length of the data transfer.
+ *
+ * Copy the data from the buffer for the length specified to the IO reqeust SGL
+ * specified data region. enum sci_status
+ */
+static enum sci_status scic_sds_stp_request_pio_data_in_copy_data_buffer(
+ struct scic_sds_stp_request *this_request,
+ u8 *data_buffer,
+ u32 length)
+{
+ enum sci_status status;
+ struct scu_sgl_element *current_sgl;
+ u32 sgl_offset;
+ u32 data_offset;
+ u8 *source_address;
+ u8 *destination_address;
+ u32 copy_length;
+
+ /* Initial setup to get the current working SGL and the offset within the buffer */
+ current_sgl =
+ (this_request->type.pio.request_current.sgl_set == SCU_SGL_ELEMENT_PAIR_A) ?
+ &(this_request->type.pio.request_current.sgl_pair->A) :
+ &(this_request->type.pio.request_current.sgl_pair->B);
+
+ sgl_offset = this_request->type.pio.request_current.sgl_offset;
+
+ source_address = data_buffer;
+ data_offset = 0;
+
+ status = SCI_SUCCESS;
+
+ /* While we are still doing Ok and there is more data to transfer */
+ while (
+ (length > 0)
+ && (status == SCI_SUCCESS)
+ ) {
+ if (current_sgl->length == sgl_offset) {
+ /* This SGL has been exauhasted so we need to get the next SGL */
+ current_sgl = scic_sds_stp_request_pio_get_next_sgl(this_request);
+
+ if (current_sgl == NULL)
+ status = SCI_FAILURE;
+ else
+ sgl_offset = 0;
+ } else {
+ dma_addr_t physical_address;
+
+ sci_cb_make_physical_address(
+ physical_address,
+ current_sgl->address_upper,
+ current_sgl->address_lower
+ );
+
+ destination_address = (u8 *)scic_cb_get_virtual_address(
+ this_request->parent.owning_controller,
+ physical_address
+ );
+
+ source_address += data_offset;
+ destination_address += sgl_offset;
+
+ copy_length = min(length, current_sgl->length - sgl_offset);
+
+ memcpy(destination_address, source_address, copy_length);
+
+ length -= copy_length;
+ sgl_offset += copy_length;
+ data_offset += copy_length;
+ }
+ }
+
+ this_request->type.pio.request_current.sgl_offset = sgl_offset;
+
+ return status;
+}
+
+/**
+ *
+ * @this_request: The PIO DATA IN request that is to receive the data.
+ * @data_buffer: The buffer to copy from.
+ *
+ * Copy the data buffer to the io request data region. enum sci_status
+ */
+static enum sci_status scic_sds_stp_request_pio_data_in_copy_data(
+ struct scic_sds_stp_request *this_request,
+ u8 *data_buffer)
+{
+ enum sci_status status;
+
+ /*
+ * If there is less than 1K remaining in the transfer request
+ * copy just the data for the transfer */
+ if (this_request->type.pio.pio_transfer_bytes < SCU_MAX_FRAME_BUFFER_SIZE) {
+ status = scic_sds_stp_request_pio_data_in_copy_data_buffer(
+ this_request, data_buffer, this_request->type.pio.pio_transfer_bytes);
+
+ if (status == SCI_SUCCESS)
+ this_request->type.pio.pio_transfer_bytes = 0;
+ } else {
+ /* We are transfering the whole frame so copy */
+ status = scic_sds_stp_request_pio_data_in_copy_data_buffer(
+ this_request, data_buffer, SCU_MAX_FRAME_BUFFER_SIZE);
+
+ if (status == SCI_SUCCESS)
+ this_request->type.pio.pio_transfer_bytes -= SCU_MAX_FRAME_BUFFER_SIZE;
+ }
+
+ return status;
+}
+
+/**
+ *
+ * @this_request:
+ * @completion_code:
+ *
+ * enum sci_status
+ */
+static enum sci_status scic_sds_stp_request_pio_await_h2d_completion_tc_completion_handler(
+ struct scic_sds_request *this_request,
+ u32 completion_code)
+{
+ enum sci_status status = SCI_SUCCESS;
+
+ switch (SCU_GET_COMPLETION_TL_STATUS(completion_code)) {
+ case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_GOOD):
+ scic_sds_request_set_status(
+ this_request, SCU_TASK_DONE_GOOD, SCI_SUCCESS
+ );
+
+ sci_base_state_machine_change_state(
+ &this_request->started_substate_machine,
+ SCIC_SDS_STP_REQUEST_STARTED_PIO_AWAIT_FRAME_SUBSTATE
+ );
+ break;
+
+ default:
+ /*
+ * All other completion status cause the IO to be complete. If a NAK
+ * was received, then it is up to the user to retry the request. */
+ scic_sds_request_set_status(
+ this_request,
+ SCU_NORMALIZE_COMPLETION_STATUS(completion_code),
+ SCI_FAILURE_CONTROLLER_SPECIFIC_IO_ERR
+ );
+
+ sci_base_state_machine_change_state(
+ &this_request->parent.state_machine,
+ SCI_BASE_REQUEST_STATE_COMPLETED
+ );
+ break;
+ }
+
+ return status;
+}
+
+/**
+ *
+ * @this_request:
+ * @frame_index:
+ *
+ * enum sci_status
+ */
+static enum sci_status scic_sds_stp_request_pio_await_frame_frame_handler(
+ struct scic_sds_request *request,
+ u32 frame_index)
+{
+ enum sci_status status;
+ struct sata_fis_header *frame_header;
+ u32 *frame_buffer;
+ struct scic_sds_stp_request *this_request;
+
+ this_request = (struct scic_sds_stp_request *)request;
+
+ status = scic_sds_unsolicited_frame_control_get_header(
+ &(this_request->parent.owning_controller->uf_control),
+ frame_index,
+ (void **)&frame_header
+ );
+
+ if (status == SCI_SUCCESS) {
+ switch (frame_header->fis_type) {
+ case SATA_FIS_TYPE_PIO_SETUP:
+ /* Get from the frame buffer the PIO Setup Data */
+ scic_sds_unsolicited_frame_control_get_buffer(
+ &(this_request->parent.owning_controller->uf_control),
+ frame_index,
+ (void **)&frame_buffer
+ );
+
+ /*
+ * Get the data from the PIO Setup
+ * The SCU Hardware returns first word in the frame_header and the rest
+ * of the data is in the frame buffer so we need to back up one dword */
+ this_request->type.pio.pio_transfer_bytes =
+ (u16)((struct sata_fis_pio_setup *)(&frame_buffer[-1]))->transfter_count;
+ this_request->type.pio.ending_status =
+ (u8)((struct sata_fis_pio_setup *)(&frame_buffer[-1]))->ending_status;
+
+ scic_sds_controller_copy_sata_response(
+ &this_request->d2h_reg_fis, (u32 *)frame_header, frame_buffer
+ );
+
+ this_request->d2h_reg_fis.status =
+ this_request->type.pio.ending_status;
+
+ /* The next state is dependent on whether the request was PIO Data-in or Data out */
+ if (this_request->type.pio.sat_protocol == SAT_PROTOCOL_PIO_DATA_IN) {
+ sci_base_state_machine_change_state(
+ &this_request->parent.started_substate_machine,
+ SCIC_SDS_STP_REQUEST_STARTED_PIO_DATA_IN_AWAIT_DATA_SUBSTATE
+ );
+ } else if (this_request->type.pio.sat_protocol == SAT_PROTOCOL_PIO_DATA_OUT) {
+ /* Transmit data */
+ status = scic_sds_stp_request_pio_data_out_transmit_data(request);
+ if (status == SCI_SUCCESS) {
+ sci_base_state_machine_change_state(
+ &this_request->parent.started_substate_machine,
+ SCIC_SDS_STP_REQUEST_STARTED_PIO_DATA_OUT_TRANSMIT_DATA_SUBSTATE
+ );
+ }
+ }
+ break;
+
+ case SATA_FIS_TYPE_SETDEVBITS:
+ sci_base_state_machine_change_state(
+ &this_request->parent.started_substate_machine,
+ SCIC_SDS_STP_REQUEST_STARTED_PIO_AWAIT_FRAME_SUBSTATE
+ );
+ break;
+
+ case SATA_FIS_TYPE_REGD2H:
+ if ((frame_header->status & ATA_STATUS_REG_BSY_BIT) == 0) {
+ scic_sds_unsolicited_frame_control_get_buffer(
+ &(this_request->parent.owning_controller->uf_control),
+ frame_index,
+ (void **)&frame_buffer
+ );
+
+ scic_sds_controller_copy_sata_response(
+ &this_request->d2h_reg_fis, (u32 *)frame_header, frame_buffer);
+
+ scic_sds_request_set_status(
+ &this_request->parent,
+ SCU_TASK_DONE_CHECK_RESPONSE,
+ SCI_FAILURE_IO_RESPONSE_VALID
+ );
+
+ sci_base_state_machine_change_state(
+ &this_request->parent.parent.state_machine,
+ SCI_BASE_REQUEST_STATE_COMPLETED
+ );
+ } else {
+ /*
+ * Now why is the drive sending a D2H Register FIS when it is still busy?
+ * Do nothing since we are still in the right state. */
+ dev_dbg(scic_to_dev(request->owning_controller),
+ "%s: SCIC PIO Request 0x%p received "
+ "D2H Register FIS with BSY status "
+ "0x%x\n",
+ __func__,
+ this_request,
+ frame_header->status);
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ /* Frame is decoded return it to the controller */
+ scic_sds_controller_release_frame(
+ this_request->parent.owning_controller,
+ frame_index
+ );
+ } else
+ dev_err(scic_to_dev(request->owning_controller),
+ "%s: SCIC IO Request 0x%p could not get frame header "
+ "for frame index %d, status %x\n",
+ __func__, this_request, frame_index, status);
+
+ return status;
+}
+
+/**
+ *
+ * @this_request:
+ * @frame_index:
+ *
+ * enum sci_status
+ */
+static enum sci_status scic_sds_stp_request_pio_data_in_await_data_frame_handler(
+ struct scic_sds_request *request,
+ u32 frame_index)
+{
+ enum sci_status status;
+ struct sata_fis_header *frame_header;
+ struct sata_fis_data *frame_buffer;
+ struct scic_sds_stp_request *this_request;
+
+ this_request = (struct scic_sds_stp_request *)request;
+
+ status = scic_sds_unsolicited_frame_control_get_header(
+ &(this_request->parent.owning_controller->uf_control),
+ frame_index,
+ (void **)&frame_header
+ );
+
+ if (status == SCI_SUCCESS) {
+ if (frame_header->fis_type == SATA_FIS_TYPE_DATA) {
+ if (this_request->type.pio.request_current.sgl_pair == NULL) {
+ this_request->parent.saved_rx_frame_index = frame_index;
+ this_request->type.pio.pio_transfer_bytes = 0;
+ } else {
+ status = scic_sds_unsolicited_frame_control_get_buffer(
+ &(this_request->parent.owning_controller->uf_control),
+ frame_index,
+ (void **)&frame_buffer
+ );
+
+ status = scic_sds_stp_request_pio_data_in_copy_data(this_request, (u8 *)frame_buffer);
+
+ /* Frame is decoded return it to the controller */
+ scic_sds_controller_release_frame(
+ this_request->parent.owning_controller,
+ frame_index
+ );
+ }
+
+ /*
+ * Check for the end of the transfer, are there more bytes remaining
+ * for this data transfer */
+ if (
+ (status == SCI_SUCCESS)
+ && (this_request->type.pio.pio_transfer_bytes == 0)
+ ) {
+ if ((this_request->type.pio.ending_status & ATA_STATUS_REG_BSY_BIT) == 0) {
+ scic_sds_request_set_status(
+ &this_request->parent,
+ SCU_TASK_DONE_CHECK_RESPONSE,
+ SCI_FAILURE_IO_RESPONSE_VALID
+ );
+
+ sci_base_state_machine_change_state(
+ &this_request->parent.parent.state_machine,
+ SCI_BASE_REQUEST_STATE_COMPLETED
+ );
+ } else {
+ sci_base_state_machine_change_state(
+ &this_request->parent.started_substate_machine,
+ SCIC_SDS_STP_REQUEST_STARTED_PIO_AWAIT_FRAME_SUBSTATE
+ );
+ }
+ }
+ } else {
+ dev_err(scic_to_dev(request->owning_controller),
+ "%s: SCIC PIO Request 0x%p received frame %d "
+ "with fis type 0x%02x when expecting a data "
+ "fis.\n",
+ __func__,
+ this_request,
+ frame_index,
+ frame_header->fis_type);
+
+ scic_sds_request_set_status(
+ &this_request->parent,
+ SCU_TASK_DONE_GOOD,
+ SCI_FAILURE_IO_REQUIRES_SCSI_ABORT
+ );
+
+ sci_base_state_machine_change_state(
+ &this_request->parent.parent.state_machine,
+ SCI_BASE_REQUEST_STATE_COMPLETED
+ );
+
+ /* Frame is decoded return it to the controller */
+ scic_sds_controller_release_frame(
+ this_request->parent.owning_controller,
+ frame_index
+ );
+ }
+ } else
+ dev_err(scic_to_dev(request->owning_controller),
+ "%s: SCIC IO Request 0x%p could not get frame header "
+ "for frame index %d, status %x\n",
+ __func__, this_request, frame_index, status);
+
+ return status;
+}
+
+
+/**
+ *
+ * @this_request:
+ * @completion_code:
+ *
+ * enum sci_status
+ */
+static enum sci_status scic_sds_stp_request_pio_data_out_await_data_transmit_completion_tc_completion_handler(
+
+ struct scic_sds_request *this_request,
+ u32 completion_code)
+{
+ enum sci_status status = SCI_SUCCESS;
+ bool all_frames_transferred = false;
+
+ struct scic_sds_stp_request *this_scic_sds_stp_request = (struct scic_sds_stp_request *)this_request;
+
+ switch (SCU_GET_COMPLETION_TL_STATUS(completion_code)) {
+ case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_GOOD):
+ /* Transmit data */
+ if (this_scic_sds_stp_request->type.pio.pio_transfer_bytes != 0) {
+ status = scic_sds_stp_request_pio_data_out_transmit_data(this_request);
+ if (status == SCI_SUCCESS) {
+ if (this_scic_sds_stp_request->type.pio.pio_transfer_bytes == 0)
+ all_frames_transferred = true;
+ }
+ } else if (this_scic_sds_stp_request->type.pio.pio_transfer_bytes == 0) {
+ /*
+ * this will happen if the all data is written at the
+ * first time after the pio setup fis is received
+ */
+ all_frames_transferred = true;
+ }
+
+ /* all data transferred. */
+ if (all_frames_transferred) {
+ /*
+ * Change the state to SCIC_SDS_STP_REQUEST_STARTED_PIO_DATA_IN_AWAIT_FRAME_SUBSTATE
+ * and wait for PIO_SETUP fis / or D2H REg fis. */
+ sci_base_state_machine_change_state(
+ &this_request->started_substate_machine,
+ SCIC_SDS_STP_REQUEST_STARTED_PIO_AWAIT_FRAME_SUBSTATE
+ );
+ }
+ break;
+
+ default:
+ /*
+ * All other completion status cause the IO to be complete. If a NAK
+ * was received, then it is up to the user to retry the request. */
+ scic_sds_request_set_status(
+ this_request,
+ SCU_NORMALIZE_COMPLETION_STATUS(completion_code),
+ SCI_FAILURE_CONTROLLER_SPECIFIC_IO_ERR
+ );
+
+ sci_base_state_machine_change_state(
+ &this_request->parent.state_machine,
+ SCI_BASE_REQUEST_STATE_COMPLETED
+ );
+ break;
+ }
+
+ return status;
+}
+
+/**
+ *
+ * @request: This is the request which is receiving the event.
+ * @event_code: This is the event code that the request on which the request is
+ * expected to take action.
+ *
+ * This method will handle any link layer events while waiting for the data
+ * frame. enum sci_status SCI_SUCCESS SCI_FAILURE
+ */
+static enum sci_status scic_sds_stp_request_pio_data_in_await_data_event_handler(
+ struct scic_sds_request *request,
+ u32 event_code)
+{
+ enum sci_status status;
+
+ switch (scu_get_event_specifier(event_code)) {
+ case SCU_TASK_DONE_CRC_ERR << SCU_EVENT_SPECIFIC_CODE_SHIFT:
+ /*
+ * We are waiting for data and the SCU has R_ERR the data frame.
+ * Go back to waiting for the D2H Register FIS */
+ sci_base_state_machine_change_state(
+ &request->started_substate_machine,
+ SCIC_SDS_STP_REQUEST_STARTED_PIO_AWAIT_FRAME_SUBSTATE
+ );
+
+ status = SCI_SUCCESS;
+ break;
+
+ default:
+ dev_err(scic_to_dev(request->owning_controller),
+ "%s: SCIC PIO Request 0x%p received unexpected "
+ "event 0x%08x\n",
+ __func__, request, event_code);
+
+ /* / @todo Should we fail the PIO request when we get an unexpected event? */
+ status = SCI_FAILURE;
+ break;
+ }
+
+ return status;
+}
+
+/* --------------------------------------------------------------------------- */
+
+const struct scic_sds_io_request_state_handler scic_sds_stp_request_started_pio_substate_handler_table[] = {
+ [SCIC_SDS_STP_REQUEST_STARTED_PIO_AWAIT_H2D_COMPLETION_SUBSTATE] = {
+ .parent.start_handler = scic_sds_request_default_start_handler,
+ .parent.abort_handler = scic_sds_request_started_state_abort_handler,
+ .parent.complete_handler = scic_sds_request_default_complete_handler,
+ .parent.destruct_handler = scic_sds_request_default_destruct_handler,
+ .tc_completion_handler = scic_sds_stp_request_pio_await_h2d_completion_tc_completion_handler,
+ .event_handler = scic_sds_request_default_event_handler,
+ .frame_handler = scic_sds_request_default_frame_handler
+ },
+ [SCIC_SDS_STP_REQUEST_STARTED_PIO_AWAIT_FRAME_SUBSTATE] = {
+ .parent.start_handler = scic_sds_request_default_start_handler,
+ .parent.abort_handler = scic_sds_request_started_state_abort_handler,
+ .parent.complete_handler = scic_sds_request_default_complete_handler,
+ .parent.destruct_handler = scic_sds_request_default_destruct_handler,
+ .tc_completion_handler = scic_sds_request_default_tc_completion_handler,
+ .event_handler = scic_sds_request_default_event_handler,
+ .frame_handler = scic_sds_stp_request_pio_await_frame_frame_handler
+ },
+ [SCIC_SDS_STP_REQUEST_STARTED_PIO_DATA_IN_AWAIT_DATA_SUBSTATE] = {
+ .parent.start_handler = scic_sds_request_default_start_handler,
+ .parent.abort_handler = scic_sds_request_started_state_abort_handler,
+ .parent.complete_handler = scic_sds_request_default_complete_handler,
+ .parent.destruct_handler = scic_sds_request_default_destruct_handler,
+ .tc_completion_handler = scic_sds_request_default_tc_completion_handler,
+ .event_handler = scic_sds_stp_request_pio_data_in_await_data_event_handler,
+ .frame_handler = scic_sds_stp_request_pio_data_in_await_data_frame_handler
+ },
+ [SCIC_SDS_STP_REQUEST_STARTED_PIO_DATA_OUT_TRANSMIT_DATA_SUBSTATE] = {
+ .parent.start_handler = scic_sds_request_default_start_handler,
+ .parent.abort_handler = scic_sds_request_started_state_abort_handler,
+ .parent.complete_handler = scic_sds_request_default_complete_handler,
+ .parent.destruct_handler = scic_sds_request_default_destruct_handler,
+ .tc_completion_handler = scic_sds_stp_request_pio_data_out_await_data_transmit_completion_tc_completion_handler,
+ .event_handler = scic_sds_request_default_event_handler,
+ .frame_handler = scic_sds_request_default_frame_handler,
+ }
+};
+
+static void scic_sds_stp_request_started_pio_await_h2d_completion_enter(
+ struct sci_base_object *object)
+{
+ struct scic_sds_request *this_request = (struct scic_sds_request *)object;
+
+ SET_STATE_HANDLER(
+ this_request,
+ scic_sds_stp_request_started_pio_substate_handler_table,
+ SCIC_SDS_STP_REQUEST_STARTED_PIO_AWAIT_H2D_COMPLETION_SUBSTATE
+ );
+
+ scic_sds_remote_device_set_working_request(
+ this_request->target_device, this_request);
+}
+
+static void scic_sds_stp_request_started_pio_await_frame_enter(
+ struct sci_base_object *object)
+{
+ struct scic_sds_request *this_request = (struct scic_sds_request *)object;
+
+ SET_STATE_HANDLER(
+ this_request,
+ scic_sds_stp_request_started_pio_substate_handler_table,
+ SCIC_SDS_STP_REQUEST_STARTED_PIO_AWAIT_FRAME_SUBSTATE
+ );
+}
+
+static void scic_sds_stp_request_started_pio_data_in_await_data_enter(
+ struct sci_base_object *object)
+{
+ struct scic_sds_request *this_request = (struct scic_sds_request *)object;
+
+ SET_STATE_HANDLER(
+ this_request,
+ scic_sds_stp_request_started_pio_substate_handler_table,
+ SCIC_SDS_STP_REQUEST_STARTED_PIO_DATA_IN_AWAIT_DATA_SUBSTATE
+ );
+}
+
+static void scic_sds_stp_request_started_pio_data_out_transmit_data_enter(
+ struct sci_base_object *object)
+{
+ struct scic_sds_request *this_request = (struct scic_sds_request *)object;
+
+ SET_STATE_HANDLER(
+ this_request,
+ scic_sds_stp_request_started_pio_substate_handler_table,
+ SCIC_SDS_STP_REQUEST_STARTED_PIO_DATA_OUT_TRANSMIT_DATA_SUBSTATE
+ );
+}
+
+/* --------------------------------------------------------------------------- */
+
+const struct sci_base_state scic_sds_stp_request_started_pio_substate_table[] = {
+ [SCIC_SDS_STP_REQUEST_STARTED_PIO_AWAIT_H2D_COMPLETION_SUBSTATE] = {
+ .enter_state = scic_sds_stp_request_started_pio_await_h2d_completion_enter,
+ },
+ [SCIC_SDS_STP_REQUEST_STARTED_PIO_AWAIT_FRAME_SUBSTATE] = {
+ .enter_state = scic_sds_stp_request_started_pio_await_frame_enter,
+ },
+ [SCIC_SDS_STP_REQUEST_STARTED_PIO_DATA_IN_AWAIT_DATA_SUBSTATE] = {
+ .enter_state = scic_sds_stp_request_started_pio_data_in_await_data_enter,
+ },
+ [SCIC_SDS_STP_REQUEST_STARTED_PIO_DATA_OUT_TRANSMIT_DATA_SUBSTATE] = {
+ .enter_state = scic_sds_stp_request_started_pio_data_out_transmit_data_enter,
+ }
+};
+
+static void scic_sds_stp_request_udma_complete_request(
+ struct scic_sds_request *this_request,
+ u32 scu_status,
+ enum sci_status sci_status)
+{
+ scic_sds_request_set_status(
+ this_request, scu_status, sci_status
+ );
+
+ sci_base_state_machine_change_state(
+ &this_request->parent.state_machine,
+ SCI_BASE_REQUEST_STATE_COMPLETED
+ );
+}
+
+/**
+ *
+ * @this_request:
+ * @frame_index:
+ *
+ * enum sci_status
+ */
+static enum sci_status scic_sds_stp_request_udma_general_frame_handler(
+ struct scic_sds_request *this_request,
+ u32 frame_index)
+{
+ enum sci_status status;
+ struct sata_fis_header *frame_header;
+ u32 *frame_buffer;
+
+ status = scic_sds_unsolicited_frame_control_get_header(
+ &this_request->owning_controller->uf_control,
+ frame_index,
+ (void **)&frame_header
+ );
+
+ if (
+ (status == SCI_SUCCESS)
+ && (frame_header->fis_type == SATA_FIS_TYPE_REGD2H)
+ ) {
+ scic_sds_unsolicited_frame_control_get_buffer(
+ &this_request->owning_controller->uf_control,
+ frame_index,
+ (void **)&frame_buffer
+ );
+
+ scic_sds_controller_copy_sata_response(
+ &((struct scic_sds_stp_request *)this_request)->d2h_reg_fis,
+ (u32 *)frame_header,
+ frame_buffer
+ );
+ }
+
+ scic_sds_controller_release_frame(
+ this_request->owning_controller, frame_index);
+
+ return status;
+}
+
+/**
+ * This method process TC completions while in the state where we are waiting
+ * for TC completions.
+ * @this_request:
+ * @completion_code:
+ *
+ * enum sci_status
+ */
+static enum sci_status scic_sds_stp_request_udma_await_tc_completion_tc_completion_handler(
+ struct scic_sds_request *request,
+ u32 completion_code)
+{
+ enum sci_status status = SCI_SUCCESS;
+ struct scic_sds_stp_request *this_request = (struct scic_sds_stp_request *)request;
+
+ switch (SCU_GET_COMPLETION_TL_STATUS(completion_code)) {
+ case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_GOOD):
+ scic_sds_stp_request_udma_complete_request(
+ &this_request->parent, SCU_TASK_DONE_GOOD, SCI_SUCCESS
+ );
+ break;
+
+ case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_UNEXP_FIS):
+ case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_REG_ERR):
+ /*
+ * We must check ther response buffer to see if the D2H Register FIS was
+ * received before we got the TC completion. */
+ if (this_request->d2h_reg_fis.fis_type == SATA_FIS_TYPE_REGD2H) {
+ scic_sds_remote_device_suspend(
+ this_request->parent.target_device,
+ SCU_EVENT_SPECIFIC(SCU_NORMALIZE_COMPLETION_STATUS(completion_code))
+ );
+
+ scic_sds_stp_request_udma_complete_request(
+ &this_request->parent,
+ SCU_TASK_DONE_CHECK_RESPONSE,
+ SCI_FAILURE_IO_RESPONSE_VALID
+ );
+ } else {
+ /*
+ * If we have an error completion status for the TC then we can expect a
+ * D2H register FIS from the device so we must change state to wait for it */
+ sci_base_state_machine_change_state(
+ &this_request->parent.started_substate_machine,
+ SCIC_SDS_STP_REQUEST_STARTED_UDMA_AWAIT_D2H_REG_FIS_SUBSTATE
+ );
+ }
+ break;
+
+ /*
+ * / @todo Check to see if any of these completion status need to wait for
+ * / the device to host register fis. */
+ case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_INV_FIS_LEN):
+ case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_MAX_PLD_ERR):
+ case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_LL_R_ERR):
+ case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_CRC_ERR):
+ scic_sds_remote_device_suspend(
+ this_request->parent.target_device,
+ SCU_EVENT_SPECIFIC(SCU_NORMALIZE_COMPLETION_STATUS(completion_code))
+ );
+ /* Fall through to the default case */
+ default:
+ /* All other completion status cause the IO to be complete. */
+ scic_sds_stp_request_udma_complete_request(
+ &this_request->parent,
+ SCU_NORMALIZE_COMPLETION_STATUS(completion_code),
+ SCI_FAILURE_CONTROLLER_SPECIFIC_IO_ERR
+ );
+ break;
+ }
+
+ return status;
+}
+
+static enum sci_status scic_sds_stp_request_udma_await_d2h_reg_fis_frame_handler(
+ struct scic_sds_request *this_request,
+ u32 frame_index)
+{
+ enum sci_status status;
+
+ /* Use the general frame handler to copy the resposne data */
+ status = scic_sds_stp_request_udma_general_frame_handler(this_request, frame_index);
+
+ if (status == SCI_SUCCESS) {
+ scic_sds_stp_request_udma_complete_request(
+ this_request,
+ SCU_TASK_DONE_CHECK_RESPONSE,
+ SCI_FAILURE_IO_RESPONSE_VALID
+ );
+ }
+
+ return status;
+}
+
+/* --------------------------------------------------------------------------- */
+
+const struct scic_sds_io_request_state_handler scic_sds_stp_request_started_udma_substate_handler_table[] = {
+ [SCIC_SDS_STP_REQUEST_STARTED_UDMA_AWAIT_TC_COMPLETION_SUBSTATE] = {
+ .parent.start_handler = scic_sds_request_default_start_handler,
+ .parent.abort_handler = scic_sds_request_started_state_abort_handler,
+ .parent.complete_handler = scic_sds_request_default_complete_handler,
+ .parent.destruct_handler = scic_sds_request_default_destruct_handler,
+ .tc_completion_handler = scic_sds_stp_request_udma_await_tc_completion_tc_completion_handler,
+ .event_handler = scic_sds_request_default_event_handler,
+ .frame_handler = scic_sds_stp_request_udma_general_frame_handler,
+ },
+ [SCIC_SDS_STP_REQUEST_STARTED_UDMA_AWAIT_D2H_REG_FIS_SUBSTATE] = {
+ .parent.start_handler = scic_sds_request_default_start_handler,
+ .parent.abort_handler = scic_sds_request_started_state_abort_handler,
+ .parent.complete_handler = scic_sds_request_default_complete_handler,
+ .parent.destruct_handler = scic_sds_request_default_destruct_handler,
+ .tc_completion_handler = scic_sds_request_default_tc_completion_handler,
+ .event_handler = scic_sds_request_default_event_handler,
+ .frame_handler = scic_sds_stp_request_udma_await_d2h_reg_fis_frame_handler,
+ },
+};
+
+static void scic_sds_stp_request_started_udma_await_tc_completion_enter(
+ struct sci_base_object *object)
+{
+ struct scic_sds_request *this_request = (struct scic_sds_request *)object;
+
+ SET_STATE_HANDLER(
+ this_request,
+ scic_sds_stp_request_started_udma_substate_handler_table,
+ SCIC_SDS_STP_REQUEST_STARTED_UDMA_AWAIT_TC_COMPLETION_SUBSTATE
+ );
+}
+
+/**
+ *
+ *
+ * This state is entered when there is an TC completion failure. The hardware
+ * received an unexpected condition while processing the IO request and now
+ * will UF the D2H register FIS to complete the IO.
+ */
+static void scic_sds_stp_request_started_udma_await_d2h_reg_fis_enter(
+ struct sci_base_object *object)
+{
+ struct scic_sds_request *this_request = (struct scic_sds_request *)object;
+
+ SET_STATE_HANDLER(
+ this_request,
+ scic_sds_stp_request_started_udma_substate_handler_table,
+ SCIC_SDS_STP_REQUEST_STARTED_UDMA_AWAIT_D2H_REG_FIS_SUBSTATE
+ );
+}
+
+/* --------------------------------------------------------------------------- */
+
+const struct sci_base_state scic_sds_stp_request_started_udma_substate_table[] = {
+ [SCIC_SDS_STP_REQUEST_STARTED_UDMA_AWAIT_TC_COMPLETION_SUBSTATE] = {
+ .enter_state = scic_sds_stp_request_started_udma_await_tc_completion_enter,
+ },
+ [SCIC_SDS_STP_REQUEST_STARTED_UDMA_AWAIT_D2H_REG_FIS_SUBSTATE] = {
+ .enter_state = scic_sds_stp_request_started_udma_await_d2h_reg_fis_enter,
+ },
+};
+
+/**
+ *
+ * @this_request:
+ * @completion_code:
+ *
+ * This method processes a TC completion. The expected TC completion is for
+ * the transmission of the H2D register FIS containing the SATA/STP non-data
+ * request. This method always successfully processes the TC completion.
+ * SCI_SUCCESS This value is always returned.
+ */
+static enum sci_status scic_sds_stp_request_soft_reset_await_h2d_asserted_tc_completion_handler(
+ struct scic_sds_request *this_request,
+ u32 completion_code)
+{
+ switch (SCU_GET_COMPLETION_TL_STATUS(completion_code)) {
+ case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_GOOD):
+ scic_sds_request_set_status(
+ this_request, SCU_TASK_DONE_GOOD, SCI_SUCCESS
+ );
+
+ sci_base_state_machine_change_state(
+ &this_request->started_substate_machine,
+ SCIC_SDS_STP_REQUEST_STARTED_SOFT_RESET_AWAIT_H2D_DIAGNOSTIC_COMPLETION_SUBSTATE
+ );
+ break;
+
+ default:
+ /*
+ * All other completion status cause the IO to be complete. If a NAK
+ * was received, then it is up to the user to retry the request. */
+ scic_sds_request_set_status(
+ this_request,
+ SCU_NORMALIZE_COMPLETION_STATUS(completion_code),
+ SCI_FAILURE_CONTROLLER_SPECIFIC_IO_ERR
+ );
+
+ sci_base_state_machine_change_state(
+ &this_request->parent.state_machine, SCI_BASE_REQUEST_STATE_COMPLETED
+ );
+ break;
+ }
+
+ return SCI_SUCCESS;
+}
+
+/**
+ *
+ * @this_request:
+ * @completion_code:
+ *
+ * This method processes a TC completion. The expected TC completion is for
+ * the transmission of the H2D register FIS containing the SATA/STP non-data
+ * request. This method always successfully processes the TC completion.
+ * SCI_SUCCESS This value is always returned.
+ */
+static enum sci_status scic_sds_stp_request_soft_reset_await_h2d_diagnostic_tc_completion_handler(
+ struct scic_sds_request *this_request,
+ u32 completion_code)
+{
+ switch (SCU_GET_COMPLETION_TL_STATUS(completion_code)) {
+ case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_GOOD):
+ scic_sds_request_set_status(
+ this_request, SCU_TASK_DONE_GOOD, SCI_SUCCESS
+ );
+
+ sci_base_state_machine_change_state(
+ &this_request->started_substate_machine,
+ SCIC_SDS_STP_REQUEST_STARTED_SOFT_RESET_AWAIT_D2H_RESPONSE_FRAME_SUBSTATE
+ );
+ break;
+
+ default:
+ /*
+ * All other completion status cause the IO to be complete. If a NAK
+ * was received, then it is up to the user to retry the request. */
+ scic_sds_request_set_status(
+ this_request,
+ SCU_NORMALIZE_COMPLETION_STATUS(completion_code),
+ SCI_FAILURE_CONTROLLER_SPECIFIC_IO_ERR
+ );
+
+ sci_base_state_machine_change_state(
+ &this_request->parent.state_machine, SCI_BASE_REQUEST_STATE_COMPLETED
+ );
+ break;
+ }
+
+ return SCI_SUCCESS;
+}
+
+/**
+ *
+ * @request: This parameter specifies the request for which a frame has been
+ * received.
+ * @frame_index: This parameter specifies the index of the frame that has been
+ * received.
+ *
+ * This method processes frames received from the target while waiting for a
+ * device to host register FIS. If a non-register FIS is received during this
+ * time, it is treated as a protocol violation from an IO perspective. Indicate
+ * if the received frame was processed successfully.
+ */
+static enum sci_status scic_sds_stp_request_soft_reset_await_d2h_frame_handler(
+ struct scic_sds_request *request,
+ u32 frame_index)
+{
+ enum sci_status status;
+ struct sata_fis_header *frame_header;
+ u32 *frame_buffer;
+ struct scic_sds_stp_request *this_request = (struct scic_sds_stp_request *)request;
+
+ status = scic_sds_unsolicited_frame_control_get_header(
+ &(this_request->parent.owning_controller->uf_control),
+ frame_index,
+ (void **)&frame_header
+ );
+
+ if (status == SCI_SUCCESS) {
+ switch (frame_header->fis_type) {
+ case SATA_FIS_TYPE_REGD2H:
+ scic_sds_unsolicited_frame_control_get_buffer(
+ &(this_request->parent.owning_controller->uf_control),
+ frame_index,
+ (void **)&frame_buffer
+ );
+
+ scic_sds_controller_copy_sata_response(
+ &this_request->d2h_reg_fis, (u32 *)frame_header, frame_buffer
+ );
+
+ /* The command has completed with error */
+ scic_sds_request_set_status(
+ &this_request->parent,
+ SCU_TASK_DONE_CHECK_RESPONSE,
+ SCI_FAILURE_IO_RESPONSE_VALID
+ );
+ break;
+
+ default:
+ dev_warn(scic_to_dev(request->owning_controller),
+ "%s: IO Request:0x%p Frame Id:%d protocol "
+ "violation occurred\n",
+ __func__,
+ this_request,
+ frame_index);
+
+ scic_sds_request_set_status(
+ &this_request->parent,
+ SCU_TASK_DONE_UNEXP_FIS,
+ SCI_FAILURE_PROTOCOL_VIOLATION
+ );
+ break;
+ }
+
+ sci_base_state_machine_change_state(
+ &this_request->parent.parent.state_machine,
+ SCI_BASE_REQUEST_STATE_COMPLETED
+ );
+
+ /* Frame has been decoded return it to the controller */
+ scic_sds_controller_release_frame(
+ this_request->parent.owning_controller, frame_index
+ );
+ } else
+ dev_err(scic_to_dev(request->owning_controller),
+ "%s: SCIC IO Request 0x%p could not get frame header "
+ "for frame index %d, status %x\n",
+ __func__, this_request, frame_index, status);
+
+ return status;
+}
+
+/* --------------------------------------------------------------------------- */
+
+const struct scic_sds_io_request_state_handler scic_sds_stp_request_started_soft_reset_substate_handler_table[] = {
+ [SCIC_SDS_STP_REQUEST_STARTED_SOFT_RESET_AWAIT_H2D_ASSERTED_COMPLETION_SUBSTATE] = {
+ .parent.start_handler = scic_sds_request_default_start_handler,
+ .parent.abort_handler = scic_sds_request_started_state_abort_handler,
+ .parent.complete_handler = scic_sds_request_default_complete_handler,
+ .parent.destruct_handler = scic_sds_request_default_destruct_handler,
+ .tc_completion_handler = scic_sds_stp_request_soft_reset_await_h2d_asserted_tc_completion_handler,
+ .event_handler = scic_sds_request_default_event_handler,
+ .frame_handler = scic_sds_request_default_frame_handler,
+ },
+ [SCIC_SDS_STP_REQUEST_STARTED_SOFT_RESET_AWAIT_H2D_DIAGNOSTIC_COMPLETION_SUBSTATE] = {
+ .parent.start_handler = scic_sds_request_default_start_handler,
+ .parent.abort_handler = scic_sds_request_started_state_abort_handler,
+ .parent.complete_handler = scic_sds_request_default_complete_handler,
+ .parent.destruct_handler = scic_sds_request_default_destruct_handler,
+ .tc_completion_handler = scic_sds_stp_request_soft_reset_await_h2d_diagnostic_tc_completion_handler,
+ .event_handler = scic_sds_request_default_event_handler,
+ .frame_handler = scic_sds_request_default_frame_handler,
+ },
+ [SCIC_SDS_STP_REQUEST_STARTED_SOFT_RESET_AWAIT_D2H_RESPONSE_FRAME_SUBSTATE] = {
+ .parent.start_handler = scic_sds_request_default_start_handler,
+ .parent.abort_handler = scic_sds_request_started_state_abort_handler,
+ .parent.complete_handler = scic_sds_request_default_complete_handler,
+ .parent.destruct_handler = scic_sds_request_default_destruct_handler,
+ .tc_completion_handler = scic_sds_request_default_tc_completion_handler,
+ .event_handler = scic_sds_request_default_event_handler,
+ .frame_handler = scic_sds_stp_request_soft_reset_await_d2h_frame_handler,
+ },
+};
+
+static void scic_sds_stp_request_started_soft_reset_await_h2d_asserted_completion_enter(
+ struct sci_base_object *object)
+{
+ struct scic_sds_request *this_request = (struct scic_sds_request *)object;
+
+ SET_STATE_HANDLER(
+ this_request,
+ scic_sds_stp_request_started_soft_reset_substate_handler_table,
+ SCIC_SDS_STP_REQUEST_STARTED_SOFT_RESET_AWAIT_H2D_ASSERTED_COMPLETION_SUBSTATE
+ );
+
+ scic_sds_remote_device_set_working_request(
+ this_request->target_device, this_request
+ );
+}
+
+static void scic_sds_stp_request_started_soft_reset_await_h2d_diagnostic_completion_enter(
+ struct sci_base_object *object)
+{
+ struct scic_sds_request *this_request = (struct scic_sds_request *)object;
+ sci_base_controller_request_handler_t continue_io;
+ struct scu_task_context *task_context;
+ struct sata_fis_reg_h2d *h2d_fis;
+ struct scic_sds_controller *scic;
+ enum sci_status status;
+ u32 state;
+
+ /* Clear the SRST bit */
+ h2d_fis = scic_stp_io_request_get_h2d_reg_address(this_request);
+ h2d_fis->control = 0;
+
+ /* Clear the TC control bit */
+ task_context = scic_sds_controller_get_task_context_buffer(
+ this_request->owning_controller, this_request->io_tag);
+ task_context->control_frame = 0;
+
+ scic = this_request->owning_controller;
+ state = scic->parent.state_machine.current_state_id;
+ continue_io = scic_sds_controller_state_handler_table[state].base.continue_io;
+
+ status = continue_io(&scic->parent, &this_request->target_device->parent,
+ &this_request->parent);
+
+ if (status == SCI_SUCCESS) {
+ SET_STATE_HANDLER(
+ this_request,
+ scic_sds_stp_request_started_soft_reset_substate_handler_table,
+ SCIC_SDS_STP_REQUEST_STARTED_SOFT_RESET_AWAIT_H2D_DIAGNOSTIC_COMPLETION_SUBSTATE
+ );
+ }
+}
+
+static void scic_sds_stp_request_started_soft_reset_await_d2h_response_enter(
+ struct sci_base_object *object)
+{
+ struct scic_sds_request *this_request = (struct scic_sds_request *)object;
+
+ SET_STATE_HANDLER(
+ this_request,
+ scic_sds_stp_request_started_soft_reset_substate_handler_table,
+ SCIC_SDS_STP_REQUEST_STARTED_SOFT_RESET_AWAIT_D2H_RESPONSE_FRAME_SUBSTATE
+ );
+}
+
+/* --------------------------------------------------------------------------- */
+
+const struct sci_base_state scic_sds_stp_request_started_soft_reset_substate_table[] = {
+ [SCIC_SDS_STP_REQUEST_STARTED_SOFT_RESET_AWAIT_H2D_ASSERTED_COMPLETION_SUBSTATE] = {
+ .enter_state = scic_sds_stp_request_started_soft_reset_await_h2d_asserted_completion_enter,
+ },
+ [SCIC_SDS_STP_REQUEST_STARTED_SOFT_RESET_AWAIT_H2D_DIAGNOSTIC_COMPLETION_SUBSTATE] = {
+ .enter_state = scic_sds_stp_request_started_soft_reset_await_h2d_diagnostic_completion_enter,
+ },
+ [SCIC_SDS_STP_REQUEST_STARTED_SOFT_RESET_AWAIT_D2H_RESPONSE_FRAME_SUBSTATE] = {
+ .enter_state = scic_sds_stp_request_started_soft_reset_await_d2h_response_enter,
+ },
+};
+
diff --git a/drivers/scsi/isci/core/scic_sds_stp_request.h b/drivers/scsi/isci/core/scic_sds_stp_request.h
new file mode 100644
index 000000000000..5578d2baf7ca
--- /dev/null
+++ b/drivers/scsi/isci/core/scic_sds_stp_request.h
@@ -0,0 +1,221 @@
+/*
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Intel Corporation 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
+ * OWNER 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.
+ */
+
+#ifndef _SCIC_SDS_STP_REQUEST_T_
+#define _SCIC_SDS_STP_REQUEST_T_
+
+#include "intel_sata.h"
+#include "sci_types.h"
+#include "scic_sds_request.h"
+
+/**
+ * This structure represents the additional information that is required to
+ * handle SATA PIO requests.
+ *
+ *
+ */
+struct scic_sds_stp_request {
+ struct scic_sds_request parent;
+
+ struct sata_fis_reg_d2h d2h_reg_fis;
+
+ union {
+ u32 ncq;
+
+ u32 udma;
+
+ struct {
+ /**
+ * Total transfer for the entire PIO request recorded at request constuction
+ * time.
+ *
+ * @todo Should we just decrement this value for each byte of data transitted
+ * or received to elemenate the current_transfer_bytes field?
+ */
+ u32 total_transfer_bytes;
+
+ /**
+ * Total number of bytes received/transmitted in data frames since the start
+ * of the IO request. At the end of the IO request this should equal the
+ * total_transfer_bytes.
+ */
+ u32 current_transfer_bytes;
+
+ /**
+ * The number of bytes requested in the in the PIO setup.
+ */
+ u32 pio_transfer_bytes;
+
+ /**
+ * PIO Setup ending status value to tell us if we need to wait for another FIS
+ * or if the transfer is complete. On the receipt of a D2H FIS this will be
+ * the status field of that FIS.
+ */
+ u8 ending_status;
+
+ /**
+ * On receipt of a D2H FIS this will be the ending error field if the
+ * ending_status has the SATA_STATUS_ERR bit set.
+ */
+ u8 ending_error;
+
+ /**
+ * Protocol Type. This is filled in by core during IO Request construction type.
+ */
+ u8 sat_protocol;
+
+ struct {
+ struct scu_sgl_element_pair *sgl_pair;
+ u8 sgl_set;
+ u32 sgl_offset;
+ } request_current;
+ } pio;
+
+ struct {
+ /**
+ * The number of bytes requested in the PIO setup before CDB data frame.
+ */
+ u32 device_preferred_cdb_length;
+ } packet;
+ } type;
+
+};
+
+/**
+ * enum SCIC_SDS_STP_REQUEST_STARTED_UDMA_SUBSTATES - This enumeration depicts
+ * the various sub-states associated with a SATA/STP UDMA protocol operation.
+ *
+ *
+ */
+enum SCIC_SDS_STP_REQUEST_STARTED_UDMA_SUBSTATES {
+ SCIC_SDS_STP_REQUEST_STARTED_UDMA_AWAIT_TC_COMPLETION_SUBSTATE,
+ SCIC_SDS_STP_REQUEST_STARTED_UDMA_AWAIT_D2H_REG_FIS_SUBSTATE,
+};
+
+/**
+ * enum SCIC_SDS_STP_REQUEST_STARTED_NON_DATA_SUBSTATES - This enumeration
+ * depicts the various sub-states associated with a SATA/STP non-data
+ * protocol operation.
+ *
+ *
+ */
+enum SCIC_SDS_STP_REQUEST_STARTED_NON_DATA_SUBSTATES {
+ SCIC_SDS_STP_REQUEST_STARTED_NON_DATA_AWAIT_H2D_COMPLETION_SUBSTATE,
+ SCIC_SDS_STP_REQUEST_STARTED_NON_DATA_AWAIT_D2H_SUBSTATE,
+};
+
+/**
+ * enum SCIC_SDS_STP_REQUEST_STARTED_SOFT_RESET_SUBSTATES - THis enumeration
+ * depicts the various sub-states associated with a SATA/STP soft reset
+ * operation.
+ *
+ *
+ */
+enum SCIC_SDS_STP_REQUEST_STARTED_SOFT_RESET_SUBSTATES {
+ SCIC_SDS_STP_REQUEST_STARTED_SOFT_RESET_AWAIT_H2D_ASSERTED_COMPLETION_SUBSTATE,
+ SCIC_SDS_STP_REQUEST_STARTED_SOFT_RESET_AWAIT_H2D_DIAGNOSTIC_COMPLETION_SUBSTATE,
+ SCIC_SDS_STP_REQUEST_STARTED_SOFT_RESET_AWAIT_D2H_RESPONSE_FRAME_SUBSTATE,
+};
+
+extern const struct scic_sds_io_request_state_handler scic_sds_stp_request_started_udma_substate_handler_table[];
+
+extern const struct sci_base_state scic_sds_stp_request_started_udma_substate_table[];
+
+extern const struct scic_sds_io_request_state_handler scic_sds_stp_request_started_non_data_substate_handler_table[];
+
+extern const struct sci_base_state scic_sds_stp_request_started_non_data_substate_table[];
+
+extern const struct scic_sds_io_request_state_handler scic_sds_stp_request_started_soft_reset_substate_handler_table[];
+
+extern const struct sci_base_state scic_sds_stp_request_started_soft_reset_substate_table[];
+
+/* --------------------------------------------------------------------------- */
+
+u32 scic_sds_stp_request_get_object_size(void);
+
+
+void scic_sds_stp_non_ncq_request_construct(
+ struct scic_sds_request *this_request);
+
+enum sci_status scic_sds_stp_pio_request_construct(
+ struct scic_sds_request *scic_io_request,
+ u8 sat_protocol,
+ bool copy_rx_frame);
+
+enum sci_status scic_sds_stp_pio_request_construct_pass_through(
+ struct scic_sds_request *scic_io_request,
+ struct scic_stp_passthru_request_callbacks *passthru_cb);
+
+enum sci_status scic_sds_stp_udma_request_construct(
+ struct scic_sds_request *this_request,
+ u32 transfer_length,
+ SCI_IO_REQUEST_DATA_DIRECTION data_direction);
+
+enum sci_status scic_sds_stp_non_data_request_construct(
+ struct scic_sds_request *this_request);
+
+enum sci_status scic_sds_stp_soft_reset_request_construct(
+ struct scic_sds_request *this_request);
+
+enum sci_status scic_sds_stp_ncq_request_construct(
+ struct scic_sds_request *this_request,
+ u32 transfer_length,
+ SCI_IO_REQUEST_DATA_DIRECTION data_direction);
+
+void scu_stp_raw_request_construct_task_context(
+ struct scic_sds_stp_request *this_request,
+ struct scu_task_context *task_context);
+
+#endif /* _SCIC_SDS_STP_REQUEST_T_ */
diff --git a/drivers/scsi/isci/core/scic_sds_unsolicited_frame_control.c b/drivers/scsi/isci/core/scic_sds_unsolicited_frame_control.c
new file mode 100644
index 000000000000..7ca2f1709f6d
--- /dev/null
+++ b/drivers/scsi/isci/core/scic_sds_unsolicited_frame_control.c
@@ -0,0 +1,379 @@
+/*
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Intel Corporation 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
+ * OWNER 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.
+ */
+
+/**
+ * This file contains the implementation of the
+ * struct scic_sds_unsolicited_frame_control object and it's public, protected, and
+ * private methods.
+ *
+ *
+ */
+
+#include "scic_sds_unsolicited_frame_control.h"
+#include "scu_registers.h"
+#include "scic_sds_controller.h"
+#include "scic_user_callback.h"
+#include "sci_util.h"
+#include "sci_environment.h"
+
+/**
+ * The UF buffer address table size must be programmed to a power of 2. Find
+ * the first power of 2 that is equal to or greater then the number of
+ * unsolicited frame buffers to be utilized.
+ * @uf_control: This parameter specifies the UF control object for which to
+ * update the address table count.
+ *
+ */
+void scic_sds_unsolicited_frame_control_set_address_table_count(
+ struct scic_sds_unsolicited_frame_control *uf_control)
+{
+ uf_control->address_table.count = SCU_MIN_UF_TABLE_ENTRIES;
+ while (
+ (uf_control->address_table.count < uf_control->buffers.count)
+ && (uf_control->address_table.count < SCU_ABSOLUTE_MAX_UNSOLICITED_FRAMES)
+ ) {
+ uf_control->address_table.count <<= 1;
+ }
+}
+
+/**
+ * This method will program the unsolicited frames (UFs) into the UF address
+ * table and construct the UF frame structure being modeled in the core. It
+ * will handle the case where some of the UFs are not being used and thus
+ * should have entries programmed to zero in the address table.
+ * @uf_control: This parameter specifies the unsolicted frame control object
+ * for which to construct the unsolicited frames objects.
+ * @uf_buffer_phys_address: This parameter specifies the physical address for
+ * the first unsolicited frame buffer.
+ * @uf_buffer_virt_address: This parameter specifies the virtual address for
+ * the first unsolicited frame buffer.
+ * @unused_uf_header_entries: This parameter specifies the number of unused UF
+ * headers. This value can be non-zero when there are a non-power of 2
+ * number of unsolicited frames being supported.
+ * @used_uf_header_entries: This parameter specifies the number of actually
+ * utilized UF headers.
+ *
+ */
+static void scic_sds_unsolicited_frame_control_construct_frames(
+ struct scic_sds_unsolicited_frame_control *uf_control,
+ dma_addr_t uf_buffer_phys_address,
+ unsigned long uf_buffer_virt_address,
+ u32 unused_uf_header_entries,
+ u32 used_uf_header_entries)
+{
+ u32 index;
+ struct scic_sds_unsolicited_frame *uf;
+
+ /*
+ * Program the unused buffers into the UF address table and the
+ * controller's array of UFs. */
+ for (index = 0; index < unused_uf_header_entries; index++) {
+ uf = &uf_control->buffers.array[index];
+
+ sci_cb_make_physical_address(
+ uf_control->address_table.array[index], 0, 0
+ );
+ uf->buffer = NULL;
+ uf->header = &uf_control->headers.array[index];
+ uf->state = UNSOLICITED_FRAME_EMPTY;
+ }
+
+ /*
+ * Program the actual used UF buffers into the UF address table and
+ * the controller's array of UFs. */
+ for (index = unused_uf_header_entries;
+ index < unused_uf_header_entries + used_uf_header_entries;
+ index++) {
+ uf = &uf_control->buffers.array[index];
+
+ uf_control->address_table.array[index] = uf_buffer_phys_address;
+
+ uf->buffer = (void *)uf_buffer_virt_address;
+ uf->header = &uf_control->headers.array[index];
+ uf->state = UNSOLICITED_FRAME_EMPTY;
+
+ /*
+ * Increment the address of the physical and virtual memory pointers
+ * Everything is aligned on 1k boundary with an increment of 1k */
+ uf_buffer_virt_address += SCU_UNSOLICITED_FRAME_BUFFER_SIZE;
+ sci_physical_address_add(
+ uf_buffer_phys_address, SCU_UNSOLICITED_FRAME_BUFFER_SIZE
+ );
+ }
+}
+
+/**
+ * This method constructs the various members of the unsolicted frame control
+ * object (buffers, headers, address, table, etc).
+ * @uf_control: This parameter specifies the unsolicited frame control object
+ * to construct.
+ * @mde: This parameter specifies the memory descriptor from which to derive
+ * all of the address information needed to get the unsolicited frame
+ * functionality working.
+ * @controller: This parameter specifies the controller object associated with
+ * the uf_control being constructed.
+ *
+ */
+void scic_sds_unsolicited_frame_control_construct(
+ struct scic_sds_unsolicited_frame_control *uf_control,
+ struct sci_physical_memory_descriptor *mde,
+ struct scic_sds_controller *controller)
+{
+ u32 unused_uf_header_entries;
+ u32 used_uf_header_entries;
+ u32 used_uf_buffer_bytes;
+ u32 unused_uf_header_bytes;
+ u32 used_uf_header_bytes;
+ dma_addr_t uf_buffer_phys_address;
+
+ /*
+ * Prepare all of the memory sizes for the UF headers, UF address
+ * table, and UF buffers themselves. */
+ used_uf_buffer_bytes = uf_control->buffers.count
+ * SCU_UNSOLICITED_FRAME_BUFFER_SIZE;
+ unused_uf_header_entries = uf_control->address_table.count
+ - uf_control->buffers.count;
+ used_uf_header_entries = uf_control->buffers.count;
+ unused_uf_header_bytes = unused_uf_header_entries
+ * sizeof(struct scu_unsolicited_frame_header);
+ used_uf_header_bytes = used_uf_header_entries
+ * sizeof(struct scu_unsolicited_frame_header);
+
+ /*
+ * The Unsolicited Frame buffers are set at the start of the UF
+ * memory descriptor entry. The headers and address table will be
+ * placed after the buffers. */
+ uf_buffer_phys_address = mde->physical_address;
+
+ /*
+ * Program the location of the UF header table into the SCU.
+ * Notes:
+ * - The address must align on a 64-byte boundary. Guaranteed to be
+ * on 64-byte boundary already 1KB boundary for unsolicited frames.
+ * - Program unused header entries to overlap with the last
+ * unsolicited frame. The silicon will never DMA to these unused
+ * headers, since we program the UF address table pointers to
+ * NULL. */
+ uf_control->headers.physical_address = uf_buffer_phys_address;
+ sci_physical_address_add(
+ uf_control->headers.physical_address, used_uf_buffer_bytes);
+ sci_physical_address_subtract(
+ uf_control->headers.physical_address, unused_uf_header_bytes);
+ uf_control->headers.array
+ = (struct scu_unsolicited_frame_header *)
+ scic_cb_get_virtual_address(
+ controller, uf_control->headers.physical_address
+ );
+
+ /*
+ * Program the location of the UF address table into the SCU.
+ * Notes:
+ * - The address must align on a 64-bit boundary. Guaranteed to be on 64
+ * byte boundary already due to above programming headers being on a
+ * 64-bit boundary and headers are on a 64-bytes in size. */
+ uf_control->address_table.physical_address = uf_buffer_phys_address;
+ sci_physical_address_add(
+ uf_control->address_table.physical_address, used_uf_buffer_bytes);
+ sci_physical_address_add(
+ uf_control->address_table.physical_address, used_uf_header_bytes);
+ uf_control->address_table.array
+ = (dma_addr_t *)
+ scic_cb_get_virtual_address(
+ controller, uf_control->address_table.physical_address
+ );
+
+ uf_control->get = 0;
+
+ /*
+ * UF buffer requirements are:
+ * - The last entry in the UF queue is not NULL.
+ * - There is a power of 2 number of entries (NULL or not-NULL)
+ * programmed into the queue.
+ * - Aligned on a 1KB boundary. */
+
+ /*
+ * If the user provided less then the maximum amount of memory,
+ * then be sure that we programm the first entries in the UF
+ * address table to NULL. */
+ scic_sds_unsolicited_frame_control_construct_frames(
+ uf_control,
+ uf_buffer_phys_address,
+ (unsigned long)mde->virtual_address,
+ unused_uf_header_entries,
+ used_uf_header_entries
+ );
+}
+
+/**
+ * This method returns the frame header for the specified frame index.
+ * @uf_control:
+ * @frame_index:
+ * @frame_header:
+ *
+ * enum sci_status
+ */
+enum sci_status scic_sds_unsolicited_frame_control_get_header(
+ struct scic_sds_unsolicited_frame_control *uf_control,
+ u32 frame_index,
+ void **frame_header)
+{
+ if (frame_index < uf_control->address_table.count) {
+ /*
+ * Skip the first word in the frame since this is a controll word used
+ * by the hardware. */
+ *frame_header = &uf_control->buffers.array[frame_index].header->data;
+
+ return SCI_SUCCESS;
+ }
+
+ return SCI_FAILURE_INVALID_PARAMETER_VALUE;
+}
+
+/**
+ * This method returns the frame buffer for the specified frame index.
+ * @uf_control:
+ * @frame_index:
+ * @frame_buffer:
+ *
+ * enum sci_status
+ */
+enum sci_status scic_sds_unsolicited_frame_control_get_buffer(
+ struct scic_sds_unsolicited_frame_control *uf_control,
+ u32 frame_index,
+ void **frame_buffer)
+{
+ if (frame_index < uf_control->address_table.count) {
+ *frame_buffer = uf_control->buffers.array[frame_index].buffer;
+
+ return SCI_SUCCESS;
+ }
+
+ return SCI_FAILURE_INVALID_PARAMETER_VALUE;
+}
+
+/**
+ * This method releases the frame once this is done the frame is available for
+ * re-use by the hardware. The data contained in the frame header and frame
+ * buffer is no longer valid.
+ * @uf_control: This parameter specifies the UF control object
+ * @frame_index: This parameter specifies the frame index to attempt to release.
+ *
+ * This method returns an indication to the caller as to whether the
+ * unsolicited frame get pointer should be updated. true This value indicates
+ * the unsolicited frame get pointer should be updated (i.e. write
+ * SCU_UFQGP_WRITE). false This value indicates the get pointer should not be
+ * updated.
+ */
+bool scic_sds_unsolicited_frame_control_release_frame(
+ struct scic_sds_unsolicited_frame_control *uf_control,
+ u32 frame_index)
+{
+ u32 frame_get;
+ u32 frame_cycle;
+
+ frame_get = uf_control->get & (uf_control->address_table.count - 1);
+ frame_cycle = uf_control->get & uf_control->address_table.count;
+
+ /*
+ * In the event there are NULL entries in the UF table, we need to
+ * advance the get pointer in order to find out if this frame should
+ * be released (i.e. update the get pointer). */
+ while (((lower_32_bits(uf_control->address_table.array[frame_get])
+ == 0) &&
+ (upper_32_bits(uf_control->address_table.array[frame_get])
+ == 0)) &&
+ (frame_get < uf_control->address_table.count))
+ frame_get++;
+
+ /*
+ * The table has a NULL entry as it's last element. This is
+ * illegal. */
+ BUG_ON(frame_get >= uf_control->address_table.count);
+
+ if (frame_index < uf_control->address_table.count) {
+ uf_control->buffers.array[frame_index].state = UNSOLICITED_FRAME_RELEASED;
+
+ /*
+ * The frame index is equal to the current get pointer so we
+ * can now free up all of the frame entries that */
+ if (frame_get == frame_index) {
+ while (
+ uf_control->buffers.array[frame_get].state
+ == UNSOLICITED_FRAME_RELEASED
+ ) {
+ uf_control->buffers.array[frame_get].state = UNSOLICITED_FRAME_EMPTY;
+
+ INCREMENT_QUEUE_GET(
+ frame_get,
+ frame_cycle,
+ uf_control->address_table.count - 1,
+ uf_control->address_table.count
+ );
+ }
+
+ uf_control->get =
+ (SCU_UFQGP_GEN_BIT(ENABLE_BIT) | frame_cycle | frame_get);
+
+ return true;
+ } else {
+ /*
+ * Frames remain in use until we advance the get pointer
+ * so there is nothing we can do here */
+ }
+ }
+
+ return false;
+}
+
diff --git a/drivers/scsi/isci/core/scic_sds_unsolicited_frame_control.h b/drivers/scsi/isci/core/scic_sds_unsolicited_frame_control.h
new file mode 100644
index 000000000000..49db83faac37
--- /dev/null
+++ b/drivers/scsi/isci/core/scic_sds_unsolicited_frame_control.h
@@ -0,0 +1,286 @@
+/*
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Intel Corporation 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
+ * OWNER 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.
+ */
+
+/**
+ * This file contains all of the unsolicited frame related management for the
+ * address table, the headers, and actual payload buffers.
+ *
+ *
+ */
+
+#ifndef _SCIC_SDS_UNSOLICITED_FRAME_CONTROL_H_
+#define _SCIC_SDS_UNSOLICITED_FRAME_CONTROL_H_
+
+#include "scu_unsolicited_frame.h"
+#include "sci_memory_descriptor_list.h"
+#include "scu_constants.h"
+#include "sci_status.h"
+
+/**
+ * enum UNSOLICITED_FRAME_STATE -
+ *
+ * This enumeration represents the current unsolicited frame state. The
+ * controller object can not updtate the hardware unsolicited frame put pointer
+ * unless it has already processed the priror unsolicited frames.
+ */
+enum UNSOLICITED_FRAME_STATE {
+ /**
+ * This state is when the frame is empty and not in use. It is
+ * different from the released state in that the hardware could DMA
+ * data to this frame buffer.
+ */
+ UNSOLICITED_FRAME_EMPTY,
+
+ /**
+ * This state is set when the frame buffer is in use by by some
+ * object in the system.
+ */
+ UNSOLICITED_FRAME_IN_USE,
+
+ /**
+ * This state is set when the frame is returned to the free pool
+ * but one or more frames prior to this one are still in use.
+ * Once all of the frame before this one are freed it will go to
+ * the empty state.
+ */
+ UNSOLICITED_FRAME_RELEASED,
+
+ UNSOLICITED_FRAME_MAX_STATES
+};
+
+/**
+ * struct scic_sds_unsolicited_frame -
+ *
+ * This is the unsolicited frame data structure it acts as the container for
+ * the current frame state, frame header and frame buffer.
+ */
+struct scic_sds_unsolicited_frame {
+ /**
+ * This field contains the current frame state
+ */
+ enum UNSOLICITED_FRAME_STATE state;
+
+ /**
+ * This field points to the frame header data.
+ */
+ struct scu_unsolicited_frame_header *header;
+
+ /**
+ * This field points to the frame buffer data.
+ */
+ void *buffer;
+
+};
+
+/**
+ * struct scic_sds_uf_header_array -
+ *
+ * This structure contains all of the unsolicited frame header information.
+ */
+struct scic_sds_uf_header_array {
+ /**
+ * This field is represents a virtual pointer to the start
+ * address of the UF address table. The table contains
+ * 64-bit pointers as required by the hardware.
+ */
+ struct scu_unsolicited_frame_header *array;
+
+ /**
+ * This field specifies the physical address location for the UF
+ * buffer array.
+ */
+ dma_addr_t physical_address;
+
+};
+
+/*
+ * Determine the size of the unsolicited frame array including
+ * unused buffers. */
+#if SCU_UNSOLICITED_FRAME_COUNT <= SCU_MIN_UF_TABLE_ENTRIES
+#define SCU_UNSOLICITED_FRAME_CONTROL_ARRAY_SIZE SCU_MIN_UF_TABLE_ENTRIES
+#else
+#define SCU_UNSOLICITED_FRAME_CONTROL_ARRAY_SIZE SCU_MAX_UNSOLICITED_FRAMES
+#endif /* SCU_UNSOLICITED_FRAME_COUNT <= SCU_MIN_UF_TABLE_ENTRIES */
+
+/**
+ * struct scic_sds_uf_buffer_array -
+ *
+ * This structure contains all of the unsolicited frame buffer (actual payload)
+ * information.
+ */
+struct scic_sds_uf_buffer_array {
+ /**
+ * This field is the minimum number of unsolicited frames supported by the
+ * hardware and the number of unsolicited frames requested by the software.
+ */
+ u32 count;
+
+ /**
+ * This field is the SCIC_UNSOLICITED_FRAME data its used to manage
+ * the data for the unsolicited frame requests. It also represents
+ * the virtual address location that corresponds to the
+ * physical_address field.
+ */
+ struct scic_sds_unsolicited_frame array[SCU_UNSOLICITED_FRAME_CONTROL_ARRAY_SIZE];
+
+ /**
+ * This field specifies the physical address location for the UF
+ * buffer array.
+ */
+ dma_addr_t physical_address;
+
+};
+
+/**
+ * struct scic_sds_uf_address_table_array -
+ *
+ * This object maintains all of the unsolicited frame address table specific
+ * data. The address table is a collection of 64-bit pointers that point to
+ * 1KB buffers into which the silicon will DMA unsolicited frames.
+ */
+struct scic_sds_uf_address_table_array {
+ /**
+ * This field specifies the actual programmed size of the
+ * unsolicited frame buffer address table. The size of the table
+ * can be larger than the actual number of UF buffers, but it must
+ * be a power of 2 and the last entry in the table is not allowed
+ * to be NULL.
+ */
+ u32 count;
+
+ /**
+ * This field represents a virtual pointer that refers to the
+ * starting address of the UF address table.
+ * 64-bit pointers are required by the hardware.
+ */
+ dma_addr_t *array;
+
+ /**
+ * This field specifies the physical address location for the UF
+ * address table.
+ */
+ dma_addr_t physical_address;
+
+};
+
+/**
+ * struct scic_sds_unsolicited_frame_control -
+ *
+ * This object contains all of the data necessary to handle unsolicited frames.
+ */
+struct scic_sds_unsolicited_frame_control {
+ /**
+ * This field is the software copy of the unsolicited frame queue
+ * get pointer. The controller object writes this value to the
+ * hardware to let the hardware put more unsolicited frame entries.
+ */
+ u32 get;
+
+ /**
+ * This field contains all of the unsolicited frame header
+ * specific fields.
+ */
+ struct scic_sds_uf_header_array headers;
+
+ /**
+ * This field contains all of the unsolicited frame buffer
+ * specific fields.
+ */
+ struct scic_sds_uf_buffer_array buffers;
+
+ /**
+ * This field contains all of the unsolicited frame address table
+ * specific fields.
+ */
+ struct scic_sds_uf_address_table_array address_table;
+
+};
+
+void scic_sds_unsolicited_frame_control_set_address_table_count(
+ struct scic_sds_unsolicited_frame_control *uf_control);
+
+struct scic_sds_controller;
+void scic_sds_unsolicited_frame_control_construct(
+ struct scic_sds_unsolicited_frame_control *uf_control,
+ struct sci_physical_memory_descriptor *mde,
+ struct scic_sds_controller *this_controller);
+
+enum sci_status scic_sds_unsolicited_frame_control_get_header(
+ struct scic_sds_unsolicited_frame_control *uf_control,
+ u32 frame_index,
+ void **frame_header);
+
+enum sci_status scic_sds_unsolicited_frame_control_get_buffer(
+ struct scic_sds_unsolicited_frame_control *uf_control,
+ u32 frame_index,
+ void **frame_buffer);
+
+bool scic_sds_unsolicited_frame_control_release_frame(
+ struct scic_sds_unsolicited_frame_control *uf_control,
+ u32 frame_index);
+
+/**
+ * scic_sds_unsolicited_frame_control_get_mde_size() -
+ *
+ * This macro simply calculates the size of the memory descriptor entry that
+ * relates to unsolicited frames and the surrounding silicon memory required to
+ * utilize it.
+ */
+#define scic_sds_unsolicited_frame_control_get_mde_size(uf_control) \
+ (((uf_control).buffers.count * SCU_UNSOLICITED_FRAME_BUFFER_SIZE) \
+ + ((uf_control).address_table.count * sizeof(dma_addr_t)) \
+ + ((uf_control).buffers.count * sizeof(struct scu_unsolicited_frame_header)))
+
+#endif /* _SCIC_SDS_UNSOLICITED_FRAME_CONTROL_H_ */
diff --git a/drivers/scsi/isci/core/scic_task_request.h b/drivers/scsi/isci/core/scic_task_request.h
new file mode 100644
index 000000000000..ef76cb6bdbea
--- /dev/null
+++ b/drivers/scsi/isci/core/scic_task_request.h
@@ -0,0 +1,148 @@
+/*
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Intel Corporation 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
+ * OWNER 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.
+ */
+
+#ifndef _SCIC_TASK_REQUEST_H_
+#define _SCIC_TASK_REQUEST_H_
+
+/**
+ * This file contains the structures and interface methods that can be
+ * referenced and used by the SCI user for to utilize task management
+ * requests.
+ *
+ *
+ */
+
+
+#include "sci_types.h"
+#include "sci_status.h"
+
+struct scic_sds_request;
+struct scic_sds_remote_device;
+struct scic_sds_controller;
+
+
+/**
+ * scic_task_request_construct() - This method is called by the SCI user to
+ * construct all SCI Core task management requests, regardless of protocol.
+ * Memory initialization and functionality common to all task request types
+ * is performed in this method.
+ * @scic_controller: the handle to the core controller object for which to
+ * build the task managmement request.
+ * @scic_remote_device: the handle to the core remote device object for which
+ * to build the task management request. passed, then a copy of the request
+ * is built internally. The request will be copied into the actual
+ * controller request memory when the task is allocated internally during
+ * the scic_controller_start_task() method.
+ * @io_tag: This parameter specifies the IO tag to be associated with this
+ * request. If SCI_CONTROLLER_INVALID_IO_TAG is passed, then a copy of the
+ * request is built internally. The request will be copied into the actual
+ * controller request memory when the IO tag is allocated internally during
+ * the scic_controller_start_io() method.
+ * @user_task_request_object: This parameter specifies the user task request to
+ * be utilized during construction. This task pointer will become the
+ * associated object for the core task request object.
+ * @scic_task_request_memory: This parameter specifies the memory location to
+ * be utilized when building the core request.
+ * @new_scic_task_request_handle: This parameter specifies a pointer to the
+ * handle the core will expect in further interactions with the core task
+ * request object.
+ *
+ * The SCI core implementation will create an association between the user task
+ * request object and the core task request object. Indicate if the controller
+ * successfully built the task request. SCI_SUCCESS This value is returned if
+ * the task request was successfully built.
+ */
+enum sci_status scic_task_request_construct(
+ struct scic_sds_controller *scic_controller,
+ struct scic_sds_remote_device *scic_remote_device,
+ u16 io_tag,
+ void *user_task_request_object,
+ void *scic_task_request_memory,
+ struct scic_sds_request **new_scic_task_request_handle);
+
+/**
+ * scic_task_request_construct_ssp() - This method is called by the SCI user to
+ * construct all SCI Core SSP task management requests. Memory
+ * initialization and functionality common to all task request types is
+ * performed in this method.
+ * @scic_task_request: This parameter specifies the handle to the core task
+ * request object for which to construct a SATA specific task management
+ * request.
+ *
+ * Indicate if the controller successfully built the task request. SCI_SUCCESS
+ * This value is returned if the task request was successfully built.
+ */
+enum sci_status scic_task_request_construct_ssp(
+ struct scic_sds_request *scic_task_request);
+
+/**
+ * scic_task_request_construct_sata() - This method is called by the SCI user
+ * to construct all SCI Core SATA task management requests. Memory
+ * initialization and functionality common to all task request types is
+ * performed in this method.
+ * @scic_task_request_handle: This parameter specifies the handle to the core
+ * task request object for which to construct a SATA specific task
+ * management request.
+ *
+ * Indicate if the controller successfully built the task request. SCI_SUCCESS
+ * This value is returned if the task request was successfully built.
+ */
+enum sci_status scic_task_request_construct_sata(
+ struct scic_sds_request *scic_task_request_handle);
+
+
+
+#endif /* _SCIC_TASK_REQUEST_H_ */
+
diff --git a/drivers/scsi/isci/core/scic_user_callback.h b/drivers/scsi/isci/core/scic_user_callback.h
new file mode 100644
index 000000000000..6eca5a96649e
--- /dev/null
+++ b/drivers/scsi/isci/core/scic_user_callback.h
@@ -0,0 +1,740 @@
+/*
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Intel Corporation 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
+ * OWNER 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.
+ */
+
+#ifndef _SCIC_USER_CALLBACK_H_
+#define _SCIC_USER_CALLBACK_H_
+
+/**
+ * This file contains all of the interface methods/macros that must be
+ * implemented by an SCI Core user.
+ *
+ *
+ */
+
+
+#include "sci_types.h"
+#include "sci_status.h"
+
+struct scic_sds_request;
+struct scic_sds_phy;
+struct scic_sds_port;
+struct scic_sds_remote_device;
+struct scic_sds_controller;
+
+/**
+ * scic_cb_timer_create() - This callback method asks the user to create a
+ * timer and provide a handle for this timer for use in further timer
+ * interactions.
+ * @controller: This parameter specifies the controller with which this timer
+ * is to be associated.
+ * @timer_callback: This parameter specifies the callback method to be invoked
+ * whenever the timer expires.
+ * @cookie: This parameter specifies a piece of information that the user must
+ * retain. This cookie is to be supplied by the user anytime a timeout
+ * occurs for the created timer.
+ *
+ * The "timer_callback" method should be executed in a mutually exlusive manner
+ * from the controller completion handler handler (refer to
+ * scic_controller_get_handler_methods()). This method returns a handle to a
+ * timer object created by the user. The handle will be utilized for all
+ * further interactions relating to this timer.
+ */
+void *scic_cb_timer_create(
+ struct scic_sds_controller *controller,
+ void (*timer_callback)(void *),
+ void *cookie);
+
+
+/**
+ * scic_cb_timer_start() - This callback method asks the user to start the
+ * supplied timer.
+ * @controller: This parameter specifies the controller with which this timer
+ * is to associated.
+ * @timer: This parameter specifies the timer to be started.
+ * @milliseconds: This parameter specifies the number of milliseconds for which
+ * to stall. The operating system driver is allowed to round this value up
+ * where necessary.
+ *
+ * All timers in the system started by the SCI Core are one shot timers.
+ * Therefore, the SCI user should make sure that it removes the timer from it's
+ * list when a timer actually fires. Additionally, SCI Core user's should be
+ * able to handle calls from the SCI Core to stop a timer that may already be
+ * stopped. none
+ */
+void scic_cb_timer_start(
+ struct scic_sds_controller *controller,
+ void *timer,
+ u32 milliseconds);
+
+/**
+ * scic_cb_timer_stop() - This callback method asks the user to stop the
+ * supplied timer.
+ * @controller: This parameter specifies the controller with which this timer
+ * is to associated.
+ * @timer: This parameter specifies the timer to be stopped.
+ *
+ */
+void scic_cb_timer_stop(
+ struct scic_sds_controller *controller,
+ void *timer);
+
+/**
+ * scic_cb_stall_execution() - This method is called when the core requires the
+ * OS driver to stall execution. This method is utilized during
+ * initialization or non-performance paths only.
+ * @microseconds: This parameter specifies the number of microseconds for which
+ * to stall. The operating system driver is allowed to round this value up
+ * where necessary.
+ *
+ * none.
+ */
+void scic_cb_stall_execution(
+ u32 microseconds);
+
+/**
+ * scic_cb_controller_start_complete() - This user callback will inform the
+ * user that the controller has finished the start process.
+ * @controller: This parameter specifies the controller that was started.
+ * @completion_status: This parameter specifies the results of the start
+ * operation. SCI_SUCCESS indicates successful completion.
+ *
+ */
+void scic_cb_controller_start_complete(
+ struct scic_sds_controller *controller,
+ enum sci_status completion_status);
+
+/**
+ * scic_cb_controller_stop_complete() - This user callback will inform the user
+ * that the controller has finished the stop process.
+ * @controller: This parameter specifies the controller that was stopped.
+ * @completion_status: This parameter specifies the results of the stop
+ * operation. SCI_SUCCESS indicates successful completion.
+ *
+ */
+void scic_cb_controller_stop_complete(
+ struct scic_sds_controller *controller,
+ enum sci_status completion_status);
+
+/**
+ * scic_cb_io_request_complete() - This user callback will inform the user that
+ * an IO request has completed.
+ * @controller: This parameter specifies the controller on which the IO is
+ * completing.
+ * @remote_device: This parameter specifies the remote device on which this IO
+ * request is completing.
+ * @io_request: This parameter specifies the IO request that has completed.
+ * @completion_status: This parameter specifies the results of the IO request
+ * operation. SCI_SUCCESS indicates successful completion.
+ *
+ */
+void scic_cb_io_request_complete(
+ struct scic_sds_controller *controller,
+ struct scic_sds_remote_device *remote_device,
+ struct scic_sds_request *io_request,
+ enum sci_io_status completion_status);
+
+/**
+ * scic_cb_task_request_complete() - This user callback will inform the user
+ * that a task management request completed.
+ * @controller: This parameter specifies the controller on which the task
+ * management request is completing.
+ * @remote_device: This parameter specifies the remote device on which this
+ * task management request is completing.
+ * @task_request: This parameter specifies the task management request that has
+ * completed.
+ * @completion_status: This parameter specifies the results of the IO request
+ * operation. SCI_SUCCESS indicates successful completion.
+ *
+ */
+void scic_cb_task_request_complete(
+ struct scic_sds_controller *controller,
+ struct scic_sds_remote_device *remote_device,
+ struct scic_sds_request *task_request,
+ enum sci_task_status completion_status);
+
+#ifndef SCI_GET_PHYSICAL_ADDRESS_OPTIMIZATION_ENABLED
+/**
+ * scic_cb_io_request_get_physical_address() - This callback method asks the
+ * user to provide the physical address for the supplied virtual address
+ * when building an io request object.
+ * @controller: This parameter is the core controller object handle.
+ * @io_request: This parameter is the io request object handle for which the
+ * physical address is being requested.
+ * @virtual_address: This paramter is the virtual address which is to be
+ * returned as a physical address.
+ * @physical_address: The physical address for the supplied virtual address.
+ *
+ * None.
+ */
+void scic_cb_io_request_get_physical_address(
+ struct scic_sds_controller *controller,
+ struct scic_sds_request *io_request,
+ void *virtual_address,
+ dma_addr_t *physical_address);
+#endif /* SCI_GET_PHYSICAL_ADDRESS_OPTIMIZATION_ENABLED */
+
+/**
+ * scic_cb_io_request_get_transfer_length() - This callback method asks the
+ * user to provide the number of bytes to be transfered as part of this
+ * request.
+ * @scic_user_io_request: This parameter points to the user's IO request
+ * object. It is a cookie that allows the user to provide the necessary
+ * information for this callback.
+ *
+ * This method returns the number of payload data bytes to be transfered for
+ * this IO request.
+ */
+u32 scic_cb_io_request_get_transfer_length(
+ void *scic_user_io_request);
+
+/**
+ * scic_cb_io_request_get_data_direction() - This callback method asks the user
+ * to provide the data direction for this request.
+ * @scic_user_io_request: This parameter points to the user's IO request
+ * object. It is a cookie that allows the user to provide the necessary
+ * information for this callback.
+ *
+ * This method returns the value of SCI_IO_REQUEST_DATA_OUT or
+ * SCI_IO_REQUEST_DATA_IN, or SCI_IO_REQUEST_NO_DATA.
+ */
+SCI_IO_REQUEST_DATA_DIRECTION scic_cb_io_request_get_data_direction(
+ void *scic_user_io_request);
+
+#ifndef SCI_SGL_OPTIMIZATION_ENABLED
+/**
+ * scic_cb_io_request_get_next_sge() - This callback method asks the user to
+ * provide the address to where the next Scatter-Gather Element is located.
+ * Details regarding usage: - Regarding the first SGE: the user should
+ * initialize an index, or a pointer, prior to construction of the request
+ * that will reference the very first scatter-gather element. This is
+ * important since this method is called for every scatter-gather element,
+ * including the first element. - Regarding the last SGE: the user should
+ * return NULL from this method when this method is called and the SGL has
+ * exhausted all elements.
+ * @scic_user_io_request: This parameter points to the user's IO request
+ * object. It is a cookie that allows the user to provide the necessary
+ * information for this callback.
+ * @current_sge_address: This parameter specifies the address for the current
+ * SGE (i.e. the one that has just processed).
+ * @next_sge: An address specifying the location for the next scatter gather
+ * element to be processed.
+ *
+ * None
+ */
+void scic_cb_io_request_get_next_sge(
+ void *scic_user_io_request,
+ void *current_sge_address,
+ void **next_sge);
+#endif /* SCI_SGL_OPTIMIZATION_ENABLED */
+
+/**
+ * scic_cb_sge_get_address_field() - This callback method asks the user to
+ * provide the contents of the "address" field in the Scatter-Gather Element.
+ * @scic_user_io_request: This parameter points to the user's IO request
+ * object. It is a cookie that allows the user to provide the necessary
+ * information for this callback.
+ * @sge_address: This parameter specifies the address for the SGE from which to
+ * retrieve the address field.
+ *
+ * A physical address specifying the contents of the SGE's address field.
+ */
+dma_addr_t scic_cb_sge_get_address_field(
+ void *scic_user_io_request,
+ void *sge_address);
+
+/**
+ * scic_cb_sge_get_length_field() - This callback method asks the user to
+ * provide the contents of the "length" field in the Scatter-Gather Element.
+ * @scic_user_io_request: This parameter points to the user's IO request
+ * object. It is a cookie that allows the user to provide the necessary
+ * information for this callback.
+ * @sge_address: This parameter specifies the address for the SGE from which to
+ * retrieve the address field.
+ *
+ * This method returns the length field specified inside the SGE referenced by
+ * the sge_address parameter.
+ */
+u32 scic_cb_sge_get_length_field(
+ void *scic_user_io_request,
+ void *sge_address);
+
+/**
+ * scic_cb_ssp_io_request_get_cdb_address() - This callback method asks the
+ * user to provide the address for the command descriptor block (CDB)
+ * associated with this IO request.
+ * @scic_user_io_request: This parameter points to the user's IO request
+ * object. It is a cookie that allows the user to provide the necessary
+ * information for this callback.
+ *
+ * This method returns the virtual address of the CDB.
+ */
+void *scic_cb_ssp_io_request_get_cdb_address(
+ void *scic_user_io_request);
+
+/**
+ * scic_cb_ssp_io_request_get_cdb_length() - This callback method asks the user
+ * to provide the length of the command descriptor block (CDB) associated
+ * with this IO request.
+ * @scic_user_io_request: This parameter points to the user's IO request
+ * object. It is a cookie that allows the user to provide the necessary
+ * information for this callback.
+ *
+ * This method returns the length of the CDB.
+ */
+u32 scic_cb_ssp_io_request_get_cdb_length(
+ void *scic_user_io_request);
+
+/**
+ * scic_cb_ssp_io_request_get_lun() - This callback method asks the user to
+ * provide the Logical Unit (LUN) associated with this IO request.
+ * @scic_user_io_request: This parameter points to the user's IO request
+ * object. It is a cookie that allows the user to provide the necessary
+ * information for this callback.
+ *
+ * The contents of the value returned from this callback are defined by the
+ * protocol standard (e.g. T10 SAS specification). Please refer to the
+ * transport command information unit description in the associated standard.
+ * This method returns the LUN associated with this request. This should be u64?
+ */
+u32 scic_cb_ssp_io_request_get_lun(
+ void *scic_user_io_request);
+
+/**
+ * scic_cb_ssp_io_request_get_task_attribute() - This callback method asks the
+ * user to provide the task attribute associated with this IO request.
+ * @scic_user_io_request: This parameter points to the user's IO request
+ * object. It is a cookie that allows the user to provide the necessary
+ * information for this callback.
+ *
+ * The contents of the value returned from this callback are defined by the
+ * protocol standard (e.g. T10 SAS specification). Please refer to the
+ * transport command information unit description in the associated standard.
+ * This method returns the task attribute associated with this IO request.
+ */
+u32 scic_cb_ssp_io_request_get_task_attribute(
+ void *scic_user_io_request);
+
+/**
+ * scic_cb_ssp_io_request_get_command_priority() - This callback method asks
+ * the user to provide the command priority associated with this IO request.
+ * @scic_user_io_request: This parameter points to the user's IO request
+ * object. It is a cookie that allows the user to provide the necessary
+ * information for this callback.
+ *
+ * The contents of the value returned from this callback are defined by the
+ * protocol standard (e.g. T10 SAS specification). Please refer to the
+ * transport command information unit description in the associated standard.
+ * This method returns the command priority associated with this IO request.
+ */
+u32 scic_cb_ssp_io_request_get_command_priority(
+ void *scic_user_io_request);
+
+/**
+ * scic_cb_io_request_do_copy_rx_frames() - This callback method asks the user
+ * if the received RX frame data is to be copied to the SGL or should be
+ * stored by the SCI core to be retrieved later with the
+ * scic_io_request_get_rx_frame().
+ * @scic_user_io_request: This parameter points to the user's IO request
+ * object. It is a cookie that allows the user to provide the necessary
+ * information for this callback.
+ *
+ * This method returns true if the SCI core should copy the received frame data
+ * to the SGL location or false if the SCI user wants to retrieve the frame
+ * data at a later time.
+ */
+bool scic_cb_io_request_do_copy_rx_frames(
+ void *scic_user_io_request);
+
+/**
+ * scic_cb_request_get_sat_protocol() - This callback method asks the user to
+ * return the SAT protocol definition for this IO request. This method is
+ * only called by the SCI core if the request type constructed is SATA.
+ * @scic_user_io_request: This parameter points to the user's IO request
+ * object. It is a cookie that allows the user to provide the necessary
+ * information for this callback.
+ *
+ * This method returns one of the sat.h defined protocols for the given io
+ * request.
+ */
+u8 scic_cb_request_get_sat_protocol(
+ void *scic_user_io_request);
+
+
+/**
+ * scic_cb_ssp_task_request_get_lun() - This method returns the Logical Unit to
+ * be utilized for this task management request.
+ * @scic_user_task_request: This parameter points to the user's task request
+ * object. It is a cookie that allows the user to provide the necessary
+ * information for this callback.
+ *
+ * The contents of the value returned from this callback are defined by the
+ * protocol standard (e.g. T10 SAS specification). Please refer to the
+ * transport task information unit description in the associated standard. This
+ * method returns the LUN associated with this request. This should be u64?
+ */
+u32 scic_cb_ssp_task_request_get_lun(
+ void *scic_user_task_request);
+
+/**
+ * scic_cb_ssp_task_request_get_function() - This method returns the task
+ * management function to be utilized for this task request.
+ * @scic_user_task_request: This parameter points to the user's task request
+ * object. It is a cookie that allows the user to provide the necessary
+ * information for this callback.
+ *
+ * The contents of the value returned from this callback are defined by the
+ * protocol standard (e.g. T10 SAS specification). Please refer to the
+ * transport task information unit description in the associated standard. This
+ * method returns an unsigned byte representing the task management function to
+ * be performed.
+ */
+u8 scic_cb_ssp_task_request_get_function(
+ void *scic_user_task_request);
+
+/**
+ * scic_cb_ssp_task_request_get_io_tag_to_manage() - This method returns the
+ * task management IO tag to be managed. Depending upon the task management
+ * function the value returned from this method may be ignored.
+ * @scic_user_task_request: This parameter points to the user's task request
+ * object. It is a cookie that allows the user to provide the necessary
+ * information for this callback.
+ *
+ * This method returns an unsigned 16-bit word depicting the IO tag to be
+ * managed.
+ */
+u16 scic_cb_ssp_task_request_get_io_tag_to_manage(
+ void *scic_user_task_request);
+
+/**
+ * scic_cb_ssp_task_request_get_response_data_address() - This callback method
+ * asks the user to provide the virtual address of the response data buffer
+ * for the supplied IO request.
+ * @scic_user_task_request: This parameter points to the user's task request
+ * object. It is a cookie that allows the user to provide the necessary
+ * information for this callback.
+ *
+ * This method returns the virtual address for the response data buffer
+ * associated with this IO request.
+ */
+void *scic_cb_ssp_task_request_get_response_data_address(
+ void *scic_user_task_request);
+
+/**
+ * scic_cb_ssp_task_request_get_response_data_length() - This callback method
+ * asks the user to provide the length of the response data buffer for the
+ * supplied IO request.
+ * @scic_user_task_request: This parameter points to the user's task request
+ * object. It is a cookie that allows the user to provide the necessary
+ * information for this callback.
+ *
+ * This method returns the length of the response buffer data associated with
+ * this IO request.
+ */
+u32 scic_cb_ssp_task_request_get_response_data_length(
+ void *scic_user_task_request);
+
+/**
+ * scic_cb_pci_get_bar() - In this method the user must return the base address
+ * register (BAR) value for the supplied base address register number.
+ * @controller: The controller for which to retrieve the bar number.
+ * @bar_number: This parameter depicts the BAR index/number to be read.
+ *
+ * Return a pointer value indicating the contents of the BAR. NULL indicates an
+ * invalid BAR index/number was specified. All other values indicate a valid
+ * VIRTUAL address from the BAR.
+ */
+void *scic_cb_pci_get_bar(
+ struct scic_sds_controller *controller,
+ u16 bar_number);
+
+/**
+ * scic_cb_get_virtual_address() - This callback method asks the user to
+ * provide the virtual address for the supplied physical address.
+ * @controller: This parameter is the core controller object handle.
+ * @physical_address: This parameter is the physical address which is to be
+ * returned as a virtual address.
+ *
+ * The method returns the virtual address for the supplied physical address.
+ */
+void *scic_cb_get_virtual_address(
+ struct scic_sds_controller *controller,
+ dma_addr_t physical_address);
+
+/**
+ * scic_cb_port_stop_complete() - This method informs the user when a stop
+ * operation on the port has completed.
+ * @controller: This parameter represents the controller which contains the
+ * port.
+ * @port: This parameter specifies the SCI port object for which the callback
+ * is being invoked.
+ * @completion_status: This parameter specifies the status for the operation
+ * being completed.
+ *
+ */
+void scic_cb_port_stop_complete(
+ struct scic_sds_controller *controller,
+ struct scic_sds_port *port,
+ enum sci_status completion_status);
+
+/**
+ * scic_cb_port_hard_reset_complete() - This method informs the user when a
+ * hard reset on the port has completed. This hard reset could have been
+ * initiated by the user or by the remote port.
+ * @controller: This parameter represents the controller which contains the
+ * port.
+ * @port: This parameter specifies the SCI port object for which the callback
+ * is being invoked.
+ * @completion_status: This parameter specifies the status for the operation
+ * being completed.
+ *
+ */
+void scic_cb_port_hard_reset_complete(
+ struct scic_sds_controller *controller,
+ struct scic_sds_port *port,
+ enum sci_status completion_status);
+
+/**
+ * scic_cb_port_ready() - This method informs the user that the port is now in
+ * a ready state and can be utilized to issue IOs.
+ * @controller: This parameter represents the controller which contains the
+ * port.
+ * @port: This parameter specifies the SCI port object for which the callback
+ * is being invoked.
+ *
+ */
+void scic_cb_port_ready(
+ struct scic_sds_controller *controller,
+ struct scic_sds_port *port);
+
+/**
+ * scic_cb_port_not_ready() - This method informs the user that the port is now
+ * not in a ready (i.e. busy) state and can't be utilized to issue IOs.
+ * @controller: This parameter represents the controller which contains the
+ * port.
+ * @port: This parameter specifies the SCI port object for which the callback
+ * is being invoked.
+ * @reason_code: This parameter specifies the reason for the port not ready
+ * callback.
+ *
+ */
+void scic_cb_port_not_ready(
+ struct scic_sds_controller *controller,
+ struct scic_sds_port *port,
+ u32 reason_code);
+
+/**
+ * scic_cb_port_invalid_link_up() - This method informs the SCI Core user that
+ * a phy/link became ready, but the phy is not allowed in the port. In some
+ * situations the underlying hardware only allows for certain phy to port
+ * mappings. If these mappings are violated, then this API is invoked.
+ * @controller: This parameter represents the controller which contains the
+ * port.
+ * @port: This parameter specifies the SCI port object for which the callback
+ * is being invoked.
+ * @phy: This parameter specifies the phy that came ready, but the phy can't be
+ * a valid member of the port.
+ *
+ */
+void scic_cb_port_invalid_link_up(
+ struct scic_sds_controller *controller,
+ struct scic_sds_port *port,
+ struct scic_sds_phy *phy);
+
+/**
+ * scic_cb_port_bc_change_primitive_received() - This callback method informs
+ * the user that a broadcast change primitive was received.
+ * @controller: This parameter represents the controller which contains the
+ * port.
+ * @port: This parameter specifies the SCI port object for which the callback
+ * is being invoked. For instances where the phy on which the primitive was
+ * received is not part of a port, this parameter will be
+ * SCI_INVALID_HANDLE_T.
+ * @phy: This parameter specifies the phy on which the primitive was received.
+ *
+ */
+void scic_cb_port_bc_change_primitive_received(
+ struct scic_sds_controller *controller,
+ struct scic_sds_port *port,
+ struct scic_sds_phy *phy);
+
+
+
+
+/**
+ * scic_cb_port_link_up() - This callback method informs the user that a phy
+ * has become operational and is capable of communicating with the remote
+ * end point.
+ * @controller: This parameter represents the controller associated with the
+ * phy.
+ * @port: This parameter specifies the port object for which the user callback
+ * is being invoked. There may be conditions where this parameter can be
+ * SCI_INVALID_HANDLE
+ * @phy: This parameter specifies the phy object for which the user callback is
+ * being invoked.
+ *
+ */
+void scic_cb_port_link_up(
+ struct scic_sds_controller *controller,
+ struct scic_sds_port *port,
+ struct scic_sds_phy *phy);
+
+/**
+ * scic_cb_port_link_down() - This callback method informs the user that a phy
+ * is no longer operational and is not capable of communicating with the
+ * remote end point.
+ * @controller: This parameter represents the controller associated with the
+ * phy.
+ * @port: This parameter specifies the port object for which the user callback
+ * is being invoked. There may be conditions where this parameter can be
+ * SCI_INVALID_HANDLE
+ * @phy: This parameter specifies the phy object for which the user callback is
+ * being invoked.
+ *
+ */
+void scic_cb_port_link_down(
+ struct scic_sds_controller *controller,
+ struct scic_sds_port *port,
+ struct scic_sds_phy *phy);
+
+/**
+ * scic_cb_remote_device_start_complete() - This user callback method will
+ * inform the user that a start operation has completed.
+ * @controller: This parameter specifies the core controller associated with
+ * the completion callback.
+ * @remote_device: This parameter specifies the remote device associated with
+ * the completion callback.
+ * @completion_status: This parameter specifies the completion status for the
+ * operation.
+ *
+ */
+void scic_cb_remote_device_start_complete(
+ struct scic_sds_controller *controller,
+ struct scic_sds_remote_device *remote_device,
+ enum sci_status completion_status);
+
+/**
+ * scic_cb_remote_device_stop_complete() - This user callback method will
+ * inform the user that a stop operation has completed.
+ * @controller: This parameter specifies the core controller associated with
+ * the completion callback.
+ * @remote_device: This parameter specifies the remote device associated with
+ * the completion callback.
+ * @completion_status: This parameter specifies the completion status for the
+ * operation.
+ *
+ */
+void scic_cb_remote_device_stop_complete(
+ struct scic_sds_controller *controller,
+ struct scic_sds_remote_device *remote_device,
+ enum sci_status completion_status);
+
+/**
+ * scic_cb_remote_device_ready() - This user callback method will inform the
+ * user that a remote device is now capable of handling IO requests.
+ * @controller: This parameter specifies the core controller associated with
+ * the completion callback.
+ * @remote_device: This parameter specifies the remote device associated with
+ * the callback.
+ *
+ */
+void scic_cb_remote_device_ready(
+ struct scic_sds_controller *controller,
+ struct scic_sds_remote_device *remote_device);
+
+/**
+ * scic_cb_remote_device_not_ready() - This user callback method will inform
+ * the user that a remote device is no longer capable of handling IO
+ * requests (until a ready callback is invoked).
+ * @controller: This parameter specifies the core controller associated with
+ * the completion callback.
+ * @remote_device: This parameter specifies the remote device associated with
+ * the callback.
+ * @reason_code: This paramete specifies the reason the remote device is not
+ * ready.
+ *
+ */
+void scic_cb_remote_device_not_ready(
+ struct scic_sds_controller *controller,
+ struct scic_sds_remote_device *remote_device,
+ u32 reason_code);
+
+#if !defined(DISABLE_ATAPI)
+/**
+ * scic_cb_stp_packet_io_request_get_cdb_address() - This user callback gets
+ * from stp packet io's user request the CDB address.
+ * @scic_user_io_request:
+ *
+ * The cdb adress.
+ */
+void *scic_cb_stp_packet_io_request_get_cdb_address(
+ void *scic_user_io_request);
+
+/**
+ * scic_cb_stp_packet_io_request_get_cdb_length() - This user callback gets
+ * from stp packet io's user request the CDB length.
+ * @scic_user_io_request:
+ *
+ * The cdb length.
+ */
+u32 scic_cb_stp_packet_io_request_get_cdb_length(
+ void *scic_user_io_request);
+#else /* !defined(DISABLE_ATAPI) */
+#define scic_cb_stp_packet_io_request_get_cdb_address(scic_user_io_request) NULL
+#define scic_cb_stp_packet_io_request_get_cdb_length(scic_user_io_request) 0
+#endif /* !defined(DISABLE_ATAPI) */
+
+
+#endif /* _SCIC_USER_CALLBACK_H_ */
+
diff --git a/drivers/scsi/isci/core/scu_completion_codes.h b/drivers/scsi/isci/core/scu_completion_codes.h
new file mode 100644
index 000000000000..17ee4c8b9122
--- /dev/null
+++ b/drivers/scsi/isci/core/scu_completion_codes.h
@@ -0,0 +1,280 @@
+/*
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Intel Corporation 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
+ * OWNER 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.
+ */
+
+#ifndef _SCU_COMPLETION_CODES_HEADER_
+#define _SCU_COMPLETION_CODES_HEADER_
+
+/**
+ * This file contains the constants and macros for the SCU hardware completion
+ * codes.
+ *
+ *
+ */
+
+#define SCU_COMPLETION_TYPE_SHIFT 28
+#define SCU_COMPLETION_TYPE_MASK 0x70000000
+
+/**
+ * SCU_COMPLETION_TYPE() -
+ *
+ * This macro constructs an SCU completion type
+ */
+#define SCU_COMPLETION_TYPE(type) \
+ ((u32)(type) << SCU_COMPLETION_TYPE_SHIFT)
+
+/**
+ * SCU_COMPLETION_TYPE() -
+ *
+ * These macros contain the SCU completion types SCU_COMPLETION_TYPE
+ */
+#define SCU_COMPLETION_TYPE_TASK SCU_COMPLETION_TYPE(0)
+#define SCU_COMPLETION_TYPE_SDMA SCU_COMPLETION_TYPE(1)
+#define SCU_COMPLETION_TYPE_UFI SCU_COMPLETION_TYPE(2)
+#define SCU_COMPLETION_TYPE_EVENT SCU_COMPLETION_TYPE(3)
+#define SCU_COMPLETION_TYPE_NOTIFY SCU_COMPLETION_TYPE(4)
+
+/**
+ *
+ *
+ * These constants provide the shift and mask values for the various parts of
+ * an SCU completion code.
+ */
+#define SCU_COMPLETION_STATUS_MASK 0x0FFC0000
+#define SCU_COMPLETION_TL_STATUS_MASK 0x0FC00000
+#define SCU_COMPLETION_TL_STATUS_SHIFT 22
+#define SCU_COMPLETION_SDMA_STATUS_MASK 0x003C0000
+#define SCU_COMPLETION_PEG_MASK 0x00010000
+#define SCU_COMPLETION_PORT_MASK 0x00007000
+#define SCU_COMPLETION_PE_MASK SCU_COMPLETION_PORT_MASK
+#define SCU_COMPLETION_PE_SHIFT 12
+#define SCU_COMPLETION_INDEX_MASK 0x00000FFF
+
+/**
+ * SCU_GET_COMPLETION_TYPE() -
+ *
+ * This macro returns the SCU completion type.
+ */
+#define SCU_GET_COMPLETION_TYPE(completion_code) \
+ ((completion_code) & SCU_COMPLETION_TYPE_MASK)
+
+/**
+ * SCU_GET_COMPLETION_STATUS() -
+ *
+ * This macro returns the SCU completion status.
+ */
+#define SCU_GET_COMPLETION_STATUS(completion_code) \
+ ((completion_code) & SCU_COMPLETION_STATUS_MASK)
+
+/**
+ * SCU_GET_COMPLETION_TL_STATUS() -
+ *
+ * This macro returns the transport layer completion status.
+ */
+#define SCU_GET_COMPLETION_TL_STATUS(completion_code) \
+ ((completion_code) & SCU_COMPLETION_TL_STATUS_MASK)
+
+/**
+ * SCU_MAKE_COMPLETION_STATUS() -
+ *
+ * This macro takes a completion code and performs the shift and mask
+ * operations to turn it into a completion code that can be compared to a
+ * SCU_GET_COMPLETION_TL_STATUS.
+ */
+#define SCU_MAKE_COMPLETION_STATUS(completion_code) \
+ ((u32)(completion_code) << SCU_COMPLETION_TL_STATUS_SHIFT)
+
+/**
+ * SCU_NORMALIZE_COMPLETION_STATUS() -
+ *
+ * This macro takes a SCU_GET_COMPLETION_TL_STATUS and normalizes it for a
+ * return code.
+ */
+#define SCU_NORMALIZE_COMPLETION_STATUS(completion_code) \
+ (\
+ ((completion_code) & SCU_COMPLETION_TL_STATUS_MASK) \
+ >> SCU_COMPLETION_TL_STATUS_SHIFT \
+ )
+
+/**
+ * SCU_GET_COMPLETION_SDMA_STATUS() -
+ *
+ * This macro returns the SDMA completion status.
+ */
+#define SCU_GET_COMPLETION_SDMA_STATUS(completion_code) \
+ ((completion_code) & SCU_COMPLETION_SDMA_STATUS_MASK)
+
+/**
+ * SCU_GET_COMPLETION_PEG() -
+ *
+ * This macro returns the Protocol Engine Group from the completion code.
+ */
+#define SCU_GET_COMPLETION_PEG(completion_code) \
+ ((completion_code) & SCU_COMPLETION_PEG_MASK)
+
+/**
+ * SCU_GET_COMPLETION_PORT() -
+ *
+ * This macro reuturns the logical port index from the completion code.
+ */
+#define SCU_GET_COMPLETION_PORT(completion_code) \
+ ((completion_code) & SCU_COMPLETION_PORT_MASK)
+
+/**
+ * SCU_GET_PROTOCOL_ENGINE_INDEX() -
+ *
+ * This macro returns the PE index from the completion code.
+ */
+#define SCU_GET_PROTOCOL_ENGINE_INDEX(completion_code) \
+ (((completion_code) & SCU_COMPLETION_PE_MASK) >> SCU_COMPLETION_PE_SHIFT)
+
+/**
+ * SCU_GET_COMPLETION_INDEX() -
+ *
+ * This macro returns the index of the completion which is either a TCi or an
+ * RNi depending on the completion type.
+ */
+#define SCU_GET_COMPLETION_INDEX(completion_code) \
+ ((completion_code) & SCU_COMPLETION_INDEX_MASK)
+
+#define SCU_UNSOLICITED_FRAME_MASK 0x0FFF0000
+#define SCU_UNSOLICITED_FRAME_SHIFT 16
+
+/**
+ * SCU_GET_FRAME_INDEX() -
+ *
+ * This macro returns a normalized frame index from an unsolicited frame
+ * completion.
+ */
+#define SCU_GET_FRAME_INDEX(completion_code) \
+ (\
+ ((completion_code) & SCU_UNSOLICITED_FRAME_MASK) \
+ >> SCU_UNSOLICITED_FRAME_SHIFT \
+ )
+
+#define SCU_UNSOLICITED_FRAME_ERROR_MASK 0x00008000
+
+/**
+ * SCU_GET_FRAME_ERROR() -
+ *
+ * This macro returns a zero (0) value if there is no frame error otherwise it
+ * returns non-zero (!0).
+ */
+#define SCU_GET_FRAME_ERROR(completion_code) \
+ ((completion_code) & SCU_UNSOLICITED_FRAME_ERROR_MASK)
+
+/**
+ *
+ *
+ * These constants represent normalized completion codes which must be shifted
+ * 18 bits to match it with the hardware completion code. In a 16-bit compiler,
+ * immediate constants are 16-bit values (the size of an int). If we shift
+ * those by 18 bits, we completely lose the value. To ensure the value is a
+ * 32-bit value like we want, each immediate value must be cast to a u32.
+ */
+#define SCU_TASK_DONE_GOOD ((u32)0x00)
+#define SCU_TASK_DONE_CRC_ERR ((u32)0x14)
+#define SCU_TASK_DONE_CHECK_RESPONSE ((u32)0x14)
+#define SCU_TASK_DONE_GEN_RESPONSE ((u32)0x15)
+#define SCU_TASK_DONE_NAK_CMD_ERR ((u32)0x16)
+#define SCU_TASK_DONE_LL_R_ERR ((u32)0x17)
+#define SCU_TASK_DONE_ACK_NAK_TO ((u32)0x17)
+#define SCU_TASK_DONE_LL_PERR ((u32)0x18)
+#define SCU_TASK_DONE_LL_SY_TERM ((u32)0x19)
+#define SCU_TASK_DONE_NAK_ERR ((u32)0x19)
+#define SCU_TASK_DONE_LL_LF_TERM ((u32)0x1A)
+#define SCU_TASK_DONE_DATA_LEN_ERR ((u32)0x1A)
+#define SCU_TASK_DONE_LL_CL_TERM ((u32)0x1B)
+#define SCU_TASK_DONE_LL_ABORT_ERR ((u32)0x1B)
+#define SCU_TASK_DONE_SEQ_INV_TYPE ((u32)0x1C)
+#define SCU_TASK_DONE_UNEXP_XR ((u32)0x1C)
+#define SCU_TASK_DONE_INV_FIS_TYPE ((u32)0x1D)
+#define SCU_TASK_DONE_XR_IU_LEN_ERR ((u32)0x1D)
+#define SCU_TASK_DONE_INV_FIS_LEN ((u32)0x1E)
+#define SCU_TASK_DONE_XR_WD_LEN ((u32)0x1E)
+#define SCU_TASK_DONE_SDMA_ERR ((u32)0x1F)
+#define SCU_TASK_DONE_OFFSET_ERR ((u32)0x20)
+#define SCU_TASK_DONE_MAX_PLD_ERR ((u32)0x21)
+#define SCU_TASK_DONE_EXCESS_DATA ((u32)0x22)
+#define SCU_TASK_DONE_LF_ERR ((u32)0x23)
+#define SCU_TASK_DONE_UNEXP_FIS ((u32)0x24)
+#define SCU_TASK_DONE_UNEXP_RESP ((u32)0x24)
+#define SCU_TASK_DONE_EARLY_RESP ((u32)0x25)
+#define SCU_TASK_DONE_SMP_RESP_TO_ERR ((u32)0x26)
+#define SCU_TASK_DONE_DMASETUP_DIRERR ((u32)0x27)
+#define SCU_TASK_DONE_SMP_UFI_ERR ((u32)0x27)
+#define SCU_TASK_DONE_XFERCNT_ERR ((u32)0x28)
+#define SCU_TASK_DONE_SMP_FRM_TYPE_ERR ((u32)0x28)
+#define SCU_TASK_DONE_SMP_LL_RX_ERR ((u32)0x29)
+#define SCU_TASK_DONE_RESP_LEN_ERR ((u32)0x2A)
+#define SCU_TASK_DONE_UNEXP_DATA ((u32)0x2B)
+#define SCU_TASK_DONE_OPEN_FAIL ((u32)0x2C)
+#define SCU_TASK_DONE_UNEXP_SDBFIS ((u32)0x2D)
+#define SCU_TASK_DONE_REG_ERR ((u32)0x2E)
+#define SCU_TASK_DONE_SDB_ERR ((u32)0x2F)
+#define SCU_TASK_DONE_TASK_ABORT ((u32)0x30)
+#define SCU_TASK_OPEN_REJECT_WRONG_DESTINATION ((u32)0x34)
+#define SCU_TASK_OPEN_REJECT_RESERVED_ABANDON_1 ((u32)0x35)
+#define SCU_TASK_OPEN_REJECT_RESERVED_ABANDON_2 ((u32)0x36)
+#define SCU_TASK_OPEN_REJECT_RESERVED_ABANDON_3 ((u32)0x37)
+#define SCU_TASK_OPEN_REJECT_BAD_DESTINATION ((u32)0x38)
+#define SCU_TASK_OPEN_REJECT_ZONE_VIOLATION ((u32)0x39)
+#define SCU_TASK_DONE_VIIT_ENTRY_NV ((u32)0x3A)
+#define SCU_TASK_DONE_IIT_ENTRY_NV ((u32)0x3B)
+#define SCU_TASK_DONE_RNCNV_OUTBOUND ((u32)0x3C)
+#define SCU_TASK_OPEN_REJECT_STP_RESOURCES_BUSY ((u32)0x3D)
+#define SCU_TASK_OPEN_REJECT_PROTOCOL_NOT_SUPPORTED ((u32)0x3E)
+#define SCU_TASK_OPEN_REJECT_CONNECTION_RATE_NOT_SUPPORTED ((u32)0x3F)
+
+#endif /* _SCU_COMPLETION_CODES_HEADER_ */
diff --git a/drivers/scsi/isci/core/scu_constants.h b/drivers/scsi/isci/core/scu_constants.h
new file mode 100644
index 000000000000..a99d1103ad3b
--- /dev/null
+++ b/drivers/scsi/isci/core/scu_constants.h
@@ -0,0 +1,151 @@
+/*
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Intel Corporation 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
+ * OWNER 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.
+ */
+
+#ifndef _SCU_CONSTANTS_H_
+#define _SCU_CONSTANTS_H_
+
+/**
+ * This file contains the SCU hardware constants.
+ *
+ *
+ */
+
+#include "sci_controller_constants.h"
+
+/**
+ *
+ *
+ * 2 indicates the maximum number of UFs that can occur for a given IO request.
+ * The hardware handles reception of additional unsolicited frames while all
+ * UFs are in use, by holding off the transmitting device. This number could
+ * be theoretically reduced to 1, but 2 provides for more reliable operation.
+ * During SATA PIO operation, it is possible under some conditions for there to
+ * be 3 separate FISes received, back to back to back (PIO Setup, Data, D2H
+ * Register). It is unlikely to have all 3 pending all at once without some of
+ * them already being processed.
+ */
+#define SCU_MIN_UNSOLICITED_FRAMES (1)
+#define SCU_MIN_CRITICAL_NOTIFICATIONS (24)
+#define SCU_MIN_EVENTS (4)
+#define SCU_MIN_COMPLETION_QUEUE_SCRATCH (2)
+#define SCU_MIN_COMPLETION_QUEUE_ENTRIES (SCU_MIN_CRITICAL_NOTIFICATIONS \
+ + SCU_MIN_EVENTS \
+ + SCU_MIN_UNSOLICITED_FRAMES \
+ + SCI_MIN_IO_REQUESTS \
+ + SCU_MIN_COMPLETION_QUEUE_SCRATCH)
+
+#define SCU_MAX_CRITICAL_NOTIFICATIONS (384)
+#define SCU_MAX_EVENTS (128)
+#define SCU_MAX_UNSOLICITED_FRAMES (128)
+#define SCU_MAX_COMPLETION_QUEUE_SCRATCH (128)
+#define SCU_MAX_COMPLETION_QUEUE_ENTRIES (SCU_MAX_CRITICAL_NOTIFICATIONS \
+ + SCU_MAX_EVENTS \
+ + SCU_MAX_UNSOLICITED_FRAMES \
+ + SCI_MAX_IO_REQUESTS \
+ + SCU_MAX_COMPLETION_QUEUE_SCRATCH)
+
+#if !defined(ENABLE_MINIMUM_MEMORY_MODE)
+#define SCU_UNSOLICITED_FRAME_COUNT SCU_MAX_UNSOLICITED_FRAMES
+#define SCU_CRITICAL_NOTIFICATION_COUNT SCU_MAX_CRITICAL_NOTIFICATIONS
+#define SCU_EVENT_COUNT SCU_MAX_EVENTS
+#define SCU_COMPLETION_QUEUE_SCRATCH SCU_MAX_COMPLETION_QUEUE_SCRATCH
+#define SCU_IO_REQUEST_COUNT SCI_MAX_IO_REQUESTS
+#define SCU_IO_REQUEST_SGE_COUNT SCI_MAX_SCATTER_GATHER_ELEMENTS
+#define SCU_COMPLETION_QUEUE_COUNT SCU_MAX_COMPLETION_QUEUE_ENTRIES
+#else
+#define SCU_UNSOLICITED_FRAME_COUNT SCU_MIN_UNSOLICITED_FRAMES
+#define SCU_CRITICAL_NOTIFICATION_COUNT SCU_MIN_CRITICAL_NOTIFICATIONS
+#define SCU_EVENT_COUNT SCU_MIN_EVENTS
+#define SCU_COMPLETION_QUEUE_SCRATCH SCU_MIN_COMPLETION_QUEUE_SCRATCH
+#define SCU_IO_REQUEST_COUNT SCI_MIN_IO_REQUESTS
+#define SCU_IO_REQUEST_SGE_COUNT SCI_MIN_SCATTER_GATHER_ELEMENTS
+#define SCU_COMPLETION_QUEUE_COUNT SCU_MIN_COMPLETION_QUEUE_ENTRIES
+#endif /* !defined(ENABLE_MINIMUM_MEMORY_OPERATION) */
+
+/**
+ *
+ *
+ * The SCU_COMPLETION_QUEUE_COUNT constant indicates the size of the completion
+ * queue into which the hardware DMAs 32-bit quantas (completion entries).
+ */
+
+/**
+ *
+ *
+ * This queue must be programmed to a power of 2 size (e.g. 32, 64, 1024, etc.).
+ */
+#if (SCU_COMPLETION_QUEUE_COUNT != 16) && \
+ (SCU_COMPLETION_QUEUE_COUNT != 32) && \
+ (SCU_COMPLETION_QUEUE_COUNT != 64) && \
+ (SCU_COMPLETION_QUEUE_COUNT != 128) && \
+ (SCU_COMPLETION_QUEUE_COUNT != 256) && \
+ (SCU_COMPLETION_QUEUE_COUNT != 512) && \
+ (SCU_COMPLETION_QUEUE_COUNT != 1024)
+#error "SCU_COMPLETION_QUEUE_COUNT must be set to a power of 2."
+#endif
+
+#if SCU_MIN_UNSOLICITED_FRAMES > SCU_MAX_UNSOLICITED_FRAMES
+#error "Invalid configuration of unsolicited frame constants"
+#endif /* SCU_MIN_UNSOLICITED_FRAMES > SCU_MAX_UNSOLICITED_FRAMES */
+
+#define SCU_MIN_UF_TABLE_ENTRIES (8)
+#define SCU_ABSOLUTE_MAX_UNSOLICITED_FRAMES (4096)
+#define SCU_UNSOLICITED_FRAME_BUFFER_SIZE (1024)
+#define SCU_INVALID_FRAME_INDEX (0xFFFF)
+
+#define SCU_IO_REQUEST_MAX_SGE_SIZE (0x00FFFFFF)
+#define SCU_IO_REQUEST_MAX_TRANSFER_LENGTH (0x00FFFFFF)
+
+#endif /* _SCU_CONSTANTS_H_ */
diff --git a/drivers/scsi/isci/core/scu_event_codes.h b/drivers/scsi/isci/core/scu_event_codes.h
new file mode 100644
index 000000000000..36a945ad5722
--- /dev/null
+++ b/drivers/scsi/isci/core/scu_event_codes.h
@@ -0,0 +1,336 @@
+/*
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Intel Corporation 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
+ * OWNER 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.
+ */
+
+#ifndef __SCU_EVENT_CODES_HEADER__
+#define __SCU_EVENT_CODES_HEADER__
+
+/**
+ * This file contains the constants and macros for the SCU event codes.
+ *
+ *
+ */
+
+#define SCU_EVENT_TYPE_CODE_SHIFT 24
+#define SCU_EVENT_TYPE_CODE_MASK 0x0F000000
+
+#define SCU_EVENT_SPECIFIC_CODE_SHIFT 18
+#define SCU_EVENT_SPECIFIC_CODE_MASK 0x00FC0000
+
+#define SCU_EVENT_CODE_MASK \
+ (SCU_EVENT_TYPE_CODE_MASK | SCU_EVENT_SPECIFIC_CODE_MASK)
+
+/**
+ * SCU_EVENT_TYPE() -
+ *
+ * This macro constructs an SCU event type from the type value.
+ */
+#define SCU_EVENT_TYPE(type) \
+ ((u32)(type) << SCU_EVENT_TYPE_CODE_SHIFT)
+
+/**
+ * SCU_EVENT_SPECIFIC() -
+ *
+ * This macro constructs an SCU event specifier from the code value.
+ */
+#define SCU_EVENT_SPECIFIC(code) \
+ ((u32)(code) << SCU_EVENT_SPECIFIC_CODE_SHIFT)
+
+/**
+ * SCU_EVENT_MESSAGE() -
+ *
+ * This macro constructs a combines an SCU event type and SCU event specifier
+ * from the type and code values.
+ */
+#define SCU_EVENT_MESSAGE(type, code) \
+ ((type) | SCU_EVENT_SPECIFIC(code))
+
+/**
+ * SCU_EVENT_TYPE() -
+ *
+ * SCU_EVENT_TYPES
+ */
+#define SCU_EVENT_TYPE_SMU_COMMAND_ERROR SCU_EVENT_TYPE(0x08)
+#define SCU_EVENT_TYPE_SMU_PCQ_ERROR SCU_EVENT_TYPE(0x09)
+#define SCU_EVENT_TYPE_SMU_ERROR SCU_EVENT_TYPE(0x00)
+#define SCU_EVENT_TYPE_TRANSPORT_ERROR SCU_EVENT_TYPE(0x01)
+#define SCU_EVENT_TYPE_BROADCAST_CHANGE SCU_EVENT_TYPE(0x02)
+#define SCU_EVENT_TYPE_OSSP_EVENT SCU_EVENT_TYPE(0x03)
+#define SCU_EVENT_TYPE_FATAL_MEMORY_ERROR SCU_EVENT_TYPE(0x0F)
+#define SCU_EVENT_TYPE_RNC_SUSPEND_TX SCU_EVENT_TYPE(0x04)
+#define SCU_EVENT_TYPE_RNC_SUSPEND_TX_RX SCU_EVENT_TYPE(0x05)
+#define SCU_EVENT_TYPE_RNC_OPS_MISC SCU_EVENT_TYPE(0x06)
+#define SCU_EVENT_TYPE_PTX_SCHEDULE_EVENT SCU_EVENT_TYPE(0x07)
+#define SCU_EVENT_TYPE_ERR_CNT_EVENT SCU_EVENT_TYPE(0x0A)
+
+/**
+ *
+ *
+ * SCU_EVENT_SPECIFIERS
+ */
+#define SCU_EVENT_SPECIFIER_DRIVER_SUSPEND 0x20
+#define SCU_EVENT_SPECIFIER_RNC_RELEASE 0x00
+
+/**
+ *
+ *
+ * SMU_COMMAND_EVENTS
+ */
+#define SCU_EVENT_INVALID_CONTEXT_COMMAND \
+ SCU_EVENT_MESSAGE(SCU_EVENT_TYPE_SMU_COMMAND_ERROR, 0x00)
+
+/**
+ *
+ *
+ * SMU_PCQ_EVENTS
+ */
+#define SCU_EVENT_UNCORRECTABLE_PCQ_ERROR \
+ SCU_EVENT_MESSAGE(SCU_EVENT_TYPE_SMU_PCQ_ERROR, 0x00)
+
+/**
+ *
+ *
+ * SMU_EVENTS
+ */
+#define SCU_EVENT_UNCORRECTABLE_REGISTER_WRITE \
+ SCU_EVENT_MESSAGE(SCU_EVENT_TYPE_SMU_ERROR, 0x02)
+#define SCU_EVENT_UNCORRECTABLE_REGISTER_READ \
+ SCU_EVENT_MESSAGE(SCU_EVENT_TYPE_SMU_ERROR, 0x03)
+#define SCU_EVENT_PCIE_INTERFACE_ERROR \
+ SCU_EVENT_MESSAGE(SCU_EVENT_TYPE_SMU_ERROR, 0x04)
+#define SCU_EVENT_FUNCTION_LEVEL_RESET \
+ SCU_EVENT_MESSAGE(SCU_EVENT_TYPE_SMU_ERROR, 0x05)
+
+/**
+ *
+ *
+ * TRANSPORT_LEVEL_ERRORS
+ */
+#define SCU_EVENT_ACK_NAK_TIMEOUT_ERROR \
+ SCU_EVENT_MESSAGE(SCU_EVENT_TYPE_TRANSPORT_ERROR, 0x00)
+
+/**
+ *
+ *
+ * BROADCAST_CHANGE_EVENTS
+ */
+#define SCU_EVENT_BROADCAST_CHANGE \
+ SCU_EVENT_MESSAGE(SCU_EVENT_TYPE_BROADCAST_CHANGE, 0x01)
+#define SCU_EVENT_BROADCAST_RESERVED0 \
+ SCU_EVENT_MESSAGE(SCU_EVENT_TYPE_BROADCAST_CHANGE, 0x02)
+#define SCU_EVENT_BROADCAST_RESERVED1 \
+ SCU_EVENT_MESSAGE(SCU_EVENT_TYPE_BROADCAST_CHANGE, 0x03)
+#define SCU_EVENT_BROADCAST_SES \
+ SCU_EVENT_MESSAGE(SCU_EVENT_TYPE_BROADCAST_CHANGE, 0x04)
+#define SCU_EVENT_BROADCAST_EXPANDER \
+ SCU_EVENT_MESSAGE(SCU_EVENT_TYPE_BROADCAST_CHANGE, 0x05)
+#define SCU_EVENT_BROADCAST_AEN \
+ SCU_EVENT_MESSAGE(SCU_EVENT_TYPE_BROADCAST_CHANGE, 0x06)
+#define SCU_EVENT_BROADCAST_RESERVED3 \
+ SCU_EVENT_MESSAGE(SCU_EVENT_TYPE_BROADCAST_CHANGE, 0x07)
+#define SCU_EVENT_BROADCAST_RESERVED4 \
+ SCU_EVENT_MESSAGE(SCU_EVENT_TYPE_BROADCAST_CHANGE, 0x08)
+#define SCU_EVENT_PE_SUSPENDED \
+ SCU_EVENT_MESSAGE(SCU_EVENT_TYPE_BROADCAST_CHANGE, 0x09)
+
+/**
+ *
+ *
+ * OSSP_EVENTS
+ */
+#define SCU_EVENT_PORT_SELECTOR_DETECTED \
+ SCU_EVENT_MESSAGE(SCU_EVENT_TYPE_OSSP_EVENT, 0x10)
+#define SCU_EVENT_SENT_PORT_SELECTION \
+ SCU_EVENT_MESSAGE(SCU_EVENT_TYPE_OSSP_EVENT, 0x11)
+#define SCU_EVENT_HARD_RESET_TRANSMITTED \
+ SCU_EVENT_MESSAGE(SCU_EVENT_TYPE_OSSP_EVENT, 0x12)
+#define SCU_EVENT_HARD_RESET_RECEIVED \
+ SCU_EVENT_MESSAGE(SCU_EVENT_TYPE_OSSP_EVENT, 0x13)
+#define SCU_EVENT_RECEIVED_IDENTIFY_TIMEOUT \
+ SCU_EVENT_MESSAGE(SCU_EVENT_TYPE_OSSP_EVENT, 0x15)
+#define SCU_EVENT_LINK_FAILURE \
+ SCU_EVENT_MESSAGE(SCU_EVENT_TYPE_OSSP_EVENT, 0x16)
+#define SCU_EVENT_SATA_SPINUP_HOLD \
+ SCU_EVENT_MESSAGE(SCU_EVENT_TYPE_OSSP_EVENT, 0x17)
+#define SCU_EVENT_SAS_15_SSC \
+ SCU_EVENT_MESSAGE(SCU_EVENT_TYPE_OSSP_EVENT, 0x18)
+#define SCU_EVENT_SAS_15 \
+ SCU_EVENT_MESSAGE(SCU_EVENT_TYPE_OSSP_EVENT, 0x19)
+#define SCU_EVENT_SAS_30_SSC \
+ SCU_EVENT_MESSAGE(SCU_EVENT_TYPE_OSSP_EVENT, 0x1A)
+#define SCU_EVENT_SAS_30 \
+ SCU_EVENT_MESSAGE(SCU_EVENT_TYPE_OSSP_EVENT, 0x1B)
+#define SCU_EVENT_SAS_60_SSC \
+ SCU_EVENT_MESSAGE(SCU_EVENT_TYPE_OSSP_EVENT, 0x1C)
+#define SCU_EVENT_SAS_60 \
+ SCU_EVENT_MESSAGE(SCU_EVENT_TYPE_OSSP_EVENT, 0x1D)
+#define SCU_EVENT_SATA_15_SSC \
+ SCU_EVENT_MESSAGE(SCU_EVENT_TYPE_OSSP_EVENT, 0x1E)
+#define SCU_EVENT_SATA_15 \
+ SCU_EVENT_MESSAGE(SCU_EVENT_TYPE_OSSP_EVENT, 0x1F)
+#define SCU_EVENT_SATA_30_SSC \
+ SCU_EVENT_MESSAGE(SCU_EVENT_TYPE_OSSP_EVENT, 0x20)
+#define SCU_EVENT_SATA_30 \
+ SCU_EVENT_MESSAGE(SCU_EVENT_TYPE_OSSP_EVENT, 0x21)
+#define SCU_EVENT_SATA_60_SSC \
+ SCU_EVENT_MESSAGE(SCU_EVENT_TYPE_OSSP_EVENT, 0x22)
+#define SCU_EVENT_SATA_60 \
+ SCU_EVENT_MESSAGE(SCU_EVENT_TYPE_OSSP_EVENT, 0x23)
+#define SCU_EVENT_SAS_PHY_DETECTED \
+ SCU_EVENT_MESSAGE(SCU_EVENT_TYPE_OSSP_EVENT, 0x24)
+#define SCU_EVENT_SATA_PHY_DETECTED \
+ SCU_EVENT_MESSAGE(SCU_EVENT_TYPE_OSSP_EVENT, 0x25)
+
+/**
+ *
+ *
+ * FATAL_INTERNAL_MEMORY_ERROR_EVENTS
+ */
+#define SCU_EVENT_TSC_RNSC_UNCORRECTABLE_ERROR \
+ SCU_EVENT_MESSAGE(SCU_EVENT_TYPE_FATAL_MEMORY_ERROR, 0x00)
+#define SCU_EVENT_TC_RNC_UNCORRECTABLE_ERROR \
+ SCU_EVENT_MESSAGE(SCU_EVENT_TYPE_FATAL_MEMORY_ERROR, 0x01)
+#define SCU_EVENT_ZPT_UNCORRECTABLE_ERROR \
+ SCU_EVENT_MESSAGE(SCU_EVENT_TYPE_FATAL_MEMORY_ERROR, 0x02)
+
+/**
+ *
+ *
+ * REMOTE_NODE_SUSPEND_EVENTS
+ */
+#define SCU_EVENT_TL_RNC_SUSPEND_TX \
+ SCU_EVENT_MESSAGE(SCU_EVENT_TYPE_RNC_SUSPEND_TX, 0x00)
+#define SCU_EVENT_TL_RNC_SUSPEND_TX_RX \
+ SCU_EVENT_MESSAGE(SCU_EVENT_TYPE_RNC_SUSPEND_TX_RX, 0x00)
+#define SCU_EVENT_DRIVER_POST_RNC_SUSPEND_TX \
+ SCU_EVENT_MESSAGE(SCU_EVENT_TYPE_RNC_SUSPEND_TX, 0x20)
+#define SCU_EVENT_DRIVER_POST_RNC_SUSPEND_TX_RX \
+ SCU_EVENT_MESSAGE(SCU_EVENT_TYPE_RNC_SUSPEND_TX_RX, 0x20)
+
+/**
+ *
+ *
+ * REMOTE_NODE_MISC_EVENTS
+ */
+#define SCU_EVENT_POST_RCN_RELEASE \
+ SCU_EVENT_MESSAGE(SCU_EVENT_TYPE_RNC_OPS_MISC, SCU_EVENT_SPECIFIER_RNC_RELEASE)
+#define SCU_EVENT_POST_IT_NEXUS_LOSS_TIMER_ENABLE \
+ SCU_EVENT_MESSAGE(SCU_EVENT_TYPE_RNC_OPS_MISC, 0x01)
+#define SCU_EVENT_POST_IT_NEXUS_LOSS_TIMER_DISABLE \
+ SCU_EVENT_MESSAGE(SCU_EVENT_TYPE_RNC_OPS_MISC, 0x02)
+#define SCU_EVENT_POST_RNC_COMPLETE \
+ SCU_EVENT_MESSAGE(SCU_EVENT_TYPE_RNC_OPS_MISC, 0x03)
+#define SCU_EVENT_POST_RNC_INVALIDATE_COMPLETE \
+ SCU_EVENT_MESSAGE(SCU_EVENT_TYPE_RNC_OPS_MISC, 0x04)
+
+/**
+ *
+ *
+ * ERROR_COUNT_EVENT
+ */
+#define SCU_EVENT_RX_CREDIT_BLOCKED_RECEIVED \
+ SCU_EVENT_MESSAGE(SCU_EVENT_TYPE_ERR_CNT_EVENT, 0x00)
+#define SCU_EVENT_TX_DONE_CREDIT_TIMEOUT \
+ SCU_EVENT_MESSAGE(SCU_EVENT_TYPE_ERR_CNT_EVENT, 0x01)
+#define SCU_EVENT_RX_DONE_CREDIT_TIMEOUT \
+ SCU_EVENT_MESSAGE(SCU_EVENT_TYPE_ERR_CNT_EVENT, 0x02)
+
+/**
+ * scu_get_event_type() -
+ *
+ * This macro returns the SCU event type from the event code.
+ */
+#define scu_get_event_type(event_code) \
+ ((event_code) & SCU_EVENT_TYPE_CODE_MASK)
+
+/**
+ * scu_get_event_specifier() -
+ *
+ * This macro returns the SCU event specifier from the event code.
+ */
+#define scu_get_event_specifier(event_code) \
+ ((event_code) & SCU_EVENT_SPECIFIC_CODE_MASK)
+
+/**
+ * scu_get_event_code() -
+ *
+ * This macro returns the combined SCU event type and SCU event specifier from
+ * the event code.
+ */
+#define scu_get_event_code(event_code) \
+ ((event_code) & SCU_EVENT_CODE_MASK)
+
+
+/**
+ *
+ *
+ * PTS_SCHEDULE_EVENT
+ */
+#define SCU_EVENT_SMP_RESPONSE_NO_PE \
+ SCU_EVENT_MESSAGE(SCU_EVENT_TYPE_PTX_SCHEDULE_EVENT, 0x00)
+#define SCU_EVENT_SPECIFIC_SMP_RESPONSE_NO_PE \
+ scu_get_event_specifier(SCU_EVENT_SMP_RESPONSE_NO_PE)
+
+#define SCU_EVENT_TASK_TIMEOUT \
+ SCU_EVENT_MESSAGE(SCU_EVENT_TYPE_PTX_SCHEDULE_EVENT, 0x01)
+#define SCU_EVENT_SPECIFIC_TASK_TIMEOUT \
+ scu_get_event_specifier(SCU_EVENT_TASK_TIMEOUT)
+
+#define SCU_EVENT_IT_NEXUS_TIMEOUT \
+ SCU_EVENT_MESSAGE(SCU_EVENT_TYPE_PTX_SCHEDULE_EVENT, 0x02)
+#define SCU_EVENT_SPECIFIC_IT_NEXUS_TIMEOUT \
+ scu_get_event_specifier(SCU_EVENT_IT_NEXUS_TIMEOUT)
+
+
+#endif /* __SCU_EVENT_CODES_HEADER__ */
diff --git a/drivers/scsi/isci/core/scu_registers.h b/drivers/scsi/isci/core/scu_registers.h
new file mode 100644
index 000000000000..175d2b98bdf2
--- /dev/null
+++ b/drivers/scsi/isci/core/scu_registers.h
@@ -0,0 +1,1824 @@
+/*
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Intel Corporation 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
+ * OWNER 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.
+ */
+
+#ifndef _SCU_REGISTERS_H_
+#define _SCU_REGISTERS_H_
+
+/**
+ * This file contains the constants and structures for the SCU memory mapped
+ * registers.
+ *
+ *
+ */
+
+#include "sci_types.h"
+#include "scu_viit_data.h"
+
+
+/* Generate a value for an SCU register */
+#define SCU_GEN_VALUE(name, value) \
+ (((value) << name ## _SHIFT) & (name ## _MASK))
+
+/*
+ * Generate a bit value for an SCU register
+ * Make sure that the register MASK is just a single bit */
+#define SCU_GEN_BIT(name) \
+ SCU_GEN_VALUE(name, ((u32)1))
+
+#define SCU_SET_BIT(name, reg_value) \
+ ((reg_value) | SCU_GEN_BIT(name))
+
+#define SCU_CLEAR_BIT(name, reg_value) \
+ ((reg_value)$ ~(SCU_GEN_BIT(name)))
+
+/*
+ * *****************************************************************************
+ * Unions for bitfield definitions of SCU Registers
+ * SMU Post Context Port
+ * ***************************************************************************** */
+#define SMU_POST_CONTEXT_PORT_CONTEXT_INDEX_SHIFT (0)
+#define SMU_POST_CONTEXT_PORT_CONTEXT_INDEX_MASK (0x00000FFF)
+#define SMU_POST_CONTEXT_PORT_LOGICAL_PORT_INDEX_SHIFT (12)
+#define SMU_POST_CONTEXT_PORT_LOGICAL_PORT_INDEX_MASK (0x0000F000)
+#define SMU_POST_CONTEXT_PORT_PROTOCOL_ENGINE_SHIFT (16)
+#define SMU_POST_CONTEXT_PORT_PROTOCOL_ENGINE_MASK (0x00030000)
+#define SMU_POST_CONTEXT_PORT_COMMAND_CONTEXT_SHIFT (18)
+#define SMU_POST_CONTEXT_PORT_COMMAND_CONTEXT_MASK (0x00FC0000)
+#define SMU_POST_CONTEXT_PORT_RESERVED_MASK (0xFF000000)
+
+#define SMU_PCP_GEN_VAL(name, value) \
+ SCU_GEN_VALUE(SMU_POST_CONTEXT_PORT_ ## name, value)
+
+/* ***************************************************************************** */
+#define SMU_INTERRUPT_STATUS_COMPLETION_SHIFT (31)
+#define SMU_INTERRUPT_STATUS_COMPLETION_MASK (0x80000000)
+#define SMU_INTERRUPT_STATUS_QUEUE_SUSPEND_SHIFT (1)
+#define SMU_INTERRUPT_STATUS_QUEUE_SUSPEND_MASK (0x00000002)
+#define SMU_INTERRUPT_STATUS_QUEUE_ERROR_SHIFT (0)
+#define SMU_INTERRUPT_STATUS_QUEUE_ERROR_MASK (0x00000001)
+#define SMU_INTERRUPT_STATUS_RESERVED_MASK (0x7FFFFFFC)
+
+#define SMU_ISR_GEN_BIT(name) \
+ SCU_GEN_BIT(SMU_INTERRUPT_STATUS_ ## name)
+
+#define SMU_ISR_QUEUE_ERROR SMU_ISR_GEN_BIT(QUEUE_ERROR)
+#define SMU_ISR_QUEUE_SUSPEND SMU_ISR_GEN_BIT(QUEUE_SUSPEND)
+#define SMU_ISR_COMPLETION SMU_ISR_GEN_BIT(COMPLETION)
+
+/* ***************************************************************************** */
+#define SMU_INTERRUPT_MASK_COMPLETION_SHIFT (31)
+#define SMU_INTERRUPT_MASK_COMPLETION_MASK (0x80000000)
+#define SMU_INTERRUPT_MASK_QUEUE_SUSPEND_SHIFT (1)
+#define SMU_INTERRUPT_MASK_QUEUE_SUSPEND_MASK (0x00000002)
+#define SMU_INTERRUPT_MASK_QUEUE_ERROR_SHIFT (0)
+#define SMU_INTERRUPT_MASK_QUEUE_ERROR_MASK (0x00000001)
+#define SMU_INTERRUPT_MASK_RESERVED_MASK (0x7FFFFFFC)
+
+#define SMU_IMR_GEN_BIT(name) \
+ SCU_GEN_BIT(SMU_INTERRUPT_MASK_ ## name)
+
+#define SMU_IMR_QUEUE_ERROR SMU_IMR_GEN_BIT(QUEUE_ERROR)
+#define SMU_IMR_QUEUE_SUSPEND SMU_IMR_GEN_BIT(QUEUE_SUSPEND)
+#define SMU_IMR_COMPLETION SMU_IMR_GEN_BIT(COMPLETION)
+
+/* ***************************************************************************** */
+#define SMU_INTERRUPT_COALESCING_CONTROL_TIMER_SHIFT (0)
+#define SMU_INTERRUPT_COALESCING_CONTROL_TIMER_MASK (0x0000001F)
+#define SMU_INTERRUPT_COALESCING_CONTROL_NUMBER_SHIFT (8)
+#define SMU_INTERRUPT_COALESCING_CONTROL_NUMBER_MASK (0x0000FF00)
+#define SMU_INTERRUPT_COALESCING_CONTROL_RESERVED_MASK (0xFFFF00E0)
+
+#define SMU_ICC_GEN_VAL(name, value) \
+ SCU_GEN_VALUE(SMU_INTERRUPT_COALESCING_CONTROL_ ## name, value)
+
+/* ***************************************************************************** */
+#define SMU_TASK_CONTEXT_RANGE_START_SHIFT (0)
+#define SMU_TASK_CONTEXT_RANGE_START_MASK (0x00000FFF)
+#define SMU_TASK_CONTEXT_RANGE_ENDING_SHIFT (16)
+#define SMU_TASK_CONTEXT_RANGE_ENDING_MASK (0x0FFF0000)
+#define SMU_TASK_CONTEXT_RANGE_ENABLE_SHIFT (31)
+#define SMU_TASK_CONTEXT_RANGE_ENABLE_MASK (0x80000000)
+#define SMU_TASK_CONTEXT_RANGE_RESERVED_MASK (0x7000F000)
+
+#define SMU_TCR_GEN_VAL(name, value) \
+ SCU_GEN_VALUE(SMU_TASK_CONTEXT_RANGE_ ## name, value)
+
+#define SMU_TCR_GEN_BIT(name, value) \
+ SCU_GEN_BIT(SMU_TASK_CONTEXT_RANGE_ ## name)
+
+/* ***************************************************************************** */
+
+#define SMU_COMPLETION_QUEUE_PUT_POINTER_SHIFT (0)
+#define SMU_COMPLETION_QUEUE_PUT_POINTER_MASK (0x00003FFF)
+#define SMU_COMPLETION_QUEUE_PUT_CYCLE_BIT_SHIFT (15)
+#define SMU_COMPLETION_QUEUE_PUT_CYCLE_BIT_MASK (0x00008000)
+#define SMU_COMPLETION_QUEUE_PUT_EVENT_POINTER_SHIFT (16)
+#define SMU_COMPLETION_QUEUE_PUT_EVENT_POINTER_MASK (0x03FF0000)
+#define SMU_COMPLETION_QUEUE_PUT_EVENT_CYCLE_BIT_SHIFT (26)
+#define SMU_COMPLETION_QUEUE_PUT_EVENT_CYCLE_BIT_MASK (0x04000000)
+#define SMU_COMPLETION_QUEUE_PUT_RESERVED_MASK (0xF8004000)
+
+#define SMU_CQPR_GEN_VAL(name, value) \
+ SCU_GEN_VALUE(SMU_COMPLETION_QUEUE_PUT_ ## name, value)
+
+#define SMU_CQPR_GEN_BIT(name) \
+ SCU_GEN_BIT(SMU_COMPLETION_QUEUE_PUT_ ## name)
+
+/* ***************************************************************************** */
+
+#define SMU_COMPLETION_QUEUE_GET_POINTER_SHIFT (0)
+#define SMU_COMPLETION_QUEUE_GET_POINTER_MASK (0x00003FFF)
+#define SMU_COMPLETION_QUEUE_GET_CYCLE_BIT_SHIFT (15)
+#define SMU_COMPLETION_QUEUE_GET_CYCLE_BIT_MASK (0x00008000)
+#define SMU_COMPLETION_QUEUE_GET_EVENT_POINTER_SHIFT (16)
+#define SMU_COMPLETION_QUEUE_GET_EVENT_POINTER_MASK (0x03FF0000)
+#define SMU_COMPLETION_QUEUE_GET_EVENT_CYCLE_BIT_SHIFT (26)
+#define SMU_COMPLETION_QUEUE_GET_EVENT_CYCLE_BIT_MASK (0x04000000)
+#define SMU_COMPLETION_QUEUE_GET_ENABLE_SHIFT (30)
+#define SMU_COMPLETION_QUEUE_GET_ENABLE_MASK (0x40000000)
+#define SMU_COMPLETION_QUEUE_GET_EVENT_ENABLE_SHIFT (31)
+#define SMU_COMPLETION_QUEUE_GET_EVENT_ENABLE_MASK (0x80000000)
+#define SMU_COMPLETION_QUEUE_GET_RESERVED_MASK (0x38004000)
+
+#define SMU_CQGR_GEN_VAL(name, value) \
+ SCU_GEN_VALUE(SMU_COMPLETION_QUEUE_GET_ ## name, value)
+
+#define SMU_CQGR_GEN_BIT(name) \
+ SCU_GEN_BIT(SMU_COMPLETION_QUEUE_GET_ ## name)
+
+#define SMU_CQGR_CYCLE_BIT \
+ SMU_CQGR_GEN_BIT(CYCLE_BIT)
+
+#define SMU_CQGR_EVENT_CYCLE_BIT \
+ SMU_CQGR_GEN_BIT(EVENT_CYCLE_BIT)
+
+#define SMU_CQGR_GET_POINTER_SET(value) \
+ SMU_CQGR_GEN_VAL(POINTER, value)
+
+
+/* ***************************************************************************** */
+#define SMU_COMPLETION_QUEUE_CONTROL_QUEUE_LIMIT_SHIFT (0)
+#define SMU_COMPLETION_QUEUE_CONTROL_QUEUE_LIMIT_MASK (0x00003FFF)
+#define SMU_COMPLETION_QUEUE_CONTROL_EVENT_LIMIT_SHIFT (16)
+#define SMU_COMPLETION_QUEUE_CONTROL_EVENT_LIMIT_MASK (0x03FF0000)
+#define SMU_COMPLETION_QUEUE_CONTROL_RESERVED_MASK (0xFC00C000)
+
+#define SMU_CQC_GEN_VAL(name, value) \
+ SCU_GEN_VALUE(SMU_COMPLETION_QUEUE_CONTROL_ ## name, value)
+
+#define SMU_CQC_QUEUE_LIMIT_SET(value) \
+ SMU_CQC_GEN_VAL(QUEUE_LIMIT, value)
+
+#define SMU_CQC_EVENT_LIMIT_SET(value) \
+ SMU_CQC_GEN_VAL(EVENT_LIMIT, value)
+
+
+/* ***************************************************************************** */
+#define SMU_DEVICE_CONTEXT_CAPACITY_MAX_TC_SHIFT (0)
+#define SMU_DEVICE_CONTEXT_CAPACITY_MAX_TC_MASK (0x00000FFF)
+#define SMU_DEVICE_CONTEXT_CAPACITY_MAX_LP_SHIFT (12)
+#define SMU_DEVICE_CONTEXT_CAPACITY_MAX_LP_MASK (0x00007000)
+#define SMU_DEVICE_CONTEXT_CAPACITY_MAX_RNC_SHIFT (15)
+#define SMU_DEVICE_CONTEXT_CAPACITY_MAX_RNC_MASK (0x07FF8000)
+#define SMU_DEVICE_CONTEXT_CAPACITY_MAX_PEG_SHIFT (27)
+#define SMU_DEVICE_CONTEXT_CAPACITY_MAX_PEG_MASK (0x08000000)
+#define SMU_DEVICE_CONTEXT_CAPACITY_RESERVED_MASK (0xF0000000)
+
+#define SMU_DCC_GEN_VAL(name, value) \
+ SCU_GEN_VALUE(SMU_DEVICE_CONTEXT_CAPACITY_ ## name, value)
+
+#define SMU_DCC_GET_MAX_PEG(value) \
+ (\
+ ((value) & SMU_DEVICE_CONTEXT_CAPACITY_MAX_PEG_MASK) \
+ >> SMU_DEVICE_CONTEXT_CAPACITY_MAX_LP_SHIFT \
+ )
+
+#define SMU_DCC_GET_MAX_LP(value) \
+ (\
+ ((value) & SMU_DEVICE_CONTEXT_CAPACITY_MAX_LP_MASK) \
+ >> SMU_DEVICE_CONTEXT_CAPACITY_MAX_LP_SHIFT \
+ )
+
+#define SMU_DCC_GET_MAX_TC(value) \
+ (\
+ ((value) & SMU_DEVICE_CONTEXT_CAPACITY_MAX_TC_MASK) \
+ >> SMU_DEVICE_CONTEXT_CAPACITY_MAX_TC_SHIFT \
+ )
+
+#define SMU_DCC_GET_MAX_RNC(value) \
+ (\
+ ((value) & SMU_DEVICE_CONTEXT_CAPACITY_MAX_RNC_MASK) \
+ >> SMU_DEVICE_CONTEXT_CAPACITY_MAX_RNC_SHIFT \
+ )
+
+/* -------------------------------------------------------------------------- */
+
+#define SMU_CONTROL_STATUS_TASK_CONTEXT_RANGE_ENABLE_SHIFT (0)
+#define SMU_CONTROL_STATUS_TASK_CONTEXT_RANGE_ENABLE_MASK (0x00000001)
+#define SMU_CONTROL_STATUS_COMPLETION_BYTE_SWAP_ENABLE_SHIFT (1)
+#define SMU_CONTROL_STATUS_COMPLETION_BYTE_SWAP_ENABLE_MASK (0x00000002)
+#define SMU_CONTROL_STATUS_CONTEXT_RAM_INIT_COMPLETED_SHIFT (16)
+#define SMU_CONTROL_STATUS_CONTEXT_RAM_INIT_COMPLETED_MASK (0x00010000)
+#define SMU_CONTROL_STATUS_SCHEDULER_RAM_INIT_COMPLETED_SHIFT (17)
+#define SMU_CONTROL_STATUS_SCHEDULER_RAM_INIT_COMPLETED_MASK (0x00020000)
+#define SMU_CONTROL_STATUS_RESERVED_MASK (0xFFFCFFFC)
+
+#define SMU_SMUCSR_GEN_BIT(name) \
+ SCU_GEN_BIT(SMU_CONTROL_STATUS_ ## name)
+
+#define SMU_SMUCSR_SCHEDULER_RAM_INIT_COMPLETED \
+ (SMU_SMUCSR_GEN_BIT(SCHEDULER_RAM_INIT_COMPLETED))
+
+#define SMU_SMUCSR_CONTEXT_RAM_INIT_COMPLETED \
+ (SMU_SMUCSR_GEN_BIT(CONTEXT_RAM_INIT_COMPLETED))
+
+#define SCU_RAM_INIT_COMPLETED \
+ (\
+ SMU_SMUCSR_CONTEXT_RAM_INIT_COMPLETED \
+ | SMU_SMUCSR_SCHEDULER_RAM_INIT_COMPLETED \
+ )
+
+/* -------------------------------------------------------------------------- */
+
+#define SMU_SOFTRESET_CONTROL_RESET_PEG0_PE0_SHIFT (0)
+#define SMU_SOFTRESET_CONTROL_RESET_PEG0_PE0_MASK (0x00000001)
+#define SMU_SOFTRESET_CONTROL_RESET_PEG0_PE1_SHIFT (1)
+#define SMU_SOFTRESET_CONTROL_RESET_PEG0_PE1_MASK (0x00000002)
+#define SMU_SOFTRESET_CONTROL_RESET_PEG0_PE2_SHIFT (2)
+#define SMU_SOFTRESET_CONTROL_RESET_PEG0_PE2_MASK (0x00000004)
+#define SMU_SOFTRESET_CONTROL_RESET_PEG0_PE3_SHIFT (3)
+#define SMU_SOFTRESET_CONTROL_RESET_PEG0_PE3_MASK (0x00000008)
+#define SMU_SOFTRESET_CONTROL_RESET_PEG1_PE0_SHIFT (8)
+#define SMU_SOFTRESET_CONTROL_RESET_PEG1_PE0_MASK (0x00000100)
+#define SMU_SOFTRESET_CONTROL_RESET_PEG1_PE1_SHIFT (9)
+#define SMU_SOFTRESET_CONTROL_RESET_PEG1_PE1_MASK (0x00000200)
+#define SMU_SOFTRESET_CONTROL_RESET_PEG1_PE2_SHIFT (10)
+#define SMU_SOFTRESET_CONTROL_RESET_PEG1_PE2_MASK (0x00000400)
+#define SMU_SOFTRESET_CONTROL_RESET_PEG1_PE3_SHIFT (11)
+#define SMU_SOFTRESET_CONTROL_RESET_PEG1_PE3_MASK (0x00000800)
+
+#define SMU_RESET_PROTOCOL_ENGINE(peg, pe) \
+ ((1 << (pe)) << ((peg) * 8))
+
+#define SMU_RESET_PEG_PROTOCOL_ENGINES(peg) \
+ (\
+ SMU_RESET_PROTOCOL_ENGINE(peg, 0) \
+ | SMU_RESET_PROTOCOL_ENGINE(peg, 1) \
+ | SMU_RESET_PROTOCOL_ENGINE(peg, 2) \
+ | SMU_RESET_PROTOCOL_ENGINE(peg, 3) \
+ )
+
+#define SMU_RESET_ALL_PROTOCOL_ENGINES() \
+ (\
+ SMU_RESET_PEG_PROTOCOL_ENGINES(0) \
+ | SMU_RESET_PEG_PROTOCOL_ENGINES(1) \
+ )
+
+#define SMU_SOFTRESET_CONTROL_RESET_WIDE_PORT_PEG0_LP0_SHIFT (16)
+#define SMU_SOFTRESET_CONTROL_RESET_WIDE_PORT_PEG0_LP0_MASK (0x00010000)
+#define SMU_SOFTRESET_CONTROL_RESET_WIDE_PORT_PEG0_LP2_SHIFT (17)
+#define SMU_SOFTRESET_CONTROL_RESET_WIDE_PORT_PEG0_LP2_MASK (0x00020000)
+#define SMU_SOFTRESET_CONTROL_RESET_WIDE_PORT_PEG1_LP0_SHIFT (18)
+#define SMU_SOFTRESET_CONTROL_RESET_WIDE_PORT_PEG1_LP0_MASK (0x00040000)
+#define SMU_SOFTRESET_CONTROL_RESET_WIDE_PORT_PEG1_LP2_SHIFT (19)
+#define SMU_SOFTRESET_CONTROL_RESET_WIDE_PORT_PEG1_LP2_MASK (0x00080000)
+
+#define SMU_RESET_WIDE_PORT_QUEUE(peg, wide_port) \
+ ((1 << ((wide_port) / 2)) << ((peg) * 2) << 16)
+
+#define SMU_SOFTRESET_CONTROL_RESET_PEG0_SHIFT (20)
+#define SMU_SOFTRESET_CONTROL_RESET_PEG0_MASK (0x00100000)
+#define SMU_SOFTRESET_CONTROL_RESET_PEG1_SHIFT (21)
+#define SMU_SOFTRESET_CONTROL_RESET_PEG1_MASK (0x00200000)
+#define SMU_SOFTRESET_CONTROL_RESET_SCU_SHIFT (22)
+#define SMU_SOFTRESET_CONTROL_RESET_SCU_MASK (0x00400000)
+
+/*
+ * It seems to make sense that if you are going to reset the protocol
+ * engine group that you would also reset all of the protocol engines */
+#define SMU_RESET_PROTOCOL_ENGINE_GROUP(peg) \
+ (\
+ (1 << ((peg) + 20)) \
+ | SMU_RESET_WIDE_PORT_QUEUE(peg, 0) \
+ | SMU_RESET_WIDE_PORT_QUEUE(peg, 1) \
+ | SMU_RESET_PEG_PROTOCOL_ENGINES(peg) \
+ )
+
+#define SMU_RESET_ALL_PROTOCOL_ENGINE_GROUPS() \
+ (\
+ SMU_RESET_PROTOCOL_ENGINE_GROUP(0) \
+ | SMU_RESET_PROTOCOL_ENGINE_GROUP(1) \
+ )
+
+#define SMU_RESET_SCU() (0xFFFFFFFF)
+
+
+
+/* ***************************************************************************** */
+#define SMU_TASK_CONTEXT_ASSIGNMENT_STARTING_SHIFT (0)
+#define SMU_TASK_CONTEXT_ASSIGNMENT_STARTING_MASK (0x00000FFF)
+#define SMU_TASK_CONTEXT_ASSIGNMENT_ENDING_SHIFT (16)
+#define SMU_TASK_CONTEXT_ASSIGNMENT_ENDING_MASK (0x0FFF0000)
+#define SMU_TASK_CONTEXT_ASSIGNMENT_RANGE_CHECK_ENABLE_SHIFT (31)
+#define SMU_TASK_CONTEXT_ASSIGNMENT_RANGE_CHECK_ENABLE_MASK (0x80000000)
+#define SMU_TASK_CONTEXT_ASSIGNMENT_RESERVED_MASK (0x7000F000)
+
+#define SMU_TCA_GEN_VAL(name, value) \
+ SCU_GEN_VALUE(SMU_TASK_CONTEXT_ASSIGNMENT_ ## name, value)
+
+#define SMU_TCA_GEN_BIT(name) \
+ SCU_GEN_BIT(SMU_TASK_CONTEXT_ASSIGNMENT_ ## name)
+
+/* ***************************************************************************** */
+#define SCU_SDMA_UNSOLICITED_FRAME_QUEUE_CONTROL_QUEUE_SIZE_SHIFT (0)
+#define SCU_SDMA_UNSOLICITED_FRAME_QUEUE_CONTROL_QUEUE_SIZE_MASK (0x00000FFF)
+#define SCU_SDMA_UNSOLICITED_FRAME_QUEUE_CONTROL_RESERVED_MASK (0xFFFFF000)
+
+#define SCU_UFQC_GEN_VAL(name, value) \
+ SCU_GEN_VALUE(SCU_SDMA_UNSOLICITED_FRAME_QUEUE_CONTROL_ ## name, value)
+
+#define SCU_UFQC_QUEUE_SIZE_SET(value) \
+ SCU_UFQC_GEN_VAL(QUEUE_SIZE, value)
+
+/* ***************************************************************************** */
+#define SCU_SDMA_UNSOLICITED_FRAME_QUEUE_PUT_POINTER_SHIFT (0)
+#define SCU_SDMA_UNSOLICITED_FRAME_QUEUE_PUT_POINTER_MASK (0x00000FFF)
+#define SCU_SDMA_UNSOLICITED_FRAME_QUEUE_PUT_CYCLE_BIT_SHIFT (12)
+#define SCU_SDMA_UNSOLICITED_FRAME_QUEUE_PUT_CYCLE_BIT_MASK (0x00001000)
+#define SCU_SDMA_UNSOLICITED_FRAME_QUEUE_PUT_RESERVED_MASK (0xFFFFE000)
+
+#define SCU_UFQPP_GEN_VAL(name, value) \
+ SCU_GEN_VALUE(SCU_SDMA_UNSOLICITED_FRAME_QUEUE_PUT_ ## name, value)
+
+#define SCU_UFQPP_GEN_BIT(name) \
+ SCU_GEN_BIT(SCU_SDMA_UNSOLICITED_FRAME_QUEUE_PUT_ ## name)
+
+/*
+ * *****************************************************************************
+ * * SDMA Registers
+ * ***************************************************************************** */
+#define SCU_SDMA_UNSOLICITED_FRAME_QUEUE_GET_POINTER_SHIFT (0)
+#define SCU_SDMA_UNSOLICITED_FRAME_QUEUE_GET_POINTER_MASK (0x00000FFF)
+#define SCU_SDMA_UNSOLICITED_FRAME_QUEUE_GET_CYCLE_BIT_SHIFT (12)
+#define SCU_SDMA_UNSOLICITED_FRAME_QUEUE_GET_CYCLE_BIT_MASK (12)
+#define SCU_SDMA_UNSOLICITED_FRAME_QUEUE_GET_ENABLE_BIT_SHIFT (31)
+#define SCU_SDMA_UNSOLICITED_FRAME_QUEUE_GET_ENABLE_BIT_MASK (0x80000000)
+#define SCU_SDMA_UNSOLICITED_FRAME_QUEUE_GET_RESERVED_MASK (0x7FFFE000)
+
+#define SCU_UFQGP_GEN_VAL(name, value) \
+ SCU_GEN_VALUE(SCU_SDMA_UNSOLICITED_FRAME_QUEUE_GET_ ## name, value)
+
+#define SCU_UFQGP_GEN_BIT(name) \
+ SCU_GEN_BIT(SCU_SDMA_UNSOLICITED_FRAME_QUEUE_GET_ ## name)
+
+#define SCU_UFQGP_CYCLE_BIT(value) \
+ SCU_UFQGP_GEN_BIT(CYCLE_BIT, value)
+
+#define SCU_UFQGP_GET_POINTER(value) \
+ SCU_UFQGP_GEN_VALUE(POINTER, value)
+
+#define SCU_UFQGP_ENABLE(value) \
+ (SCU_UFQGP_GEN_BIT(ENABLE) | value)
+
+#define SCU_UFQGP_DISABLE(value) \
+ (~SCU_UFQGP_GEN_BIT(ENABLE) & value)
+
+#define SCU_UFQGP_VALUE(bit, value) \
+ (SCU_UFQGP_CYCLE_BIT(bit) | SCU_UFQGP_GET_POINTER(value))
+
+/* ***************************************************************************** */
+#define SCU_PDMA_CONFIGURATION_ADDRESS_MODIFIER_SHIFT (0)
+#define SCU_PDMA_CONFIGURATION_ADDRESS_MODIFIER_MASK (0x0000FFFF)
+#define SCU_PDMA_CONFIGURATION_PCI_RELAXED_ORDERING_ENABLE_SHIFT (16)
+#define SCU_PDMA_CONFIGURATION_PCI_RELAXED_ORDERING_ENABLE_MASK (0x00010000)
+#define SCU_PDMA_CONFIGURATION_PCI_NO_SNOOP_ENABLE_SHIFT (17)
+#define SCU_PDMA_CONFIGURATION_PCI_NO_SNOOP_ENABLE_MASK (0x00020000)
+#define SCU_PDMA_CONFIGURATION_BIG_ENDIAN_CONTROL_BYTE_SWAP_SHIFT (18)
+#define SCU_PDMA_CONFIGURATION_BIG_ENDIAN_CONTROL_BYTE_SWAP_MASK (0x00040000)
+#define SCU_PDMA_CONFIGURATION_BIG_ENDIAN_CONTROL_XPI_SGL_FETCH_SHIFT (19)
+#define SCU_PDMA_CONFIGURATION_BIG_ENDIAN_CONTROL_XPI_SGL_FETCH_MASK (0x00080000)
+#define SCU_PDMA_CONFIGURATION_BIG_ENDIAN_CONTROL_XPI_RX_HEADER_RAM_WRITE_SHIFT (20)
+#define SCU_PDMA_CONFIGURATION_BIG_ENDIAN_CONTROL_XPI_RX_HEADER_RAM_WRITE_MASK (0x00100000)
+#define SCU_PDMA_CONFIGURATION_BIG_ENDIAN_CONTROL_XPI_UF_ADDRESS_FETCH_SHIFT (21)
+#define SCU_PDMA_CONFIGURATION_BIG_ENDIAN_CONTROL_XPI_UF_ADDRESS_FETCH_MASK (0x00200000)
+#define SCU_PDMA_CONFIGURATION_ADDRESS_MODIFIER_SELECT_SHIFT (22)
+#define SCU_PDMA_CONFIGURATION_ADDRESS_MODIFIER_SELECT_MASK (0x00400000)
+#define SCU_PDMA_CONFIGURATION_RESERVED_MASK (0xFF800000)
+
+#define SCU_PDMACR_GEN_VALUE(name, value) \
+ SCU_GEN_VALUE(SCU_PDMA_CONFIGURATION_ ## name, value)
+
+#define SCU_PDMACR_GEN_BIT(name) \
+ SCU_GEN_BIT(SCU_PDMA_CONFIGURATION_ ## name)
+
+#define SCU_PDMACR_BE_GEN_BIT(name) \
+ SCU_PCMACR_GEN_BIT(BIG_ENDIAN_CONTROL_ ## name)
+
+/* ***************************************************************************** */
+#define SCU_CDMA_CONFIGURATION_PCI_RELAXED_ORDERING_ENABLE_SHIFT (8)
+#define SCU_CDMA_CONFIGURATION_PCI_RELAXED_ORDERING_ENABLE_MASK (0x00000100)
+
+#define SCU_CDMACR_GEN_BIT(name) \
+ SCU_GEN_BIT(SCU_CDMA_CONFIGURATION_ ## name)
+
+/*
+ * *****************************************************************************
+ * * SCU Link Layer Registers
+ * ***************************************************************************** */
+#define SCU_LINK_LAYER_SPEED_NEGOTIATION_TIMER_VALUES_TIMEOUT_SHIFT (0)
+#define SCU_LINK_LAYER_SPEED_NEGOTIATION_TIMER_VALUES_TIMEOUT_MASK (0x000000FF)
+#define SCU_LINK_LAYER_SPEED_NEGOTIATION_TIMER_VALUES_LOCK_TIME_SHIFT (8)
+#define SCU_LINK_LAYER_SPEED_NEGOTIATION_TIMER_VALUES_LOCK_TIME_MASK (0x0000FF00)
+#define SCU_LINK_LAYER_SPEED_NEGOTIATION_TIMER_VALUES_RATE_CHANGE_DELAY_SHIFT (16)
+#define SCU_LINK_LAYER_SPEED_NEGOTIATION_TIMER_VALUES_RATE_CHANGE_DELAY_MASK (0x00FF0000)
+#define SCU_LINK_LAYER_SPEED_NEGOTIATION_TIMER_VALUES_DWORD_SYNC_TIMEOUT_SHIFT (24)
+#define SCU_LINK_LAYER_SPEED_NEGOTIATION_TIMER_VALUES_DWORD_SYNC_TIMEOUT_MASK (0xFF000000)
+#define SCU_LINK_LAYER_SPEED_NECGOIATION_TIMER_VALUES_REQUIRED_MASK (0x00000000)
+#define SCU_LINK_LAYER_SPEED_NECGOIATION_TIMER_VALUES_DEFAULT_MASK (0x7D00676F)
+#define SCU_LINK_LAYER_SPEED_NECGOIATION_TIMER_VALUES_RESERVED_MASK (0x00FF0000)
+
+#define SCU_SAS_SPDTOV_GEN_VALUE(name, value) \
+ SCU_GEN_VALUE(SCU_LINK_LAYER_SPEED_NEGOTIATION_TIMER_VALUES_ ## name, value)
+
+
+#define SCU_LINK_STATUS_DWORD_SYNC_AQUIRED_SHIFT (2)
+#define SCU_LINK_STATUS_DWORD_SYNC_AQUIRED_MASK (0x00000004)
+#define SCU_LINK_STATUS_TRANSMIT_PORT_SELECTION_DONE_SHIFT (4)
+#define SCU_LINK_STATUS_TRANSMIT_PORT_SELECTION_DONE_MASK (0x00000010)
+#define SCU_LINK_STATUS_RECEIVER_CREDIT_EXHAUSTED_SHIFT (5)
+#define SCU_LINK_STATUS_RECEIVER_CREDIT_EXHAUSTED_MASK (0x00000020)
+#define SCU_LINK_STATUS_RESERVED_MASK (0xFFFFFFCD)
+
+#define SCU_SAS_LLSTA_GEN_BIT(name) \
+ SCU_GEN_BIT(SCU_LINK_STATUS_ ## name)
+
+
+/* TODO: Where is the SATA_PSELTOV register? */
+
+/*
+ * *****************************************************************************
+ * * SCU SAS Maximum Arbitration Wait Time Timeout Register
+ * ***************************************************************************** */
+#define SCU_SAS_MAX_ARBITRATION_WAIT_TIME_TIMEOUT_VALUE_SHIFT (0)
+#define SCU_SAS_MAX_ARBITRATION_WAIT_TIME_TIMEOUT_VALUE_MASK (0x00007FFF)
+#define SCU_SAS_MAX_ARBITRATION_WAIT_TIME_TIMEOUT_SCALE_SHIFT (15)
+#define SCU_SAS_MAX_ARBITRATION_WAIT_TIME_TIMEOUT_SCALE_MASK (0x00008000)
+
+#define SCU_SAS_MAWTTOV_GEN_VALUE(name, value) \
+ SCU_GEN_VALUE(SCU_SAS_MAX_ARBITRATION_WAIT_TIME_TIMEOUT_ ## name, value)
+
+#define SCU_SAS_MAWTTOV_GEN_BIT(name) \
+ SCU_GEN_BIT(SCU_SAS_MAX_ARBITRATION_WAIT_TIME_TIMEOUT_ ## name)
+
+
+/*
+ * TODO: Where is the SAS_LNKTOV regsiter?
+ * TODO: Where is the SAS_PHYTOV register? */
+
+#define SCU_SAS_TRANSMIT_IDENTIFICATION_SMP_TARGET_SHIFT (1)
+#define SCU_SAS_TRANSMIT_IDENTIFICATION_SMP_TARGET_MASK (0x00000002)
+#define SCU_SAS_TRANSMIT_IDENTIFICATION_STP_TARGET_SHIFT (2)
+#define SCU_SAS_TRANSMIT_IDENTIFICATION_STP_TARGET_MASK (0x00000004)
+#define SCU_SAS_TRANSMIT_IDENTIFICATION_SSP_TARGET_SHIFT (3)
+#define SCU_SAS_TRANSMIT_IDENTIFICATION_SSP_TARGET_MASK (0x00000008)
+#define SCU_SAS_TRANSMIT_IDENTIFICATION_DA_SATA_HOST_SHIFT (8)
+#define SCU_SAS_TRANSMIT_IDENTIFICATION_DA_SATA_HOST_MASK (0x00000100)
+#define SCU_SAS_TRANSMIT_IDENTIFICATION_SMP_INITIATOR_SHIFT (9)
+#define SCU_SAS_TRANSMIT_IDENTIFICATION_SMP_INITIATOR_MASK (0x00000200)
+#define SCU_SAS_TRANSMIT_IDENTIFICATION_STP_INITIATOR_SHIFT (10)
+#define SCU_SAS_TRANSMIT_IDENTIFICATION_STP_INITIATOR_MASK (0x00000400)
+#define SCU_SAS_TRANSMIT_IDENTIFICATION_SSP_INITIATOR_SHIFT (11)
+#define SCU_SAS_TRANSMIT_IDENTIFICATION_SSP_INITIATOR_MASK (0x00000800)
+#define SCU_SAS_TRANSMIT_IDENTIFICATION_REASON_CODE_SHIFT (16)
+#define SCU_SAS_TRANSMIT_IDENTIFICATION_REASON_CODE_MASK (0x000F0000)
+#define SCU_SAS_TRANSMIT_IDENTIFICATION_ADDRESS_FRAME_TYPE_SHIFT (24)
+#define SCU_SAS_TRANSMIT_IDENTIFICATION_ADDRESS_FRAME_TYPE_MASK (0x0F000000)
+#define SCU_SAS_TRANSMIT_IDENTIFICATION_DEVICE_TYPE_SHIFT (28)
+#define SCU_SAS_TRANSMIT_IDENTIFICATION_DEVICE_TYPE_MASK (0x70000000)
+#define SCU_SAS_TRANSMIT_IDENTIFICATION_RESERVED_MASK (0x80F0F1F1)
+
+#define SCU_SAS_TIID_GEN_VAL(name, value) \
+ SCU_GEN_VALUE(SCU_SAS_TRANSMIT_IDENTIFICATION_ ## name, value)
+
+#define SCU_SAS_TIID_GEN_BIT(name) \
+ SCU_GEN_BIT(SCU_SAS_TRANSMIT_IDENTIFICATION_ ## name)
+
+/* SAS Identify Frame PHY Identifier Register */
+#define SCU_LINK_LAYER_IDENTIFY_FRAME_PHY_IDENTIFIER_BREAK_REPLY_CAPABLE_SHIFT (16)
+#define SCU_LINK_LAYER_IDENTIFY_FRAME_PHY_IDENTIFIER_BREAK_REPLY_CAPABLE_MASK (0x00010000)
+#define SCU_LINK_LAYER_IDENTIFY_FRAME_PHY_IDENTIFIER_REQUESTED_INSIDE_ZPSDS_SHIFT (17)
+#define SCU_LINK_LAYER_IDENTIFY_FRAME_PHY_IDENTIFIER_REQUESTED_INSIDE_ZPSDS_MASK (0x00020000)
+#define SCU_LINK_LAYER_IDENTIFY_FRAME_PHY_IDENTIFIER_INSIDE_ZPSDS_PERSISTENT_SHIFT (18)
+#define SCU_LINK_LAYER_IDENTIFY_FRAME_PHY_IDENTIFIER_INSIDE_ZPSDS_PERSISTENT_MASK (0x00040000)
+#define SCU_LINK_LAYER_IDENTIFY_FRAME_PHY_IDENTIFIER_ID_SHIFT (24)
+#define SCU_LINK_LAYER_IDENTIFY_FRAME_PHY_IDENTIFIER_ID_MASK (0xFF000000)
+#define SCU_LINK_LAYER_IDENTIFY_FRAME_PHY_IDENTIFIER_RESERVED_MASK (0x00F800FF)
+
+#define SCU_SAS_TIPID_GEN_VALUE(name, value) \
+ SCU_GEN_VALUE(SCU_LINK_LAYER_IDENTIFY_FRAME_PHY_IDENTIFIER_ ## name, value)
+
+#define SCU_SAS_TIPID_GEN_BIT(name) \
+ SCU_GEN_BIT(SCU_LINK_LAYER_IDENTIFY_FRAME_PHY_IDENTIFIER_ ## name)
+
+
+#define SCU_SAS_PHY_CONFIGURATION_TX_PARITY_CHECK_SHIFT (4)
+#define SCU_SAS_PHY_CONFIGURATION_TX_PARITY_CHECK_MASK (0x00000010)
+#define SCU_SAS_PHY_CONFIGURATION_TX_BAD_CRC_SHIFT (6)
+#define SCU_SAS_PHY_CONFIGURATION_TX_BAD_CRC_MASK (0x00000040)
+#define SCU_SAS_PHY_CONFIGURATION_DISABLE_SCRAMBLER_SHIFT (7)
+#define SCU_SAS_PHY_CONFIGURATION_DISABLE_SCRAMBLER_MASK (0x00000080)
+#define SCU_SAS_PHY_CONFIGURATION_DISABLE_DESCRAMBLER_SHIFT (8)
+#define SCU_SAS_PHY_CONFIGURATION_DISABLE_DESCRAMBLER_MASK (0x00000100)
+#define SCU_SAS_PHY_CONFIGURATION_DISABLE_CREDIT_INSERTION_SHIFT (9)
+#define SCU_SAS_PHY_CONFIGURATION_DISABLE_CREDIT_INSERTION_MASK (0x00000200)
+#define SCU_SAS_PHY_CONFIGURATION_SUSPEND_PROTOCOL_ENGINE_SHIFT (11)
+#define SCU_SAS_PHY_CONFIGURATION_SUSPEND_PROTOCOL_ENGINE_MASK (0x00000800)
+#define SCU_SAS_PHY_CONFIGURATION_SATA_SPINUP_HOLD_SHIFT (12)
+#define SCU_SAS_PHY_CONFIGURATION_SATA_SPINUP_HOLD_MASK (0x00001000)
+#define SCU_SAS_PHY_CONFIGURATION_TRANSMIT_PORT_SELECTION_SIGNAL_SHIFT (13)
+#define SCU_SAS_PHY_CONFIGURATION_TRANSMIT_PORT_SELECTION_SIGNAL_MASK (0x00002000)
+#define SCU_SAS_PHY_CONFIGURATION_HARD_RESET_SHIFT (14)
+#define SCU_SAS_PHY_CONFIGURATION_HARD_RESET_MASK (0x00004000)
+#define SCU_SAS_PHY_CONFIGURATION_OOB_ENABLE_SHIFT (15)
+#define SCU_SAS_PHY_CONFIGURATION_OOB_ENABLE_MASK (0x00008000)
+#define SCU_SAS_PHY_CONFIGURATION_ENABLE_FRAME_TX_INSERT_ALIGN_SHIFT (23)
+#define SCU_SAS_PHY_CONFIGURATION_ENABLE_FRAME_TX_INSERT_ALIGN_MASK (0x00800000)
+#define SCU_SAS_PHY_CONFIGURATION_FORWARD_IDENTIFY_FRAME_SHIFT (27)
+#define SCU_SAS_PHY_CONFIGURATION_FORWARD_IDENTIFY_FRAME_MASK (0x08000000)
+#define SCU_SAS_PHY_CONFIGURATION_DISABLE_BYTE_TRANSPOSE_STP_FRAME_SHIFT (28)
+#define SCU_SAS_PHY_CONFIGURATION_DISABLE_BYTE_TRANSPOSE_STP_FRAME_MASK (0x10000000)
+#define SCU_SAS_PHY_CONFIGURATION_OOB_RESET_SHIFT (29)
+#define SCU_SAS_PHY_CONFIGURATION_OOB_RESET_MASK (0x20000000)
+#define SCU_SAS_PHY_CONFIGURATION_THREE_IAF_ENABLE_SHIFT (30)
+#define SCU_SAS_PHY_CONFIGURATION_THREE_IAF_ENABLE_MASK (0x40000000)
+#define SCU_SAS_PHY_CONFIGURATION_OOB_ALIGN0_ENABLE_SHIFT (31)
+#define SCU_SAS_PHY_CONFIGURATION_OOB_ALIGN0_ENABLE_MASK (0x80000000)
+#define SCU_SAS_PHY_CONFIGURATION_REQUIRED_MASK (0x0100000F)
+#define SCU_SAS_PHY_CONFIGURATION_DEFAULT_MASK (0x4180100F)
+#define SCU_SAS_PHY_CONFIGURATION_RESERVED_MASK (0x00000000)
+
+#define SCU_SAS_PCFG_GEN_BIT(name) \
+ SCU_GEN_BIT(SCU_SAS_PHY_CONFIGURATION_ ## name)
+
+
+#define SCU_LINK_LAYER_ENABLE_SPINUP_CONTROL_COUNT_SHIFT (0)
+#define SCU_LINK_LAYER_ENABLE_SPINUP_CONTROL_COUNT_MASK (0x0003FFFF)
+#define SCU_LINK_LAYER_ENABLE_SPINUP_CONTROL_ENABLE_SHIFT (31)
+#define SCU_LINK_LAYER_ENABLE_SPINUP_CONTROL_ENABLE_MASK (0x80000000)
+#define SCU_LINK_LAYER_ENABLE_SPINUP_CONTROL_RESERVED_MASK (0x7FFC0000)
+
+#define SCU_ENSPINUP_GEN_VAL(name, value) \
+ SCU_GEN_VALUE(SCU_LINK_LAYER_ENABLE_SPINUP_CONTROL_ ## name, value)
+
+#define SCU_ENSPINUP_GEN_BIT(name) \
+ SCU_GEN_BIT(SCU_LINK_LAYER_ENABLE_SPINUP_CONTROL_ ## name)
+
+
+#define SCU_LINK_LAYER_PHY_CAPABILITIES_TXSSCTYPE_SHIFT (1)
+#define SCU_LINK_LAYER_PHY_CAPABILITIES_TXSSCTYPE_MASK (0x00000002)
+#define SCU_LINK_LAYER_PHY_CAPABILITIES_RLLRATE_SHIFT (4)
+#define SCU_LINK_LAYER_PHY_CAPABILITIES_RLLRATE_MASK (0x000000F0)
+#define SCU_LINK_LAYER_PHY_CAPABILITIES_SWO15GBPS_SHIFT (8)
+#define SCU_LINK_LAYER_PHY_CAPABILITIES_SWO15GBPS_MASK (0x00000100)
+#define SCU_LINK_LAYER_PHY_CAPABILITIES_SW15GBPS_SHIFT (9)
+#define SCU_LINK_LAYER_PHY_CAPABILITIES_SW15GBPS_MASK (0x00000201)
+#define SCU_LINK_LAYER_PHY_CAPABILITIES_SWO30GBPS_SHIFT (10)
+#define SCU_LINK_LAYER_PHY_CAPABILITIES_SWO30GBPS_MASK (0x00000401)
+#define SCU_LINK_LAYER_PHY_CAPABILITIES_SW30GBPS_SHIFT (11)
+#define SCU_LINK_LAYER_PHY_CAPABILITIES_SW30GBPS_MASK (0x00000801)
+#define SCU_LINK_LAYER_PHY_CAPABILITIES_SWO60GBPS_SHIFT (12)
+#define SCU_LINK_LAYER_PHY_CAPABILITIES_SWO60GBPS_MASK (0x00001001)
+#define SCU_LINK_LAYER_PHY_CAPABILITIES_SW60GBPS_SHIFT (13)
+#define SCU_LINK_LAYER_PHY_CAPABILITIES_SW60GBPS_MASK (0x00002001)
+#define SCU_LINK_LAYER_PHY_CAPABILITIES_EVEN_PARITY_SHIFT (31)
+#define SCU_LINK_LAYER_PHY_CAPABILITIES_EVEN_PARITY_MASK (0x80000000)
+#define SCU_LINK_LAYER_PHY_CAPABILITIES_DEFAULT_MASK (0x00003F01)
+#define SCU_LINK_LAYER_PHY_CAPABILITIES_REQUIRED_MASK (0x00000001)
+#define SCU_LINK_LAYER_PHY_CAPABILITIES_RESERVED_MASK (0x7FFFC00D)
+
+#define SCU_SAS_PHYCAP_GEN_VAL(name, value) \
+ SCU_GEN_VALUE(SCU_LINK_LAYER_PHY_CAPABILITIES_ ## name, value)
+
+#define SCU_SAS_PHYCAP_GEN_BIT(name) \
+ SCU_GEN_BIT(SCU_LINK_LAYER_PHY_CAPABILITIES_ ## name)
+
+
+#define SCU_LINK_LAYER_PHY_SOURCE_ZONE_GROUP_CONTROL_VIRTUAL_EXPANDER_PHY_ZONE_GROUP_SHIFT (0)
+#define SCU_LINK_LAYER_PHY_SOURCE_ZONE_GROUP_CONTROL_VIRTUAL_EXPANDER_PHY_ZONE_GROUP_MASK (0x000000FF)
+#define SCU_LINK_LAYER_PHY_SOURCE_ZONE_GROUP_CONTROL_INSIDE_SOURCE_ZONE_GROUP_SHIFT (31)
+#define SCU_LINK_LAYER_PHY_SOURCE_ZONE_GROUP_CONTROL_INSIDE_SOURCE_ZONE_GROUP_MASK (0x80000000)
+#define SCU_LINK_LAYER_PHY_SOURCE_ZONE_GROUP_CONTROL_RESERVED_MASK (0x7FFFFF00)
+
+#define SCU_PSZGCR_GEN_VAL(name, value) \
+ SCU_GEN_VALUE(SCU_LINK_LAYER_PHY_SOURCE_ZONE_GROUP_CONTROL_ ## name, value)
+
+#define SCU_PSZGCR_GEN_BIT(name) \
+ SCU_GEN_BIT(SCU_LINK_LAYER_PHY_SOURCE_ZONE_GROUP_CONTROL_ ## name)
+
+#define SCU_PROTOCOL_ENGINE_GROUP_VIRTUAL_ZONING_EXPANDER_CONTROL_ZONE0_LOCKED_SHIFT (1)
+#define SCU_PROTOCOL_ENGINE_GROUP_VIRTUAL_ZONING_EXPANDER_CONTROL_ZONE0_LOCKED_MASK (0x00000002)
+#define SCU_PROTOCOL_ENGINE_GROUP_VIRTUAL_ZONING_EXPANDER_CONTROL_ZONE0_UPDATING_SHIFT (2)
+#define SCU_PROTOCOL_ENGINE_GROUP_VIRTUAL_ZONING_EXPANDER_CONTROL_ZONE0_UPDATING_MASK (0x00000004)
+#define SCU_PROTOCOL_ENGINE_GROUP_VIRTUAL_ZONING_EXPANDER_CONTROL_ZONE1_LOCKED_SHIFT (4)
+#define SCU_PROTOCOL_ENGINE_GROUP_VIRTUAL_ZONING_EXPANDER_CONTROL_ZONE1_LOCKED_MASK (0x00000010)
+#define SCU_PROTOCOL_ENGINE_GROUP_VIRTUAL_ZONING_EXPANDER_CONTROL_ZONE1_UPDATING_SHIFT (5)
+#define SCU_PROTOCOL_ENGINE_GROUP_VIRTUAL_ZONING_EXPANDER_CONTROL_ZONE1_UPDATING_MASK (0x00000020)
+#define SCU_PROTOCOL_ENGINE_GROUP_VIRTUAL_ZONING_EXPANDER_CONTROL_ZPT_ASSOCIATION_PE0_SHIFT (16)
+#define SCU_PROTOCOL_ENGINE_GROUP_VIRTUAL_ZONING_EXPANDER_CONTROL_ZPT_ASSOCIATION_PE0_MASK (0x00030000)
+#define SCU_PROTOCOL_ENGINE_GROUP_VIRTUAL_ZONING_EXPANDER_CONTROL_AIP_ENABLE_PE0_SHIFT (19)
+#define SCU_PROTOCOL_ENGINE_GROUP_VIRTUAL_ZONING_EXPANDER_CONTROL_AIP_ENABLE_PE0_MASK (0x00080000)
+#define SCU_PROTOCOL_ENGINE_GROUP_VIRTUAL_ZONING_EXPANDER_CONTROL_ZPT_ASSOCIATION_PE1_SHIFT (20)
+#define SCU_PROTOCOL_ENGINE_GROUP_VIRTUAL_ZONING_EXPANDER_CONTROL_ZPT_ASSOCIATION_PE1_MASK (0x00300000)
+#define SCU_PROTOCOL_ENGINE_GROUP_VIRTUAL_ZONING_EXPANDER_CONTROL_AIP_ENABLE_PE1_SHIFT (23)
+#define SCU_PROTOCOL_ENGINE_GROUP_VIRTUAL_ZONING_EXPANDER_CONTROL_AIP_ENABLE_PE1_MASK (0x00800000)
+#define SCU_PROTOCOL_ENGINE_GROUP_VIRTUAL_ZONING_EXPANDER_CONTROL_ZPT_ASSOCIATION_PE2_SHIFT (24)
+#define SCU_PROTOCOL_ENGINE_GROUP_VIRTUAL_ZONING_EXPANDER_CONTROL_ZPT_ASSOCIATION_PE2_MASK (0x03000000)
+#define SCU_PROTOCOL_ENGINE_GROUP_VIRTUAL_ZONING_EXPANDER_CONTROL_AIP_ENABLE_PE2_SHIFT (27)
+#define SCU_PROTOCOL_ENGINE_GROUP_VIRTUAL_ZONING_EXPANDER_CONTROL_AIP_ENABLE_PE2_MASK (0x08000000)
+#define SCU_PROTOCOL_ENGINE_GROUP_VIRTUAL_ZONING_EXPANDER_CONTROL_ZPT_ASSOCIATION_PE3_SHIFT (28)
+#define SCU_PROTOCOL_ENGINE_GROUP_VIRTUAL_ZONING_EXPANDER_CONTROL_ZPT_ASSOCIATION_PE3_MASK (0x30000000)
+#define SCU_PROTOCOL_ENGINE_GROUP_VIRTUAL_ZONING_EXPANDER_CONTROL_AIP_ENABLE_PE3_SHIFT (31)
+#define SCU_PROTOCOL_ENGINE_GROUP_VIRTUAL_ZONING_EXPANDER_CONTROL_AIP_ENABLE_PE3_MASK (0x80000000)
+#define SCU_PROTOCOL_ENGINE_GROUP_VIRTUAL_ZONING_EXPANDER_CONTROL_RESERVED_MASK (0x4444FFC9)
+
+#define SCU_PEG_SCUVZECR_GEN_VAL(name, val) \
+ SCU_GEN_VALUE(SCU_PROTOCOL_ENGINE_GROUP_VIRTUAL_ZONING_EXPANDER_CONTROL_ ## name, val)
+
+#define SCU_PEG_SCUVZECR_GEN_BIT(name) \
+ SCU_GEN_BIT(SCU_PROTOCOL_ENGINE_GROUP_VIRTUAL_ZONING_EXPANDER_CONTROL_ ## name)
+
+
+/*
+ * *****************************************************************************
+ * * Port Task Scheduler registers shift and mask values
+ * ***************************************************************************** */
+#define SCU_PTSG_CONTROL_IT_NEXUS_TIMEOUT_SHIFT (0)
+#define SCU_PTSG_CONTROL_IT_NEXUS_TIMEOUT_MASK (0x0000FFFF)
+#define SCU_PTSG_CONTROL_TASK_TIMEOUT_SHIFT (16)
+#define SCU_PTSG_CONTROL_TASK_TIMEOUT_MASK (0x00FF0000)
+#define SCU_PTSG_CONTROL_PTSG_ENABLE_SHIFT (24)
+#define SCU_PTSG_CONTROL_PTSG_ENABLE_MASK (0x01000000)
+#define SCU_PTSG_CONTROL_ETM_ENABLE_SHIFT (25)
+#define SCU_PTSG_CONTROL_ETM_ENABLE_MASK (0x02000000)
+#define SCU_PTSG_CONTROL_DEFAULT_MASK (0x00020002)
+#define SCU_PTSG_CONTROL_REQUIRED_MASK (0x00000000)
+#define SCU_PTSG_CONTROL_RESERVED_MASK (0xFC000000)
+
+#define SCU_PTSGCR_GEN_VAL(name, val) \
+ SCU_GEN_VALUE(SCU_PTSG_CONTROL_ ## name, val)
+
+#define SCU_PTSGCR_GEN_BIT(name) \
+ SCU_GEN_BIT(SCU_PTSG_CONTROL_ ## name)
+
+
+/* ***************************************************************************** */
+#define SCU_PTSG_REAL_TIME_CLOCK_SHIFT (0)
+#define SCU_PTSG_REAL_TIME_CLOCK_MASK (0x0000FFFF)
+#define SCU_PTSG_REAL_TIME_CLOCK_RESERVED_MASK (0xFFFF0000)
+
+#define SCU_RTCR_GEN_VAL(name, val) \
+ SCU_GEN_VALUE(SCU_PTSG_ ## name, val)
+
+
+#define SCU_PTSG_REAL_TIME_CLOCK_CONTROL_PRESCALER_VALUE_SHIFT (0)
+#define SCU_PTSG_REAL_TIME_CLOCK_CONTROL_PRESCALER_VALUE_MASK (0x00FFFFFF)
+#define SCU_PTSG_REAL_TIME_CLOCK_CONTROL_RESERVED_MASK (0xFF000000)
+
+#define SCU_RTCCR_GEN_VAL(name, val) \
+ SCU_GEN_VALUE(SCU_PTSG_REAL_TIME_CLOCK_CONTROL_ ## name, val)
+
+
+#define SCU_PTSG_PORT_TASK_SCHEDULER_CONTROL_SUSPEND_SHIFT (0)
+#define SCU_PTSG_PORT_TASK_SCHEDULER_CONTROL_SUSPEND_MASK (0x00000001)
+#define SCU_PTSG_PORT_TASK_SCHEDULER_CONTROL_ENABLE_SHIFT (1)
+#define SCU_PTSG_PORT_TASK_SCHEDULER_CONTROL_ENABLE_MASK (0x00000002)
+#define SCU_PTSG_PORT_TASK_SCHEDULER_CONTROL_RESERVED_MASK (0xFFFFFFFC)
+
+#define SCU_PTSxCR_GEN_BIT(name) \
+ SCU_GEN_BIT(SCU_PTSG_PORT_TASK_SCHEDULER_CONTROL_ ## name)
+
+
+#define SCU_PTSG_PORT_TASK_SCHEDULER_STATUS_NEXT_RN_VALID_SHIFT (0)
+#define SCU_PTSG_PORT_TASK_SCHEDULER_STATUS_NEXT_RN_VALID_MASK (0x00000001)
+#define SCU_PTSG_PORT_TASK_SCHEDULER_STATUS_ACTIVE_RNSC_LIST_VALID_SHIFT (1)
+#define SCU_PTSG_PORT_TASK_SCHEDULER_STATUS_ACTIVE_RNSC_LIST_VALID_MASK (0x00000002)
+#define SCU_PTSG_PORT_TASK_SCHEDULER_STATUS_PTS_SUSPENDED_SHIFT (2)
+#define SCU_PTSG_PORT_TASK_SCHEDULER_STATUS_PTS_SUSPENDED_MASK (0x00000004)
+#define SCU_PTSG_PORT_TASK_SCHEDULER_STATUS_RESERVED_MASK (0xFFFFFFF8)
+
+#define SCU_PTSxSR_GEN_BIT(name) \
+ SCU_GEN_BIT(SCU_PTSG_PORT_TASK_SCHEDULER_STATUS_ ## name)
+
+
+/*
+ * *****************************************************************************
+ * * SGPIO Register shift and mask values
+ * ***************************************************************************** */
+#define SCU_SGPIO_CONTROL_SGPIO_ENABLE_SHIFT (0)
+#define SCU_SGPIO_CONTROL_SGPIO_ENABLE_MASK (0x00000001)
+#define SCU_SGPIO_CONTROL_SGPIO_SERIAL_CLOCK_SELECT_SHIFT (1)
+#define SCU_SGPIO_CONTROL_SGPIO_SERIAL_CLOCK_SELECT_MASK (0x00000002)
+#define SCU_SGPIO_CONTROL_SGPIO_SERIAL_SHIFT_WIDTH_SELECT_SHIFT (2)
+#define SCU_SGPIO_CONTROL_SGPIO_SERIAL_SHIFT_WIDTH_SELECT_MASK (0x00000004)
+#define SCU_SGPIO_CONTROL_SGPIO_TEST_BIT_SHIFT (15)
+#define SCU_SGPIO_CONTROL_SGPIO_TEST_BIT_MASK (0x00008000)
+#define SCU_SGPIO_CONTROL_SGPIO_RESERVED_MASK (0xFFFF7FF8)
+
+#define SCU_SGICRx_GEN_BIT(name) \
+ SCU_GEN_BIT(SCU_SGPIO_CONTROL_SGPIO_ ## name)
+
+#define SCU_SGPIO_PROGRAMMABLE_BLINK_REGISTER_R0_SHIFT (0)
+#define SCU_SGPIO_PROGRAMMABLE_BLINK_REGISTER_R0_MASK (0x0000000F)
+#define SCU_SGPIO_PROGRAMMABLE_BLINK_REGISTER_R1_SHIFT (4)
+#define SCU_SGPIO_PROGRAMMABLE_BLINK_REGISTER_R1_MASK (0x000000F0)
+#define SCU_SGPIO_PROGRAMMABLE_BLINK_REGISTER_R2_SHIFT (8)
+#define SCU_SGPIO_PROGRAMMABLE_BLINK_REGISTER_R2_MASK (0x00000F00)
+#define SCU_SGPIO_PROGRAMMABLE_BLINK_REGISTER_R3_SHIFT (12)
+#define SCU_SGPIO_PROGRAMMABLE_BLINK_REGISTER_R3_MASK (0x0000F000)
+#define SCU_SGPIO_PROGRAMMABLE_BLINK_REGISTER_RESERVED_MASK (0xFFFF0000)
+
+#define SCU_SGPBRx_GEN_VAL(name, value) \
+ SCU_GEN_VALUE(SCU_SGPIO_PROGRAMMABLE_BLINK_REGISTER_ ## name, value)
+
+#define SCU_SGPIO_START_DRIVE_LOWER_R0_SHIFT (0)
+#define SCU_SGPIO_START_DRIVE_LOWER_R0_MASK (0x00000003)
+#define SCU_SGPIO_START_DRIVE_LOWER_R1_SHIFT (4)
+#define SCU_SGPIO_START_DRIVE_LOWER_R1_MASK (0x00000030)
+#define SCU_SGPIO_START_DRIVE_LOWER_R2_SHIFT (8)
+#define SCU_SGPIO_START_DRIVE_LOWER_R2_MASK (0x00000300)
+#define SCU_SGPIO_START_DRIVE_LOWER_R3_SHIFT (12)
+#define SCU_SGPIO_START_DRIVE_LOWER_R3_MASK (0x00003000)
+#define SCU_SGPIO_START_DRIVE_LOWER_RESERVED_MASK (0xFFFF8888)
+
+#define SCU_SGSDLRx_GEN_VAL(name, value) \
+ SCU_GEN_VALUE(SCU_SGPIO_START_DRIVE_LOWER_ ## name, value)
+
+#define SCU_SGPIO_START_DRIVE_UPPER_R0_SHIFT (0)
+#define SCU_SGPIO_START_DRIVE_UPPER_R0_MASK (0x00000003)
+#define SCU_SGPIO_START_DRIVE_UPPER_R1_SHIFT (4)
+#define SCU_SGPIO_START_DRIVE_UPPER_R1_MASK (0x00000030)
+#define SCU_SGPIO_START_DRIVE_UPPER_R2_SHIFT (8)
+#define SCU_SGPIO_START_DRIVE_UPPER_R2_MASK (0x00000300)
+#define SCU_SGPIO_START_DRIVE_UPPER_R3_SHIFT (12)
+#define SCU_SGPIO_START_DRIVE_UPPER_R3_MASK (0x00003000)
+#define SCU_SGPIO_START_DRIVE_UPPER_RESERVED_MASK (0xFFFF8888)
+
+#define SCU_SGSDURx_GEN_VAL(name, value) \
+ SCU_GEN_VALUE(SCU_SGPIO_START_DRIVE_LOWER_ ## name, value)
+
+#define SCU_SGPIO_SERIAL_INPUT_DATA_LOWER_D0_SHIFT (0)
+#define SCU_SGPIO_SERIAL_INPUT_DATA_LOWER_D0_MASK (0x00000003)
+#define SCU_SGPIO_SERIAL_INPUT_DATA_LOWER_D1_SHIFT (4)
+#define SCU_SGPIO_SERIAL_INPUT_DATA_LOWER_D1_MASK (0x00000030)
+#define SCU_SGPIO_SERIAL_INPUT_DATA_LOWER_D2_SHIFT (8)
+#define SCU_SGPIO_SERIAL_INPUT_DATA_LOWER_D2_MASK (0x00000300)
+#define SCU_SGPIO_SERIAL_INPUT_DATA_LOWER_D3_SHIFT (12)
+#define SCU_SGPIO_SERIAL_INPUT_DATA_LOWER_D3_MASK (0x00003000)
+#define SCU_SGPIO_SERIAL_INPUT_DATA_LOWER_RESERVED_MASK (0xFFFF8888)
+
+#define SCU_SGSIDLRx_GEN_VAL(name, value) \
+ SCU_GEN_VALUE(SCU_SGPIO_SERIAL_INPUT_DATA_LOWER_ ## name, value)
+
+#define SCU_SGPIO_SERIAL_INPUT_DATA_UPPER_D0_SHIFT (0)
+#define SCU_SGPIO_SERIAL_INPUT_DATA_UPPER_D0_MASK (0x00000003)
+#define SCU_SGPIO_SERIAL_INPUT_DATA_UPPER_D1_SHIFT (4)
+#define SCU_SGPIO_SERIAL_INPUT_DATA_UPPER_D1_MASK (0x00000030)
+#define SCU_SGPIO_SERIAL_INPUT_DATA_UPPER_D2_SHIFT (8)
+#define SCU_SGPIO_SERIAL_INPUT_DATA_UPPER_D2_MASK (0x00000300)
+#define SCU_SGPIO_SERIAL_INPUT_DATA_UPPER_D3_SHIFT (12)
+#define SCU_SGPIO_SERIAL_INPUT_DATA_UPPER_D3_MASK (0x00003000)
+#define SCU_SGPIO_SERIAL_INPUT_DATA_UPPER_RESERVED_MASK (0xFFFF8888)
+
+#define SCU_SGSIDURx_GEN_VAL(name, value) \
+ SCU_GEN_VALUE(SCU_SGPIO_SERIAL_INPUT_DATA_LOWER_ ## name, value)
+
+#define SCU_SGPIO_VENDOR_SPECIFIC_CODE_SHIFT (0)
+#define SCU_SGPIO_VENDOR_SPECIFIC_CODE_MASK (0x0000000F)
+#define SCU_SGPIO_VENDOR_SPECIFIC_CODE_RESERVED_MASK (0xFFFFFFF0)
+
+#define SCU_SGVSCR_GEN_VAL(value) \
+ SCU_GEN_VALUE(SCU_SGPIO_VENDOR_SPECIFIC_CODE ## name, value)
+
+#define SCU_SGPIO_OUPUT_DATA_SELECT_INPUT_DATA0_SHIFT (0)
+#define SCU_SGPIO_OUPUT_DATA_SELECT_INPUT_DATA0_MASK (0x00000003)
+#define SCU_SGPIO_OUPUT_DATA_SELECT_INVERT_INPUT_DATA0_SHIFT (2)
+#define SCU_SGPIO_OUPUT_DATA_SELECT_INVERT_INPUT_DATA0_MASK (0x00000004)
+#define SCU_SGPIO_OUPUT_DATA_SELECT_JOG_ENABLE_DATA0_SHIFT (3)
+#define SCU_SGPIO_OUPUT_DATA_SELECT_JOG_ENABLE_DATA0_MASK (0x00000008)
+#define SCU_SGPIO_OUPUT_DATA_SELECT_INPUT_DATA1_SHIFT (4)
+#define SCU_SGPIO_OUPUT_DATA_SELECT_INPUT_DATA1_MASK (0x00000030)
+#define SCU_SGPIO_OUPUT_DATA_SELECT_INVERT_INPUT_DATA1_SHIFT (6)
+#define SCU_SGPIO_OUPUT_DATA_SELECT_INVERT_INPUT_DATA1_MASK (0x00000040)
+#define SCU_SGPIO_OUPUT_DATA_SELECT_JOG_ENABLE_DATA1_SHIFT (7)
+#define SCU_SGPIO_OUPUT_DATA_SELECT_JOG_ENABLE_DATA1_MASK (0x00000080)
+#define SCU_SGPIO_OUPUT_DATA_SELECT_INPUT_DATA2_SHIFT (8)
+#define SCU_SGPIO_OUPUT_DATA_SELECT_INPUT_DATA2_MASK (0x00000300)
+#define SCU_SGPIO_OUPUT_DATA_SELECT_INVERT_INPUT_DATA2_SHIFT (10)
+#define SCU_SGPIO_OUPUT_DATA_SELECT_INVERT_INPUT_DATA2_MASK (0x00000400)
+#define SCU_SGPIO_OUPUT_DATA_SELECT_JOG_ENABLE_DATA2_SHIFT (11)
+#define SCU_SGPIO_OUPUT_DATA_SELECT_JOG_ENABLE_DATA2_MASK (0x00000800)
+#define SCU_SGPIO_OUPUT_DATA_SELECT_RESERVED_MASK (0xFFFFF000)
+
+#define SCU_SGODSR_GEN_VAL(name, value) \
+ SCU_GEN_VALUE(SCU_SGPIO_OUPUT_DATA_SELECT_ ## name, value)
+
+#define SCU_SGODSR_GEN_BIT(name) \
+ SCU_GEN_BIT(SCU_SGPIO_OUPUT_DATA_SELECT_ ## name)
+
+/*
+ * *****************************************************************************
+ * * SMU Registers
+ * ***************************************************************************** */
+
+/*
+ * ----------------------------------------------------------------------------
+ * SMU Registers
+ * These registers are based off of BAR0
+ *
+ * To calculate the offset for other functions use
+ * BAR0 + FN# * SystemPageSize * 2
+ *
+ * The TCA is only accessable from FN#0 (Physical Function) and each
+ * is programmed by (BAR0 + SCU_SMU_TCA_OFFSET + (FN# * 0x04)) or
+ * TCA0 for FN#0 is at BAR0 + 0x0400
+ * TCA1 for FN#1 is at BAR0 + 0x0404
+ * etc.
+ * ----------------------------------------------------------------------------
+ * Accessable to all FN#s */
+#define SCU_SMU_PCP_OFFSET 0x0000
+#define SCU_SMU_AMR_OFFSET 0x0004
+#define SCU_SMU_ISR_OFFSET 0x0010
+#define SCU_SMU_IMR_OFFSET 0x0014
+#define SCU_SMU_ICC_OFFSET 0x0018
+#define SCU_SMU_HTTLBAR_OFFSET 0x0020
+#define SCU_SMU_HTTUBAR_OFFSET 0x0024
+#define SCU_SMU_TCR_OFFSET 0x0028
+#define SCU_SMU_CQLBAR_OFFSET 0x0030
+#define SCU_SMU_CQUBAR_OFFSET 0x0034
+#define SCU_SMU_CQPR_OFFSET 0x0040
+#define SCU_SMU_CQGR_OFFSET 0x0044
+#define SCU_SMU_CQC_OFFSET 0x0048
+/* Accessable to FN#0 only */
+#define SCU_SMU_RNCLBAR_OFFSET 0x0080
+#define SCU_SMU_RNCUBAR_OFFSET 0x0084
+#define SCU_SMU_DCC_OFFSET 0x0090
+#define SCU_SMU_DFC_OFFSET 0x0094
+#define SCU_SMU_SMUCSR_OFFSET 0x0098
+#define SCU_SMU_SCUSRCR_OFFSET 0x009C
+#define SCU_SMU_SMAW_OFFSET 0x00A0
+#define SCU_SMU_SMDW_OFFSET 0x00A4
+/* Accessable to FN#0 only */
+#define SCU_SMU_TCA_OFFSET 0x0400
+/* Accessable to all FN#s */
+#define SCU_SMU_MT_MLAR0_OFFSET 0x2000
+#define SCU_SMU_MT_MUAR0_OFFSET 0x2004
+#define SCU_SMU_MT_MDR0_OFFSET 0x2008
+#define SCU_SMU_MT_VCR0_OFFSET 0x200C
+#define SCU_SMU_MT_MLAR1_OFFSET 0x2010
+#define SCU_SMU_MT_MUAR1_OFFSET 0x2014
+#define SCU_SMU_MT_MDR1_OFFSET 0x2018
+#define SCU_SMU_MT_VCR1_OFFSET 0x201C
+#define SCU_SMU_MPBA_OFFSET 0x3000
+
+/**
+ * struct smu_registers - These are the SMU registers
+ *
+ *
+ */
+struct smu_registers {
+/* 0x0000 PCP */
+ u32 post_context_port;
+/* 0x0004 AMR */
+ u32 address_modifier;
+ u32 reserved_08;
+ u32 reserved_0C;
+/* 0x0010 ISR */
+ u32 interrupt_status;
+/* 0x0014 IMR */
+ u32 interrupt_mask;
+/* 0x0018 ICC */
+ u32 interrupt_coalesce_control;
+ u32 reserved_1C;
+/* 0x0020 HTTLBAR */
+ u32 host_task_table_lower;
+/* 0x0024 HTTUBAR */
+ u32 host_task_table_upper;
+/* 0x0028 TCR */
+ u32 task_context_range;
+ u32 reserved_2C;
+/* 0x0030 CQLBAR */
+ u32 completion_queue_lower;
+/* 0x0034 CQUBAR */
+ u32 completion_queue_upper;
+ u32 reserved_38;
+ u32 reserved_3C;
+/* 0x0040 CQPR */
+ u32 completion_queue_put;
+/* 0x0044 CQGR */
+ u32 completion_queue_get;
+/* 0x0048 CQC */
+ u32 completion_queue_control;
+ u32 reserved_4C;
+ u32 reserved_5x[4];
+ u32 reserved_6x[4];
+ u32 reserved_7x[4];
+/*
+ * Accessable to FN#0 only
+ * 0x0080 RNCLBAR */
+ u32 remote_node_context_lower;
+/* 0x0084 RNCUBAR */
+ u32 remote_node_context_upper;
+ u32 reserved_88;
+ u32 reserved_8C;
+/* 0x0090 DCC */
+ u32 device_context_capacity;
+/* 0x0094 DFC */
+ u32 device_function_capacity;
+/* 0x0098 SMUCSR */
+ u32 control_status;
+/* 0x009C SCUSRCR */
+ u32 soft_reset_control;
+/* 0x00A0 SMAW */
+ u32 mmr_address_window;
+/* 0x00A4 SMDW */
+ u32 mmr_data_window;
+ u32 reserved_A8;
+ u32 reserved_AC;
+/* A whole bunch of reserved space */
+ u32 reserved_Bx[4];
+ u32 reserved_Cx[4];
+ u32 reserved_Dx[4];
+ u32 reserved_Ex[4];
+ u32 reserved_Fx[4];
+ u32 reserved_1xx[64];
+ u32 reserved_2xx[64];
+ u32 reserved_3xx[64];
+/*
+ * Accessable to FN#0 only
+ * 0x0400 TCA */
+ u32 task_context_assignment[256];
+/* MSI-X registers not included */
+};
+
+/*
+ * *****************************************************************************
+ * SDMA Registers
+ * ***************************************************************************** */
+#define SCU_SDMA_BASE 0x6000
+#define SCU_SDMA_PUFATLHAR_OFFSET 0x0000
+#define SCU_SDMA_PUFATUHAR_OFFSET 0x0004
+#define SCU_SDMA_UFLHBAR_OFFSET 0x0008
+#define SCU_SDMA_UFUHBAR_OFFSET 0x000C
+#define SCU_SDMA_UFQC_OFFSET 0x0010
+#define SCU_SDMA_UFQPP_OFFSET 0x0014
+#define SCU_SDMA_UFQGP_OFFSET 0x0018
+#define SCU_SDMA_PDMACR_OFFSET 0x001C
+#define SCU_SDMA_CDMACR_OFFSET 0x0080
+
+/**
+ * struct scu_sdma_registers - These are the SCU SDMA Registers
+ *
+ *
+ */
+struct scu_sdma_registers {
+/* 0x0000 PUFATLHAR */
+ u32 uf_address_table_lower;
+/* 0x0004 PUFATUHAR */
+ u32 uf_address_table_upper;
+/* 0x0008 UFLHBAR */
+ u32 uf_header_base_address_lower;
+/* 0x000C UFUHBAR */
+ u32 uf_header_base_address_upper;
+/* 0x0010 UFQC */
+ u32 unsolicited_frame_queue_control;
+/* 0x0014 UFQPP */
+ u32 unsolicited_frame_put_pointer;
+/* 0x0018 UFQGP */
+ u32 unsolicited_frame_get_pointer;
+/* 0x001C PDMACR */
+ u32 pdma_configuration;
+/* Reserved until offset 0x80 */
+ u32 reserved_0020_007C[0x18];
+/* 0x0080 CDMACR */
+ u32 cdma_configuration;
+/* Remainder SDMA register space */
+ u32 reserved_0084_0400[0xDF];
+
+};
+
+/*
+ * *****************************************************************************
+ * * SCU Link Registers
+ * ***************************************************************************** */
+#define SCU_PEG0_OFFSET 0x0000
+#define SCU_PEG1_OFFSET 0x8000
+
+#define SCU_TL0_OFFSET 0x0000
+#define SCU_TL1_OFFSET 0x0400
+#define SCU_TL2_OFFSET 0x0800
+#define SCU_TL3_OFFSET 0x0C00
+
+#define SCU_LL_OFFSET 0x0080
+#define SCU_LL0_OFFSET (SCU_TL0_OFFSET + SCU_LL_OFFSET)
+#define SCU_LL1_OFFSET (SCU_TL1_OFFSET + SCU_LL_OFFSET)
+#define SCU_LL2_OFFSET (SCU_TL2_OFFSET + SCU_LL_OFFSET)
+#define SCU_LL3_OFFSET (SCU_TL3_OFFSET + SCU_LL_OFFSET)
+
+/* Transport Layer Offsets (PEG + TL) */
+#define SCU_TLCR_OFFSET 0x0000
+#define SCU_TLADTR_OFFSET 0x0004
+#define SCU_TLTTMR_OFFSET 0x0008
+#define SCU_TLEECR0_OFFSET 0x000C
+#define SCU_STPTLDARNI_OFFSET 0x0010
+
+
+#define SCU_TLCR_HASH_SAS_CHECKING_ENABLE_SHIFT (0)
+#define SCU_TLCR_HASH_SAS_CHECKING_ENABLE_MASK (0x00000001)
+#define SCU_TLCR_CLEAR_TCI_NCQ_MAPPING_TABLE_SHIFT (1)
+#define SCU_TLCR_CLEAR_TCI_NCQ_MAPPING_TABLE_MASK (0x00000002)
+#define SCU_TLCR_STP_WRITE_DATA_PREFETCH_SHIFT (3)
+#define SCU_TLCR_STP_WRITE_DATA_PREFETCH_MASK (0x00000008)
+#define SCU_TLCR_CMD_NAK_STATUS_CODE_SHIFT (4)
+#define SCU_TLCR_CMD_NAK_STATUS_CODE_MASK (0x00000010)
+#define SCU_TLCR_RESERVED_MASK (0xFFFFFFEB)
+
+#define SCU_TLCR_GEN_BIT(name) \
+ SCU_GEN_BIT(SCU_TLCR_ ## name)
+
+/**
+ * struct scu_transport_layer_registers - These are the SCU Transport Layer
+ * registers
+ *
+ *
+ */
+struct scu_transport_layer_registers {
+ /* 0x0000 TLCR */
+ u32 control;
+ /* 0x0004 TLADTR */
+ u32 arbitration_delay_timer;
+ /* 0x0008 TLTTMR */
+ u32 timer_test_mode;
+ /* 0x000C reserved */
+ u32 reserved_0C;
+ /* 0x0010 STPTLDARNI */
+ u32 stp_rni;
+ /* 0x0014 TLFEWPORCTRL */
+ u32 tlfe_wpo_read_control;
+ /* 0x0018 TLFEWPORDATA */
+ u32 tlfe_wpo_read_data;
+ /* 0x001C RXTLSSCSR1 */
+ u32 rxtl_single_step_control_status_1;
+ /* 0x0020 RXTLSSCSR2 */
+ u32 rxtl_single_step_control_status_2;
+ /* 0x0024 AWTRDDCR */
+ u32 tlfe_awt_retry_delay_debug_control;
+ /* Remainder of TL memory space */
+ u32 reserved_0028_007F[0x16];
+
+};
+
+/* Protocol Engine Group Registers */
+#define SCU_SCUVZECRx_OFFSET 0x1080
+
+/* Link Layer Offsets (PEG + TL + LL) */
+#define SCU_SAS_SPDTOV_OFFSET 0x0000
+#define SCU_SAS_LLSTA_OFFSET 0x0004
+#define SCU_SATA_PSELTOV_OFFSET 0x0008
+#define SCU_SAS_TIMETOV_OFFSET 0x0010
+#define SCU_SAS_LOSTOT_OFFSET 0x0014
+#define SCU_SAS_LNKTOV_OFFSET 0x0018
+#define SCU_SAS_PHYTOV_OFFSET 0x001C
+#define SCU_SAS_AFERCNT_OFFSET 0x0020
+#define SCU_SAS_WERCNT_OFFSET 0x0024
+#define SCU_SAS_TIID_OFFSET 0x0028
+#define SCU_SAS_TIDNH_OFFSET 0x002C
+#define SCU_SAS_TIDNL_OFFSET 0x0030
+#define SCU_SAS_TISSAH_OFFSET 0x0034
+#define SCU_SAS_TISSAL_OFFSET 0x0038
+#define SCU_SAS_TIPID_OFFSET 0x003C
+#define SCU_SAS_TIRES2_OFFSET 0x0040
+#define SCU_SAS_ADRSTA_OFFSET 0x0044
+#define SCU_SAS_MAWTTOV_OFFSET 0x0048
+#define SCU_SAS_FRPLDFIL_OFFSET 0x0054
+#define SCU_SAS_RFCNT_OFFSET 0x0060
+#define SCU_SAS_TFCNT_OFFSET 0x0064
+#define SCU_SAS_RFDCNT_OFFSET 0x0068
+#define SCU_SAS_TFDCNT_OFFSET 0x006C
+#define SCU_SAS_LERCNT_OFFSET 0x0070
+#define SCU_SAS_RDISERRCNT_OFFSET 0x0074
+#define SCU_SAS_CRERCNT_OFFSET 0x0078
+#define SCU_STPCTL_OFFSET 0x007C
+#define SCU_SAS_PCFG_OFFSET 0x0080
+#define SCU_SAS_CLKSM_OFFSET 0x0084
+#define SCU_SAS_TXCOMWAKE_OFFSET 0x0088
+#define SCU_SAS_TXCOMINIT_OFFSET 0x008C
+#define SCU_SAS_TXCOMSAS_OFFSET 0x0090
+#define SCU_SAS_COMINIT_OFFSET 0x0094
+#define SCU_SAS_COMWAKE_OFFSET 0x0098
+#define SCU_SAS_COMSAS_OFFSET 0x009C
+#define SCU_SAS_SFERCNT_OFFSET 0x00A0
+#define SCU_SAS_CDFERCNT_OFFSET 0x00A4
+#define SCU_SAS_DNFERCNT_OFFSET 0x00A8
+#define SCU_SAS_PRSTERCNT_OFFSET 0x00AC
+#define SCU_SAS_CNTCTL_OFFSET 0x00B0
+#define SCU_SAS_SSPTOV_OFFSET 0x00B4
+#define SCU_FTCTL_OFFSET 0x00B8
+#define SCU_FRCTL_OFFSET 0x00BC
+#define SCU_FTWMRK_OFFSET 0x00C0
+#define SCU_ENSPINUP_OFFSET 0x00C4
+#define SCU_SAS_TRNTOV_OFFSET 0x00C8
+#define SCU_SAS_PHYCAP_OFFSET 0x00CC
+#define SCU_SAS_PHYCTL_OFFSET 0x00D0
+#define SCU_SAS_LLCTL_OFFSET 0x00D8
+#define SCU_AFE_XCVRCR_OFFSET 0x00DC
+#define SCU_AFE_LUTCR_OFFSET 0x00E0
+
+#define SCU_SAS_LINK_LAYER_CONTROL_MAX_LINK_RATE_SHIFT (0)
+#define SCU_SAS_LINK_LAYER_CONTROL_MAX_LINK_RATE_MASK (0x00000003)
+#define SCU_SAS_LINK_LAYER_CONTROL_MAX_LINK_RATE_GEN1 (0)
+#define SCU_SAS_LINK_LAYER_CONTROL_MAX_LINK_RATE_GEN2 (1)
+#define SCU_SAS_LINK_LAYER_CONTROL_MAX_LINK_RATE_GEN3 (2)
+#define SCU_SAS_LINK_LAYER_CONTROL_BROADCAST_PRIMITIVE_SHIFT (2)
+#define SCU_SAS_LINK_LAYER_CONTROL_BROADCAST_PRIMITIVE_MASK (0x000003FC)
+#define SCU_SAS_LINK_LAYER_CONTROL_CLOSE_NO_ACTIVE_TASK_DISABLE_SHIFT (16)
+#define SCU_SAS_LINK_LAYER_CONTROL_CLOSE_NO_ACTIVE_TASK_DISABLE_MASK (0x00010000)
+#define SCU_SAS_LINK_LAYER_CONTROL_CLOSE_NO_OUTBOUND_TASK_DISABLE_SHIFT (17)
+#define SCU_SAS_LINK_LAYER_CONTROL_CLOSE_NO_OUTBOUND_TASK_DISABLE_MASK (0x00020000)
+#define SCU_SAS_LINK_LAYER_CONTROL_NO_OUTBOUND_TASK_TIMEOUT_SHIFT (24)
+#define SCU_SAS_LINK_LAYER_CONTROL_NO_OUTBOUND_TASK_TIMEOUT_MASK (0xFF000000)
+#define SCU_SAS_LINK_LAYER_CONTROL_RESERVED (0x00FCFC00)
+
+#define SCU_SAS_LLCTL_GEN_VAL(name, value) \
+ SCU_GEN_VALUE(SCU_SAS_LINK_LAYER_CONTROL_ ## name, value)
+
+#define SCU_SAS_LLCTL_GEN_BIT(name) \
+ SCU_GEN_BIT(SCU_SAS_LINK_LAYER_CONTROL_ ## name)
+
+
+/* #define SCU_FRXHECR_DCNT_OFFSET 0x00B0 */
+#define SCU_PSZGCR_OFFSET 0x00E4
+#define SCU_SAS_RECPHYCAP_OFFSET 0x00E8
+/* #define SCU_TX_LUTSEL_OFFSET 0x00B8 */
+
+#define SCU_SAS_PTxC_OFFSET 0x00D4 /* Same offset as SAS_TCTSTM */
+
+/**
+ * struct scu_link_layer_registers - SCU Link Layer Registers
+ *
+ *
+ */
+struct scu_link_layer_registers {
+/* 0x0000 SAS_SPDTOV */
+ u32 speed_negotiation_timers;
+/* 0x0004 SAS_LLSTA */
+ u32 link_layer_status;
+/* 0x0008 SATA_PSELTOV */
+ u32 port_selector_timeout;
+ u32 reserved0C;
+/* 0x0010 SAS_TIMETOV */
+ u32 timeout_unit_value;
+/* 0x0014 SAS_RCDTOV */
+ u32 rcd_timeout;
+/* 0x0018 SAS_LNKTOV */
+ u32 link_timer_timeouts;
+/* 0x001C SAS_PHYTOV */
+ u32 sas_phy_timeouts;
+/* 0x0020 SAS_AFERCNT */
+ u32 received_address_frame_error_counter;
+/* 0x0024 SAS_WERCNT */
+ u32 invalid_dword_counter;
+/* 0x0028 SAS_TIID */
+ u32 transmit_identification;
+/* 0x002C SAS_TIDNH */
+ u32 sas_device_name_high;
+/* 0x0030 SAS_TIDNL */
+ u32 sas_device_name_low;
+/* 0x0034 SAS_TISSAH */
+ u32 source_sas_address_high;
+/* 0x0038 SAS_TISSAL */
+ u32 source_sas_address_low;
+/* 0x003C SAS_TIPID */
+ u32 identify_frame_phy_id;
+/* 0x0040 SAS_TIRES2 */
+ u32 identify_frame_reserved;
+/* 0x0044 SAS_ADRSTA */
+ u32 received_address_frame;
+/* 0x0048 SAS_MAWTTOV */
+ u32 maximum_arbitration_wait_timer_timeout;
+/* 0x004C SAS_PTxC */
+ u32 transmit_primitive;
+/* 0x0050 SAS_RORES */
+ u32 error_counter_event_notification_control;
+/* 0x0054 SAS_FRPLDFIL */
+ u32 frxq_payload_fill_threshold;
+/* 0x0058 SAS_LLHANG_TOT */
+ u32 link_layer_hang_detection_timeout;
+ u32 reserved_5C;
+/* 0x0060 SAS_RFCNT */
+ u32 received_frame_count;
+/* 0x0064 SAS_TFCNT */
+ u32 transmit_frame_count;
+/* 0x0068 SAS_RFDCNT */
+ u32 received_dword_count;
+/* 0x006C SAS_TFDCNT */
+ u32 transmit_dword_count;
+/* 0x0070 SAS_LERCNT */
+ u32 loss_of_sync_error_count;
+/* 0x0074 SAS_RDISERRCNT */
+ u32 running_disparity_error_count;
+/* 0x0078 SAS_CRERCNT */
+ u32 received_frame_crc_error_count;
+/* 0x007C STPCTL */
+ u32 stp_control;
+/* 0x0080 SAS_PCFG */
+ u32 phy_configuration;
+/* 0x0084 SAS_CLKSM */
+ u32 clock_skew_management;
+/* 0x0088 SAS_TXCOMWAKE */
+ u32 transmit_comwake_signal;
+/* 0x008C SAS_TXCOMINIT */
+ u32 transmit_cominit_signal;
+/* 0x0090 SAS_TXCOMSAS */
+ u32 transmit_comsas_signal;
+/* 0x0094 SAS_COMINIT */
+ u32 cominit_control;
+/* 0x0098 SAS_COMWAKE */
+ u32 comwake_control;
+/* 0x009C SAS_COMSAS */
+ u32 comsas_control;
+/* 0x00A0 SAS_SFERCNT */
+ u32 received_short_frame_count;
+/* 0x00A4 SAS_CDFERCNT */
+ u32 received_frame_without_credit_count;
+/* 0x00A8 SAS_DNFERCNT */
+ u32 received_frame_after_done_count;
+/* 0x00AC SAS_PRSTERCNT */
+ u32 phy_reset_problem_count;
+/* 0x00B0 SAS_CNTCTL */
+ u32 counter_control;
+/* 0x00B4 SAS_SSPTOV */
+ u32 ssp_timer_timeout_values;
+/* 0x00B8 FTCTL */
+ u32 ftx_control;
+/* 0x00BC FRCTL */
+ u32 frx_control;
+/* 0x00C0 FTWMRK */
+ u32 ftx_watermark;
+/* 0x00C4 ENSPINUP */
+ u32 notify_enable_spinup_control;
+/* 0x00C8 SAS_TRNTOV */
+ u32 sas_training_sequence_timer_values;
+/* 0x00CC SAS_PHYCAP */
+ u32 phy_capabilities;
+/* 0x00D0 SAS_PHYCTL */
+ u32 phy_control;
+ u32 reserved_d4;
+/* 0x00D8 LLCTL */
+ u32 link_layer_control;
+/* 0x00DC AFE_XCVRCR */
+ u32 afe_xcvr_control;
+/* 0x00E0 AFE_LUTCR */
+ u32 afe_lookup_table_control;
+/* 0x00E4 PSZGCR */
+ u32 phy_source_zone_group_control;
+/* 0x00E8 SAS_RECPHYCAP */
+ u32 receive_phycap;
+ u32 reserved_ec;
+/* 0x00F0 SNAFERXRSTCTL */
+ u32 speed_negotiation_afe_rx_reset_control;
+/* 0x00F4 SAS_SSIPMCTL */
+ u32 power_management_control;
+/* 0x00F8 SAS_PSPREQ_PRIM */
+ u32 sas_pm_partial_request_primitive;
+/* 0x00FC SAS_PSSREQ_PRIM */
+ u32 sas_pm_slumber_request_primitive;
+/* 0x0100 SAS_PPSACK_PRIM */
+ u32 sas_pm_ack_primitive_register;
+/* 0x0104 SAS_PSNAK_PRIM */
+ u32 sas_pm_nak_primitive_register;
+/* 0x0108 SAS_SSIPMTOV */
+ u32 sas_primitive_timeout;
+ u32 reserved_10c;
+/* 0x0110 - 0x011C PLAPRDCTRLxREG */
+ u32 pla_product_control[4];
+/* 0x0120 PLAPRDSUMREG */
+ u32 pla_product_sum;
+/* 0x0124 PLACONTROLREG */
+ u32 pla_control;
+/* Remainder of memory space 896 bytes */
+ u32 reserved_0128_037f[0x96];
+
+};
+
+/*
+ * 0x00D4 // Same offset as SAS_TCTSTM SAS_PTxC
+ * u32 primitive_transmit_control; */
+
+/*
+ * ----------------------------------------------------------------------------
+ * SGPIO
+ * ---------------------------------------------------------------------------- */
+#define SCU_SGPIO_OFFSET 0x1400
+
+/* #define SCU_SGPIO_OFFSET 0x6000 // later moves to 0x1400 see HSD 652625 */
+#define SCU_SGPIO_SGICR_OFFSET 0x0000
+#define SCU_SGPIO_SGPBR_OFFSET 0x0004
+#define SCU_SGPIO_SGSDLR_OFFSET 0x0008
+#define SCU_SGPIO_SGSDUR_OFFSET 0x000C
+#define SCU_SGPIO_SGSIDLR_OFFSET 0x0010
+#define SCU_SGPIO_SGSIDUR_OFFSET 0x0014
+#define SCU_SGPIO_SGVSCR_OFFSET 0x0018
+/* Address from 0x0820 to 0x083C */
+#define SCU_SGPIO_SGODSR_OFFSET 0x0020
+
+/**
+ * struct scu_sgpio_registers - SCU SGPIO Registers
+ *
+ *
+ */
+struct scu_sgpio_registers {
+/* 0x0000 SGPIO_SGICR */
+ u32 interface_control;
+/* 0x0004 SGPIO_SGPBR */
+ u32 blink_rate;
+/* 0x0008 SGPIO_SGSDLR */
+ u32 start_drive_lower;
+/* 0x000C SGPIO_SGSDUR */
+ u32 start_drive_upper;
+/* 0x0010 SGPIO_SGSIDLR */
+ u32 serial_input_lower;
+/* 0x0014 SGPIO_SGSIDUR */
+ u32 serial_input_upper;
+/* 0x0018 SGPIO_SGVSCR */
+ u32 vendor_specific_code;
+/* 0x0020 SGPIO_SGODSR */
+ u32 ouput_data_select[8];
+/* Remainder of memory space 256 bytes */
+ u32 reserved_1444_14ff[0x31];
+
+};
+
+/*
+ * *****************************************************************************
+ * * Defines for VIIT entry offsets
+ * * Access additional entries by SCU_VIIT_BASE + index * 0x10
+ * ***************************************************************************** */
+#define SCU_VIIT_BASE 0x1c00
+
+struct SCU_VIIT_REGISTERS {
+ u32 registers[256];
+};
+
+/*
+ * *****************************************************************************
+ * * SCU PORT TASK SCHEDULER REGISTERS
+ * ***************************************************************************** */
+
+#define SCU_PTSG_BASE 0x1000
+
+#define SCU_PTSG_PTSGCR_OFFSET 0x0000
+#define SCU_PTSG_RTCR_OFFSET 0x0004
+#define SCU_PTSG_RTCCR_OFFSET 0x0008
+#define SCU_PTSG_PTS0CR_OFFSET 0x0010
+#define SCU_PTSG_PTS0SR_OFFSET 0x0014
+#define SCU_PTSG_PTS1CR_OFFSET 0x0018
+#define SCU_PTSG_PTS1SR_OFFSET 0x001C
+#define SCU_PTSG_PTS2CR_OFFSET 0x0020
+#define SCU_PTSG_PTS2SR_OFFSET 0x0024
+#define SCU_PTSG_PTS3CR_OFFSET 0x0028
+#define SCU_PTSG_PTS3SR_OFFSET 0x002C
+#define SCU_PTSG_PCSPE0CR_OFFSET 0x0030
+#define SCU_PTSG_PCSPE1CR_OFFSET 0x0034
+#define SCU_PTSG_PCSPE2CR_OFFSET 0x0038
+#define SCU_PTSG_PCSPE3CR_OFFSET 0x003C
+#define SCU_PTSG_ETMTSCCR_OFFSET 0x0040
+#define SCU_PTSG_ETMRNSCCR_OFFSET 0x0044
+
+/**
+ * struct scu_port_task_scheduler_registers - These are the control/stats pairs
+ * for each Port Task Scheduler.
+ *
+ *
+ */
+struct scu_port_task_scheduler_registers {
+ u32 control;
+ u32 status;
+};
+
+typedef u32 SCU_PORT_PE_CONFIGURATION_REGISTER_T;
+
+/**
+ * struct scu_port_task_scheduler_group_registers - These are the PORT Task
+ * Scheduler registers
+ *
+ *
+ */
+struct scu_port_task_scheduler_group_registers {
+/* 0x0000 PTSGCR */
+ u32 control;
+/* 0x0004 RTCR */
+ u32 real_time_clock;
+/* 0x0008 RTCCR */
+ u32 real_time_clock_control;
+/* 0x000C */
+ u32 reserved_0C;
+/*
+ * 0x0010 PTS0CR
+ * 0x0014 PTS0SR
+ * 0x0018 PTS1CR
+ * 0x001C PTS1SR
+ * 0x0020 PTS2CR
+ * 0x0024 PTS2SR
+ * 0x0028 PTS3CR
+ * 0x002C PTS3SR */
+ struct scu_port_task_scheduler_registers port[4];
+/*
+ * 0x0030 PCSPE0CR
+ * 0x0034 PCSPE1CR
+ * 0x0038 PCSPE2CR
+ * 0x003C PCSPE3CR */
+ SCU_PORT_PE_CONFIGURATION_REGISTER_T protocol_engine[4];
+/* 0x0040 ETMTSCCR */
+ u32 tc_scanning_interval_control;
+/* 0x0044 ETMRNSCCR */
+ u32 rnc_scanning_interval_control;
+/* Remainder of memory space 128 bytes */
+ u32 reserved_1048_107f[0x0E];
+
+};
+
+#define SCU_PTSG_SCUVZECR_OFFSET 0x003C
+
+/*
+ * *****************************************************************************
+ * * AFE REGISTERS
+ * ***************************************************************************** */
+#define SCU_AFE_MMR_BASE 0xE000
+
+/*
+ * AFE 0 is at offset 0x0800
+ * AFE 1 is at offset 0x0900
+ * AFE 2 is at offset 0x0a00
+ * AFE 3 is at offset 0x0b00 */
+struct scu_afe_transceiver {
+ /* 0x0000 AFE_XCVR_CTRL0 */
+ u32 afe_xcvr_control0;
+ /* 0x0004 AFE_XCVR_CTRL1 */
+ u32 afe_xcvr_control1;
+ /* 0x0008 */
+ u32 reserved_0008;
+ /* 0x000c afe_dfx_rx_control0 */
+ u32 afe_dfx_rx_control0;
+ /* 0x0010 AFE_DFX_RX_CTRL1 */
+ u32 afe_dfx_rx_control1;
+ /* 0x0014 */
+ u32 reserved_0014;
+ /* 0x0018 AFE_DFX_RX_STS0 */
+ u32 afe_dfx_rx_status0;
+ /* 0x001c AFE_DFX_RX_STS1 */
+ u32 afe_dfx_rx_status1;
+ /* 0x0020 */
+ u32 reserved_0020;
+ /* 0x0024 AFE_TX_CTRL */
+ u32 afe_tx_control;
+ /* 0x0028 AFE_TX_AMP_CTRL0 */
+ u32 afe_tx_amp_control0;
+ /* 0x002c AFE_TX_AMP_CTRL1 */
+ u32 afe_tx_amp_control1;
+ /* 0x0030 AFE_TX_AMP_CTRL2 */
+ u32 afe_tx_amp_control2;
+ /* 0x0034 AFE_TX_AMP_CTRL3 */
+ u32 afe_tx_amp_control3;
+ /* 0x0038 afe_tx_ssc_control */
+ u32 afe_tx_ssc_control;
+ /* 0x003c */
+ u32 reserved_003c;
+ /* 0x0040 AFE_RX_SSC_CTRL0 */
+ u32 afe_rx_ssc_control0;
+ /* 0x0044 AFE_RX_SSC_CTRL1 */
+ u32 afe_rx_ssc_control1;
+ /* 0x0048 AFE_RX_SSC_CTRL2 */
+ u32 afe_rx_ssc_control2;
+ /* 0x004c AFE_RX_EQ_STS0 */
+ u32 afe_rx_eq_status0;
+ /* 0x0050 AFE_RX_EQ_STS1 */
+ u32 afe_rx_eq_status1;
+ /* 0x0054 AFE_RX_CDR_STS */
+ u32 afe_rx_cdr_status;
+ /* 0x0058 */
+ u32 reserved_0058;
+ /* 0x005c AFE_CHAN_CTRL */
+ u32 afe_channel_control;
+ /* 0x0060-0x006c */
+ u32 reserved_0060_006c[0x04];
+ /* 0x0070 AFE_XCVR_EC_STS0 */
+ u32 afe_xcvr_error_capture_status0;
+ /* 0x0074 AFE_XCVR_EC_STS1 */
+ u32 afe_xcvr_error_capture_status1;
+ /* 0x0078 AFE_XCVR_EC_STS2 */
+ u32 afe_xcvr_error_capture_status2;
+ /* 0x007c afe_xcvr_ec_status3 */
+ u32 afe_xcvr_error_capture_status3;
+ /* 0x0080 AFE_XCVR_EC_STS4 */
+ u32 afe_xcvr_error_capture_status4;
+ /* 0x0084 AFE_XCVR_EC_STS5 */
+ u32 afe_xcvr_error_capture_status5;
+ /* 0x0088-0x00fc */
+ u32 reserved_008c_00fc[0x1e];
+};
+
+/**
+ * struct scu_afe_registers - AFE Regsiters
+ *
+ *
+ */
+/* Uaoa AFE registers */
+struct scu_afe_registers {
+ /* 0Xe000 AFE_BIAS_CTRL */
+ u32 afe_bias_control;
+ u32 reserved_0004;
+ /* 0x0008 AFE_PLL_CTRL0 */
+ u32 afe_pll_control0;
+ /* 0x000c AFE_PLL_CTRL1 */
+ u32 afe_pll_control1;
+ /* 0x0010 AFE_PLL_CTRL2 */
+ u32 afe_pll_control2;
+ /* 0x0014 AFE_CB_STS */
+ u32 afe_common_block_status;
+ /* 0x0018-0x007c */
+ u32 reserved_18_7c[0x1a];
+ /* 0x0080 AFE_PMSN_MCTRL0 */
+ u32 afe_pmsn_master_control0;
+ /* 0x0084 AFE_PMSN_MCTRL1 */
+ u32 afe_pmsn_master_control1;
+ /* 0x0088 AFE_PMSN_MCTRL2 */
+ u32 afe_pmsn_master_control2;
+ /* 0x008C-0x00fc */
+ u32 reserved_008c_00fc[0x1D];
+ /* 0x0100 AFE_DFX_MST_CTRL0 */
+ u32 afe_dfx_master_control0;
+ /* 0x0104 AFE_DFX_MST_CTRL1 */
+ u32 afe_dfx_master_control1;
+ /* 0x0108 AFE_DFX_DCL_CTRL */
+ u32 afe_dfx_dcl_control;
+ /* 0x010c AFE_DFX_DMON_CTRL */
+ u32 afe_dfx_digital_monitor_control;
+ /* 0x0110 AFE_DFX_AMONP_CTRL */
+ u32 afe_dfx_analog_p_monitor_control;
+ /* 0x0114 AFE_DFX_AMONN_CTRL */
+ u32 afe_dfx_analog_n_monitor_control;
+ /* 0x0118 AFE_DFX_NTL_STS */
+ u32 afe_dfx_ntl_status;
+ /* 0x011c AFE_DFX_FIFO_STS0 */
+ u32 afe_dfx_fifo_status0;
+ /* 0x0120 AFE_DFX_FIFO_STS1 */
+ u32 afe_dfx_fifo_status1;
+ /* 0x0124 AFE_DFX_MPAT_CTRL */
+ u32 afe_dfx_master_pattern_control;
+ /* 0x0128 AFE_DFX_P0_CTRL */
+ u32 afe_dfx_p0_control;
+ /* 0x012c-0x01a8 AFE_DFX_P0_DRx */
+ u32 afe_dfx_p0_data[32];
+ /* 0x01ac */
+ u32 reserved_01ac;
+ /* 0x01b0-0x020c AFE_DFX_P0_IRx */
+ u32 afe_dfx_p0_instruction[24];
+ /* 0x0210 */
+ u32 reserved_0210;
+ /* 0x0214 AFE_DFX_P1_CTRL */
+ u32 afe_dfx_p1_control;
+ /* 0x0218-0x245 AFE_DFX_P1_DRx */
+ u32 afe_dfx_p1_data[16];
+ /* 0x0258-0x029c */
+ u32 reserved_0258_029c[0x12];
+ /* 0x02a0-0x02bc AFE_DFX_P1_IRx */
+ u32 afe_dfx_p1_instruction[8];
+ /* 0x02c0-0x2fc */
+ u32 reserved_02c0_02fc[0x10];
+ /* 0x0300 AFE_DFX_TX_PMSN_CTRL */
+ u32 afe_dfx_tx_pmsn_control;
+ /* 0x0304 AFE_DFX_RX_PMSN_CTRL */
+ u32 afe_dfx_rx_pmsn_control;
+ u32 reserved_0308;
+ /* 0x030c AFE_DFX_NOA_CTRL0 */
+ u32 afe_dfx_noa_control0;
+ /* 0x0310 AFE_DFX_NOA_CTRL1 */
+ u32 afe_dfx_noa_control1;
+ /* 0x0314 AFE_DFX_NOA_CTRL2 */
+ u32 afe_dfx_noa_control2;
+ /* 0x0318 AFE_DFX_NOA_CTRL3 */
+ u32 afe_dfx_noa_control3;
+ /* 0x031c AFE_DFX_NOA_CTRL4 */
+ u32 afe_dfx_noa_control4;
+ /* 0x0320 AFE_DFX_NOA_CTRL5 */
+ u32 afe_dfx_noa_control5;
+ /* 0x0324 AFE_DFX_NOA_CTRL6 */
+ u32 afe_dfx_noa_control6;
+ /* 0x0328 AFE_DFX_NOA_CTRL7 */
+ u32 afe_dfx_noa_control7;
+ /* 0x032c-0x07fc */
+ u32 reserved_032c_07fc[0x135];
+
+ /* 0x0800-0x0bfc */
+ struct scu_afe_transceiver scu_afe_xcvr[4];
+
+ /* 0x0c00-0x0ffc */
+ u32 reserved_0c00_0ffc[0x0100];
+};
+
+struct SCU_PROTOCOL_ENGINE_GROUP_REGISTERS {
+ u32 table[0xE0];
+};
+
+
+struct SCU_VIIT_IIT {
+ u32 table[256];
+};
+
+/**
+ * Placeholder for the ZONE Partition Table information ZONING will not be
+ * included in the 1.1 release.
+ *
+ *
+ */
+struct SCU_ZONE_PARTITION_TABLE {
+ u32 table[2048];
+};
+
+/**
+ * Placeholder for the CRAM register since I am not sure if we need to
+ * read/write to these registers as yet.
+ *
+ *
+ */
+struct SCU_COMPLETION_RAM {
+ u32 ram[128];
+};
+
+/**
+ * Placeholder for the FBRAM registers since I am not sure if we need to
+ * read/write to these registers as yet.
+ *
+ *
+ */
+struct SCU_FRAME_BUFFER_RAM {
+ u32 ram[128];
+};
+
+#define SCU_SCRATCH_RAM_SIZE_IN_DWORDS 256
+
+/**
+ * Placeholder for the scratch RAM registers.
+ *
+ *
+ */
+struct SCU_SCRATCH_RAM {
+ u32 ram[SCU_SCRATCH_RAM_SIZE_IN_DWORDS];
+};
+
+/**
+ * Placeholder since I am not yet sure what these registers are here for.
+ *
+ *
+ */
+struct NOA_PROTOCOL_ENGINE_PARTITION {
+ u32 reserved[64];
+};
+
+/**
+ * Placeholder since I am not yet sure what these registers are here for.
+ *
+ *
+ */
+struct NOA_HUB_PARTITION {
+ u32 reserved[64];
+};
+
+/**
+ * Placeholder since I am not yet sure what these registers are here for.
+ *
+ *
+ */
+struct NOA_HOST_INTERFACE_PARTITION {
+ u32 reserved[64];
+};
+
+/**
+ * struct TRANSPORT_LINK_LAYER_PAIR - The SCU Hardware pairs up the TL
+ * registers with the LL registers so we must place them adjcent to make the
+ * array of registers in the PEG.
+ *
+ *
+ */
+struct TRANSPORT_LINK_LAYER_PAIR {
+ struct scu_transport_layer_registers tl;
+ struct scu_link_layer_registers ll;
+};
+
+/**
+ * struct SCU_PEG_REGISTERS - SCU Protocol Engine Memory mapped register space.
+ * These registers are unique to each protocol engine group. There can be
+ * at most two PEG for a single SCU part.
+ *
+ *
+ */
+struct SCU_PEG_REGISTERS {
+ struct TRANSPORT_LINK_LAYER_PAIR pe[4];
+ struct scu_port_task_scheduler_group_registers ptsg;
+ struct SCU_PROTOCOL_ENGINE_GROUP_REGISTERS peg;
+ struct scu_sgpio_registers sgpio;
+ u32 reserved_01500_1BFF[0x1C0];
+ struct scu_viit_entry viit[64];
+ struct SCU_ZONE_PARTITION_TABLE zpt0;
+ struct SCU_ZONE_PARTITION_TABLE zpt1;
+};
+
+/**
+ * struct scu_registers - SCU regsiters including both PEG registers if we turn
+ * on that compile option. All of these registers are in the memory mapped
+ * space returned from BAR1.
+ *
+ *
+ */
+struct scu_registers {
+ /* 0x0000 - PEG 0 */
+ struct SCU_PEG_REGISTERS peg0;
+
+ /* 0x6000 - SDMA and Miscellaneous */
+ struct scu_sdma_registers sdma;
+ struct SCU_COMPLETION_RAM cram;
+ struct SCU_FRAME_BUFFER_RAM fbram;
+ u32 reserved_6800_69FF[0x80];
+ struct NOA_PROTOCOL_ENGINE_PARTITION noa_pe;
+ struct NOA_HUB_PARTITION noa_hub;
+ struct NOA_HOST_INTERFACE_PARTITION noa_if;
+ u32 reserved_6d00_7fff[0x4c0];
+
+ /* 0x8000 - PEG 1 */
+ struct SCU_PEG_REGISTERS peg1;
+
+ /* 0xE000 - AFE Registers */
+ struct scu_afe_registers afe;
+
+ /* 0xF000 - reserved */
+ u32 reserved_f000_211fff[0x80c00];
+
+ /* 0x212000 - scratch RAM */
+ struct SCU_SCRATCH_RAM scratch_ram;
+
+};
+
+
+#endif /* _SCU_REGISTERS_HEADER_ */
diff --git a/drivers/scsi/isci/core/scu_remote_node_context.h b/drivers/scsi/isci/core/scu_remote_node_context.h
new file mode 100644
index 000000000000..8006f2ee2d1d
--- /dev/null
+++ b/drivers/scsi/isci/core/scu_remote_node_context.h
@@ -0,0 +1,230 @@
+/*
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Intel Corporation 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
+ * OWNER 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.
+ */
+
+#ifndef __SCU_REMOTE_NODE_CONTEXT_HEADER__
+#define __SCU_REMOTE_NODE_CONTEXT_HEADER__
+
+/**
+ * This file contains the structures and constatns used by the SCU hardware to
+ * describe a remote node context.
+ *
+ *
+ */
+#include "sci_types.h"
+
+/**
+ * struct ssp_remote_node_context - This structure contains the SCU hardware
+ * definition for an SSP remote node.
+ *
+ *
+ */
+struct ssp_remote_node_context {
+ /* WORD 0 */
+
+ /**
+ * This field is the remote node index assigned for this remote node. All
+ * remote nodes must have a unique remote node index. The value of the remote
+ * node index can not exceed the maximum number of remote nodes reported in
+ * the SCU device context capacity register.
+ */
+ u32 remote_node_index:12;
+ u32 reserved0_1:4;
+
+ /**
+ * This field tells the SCU hardware how many simultaneous connections that
+ * this remote node will support.
+ */
+ u32 remote_node_port_width:4;
+
+ /**
+ * This field tells the SCU hardware which logical port to associate with this
+ * remote node.
+ */
+ u32 logical_port_index:3;
+ u32 reserved0_2:5;
+
+ /**
+ * This field will enable the I_T nexus loss timer for this remote node.
+ */
+ u32 nexus_loss_timer_enable:1;
+
+ /**
+ * This field is the for driver debug only and is not used.
+ */
+ u32 check_bit:1;
+
+ /**
+ * This field must be set to true when the hardware DMAs the remote node
+ * context to the hardware SRAM. When the remote node is being invalidated
+ * this field must be set to false.
+ */
+ u32 is_valid:1;
+
+ /**
+ * This field must be set to true.
+ */
+ u32 is_remote_node_context:1;
+
+ /* WORD 1 - 2 */
+
+ /**
+ * This is the low word of the remote device SAS Address
+ */
+ u32 remote_sas_address_lo;
+
+ /**
+ * This field is the high word of the remote device SAS Address
+ */
+ u32 remote_sas_address_hi;
+
+ /* WORD 3 */
+ /**
+ * This field reprensets the function number assigned to this remote device.
+ * This value must match the virtual function number that is being used to
+ * communicate to the device.
+ */
+ u32 function_number:8;
+ u32 reserved3_1:8;
+
+ /**
+ * This field provides the driver a way to cheat on the arbitration wait time
+ * for this remote node.
+ */
+ u32 arbitration_wait_time:16;
+
+ /* WORD 4 */
+ /**
+ * This field tells the SCU hardware how long this device may occupy the
+ * connection before it must be closed.
+ */
+ u32 connection_occupancy_timeout:16;
+
+ /**
+ * This field tells the SCU hardware how long to maintain a connection when
+ * there are no frames being transmitted on the link.
+ */
+ u32 connection_inactivity_timeout:16;
+
+ /* WORD 5 */
+ /**
+ * This field allows the driver to cheat on the arbitration wait time for this
+ * remote node.
+ */
+ u32 initial_arbitration_wait_time:16;
+
+ /**
+ * This field is tells the hardware what to program for the connection rate in
+ * the open address frame. See the SAS spec for valid values.
+ */
+ u32 oaf_connection_rate:4;
+
+ /**
+ * This field tells the SCU hardware what to program for the features in the
+ * open address frame. See the SAS spec for valid values.
+ */
+ u32 oaf_features:4;
+
+ /**
+ * This field tells the SCU hardware what to use for the source zone group in
+ * the open address frame. See the SAS spec for more details on zoning.
+ */
+ u32 oaf_source_zone_group:8;
+
+ /* WORD 6 */
+ /**
+ * This field tells the SCU hardware what to use as the more capibilities in
+ * the open address frame. See the SAS Spec for details.
+ */
+ u32 oaf_more_compatibility_features;
+
+ /* WORD 7 */
+ u32 reserved7;
+
+};
+
+/**
+ * struct stp_remote_node_context - This structure contains the SCU hardware
+ * definition for a STP remote node.
+ *
+ * STP Targets are not yet supported so this definition is a placeholder until
+ * we do support them.
+ */
+struct stp_remote_node_context {
+ /**
+ * Placeholder data for the STP remote node.
+ */
+ u32 data[8];
+
+};
+
+/**
+ * This union combines the SAS and SATA remote node definitions.
+ *
+ * union scu_remote_node_context
+ */
+union scu_remote_node_context {
+ /**
+ * SSP Remote Node
+ */
+ struct ssp_remote_node_context ssp;
+
+ /**
+ * STP Remote Node
+ */
+ struct stp_remote_node_context stp;
+
+};
+
+#endif /* __SCU_REMOTE_NODE_CONTEXT_HEADER__ */
diff --git a/drivers/scsi/isci/core/scu_task_context.h b/drivers/scsi/isci/core/scu_task_context.h
new file mode 100644
index 000000000000..d08c51bb2262
--- /dev/null
+++ b/drivers/scsi/isci/core/scu_task_context.h
@@ -0,0 +1,943 @@
+/*
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Intel Corporation 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
+ * OWNER 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.
+ */
+
+#ifndef _SCU_TASK_CONTEXT_H_
+#define _SCU_TASK_CONTEXT_H_
+
+/**
+ * This file contains the structures and constants for the SCU hardware task
+ * context.
+ *
+ *
+ */
+
+#include "sci_types.h"
+
+/**
+ * enum SCU_SSP_TASK_TYPE - This enumberation defines the various SSP task
+ * types the SCU hardware will accept. The definition for the various task
+ * types the SCU hardware will accept can be found in the DS specification.
+ *
+ *
+ */
+typedef enum {
+ SCU_TASK_TYPE_IOREAD, /* /< IO READ direction or no direction */
+ SCU_TASK_TYPE_IOWRITE, /* /< IO Write direction */
+ SCU_TASK_TYPE_SMP_REQUEST, /* /< SMP Request type */
+ SCU_TASK_TYPE_RESPONSE, /* /< Driver generated response frame (targt mode) */
+ SCU_TASK_TYPE_RAW_FRAME, /* /< Raw frame request type */
+ SCU_TASK_TYPE_PRIMITIVE /* /< Request for a primitive to be transmitted */
+} SCU_SSP_TASK_TYPE;
+
+/**
+ * enum SCU_SATA_TASK_TYPE - This enumeration defines the various SATA task
+ * types the SCU hardware will accept. The definition for the various task
+ * types the SCU hardware will accept can be found in the DS specification.
+ *
+ *
+ */
+typedef enum {
+ SCU_TASK_TYPE_DMA_IN, /* /< Read request */
+ SCU_TASK_TYPE_FPDMAQ_READ, /* /< NCQ read request */
+ SCU_TASK_TYPE_PACKET_DMA_IN, /* /< Packet read request */
+ SCU_TASK_TYPE_SATA_RAW_FRAME, /* /< Raw frame request */
+ RESERVED_4,
+ RESERVED_5,
+ RESERVED_6,
+ RESERVED_7,
+ SCU_TASK_TYPE_DMA_OUT, /* /< Write request */
+ SCU_TASK_TYPE_FPDMAQ_WRITE, /* /< NCQ write Request */
+ SCU_TASK_TYPE_PACKET_DMA_OUT /* /< Packet write request */
+} SCU_SATA_TASK_TYPE;
+
+
+/**
+ *
+ *
+ * SCU_CONTEXT_TYPE
+ */
+#define SCU_TASK_CONTEXT_TYPE 0
+#define SCU_RNC_CONTEXT_TYPE 1
+
+/**
+ *
+ *
+ * SCU_TASK_CONTEXT_VALIDITY
+ */
+#define SCU_TASK_CONTEXT_INVALID 0
+#define SCU_TASK_CONTEXT_VALID 1
+
+/**
+ *
+ *
+ * SCU_COMMAND_CODE
+ */
+#define SCU_COMMAND_CODE_INITIATOR_NEW_TASK 0
+#define SCU_COMMAND_CODE_ACTIVE_TASK 1
+#define SCU_COMMAND_CODE_PRIMITIVE_SEQ_TASK 2
+#define SCU_COMMAND_CODE_TARGET_RAW_FRAMES 3
+
+/**
+ *
+ *
+ * SCU_TASK_PRIORITY
+ */
+/**
+ *
+ *
+ * This priority is used when there is no priority request for this request.
+ */
+#define SCU_TASK_PRIORITY_NORMAL 0
+
+/**
+ *
+ *
+ * This priority indicates that the task should be scheduled to the head of the
+ * queue. The task will NOT be executed if the TX is suspended for the remote
+ * node.
+ */
+#define SCU_TASK_PRIORITY_HEAD_OF_Q 1
+
+/**
+ *
+ *
+ * This priority indicates that the task will be executed before all
+ * SCU_TASK_PRIORITY_NORMAL and SCU_TASK_PRIORITY_HEAD_OF_Q tasks. The task
+ * WILL be executed if the TX is suspended for the remote node.
+ */
+#define SCU_TASK_PRIORITY_HIGH 2
+
+/**
+ *
+ *
+ * This task priority is reserved and should not be used.
+ */
+#define SCU_TASK_PRIORITY_RESERVED 3
+
+#define SCU_TASK_INITIATOR_MODE 1
+#define SCU_TASK_TARGET_MODE 0
+
+#define SCU_TASK_REGULAR 0
+#define SCU_TASK_ABORTED 1
+
+/* direction bit defintion */
+/**
+ *
+ *
+ * SATA_DIRECTION
+ */
+#define SCU_SATA_WRITE_DATA_DIRECTION 0
+#define SCU_SATA_READ_DATA_DIRECTION 1
+
+/**
+ *
+ *
+ * SCU_COMMAND_CONTEXT_MACROS These macros provide the mask and shift
+ * operations to construct the various SCU commands
+ */
+#define SCU_CONTEXT_COMMAND_REQUEST_TYPE_SHIFT 21
+#define SCU_CONTEXT_COMMAND_REQUEST_TYPE_MASK 0x00E00000
+#define scu_get_command_request_type(x) \
+ ((x) & SCU_CONTEXT_COMMAND_REQUEST_TYPE_MASK)
+
+#define SCU_CONTEXT_COMMAND_REQUEST_SUBTYPE_SHIFT 18
+#define SCU_CONTEXT_COMMAND_REQUEST_SUBTYPE_MASK 0x001C0000
+#define scu_get_command_request_subtype(x) \
+ ((x) & SCU_CONTEXT_COMMAND_REQUEST_SUBTYPE_MASK)
+
+#define SCU_CONTEXT_COMMAND_REQUEST_FULLTYPE_MASK \
+ (\
+ SCU_CONTEXT_COMMAND_REQUEST_TYPE_MASK \
+ | SCU_CONTEXT_COMMAND_REQUEST_SUBTYPE_MASK \
+ )
+#define scu_get_command_request_full_type(x) \
+ ((x) & SCU_CONTEXT_COMMAND_REQUEST_FULLTYPE_MASK)
+
+#define SCU_CONTEXT_COMMAND_PROTOCOL_ENGINE_GROUP_SHIFT 16
+#define SCU_CONTEXT_COMMAND_PROTOCOL_ENGINE_GROUP_MASK 0x00010000
+#define scu_get_command_protocl_engine_group(x) \
+ ((x) & SCU_CONTEXT_COMMAND_PROTOCOL_ENGINE_GROUP_MASK)
+
+#define SCU_CONTEXT_COMMAND_LOGICAL_PORT_SHIFT 12
+#define SCU_CONTEXT_COMMAND_LOGICAL_PORT_MASK 0x00007000
+#define scu_get_command_reqeust_logical_port(x) \
+ ((x) & SCU_CONTEXT_COMMAND_LOGICAL_PORT_MASK)
+
+
+#define MAKE_SCU_CONTEXT_COMMAND_TYPE(type) \
+ ((u32)(type) << SCU_CONTEXT_COMMAND_REQUEST_TYPE_SHIFT)
+
+/**
+ * MAKE_SCU_CONTEXT_COMMAND_TYPE() -
+ *
+ * SCU_COMMAND_TYPES These constants provide the grouping of the different SCU
+ * command types.
+ */
+#define SCU_CONTEXT_COMMAND_REQUEST_TYPE_POST_TC MAKE_SCU_CONTEXT_COMMAND_TYPE(0)
+#define SCU_CONTEXT_COMMAND_REQUEST_TYPE_DUMP_TC MAKE_SCU_CONTEXT_COMMAND_TYPE(1)
+#define SCU_CONTEXT_COMMAND_REQUEST_TYPE_POST_RNC MAKE_SCU_CONTEXT_COMMAND_TYPE(2)
+#define SCU_CONTEXT_COMMAND_REQUEST_TYPE_DUMP_RNC MAKE_SCU_CONTEXT_COMMAND_TYPE(3)
+#define SCU_CONTEXT_COMMAND_REQUEST_TYPE_OTHER_RNC MAKE_SCU_CONTEXT_COMMAND_TYPE(6)
+
+#define MAKE_SCU_CONTEXT_COMMAND_REQUEST(type, command) \
+ ((type) | ((command) << SCU_CONTEXT_COMMAND_REQUEST_SUBTYPE_SHIFT))
+
+/**
+ *
+ *
+ * SCU_REQUEST_TYPES These constants are the various request types that can be
+ * posted to the SCU hardware.
+ */
+#define SCU_CONTEXT_COMMAND_REQUST_POST_TC \
+ (MAKE_SCU_CONTEXT_COMMAND_REQUEST(SCU_CONTEXT_COMMAND_REQUEST_TYPE_POST_TC, 0))
+
+#define SCU_CONTEXT_COMMAND_REQUEST_POST_TC_ABORT \
+ (MAKE_SCU_CONTEXT_COMMAND_REQUEST(SCU_CONTEXT_COMMAND_REQUEST_TYPE_POST_TC, 1))
+
+#define SCU_CONTEXT_COMMAND_REQUST_DUMP_TC \
+ (MAKE_SCU_CONTEXT_COMMAND_REQUEST(SCU_CONTEXT_COMMAND_REQUEST_TYPE_DUMP_TC, 0))
+
+#define SCU_CONTEXT_COMMAND_POST_RNC_32 \
+ (MAKE_SCU_CONTEXT_COMMAND_REQUEST(SCU_CONTEXT_COMMAND_REQUEST_TYPE_POST_RNC, 0))
+
+#define SCU_CONTEXT_COMMAND_POST_RNC_96 \
+ (MAKE_SCU_CONTEXT_COMMAND_REQUEST(SCU_CONTEXT_COMMAND_REQUEST_TYPE_POST_RNC, 1))
+
+#define SCU_CONTEXT_COMMAND_POST_RNC_INVALIDATE \
+ (MAKE_SCU_CONTEXT_COMMAND_REQUEST(SCU_CONTEXT_COMMAND_REQUEST_TYPE_POST_RNC, 2))
+
+#define SCU_CONTEXT_COMMAND_DUMP_RNC_32 \
+ (MAKE_SCU_CONTEXT_COMMAND_REQUEST(SCU_CONTEXT_COMMAND_REQUEST_TYPE_DUMP_RNC, 0))
+
+#define SCU_CONTEXT_COMMAND_DUMP_RNC_96 \
+ (MAKE_SCU_CONTEXT_COMMAND_REQUEST(SCU_CONTEXT_COMMAND_REQUEST_TYPE_DUMP_RNC, 1))
+
+#define SCU_CONTEXT_COMMAND_POST_RNC_SUSPEND_TX \
+ (MAKE_SCU_CONTEXT_COMMAND_REQUEST(SCU_CONTEXT_COMMAND_REQUEST_TYPE_OTHER_RNC, 0))
+
+#define SCU_CONTEXT_COMMAND_POST_RNC_SUSPEND_TX_RX \
+ (MAKE_SCU_CONTEXT_COMMAND_REQUEST(SCU_CONTEXT_COMMAND_REQUEST_TYPE_OTHER_RNC, 1))
+
+#define SCU_CONTEXT_COMMAND_POST_RNC_RESUME \
+ (MAKE_SCU_CONTEXT_COMMAND_REQUEST(SCU_CONTEXT_COMMAND_REQUEST_TYPE_OTHER_RNC, 2))
+
+#define SCU_CONTEXT_IT_NEXUS_LOSS_TIMER_ENABLE \
+ (MAKE_SCU_CONTEXT_COMMAND_REQUEST(SCU_CONTEXT_COMMAND_REQUEST_TYPE_OTHER_RNC, 3))
+
+#define SCU_CONTEXT_IT_NEXUS_LOSS_TIMER_DISABLE \
+ (MAKE_SCU_CONTEXT_COMMAND_REQUEST(SCU_CONTEXT_COMMAND_REQUEST_TYPE_OTHER_RNC, 4))
+
+/**
+ *
+ *
+ * SCU_TASK_CONTEXT_PROTOCOL SCU Task context protocol types this is uesd to
+ * program the SCU Task context protocol field in word 0x00.
+ */
+#define SCU_TASK_CONTEXT_PROTOCOL_SMP 0x00
+#define SCU_TASK_CONTEXT_PROTOCOL_SSP 0x01
+#define SCU_TASK_CONTEXT_PROTOCOL_STP 0x02
+#define SCU_TASK_CONTEXT_PROTOCOL_NONE 0x07
+
+/**
+ * struct SSP_TASK_CONTEXT - This is the SCU hardware definition for an SSP
+ * request.
+ *
+ *
+ */
+struct SSP_TASK_CONTEXT {
+ /* OFFSET 0x18 */
+ u32 reserved00:24;
+ u32 frame_type:8;
+
+ /* OFFSET 0x1C */
+ u32 reserved01;
+
+ /* OFFSET 0x20 */
+ u32 fill_bytes:2;
+ u32 reserved02:6;
+ u32 changing_data_pointer:1;
+ u32 retransmit:1;
+ u32 retry_data_frame:1;
+ u32 tlr_control:2;
+ u32 reserved03:19;
+
+ /* OFFSET 0x24 */
+ u32 uiRsvd4;
+
+ /* OFFSET 0x28 */
+ u32 target_port_transfer_tag:16;
+ u32 tag:16;
+
+ /* OFFSET 0x2C */
+ u32 data_offset;
+};
+
+/**
+ * struct STP_TASK_CONTEXT - This is the SCU hardware definition for an STP
+ * request.
+ *
+ *
+ */
+struct STP_TASK_CONTEXT {
+ /* OFFSET 0x18 */
+ u32 fis_type:8;
+ u32 pm_port:4;
+ u32 reserved0:3;
+ u32 control:1;
+ u32 command:8;
+ u32 features:8;
+
+ /* OFFSET 0x1C */
+ u32 reserved1;
+
+ /* OFFSET 0x20 */
+ u32 reserved2;
+
+ /* OFFSET 0x24 */
+ u32 reserved3;
+
+ /* OFFSET 0x28 */
+ u32 ncq_tag:5;
+ u32 reserved4:27;
+
+ /* OFFSET 0x2C */
+ u32 data_offset; /* TODO: What is this used for? */
+};
+
+/**
+ * struct SMP_TASK_CONTEXT - This is the SCU hardware definition for an SMP
+ * request.
+ *
+ *
+ */
+struct SMP_TASK_CONTEXT {
+ /* OFFSET 0x18 */
+ u32 response_length:8;
+ u32 function_result:8;
+ u32 function:8;
+ u32 frame_type:8;
+
+ /* OFFSET 0x1C */
+ u32 smp_response_ufi:12;
+ u32 reserved1:20;
+
+ /* OFFSET 0x20 */
+ u32 reserved2;
+
+ /* OFFSET 0x24 */
+ u32 reserved3;
+
+ /* OFFSET 0x28 */
+ u32 reserved4;
+
+ /* OFFSET 0x2C */
+ u32 reserved5;
+};
+
+/**
+ * struct PRIMITIVE_TASK_CONTEXT - This is the SCU hardware definition used
+ * when the driver wants to send a primitive on the link.
+ *
+ *
+ */
+struct PRIMITIVE_TASK_CONTEXT {
+ /* OFFSET 0x18 */
+ /**
+ * This field is the control word and it must be 0.
+ */
+ u32 control; /* /< must be set to 0 */
+
+ /* OFFSET 0x1C */
+ /**
+ * This field specifies the primitive that is to be transmitted.
+ */
+ u32 sequence;
+
+ /* OFFSET 0x20 */
+ u32 reserved0;
+
+ /* OFFSET 0x24 */
+ u32 reserved1;
+
+ /* OFFSET 0x28 */
+ u32 reserved2;
+
+ /* OFFSET 0x2C */
+ u32 reserved3;
+};
+
+/**
+ * The union of the protocols that can be selected in the SCU task context
+ * field.
+ *
+ * PROTOCOL_CONTEXT
+ */
+union PROTOCOL_CONTEXT {
+ struct SSP_TASK_CONTEXT ssp;
+ struct STP_TASK_CONTEXT stp;
+ struct SMP_TASK_CONTEXT smp;
+ struct PRIMITIVE_TASK_CONTEXT primitive;
+ u32 words[6];
+};
+
+/**
+ * struct scu_sgl_element - This structure represents a single SCU defined SGL
+ * element. SCU SGLs contain a 64 bit address with the maximum data transfer
+ * being 24 bits in size. The SGL can not cross a 4GB boundary.
+ *
+ * struct scu_sgl_element
+ */
+struct scu_sgl_element {
+ /**
+ * This field is the upper 32 bits of the 64 bit physical address.
+ */
+ u32 address_upper;
+
+ /**
+ * This field is the lower 32 bits of the 64 bit physical address.
+ */
+ u32 address_lower;
+
+ /**
+ * This field is the number of bytes to transfer.
+ */
+ u32 length:24;
+
+ /**
+ * This field is the address modifier to be used when a virtual function is
+ * requesting a data transfer.
+ */
+ u32 address_modifier:8;
+
+};
+
+#define SCU_SGL_ELEMENT_PAIR_A 0
+#define SCU_SGL_ELEMENT_PAIR_B 1
+
+/**
+ * struct scu_sgl_element_pair - This structure is the SCU hardware definition
+ * of a pair of SGL elements. The SCU hardware always works on SGL pairs.
+ * They are refered to in the DS specification as SGL A and SGL B. Each SGL
+ * pair is followed by the address of the next pair.
+ *
+ *
+ */
+struct scu_sgl_element_pair {
+ /* OFFSET 0x60-0x68 */
+ /**
+ * This field is the SGL element A of the SGL pair.
+ */
+ struct scu_sgl_element A;
+
+ /* OFFSET 0x6C-0x74 */
+ /**
+ * This field is the SGL element B of the SGL pair.
+ */
+ struct scu_sgl_element B;
+
+ /* OFFSET 0x78-0x7C */
+ /**
+ * This field is the upper 32 bits of the 64 bit address to the next SGL
+ * element pair.
+ */
+ u32 next_pair_upper;
+
+ /**
+ * This field is the lower 32 bits of the 64 bit address to the next SGL
+ * element pair.
+ */
+ u32 next_pair_lower;
+
+};
+
+/**
+ * struct TRANSPORT_SNAPSHOT - This structure is the SCU hardware scratch area
+ * for the task context. This is set to 0 by the driver but can be read by
+ * issuing a dump TC request to the SCU.
+ *
+ *
+ */
+struct TRANSPORT_SNAPSHOT {
+ /* OFFSET 0x48 */
+ u32 xfer_rdy_write_data_length;
+
+ /* OFFSET 0x4C */
+ u32 data_offset;
+
+ /* OFFSET 0x50 */
+ u32 data_transfer_size:24;
+ u32 reserved_50_0:8;
+
+ /* OFFSET 0x54 */
+ u32 next_initiator_write_data_offset;
+
+ /* OFFSET 0x58 */
+ u32 next_initiator_write_data_xfer_size:24;
+ u32 reserved_58_0:8;
+};
+
+/**
+ * struct scu_task_context - This structure defines the contents of the SCU
+ * silicon task context. It lays out all of the fields according to the
+ * expected order and location for the Storage Controller unit.
+ *
+ *
+ */
+struct scu_task_context {
+ /* OFFSET 0x00 ------ */
+ /**
+ * This field must be encoded to one of the valid SCU task priority values
+ * - SCU_TASK_PRIORITY_NORMAL
+ * - SCU_TASK_PRIORITY_HEAD_OF_Q
+ * - SCU_TASK_PRIORITY_HIGH
+ */
+ u32 priority:2;
+
+ /**
+ * This field must be set to true if this is an initiator generated request.
+ * Until target mode is supported all task requests are initiator requests.
+ */
+ u32 initiator_request:1;
+
+ /**
+ * This field must be set to one of the valid connection rates valid values
+ * are 0x8, 0x9, and 0xA.
+ */
+ u32 connection_rate:4;
+
+ /**
+ * This field muse be programed when generating an SMP response since the SMP
+ * connection remains open until the SMP response is generated.
+ */
+ u32 protocol_engine_index:3;
+
+ /**
+ * This field must contain the logical port for the task request.
+ */
+ u32 logical_port_index:3;
+
+ /**
+ * This field must be set to one of the SCU_TASK_CONTEXT_PROTOCOL values
+ * - SCU_TASK_CONTEXT_PROTOCOL_SMP
+ * - SCU_TASK_CONTEXT_PROTOCOL_SSP
+ * - SCU_TASK_CONTEXT_PROTOCOL_STP
+ * - SCU_TASK_CONTEXT_PROTOCOL_NONE
+ */
+ u32 protocol_type:3;
+
+ /**
+ * This filed must be set to the TCi allocated for this task
+ */
+ u32 task_index:12;
+
+ /**
+ * This field is reserved and must be set to 0x00
+ */
+ u32 reserved_00_0:1;
+
+ /**
+ * For a normal task request this must be set to 0. If this is an abort of
+ * this task request it must be set to 1.
+ */
+ u32 abort:1;
+
+ /**
+ * This field must be set to true for the SCU hardware to process the task.
+ */
+ u32 valid:1;
+
+ /**
+ * This field must be set to SCU_TASK_CONTEXT_TYPE
+ */
+ u32 context_type:1;
+
+ /* OFFSET 0x04 */
+ /**
+ * This field contains the RNi that is the target of this request.
+ */
+ u32 remote_node_index:12;
+
+ /**
+ * This field is programmed if this is a mirrored request, which we are not
+ * using, in which case it is the RNi for the mirrored target.
+ */
+ u32 mirrored_node_index:12;
+
+ /**
+ * This field is programmed with the direction of the SATA reqeust
+ * - SCU_SATA_WRITE_DATA_DIRECTION
+ * - SCU_SATA_READ_DATA_DIRECTION
+ */
+ u32 sata_direction:1;
+
+ /**
+ * This field is programmsed with one of the following SCU_COMMAND_CODE
+ * - SCU_COMMAND_CODE_INITIATOR_NEW_TASK
+ * - SCU_COMMAND_CODE_ACTIVE_TASK
+ * - SCU_COMMAND_CODE_PRIMITIVE_SEQ_TASK
+ * - SCU_COMMAND_CODE_TARGET_RAW_FRAMES
+ */
+ u32 command_code:2;
+
+ /**
+ * This field is set to true if the remote node should be suspended.
+ * This bit is only valid for SSP & SMP target devices.
+ */
+ u32 suspend_node:1;
+
+ /**
+ * This field is programmed with one of the following command type codes
+ *
+ * For SAS requests use the SCU_SSP_TASK_TYPE
+ * - SCU_TASK_TYPE_IOREAD
+ * - SCU_TASK_TYPE_IOWRITE
+ * - SCU_TASK_TYPE_SMP_REQUEST
+ * - SCU_TASK_TYPE_RESPONSE
+ * - SCU_TASK_TYPE_RAW_FRAME
+ * - SCU_TASK_TYPE_PRIMITIVE
+ *
+ * For SATA requests use the SCU_SATA_TASK_TYPE
+ * - SCU_TASK_TYPE_DMA_IN
+ * - SCU_TASK_TYPE_FPDMAQ_READ
+ * - SCU_TASK_TYPE_PACKET_DMA_IN
+ * - SCU_TASK_TYPE_SATA_RAW_FRAME
+ * - SCU_TASK_TYPE_DMA_OUT
+ * - SCU_TASK_TYPE_FPDMAQ_WRITE
+ * - SCU_TASK_TYPE_PACKET_DMA_OUT
+ */
+ u32 task_type:4;
+
+ /* OFFSET 0x08 */
+ /**
+ * This field is reserved and the must be set to 0x00
+ */
+ u32 link_layer_control:8; /* presently all reserved */
+
+ /**
+ * This field is set to true when TLR is to be enabled
+ */
+ u32 ssp_tlr_enable:1;
+
+ /**
+ * This is field specifies if the SCU DMAs a response frame to host
+ * memory for good response frames when operating in target mode.
+ */
+ u32 dma_ssp_target_good_response:1;
+
+ /**
+ * This field indicates if the SCU should DMA the response frame to
+ * host memory.
+ */
+ u32 do_not_dma_ssp_good_response:1;
+
+ /**
+ * This field is set to true when strict ordering is to be enabled
+ */
+ u32 strict_ordering:1;
+
+ /**
+ * This field indicates the type of endianess to be utilized for the
+ * frame. command, task, and response frames utilized control_frame
+ * set to 1.
+ */
+ u32 control_frame:1;
+
+ /**
+ * This field is reserved and the driver should set to 0x00
+ */
+ u32 tl_control_reserved:3;
+
+ /**
+ * This field is set to true when the SCU hardware task timeout control is to
+ * be enabled
+ */
+ u32 timeout_enable:1;
+
+ /**
+ * This field is reserved and the driver should set it to 0x00
+ */
+ u32 pts_control_reserved:7;
+
+ /**
+ * This field should be set to true when block guard is to be enabled
+ */
+ u32 block_guard_enable:1;
+
+ /**
+ * This field is reserved and the driver should set to 0x00
+ */
+ u32 sdma_control_reserved:7;
+
+ /* OFFSET 0x0C */
+ /**
+ * This field is the address modifier for this io request it should be
+ * programmed with the virtual function that is making the request.
+ */
+ u32 address_modifier:16;
+
+ /**
+ * @todo What we support mirrored SMP response frame?
+ */
+ u32 mirrored_protocol_engine:3; /* mirrored protocol Engine Index */
+
+ /**
+ * If this is a mirrored request the logical port index for the mirrored RNi
+ * must be programmed.
+ */
+ u32 mirrored_logical_port:4; /* mirrored local port index */
+
+ /**
+ * This field is reserved and the driver must set it to 0x00
+ */
+ u32 reserved_0C_0:8;
+
+ /**
+ * This field must be set to true if the mirrored request processing is to be
+ * enabled.
+ */
+ u32 mirror_request_enable:1; /* Mirrored request Enable */
+
+ /* OFFSET 0x10 */
+ /**
+ * This field is the command iu length in dwords
+ */
+ u32 ssp_command_iu_length:8;
+
+ /**
+ * This is the target TLR enable bit it must be set to 0 when creatning the
+ * task context.
+ */
+ u32 xfer_ready_tlr_enable:1;
+
+ /**
+ * This field is reserved and the driver must set it to 0x00
+ */
+ u32 reserved_10_0:7;
+
+ /**
+ * This is the maximum burst size that the SCU hardware will send in one
+ * connection its value is (N x 512) and N must be a multiple of 2. If the
+ * value is 0x00 then maximum burst size is disabled.
+ */
+ u32 ssp_max_burst_size:16;
+
+ /* OFFSET 0x14 */
+ /**
+ * This filed is set to the number of bytes to be transfered in the request.
+ */
+ u32 transfer_length_bytes:24; /* In terms of bytes */
+
+ /**
+ * This field is reserved and the driver should set it to 0x00
+ */
+ u32 reserved_14_0:8;
+
+ /* OFFSET 0x18-0x2C */
+ /**
+ * This union provides for the protocol specif part of the SCU Task Context.
+ */
+ union PROTOCOL_CONTEXT type;
+
+ /* OFFSET 0x30-0x34 */
+ /**
+ * This field is the upper 32 bits of the 64 bit physical address of the
+ * command iu buffer
+ */
+ u32 command_iu_upper;
+
+ /**
+ * This field is the lower 32 bits of the 64 bit physical address of the
+ * command iu buffer
+ */
+ u32 command_iu_lower;
+
+ /* OFFSET 0x38-0x3C */
+ /**
+ * This field is the upper 32 bits of the 64 bit physical address of the
+ * response iu buffer
+ */
+ u32 response_iu_upper;
+
+ /**
+ * This field is the lower 32 bits of the 64 bit physical address of the
+ * response iu buffer
+ */
+ u32 response_iu_lower;
+
+ /* OFFSET 0x40 */
+ /**
+ * This field is set to the task phase of the SCU hardware. The driver must
+ * set this to 0x01
+ */
+ u32 task_phase:8;
+
+ /**
+ * This field is set to the transport layer task status. The driver must set
+ * this to 0x00
+ */
+ u32 task_status:8;
+
+ /**
+ * This field is used during initiator write TLR
+ */
+ u32 previous_extended_tag:4;
+
+ /**
+ * This field is set the maximum number of retries for a STP non-data FIS
+ */
+ u32 stp_retry_count:2;
+
+ /**
+ * This field is reserved and the driver must set it to 0x00
+ */
+ u32 reserved_40_1:2;
+
+ /**
+ * This field is used by the SCU TL to determine when to take a snapshot when
+ * tranmitting read data frames.
+ * - 0x00 The entire IO
+ * - 0x01 32k
+ * - 0x02 64k
+ * - 0x04 128k
+ * - 0x08 256k
+ */
+ u32 ssp_tlr_threshold:4;
+
+ /**
+ * This field is reserved and the driver must set it to 0x00
+ */
+ u32 reserved_40_2:4;
+
+ /* OFFSET 0x44 */
+ u32 write_data_length; /* read only set to 0 */
+
+ /* OFFSET 0x48-0x58 */
+ struct TRANSPORT_SNAPSHOT snapshot; /* read only set to 0 */
+
+ /* OFFSET 0x5C */
+ u32 block_protection_enable:1;
+ u32 block_size:2;
+ u32 block_protection_function:2;
+ u32 reserved_5C_0:9;
+ u32 active_sgl_element:2; /* read only set to 0 */
+ u32 sgl_exhausted:1; /* read only set to 0 */
+ u32 payload_data_transfer_error:4; /* read only set to 0 */
+ u32 frame_buffer_offset:11; /* read only set to 0 */
+
+ /* OFFSET 0x60-0x7C */
+ /**
+ * This field is the first SGL element pair found in the TC data structure.
+ */
+ struct scu_sgl_element_pair sgl_pair_ab;
+ /* OFFSET 0x80-0x9C */
+ /**
+ * This field is the second SGL element pair found in the TC data structure.
+ */
+ struct scu_sgl_element_pair sgl_pair_cd;
+
+ /* OFFSET 0xA0-BC */
+ struct scu_sgl_element_pair sgl_snapshot_ac;
+
+ /* OFFSET 0xC0 */
+ u32 active_sgl_element_pair; /* read only set to 0 */
+
+ /* OFFSET 0xC4-0xCC */
+ u32 reserved_C4_CC[3];
+
+ /* OFFSET 0xD0 */
+ u32 intermediate_crc_value:16;
+ u32 initial_crc_seed:16;
+
+ /* OFFSET 0xD4 */
+ u32 application_tag_for_verify:16;
+ u32 application_tag_for_generate:16;
+
+ /* OFFSET 0xD8 */
+ u32 reference_tag_seed_for_verify_function;
+
+ /* OFFSET 0xDC */
+ u32 reserved_DC;
+
+ /* OFFSET 0xE0 */
+ u32 reserved_E0_0:16;
+ u32 application_tag_mask_for_generate:16;
+
+ /* OFFSET 0xE4 */
+ u32 block_protection_control:16;
+ u32 application_tag_mask_for_verify:16;
+
+ /* OFFSET 0xE8 */
+ u32 block_protection_error:8;
+ u32 reserved_E8_0:24;
+
+ /* OFFSET 0xEC */
+ u32 reference_tag_seed_for_verify;
+
+ /* OFFSET 0xF0 */
+ u32 intermediate_crc_valid_snapshot:16;
+ u32 reserved_F0_0:16;
+
+ /* OFFSET 0xF4 */
+ u32 reference_tag_seed_for_verify_function_snapshot;
+
+ /* OFFSET 0xF8 */
+ u32 snapshot_of_reserved_dword_DC_of_tc;
+
+ /* OFFSET 0xFC */
+ u32 reference_tag_seed_for_generate_function_snapshot;
+
+};
+
+#endif /* _SCU_TASK_CONTEXT_H_ */
diff --git a/drivers/scsi/isci/core/scu_unsolicited_frame.h b/drivers/scsi/isci/core/scu_unsolicited_frame.h
new file mode 100644
index 000000000000..590ea02745fd
--- /dev/null
+++ b/drivers/scsi/isci/core/scu_unsolicited_frame.h
@@ -0,0 +1,117 @@
+/*
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Intel Corporation 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
+ * OWNER 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.
+ */
+
+/**
+ * This field defines the SCU format of an unsolicited frame (UF). A UF is a
+ * frame received by the SCU for which there is no known corresponding task
+ * context (TC).
+ *
+ *
+ */
+
+#ifndef _SCU_UNSOLICITED_FRAME_H_
+#define _SCU_UNSOLICITED_FRAME_H_
+
+#include "sci_types.h"
+
+/**
+ *
+ *
+ * This constant defines the number of DWORDS found the unsolicited frame
+ * header data member.
+ */
+#define SCU_UNSOLICITED_FRAME_HEADER_DATA_DWORDS 15
+
+/**
+ * struct scu_unsolicited_frame_header -
+ *
+ * This structure delineates the format of an unsolicited frame header. The
+ * first DWORD are UF attributes defined by the silicon architecture. The data
+ * depicts actual header information received on the link.
+ */
+struct scu_unsolicited_frame_header {
+ /**
+ * This field indicates if there is an Initiator Index Table entry with
+ * which this header is associated.
+ */
+ u32 iit_exists:1;
+
+ /**
+ * This field simply indicates the protocol type (i.e. SSP, STP, SMP).
+ */
+ u32 protocol_type:3;
+
+ /**
+ * This field indicates if the frame is an address frame (IAF or OAF)
+ * or if it is a information unit frame.
+ */
+ u32 is_address_frame:1;
+
+ /**
+ * This field simply indicates the connection rate at which the frame
+ * was received.
+ */
+ u32 connection_rate:4;
+
+ u32 reserved:23;
+
+ /**
+ * This field represents the actual header data received on the link.
+ */
+ u32 data[SCU_UNSOLICITED_FRAME_HEADER_DATA_DWORDS];
+
+};
+
+#endif /* _SCU_UNSOLICITED_FRAME_H_ */
diff --git a/drivers/scsi/isci/core/scu_viit_data.h b/drivers/scsi/isci/core/scu_viit_data.h
new file mode 100644
index 000000000000..4601d1962ca3
--- /dev/null
+++ b/drivers/scsi/isci/core/scu_viit_data.h
@@ -0,0 +1,179 @@
+/*
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Intel Corporation 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
+ * OWNER 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.
+ */
+
+#ifndef _SCU_VIIT_DATA_HEADER_
+#define _SCU_VIIT_DATA_HEADER_
+
+/**
+ * This file contains the constants and structures for the SCU hardware VIIT
+ * table entries.
+ *
+ *
+ */
+
+#include "sci_types.h"
+
+#define SCU_VIIT_ENTRY_ID_MASK (0xC0000000)
+#define SCU_VIIT_ENTRY_ID_SHIFT (30)
+
+#define SCU_VIIT_ENTRY_FUNCTION_MASK (0x0FF00000)
+#define SCU_VIIT_ENTRY_FUNCTION_SHIFT (20)
+
+#define SCU_VIIT_ENTRY_IPPTMODE_MASK (0x0001F800)
+#define SCU_VIIT_ENTRY_IPPTMODE_SHIFT (12)
+
+#define SCU_VIIT_ENTRY_LPVIE_MASK (0x00000F00)
+#define SCU_VIIT_ENTRY_LPVIE_SHIFT (8)
+
+#define SCU_VIIT_ENTRY_STATUS_MASK (0x000000FF)
+#define SCU_VIIT_ENTRY_STATUS_SHIFT (0)
+
+#define SCU_VIIT_ENTRY_ID_INVALID (0 << SCU_VIIT_ENTRY_ID_SHIFT)
+#define SCU_VIIT_ENTRY_ID_VIIT (1 << SCU_VIIT_ENTRY_ID_SHIFT)
+#define SCU_VIIT_ENTRY_ID_IIT (2 << SCU_VIIT_ENTRY_ID_SHIFT)
+#define SCU_VIIT_ENTRY_ID_VIRT_EXP (3 << SCU_VIIT_ENTRY_ID_SHIFT)
+
+#define SCU_VIIT_IPPT_SSP_INITIATOR (0x01 << SCU_VIIT_ENTRY_IPPTMODE_SHIFT)
+#define SCU_VIIT_IPPT_SMP_INITIATOR (0x02 << SCU_VIIT_ENTRY_IPPTMODE_SHIFT)
+#define SCU_VIIT_IPPT_STP_INITIATOR (0x04 << SCU_VIIT_ENTRY_IPPTMODE_SHIFT)
+#define SCU_VIIT_IPPT_INITIATOR \
+ (\
+ SCU_VIIT_IPPT_SSP_INITIATOR \
+ | SCU_VIIT_IPPT_SMP_INITIATOR \
+ | SCU_VIIT_IPPT_STP_INITIATOR \
+ )
+
+#define SCU_VIIT_STATUS_RNC_VALID (0x01 << SCU_VIIT_ENTRY_STATUS_SHIFT)
+#define SCU_VIIT_STATUS_ADDRESS_VALID (0x02 << SCU_VIIT_ENTRY_STATUS_SHIFT)
+#define SCU_VIIT_STATUS_RNI_VALID (0x04 << SCU_VIIT_ENTRY_STATUS_SHIFT)
+#define SCU_VIIT_STATUS_ALL_VALID \
+ (\
+ SCU_VIIT_STATUS_RNC_VALID \
+ | SCU_VIIT_STATUS_ADDRESS_VALID \
+ | SCU_VIIT_STATUS_RNI_VALID \
+ )
+
+#define SCU_VIIT_IPPT_SMP_TARGET (0x10 << SCU_VIIT_ENTRY_IPPTMODE_SHIFT)
+
+/**
+ * struct scu_viit_entry - This is the SCU Virtual Initiator Table Entry
+ *
+ *
+ */
+struct scu_viit_entry {
+ /**
+ * This must be encoded as to the type of initiator that is being constructed
+ * for this port.
+ */
+ u32 status;
+
+ /**
+ * Virtual initiator high SAS Address
+ */
+ u32 initiator_sas_address_hi;
+
+ /**
+ * Virtual initiator low SAS Address
+ */
+ u32 initiator_sas_address_lo;
+
+ /**
+ * This must be 0
+ */
+ u32 reserved;
+
+};
+
+
+/* IIT Status Defines */
+#define SCU_IIT_ENTRY_ID_MASK (0xC0000000)
+#define SCU_IIT_ENTRY_ID_SHIFT (30)
+
+#define SCU_IIT_ENTRY_STATUS_UPDATE_MASK (0x20000000)
+#define SCU_IIT_ENTRY_STATUS_UPDATE_SHIFT (29)
+
+#define SCU_IIT_ENTRY_LPI_MASK (0x00000F00)
+#define SCU_IIT_ENTRY_LPI_SHIFT (8)
+
+#define SCU_IIT_ENTRY_STATUS_MASK (0x000000FF)
+#define SCU_IIT_ENTRY_STATUS_SHIFT (0)
+
+/* IIT Remote Initiator Defines */
+#define SCU_IIT_ENTRY_REMOTE_TAG_MASK (0x0000FFFF)
+#define SCU_IIT_ENTRY_REMOTE_TAG_SHIFT (0)
+
+#define SCU_IIT_ENTRY_REMOTE_RNC_MASK (0x0FFF0000)
+#define SCU_IIT_ENTRY_REMOTE_RNC_SHIFT (16)
+
+#define SCU_IIT_ENTRY_ID_INVALID (0 << SCU_IIT_ENTRY_ID_SHIFT)
+#define SCU_IIT_ENTRY_ID_VIIT (1 << SCU_IIT_ENTRY_ID_SHIFT)
+#define SCU_IIT_ENTRY_ID_IIT (2 << SCU_IIT_ENTRY_ID_SHIFT)
+#define SCU_IIT_ENTRY_ID_VIRT_EXP (3 << SCU_IIT_ENTRY_ID_SHIFT)
+
+/**
+ * struct scu_iit_entry - This will be implemented later when we support
+ * virtual functions
+ *
+ *
+ */
+struct scu_iit_entry {
+ u32 status;
+ u32 remote_initiator_sas_address_hi;
+ u32 remote_initiator_sas_address_lo;
+ u32 remote_initiator;
+
+};
+
+#endif /* _SCU_VIIT_DATA_HEADER_ */
diff --git a/drivers/scsi/isci/deprecated.c b/drivers/scsi/isci/deprecated.c
new file mode 100644
index 000000000000..847e6874e1a8
--- /dev/null
+++ b/drivers/scsi/isci/deprecated.c
@@ -0,0 +1,491 @@
+/*
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Intel Corporation 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
+ * OWNER 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.
+ */
+
+
+/**
+ * This file contains isci module object implementation.
+ *
+ *
+ */
+
+#include "isci.h"
+#include "request.h"
+#include "sata.h"
+#include "task.h"
+
+
+/**
+ * scic_cb_stall_execution() - This method is called when the core requires the
+ * OS driver to stall execution. This method is utilized during
+ * initialization or non-performance paths only.
+ * @microseconds: This parameter specifies the number of microseconds for which
+ * to stall. The operating system driver is allowed to round this value up
+ * where necessary.
+ *
+ * none.
+ */
+void scic_cb_stall_execution(
+ u32 microseconds)
+{
+ udelay(microseconds);
+}
+
+
+/**
+ * scic_cb_io_request_get_physical_address() - This callback method asks the
+ * user to provide the physical address for the supplied virtual address
+ * when building an io request object.
+ * @controller: This parameter is the core controller object handle.
+ * @io_request: This parameter is the io request object handle for which the
+ * physical address is being requested.
+ *
+ *
+ */
+void scic_cb_io_request_get_physical_address(
+ struct scic_sds_controller *controller,
+ struct scic_sds_request *io_request,
+ void *virtual_address,
+ dma_addr_t *physical_address)
+{
+ struct isci_request *request =
+ (struct isci_request *)sci_object_get_association(io_request);
+
+ char *requested_address = (char *)virtual_address;
+ char *base_address = (char *)request;
+
+ BUG_ON(requested_address < base_address);
+ BUG_ON((requested_address - base_address) >=
+ request->request_alloc_size);
+
+ *physical_address = request->request_daddr +
+ (requested_address - base_address);
+}
+
+/**
+ * scic_cb_io_request_get_transfer_length() - This callback method asks the
+ * user to provide the number of bytes to be transfered as part of this
+ * request.
+ * @scic_user_io_request: This parameter points to the user's IO request
+ * object. It is a cookie that allows the user to provide the necessary
+ * information for this callback.
+ *
+ * This method returns the number of payload data bytes to be transfered for
+ * this IO request.
+ */
+u32 scic_cb_io_request_get_transfer_length(
+ void *scic_user_io_request)
+{
+ return isci_request_io_request_get_transfer_length(
+ scic_user_io_request
+ );
+}
+
+
+/**
+ * scic_cb_io_request_get_data_direction() - This callback method asks the user
+ * to provide the data direction for this request.
+ * @scic_user_io_request: This parameter points to the user's IO request
+ * object. It is a cookie that allows the user to provide the necessary
+ * information for this callback.
+ *
+ * This method returns the value of SCI_IO_REQUEST_DATA_OUT or
+ * SCI_IO_REQUEST_DATA_IN, or SCI_IO_REQUEST_NO_DATA.
+ */
+SCI_IO_REQUEST_DATA_DIRECTION scic_cb_io_request_get_data_direction(
+ void *scic_user_io_request)
+{
+ return isci_request_io_request_get_data_direction(
+ scic_user_io_request
+ );
+}
+
+
+/**
+ * scic_cb_io_request_get_next_sge() - This callback method asks the user to
+ * provide the address to where the next Scatter-Gather Element is located.
+ * @scic_user_io_request: This parameter points to the user's IO request
+ * object. It is a cookie that allows the user to provide the necessary
+ * information for this callback.
+ * @current_sge_address: This parameter specifies the address for the current
+ * SGE (i.e. the one that has just processed).
+ *
+ * An address specifying the location for the next scatter gather element to be
+ * processed.
+ */
+void scic_cb_io_request_get_next_sge(
+ void *scic_user_io_request,
+ void *current_sge_address,
+ void **next_sge)
+{
+ *next_sge = isci_request_io_request_get_next_sge(
+ scic_user_io_request,
+ current_sge_address
+ );
+}
+
+/**
+ * scic_cb_sge_get_address_field() - This callback method asks the user to
+ * provide the contents of the "address" field in the Scatter-Gather Element.
+ * @scic_user_io_request: This parameter points to the user's IO request
+ * object. It is a cookie that allows the user to provide the necessary
+ * information for this callback.
+ * @sge_address: This parameter specifies the address for the SGE from which to
+ * retrieve the address field.
+ *
+ * A physical address specifying the contents of the SGE's address field.
+ */
+dma_addr_t scic_cb_sge_get_address_field(
+ void *scic_user_io_request,
+ void *sge_address)
+{
+ return isci_request_sge_get_address_field(
+ scic_user_io_request,
+ sge_address
+ );
+}
+
+/**
+ * scic_cb_sge_get_length_field() - This callback method asks the user to
+ * provide the contents of the "length" field in the Scatter-Gather Element.
+ * @scic_user_io_request: This parameter points to the user's IO request
+ * object. It is a cookie that allows the user to provide the necessary
+ * information for this callback.
+ * @sge_address: This parameter specifies the address for the SGE from which to
+ * retrieve the address field.
+ *
+ * This method returns the length field specified inside the SGE referenced by
+ * the sge_address parameter.
+ */
+u32 scic_cb_sge_get_length_field(
+ void *scic_user_io_request,
+ void *sge_address)
+{
+ return isci_request_sge_get_length_field(
+ scic_user_io_request,
+ sge_address
+ );
+}
+
+/**
+ * scic_cb_ssp_io_request_get_cdb_address() - This callback method asks the
+ * user to provide the address for the command descriptor block (CDB)
+ * associated with this IO request.
+ * @scic_user_io_request: This parameter points to the user's IO request
+ * object. It is a cookie that allows the user to provide the necessary
+ * information for this callback.
+ *
+ * This method returns the virtual address of the CDB.
+ */
+void *scic_cb_ssp_io_request_get_cdb_address(
+ void *scic_user_io_request)
+{
+ return isci_request_ssp_io_request_get_cdb_address(
+ scic_user_io_request
+ );
+}
+
+/**
+ * scic_cb_ssp_io_request_get_cdb_length() - This callback method asks the user
+ * to provide the length of the command descriptor block (CDB) associated
+ * with this IO request.
+ * @scic_user_io_request: This parameter points to the user's IO request
+ * object. It is a cookie that allows the user to provide the necessary
+ * information for this callback.
+ *
+ * This method returns the length of the CDB.
+ */
+u32 scic_cb_ssp_io_request_get_cdb_length(
+ void *scic_user_io_request)
+{
+ return isci_request_ssp_io_request_get_cdb_length(
+ scic_user_io_request
+ );
+}
+
+/**
+ * scic_cb_ssp_io_request_get_lun() - This callback method asks the user to
+ * provide the Logical Unit (LUN) associated with this IO request.
+ * @scic_user_io_request: This parameter points to the user's IO request
+ * object. It is a cookie that allows the user to provide the necessary
+ * information for this callback.
+ *
+ * This method returns the LUN associated with this request. This should be u64?
+ */
+u32 scic_cb_ssp_io_request_get_lun(
+ void *scic_user_io_request)
+{
+ return isci_request_ssp_io_request_get_lun(scic_user_io_request);
+}
+
+/**
+ * scic_cb_ssp_io_request_get_task_attribute() - This callback method asks the
+ * user to provide the task attribute associated with this IO request.
+ * @scic_user_io_request: This parameter points to the user's IO request
+ * object. It is a cookie that allows the user to provide the necessary
+ * information for this callback.
+ *
+ * This method returns the task attribute associated with this IO request.
+ */
+u32 scic_cb_ssp_io_request_get_task_attribute(
+ void *scic_user_io_request)
+{
+ return isci_request_ssp_io_request_get_task_attribute(
+ scic_user_io_request
+ );
+}
+
+/**
+ * scic_cb_ssp_io_request_get_command_priority() - This callback method asks
+ * the user to provide the command priority associated with this IO request.
+ * @scic_user_io_request: This parameter points to the user's IO request
+ * object. It is a cookie that allows the user to provide the necessary
+ * information for this callback.
+ *
+ * This method returns the command priority associated with this IO request.
+ */
+u32 scic_cb_ssp_io_request_get_command_priority(
+ void *scic_user_io_request)
+{
+ return isci_request_ssp_io_request_get_command_priority(
+ scic_user_io_request
+ );
+}
+
+/**
+ * scic_cb_ssp_task_request_get_lun() - This method returns the Logical Unit to
+ * be utilized for this task management request.
+ * @scic_user_task_request: This parameter points to the user's task request
+ * object. It is a cookie that allows the user to provide the necessary
+ * information for this callback.
+ *
+ * This method returns the LUN associated with this request. This should be u64?
+ */
+u32 scic_cb_ssp_task_request_get_lun(
+ void *scic_user_task_request)
+{
+ return isci_task_ssp_request_get_lun(
+ (struct isci_request *)scic_user_task_request
+ );
+}
+
+/**
+ * scic_cb_ssp_task_request_get_function() - This method returns the task
+ * management function to be utilized for this task request.
+ * @scic_user_task_request: This parameter points to the user's task request
+ * object. It is a cookie that allows the user to provide the necessary
+ * information for this callback.
+ *
+ * This method returns an unsigned byte representing the task management
+ * function to be performed.
+ */
+u8 scic_cb_ssp_task_request_get_function(
+ void *scic_user_task_request)
+{
+ return isci_task_ssp_request_get_function(
+ (struct isci_request *)scic_user_task_request
+ );
+}
+
+/**
+ * scic_cb_ssp_task_request_get_io_tag_to_manage() - This method returns the
+ * task management IO tag to be managed. Depending upon the task management
+ * function the value returned from this method may be ignored.
+ * @scic_user_task_request: This parameter points to the user's task request
+ * object. It is a cookie that allows the user to provide the necessary
+ * information for this callback.
+ *
+ * This method returns an unsigned 16-bit word depicting the IO tag to be
+ * managed.
+ */
+u16 scic_cb_ssp_task_request_get_io_tag_to_manage(
+ void *scic_user_task_request)
+{
+ return isci_task_ssp_request_get_io_tag_to_manage(
+ (struct isci_request *)scic_user_task_request
+ );
+}
+
+/**
+ * scic_cb_ssp_task_request_get_response_data_address() - This callback method
+ * asks the user to provide the virtual address of the response data buffer
+ * for the supplied IO request.
+ * @scic_user_task_request: This parameter points to the user's task request
+ * object. It is a cookie that allows the user to provide the necessary
+ * information for this callback.
+ *
+ * This method returns the virtual address for the response data buffer
+ * associated with this IO request.
+ */
+void *scic_cb_ssp_task_request_get_response_data_address(
+ void *scic_user_task_request)
+{
+ return isci_task_ssp_request_get_response_data_address(
+ (struct isci_request *)scic_user_task_request
+ );
+}
+
+/**
+ * scic_cb_ssp_task_request_get_response_data_length() - This callback method
+ * asks the user to provide the length of the response data buffer for the
+ * supplied IO request.
+ * @scic_user_task_request: This parameter points to the user's task request
+ * object. It is a cookie that allows the user to provide the necessary
+ * information for this callback.
+ *
+ * This method returns the length of the response buffer data associated with
+ * this IO request.
+ */
+u32 scic_cb_ssp_task_request_get_response_data_length(
+ void *scic_user_task_request)
+{
+ return isci_task_ssp_request_get_response_data_length(
+ (struct isci_request *)scic_user_task_request
+ );
+}
+
+#if !defined(DISABLE_ATAPI)
+/**
+ * scic_cb_stp_packet_io_request_get_cdb_address() - This user callback asks
+ * the user to provide stp packet io's the CDB address.
+ * @scic_user_io_request:
+ *
+ * The packet IO's cdb adress.
+ */
+void *scic_cb_stp_packet_io_request_get_cdb_address(
+ void *scic_user_io_request)
+{
+ return isci_request_stp_packet_io_request_get_cdb_address(
+ scic_user_io_request
+ );
+}
+
+
+/**
+ * scic_cb_stp_packet_io_request_get_cdb_length() - This user callback asks the
+ * user to provide stp packet io's the CDB length.
+ * @scic_user_io_request:
+ *
+ * The packet IO's cdb length.
+ */
+u32 scic_cb_stp_packet_io_request_get_cdb_length(
+ void *scic_user_io_request)
+{
+ return isci_request_stp_packet_io_request_get_cdb_length(
+ scic_user_io_request
+ );
+}
+#endif /* #if !defined(DISABLE_ATAPI) */
+
+
+/**
+ * scic_cb_io_request_do_copy_rx_frames() - This callback method asks the user
+ * if the received RX frame data is to be copied to the SGL or should be
+ * stored by the SCI core to be retrieved later with the
+ * scic_io_request_get_rx_frame().
+ * @scic_user_io_request: This parameter points to the user's IO request
+ * object. It is a cookie that allows the user to provide the necessary
+ * information for this callback.
+ *
+ * This method returns true if the SCI core should copy the received frame data
+ * to the SGL location or false if the SCI user wants to retrieve the frame
+ * data at a later time.
+ */
+bool scic_cb_io_request_do_copy_rx_frames(
+ void *scic_user_io_request)
+{
+ struct sas_task *task
+ = isci_request_access_task(
+ (struct isci_request *)scic_user_io_request
+ );
+
+ return (task->data_dir == DMA_NONE) ? false : true;
+}
+
+/**
+ * scic_cb_get_virtual_address() - This callback method asks the user to
+ * provide the virtual address for the supplied physical address.
+ * @controller: This parameter is the core controller object handle.
+ * @physical_address: This parameter is the physical address which is to be
+ * returned as a virtual address.
+ *
+ * The method returns the virtual address for the supplied physical address.
+ */
+void *scic_cb_get_virtual_address(
+ struct scic_sds_controller *controller,
+ dma_addr_t physical_address)
+{
+ void *virt_addr = (void *)phys_to_virt(physical_address);
+
+ return virt_addr;
+}
+
+/**
+ * scic_cb_request_get_sat_protocol() - This callback method asks the user to
+ * return the SAT protocol definition for this IO request. This method is
+ * only called by the SCI core if the request type constructed is SATA.
+ * @scic_user_io_request: This parameter points to the user's IO request
+ * object. It is a cookie that allows the user to provide the necessary
+ * information for this callback.
+ *
+ * This method returns one of the sat.h defined protocols for the given io
+ * request.
+ */
+u8 scic_cb_request_get_sat_protocol(
+ void *scic_user_io_request)
+{
+ return isci_sata_get_sat_protocol(
+ (struct isci_request *)scic_user_io_request
+ );
+}
diff --git a/drivers/scsi/isci/events.c b/drivers/scsi/isci/events.c
new file mode 100644
index 000000000000..75f9cd551278
--- /dev/null
+++ b/drivers/scsi/isci/events.c
@@ -0,0 +1,619 @@
+/*
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Intel Corporation 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
+ * OWNER 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.
+ */
+
+
+/**
+ * This file contains isci module object implementation.
+ *
+ *
+ */
+
+#include "isci.h"
+#include "request.h"
+#include "sata.h"
+#include "task.h"
+
+/**
+ * scic_cb_timer_create() - This callback method asks the user to create a
+ * timer and provide a handle for this timer for use in further timer
+ * interactions. The appropriate isci timer object function is called to
+ * create a timer object.
+ * @timer_callback: This parameter specifies the callback method to be invoked
+ * whenever the timer expires.
+ * @controller: This parameter specifies the controller with which this timer
+ * is to be associated.
+ * @cookie: This parameter specifies a piece of information that the user must
+ * retain. This cookie is to be supplied by the user anytime a timeout
+ * occurs for the created timer.
+ *
+ * This method returns a handle to a timer object created by the user. The
+ * handle will be utilized for all further interactions relating to this timer.
+ */
+void *scic_cb_timer_create(
+ struct scic_sds_controller *controller,
+ void (*timer_callback)(void *),
+ void *cookie)
+{
+ struct isci_host *isci_host;
+ struct isci_timer *timer = NULL;
+
+ isci_host = (struct isci_host *)sci_object_get_association(controller);
+
+ dev_dbg(&isci_host->pdev->dev,
+ "%s: isci_host = %p",
+ __func__, isci_host);
+
+ timer = isci_timer_create(&isci_host->timer_list_struct,
+ isci_host,
+ cookie,
+ timer_callback);
+
+ dev_dbg(&isci_host->pdev->dev, "%s: timer = %p\n", __func__, timer);
+
+ return (void *)timer;
+}
+
+
+/**
+ * scic_cb_timer_start() - This callback method asks the user to start the
+ * supplied timer. The appropriate isci timer object function is called to
+ * start the timer.
+ * @controller: This parameter specifies the controller with which this timer
+ * is to associated.
+ * @timer: This parameter specifies the timer to be started.
+ * @milliseconds: This parameter specifies the number of milliseconds for which
+ * to stall. The operating system driver is allowed to round this value up
+ * where necessary.
+ *
+ */
+void scic_cb_timer_start(
+ struct scic_sds_controller *controller,
+ void *timer,
+ u32 milliseconds)
+{
+ struct isci_host *isci_host;
+
+ isci_host =
+ (struct isci_host *)sci_object_get_association(controller);
+
+ dev_dbg(&isci_host->pdev->dev,
+ "%s: isci_host = %p, timer = %p, milliseconds = %d\n",
+ __func__, isci_host, timer, milliseconds);
+
+ isci_timer_start((struct isci_timer *)timer, milliseconds);
+
+}
+
+/**
+ * scic_cb_timer_stop() - This callback method asks the user to stop the
+ * supplied timer. The appropriate isci timer object function is called to
+ * stop the timer.
+ * @controller: This parameter specifies the controller with which this timer
+ * is to associated.
+ * @timer: This parameter specifies the timer to be stopped.
+ *
+ */
+void scic_cb_timer_stop(
+ struct scic_sds_controller *controller,
+ void *timer)
+{
+ struct isci_host *isci_host;
+
+ isci_host =
+ (struct isci_host *)sci_object_get_association(controller);
+
+ dev_dbg(&isci_host->pdev->dev,
+ "%s: isci_host = %p, timer = %p\n",
+ __func__, isci_host, timer);
+
+ isci_timer_stop((struct isci_timer *)timer);
+}
+
+/**
+ * scic_cb_controller_start_complete() - This user callback will inform the
+ * user that the controller has finished the start process. The associated
+ * isci host adapter's start_complete function is called.
+ * @controller: This parameter specifies the controller that was started.
+ * @completion_status: This parameter specifies the results of the start
+ * operation. SCI_SUCCESS indicates successful completion.
+ *
+ */
+void scic_cb_controller_start_complete(
+ struct scic_sds_controller *controller,
+ enum sci_status completion_status)
+{
+ struct isci_host *isci_host =
+ (struct isci_host *)sci_object_get_association(controller);
+
+ dev_dbg(&isci_host->pdev->dev,
+ "%s: isci_host = %p\n", __func__, isci_host);
+
+ isci_host_start_complete(isci_host, completion_status);
+}
+
+/**
+ * scic_cb_controller_stop_complete() - This user callback will inform the user
+ * that the controller has finished the stop process. The associated isci
+ * host adapter's start_complete function is called.
+ * @controller: This parameter specifies the controller that was stopped.
+ * @completion_status: This parameter specifies the results of the stop
+ * operation. SCI_SUCCESS indicates successful completion.
+ *
+ */
+void scic_cb_controller_stop_complete(
+ struct scic_sds_controller *controller,
+ enum sci_status completion_status)
+{
+ struct isci_host *isci_host =
+ (struct isci_host *)sci_object_get_association(controller);
+
+ dev_dbg(&isci_host->pdev->dev,
+ "%s: status = 0x%x\n", __func__, completion_status);
+ isci_host_stop_complete(isci_host, completion_status);
+}
+
+/**
+ * scic_cb_io_request_complete() - This user callback will inform the user that
+ * an IO request has completed.
+ * @controller: This parameter specifies the controller on which the IO is
+ * completing.
+ * @remote_device: This parameter specifies the remote device on which this IO
+ * request is completing.
+ * @io_request: This parameter specifies the IO request that has completed.
+ * @completion_status: This parameter specifies the results of the IO request
+ * operation. SCI_SUCCESS indicates successful completion.
+ *
+ */
+void scic_cb_io_request_complete(
+ struct scic_sds_controller *controller,
+ struct scic_sds_remote_device *remote_device,
+ struct scic_sds_request *scic_io_request,
+ enum sci_io_status completion_status)
+{
+ struct isci_request *request;
+ struct isci_host *isci_host;
+
+ isci_host =
+ (struct isci_host *)sci_object_get_association(controller);
+
+ request =
+ (struct isci_request *)sci_object_get_association(
+ scic_io_request
+ );
+
+ isci_request_io_request_complete(isci_host,
+ request,
+ completion_status);
+}
+
+/**
+ * scic_cb_task_request_complete() - This user callback will inform the user
+ * that a task management request completed.
+ * @controller: This parameter specifies the controller on which the task
+ * management request is completing.
+ * @remote_device: This parameter specifies the remote device on which this
+ * task management request is completing.
+ * @task_request: This parameter specifies the task management request that has
+ * completed.
+ * @completion_status: This parameter specifies the results of the IO request
+ * operation. SCI_SUCCESS indicates successful completion.
+ *
+ */
+void scic_cb_task_request_complete(
+ struct scic_sds_controller *controller,
+ struct scic_sds_remote_device *remote_device,
+ struct scic_sds_request *scic_task_request,
+ enum sci_task_status completion_status)
+{
+ struct isci_request *request;
+ struct isci_host *isci_host;
+
+ isci_host =
+ (struct isci_host *)sci_object_get_association(controller);
+
+ request =
+ (struct isci_request *)sci_object_get_association(
+ scic_task_request);
+
+ isci_task_request_complete(isci_host, request, completion_status);
+}
+
+/**
+ * scic_cb_port_stop_complete() - This method informs the user when a stop
+ * operation on the port has completed.
+ * @controller: This parameter represents the controller which contains the
+ * port.
+ * @port: This parameter specifies the SCI port object for which the callback
+ * is being invoked.
+ * @completion_status: This parameter specifies the status for the operation
+ * being completed.
+ *
+ */
+void scic_cb_port_stop_complete(
+ struct scic_sds_controller *controller,
+ struct scic_sds_port *port,
+ enum sci_status completion_status)
+{
+ pr_warn("%s:************************************************\n",
+ __func__);
+}
+
+/**
+ * scic_cb_port_hard_reset_complete() - This method informs the user when a
+ * hard reset on the port has completed. This hard reset could have been
+ * initiated by the user or by the remote port.
+ * @controller: This parameter represents the controller which contains the
+ * port.
+ * @port: This parameter specifies the SCI port object for which the callback
+ * is being invoked.
+ * @completion_status: This parameter specifies the status for the operation
+ * being completed.
+ *
+ */
+void scic_cb_port_hard_reset_complete(
+ struct scic_sds_controller *controller,
+ struct scic_sds_port *port,
+ enum sci_status completion_status)
+{
+ struct isci_port *isci_port
+ = (struct isci_port *)sci_object_get_association(port);
+
+ isci_port_hard_reset_complete(isci_port, completion_status);
+}
+
+/**
+ * scic_cb_port_ready() - This method informs the user that the port is now in
+ * a ready state and can be utilized to issue IOs.
+ * @controller: This parameter represents the controller which contains the
+ * port.
+ * @port: This parameter specifies the SCI port object for which the callback
+ * is being invoked.
+ *
+ */
+void scic_cb_port_ready(
+ struct scic_sds_controller *controller,
+ struct scic_sds_port *port)
+{
+ struct isci_port *isci_port;
+ struct isci_host *isci_host;
+
+ isci_host =
+ (struct isci_host *)sci_object_get_association(controller);
+
+ isci_port =
+ (struct isci_port *)sci_object_get_association(port);
+
+ dev_dbg(&isci_host->pdev->dev,
+ "%s: isci_port = %p\n", __func__, isci_port);
+
+ isci_port_ready(isci_host, isci_port);
+}
+
+/**
+ * scic_cb_port_not_ready() - This method informs the user that the port is now
+ * not in a ready (i.e. busy) state and can't be utilized to issue IOs.
+ * @controller: This parameter represents the controller which contains the
+ * port.
+ * @port: This parameter specifies the SCI port object for which the callback
+ * is being invoked.
+ *
+ */
+void scic_cb_port_not_ready(
+ struct scic_sds_controller *controller,
+ struct scic_sds_port *port,
+ u32 reason_code)
+{
+ struct isci_port *isci_port;
+ struct isci_host *isci_host;
+
+ isci_host =
+ (struct isci_host *)sci_object_get_association(controller);
+
+ isci_port =
+ (struct isci_port *)sci_object_get_association(port);
+
+ dev_dbg(&isci_host->pdev->dev,
+ "%s: isci_port = %p\n", __func__, isci_port);
+
+ isci_port_not_ready(isci_host, isci_port);
+}
+
+/**
+ * scic_cb_port_invalid_link_up() - This method informs the SCI Core user that
+ * a phy/link became ready, but the phy is not allowed in the port. In some
+ * situations the underlying hardware only allows for certain phy to port
+ * mappings. If these mappings are violated, then this API is invoked.
+ * @controller: This parameter represents the controller which contains the
+ * port.
+ * @port: This parameter specifies the SCI port object for which the callback
+ * is being invoked.
+ * @phy: This parameter specifies the phy that came ready, but the phy can't be
+ * a valid member of the port.
+ *
+ */
+void scic_cb_port_invalid_link_up(
+ struct scic_sds_controller *controller,
+ struct scic_sds_port *port,
+ struct scic_sds_phy *phy)
+{
+ pr_warn("%s:************************************************\n",
+ __func__);
+}
+
+/**
+ * scic_cb_port_bc_change_primitive_received() - This callback method informs
+ * the user that a broadcast change primitive was received.
+ * @controller: This parameter represents the controller which contains the
+ * port.
+ * @port: This parameter specifies the SCI port object for which the callback
+ * is being invoked. For instances where the phy on which the primitive was
+ * received is not part of a port, this parameter will be
+ * SCI_INVALID_HANDLE_T.
+ * @phy: This parameter specifies the phy on which the primitive was received.
+ *
+ */
+void scic_cb_port_bc_change_primitive_received(
+ struct scic_sds_controller *controller,
+ struct scic_sds_port *port,
+ struct scic_sds_phy *phy)
+{
+ struct isci_host *isci_host;
+
+ isci_host =
+ (struct isci_host *)sci_object_get_association(controller);
+
+ dev_dbg(&isci_host->pdev->dev,
+ "%s: port = %p, phy = %p\n", __func__, port, phy);
+ isci_port_bc_change_received(isci_host, port, phy);
+}
+
+
+
+
+/**
+ * scic_cb_port_link_up() - This callback method informs the user that a phy
+ * has become operational and is capable of communicating with the remote
+ * end point.
+ * @controller: This parameter represents the controller associated with the
+ * phy.
+ * @port: This parameter specifies the port object for which the user callback
+ * is being invoked. There may be conditions where this parameter can be
+ * SCI_INVALID_HANDLE
+ * @phy: This parameter specifies the phy object for which the user callback is
+ * being invoked.
+ *
+ * none.
+ */
+void scic_cb_port_link_up(
+ struct scic_sds_controller *controller,
+ struct scic_sds_port *port,
+ struct scic_sds_phy *phy)
+{
+ struct isci_host *isci_host;
+
+ isci_host =
+ (struct isci_host *)sci_object_get_association(controller);
+
+ dev_dbg(&isci_host->pdev->dev,
+ "%s: phy = %p\n", __func__, phy);
+
+ isci_port_link_up(isci_host, port, phy);
+}
+
+/**
+ * scic_cb_port_link_down() - This callback method informs the user that a phy
+ * is no longer operational and is not capable of communicating with the
+ * remote end point.
+ * @controller: This parameter represents the controller associated with the
+ * phy.
+ * @port: This parameter specifies the port object for which the user callback
+ * is being invoked. There may be conditions where this parameter can be
+ * SCI_INVALID_HANDLE
+ * @phy: This parameter specifies the phy object for which the user callback is
+ * being invoked.
+ *
+ * none.
+ */
+void scic_cb_port_link_down(
+ struct scic_sds_controller *controller,
+ struct scic_sds_port *port,
+ struct scic_sds_phy *phy)
+{
+ struct isci_host *isci_host;
+ struct isci_phy *isci_phy;
+ struct isci_port *isci_port;
+
+ isci_host =
+ (struct isci_host *)sci_object_get_association(controller);
+
+ isci_phy =
+ (struct isci_phy *)sci_object_get_association(phy);
+
+ isci_port =
+ (struct isci_port *)sci_object_get_association(port);
+
+ dev_dbg(&isci_host->pdev->dev,
+ "%s: isci_port = %p\n", __func__, isci_port);
+
+ isci_port_link_down(isci_host, isci_phy, isci_port);
+}
+
+/**
+ * scic_cb_remote_device_start_complete() - This user callback method will
+ * inform the user that a start operation has completed.
+ * @controller: This parameter specifies the core controller associated with
+ * the completion callback.
+ * @remote_device: This parameter specifies the remote device associated with
+ * the completion callback.
+ * @completion_status: This parameter specifies the completion status for the
+ * operation.
+ *
+ */
+void scic_cb_remote_device_start_complete(
+ struct scic_sds_controller *controller,
+ struct scic_sds_remote_device *remote_device,
+ enum sci_status completion_status)
+{
+ struct isci_host *isci_host;
+ struct isci_remote_device *isci_device;
+
+ isci_host =
+ (struct isci_host *)sci_object_get_association(controller);
+
+ isci_device =
+ (struct isci_remote_device *)sci_object_get_association(
+ remote_device
+ );
+
+ dev_dbg(&isci_host->pdev->dev,
+ "%s: isci_device = %p\n", __func__, isci_device);
+
+ isci_remote_device_start_complete(
+ isci_host, isci_device, completion_status);
+
+}
+
+/**
+ * scic_cb_remote_device_stop_complete() - This user callback method will
+ * inform the user that a stop operation has completed.
+ * @controller: This parameter specifies the core controller associated with
+ * the completion callback.
+ * @remote_device: This parameter specifies the remote device associated with
+ * the completion callback.
+ * @completion_status: This parameter specifies the completion status for the
+ * operation.
+ *
+ */
+void scic_cb_remote_device_stop_complete(
+ struct scic_sds_controller *controller,
+ struct scic_sds_remote_device *remote_device,
+ enum sci_status completion_status)
+{
+ struct isci_host *isci_host;
+ struct isci_remote_device *isci_device;
+
+ isci_host =
+ (struct isci_host *)sci_object_get_association(controller);
+
+ isci_device =
+ (struct isci_remote_device *)sci_object_get_association(
+ remote_device
+ );
+
+ dev_dbg(&isci_host->pdev->dev,
+ "%s: isci_device = %p\n", __func__, isci_device);
+
+ isci_remote_device_stop_complete(
+ isci_host, isci_device, completion_status);
+
+}
+
+/**
+ * scic_cb_remote_device_ready() - This user callback method will inform the
+ * user that a remote device is now capable of handling IO requests.
+ * @controller: This parameter specifies the core controller associated with
+ * the completion callback.
+ * @remote_device: This parameter specifies the remote device associated with
+ * the callback.
+ *
+ */
+void scic_cb_remote_device_ready(
+ struct scic_sds_controller *controller,
+ struct scic_sds_remote_device *remote_device)
+{
+ struct isci_remote_device *isci_device =
+ (struct isci_remote_device *)
+ sci_object_get_association(remote_device);
+
+ dev_dbg(&isci_device->isci_port->isci_host->pdev->dev,
+ "%s: isci_device = %p\n", __func__, isci_device);
+
+ isci_remote_device_ready(isci_device);
+}
+
+/**
+ * scic_cb_remote_device_not_ready() - This user callback method will inform
+ * the user that a remote device is no longer capable of handling IO
+ * requests (until a ready callback is invoked).
+ * @controller: This parameter specifies the core controller associated with
+ * the completion callback.
+ * @remote_device: This parameter specifies the remote device associated with
+ * the callback.
+ * @reason_code: This parameter specifies the reason for the remote device
+ * going to a not ready state.
+ *
+ */
+void scic_cb_remote_device_not_ready(
+ struct scic_sds_controller *controller,
+ struct scic_sds_remote_device *remote_device,
+ u32 reason_code)
+{
+ struct isci_remote_device *isci_device =
+ (struct isci_remote_device *)
+ sci_object_get_association(remote_device);
+
+ struct isci_host *isci_host;
+
+ isci_host =
+ (struct isci_host *)sci_object_get_association(controller);
+
+ dev_dbg(&isci_host->pdev->dev,
+ "%s: isci_device = %p, reason_code = %x\n",
+ __func__, isci_device, reason_code);
+
+ isci_remote_device_not_ready(isci_device, reason_code);
+}
+
+
diff --git a/drivers/scsi/isci/firmware/Makefile b/drivers/scsi/isci/firmware/Makefile
new file mode 100644
index 000000000000..5f54461cabc5
--- /dev/null
+++ b/drivers/scsi/isci/firmware/Makefile
@@ -0,0 +1,19 @@
+# Makefile for create_fw
+#
+CC=gcc
+CFLAGS=-c -Wall -O2 -g
+LDFLAGS=
+SOURCES=create_fw.c
+OBJECTS=$(SOURCES:.cpp=.o)
+EXECUTABLE=create_fw
+
+all: $(SOURCES) $(EXECUTABLE)
+
+$(EXECUTABLE): $(OBJECTS)
+ $(CC) $(LDFLAGS) $(OBJECTS) -o $@
+
+.c.o:
+ $(CC) $(CFLAGS) $< -O $@
+
+clean:
+ rm -f *.o $(EXECUTABLE)
diff --git a/drivers/scsi/isci/firmware/README b/drivers/scsi/isci/firmware/README
new file mode 100644
index 000000000000..cf7e4286e896
--- /dev/null
+++ b/drivers/scsi/isci/firmware/README
@@ -0,0 +1,36 @@
+This defines the temporary binary blow we are to pass to the SCU
+driver to emulate the binary firmware that we will eventually be
+able to access via NVRAM on the SCU controller.
+
+The current size of the binary blob is expected to be 149 bytes or larger
+
+Header Types:
+0x1: Phy Masks
+0x2: Phy Gens
+0x3: SAS Addrs
+0xff: End of Data
+
+ID string - u8[12]: "#SCU MAGIC#\0"
+Version - u8: 1
+SubVersion - u8: 0
+
+Header Type - u8: 0x1
+Size - u8: 8
+Phy Mask - u32[8]
+
+Header Type - u8: 0x2
+Size - u8: 8
+Phy Gen - u32[8]
+
+Header Type - u8: 0x3
+Size - u8: 8
+Sas Addr - u64[8]
+
+Header Type - u8: 0xf
+
+
+==============================================================================
+
+Place isci_firmware.bin in /lib/firmware
+Be sure to recreate the initramfs image to include the firmware.
+
diff --git a/drivers/scsi/isci/firmware/create_fw.c b/drivers/scsi/isci/firmware/create_fw.c
new file mode 100644
index 000000000000..442caac9675d
--- /dev/null
+++ b/drivers/scsi/isci/firmware/create_fw.c
@@ -0,0 +1,177 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <string.h>
+#include <errno.h>
+
+char blob_name[] = "isci_firmware.bin";
+char id[] = "#SCU MAGIC#";
+unsigned char version = 1;
+unsigned char sub_version = 0;
+
+
+/*
+ * For all defined arrays:
+ * elements 0-3 are for SCU0, ports 0-3
+ * elements 4-7 are for SCU1, ports 0-3
+ *
+ * valid configurations for one SCU are:
+ * P0 P1 P2 P3
+ * ----------------
+ * 0xF,0x0,0x0,0x0 # 1 x4 port
+ * 0x3,0x0,0x4,0x8 # Phys 0 and 1 are a x2 port, phy 2 and phy 3 are each x1
+ * # ports
+ * 0x1,0x2,0xC,0x0 # Phys 0 and 1 are each x1 ports, phy 2 and phy 3 are a x2
+ * # port
+ * 0x3,0x0,0xC,0x0 # Phys 0 and 1 are a x2 port, phy 2 and phy 3 are a x2 port
+ * 0x1,0x2,0x4,0x8 # Each phy is a x1 port (this is the default configuration)
+ *
+ * if there is a port/phy on which you do not wish to override the default
+ * values, use the value assigned to UNINIT_PARAM (255).
+ */
+unsigned int phy_mask[] = { 1, 2, 4, 8, 1, 2, 4, 8 };
+
+
+/* denotes SAS generation. i.e. 3: SAS Gen 3 6G */
+unsigned int phy_gen[] = { 3, 3, 3, 3, 3, 3, 3, 3 };
+
+/*
+ * if there is a port/phy on which you do not wish to override the default
+ * values, use the value "0000000000000000". SAS address of zero's is
+ * considered invalid and will not be used.
+ */
+unsigned long long sas_addr[] = { 0x5FCFFFFFF0000000ULL,
+ 0x5FCFFFFFF1000000ULL,
+ 0x5FCFFFFFF2000000ULL,
+ 0x5FCFFFFFF3000000ULL,
+ 0x5FCFFFFFF4000000ULL,
+ 0x5FCFFFFFF5000000ULL,
+ 0x5FCFFFFFF6000000ULL,
+ 0x5FCFFFFFF7000000ULL };
+
+int write_blob(void)
+{
+ FILE *fd;
+ int err;
+
+ fd = fopen(blob_name, "w+");
+ if (!fd) {
+ perror("Open file for write failed");
+ return -EIO;
+ }
+
+ /* write id */
+ err = fwrite((void *)id, sizeof(char), strlen(id)+1, fd);
+ if (err == 0) {
+ perror("write id failed");
+ return err;
+ }
+
+ /* write version */
+ err = fwrite((void *)&version, sizeof(version), 1, fd);
+ if (err == 0) {
+ perror("write version failed");
+ return err;
+ }
+
+ /* write sub version */
+ err = fwrite((void *)&sub_version, sizeof(sub_version), 1, fd);
+ if (err == 0) {
+ perror("write subversion failed");
+ return err;
+ }
+
+ /* write phy mask header */
+ err = fputc(0x1, fd);
+ if (err == EOF) {
+ perror("write phy mask header failed");
+ return -EIO;
+ }
+
+ /* write size */
+ err = fputc(8, fd);
+ if (err == EOF) {
+ perror("write phy mask size failed");
+ return -EIO;
+ }
+
+ /* write phy masks */
+ err = fwrite((void *)phy_mask, 1, sizeof(phy_mask), fd);
+ if (err == 0) {
+ perror("write phy_mask failed");
+ return err;
+ }
+
+ /* write phy gen header */
+ err = fputc(0x2, fd);
+ if (err == EOF) {
+ perror("write phy gen header failed");
+ return -EIO;
+ }
+
+ /* write size */
+ err = fputc(8, fd);
+ if (err == EOF) {
+ perror("write phy gen size failed");
+ return -EIO;
+ }
+
+ /* write phy_gen */
+ err = fwrite((void *)phy_gen,
+ 1,
+ sizeof(phy_gen),
+ fd);
+ if (err == 0) {
+ perror("write phy_gen failed");
+ return err;
+ }
+
+ /* write phy gen header */
+ err = fputc(0x3, fd);
+ if (err == EOF) {
+ perror("write sas addr header failed");
+ return -EIO;
+ }
+
+ /* write size */
+ err = fputc(8, fd);
+ if (err == EOF) {
+ perror("write sas addr size failed");
+ return -EIO;
+ }
+
+ /* write sas_addr */
+ err = fwrite((void *)sas_addr,
+ 1,
+ sizeof(sas_addr),
+ fd);
+ if (err == 0) {
+ perror("write sas_addr failed");
+ return err;
+ }
+
+ /* write end header */
+ err = fputc(0xff, fd);
+ if (err == EOF) {
+ perror("write end header failed");
+ return -EIO;
+ }
+
+ fclose(fd);
+
+ return 0;
+}
+
+int main(void)
+{
+ int err;
+
+ err = write_blob();
+ if (err < 0)
+ return err;
+
+ return 0;
+}
diff --git a/drivers/scsi/isci/host.c b/drivers/scsi/isci/host.c
new file mode 100644
index 000000000000..6f16f4d6c82b
--- /dev/null
+++ b/drivers/scsi/isci/host.c
@@ -0,0 +1,781 @@
+/*
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Intel Corporation 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
+ * OWNER 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.
+ */
+
+#include "isci.h"
+#include "scic_io_request.h"
+#include "scic_remote_device.h"
+#include "scic_port.h"
+
+#include "port.h"
+#include "request.h"
+#include "host.h"
+
+/**
+ * isci_isr() - This function is the interrupt service routine for the
+ * controller. It schedules the tasklet and returns.
+ * @vec: This parameter specifies the interrupt vector.
+ * @data: This parameter specifies the ISCI host object.
+ *
+ * IRQ_HANDLED if out interrupt otherwise, IRQ_NONE
+ */
+irqreturn_t isci_isr(int vec, void *data)
+{
+ struct isci_host *isci_host
+ = (struct isci_host *)data;
+ struct scic_controller_handler_methods *handlers
+ = &isci_host->scic_irq_handlers[SCI_MSIX_NORMAL_VECTOR];
+ irqreturn_t ret = IRQ_NONE;
+
+ if (isci_host_get_state(isci_host) != isci_starting
+ && handlers->interrupt_handler) {
+
+ if (handlers->interrupt_handler(isci_host->core_controller)) {
+ if (isci_host_get_state(isci_host) != isci_stopped) {
+ tasklet_schedule(
+ &isci_host->completion_tasklet);
+ } else
+ dev_dbg(&isci_host->pdev->dev,
+ "%s: controller stopped\n",
+ __func__);
+ ret = IRQ_HANDLED;
+ }
+ } else
+ dev_warn(&isci_host->pdev->dev,
+ "%s: get_handler_methods failed, "
+ "isci_host->status = 0x%x\n",
+ __func__,
+ isci_host_get_state(isci_host));
+
+ return ret;
+}
+
+irqreturn_t isci_legacy_isr(int vec, void *data)
+{
+ struct pci_dev *pdev = data;
+ struct isci_host *isci_host;
+ struct scic_controller_handler_methods *handlers;
+ irqreturn_t ret = IRQ_NONE;
+
+ /*
+ * Since this is a legacy interrupt, either or both
+ * controllers could have triggered it. Thus, we have to call
+ * the legacy interrupt handler for all controllers on the
+ * PCI function.
+ */
+ for_each_isci_host(isci_host, pdev) {
+ handlers = &isci_host->scic_irq_handlers[SCI_MSIX_NORMAL_VECTOR];
+
+ if (isci_host_get_state(isci_host) != isci_starting
+ && handlers->interrupt_handler) {
+
+ if (handlers->interrupt_handler(isci_host->core_controller)) {
+ if (isci_host_get_state(isci_host) != isci_stopped) {
+ tasklet_schedule(
+ &isci_host->completion_tasklet);
+ } else
+ dev_dbg(&isci_host->pdev->dev,
+ "%s: controller stopped\n",
+ __func__);
+ ret = IRQ_HANDLED;
+ }
+ } else
+ dev_warn(&isci_host->pdev->dev,
+ "%s: get_handler_methods failed, "
+ "isci_host->status = 0x%x\n",
+ __func__,
+ isci_host_get_state(isci_host));
+ }
+ return ret;
+}
+
+
+/**
+ * isci_host_start_complete() - This function is called by the core library,
+ * through the ISCI Module, to indicate controller start status.
+ * @isci_host: This parameter specifies the ISCI host object
+ * @completion_status: This parameter specifies the completion status from the
+ * core library.
+ *
+ */
+void isci_host_start_complete(
+ struct isci_host *isci_host,
+ enum sci_status completion_status)
+{
+ if (completion_status == SCI_SUCCESS) {
+ dev_dbg(&isci_host->pdev->dev,
+ "%s: completion_status: SCI_SUCCESS\n", __func__);
+ isci_host_change_state(isci_host, isci_ready);
+ complete_all(&isci_host->start_complete);
+ } else
+ dev_err(&isci_host->pdev->dev,
+ "controller start failed with "
+ "completion_status = 0x%x;",
+ completion_status);
+
+}
+
+
+
+/**
+ * isci_host_scan_finished() - This function is one of the SCSI Host Template
+ * functions. The SCSI midlayer calls this function during a target scan,
+ * approx. once every 10 millisecs.
+ * @shost: This parameter specifies the SCSI host being scanned
+ * @time: This parameter specifies the number of ticks since the scan started.
+ *
+ * scan status, zero indicates the SCSI midlayer should continue to poll,
+ * otherwise assume controller is ready.
+ */
+int isci_host_scan_finished(
+ struct Scsi_Host *shost,
+ unsigned long time)
+{
+ struct isci_host *isci_host
+ = isci_host_from_sas_ha(SHOST_TO_SAS_HA(shost));
+
+ struct scic_controller_handler_methods *handlers
+ = &isci_host->scic_irq_handlers[SCI_MSIX_NORMAL_VECTOR];
+
+ if (handlers->interrupt_handler == NULL) {
+ dev_err(&isci_host->pdev->dev,
+ "%s: scic_controller_get_handler_methods failed\n",
+ __func__);
+ return 1;
+ }
+
+ /**
+ * check interrupt_handler's status and call completion_handler if true,
+ * link_up events should be coming from the scu core lib, as phy's come
+ * online. for each link_up from the core, call
+ * get_received_identify_address_frame, copy the frame into the
+ * sas_phy object and call libsas notify_port_event(PORTE_BYTES_DMAED).
+ * continue to return zero from thee scan_finished routine until
+ * the scic_cb_controller_start_complete() call comes from the core.
+ **/
+ if (handlers->interrupt_handler(isci_host->core_controller))
+ handlers->completion_handler(isci_host->core_controller);
+
+ if (isci_starting == isci_host_get_state(isci_host)
+ && time < (HZ * 10)) {
+ dev_dbg(&isci_host->pdev->dev,
+ "%s: isci_host->status = %d, time = %ld\n",
+ __func__, isci_host_get_state(isci_host), time);
+ return 0;
+ }
+
+
+ dev_dbg(&isci_host->pdev->dev,
+ "%s: isci_host->status = %d, time = %ld\n",
+ __func__, isci_host_get_state(isci_host), time);
+
+ scic_controller_enable_interrupts(isci_host->core_controller);
+
+ return 1;
+
+}
+
+
+/**
+ * isci_host_scan_start() - This function is one of the SCSI Host Template
+ * function, called by the SCSI mid layer berfore a target scan begins. The
+ * core library controller start routine is called from here.
+ * @shost: This parameter specifies the SCSI host to be scanned
+ *
+ */
+void isci_host_scan_start(struct Scsi_Host *shost)
+{
+ struct isci_host *isci_host;
+
+ isci_host = isci_host_from_sas_ha(SHOST_TO_SAS_HA(shost));
+ isci_host_change_state(isci_host, isci_starting);
+
+ scic_controller_disable_interrupts(isci_host->core_controller);
+ init_completion(&isci_host->start_complete);
+ scic_controller_start(
+ isci_host->core_controller,
+ scic_controller_get_suggested_start_timeout(
+ isci_host->core_controller)
+ );
+}
+
+void isci_host_stop_complete(
+ struct isci_host *isci_host,
+ enum sci_status completion_status)
+{
+ isci_host_change_state(isci_host, isci_stopped);
+ scic_controller_disable_interrupts(
+ isci_host->core_controller
+ );
+ complete(&isci_host->stop_complete);
+}
+
+static struct coherent_memory_info *isci_host_alloc_mdl_struct(
+ struct isci_host *isci_host,
+ u32 size)
+{
+ struct coherent_memory_info *mdl_struct;
+ void *uncached_address = NULL;
+
+
+ mdl_struct = devm_kzalloc(&isci_host->pdev->dev,
+ sizeof(*mdl_struct),
+ GFP_KERNEL);
+ if (!mdl_struct)
+ return NULL;
+
+ INIT_LIST_HEAD(&mdl_struct->node);
+
+ uncached_address = dmam_alloc_coherent(&isci_host->pdev->dev,
+ size,
+ &mdl_struct->dma_handle,
+ GFP_KERNEL);
+ if (!uncached_address)
+ return NULL;
+
+ /* memset the whole memory area. */
+ memset((char *)uncached_address, 0, size);
+ mdl_struct->vaddr = uncached_address;
+ mdl_struct->size = (size_t)size;
+
+ return mdl_struct;
+}
+
+static void isci_host_build_mde(
+ struct sci_physical_memory_descriptor *mde_struct,
+ struct coherent_memory_info *mdl_struct)
+{
+ unsigned long address = 0;
+ dma_addr_t dma_addr = 0;
+
+ address = (unsigned long)mdl_struct->vaddr;
+ dma_addr = mdl_struct->dma_handle;
+
+ /* to satisfy the alignment. */
+ if ((address % mde_struct->constant_memory_alignment) != 0) {
+ int align_offset
+ = (mde_struct->constant_memory_alignment
+ - (address % mde_struct->constant_memory_alignment));
+ address += align_offset;
+ dma_addr += align_offset;
+ }
+
+ mde_struct->virtual_address = (void *)address;
+ mde_struct->physical_address = dma_addr;
+ mdl_struct->mde = mde_struct;
+}
+
+static int isci_host_mdl_allocate_coherent(
+ struct isci_host *isci_host)
+{
+ struct sci_physical_memory_descriptor *current_mde;
+ struct coherent_memory_info *mdl_struct;
+ u32 size = 0;
+
+ struct sci_base_memory_descriptor_list *mdl_handle
+ = sci_controller_get_memory_descriptor_list_handle(
+ isci_host->core_controller);
+
+ sci_mdl_first_entry(mdl_handle);
+
+ current_mde = sci_mdl_get_current_entry(mdl_handle);
+
+ while (current_mde != NULL) {
+
+ size = (current_mde->constant_memory_size
+ + current_mde->constant_memory_alignment);
+
+ mdl_struct = isci_host_alloc_mdl_struct(isci_host, size);
+ if (!mdl_struct)
+ return -ENOMEM;
+
+ list_add_tail(&mdl_struct->node, &isci_host->mdl_struct_list);
+
+ isci_host_build_mde(current_mde, mdl_struct);
+
+ sci_mdl_next_entry(mdl_handle);
+ current_mde = sci_mdl_get_current_entry(mdl_handle);
+ }
+
+ return 0;
+}
+
+
+/**
+ * isci_host_completion_routine() - This function is the delayed service
+ * routine that calls the sci core library's completion handler. It's
+ * scheduled as a tasklet from the interrupt service routine when interrupts
+ * in use, or set as the timeout function in polled mode.
+ * @data: This parameter specifies the ISCI host object
+ *
+ */
+static void isci_host_completion_routine(unsigned long data)
+{
+ struct isci_host *isci_host = (struct isci_host *)data;
+ struct scic_controller_handler_methods *handlers
+ = &isci_host->scic_irq_handlers[SCI_MSIX_NORMAL_VECTOR];
+ struct list_head completed_request_list;
+ struct list_head aborted_request_list;
+ struct list_head *current_position;
+ struct list_head *next_position;
+ struct isci_request *request;
+ struct isci_request *next_request;
+ struct sas_task *task;
+
+ INIT_LIST_HEAD(&completed_request_list);
+ INIT_LIST_HEAD(&aborted_request_list);
+
+ spin_lock_irq(&isci_host->scic_lock);
+
+ if (handlers->completion_handler) {
+ handlers->completion_handler(
+ isci_host->core_controller
+ );
+ }
+ /* Take the lists of completed I/Os from the host. */
+ list_splice_init(&isci_host->requests_to_complete,
+ &completed_request_list);
+
+ list_splice_init(&isci_host->requests_to_abort,
+ &aborted_request_list);
+
+ spin_unlock_irq(&isci_host->scic_lock);
+
+ /* Process any completions in the lists. */
+ list_for_each_safe(current_position, next_position,
+ &completed_request_list) {
+
+ request = list_entry(current_position, struct isci_request,
+ completed_node);
+ task = isci_request_access_task(request);
+
+ /* Normal notification (task_done) */
+ dev_dbg(&isci_host->pdev->dev,
+ "%s: Normal - request/task = %p/%p\n",
+ __func__,
+ request,
+ task);
+
+ task->task_done(task);
+ task->lldd_task = NULL;
+
+ /* Free the request object. */
+ isci_request_free(isci_host, request);
+ }
+ list_for_each_entry_safe(request, next_request, &aborted_request_list,
+ completed_node) {
+
+ task = isci_request_access_task(request);
+
+ /* Use sas_task_abort */
+ dev_warn(&isci_host->pdev->dev,
+ "%s: Error - request/task = %p/%p\n",
+ __func__,
+ request,
+ task);
+
+ /* Put the task into the abort path. */
+ sas_task_abort(task);
+ }
+
+}
+
+void isci_host_deinit(
+ struct isci_host *isci_host)
+{
+ int i;
+
+ isci_host_change_state(isci_host, isci_stopping);
+ for (i = 0; i < SCI_MAX_PORTS; i++) {
+ struct isci_port *port = &isci_host->isci_ports[i];
+ struct isci_remote_device *device, *tmpdev;
+ list_for_each_entry_safe(device, tmpdev,
+ &port->remote_dev_list, node) {
+ isci_remote_device_change_state(device, isci_stopping);
+ isci_remote_device_stop(device);
+ }
+ }
+
+ /* stop the comtroller and wait for completion. */
+ init_completion(&isci_host->stop_complete);
+ scic_controller_stop(
+ isci_host->core_controller,
+ SCIC_CONTROLLER_STOP_TIMEOUT
+ );
+ wait_for_completion(&isci_host->stop_complete);
+ /* next, reset the controller. */
+ scic_controller_reset(isci_host->core_controller);
+}
+
+static int isci_verify_firmware(const struct firmware *fw,
+ struct isci_firmware *isci_fw)
+{
+ const u8 *tmp;
+
+ if (fw->size < ISCI_FIRMWARE_MIN_SIZE)
+ return -EINVAL;
+
+ tmp = fw->data;
+
+ /* 12th char should be the NULL terminate for the ID string */
+ if (tmp[11] != '\0')
+ return -EINVAL;
+
+ if (strncmp("#SCU MAGIC#", tmp, 11) != 0)
+ return -EINVAL;
+
+ isci_fw->id = tmp;
+ isci_fw->version = fw->data[ISCI_FW_VER_OFS];
+ isci_fw->subversion = fw->data[ISCI_FW_SUBVER_OFS];
+
+ tmp = fw->data + ISCI_FW_DATA_OFS;
+
+ while (*tmp != ISCI_FW_HDR_EOF) {
+ switch (*tmp) {
+ case ISCI_FW_HDR_PHYMASK:
+ tmp++;
+ isci_fw->phy_masks_size = *tmp;
+ tmp++;
+ isci_fw->phy_masks = (const u32 *)tmp;
+ tmp += sizeof(u32) * isci_fw->phy_masks_size;
+ break;
+
+ case ISCI_FW_HDR_PHYGEN:
+ tmp++;
+ isci_fw->phy_gens_size = *tmp;
+ tmp++;
+ isci_fw->phy_gens = (const u32 *)tmp;
+ tmp += sizeof(u32) * isci_fw->phy_gens_size;
+ break;
+
+ case ISCI_FW_HDR_SASADDR:
+ tmp++;
+ isci_fw->sas_addrs_size = *tmp;
+ tmp++;
+ isci_fw->sas_addrs = (const u64 *)tmp;
+ tmp += sizeof(u64) * isci_fw->sas_addrs_size;
+ break;
+
+ default:
+ pr_err("bad field in firmware binary blob\n");
+ return -EINVAL;
+ }
+ }
+
+ pr_info("isci firmware v%u.%u loaded.\n",
+ isci_fw->version, isci_fw->subversion);
+
+ return SCI_SUCCESS;
+}
+
+static void __iomem *scu_base(struct isci_host *isci_host)
+{
+ struct pci_dev *pdev = isci_host->pdev;
+ int id = isci_host->id;
+
+ return pcim_iomap_table(pdev)[SCI_SCU_BAR * 2] + SCI_SCU_BAR_SIZE * id;
+}
+
+static void __iomem *smu_base(struct isci_host *isci_host)
+{
+ struct pci_dev *pdev = isci_host->pdev;
+ int id = isci_host->id;
+
+ return pcim_iomap_table(pdev)[SCI_SMU_BAR * 2] + SCI_SMU_BAR_SIZE * id;
+}
+
+#define SCI_MAX_TIMER_COUNT 25
+
+int isci_host_init(struct isci_host *isci_host)
+{
+ int err = 0;
+ int index = 0;
+ enum sci_status status;
+ struct scic_sds_controller *controller;
+ struct scic_sds_port *scic_port;
+ struct scic_controller_handler_methods *handlers
+ = &isci_host->scic_irq_handlers[0];
+ union scic_oem_parameters scic_oem_params;
+ union scic_user_parameters scic_user_params;
+ const struct firmware *fw = NULL;
+ struct isci_firmware *isci_fw = NULL;
+
+ INIT_LIST_HEAD(&isci_host->timer_list_struct.timers);
+ isci_timer_list_construct(
+ &isci_host->timer_list_struct,
+ SCI_MAX_TIMER_COUNT
+ );
+
+ controller = scic_controller_alloc(&isci_host->pdev->dev);
+
+ if (!controller) {
+ err = -ENOMEM;
+ dev_err(&isci_host->pdev->dev, "%s: failed (%d)\n", __func__, err);
+ goto out;
+ }
+
+ isci_host->core_controller = controller;
+ spin_lock_init(&isci_host->state_lock);
+ spin_lock_init(&isci_host->scic_lock);
+ spin_lock_init(&isci_host->queue_lock);
+
+ isci_host_change_state(isci_host, isci_starting);
+ isci_host->can_queue = ISCI_CAN_QUEUE_VAL;
+
+ status = scic_controller_construct(controller, scu_base(isci_host),
+ smu_base(isci_host));
+
+ if (status != SCI_SUCCESS) {
+ dev_err(&isci_host->pdev->dev,
+ "%s: scic_controller_construct failed - status = %x\n",
+ __func__,
+ status);
+ err = -ENODEV;
+ goto out;
+ }
+
+ isci_host->sas_ha.dev = &isci_host->pdev->dev;
+ isci_host->sas_ha.lldd_ha = isci_host;
+
+ /*----------- SCIC controller Initialization Stuff ------------------
+ * set association host adapter struct in core controller.
+ */
+ sci_object_set_association(isci_host->core_controller,
+ (void *)isci_host
+ );
+
+ /* grab initial values stored in the controller object for OEM and USER
+ * parameters */
+ scic_oem_parameters_get(controller, &scic_oem_params);
+ scic_user_parameters_get(controller, &scic_user_params);
+
+ isci_fw = devm_kzalloc(&isci_host->pdev->dev,
+ sizeof(struct isci_firmware),
+ GFP_KERNEL);
+ if (!isci_fw) {
+ dev_warn(&isci_host->pdev->dev,
+ "allocating firmware struct failed\n");
+ dev_warn(&isci_host->pdev->dev,
+ "Default OEM configuration being used:"
+ " 4 narrow ports, and default SAS Addresses\n");
+ goto set_default_params;
+ }
+
+ status = request_firmware(&fw, ISCI_FW_NAME, &isci_host->pdev->dev);
+ if (status) {
+ dev_warn(&isci_host->pdev->dev,
+ "Loading firmware failed, using default values\n");
+ dev_warn(&isci_host->pdev->dev,
+ "Default OEM configuration being used:"
+ " 4 narrow ports, and default SAS Addresses\n");
+ goto set_default_params;
+ }
+ else {
+ status = isci_verify_firmware(fw, isci_fw);
+ if (status != SCI_SUCCESS) {
+ dev_warn(&isci_host->pdev->dev,
+ "firmware verification failed\n");
+ dev_warn(&isci_host->pdev->dev,
+ "Default OEM configuration being used:"
+ " 4 narrow ports, and default SAS "
+ "Addresses\n");
+ goto set_default_params;
+ }
+
+ /* grab any OEM and USER parameters specified at module load */
+ status = isci_parse_oem_parameters(&scic_oem_params,
+ isci_host->id, isci_fw);
+ if (status != SCI_SUCCESS) {
+ dev_warn(&isci_host->pdev->dev,
+ "parsing firmware oem parameters failed\n");
+ err = -EINVAL;
+ goto out;
+ }
+
+ status = isci_parse_user_parameters(&scic_user_params,
+ isci_host->id, isci_fw);
+ if (status != SCI_SUCCESS) {
+ dev_warn(&isci_host->pdev->dev,
+ "%s: isci_parse_user_parameters"
+ " failed\n", __func__);
+ err = -EINVAL;
+ goto out;
+ }
+ }
+
+ set_default_params:
+
+ status = scic_oem_parameters_set(isci_host->core_controller,
+ &scic_oem_params
+ );
+
+ if (status != SCI_SUCCESS) {
+ dev_warn(&isci_host->pdev->dev,
+ "%s: scic_oem_parameters_set failed\n",
+ __func__);
+ err = -ENODEV;
+ goto out;
+ }
+
+
+ status = scic_user_parameters_set(isci_host->core_controller,
+ &scic_user_params
+ );
+
+ if (status != SCI_SUCCESS) {
+ dev_warn(&isci_host->pdev->dev,
+ "%s: scic_user_parameters_set failed\n",
+ __func__);
+ err = -ENODEV;
+ goto out;
+ }
+
+ status = scic_controller_initialize(isci_host->core_controller);
+ if (status != SCI_SUCCESS) {
+ dev_warn(&isci_host->pdev->dev,
+ "%s: scic_controller_initialize failed -"
+ " status = 0x%x\n",
+ __func__, status);
+ err = -ENODEV;
+ goto out;
+ }
+
+ /* @todo: use both MSI-X interrupts, and don't do indirect
+ * calls to the handlers just register direct calls
+ */
+ if (isci_host->pdev->msix_enabled) {
+ status = scic_controller_get_handler_methods(
+ SCIC_MSIX_INTERRUPT_TYPE,
+ SCI_MSIX_DOUBLE_VECTOR,
+ handlers
+ );
+ } else {
+ status = scic_controller_get_handler_methods(
+ SCIC_LEGACY_LINE_INTERRUPT_TYPE,
+ 0,
+ handlers
+ );
+ }
+
+ if (status != SCI_SUCCESS) {
+ handlers->interrupt_handler = NULL;
+ handlers->completion_handler = NULL;
+ dev_err(&isci_host->pdev->dev,
+ "%s: scic_controller_get_handler_methods failed\n",
+ __func__);
+ }
+
+ tasklet_init(&isci_host->completion_tasklet,
+ isci_host_completion_routine,
+ (unsigned long)isci_host
+ );
+
+ INIT_LIST_HEAD(&(isci_host->mdl_struct_list));
+
+ INIT_LIST_HEAD(&isci_host->requests_to_complete);
+ INIT_LIST_HEAD(&isci_host->requests_to_abort);
+
+ /* populate mdl with dma memory. scu_mdl_allocate_coherent() */
+ err = isci_host_mdl_allocate_coherent(isci_host);
+
+ if (err)
+ goto err_out;
+
+ /*
+ * keep the pool alloc size around, will use it for a bounds checking
+ * when trying to convert virtual addresses to physical addresses
+ */
+ isci_host->dma_pool_alloc_size = sizeof(struct isci_request) +
+ scic_io_request_get_object_size();
+ isci_host->dma_pool = dmam_pool_create(DRV_NAME, &isci_host->pdev->dev,
+ isci_host->dma_pool_alloc_size,
+ SLAB_HWCACHE_ALIGN, 0);
+
+ if (!isci_host->dma_pool) {
+ err = -ENOMEM;
+ goto req_obj_err_out;
+ }
+
+ for (index = 0; index < SCI_MAX_PORTS; index++) {
+ isci_port_init(&isci_host->isci_ports[index],
+ isci_host, index);
+ }
+
+ for (index = 0; index < SCI_MAX_PHYS; index++)
+ isci_phy_init(&isci_host->phys[index], isci_host, index);
+
+ /* Why are we doing this? Is this even necessary? */
+ memcpy(&isci_host->sas_addr[0], &isci_host->phys[0].sas_addr[0],
+ SAS_ADDR_SIZE);
+
+ /* Start the ports */
+ for (index = 0; index < SCI_MAX_PORTS; index++) {
+
+ scic_controller_get_port_handle(controller, index, &scic_port);
+ scic_port_start(scic_port);
+ }
+
+ goto out;
+
+/* SPB_Debug: destroy request object cache */
+ req_obj_err_out:
+/* SPB_Debug: destroy remote object cache */
+ err_out:
+/* SPB_Debug: undo controller init, construct and alloc, remove from parent
+ * controller list. */
+ out:
+ if (fw)
+ release_firmware(fw);
+ return err;
+}
diff --git a/drivers/scsi/isci/host.h b/drivers/scsi/isci/host.h
new file mode 100644
index 000000000000..3530076d6107
--- /dev/null
+++ b/drivers/scsi/isci/host.h
@@ -0,0 +1,283 @@
+/*
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Intel Corporation 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
+ * OWNER 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.
+ */
+
+/**
+ * This file contains the isci_module initialization routines.
+ *
+ * host.h
+ */
+
+
+
+#if !defined(_SCI_HOST_H_)
+#define _SCI_HOST_H_
+
+#include "phy.h"
+/*#include "task.h"*/
+#include "timers.h"
+#include "remote_device.h"
+#include "scic_user_callback.h"
+
+#define DRV_NAME "isci"
+#define SCI_PCI_BAR_COUNT 2
+#define SCI_NUM_MSI_X_INT 2
+#define SCI_SMU_BAR 0
+#define SCI_SMU_BAR_SIZE (16*1024)
+#define SCI_SCU_BAR 1
+#define SCI_SCU_BAR_SIZE (4*1024*1024)
+#define SCI_IO_SPACE_BAR0 2
+#define SCI_IO_SPACE_BAR1 3
+#define SCI_MSIX_NORMAL_VECTOR 0
+#define SCI_MSIX_ERROR_VECTOR 1
+#define SCI_MSIX_SINGLE_VECTOR 1
+#define SCI_MSIX_DOUBLE_VECTOR 2
+#define ISCI_CAN_QUEUE_VAL 250 /* < SCI_MAX_IO_REQUESTS ? */
+#define SCIC_CONTROLLER_STOP_TIMEOUT 5000
+
+struct coherent_memory_info {
+ struct list_head node;
+ dma_addr_t dma_handle;
+ void *vaddr;
+ size_t size;
+ struct sci_physical_memory_descriptor *mde;
+};
+
+struct isci_host {
+ struct scic_sds_controller *core_controller;
+ struct scic_controller_handler_methods scic_irq_handlers[SCI_NUM_MSI_X_INT];
+ union scic_oem_parameters oem_parameters;
+
+ int id; /* unique within a given pci device */
+ struct isci_timer_list timer_list_struct;
+ void *core_ctrl_memory;
+ struct dma_pool *dma_pool;
+ unsigned int dma_pool_alloc_size;
+ struct isci_phy phys[SCI_MAX_PHYS];
+
+ /* isci_ports and sas_ports are implicitly parallel to the
+ * ports maintained by the core
+ */
+ struct isci_port isci_ports[SCI_MAX_PORTS];
+ struct asd_sas_port sas_ports[SCI_MAX_PORTS];
+ struct sas_ha_struct sas_ha;
+
+ int can_queue;
+ spinlock_t queue_lock;
+ spinlock_t state_lock;
+
+ struct pci_dev *pdev;
+ u8 sas_addr[SAS_ADDR_SIZE];
+
+ enum isci_status status;
+ struct Scsi_Host *shost;
+ struct tasklet_struct completion_tasklet;
+ struct list_head mdl_struct_list;
+ struct list_head requests_to_complete;
+ struct list_head requests_to_abort;
+ struct completion stop_complete;
+ struct completion start_complete;
+ spinlock_t scic_lock;
+ struct isci_host *next;
+};
+
+
+/**
+ * struct isci_pci_info - This class represents the pci function containing the
+ * controllers. Depending on PCI SKU, there could be up to 2 controllers in
+ * the PCI function.
+ */
+#define SCI_MAX_MSIX_INT (SCI_NUM_MSI_X_INT*SCI_MAX_CONTROLLERS)
+
+struct isci_pci_info {
+ struct msix_entry msix_entries[SCI_MAX_MSIX_INT];
+ int core_lib_array_index;
+ SCI_LIBRARY_HANDLE_T core_lib_handle;
+ struct isci_host *hosts;
+};
+
+static inline struct isci_pci_info *to_pci_info(struct pci_dev *pdev)
+{
+ return pci_get_drvdata(pdev);
+}
+
+#define for_each_isci_host(isci_host, pdev) \
+ for (isci_host = to_pci_info(pdev)->hosts;\
+ isci_host; isci_host = isci_host->next)
+
+static inline
+enum isci_status isci_host_get_state(
+ struct isci_host *isci_host)
+{
+ return isci_host->status;
+}
+
+
+static inline void isci_host_change_state(
+ struct isci_host *isci_host,
+ enum isci_status status)
+{
+ unsigned long flags;
+
+ dev_dbg(&isci_host->pdev->dev,
+ "%s: isci_host = %p, state = 0x%x",
+ __func__,
+ isci_host,
+ status);
+ spin_lock_irqsave(&isci_host->state_lock, flags);
+ isci_host->status = status;
+ spin_unlock_irqrestore(&isci_host->state_lock, flags);
+
+}
+
+static inline int isci_host_can_queue(
+ struct isci_host *isci_host,
+ int num)
+{
+ int ret = 0;
+ unsigned long flags;
+
+ spin_lock_irqsave(&isci_host->queue_lock, flags);
+ if ((isci_host->can_queue - num) < 0) {
+ dev_dbg(&isci_host->pdev->dev,
+ "%s: isci_host->can_queue = %d\n",
+ __func__,
+ isci_host->can_queue);
+ ret = -SAS_QUEUE_FULL;
+
+ } else
+ isci_host->can_queue -= num;
+
+ spin_unlock_irqrestore(&isci_host->queue_lock, flags);
+
+ return ret;
+}
+
+static inline void isci_host_can_dequeue(
+ struct isci_host *isci_host,
+ int num)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&isci_host->queue_lock, flags);
+ isci_host->can_queue += num;
+ spin_unlock_irqrestore(&isci_host->queue_lock, flags);
+}
+
+/**
+ * isci_host_from_sas_ha() - This accessor retrieves the isci_host object
+ * reference from the Linux sas_ha_struct reference.
+ * @ha_struct,: This parameter points to the Linux sas_ha_struct object
+ *
+ * A reference to the associated isci_host structure.
+ */
+#define isci_host_from_sas_ha(ha_struct) \
+ ((struct isci_host *)(ha_struct)->lldd_ha)
+
+/**
+ * isci_host_scan_finished() -
+ *
+ * This function is one of the SCSI Host Template functions. The SCSI midlayer
+ * calls this function during a target scan, approx. once every 10 millisecs.
+ */
+int isci_host_scan_finished(
+ struct Scsi_Host *,
+ unsigned long);
+
+
+/**
+ * isci_host_scan_start() -
+ *
+ * This function is one of the SCSI Host Template function, called by the SCSI
+ * mid layer berfore a target scan begins. The core library controller start
+ * routine is called from here.
+ */
+void isci_host_scan_start(
+ struct Scsi_Host *);
+
+/**
+ * isci_host_start_complete() -
+ *
+ * This function is called by the core library, through the ISCI Module, to
+ * indicate controller start status.
+ */
+void isci_host_start_complete(
+ struct isci_host *,
+ enum sci_status);
+
+void isci_host_stop_complete(
+ struct isci_host *isci_host,
+ enum sci_status completion_status);
+
+int isci_host_init(struct isci_host *);
+
+void isci_host_init_controller_names(
+ struct isci_host *isci_host,
+ unsigned int controller_idx);
+
+void isci_host_deinit(
+ struct isci_host *);
+
+void isci_host_port_link_up(
+ struct isci_host *,
+ struct scic_sds_port *,
+ struct scic_sds_phy *);
+int isci_host_dev_found(struct domain_device *);
+
+void isci_host_remote_device_start_complete(
+ struct isci_host *,
+ struct isci_remote_device *,
+ enum sci_status);
+
+#endif /* !defined(_SCI_HOST_H_) */
diff --git a/drivers/scsi/isci/init.c b/drivers/scsi/isci/init.c
new file mode 100644
index 000000000000..07b072f3004d
--- /dev/null
+++ b/drivers/scsi/isci/init.c
@@ -0,0 +1,613 @@
+/*
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Intel Corporation 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
+ * OWNER 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.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <asm/string.h>
+#include "isci.h"
+#include "task.h"
+#include "sci_controller_constants.h"
+#include "scic_remote_device.h"
+#include "sci_environment.h"
+
+static struct scsi_transport_template *isci_transport_template;
+struct kmem_cache *isci_kmem_cache;
+
+static DEFINE_PCI_DEVICE_TABLE(isci_id_table) = {
+ { PCI_VDEVICE(INTEL, 0x1D61),},
+ { PCI_VDEVICE(INTEL, 0x1D63),},
+ { PCI_VDEVICE(INTEL, 0x1D65),},
+ { PCI_VDEVICE(INTEL, 0x1D67),},
+ { PCI_VDEVICE(INTEL, 0x1D69),},
+ { PCI_VDEVICE(INTEL, 0x1D6B),},
+ { PCI_VDEVICE(INTEL, 0x1D60),},
+ { PCI_VDEVICE(INTEL, 0x1D62),},
+ { PCI_VDEVICE(INTEL, 0x1D64),},
+ { PCI_VDEVICE(INTEL, 0x1D66),},
+ { PCI_VDEVICE(INTEL, 0x1D68),},
+ { PCI_VDEVICE(INTEL, 0x1D6A),},
+ {}
+};
+
+static int __devinit isci_pci_probe(
+ struct pci_dev *pdev,
+ const struct pci_device_id *device_id_p);
+
+static void __devexit isci_pci_remove(struct pci_dev *pdev);
+
+MODULE_DEVICE_TABLE(pci, isci_id_table);
+
+static struct pci_driver isci_pci_driver = {
+ .name = DRV_NAME,
+ .id_table = isci_id_table,
+ .probe = isci_pci_probe,
+ .remove = __devexit_p(isci_pci_remove),
+};
+
+/* linux isci specific settings */
+int loglevel = 3;
+module_param(loglevel, int, S_IRUGO | S_IWUSR);
+
+#if defined(CONFIG_PBG_HBA_A0)
+int isci_si_rev = ISCI_SI_REVA0;
+#elif defined(CONFIG_PBG_HBA_A2)
+int isci_si_rev = ISCI_SI_REVA2;
+#else
+int isci_si_rev = ISCI_SI_REVB0;
+#endif
+module_param(isci_si_rev, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(isci_si_rev, "override default si rev (0: A0 1: A2 2: B0)");
+
+static struct scsi_host_template isci_sht = {
+
+ .module = THIS_MODULE,
+ .name = DRV_NAME,
+ .queuecommand = sas_queuecommand,
+ .target_alloc = sas_target_alloc,
+ .slave_configure = sas_slave_configure,
+ .slave_destroy = sas_slave_destroy,
+ .scan_finished = isci_host_scan_finished,
+ .scan_start = isci_host_scan_start,
+ .change_queue_depth = sas_change_queue_depth,
+ .change_queue_type = sas_change_queue_type,
+ .bios_param = sas_bios_param,
+ .can_queue = ISCI_CAN_QUEUE_VAL,
+ .cmd_per_lun = 1,
+ .this_id = -1,
+ .sg_tablesize = SG_ALL,
+ .max_sectors = SCSI_DEFAULT_MAX_SECTORS,
+ .use_clustering = ENABLE_CLUSTERING,
+ .eh_device_reset_handler = sas_eh_device_reset_handler,
+ .eh_bus_reset_handler = isci_bus_reset_handler,
+ .slave_alloc = sas_slave_alloc,
+ .target_destroy = sas_target_destroy,
+ .ioctl = sas_ioctl,
+};
+
+static struct sas_domain_function_template isci_transport_ops = {
+
+ /* The class calls these to notify the LLDD of an event. */
+ .lldd_port_formed = isci_port_formed,
+ .lldd_port_deformed = isci_port_deformed,
+
+ /* The class calls these when a device is found or gone. */
+ .lldd_dev_found = isci_remote_device_found,
+ .lldd_dev_gone = isci_remote_device_gone,
+
+ .lldd_execute_task = isci_task_execute_task,
+ /* Task Management Functions. Must be called from process context. */
+ .lldd_abort_task = isci_task_abort_task,
+ .lldd_abort_task_set = isci_task_abort_task_set,
+ .lldd_clear_aca = isci_task_clear_aca,
+ .lldd_clear_task_set = isci_task_clear_task_set,
+ .lldd_I_T_nexus_reset = isci_task_I_T_nexus_reset,
+ .lldd_lu_reset = isci_task_lu_reset,
+ .lldd_query_task = isci_task_query_task,
+
+ /* Port and Adapter management */
+ .lldd_clear_nexus_port = isci_task_clear_nexus_port,
+ .lldd_clear_nexus_ha = isci_task_clear_nexus_ha,
+
+ /* Phy management */
+ .lldd_control_phy = isci_phy_control,
+};
+
+
+/******************************************************************************
+* P R O T E C T E D M E T H O D S
+******************************************************************************/
+
+
+
+/**
+ * isci_register_sas_ha() - This method initializes various lldd
+ * specific members of the sas_ha struct and calls the libsas
+ * sas_register_ha() function.
+ * @isci_host: This parameter specifies the lldd specific wrapper for the
+ * libsas sas_ha struct.
+ *
+ * This method returns an error code indicating sucess or failure. The user
+ * should check for possible memory allocation error return otherwise, a zero
+ * indicates success.
+ */
+static int isci_register_sas_ha(struct isci_host *isci_host)
+{
+ int i;
+ struct sas_ha_struct *sas_ha = &(isci_host->sas_ha);
+ struct asd_sas_phy **sas_phys;
+ struct asd_sas_port **sas_ports;
+
+ sas_phys = devm_kzalloc(&isci_host->pdev->dev,
+ SCI_MAX_PHYS * sizeof(void *),
+ GFP_KERNEL);
+ if (!sas_phys)
+ return -ENOMEM;
+
+ sas_ports = devm_kzalloc(&isci_host->pdev->dev,
+ SCI_MAX_PORTS * sizeof(void *),
+ GFP_KERNEL);
+ if (!sas_ports)
+ return -ENOMEM;
+
+ /*----------------- Libsas Initialization Stuff----------------------
+ * Set various fields in the sas_ha struct:
+ */
+
+ sas_ha->sas_ha_name = DRV_NAME;
+ sas_ha->lldd_module = THIS_MODULE;
+ sas_ha->sas_addr = &(isci_host->sas_addr[0]);
+
+ /* set the array of phy and port structs. */
+ for (i = 0; i < SCI_MAX_PHYS; i++) {
+ sas_phys[i] = &(isci_host->phys[i].sas_phy);
+ sas_ports[i] = &(isci_host->sas_ports[i]);
+ }
+
+ sas_ha->sas_phy = sas_phys;
+ sas_ha->sas_port = sas_ports;
+ sas_ha->num_phys = SCI_MAX_PHYS;
+
+ sas_ha->lldd_queue_size = ISCI_CAN_QUEUE_VAL;
+ sas_ha->lldd_max_execute_num = 1;
+ sas_ha->strict_wide_ports = 1;
+
+ sas_register_ha(sas_ha);
+
+ return 0;
+}
+
+static void isci_unregister_sas_ha(struct isci_host *isci_host)
+{
+ if (!isci_host)
+ return;
+
+ sas_unregister_ha(&(isci_host->sas_ha));
+
+ sas_remove_host(isci_host->shost);
+ scsi_remove_host(isci_host->shost);
+ scsi_host_put(isci_host->shost);
+}
+
+static int __devinit isci_pci_init(struct pci_dev *pdev)
+{
+ int err, bar_num, bar_mask;
+ void __iomem * const *iomap;
+
+ err = pcim_enable_device(pdev);
+ if (err) {
+ dev_err(&pdev->dev,
+ "failed enable PCI device %s!\n",
+ pci_name(pdev));
+ return err;
+ }
+
+ for (bar_num = 0; bar_num < SCI_PCI_BAR_COUNT; bar_num++)
+ bar_mask |= 1 << (bar_num * 2);
+
+ err = pcim_iomap_regions(pdev, bar_mask, DRV_NAME);
+ if (err)
+ return err;
+
+ iomap = pcim_iomap_table(pdev);
+ if (!iomap)
+ return -ENOMEM;
+
+ pci_set_master(pdev);
+
+ err = pci_set_dma_mask(pdev, DMA_BIT_MASK(64));
+ if (err) {
+ err = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
+ if (err)
+ return err;
+ }
+
+ err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64));
+ if (err) {
+ err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32));
+ if (err)
+ return err;
+ }
+
+ return 0;
+}
+
+static struct isci_host *isci_host_by_id(struct pci_dev *pdev, int id)
+{
+ struct isci_host *h;
+
+ for_each_isci_host(h, pdev)
+ if (h->id == id)
+ return h;
+ return NULL;
+}
+
+static int num_controllers(struct pci_dev *pdev)
+{
+ /* bar size alone can tell us if we are running with a dual controller
+ * part, no need to trust revision ids that might be under broken firmware
+ * control
+ */
+ resource_size_t scu_bar_size = pci_resource_len(pdev, SCI_SCU_BAR*2);
+ resource_size_t smu_bar_size = pci_resource_len(pdev, SCI_SMU_BAR*2);
+
+ if (scu_bar_size >= SCI_SCU_BAR_SIZE*SCI_MAX_CONTROLLERS &&
+ smu_bar_size >= SCI_SMU_BAR_SIZE*SCI_MAX_CONTROLLERS)
+ return SCI_MAX_CONTROLLERS;
+ else
+ return 1;
+}
+
+static int isci_setup_interrupts(struct pci_dev *pdev)
+{
+ int err, i, num_msix;
+ struct isci_pci_info *pci_info = to_pci_info(pdev);
+
+ /*
+ * Determine the number of vectors associated with this
+ * PCI function.
+ */
+ num_msix = num_controllers(pdev) * SCI_NUM_MSI_X_INT;
+
+ for (i = 0; i < num_msix; i++)
+ pci_info->msix_entries[i].entry = i;
+
+ err = pci_enable_msix(pdev, pci_info->msix_entries, num_msix);
+ if (err)
+ goto intx;
+
+ for (i = 0; i < num_msix; i++) {
+ int id = i / SCI_NUM_MSI_X_INT;
+ struct msix_entry *msix = &pci_info->msix_entries[i];
+ struct isci_host *isci_host = isci_host_by_id(pdev, id);
+
+ BUG_ON(!isci_host);
+
+ /* @todo: need to handle error case. */
+ err = devm_request_irq(&pdev->dev, msix->vector, isci_isr, 0,
+ DRV_NAME"-msix", isci_host);
+ if (!err)
+ continue;
+
+ dev_info(&pdev->dev, "msix setup failed falling back to intx\n");
+ while (i--) {
+ id = i / SCI_NUM_MSI_X_INT;
+ isci_host = isci_host_by_id(pdev, id);
+ msix = &pci_info->msix_entries[i];
+ devm_free_irq(&pdev->dev, msix->vector, isci_host);
+ }
+ pci_disable_msix(pdev);
+ goto intx;
+ }
+
+ return 0;
+
+ intx:
+ err = devm_request_irq(&pdev->dev, pdev->irq, isci_legacy_isr,
+ IRQF_SHARED, DRV_NAME"-intx", pdev);
+
+ return err;
+}
+
+/**
+ * isci_parse_oem_parameters() - This method will take OEM parameters
+ * from the module init parameters and copy them to oem_params. This will
+ * only copy values that are not set to the module parameter default values
+ * @oem_parameters: This parameter specifies the controller default OEM
+ * parameters. It is expected that this has been initialized to the default
+ * parameters for the controller
+ *
+ *
+ */
+enum sci_status isci_parse_oem_parameters(union scic_oem_parameters *oem_params,
+ int scu_index,
+ struct isci_firmware *fw)
+{
+ int i;
+
+ /* check for valid inputs */
+ if (!(scu_index >= 0
+ && scu_index < SCI_MAX_CONTROLLERS
+ && oem_params != NULL)) {
+ return SCI_FAILURE;
+ }
+
+ for (i = 0; i < SCI_MAX_PHYS; i++) {
+ int array_idx = i + (SCI_MAX_PHYS * scu_index);
+ u64 sas_addr = fw->sas_addrs[array_idx];
+
+ if (sas_addr != 0) {
+ oem_params->sds1.phys[i].sas_address.low =
+ (u32)(sas_addr & 0xffffffff);
+ oem_params->sds1.phys[i].sas_address.high =
+ (u32)((sas_addr >> 32) & 0xffffffff);
+ }
+ }
+
+ for (i = 0; i < SCI_MAX_PORTS; i++) {
+ int array_idx = i + (SCI_MAX_PORTS * scu_index);
+ u32 pmask = fw->phy_masks[array_idx];
+
+ oem_params->sds1.ports[i].phy_mask = pmask;
+ }
+
+ return SCI_SUCCESS;
+}
+
+/**
+ * isci_parse_user_parameters() - This method will take user parameters
+ * from the module init parameters and copy them to user_params. This will
+ * only copy values that are not set to the module parameter default values
+ * @user_parameters: This parameter specifies the controller default user
+ * parameters. It is expected that this has been initialized to the default
+ * parameters for the controller
+ *
+ *
+ */
+enum sci_status isci_parse_user_parameters(
+ union scic_user_parameters *user_params,
+ int scu_index,
+ struct isci_firmware *fw)
+{
+ int i;
+
+ if (!(scu_index >= 0
+ && scu_index < SCI_MAX_CONTROLLERS
+ && user_params != NULL)) {
+ return SCI_FAILURE;
+ }
+
+ for (i = 0; i < SCI_MAX_PORTS; i++) {
+ int array_idx = i + (SCI_MAX_PORTS * scu_index);
+ u32 gen = fw->phy_gens[array_idx];
+
+ user_params->sds1.phys[i].max_speed_generation = gen;
+
+ }
+
+ return SCI_SUCCESS;
+}
+
+static struct isci_host *isci_host_alloc(struct pci_dev *pdev, int id)
+{
+ struct isci_host *isci_host;
+ struct Scsi_Host *shost;
+ int err;
+
+ isci_host = devm_kzalloc(&pdev->dev, sizeof(*isci_host), GFP_KERNEL);
+ if (!isci_host)
+ return NULL;
+
+ isci_host->pdev = pdev;
+ isci_host->id = id;
+
+ shost = scsi_host_alloc(&isci_sht, sizeof(void *));
+ if (!shost)
+ return NULL;
+ isci_host->shost = shost;
+
+ err = isci_host_init(isci_host);
+ if (err)
+ goto err_shost;
+
+ SHOST_TO_SAS_HA(shost) = &isci_host->sas_ha;
+ isci_host->sas_ha.core.shost = shost;
+ shost->transportt = isci_transport_template;
+
+ shost->max_id = ~0;
+ shost->max_lun = ~0;
+ shost->max_cmd_len = MAX_COMMAND_SIZE;
+
+ err = scsi_add_host(shost, &pdev->dev);
+ if (err)
+ goto err_shost;
+
+ err = isci_register_sas_ha(isci_host);
+ if (err)
+ goto err_shost_remove;
+
+ return isci_host;
+
+ err_shost_remove:
+ scsi_remove_host(shost);
+ err_shost:
+ scsi_host_put(shost);
+
+ return NULL;
+}
+
+static void check_si_rev(struct pci_dev *pdev)
+{
+ if (num_controllers(pdev) > 1)
+ isci_si_rev = ISCI_SI_REVB0;
+ else {
+ switch (pdev->revision) {
+ case 0:
+ case 1:
+ /* if the id is ambiguous don't update isci_si_rev */
+ break;
+ case 3:
+ isci_si_rev = ISCI_SI_REVA2;
+ break;
+ default:
+ case 4:
+ isci_si_rev = ISCI_SI_REVB0;
+ break;
+ }
+ }
+
+ dev_info(&pdev->dev, "driver configured for %s silicon (rev: %d)\n",
+ isci_si_rev == ISCI_SI_REVA0 ? "A0" :
+ isci_si_rev == ISCI_SI_REVA2 ? "A2" : "B0", pdev->revision);
+
+}
+
+static int __devinit isci_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
+{
+ struct isci_pci_info *pci_info;
+ int err, i;
+ struct isci_host *isci_host;
+
+ check_si_rev(pdev);
+
+ pci_info = devm_kzalloc(&pdev->dev, sizeof(*pci_info), GFP_KERNEL);
+ if (!pci_info)
+ return -ENOMEM;
+ pci_set_drvdata(pdev, pci_info);
+
+ err = isci_pci_init(pdev);
+ if (err)
+ return err;
+
+ for (i = 0; i < num_controllers(pdev); i++) {
+ struct isci_host *h = isci_host_alloc(pdev, i);
+
+ if (!h) {
+ err = -ENOMEM;
+ goto err_host_alloc;
+ }
+
+ h->next = pci_info->hosts;
+ pci_info->hosts = h;
+ }
+
+ err = isci_setup_interrupts(pdev);
+ if (err)
+ goto err_host_alloc;
+
+ for_each_isci_host(isci_host, pdev)
+ scsi_scan_host(isci_host->shost);
+
+ return 0;
+
+ err_host_alloc:
+ for_each_isci_host(isci_host, pdev)
+ isci_unregister_sas_ha(isci_host);
+ return err;
+}
+
+static void __devexit isci_pci_remove(struct pci_dev *pdev)
+{
+ struct isci_host *isci_host;
+
+ for_each_isci_host(isci_host, pdev) {
+ isci_unregister_sas_ha(isci_host);
+ isci_host_deinit(isci_host);
+ scic_controller_disable_interrupts(isci_host->core_controller);
+ }
+}
+
+static __init int isci_init(void)
+{
+ int err = -ENOMEM;
+
+ pr_info("%s: Intel(R) C600 SAS Controller Driver\n", DRV_NAME);
+
+ isci_kmem_cache = kmem_cache_create(DRV_NAME,
+ sizeof(struct isci_remote_device) +
+ scic_remote_device_get_object_size(),
+ 0, 0, NULL);
+ if (!isci_kmem_cache)
+ return err;
+
+ isci_transport_template = sas_domain_attach_transport(&isci_transport_ops);
+ if (!isci_transport_template)
+ goto err_kmem;
+
+ err = pci_register_driver(&isci_pci_driver);
+ if (err)
+ goto err_sas;
+
+ return 0;
+
+ err_sas:
+ sas_release_transport(isci_transport_template);
+ err_kmem:
+ kmem_cache_destroy(isci_kmem_cache);
+
+ return err;
+}
+
+static __exit void isci_exit(void)
+{
+ pci_unregister_driver(&isci_pci_driver);
+ sas_release_transport(isci_transport_template);
+ kmem_cache_destroy(isci_kmem_cache);
+}
+
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_FIRMWARE(ISCI_FW_NAME);
+module_init(isci_init);
+module_exit(isci_exit);
diff --git a/drivers/scsi/isci/isci.h b/drivers/scsi/isci/isci.h
new file mode 100644
index 000000000000..7d984f408f24
--- /dev/null
+++ b/drivers/scsi/isci/isci.h
@@ -0,0 +1,138 @@
+/*
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Intel Corporation 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
+ * OWNER 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.
+ */
+
+/**
+ * This file contains the isci_module object definition.
+ *
+ * isci.h
+ */
+
+#if !defined(_SCI_MODULE_H_)
+#define _SCI_MODULE_H_
+
+/**
+ * This file contains the SCI low level driver interface to the SCI and Libsas
+ * Libraries.
+ *
+ * isci.h
+ */
+
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/types.h>
+#include <linux/spinlock.h>
+#include <linux/interrupt.h>
+#include <linux/firmware.h>
+#include <linux/bug.h>
+#include <scsi/libsas.h>
+#include <scsi/scsi.h>
+
+#include "sci_types.h"
+#include "sci_base_controller.h"
+#include "scic_controller.h"
+#include "host.h"
+#include "timers.h"
+#include "sci_status.h"
+
+extern int loglevel;
+extern struct kmem_cache *isci_kmem_cache;
+
+#define ISCI_FW_NAME "isci/isci_firmware.bin"
+
+#define ISCI_FIRMWARE_MIN_SIZE 149
+
+#define ISCI_FW_IDSIZE 12
+#define ISCI_FW_VER_OFS ISCI_FW_IDSIZE
+#define ISCI_FW_SUBVER_OFS ISCI_FW_VER_OFS + 1
+#define ISCI_FW_DATA_OFS ISCI_FW_SUBVER_OFS + 1
+
+#define ISCI_FW_HDR_PHYMASK 0x1
+#define ISCI_FW_HDR_PHYGEN 0x2
+#define ISCI_FW_HDR_SASADDR 0x3
+#define ISCI_FW_HDR_EOF 0xff
+
+struct isci_firmware {
+ const u8 *id;
+ u8 version;
+ u8 subversion;
+ const u32 *phy_masks;
+ u8 phy_masks_size;
+ const u32 *phy_gens;
+ u8 phy_gens_size;
+ const u64 *sas_addrs;
+ u8 sas_addrs_size;
+};
+
+irqreturn_t isci_isr(int vec, void *data);
+irqreturn_t isci_legacy_isr(int vec, void *data);
+
+enum sci_status isci_parse_oem_parameters(
+ union scic_oem_parameters *oem_params,
+ int scu_index,
+ struct isci_firmware *fw);
+
+enum sci_status isci_parse_user_parameters(
+ union scic_user_parameters *user_params,
+ int scu_index,
+ struct isci_firmware *fw);
+
+#ifdef ISCI_SLAVE_ALLOC
+extern int ISCI_SLAVE_ALLOC(struct scsi_device *scsi_dev);
+#endif /* ISCI_SLAVE_ALLOC */
+
+#ifdef ISCI_SLAVE_DESTROY
+extern void ISCI_SLAVE_DESTROY(struct scsi_device *scsi_dev);
+#endif /* ISCI_SLAVE_DESTROY */
+#endif /* !defined(_SCI_MODULE_H_) */
diff --git a/drivers/scsi/isci/phy.c b/drivers/scsi/isci/phy.c
new file mode 100644
index 000000000000..fbda570d25e1
--- /dev/null
+++ b/drivers/scsi/isci/phy.c
@@ -0,0 +1,179 @@
+/*
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Intel Corporation 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
+ * OWNER 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.
+ */
+
+#include "isci.h"
+#include "phy.h"
+#include "scic_port.h"
+#include "scic_config_parameters.h"
+
+
+/**
+ * isci_phy_init() - This function is called by the probe function to
+ * initialize the phy objects. This func assumes that the isci_port objects
+ * associated with the SCU have been initialized.
+ * @isci_phy: This parameter specifies the isci_phy object to initialize
+ * @isci_host: This parameter specifies the parent SCU host object for this
+ * isci_phy
+ * @index: This parameter specifies which SCU phy associates with this
+ * isci_phy. Generally, SCU phy 0 relates isci_phy 0, etc.
+ *
+ */
+void isci_phy_init(
+ struct isci_phy *phy,
+ struct isci_host *isci_host,
+ int index)
+{
+ struct scic_sds_controller *controller = isci_host->core_controller;
+ struct scic_sds_phy *scic_phy;
+ union scic_oem_parameters oem_parameters;
+ enum sci_status status = SCI_SUCCESS;
+
+ /*--------------- SCU_Phy Initialization Stuff -----------------------*/
+
+ status = scic_controller_get_phy_handle(controller, index, &scic_phy);
+ if (status == SCI_SUCCESS) {
+ sci_object_set_association(scic_phy, (void *)phy);
+ phy->sci_phy_handle = scic_phy;
+ } else
+ dev_err(&isci_host->pdev->dev,
+ "failed scic_controller_get_phy_handle\n");
+
+ scic_oem_parameters_get(controller, &oem_parameters);
+
+ phy->sas_addr[0] = oem_parameters.sds1.phys[index].sas_address.low
+ & 0xFF;
+ phy->sas_addr[1] = (oem_parameters.sds1.phys[index].sas_address.low
+ >> 8) & 0xFF;
+ phy->sas_addr[2] = (oem_parameters.sds1.phys[index].sas_address.low
+ >> 16) & 0xFF;
+ phy->sas_addr[3] = (oem_parameters.sds1.phys[index].sas_address.low
+ >> 24) & 0xFF;
+ phy->sas_addr[4] = oem_parameters.sds1.phys[index].sas_address.high
+ & 0xFF;
+ phy->sas_addr[5] = (oem_parameters.sds1.phys[index].sas_address.high
+ >> 8) & 0xFF;
+ phy->sas_addr[6] = (oem_parameters.sds1.phys[index].sas_address.high
+ >> 16) & 0xFF;
+ phy->sas_addr[7] = (oem_parameters.sds1.phys[index].sas_address.high
+ >> 24) & 0xFF;
+
+ phy->isci_port = NULL;
+ phy->sas_phy.enabled = 0;
+ phy->sas_phy.id = index;
+ phy->sas_phy.sas_addr = &phy->sas_addr[0];
+ phy->sas_phy.frame_rcvd = (u8 *)&phy->frame_rcvd;
+ phy->sas_phy.ha = &isci_host->sas_ha;
+ phy->sas_phy.lldd_phy = phy;
+ phy->sas_phy.enabled = 1;
+ phy->sas_phy.class = SAS;
+ phy->sas_phy.iproto = SAS_PROTOCOL_ALL;
+ phy->sas_phy.tproto = 0;
+ phy->sas_phy.type = PHY_TYPE_PHYSICAL;
+ phy->sas_phy.role = PHY_ROLE_INITIATOR;
+ phy->sas_phy.oob_mode = OOB_NOT_CONNECTED;
+ phy->sas_phy.linkrate = SAS_LINK_RATE_UNKNOWN;
+ memset((u8 *)&phy->frame_rcvd, 0, sizeof(phy->frame_rcvd));
+}
+
+
+/**
+ * isci_phy_control() - This function is one of the SAS Domain Template
+ * functions. This is a phy management function.
+ * @phy: This parameter specifies the sphy being controlled.
+ * @func: This parameter specifies the phy control function being invoked.
+ * @buf: This parameter is specific to the phy function being invoked.
+ *
+ * status, zero indicates success.
+ */
+int isci_phy_control(
+ struct asd_sas_phy *phy,
+ enum phy_func func,
+ void *buf)
+{
+ int ret = TMF_RESP_FUNC_COMPLETE;
+ struct isci_phy *isci_phy_ptr = (struct isci_phy *)phy->lldd_phy;
+ struct isci_port *isci_port_ptr = NULL;
+
+ if (isci_phy_ptr != NULL)
+ isci_port_ptr = isci_phy_ptr->isci_port;
+
+ if ((isci_phy_ptr == NULL) || (isci_port_ptr == NULL)) {
+ pr_err("%s: asd_sas_phy %p: lldd_phy %p or "
+ "isci_port %p == NULL!\n",
+ __func__, phy, isci_phy_ptr, isci_port_ptr);
+ return TMF_RESP_FUNC_FAILED;
+ }
+
+ pr_debug("%s: phy %p; func %d; buf %p; isci phy %p, port %p\n",
+ __func__, phy, func, buf, isci_phy_ptr, isci_port_ptr);
+
+ switch (func) {
+ case PHY_FUNC_HARD_RESET:
+ case PHY_FUNC_LINK_RESET:
+
+ /* Perform the port reset. */
+ ret = isci_port_perform_hard_reset(isci_port_ptr, isci_phy_ptr);
+
+ break;
+
+ case PHY_FUNC_DISABLE:
+ default:
+ pr_debug("%s: phy %p; func %d NOT IMPLEMENTED!\n",
+ __func__, phy, func);
+ ret = TMF_RESP_FUNC_FAILED;
+ break;
+ }
+ return ret;
+}
diff --git a/drivers/scsi/isci/phy.h b/drivers/scsi/isci/phy.h
new file mode 100644
index 000000000000..44b727f1c455
--- /dev/null
+++ b/drivers/scsi/isci/phy.h
@@ -0,0 +1,104 @@
+/*
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Intel Corporation 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
+ * OWNER 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.
+ */
+
+
+#if !defined(_ISCI_PHY_H_)
+#define _ISCI_PHY_H_
+
+#include "port.h"
+#include "host.h"
+#include <scsi/libsas.h>
+
+
+/**
+ * struct isci_phy - This class implements the ISCI specific representation of
+ * the phy object.
+ *
+ *
+ */
+
+struct isci_phy {
+
+ struct scic_sds_phy *sci_phy_handle;
+
+ struct asd_sas_phy sas_phy;
+ struct sas_identify_frame *frame;
+ struct isci_port *isci_port;
+ u8 sas_addr[SAS_ADDR_SIZE];
+
+ union {
+
+ u8 aif[sizeof(struct sci_sas_identify_address_frame)];
+ u8 fis[sizeof(struct sata_fis_reg_d2h)];
+
+ } frame_rcvd;
+};
+
+#define to_isci_phy(p) \
+ container_of(p, struct isci_phy, sas_phy);
+
+struct isci_host;
+
+void isci_phy_init(
+ struct isci_phy *phy,
+ struct isci_host *isci_host,
+ int index);
+
+int isci_phy_control(
+ struct asd_sas_phy *phy,
+ enum phy_func func,
+ void *buf);
+
+#endif /* !defined(_ISCI_PHY_H_) */
diff --git a/drivers/scsi/isci/port.c b/drivers/scsi/isci/port.c
new file mode 100644
index 000000000000..2343f6556428
--- /dev/null
+++ b/drivers/scsi/isci/port.c
@@ -0,0 +1,484 @@
+/*
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Intel Corporation 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
+ * OWNER 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.
+ */
+
+/**
+ * This file contains the isci port implementation.
+ *
+ *
+ */
+
+
+#include <linux/workqueue.h>
+#include "isci.h"
+#include "scic_io_request.h"
+#include "scic_remote_device.h"
+#include "scic_phy.h"
+#include "scic_sds_phy.h"
+#include "scic_port.h"
+#include "port.h"
+#include "request.h"
+
+static void isci_port_change_state(
+ struct isci_port *isci_port,
+ enum isci_status status);
+
+
+
+/**
+ * isci_port_init() - This function initializes the given isci_port object.
+ * @isci_port: This parameter specifies the port object to be initialized.
+ * @isci_host: This parameter specifies parent controller object for the port.
+ * @index: This parameter specifies which SCU port the isci_port associates
+ * with. Generally, SCU port 0 relates to isci_port 0, etc.
+ *
+ */
+void isci_port_init(
+ struct isci_port *isci_port,
+ struct isci_host *isci_host,
+ int index)
+{
+ struct scic_sds_port *scic_port;
+ struct scic_sds_controller *controller = isci_host->core_controller;
+
+ INIT_LIST_HEAD(&isci_port->remote_dev_list);
+ INIT_LIST_HEAD(&isci_port->domain_dev_list);
+ spin_lock_init(&isci_port->remote_device_lock);
+ spin_lock_init(&isci_port->state_lock);
+ init_completion(&isci_port->start_complete);
+ isci_port->isci_host = isci_host;
+ isci_port_change_state(isci_port, isci_freed);
+
+ (void)scic_controller_get_port_handle(controller, index, &scic_port);
+ sci_object_set_association(scic_port, isci_port);
+ isci_port->sci_port_handle = scic_port;
+}
+
+
+/**
+ * isci_port_get_state() - This function gets the status of the port object.
+ * @isci_port: This parameter points to the isci_port object
+ *
+ * status of the object as a isci_status enum.
+ */
+enum isci_status isci_port_get_state(
+ struct isci_port *isci_port)
+{
+ return isci_port->status;
+}
+
+static void isci_port_change_state(
+ struct isci_port *isci_port,
+ enum isci_status status)
+{
+ unsigned long flags;
+
+ dev_dbg(&isci_port->isci_host->pdev->dev,
+ "%s: isci_port = %p, state = 0x%x\n",
+ __func__, isci_port, status);
+
+ spin_lock_irqsave(&isci_port->state_lock, flags);
+ isci_port->status = status;
+ spin_unlock_irqrestore(&isci_port->state_lock, flags);
+}
+
+void isci_port_bc_change_received(
+ struct isci_host *isci_host,
+ struct scic_sds_port *port,
+ struct scic_sds_phy *phy)
+{
+ struct isci_phy *isci_phy =
+ (struct isci_phy *)sci_object_get_association(phy);
+
+ dev_dbg(&isci_host->pdev->dev,
+ "%s: isci_phy = %p, sas_phy = %p\n",
+ __func__,
+ isci_phy,
+ &isci_phy->sas_phy);
+
+ isci_host->sas_ha.notify_port_event(
+ &isci_phy->sas_phy,
+ PORTE_BROADCAST_RCVD
+ );
+
+ scic_port_enable_broadcast_change_notification(port);
+}
+
+/**
+ * isci_port_link_up() - This function is called by the sci core when a link
+ * becomes active. the identify address frame is retrieved from the core and
+ * a notify port event is sent to libsas.
+ * @isci_host: This parameter specifies the isci host object.
+ * @port: This parameter specifies the sci port with the active link.
+ * @phy: This parameter specifies the sci phy with the active link.
+ *
+ */
+void isci_port_link_up(
+ struct isci_host *isci_host,
+ struct scic_sds_port *port,
+ struct scic_sds_phy *phy)
+{
+ unsigned long flags;
+ struct scic_port_properties properties;
+ struct isci_phy *isci_phy
+ = (struct isci_phy *)sci_object_get_association(phy);
+ struct isci_port *isci_port
+ = (struct isci_port *)sci_object_get_association(port);
+ enum sci_status call_status;
+ unsigned long success = true;
+
+ BUG_ON(isci_phy->isci_port != NULL);
+ isci_phy->isci_port = isci_port;
+
+ dev_dbg(&isci_host->pdev->dev,
+ "%s: isci_port = %p\n",
+ __func__, isci_port);
+
+ spin_lock_irqsave(&isci_phy->sas_phy.frame_rcvd_lock, flags);
+
+ isci_port_change_state(isci_phy->isci_port, isci_starting);
+
+ scic_port_get_properties(port, &properties);
+
+ if (properties.remote.protocols.u.bits.stp_target) {
+
+ struct scic_sata_phy_properties sata_phy_properties;
+
+ isci_phy->sas_phy.oob_mode = SATA_OOB_MODE;
+
+ /* Get a copy of the signature fis for libsas */
+ call_status = scic_sata_phy_get_properties(phy,
+ &sata_phy_properties);
+
+ /*
+ * XXX I am concerned about this "assert". shouldn't we
+ * handle the return appropriately?
+ */
+ BUG_ON(call_status != SCI_SUCCESS);
+
+ memcpy(isci_phy->frame_rcvd.fis,
+ &sata_phy_properties.signature_fis,
+ sizeof(struct sata_fis_reg_d2h));
+
+ isci_phy->sas_phy.frame_rcvd_size = sizeof(struct sata_fis_reg_d2h);
+
+ /*
+ * For direct-attached SATA devices, the SCI core will
+ * automagically assign a SAS address to the end device
+ * for the purpose of creating a port. This SAS address
+ * will not be the same as assigned to the PHY and needs
+ * to be obtained from struct scic_port_properties properties.
+ */
+
+ BUG_ON(((size_t)SAS_ADDR_SIZE / 2)
+ != sizeof(properties.remote.sas_address.low));
+
+ memcpy(&isci_phy->sas_phy.attached_sas_addr[0],
+ &properties.remote.sas_address.low,
+ SAS_ADDR_SIZE / 2);
+
+ memcpy(&isci_phy->sas_phy.attached_sas_addr[4],
+ &properties.remote.sas_address.high,
+ SAS_ADDR_SIZE / 2);
+
+ } else if (properties.remote.protocols.u.bits.ssp_target ||
+ properties.remote.protocols.u.bits.smp_target) {
+
+ struct scic_sas_phy_properties sas_phy_properties;
+
+ isci_phy->sas_phy.oob_mode = SAS_OOB_MODE;
+
+ /* Get a copy of the identify address frame for libsas */
+ call_status = scic_sas_phy_get_properties(phy,
+ &sas_phy_properties);
+
+ BUG_ON(call_status != SCI_SUCCESS);
+
+ memcpy(isci_phy->frame_rcvd.aif,
+ &(sas_phy_properties.received_iaf),
+ sizeof(struct sci_sas_identify_address_frame));
+
+ isci_phy->sas_phy.frame_rcvd_size
+ = sizeof(struct sci_sas_identify_address_frame);
+
+ /* Copy the attached SAS address from the IAF */
+ memcpy(isci_phy->sas_phy.attached_sas_addr,
+ ((struct sas_identify_frame *)
+ (&isci_phy->frame_rcvd.aif))->sas_addr,
+ SAS_ADDR_SIZE);
+
+ } else {
+ dev_err(&isci_host->pdev->dev, "%s: unkown target\n", __func__);
+ success = false;
+ }
+
+ spin_unlock_irqrestore(&isci_phy->sas_phy.frame_rcvd_lock, flags);
+
+ /* Notify libsas that we have an address frame, if indeed
+ * we've found an SSP, SMP, or STP target */
+ if (success)
+ isci_host->sas_ha.notify_port_event(&isci_phy->sas_phy,
+ PORTE_BYTES_DMAED);
+}
+
+
+/**
+ * isci_port_link_down() - This function is called by the sci core when a link
+ * becomes inactive.
+ * @isci_host: This parameter specifies the isci host object.
+ * @phy: This parameter specifies the isci phy with the active link.
+ * @port: This parameter specifies the isci port with the active link.
+ *
+ */
+void isci_port_link_down(
+ struct isci_host *isci_host,
+ struct isci_phy *isci_phy,
+ struct isci_port *isci_port)
+{
+ struct isci_remote_device *isci_device;
+
+ dev_dbg(&isci_host->pdev->dev,
+ "%s: isci_port = %p\n", __func__, isci_port);
+
+ if (isci_port) {
+
+ /* check to see if this is the last phy on this port. */
+ if (isci_phy->sas_phy.port
+ && isci_phy->sas_phy.port->num_phys == 1) {
+
+ /* change the state for all devices on this port.
+ * The next task sent to this device will be returned
+ * as SAS_TASK_UNDELIVERED, and the scsi mid layer
+ * will remove the target
+ */
+ list_for_each_entry(isci_device,
+ &isci_port->remote_dev_list,
+ node) {
+ dev_dbg(&isci_host->pdev->dev,
+ "%s: isci_device = %p\n",
+ __func__, isci_device);
+ isci_remote_device_change_state(isci_device,
+ isci_stopping);
+ }
+ }
+ isci_port_change_state(isci_port, isci_stopping);
+ }
+
+ /* Notify libsas of the borken link, this will trigger calls to our
+ * isci_port_deformed and isci_dev_gone functions.
+ */
+ sas_phy_disconnected(&isci_phy->sas_phy);
+ isci_host->sas_ha.notify_phy_event(&isci_phy->sas_phy,
+ PHYE_LOSS_OF_SIGNAL);
+
+ isci_phy->isci_port = NULL;
+
+ dev_dbg(&isci_host->pdev->dev,
+ "%s: isci_port = %p - Done\n", __func__, isci_port);
+}
+
+
+/**
+ * isci_port_deformed() - This function is called by libsas when a port becomes
+ * inactive.
+ * @phy: This parameter specifies the libsas phy with the inactive port.
+ *
+ */
+void isci_port_deformed(
+ struct asd_sas_phy *phy)
+{
+ pr_debug("%s: sas_phy = %p\n", __func__, phy);
+}
+
+/**
+ * isci_port_formed() - This function is called by libsas when a port becomes
+ * active.
+ * @phy: This parameter specifies the libsas phy with the active port.
+ *
+ */
+void isci_port_formed(
+ struct asd_sas_phy *phy)
+{
+ pr_debug("%s: sas_phy = %p, sas_port = %p\n", __func__, phy, phy->port);
+}
+
+/**
+ * isci_port_ready() - This function is called by the sci core when a link
+ * becomes ready.
+ * @isci_host: This parameter specifies the isci host object.
+ * @port: This parameter specifies the sci port with the active link.
+ *
+ */
+void isci_port_ready(
+ struct isci_host *isci_host,
+ struct isci_port *isci_port)
+{
+ dev_dbg(&isci_host->pdev->dev,
+ "%s: isci_port = %p\n", __func__, isci_port);
+
+ complete_all(&isci_port->start_complete);
+ isci_port_change_state(isci_port, isci_ready);
+ return;
+}
+
+/**
+ * isci_port_not_ready() - This function is called by the sci core when a link
+ * is not ready. All remote devices on this link will be removed if they are
+ * in the stopping state.
+ * @isci_host: This parameter specifies the isci host object.
+ * @port: This parameter specifies the sci port with the active link.
+ *
+ */
+void isci_port_not_ready(
+ struct isci_host *isci_host,
+ struct isci_port *isci_port)
+{
+ dev_dbg(&isci_host->pdev->dev,
+ "%s: isci_port = %p\n", __func__, isci_port);
+}
+
+/**
+ * isci_port_hard_reset_complete() - This function is called by the sci core
+ * when the hard reset complete notification has been received.
+ * @port: This parameter specifies the sci port with the active link.
+ * @completion_status: This parameter specifies the core status for the reset
+ * process.
+ *
+ */
+void isci_port_hard_reset_complete(
+ struct isci_port *isci_port,
+ enum sci_status completion_status)
+{
+ dev_dbg(&isci_port->isci_host->pdev->dev,
+ "%s: isci_port = %p, completion_status=%x\n",
+ __func__, isci_port, completion_status);
+
+ /* Save the status of the hard reset from the port. */
+ isci_port->hard_reset_status = completion_status;
+
+ complete_all(&isci_port->hard_reset_complete);
+}
+/**
+ * isci_port_perform_hard_reset() - This function is one of the SAS Domain
+ * Template functions. This is a phy management function.
+ * @isci_port:
+ * @isci_phy:
+ *
+ * status, TMF_RESP_FUNC_COMPLETE indicates success.
+ */
+int isci_port_perform_hard_reset(
+ struct isci_port *isci_port,
+ struct isci_phy *isci_phy)
+{
+ enum sci_status status;
+ int ret = TMF_RESP_FUNC_COMPLETE;
+ unsigned long flags;
+
+
+ dev_dbg(&isci_port->isci_host->pdev->dev,
+ "%s: isci_port = %p\n",
+ __func__, isci_port);
+
+ BUG_ON(isci_port == NULL);
+
+ init_completion(&isci_port->hard_reset_complete);
+
+ spin_lock_irqsave(&isci_port->isci_host->scic_lock, flags);
+
+ #define ISCI_PORT_RESET_TIMEOUT SCIC_SDS_SIGNATURE_FIS_TIMEOUT
+ status = scic_port_hard_reset(isci_port->sci_port_handle,
+ ISCI_PORT_RESET_TIMEOUT);
+
+ spin_unlock_irqrestore(&isci_port->isci_host->scic_lock, flags);
+
+ if (status == SCI_SUCCESS) {
+ wait_for_completion(&isci_port->hard_reset_complete);
+
+ dev_dbg(&isci_port->isci_host->pdev->dev,
+ "%s: isci_port = %p; hard reset completion\n",
+ __func__, isci_port);
+
+ if (isci_port->hard_reset_status != SCI_SUCCESS)
+ ret = TMF_RESP_FUNC_FAILED;
+ } else {
+ ret = TMF_RESP_FUNC_FAILED;
+
+ dev_err(&isci_port->isci_host->pdev->dev,
+ "%s: isci_port = %p; scic_port_hard_reset call"
+ " failed 0x%x\n",
+ __func__, isci_port, status);
+
+ }
+
+ /* If the hard reset for the port has failed, consider this
+ * the same as link failures on all phys in the port.
+ */
+ if (ret != TMF_RESP_FUNC_COMPLETE) {
+ BUG_ON(isci_port->isci_host == NULL);
+
+ dev_err(&isci_port->isci_host->pdev->dev,
+ "%s: isci_port = %p; hard reset failed "
+ "(0x%x) - sending link down to libsas for phy %p\n",
+ __func__,
+ isci_port,
+ isci_port->hard_reset_status,
+ isci_phy);
+
+ isci_port_link_down(isci_port->isci_host,
+ isci_phy,
+ isci_port);
+ }
+
+ return ret;
+}
diff --git a/drivers/scsi/isci/port.h b/drivers/scsi/isci/port.h
new file mode 100644
index 000000000000..b01b0c63e53f
--- /dev/null
+++ b/drivers/scsi/isci/port.h
@@ -0,0 +1,153 @@
+/*
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Intel Corporation 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
+ * OWNER 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.
+ */
+
+/**
+ * This file contains the isci_port object definition.
+ *
+ * port.h
+ */
+
+#if !defined(_ISCI_PORT_H_)
+#define _ISCI_PORT_H_
+
+struct isci_phy;
+struct isci_host;
+
+
+enum isci_status {
+ isci_freed = 0x00,
+ isci_starting = 0x01,
+ isci_ready = 0x02,
+ isci_ready_for_io = 0x03,
+ isci_stopping = 0x04,
+ isci_stopped = 0x05,
+ isci_host_quiesce = 0x06
+};
+
+/**
+ * struct isci_port - This class represents the port object used to internally
+ * represent libsas port objects. It also keeps a list of remote device
+ * objects.
+ *
+ *
+ */
+struct isci_port {
+
+ struct scic_sds_port *sci_port_handle;
+
+ enum isci_status status;
+ struct isci_host *isci_host;
+ struct asd_sas_port sas_port;
+ struct list_head remote_dev_list;
+ spinlock_t remote_device_lock;
+ spinlock_t state_lock;
+ struct list_head domain_dev_list;
+ struct completion start_complete;
+ struct completion hard_reset_complete;
+ enum sci_status hard_reset_status;
+};
+
+#define to_isci_port(p) \
+ container_of(p, struct isci_port, sas_port);
+
+enum isci_status isci_port_get_state(
+ struct isci_port *isci_port);
+
+
+
+void isci_port_formed(
+ struct asd_sas_phy *);
+
+void isci_port_deformed(
+ struct asd_sas_phy *);
+
+void isci_port_bc_change_received(
+ struct isci_host *isci_host,
+ struct scic_sds_port *port,
+ struct scic_sds_phy *phy);
+
+void isci_port_link_up(
+ struct isci_host *isci_host,
+ struct scic_sds_port *port,
+ struct scic_sds_phy *phy);
+
+void isci_port_link_down(
+ struct isci_host *isci_host,
+ struct isci_phy *isci_phy,
+ struct isci_port *port);
+
+void isci_port_ready(
+ struct isci_host *isci_host,
+ struct isci_port *isci_port);
+
+void isci_port_not_ready(
+ struct isci_host *isci_host,
+ struct isci_port *port);
+
+void isci_port_init(
+ struct isci_port *port,
+ struct isci_host *host,
+ int index);
+
+void isci_port_hard_reset_complete(
+ struct isci_port *isci_port,
+ enum sci_status completion_status);
+
+int isci_port_perform_hard_reset(
+ struct isci_port *isci_port_ptr,
+ struct isci_phy *isci_phy_ptr);
+
+#endif /* !defined(_ISCI_PORT_H_) */
+
diff --git a/drivers/scsi/isci/remote_device.c b/drivers/scsi/isci/remote_device.c
new file mode 100644
index 000000000000..dbf3c82f6195
--- /dev/null
+++ b/drivers/scsi/isci/remote_device.c
@@ -0,0 +1,698 @@
+/*
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Intel Corporation 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
+ * OWNER 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.
+ */
+
+#include "isci.h"
+#include "scic_io_request.h"
+#include "scic_remote_device.h"
+#include "scic_phy.h"
+#include "scic_port.h"
+#include "port.h"
+#include "remote_device.h"
+#include "request.h"
+#include "task.h"
+
+
+
+/**
+ * isci_remote_device_deconstruct() - This function frees an isci_remote_device.
+ * @isci_host: This parameter specifies the isci host object.
+ * @isci_device: This parameter specifies the remote device to be freed.
+ *
+ */
+static void isci_remote_device_deconstruct(
+ struct isci_host *isci_host,
+ struct isci_remote_device *isci_device)
+{
+ dev_dbg(&isci_host->pdev->dev,
+ "%s: isci_device = %p\n", __func__, isci_device);
+
+ /* There should not be any outstanding io's. All paths to
+ * here should go through isci_remote_device_nuke_requests.
+ * If we hit this condition, we will need a way to complete
+ * io requests in process */
+ while (!list_empty(&isci_device->reqs_in_process)) {
+
+ dev_err(&isci_host->pdev->dev,
+ "%s: ** request list not empty! **\n", __func__);
+ BUG();
+ }
+
+ /* Remove all related references to this device and free
+ * the cache object.
+ */
+ scic_remote_device_destruct(isci_device->sci_device_handle);
+ isci_device->domain_dev->lldd_dev = NULL;
+ list_del(&isci_device->node);
+ kmem_cache_free(isci_kmem_cache, isci_device);
+}
+
+
+/**
+ * isci_remote_device_construct() - This function calls the scic remote device
+ * construct and start functions, it waits on the remote device start
+ * completion.
+ * @port: This parameter specifies the isci port with the remote device.
+ * @isci_device: This parameter specifies the isci remote device
+ *
+ * status from the scic calls, the caller to this function should clean up
+ * resources as appropriate.
+ */
+static enum sci_status isci_remote_device_construct(
+ struct isci_port *port,
+ struct isci_remote_device *isci_device)
+{
+ enum sci_status status = SCI_SUCCESS;
+
+ /* let the core do it's common constuction. */
+ scic_remote_device_construct(port->sci_port_handle,
+ isci_device->sci_device_handle);
+
+ /* let the core do it's device specific constuction. */
+ if (isci_device->domain_dev->parent &&
+ (isci_device->domain_dev->parent->dev_type == EDGE_DEV)) {
+ int i;
+
+ /* struct smp_response_discover discover_response; */
+ struct discover_resp discover_response;
+ struct domain_device *parent =
+ isci_device->domain_dev->parent;
+
+ struct expander_device *parent_ex = &parent->ex_dev;
+
+ for (i = 0; i < parent_ex->num_phys; i++) {
+
+ struct ex_phy *phy = &parent_ex->ex_phy[i];
+
+ if ((phy->phy_state == PHY_VACANT) ||
+ (phy->phy_state == PHY_NOT_PRESENT))
+ continue;
+
+ if (SAS_ADDR(phy->attached_sas_addr)
+ == SAS_ADDR(isci_device->domain_dev->sas_addr)) {
+
+ discover_response.attached_dev_type
+ = phy->attached_dev_type;
+ discover_response.linkrate
+ = phy->linkrate;
+ discover_response.attached_sata_host
+ = phy->attached_sata_host;
+ discover_response.attached_sata_dev
+ = phy->attached_sata_dev;
+ discover_response.attached_sata_ps
+ = phy->attached_sata_ps;
+ discover_response.iproto
+ = phy->attached_iproto >> 1;
+ discover_response.tproto
+ = phy->attached_tproto >> 1;
+ memcpy(
+ discover_response.attached_sas_addr,
+ phy->attached_sas_addr,
+ SAS_ADDR_SIZE
+ );
+ discover_response.attached_phy_id
+ = phy->attached_phy_id;
+ discover_response.change_count
+ = phy->phy_change_count;
+ discover_response.routing_attr
+ = phy->routing_attr;
+ discover_response.hmin_linkrate
+ = phy->phy->minimum_linkrate_hw;
+ discover_response.hmax_linkrate
+ = phy->phy->maximum_linkrate_hw;
+ discover_response.pmin_linkrate
+ = phy->phy->minimum_linkrate;
+ discover_response.pmax_linkrate
+ = phy->phy->maximum_linkrate;
+ }
+ }
+
+
+ dev_dbg(&port->isci_host->pdev->dev,
+ "%s: parent->dev_type = EDGE_DEV\n",
+ __func__);
+
+ status = scic_remote_device_ea_construct(
+ isci_device->sci_device_handle,
+ (struct smp_response_discover *)&discover_response
+ );
+
+ } else
+ status = scic_remote_device_da_construct(
+ isci_device->sci_device_handle
+ );
+
+
+ if (status != SCI_SUCCESS) {
+ dev_dbg(&port->isci_host->pdev->dev,
+ "%s: scic_remote_device_da_construct failed - "
+ "isci_device = %p\n",
+ __func__,
+ isci_device);
+
+ return status;
+ }
+
+ sci_object_set_association(
+ isci_device->sci_device_handle,
+ isci_device
+ );
+
+ BUG_ON(port->isci_host == NULL);
+
+ /* start the device. */
+ status = scic_remote_device_start(
+ isci_device->sci_device_handle,
+ ISCI_REMOTE_DEVICE_START_TIMEOUT
+ );
+
+ if (status != SCI_SUCCESS) {
+ dev_warn(&port->isci_host->pdev->dev,
+ "%s: scic_remote_device_start failed\n",
+ __func__);
+ return status;
+ }
+
+ return status;
+}
+
+
+/**
+ * isci_remote_device_nuke_requests() - This function terminates all requests
+ * for a given remote device.
+ * @isci_device: This parameter specifies the remote device
+ *
+ */
+void isci_remote_device_nuke_requests(
+ struct isci_remote_device *isci_device)
+{
+ DECLARE_COMPLETION_ONSTACK(aborted_task_completion);
+ struct isci_host *isci_host;
+
+ isci_host = isci_device->isci_port->isci_host;
+
+ dev_dbg(&isci_host->pdev->dev,
+ "%s: isci_device = %p\n", __func__, isci_device);
+
+ /* Cleanup all requests pending for this device. */
+ isci_terminate_pending_requests(isci_host, isci_device, terminating);
+
+ dev_dbg(&isci_host->pdev->dev,
+ "%s: isci_device = %p, done\n", __func__, isci_device);
+}
+
+
+
+/**
+ * This function builds the isci_remote_device when a libsas dev_found message
+ * is received.
+ * @isci_host: This parameter specifies the isci host object.
+ * @port: This parameter specifies the isci_port conected to this device.
+ *
+ * pointer to new isci_remote_device.
+ */
+static struct isci_remote_device *
+isci_remote_device_alloc(struct isci_host *isci_host, struct isci_port *port)
+{
+ struct isci_remote_device *isci_device;
+ struct scic_sds_remote_device *sci_dev;
+
+ isci_device = kmem_cache_zalloc(isci_kmem_cache, GFP_KERNEL);
+
+ if (!isci_device) {
+ dev_warn(&isci_host->pdev->dev, "%s: failed\n", __func__);
+ return NULL;
+ }
+
+ sci_dev = (struct scic_sds_remote_device *) &isci_device[1];
+ isci_device->sci_device_handle = sci_dev;
+ INIT_LIST_HEAD(&isci_device->reqs_in_process);
+ INIT_LIST_HEAD(&isci_device->node);
+ isci_device->host_quiesce = false;
+
+ spin_lock_init(&isci_device->state_lock);
+ spin_lock_init(&isci_device->host_quiesce_lock);
+ isci_remote_device_change_state(isci_device, isci_freed);
+
+ return isci_device;
+
+}
+/**
+ * isci_device_set_host_quiesce_lock_state() - This function sets the host I/O
+ * quiesce lock state for the remote_device object.
+ * @isci_device,: This parameter points to the isci_remote_device object
+ * @isci_device: This parameter specifies the new quiesce state.
+ *
+ */
+void isci_device_set_host_quiesce_lock_state(
+ struct isci_remote_device *isci_device,
+ bool lock_state)
+{
+ unsigned long flags;
+
+ dev_dbg(&isci_device->isci_port->isci_host->pdev->dev,
+ "%s: isci_device=%p, lock_state=%d\n",
+ __func__, isci_device, lock_state);
+
+ spin_lock_irqsave(&isci_device->host_quiesce_lock, flags);
+ isci_device->host_quiesce = lock_state;
+ spin_unlock_irqrestore(&isci_device->host_quiesce_lock, flags);
+}
+
+/**
+ * isci_remote_device_ready() - This function is called by the scic when the
+ * remote device is ready. We mark the isci device as ready and signal the
+ * waiting proccess.
+ * @isci_host: This parameter specifies the isci host object.
+ * @isci_device: This parameter specifies the remote device
+ *
+ */
+void isci_remote_device_ready(struct isci_remote_device *isci_device)
+{
+ unsigned long flags;
+
+ dev_dbg(&isci_device->isci_port->isci_host->pdev->dev,
+ "%s: isci_device = %p\n", __func__, isci_device);
+
+ /* device ready is actually a "ready for io" state. */
+ if ((isci_starting == isci_remote_device_get_state(isci_device)) ||
+ (isci_ready == isci_remote_device_get_state(isci_device))) {
+ spin_lock_irqsave(&isci_device->isci_port->remote_device_lock,
+ flags);
+ isci_remote_device_change_state(isci_device, isci_ready_for_io);
+ if (isci_device->completion)
+ complete(isci_device->completion);
+ spin_unlock_irqrestore(
+ &isci_device->isci_port->remote_device_lock,
+ flags);
+ }
+
+}
+
+/**
+ * isci_remote_device_not_ready() - This function is called by the scic when
+ * the remote device is not ready. We mark the isci device as ready (not
+ * "ready_for_io") and signal the waiting proccess.
+ * @isci_host: This parameter specifies the isci host object.
+ * @isci_device: This parameter specifies the remote device
+ *
+ */
+void isci_remote_device_not_ready(
+ struct isci_remote_device *isci_device,
+ u32 reason_code)
+{
+ dev_dbg(&isci_device->isci_port->isci_host->pdev->dev,
+ "%s: isci_device = %p\n", __func__, isci_device);
+
+ if (reason_code == SCIC_REMOTE_DEVICE_NOT_READY_STOP_REQUESTED)
+ isci_remote_device_change_state(isci_device, isci_stopping);
+ else
+ /* device ready is actually a "not ready for io" state. */
+ isci_remote_device_change_state(isci_device, isci_ready);
+}
+
+/**
+ * isci_remote_device_stop_complete() - This function is called by the scic
+ * when the remote device stop has completed. We mark the isci device as not
+ * ready and remove the isci remote device.
+ * @isci_host: This parameter specifies the isci host object.
+ * @isci_device: This parameter specifies the remote device.
+ * @status: This parameter specifies status of the completion.
+ *
+ */
+void isci_remote_device_stop_complete(
+ struct isci_host *isci_host,
+ struct isci_remote_device *isci_device,
+ enum sci_status status)
+{
+ struct completion *completion = isci_device->completion;
+
+ dev_dbg(&isci_host->pdev->dev,
+ "%s: complete isci_device = %p, status = 0x%x\n",
+ __func__,
+ isci_device,
+ status);
+
+ isci_remote_device_change_state(isci_device, isci_stopped);
+
+ /* after stop, we can tear down resources. */
+ isci_remote_device_deconstruct(isci_host, isci_device);
+
+ /* notify interested parties. */
+ if (completion)
+ complete(completion);
+}
+
+/**
+ * isci_remote_device_start_complete() - This function is called by the scic
+ * when the remote device start has completed
+ * @isci_host: This parameter specifies the isci host object.
+ * @isci_device: This parameter specifies the remote device.
+ * @status: This parameter specifies status of the completion.
+ *
+ */
+void isci_remote_device_start_complete(
+ struct isci_host *isci_host,
+ struct isci_remote_device *isci_device,
+ enum sci_status status)
+{
+
+
+}
+
+
+/**
+ * isci_remote_device_stop() - This function is called internally to stop the
+ * remote device.
+ * @isci_host: This parameter specifies the isci host object.
+ * @isci_device: This parameter specifies the remote device.
+ *
+ * The status of the scic request to stop.
+ */
+enum sci_status isci_remote_device_stop(
+ struct isci_remote_device *isci_device)
+{
+ enum sci_status status;
+ unsigned long flags;
+
+ DECLARE_COMPLETION_ONSTACK(completion);
+
+ dev_dbg(&isci_device->isci_port->isci_host->pdev->dev,
+ "%s: isci_device = %p\n", __func__, isci_device);
+
+ isci_remote_device_change_state(isci_device, isci_stopping);
+
+ /* We need comfirmation that stop completed. */
+ isci_device->completion = &completion;
+
+ BUG_ON(isci_device->isci_port == NULL);
+ BUG_ON(isci_device->isci_port->isci_host == NULL);
+
+ spin_lock_irqsave(&isci_device->isci_port->isci_host->scic_lock, flags);
+
+ status = scic_remote_device_stop(
+ isci_device->sci_device_handle,
+ 50
+ );
+
+ spin_unlock_irqrestore(&isci_device->isci_port->isci_host->scic_lock, flags);
+
+ /* Wait for the stop complete callback. */
+ if (status == SCI_SUCCESS)
+ wait_for_completion(&completion);
+
+ dev_dbg(&isci_device->isci_port->isci_host->pdev->dev,
+ "%s: isci_device = %p - after completion wait\n",
+ __func__, isci_device);
+
+ isci_device->completion = NULL;
+ return status;
+}
+
+/**
+ * isci_remote_device_gone() - This function is called by libsas when a domain
+ * device is removed.
+ * @domain_device: This parameter specifies the libsas domain device.
+ *
+ */
+void isci_remote_device_gone(
+ struct domain_device *domain_dev)
+{
+ struct isci_remote_device *isci_device = isci_dev_from_domain_dev(
+ domain_dev);
+
+ dev_err(&isci_device->isci_port->isci_host->pdev->dev,
+ "%s: domain_device = %p, isci_device = %p, isci_port = %p\n",
+ __func__, domain_dev, isci_device, isci_device->isci_port);
+
+ if (isci_device != NULL)
+ isci_remote_device_stop(isci_device);
+}
+
+
+/**
+ * isci_remote_device_found() - This function is called by libsas when a remote
+ * device is discovered. A remote device object is created and started. the
+ * function then sleeps until the sci core device started message is
+ * received.
+ * @domain_device: This parameter specifies the libsas domain device.
+ *
+ * status, zero indicates success.
+ */
+int isci_remote_device_found(struct domain_device *domain_dev)
+{
+ unsigned long flags;
+ struct isci_host *isci_host;
+ struct isci_port *isci_port;
+ struct isci_phy *isci_phy;
+ struct asd_sas_port *sas_port;
+ struct asd_sas_phy *sas_phy;
+ struct isci_remote_device *isci_device;
+ enum sci_status status;
+ DECLARE_COMPLETION_ONSTACK(completion);
+
+ isci_host = isci_host_from_sas_ha(domain_dev->port->ha);
+
+ dev_dbg(&isci_host->pdev->dev,
+ "%s: domain_device = %p\n", __func__, domain_dev);
+
+ sas_port = domain_dev->port;
+ sas_phy = list_first_entry(&sas_port->phy_list, struct asd_sas_phy,
+ port_phy_el);
+ isci_phy = to_isci_phy(sas_phy);
+ isci_port = isci_phy->isci_port;
+
+ /* we are being called for a device on this port,
+ * so it has to come up eventually
+ */
+ wait_for_completion(&isci_port->start_complete);
+
+ if ((isci_stopping == isci_port_get_state(isci_port)) ||
+ (isci_stopped == isci_port_get_state(isci_port)))
+ return -ENODEV;
+
+ isci_device = isci_remote_device_alloc(isci_host, isci_port);
+
+ INIT_LIST_HEAD(&isci_device->node);
+ domain_dev->lldd_dev = isci_device;
+ isci_device->domain_dev = domain_dev;
+ isci_device->isci_port = isci_port;
+ isci_remote_device_change_state(isci_device, isci_starting);
+
+
+ spin_lock_irqsave(&isci_port->remote_device_lock, flags);
+ list_add_tail(&isci_device->node, &isci_port->remote_dev_list);
+
+ /* for the device ready event. */
+ isci_device->completion = &completion;
+
+ status = isci_remote_device_construct(isci_port, isci_device);
+
+ spin_unlock_irqrestore(&isci_port->remote_device_lock, flags);
+
+ /* wait for the device ready callback. */
+ wait_for_completion(isci_device->completion);
+ isci_device->completion = NULL;
+
+ dev_dbg(&isci_host->pdev->dev,
+ "%s: isci_device = %p\n",
+ __func__, isci_device);
+
+ if (status != SCI_SUCCESS) {
+
+ spin_lock_irqsave(&isci_port->remote_device_lock, flags);
+ isci_remote_device_deconstruct(
+ isci_host,
+ isci_device
+ );
+ spin_unlock_irqrestore(&isci_port->remote_device_lock, flags);
+ return -ENODEV;
+ }
+
+ wait_for_completion(&isci_host->start_complete);
+
+ return 0;
+}
+/**
+ * isci_device_is_reset_pending() - This function will check if there is any
+ * pending reset condition on the device.
+ * @request: This parameter is the isci_device object.
+ *
+ * true if there is a reset pending for the device.
+ */
+bool isci_device_is_reset_pending(
+ struct isci_host *isci_host,
+ struct isci_remote_device *isci_device)
+{
+ struct isci_request *isci_request;
+ struct isci_request *tmp_req;
+ bool reset_is_pending = false;
+ unsigned long flags;
+
+ dev_dbg(&isci_host->pdev->dev,
+ "%s: isci_device = %p\n", __func__, isci_device);
+
+ spin_lock_irqsave(&isci_host->scic_lock, flags);
+
+ /* Check for reset on all pending requests. */
+ list_for_each_entry_safe(isci_request, tmp_req,
+ &isci_device->reqs_in_process, dev_node) {
+ dev_dbg(&isci_host->pdev->dev,
+ "%s: isci_device = %p request = %p\n",
+ __func__, isci_device, isci_request);
+
+ if (isci_request->ttype == io_task) {
+
+ unsigned long flags;
+ struct sas_task *task = isci_request_access_task(
+ isci_request);
+
+ spin_lock_irqsave(&task->task_state_lock, flags);
+ if (task->task_state_flags & SAS_TASK_NEED_DEV_RESET)
+ reset_is_pending = true;
+ spin_unlock_irqrestore(&task->task_state_lock, flags);
+ }
+ }
+
+ spin_unlock_irqrestore(&isci_host->scic_lock, flags);
+
+ dev_dbg(&isci_host->pdev->dev,
+ "%s: isci_device = %p reset_is_pending = %d\n",
+ __func__, isci_device, reset_is_pending);
+
+ return reset_is_pending;
+}
+
+/**
+ * isci_device_clear_reset_pending() - This function will clear if any pending
+ * reset condition flags on the device.
+ * @request: This parameter is the isci_device object.
+ *
+ * true if there is a reset pending for the device.
+ */
+void isci_device_clear_reset_pending(struct isci_remote_device *isci_device)
+{
+ struct isci_request *isci_request;
+ struct isci_request *tmp_req;
+ struct isci_host *isci_host = NULL;
+ unsigned long flags = 0;
+
+ /* FIXME more port gone confusion, and this time it makes the
+ * locking "fun"
+ */
+ if (isci_device->isci_port != NULL)
+ isci_host = isci_device->isci_port->isci_host;
+
+ /*
+ * FIXME when the isci_host gets sorted out
+ * use dev_dbg()
+ */
+ pr_debug("%s: isci_device=%p, isci_host=%p\n",
+ __func__, isci_device, isci_host);
+
+ if (isci_host != NULL)
+ spin_lock_irqsave(&isci_host->scic_lock, flags);
+ else
+ pr_err("%s: isci_device %p; isci_host == NULL!\n",
+ __func__, isci_device);
+
+ /* Clear reset pending on all pending requests. */
+ list_for_each_entry_safe(isci_request, tmp_req,
+ &isci_device->reqs_in_process, dev_node) {
+ /*
+ * FIXME when the conditional spinlock is gone
+ * change to dev_dbg()
+ */
+ pr_debug("%s: isci_device = %p request = %p\n",
+ __func__, isci_device, isci_request);
+
+ if (isci_request->ttype == io_task) {
+
+ unsigned long flags2;
+ struct sas_task *task = isci_request_access_task(
+ isci_request);
+
+ spin_lock_irqsave(&task->task_state_lock, flags2);
+ task->task_state_flags &= ~SAS_TASK_NEED_DEV_RESET;
+ spin_unlock_irqrestore(&task->task_state_lock, flags2);
+ }
+ }
+
+ if (isci_host != NULL)
+ spin_unlock_irqrestore(&isci_host->scic_lock, flags);
+}
+
+/**
+ * isci_remote_device_change_state() - This function gets the status of the
+ * remote_device object.
+ * @isci_device: This parameter points to the isci_remote_device object
+ *
+ * status of the object as a isci_status enum.
+ */
+void isci_remote_device_change_state(
+ struct isci_remote_device *isci_device,
+ enum isci_status status)
+{
+ unsigned long flags;
+
+ dev_dbg(&isci_device->isci_port->isci_host->pdev->dev,
+ "%s: isci_device = %p, state = 0x%x",
+ __func__,
+ isci_device,
+ status);
+
+ spin_lock_irqsave(&isci_device->state_lock, flags);
+ isci_device->status = status;
+ spin_unlock_irqrestore(&isci_device->state_lock, flags);
+}
diff --git a/drivers/scsi/isci/remote_device.h b/drivers/scsi/isci/remote_device.h
new file mode 100644
index 000000000000..a208f81785eb
--- /dev/null
+++ b/drivers/scsi/isci/remote_device.h
@@ -0,0 +1,154 @@
+/*
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Intel Corporation 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
+ * OWNER 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.
+ */
+
+#if !defined(_ISCI_REMOTE_DEVICE_H_)
+#define _ISCI_REMOTE_DEVICE_H_
+#include "scic_user_callback.h"
+
+struct isci_host;
+struct scic_sds_remote_device;
+
+struct isci_remote_device {
+ struct scic_sds_remote_device *sci_device_handle;
+ enum isci_status status;
+ struct isci_port *isci_port;
+ struct domain_device *domain_dev;
+ struct completion *completion;
+ struct list_head node;
+ struct list_head reqs_in_process;
+ struct work_struct stop_work;
+ spinlock_t state_lock;
+ spinlock_t host_quiesce_lock;
+ bool host_quiesce;
+};
+
+#define to_isci_remote_device(p) \
+ container_of(p, struct isci_remote_device, sci_remote_device);
+
+#define ISCI_REMOTE_DEVICE_START_TIMEOUT 5000
+
+
+/**
+ * This function gets the status of the remote_device object.
+ * @isci_device: This parameter points to the isci_remote_device object
+ *
+ * status of the object as a isci_status enum.
+ */
+static inline
+enum isci_status isci_remote_device_get_state(
+ struct isci_remote_device *isci_device)
+{
+ return (isci_device->host_quiesce)
+ ? isci_host_quiesce
+ : isci_device->status;
+}
+
+
+/**
+ * isci_dev_from_domain_dev() - This accessor retrieves the remote_device
+ * object reference from the Linux domain_device reference.
+ * @domdev,: This parameter points to the Linux domain_device object .
+ *
+ * A reference to the associated isci remote device.
+ */
+#define isci_dev_from_domain_dev(domdev) \
+ ((struct isci_remote_device *)(domdev)->lldd_dev)
+
+void isci_remote_device_start_complete(
+ struct isci_host *,
+ struct isci_remote_device *,
+ enum sci_status);
+
+void isci_remote_device_stop_complete(
+ struct isci_host *,
+ struct isci_remote_device *,
+ enum sci_status);
+
+enum sci_status isci_remote_device_stop(
+ struct isci_remote_device *isci_device);
+
+void isci_remote_device_nuke_requests(
+ struct isci_remote_device *isci_device);
+
+void isci_remote_device_ready(
+ struct isci_remote_device *);
+
+void isci_remote_device_not_ready(
+ struct isci_remote_device *,
+ u32);
+
+void isci_remote_device_gone(
+ struct domain_device *domain_dev);
+
+int isci_remote_device_found(
+ struct domain_device *domain_dev);
+
+bool isci_device_is_reset_pending(
+ struct isci_host *isci_host,
+ struct isci_remote_device *isci_device);
+
+void isci_device_clear_reset_pending(
+ struct isci_remote_device *isci_device);
+
+void isci_device_set_host_quiesce_lock_state(
+ struct isci_remote_device *isci_device,
+ bool lock_state);
+
+void isci_remote_device_change_state(
+ struct isci_remote_device *isci_device,
+ enum isci_status status);
+
+#endif /* !defined(_ISCI_REMOTE_DEVICE_H_) */
+
diff --git a/drivers/scsi/isci/request.c b/drivers/scsi/isci/request.c
new file mode 100644
index 000000000000..e564121b6726
--- /dev/null
+++ b/drivers/scsi/isci/request.c
@@ -0,0 +1,1472 @@
+/*
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Intel Corporation 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
+ * OWNER 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.
+ */
+
+#include "isci.h"
+#include "scic_remote_device.h"
+#include "scic_io_request.h"
+#include "scic_task_request.h"
+#include "scic_port.h"
+#include "task.h"
+#include "request.h"
+#include "sata.h"
+#include "scu_completion_codes.h"
+
+
+static enum sci_status isci_request_ssp_request_construct(
+ struct isci_request *request)
+{
+ enum sci_status status;
+
+ dev_dbg(&request->isci_host->pdev->dev,
+ "%s: request = %p\n",
+ __func__,
+ request);
+ status = scic_io_request_construct_basic_ssp(
+ request->sci_request_handle
+ );
+ return status;
+}
+
+static enum sci_status isci_request_stp_request_construct(
+ struct isci_request *request)
+{
+ struct sas_task *task = isci_request_access_task(request);
+ enum sci_status status;
+ struct host_to_dev_fis *register_fis;
+
+ dev_dbg(&request->isci_host->pdev->dev,
+ "%s: request = %p\n",
+ __func__,
+ request);
+
+ /* Get the host_to_dev_fis from the core and copy
+ * the fis from the task into it.
+ */
+ register_fis = isci_sata_task_to_fis_copy(task);
+
+ status = scic_io_request_construct_basic_sata(
+ request->sci_request_handle
+ );
+
+ /* Set the ncq tag in the fis, from the queue
+ * command in the task.
+ */
+ if (isci_sata_is_task_ncq(task)) {
+
+ isci_sata_set_ncq_tag(
+ register_fis,
+ task
+ );
+ }
+
+ return status;
+}
+
+/**
+ * isci_smp_request_build() - This function builds the smp request object.
+ * @isci_host: This parameter specifies the ISCI host object
+ * @request: This parameter points to the isci_request object allocated in the
+ * request construct function.
+ * @sci_device: This parameter is the handle for the sci core's remote device
+ * object that is the destination for this request.
+ *
+ * SCI_SUCCESS on successfull completion, or specific failure code.
+ */
+static enum sci_status isci_smp_request_build(
+ struct isci_request *request)
+{
+ enum sci_status status = SCI_FAILURE;
+ struct sas_task *task = isci_request_access_task(request);
+
+ void *command_iu_address =
+ scic_io_request_get_command_iu_address(
+ request->sci_request_handle
+ );
+
+ dev_dbg(&request->isci_host->pdev->dev,
+ "%s: request = %p\n",
+ __func__,
+ request);
+ dev_dbg(&request->isci_host->pdev->dev,
+ "%s: smp_req len = %d\n",
+ __func__,
+ task->smp_task.smp_req.length);
+
+ /* copy the smp_command to the address; */
+ sg_copy_to_buffer(&task->smp_task.smp_req, 1,
+ (char *)command_iu_address,
+ sizeof(struct smp_request)
+ );
+
+ status = scic_io_request_construct_smp(request->sci_request_handle);
+ if (status != SCI_SUCCESS)
+ dev_warn(&request->isci_host->pdev->dev,
+ "%s: scic_io_request_construct_smp failed with "
+ "status = %d\n",
+ __func__,
+ status);
+
+ return status;
+}
+
+/**
+ * isci_io_request_build() - This function builds the io request object.
+ * @isci_host: This parameter specifies the ISCI host object
+ * @request: This parameter points to the isci_request object allocated in the
+ * request construct function.
+ * @sci_device: This parameter is the handle for the sci core's remote device
+ * object that is the destination for this request.
+ *
+ * SCI_SUCCESS on successfull completion, or specific failure code.
+ */
+static enum sci_status isci_io_request_build(
+ struct isci_host *isci_host,
+ struct isci_request *request,
+ struct isci_remote_device *isci_device)
+{
+ struct smp_discover_response_protocols dev_protocols;
+ enum sci_status status = SCI_SUCCESS;
+ struct sas_task *task = isci_request_access_task(request);
+ struct scic_sds_remote_device *sci_device =
+ isci_device->sci_device_handle;
+
+ dev_dbg(&isci_host->pdev->dev,
+ "%s: isci_device = 0x%p; request = %p, "
+ "num_scatter = %d\n",
+ __func__,
+ isci_device,
+ request,
+ task->num_scatter);
+
+ /* map the sgl addresses, if present.
+ * libata does the mapping for sata devices
+ * before we get the request.
+ */
+ if (task->num_scatter &&
+ !sas_protocol_ata(task->task_proto) &&
+ !(SAS_PROTOCOL_SMP & task->task_proto)) {
+
+ request->num_sg_entries = dma_map_sg(
+ &isci_host->pdev->dev,
+ task->scatter,
+ task->num_scatter,
+ task->data_dir
+ );
+
+ if (request->num_sg_entries == 0)
+ return SCI_FAILURE_INSUFFICIENT_RESOURCES;
+ }
+
+ /* build the common request object. For now,
+ * we will let the core allocate the IO tag.
+ */
+ status = scic_io_request_construct(
+ isci_host->core_controller,
+ sci_device,
+ SCI_CONTROLLER_INVALID_IO_TAG,
+ request,
+ request->sci_request_mem_ptr,
+ (struct scic_sds_request **)&request->sci_request_handle
+ );
+
+ if (status != SCI_SUCCESS) {
+ dev_warn(&isci_host->pdev->dev,
+ "%s: failed request construct\n",
+ __func__);
+ return SCI_FAILURE;
+ }
+
+ sci_object_set_association(request->sci_request_handle, request);
+
+ /* Determine protocol and call the appropriate basic constructor */
+ scic_remote_device_get_protocols(sci_device, &dev_protocols);
+ if (dev_protocols.u.bits.attached_ssp_target)
+ status = isci_request_ssp_request_construct(request);
+ else if (dev_protocols.u.bits.attached_stp_target)
+ status = isci_request_stp_request_construct(request);
+ else if (dev_protocols.u.bits.attached_smp_target)
+ status = isci_smp_request_build(request);
+ else {
+ dev_warn(&isci_host->pdev->dev,
+ "%s: unknown protocol\n", __func__);
+ return SCI_FAILURE;
+ }
+
+ return SCI_SUCCESS;
+}
+
+
+/**
+ * isci_request_alloc_core() - This function gets the request object from the
+ * isci_host dma cache.
+ * @isci_host: This parameter specifies the ISCI host object
+ * @isci_request: This parameter will contain the pointer to the new
+ * isci_request object.
+ * @isci_device: This parameter is the pointer to the isci remote device object
+ * that is the destination for this request.
+ * @gfp_flags: This parameter specifies the os allocation flags.
+ *
+ * SCI_SUCCESS on successfull completion, or specific failure code.
+ */
+static int isci_request_alloc_core(
+ struct isci_host *isci_host,
+ struct isci_request **isci_request,
+ struct isci_remote_device *isci_device,
+ gfp_t gfp_flags)
+{
+ int ret = 0;
+ dma_addr_t handle;
+ struct isci_request *request;
+
+
+ /* get pointer to dma memory. This actually points
+ * to both the isci_remote_device object and the
+ * sci object. The isci object is at the beginning
+ * of the memory allocated here.
+ */
+ request = dma_pool_alloc(isci_host->dma_pool, gfp_flags, &handle);
+ if (!request) {
+ dev_warn(&isci_host->pdev->dev,
+ "%s: dma_pool_alloc returned NULL\n", __func__);
+ return -ENOMEM;
+ }
+
+ /* initialize the request object. */
+ spin_lock_init(&request->state_lock);
+ isci_request_change_state(request, allocated);
+ request->sci_request_mem_ptr = ((u8 *)request) +
+ sizeof(struct isci_request);
+ request->request_daddr = handle;
+ request->isci_host = isci_host;
+ request->isci_device = isci_device;
+ request->io_request_completion = NULL;
+
+ request->request_alloc_size = isci_host->dma_pool_alloc_size;
+ request->num_sg_entries = 0;
+
+ request->complete_in_target = false;
+
+ INIT_LIST_HEAD(&request->completed_node);
+ INIT_LIST_HEAD(&request->dev_node);
+
+ *isci_request = request;
+
+ return ret;
+}
+
+static int isci_request_alloc_io(
+ struct isci_host *isci_host,
+ struct sas_task *task,
+ struct isci_request **isci_request,
+ struct isci_remote_device *isci_device,
+ gfp_t gfp_flags)
+{
+ int retval = isci_request_alloc_core(isci_host, isci_request,
+ isci_device, gfp_flags);
+
+ if (!retval) {
+ (*isci_request)->ttype_ptr.io_task_ptr = task;
+ (*isci_request)->ttype = io_task;
+
+ task->lldd_task = *isci_request;
+ }
+ return retval;
+}
+
+/**
+ * isci_request_alloc_tmf() - This function gets the request object from the
+ * isci_host dma cache and initializes the relevant fields as a sas_task.
+ * @isci_host: This parameter specifies the ISCI host object
+ * @sas_task: This parameter is the task struct from the upper layer driver.
+ * @isci_request: This parameter will contain the pointer to the new
+ * isci_request object.
+ * @isci_device: This parameter is the pointer to the isci remote device object
+ * that is the destination for this request.
+ * @gfp_flags: This parameter specifies the os allocation flags.
+ *
+ * SCI_SUCCESS on successfull completion, or specific failure code.
+ */
+int isci_request_alloc_tmf(
+ struct isci_host *isci_host,
+ struct isci_tmf *isci_tmf,
+ struct isci_request **isci_request,
+ struct isci_remote_device *isci_device,
+ gfp_t gfp_flags)
+{
+ int retval = isci_request_alloc_core(isci_host, isci_request,
+ isci_device, gfp_flags);
+
+ if (!retval) {
+
+ (*isci_request)->ttype_ptr.tmf_task_ptr = isci_tmf;
+ (*isci_request)->ttype = tmf_task;
+ }
+ return retval;
+}
+
+/**
+ * isci_request_signal_device_reset() - This function will set the "device
+ * needs target reset" flag in the given sas_tasks' task_state_flags, and
+ * then cause the task to be added into the SCSI error handler queue which
+ * will eventually be escalated to a target reset.
+ *
+ *
+ */
+static void isci_request_signal_device_reset(
+ struct isci_request *isci_request)
+{
+ unsigned long flags;
+ struct sas_task *task = isci_request_access_task(isci_request);
+
+ dev_dbg(&isci_request->isci_host->pdev->dev,
+ "%s: request=%p, task=%p\n", __func__, isci_request, task);
+
+ spin_lock_irqsave(&task->task_state_lock, flags);
+ task->task_state_flags |= SAS_TASK_NEED_DEV_RESET;
+ spin_unlock_irqrestore(&task->task_state_lock, flags);
+
+ /* Cause this task to be scheduled in the SCSI error handler
+ * thread.
+ */
+ sas_task_abort(task);
+}
+
+/**
+ * isci_request_execute() - This function allocates the isci_request object,
+ * all fills in some common fields.
+ * @isci_host: This parameter specifies the ISCI host object
+ * @sas_task: This parameter is the task struct from the upper layer driver.
+ * @isci_request: This parameter will contain the pointer to the new
+ * isci_request object.
+ * @gfp_flags: This parameter specifies the os allocation flags.
+ *
+ * SCI_SUCCESS on successfull completion, or specific failure code.
+ */
+int isci_request_execute(
+ struct isci_host *isci_host,
+ struct sas_task *task,
+ struct isci_request **isci_request,
+ gfp_t gfp_flags)
+{
+ int ret = 0;
+ struct scic_sds_remote_device *sci_device;
+ enum sci_status status = SCI_FAILURE_UNSUPPORTED_PROTOCOL;
+ struct isci_remote_device *isci_device;
+ struct isci_request *request;
+ unsigned long flags;
+
+ isci_device = isci_dev_from_domain_dev(task->dev);
+ sci_device = isci_device->sci_device_handle;
+
+ /* do common allocation and init of request object. */
+ ret = isci_request_alloc_io(
+ isci_host,
+ task,
+ &request,
+ isci_device,
+ gfp_flags
+ );
+
+ if (ret)
+ goto out;
+
+ status = isci_io_request_build(isci_host, request, isci_device);
+ if (status == SCI_SUCCESS) {
+
+ spin_lock_irqsave(&isci_host->scic_lock, flags);
+
+ /* send the request, let the core assign the IO TAG. */
+ status = scic_controller_start_io(
+ isci_host->core_controller,
+ sci_device,
+ request->sci_request_handle,
+ SCI_CONTROLLER_INVALID_IO_TAG
+ );
+
+ if (status == SCI_SUCCESS ||
+ status == SCI_FAILURE_REMOTE_DEVICE_RESET_REQUIRED) {
+
+ /* Either I/O started OK, or the core has signaled that
+ * the device needs a target reset.
+ *
+ * In either case, hold onto the I/O for later.
+ *
+ * Update it's status and add it to the list in the
+ * remote device object.
+ */
+ isci_request_change_state(request, started);
+ list_add(&request->dev_node,
+ &isci_device->reqs_in_process);
+
+ if (status ==
+ SCI_FAILURE_REMOTE_DEVICE_RESET_REQUIRED) {
+ /* Signal libsas that we need the SCSI error
+ * handler thread to work on this I/O and that
+ * we want a device reset.
+ */
+ isci_request_signal_device_reset(request);
+
+ /* Change the status, since we are holding
+ * the I/O until it is managed by the SCSI
+ * error handler.
+ */
+ status = SCI_SUCCESS;
+ }
+ } else
+ dev_warn(&isci_host->pdev->dev,
+ "%s: failed request start\n",
+ __func__);
+
+ spin_unlock_irqrestore(&isci_host->scic_lock, flags);
+
+ } else
+ dev_warn(&isci_host->pdev->dev,
+ "%s: request_construct failed - status = 0x%x\n",
+ __func__,
+ status);
+
+ out:
+ if (status != SCI_SUCCESS) {
+
+ /* release dma memory on failure. */
+ isci_request_free(isci_host, request);
+ request = NULL;
+ ret = SCI_FAILURE;
+ }
+
+ *isci_request = request;
+ return ret;
+}
+
+
+/**
+ * isci_request_process_response_iu() - This function sets the status and
+ * response iu, in the task struct, from the request object for the upper
+ * layer driver.
+ * @sas_task: This parameter is the task struct from the upper layer driver.
+ * @resp_iu: This parameter points to the response iu of the completed request.
+ * @dev: This parameter specifies the linux device struct.
+ *
+ * none.
+ */
+static void isci_request_process_response_iu(
+ struct sas_task *task,
+ struct ssp_response_iu *resp_iu,
+ struct device *dev)
+{
+ dev_dbg(dev,
+ "%s: resp_iu = %p "
+ "resp_iu->status = 0x%x,\nresp_iu->datapres = %d "
+ "resp_iu->response_data_len = %x, "
+ "resp_iu->sense_data_len = %x\nrepsonse data: ",
+ __func__,
+ resp_iu,
+ resp_iu->status,
+ resp_iu->datapres,
+ resp_iu->response_data_len,
+ resp_iu->sense_data_len);
+
+ task->task_status.stat = resp_iu->status;
+
+ /* libsas updates the task status fields based on the response iu. */
+ sas_ssp_task_response(dev, task, resp_iu);
+}
+
+/**
+ * isci_request_set_open_reject_status() - This function prepares the I/O
+ * completion for OPEN_REJECT conditions.
+ * @request: This parameter is the completed isci_request object.
+ * @response_ptr: This parameter specifies the service response for the I/O.
+ * @status_ptr: This parameter specifies the exec status for the I/O.
+ * @complete_to_host_ptr: This parameter specifies the action to be taken by
+ * the LLDD with respect to completing this request or forcing an abort
+ * condition on the I/O.
+ * @open_rej_reason: This parameter specifies the encoded reason for the
+ * abandon-class reject.
+ *
+ * none.
+ */
+static void isci_request_set_open_reject_status(
+ struct isci_request *request,
+ struct sas_task *task,
+ enum service_response *response_ptr,
+ enum exec_status *status_ptr,
+ enum isci_completion_selection *complete_to_host_ptr,
+ enum sas_open_rej_reason open_rej_reason)
+{
+ /* Task in the target is done. */
+ request->complete_in_target = true;
+ *response_ptr = SAS_TASK_UNDELIVERED;
+ *status_ptr = SAS_OPEN_REJECT;
+ *complete_to_host_ptr = isci_perform_normal_io_completion;
+ task->task_status.open_rej_reason = open_rej_reason;
+}
+
+/**
+ * isci_request_handle_controller_specific_errors() - This function decodes
+ * controller-specific I/O completion error conditions.
+ * @request: This parameter is the completed isci_request object.
+ * @response_ptr: This parameter specifies the service response for the I/O.
+ * @status_ptr: This parameter specifies the exec status for the I/O.
+ * @complete_to_host_ptr: This parameter specifies the action to be taken by
+ * the LLDD with respect to completing this request or forcing an abort
+ * condition on the I/O.
+ *
+ * none.
+ */
+static void isci_request_handle_controller_specific_errors(
+ struct isci_remote_device *isci_device,
+ struct isci_request *request,
+ struct sas_task *task,
+ enum service_response *response_ptr,
+ enum exec_status *status_ptr,
+ enum isci_completion_selection *complete_to_host_ptr)
+{
+ unsigned int cstatus;
+
+ cstatus = scic_request_get_controller_status(
+ request->sci_request_handle
+ );
+
+ dev_dbg(&request->isci_host->pdev->dev,
+ "%s: %p SCI_FAILURE_CONTROLLER_SPECIFIC_IO_ERR "
+ "- controller status = 0x%x\n",
+ __func__, request, cstatus);
+
+ /* Decode the controller-specific errors; most
+ * important is to recognize those conditions in which
+ * the target may still have a task outstanding that
+ * must be aborted.
+ *
+ * Note that there are SCU completion codes being
+ * named in the decode below for which SCIC has already
+ * done work to handle them in a way other than as
+ * a controller-specific completion code; these are left
+ * in the decode below for completeness sake.
+ */
+ switch (cstatus) {
+ case SCU_TASK_DONE_DMASETUP_DIRERR:
+ /* Also SCU_TASK_DONE_SMP_FRM_TYPE_ERR: */
+ case SCU_TASK_DONE_XFERCNT_ERR:
+ /* Also SCU_TASK_DONE_SMP_UFI_ERR: */
+ if (task->task_proto == SAS_PROTOCOL_SMP) {
+ /* SCU_TASK_DONE_SMP_UFI_ERR == Task Done. */
+ *response_ptr = SAS_TASK_COMPLETE;
+
+ /* See if the device has been/is being stopped. Note
+ * that we ignore the quiesce state, since we are
+ * concerned about the actual device state.
+ */
+ if ((isci_device->status == isci_stopping) ||
+ (isci_device->status == isci_stopped))
+ *status_ptr = SAS_DEVICE_UNKNOWN;
+ else
+ *status_ptr = SAS_ABORTED_TASK;
+
+ request->complete_in_target = true;
+
+ *complete_to_host_ptr =
+ isci_perform_normal_io_completion;
+ } else {
+ /* Task in the target is not done. */
+ *response_ptr = SAS_TASK_UNDELIVERED;
+
+ if ((isci_device->status == isci_stopping) ||
+ (isci_device->status == isci_stopped))
+ *status_ptr = SAS_DEVICE_UNKNOWN;
+ else
+ *status_ptr = SAM_STAT_TASK_ABORTED;
+
+ request->complete_in_target = false;
+
+ *complete_to_host_ptr =
+ isci_perform_error_io_completion;
+ }
+
+ break;
+
+ case SCU_TASK_DONE_CRC_ERR:
+ case SCU_TASK_DONE_NAK_CMD_ERR:
+ case SCU_TASK_DONE_EXCESS_DATA:
+ case SCU_TASK_DONE_UNEXP_FIS:
+ /* Also SCU_TASK_DONE_UNEXP_RESP: */
+ case SCU_TASK_DONE_VIIT_ENTRY_NV: /* TODO - conditions? */
+ case SCU_TASK_DONE_IIT_ENTRY_NV: /* TODO - conditions? */
+ case SCU_TASK_DONE_RNCNV_OUTBOUND: /* TODO - conditions? */
+ /* These are conditions in which the target
+ * has completed the task, so that no cleanup
+ * is necessary.
+ */
+ *response_ptr = SAS_TASK_COMPLETE;
+
+ /* See if the device has been/is being stopped. Note
+ * that we ignore the quiesce state, since we are
+ * concerned about the actual device state.
+ */
+ if ((isci_device->status == isci_stopping) ||
+ (isci_device->status == isci_stopped))
+ *status_ptr = SAS_DEVICE_UNKNOWN;
+ else
+ *status_ptr = SAS_ABORTED_TASK;
+
+ request->complete_in_target = true;
+
+ *complete_to_host_ptr = isci_perform_normal_io_completion;
+ break;
+
+
+ /* Note that the only open reject completion codes seen here will be
+ * abandon-class codes; all others are automatically retried in the SCU.
+ */
+ case SCU_TASK_OPEN_REJECT_WRONG_DESTINATION:
+
+ isci_request_set_open_reject_status(
+ request, task, response_ptr, status_ptr,
+ complete_to_host_ptr, SAS_OREJ_WRONG_DEST);
+ break;
+
+ case SCU_TASK_OPEN_REJECT_ZONE_VIOLATION:
+
+ /* Note - the return of AB0 will change when
+ * libsas implements detection of zone violations.
+ */
+ isci_request_set_open_reject_status(
+ request, task, response_ptr, status_ptr,
+ complete_to_host_ptr, SAS_OREJ_RESV_AB0);
+ break;
+
+ case SCU_TASK_OPEN_REJECT_RESERVED_ABANDON_1:
+
+ isci_request_set_open_reject_status(
+ request, task, response_ptr, status_ptr,
+ complete_to_host_ptr, SAS_OREJ_RESV_AB1);
+ break;
+
+ case SCU_TASK_OPEN_REJECT_RESERVED_ABANDON_2:
+
+ isci_request_set_open_reject_status(
+ request, task, response_ptr, status_ptr,
+ complete_to_host_ptr, SAS_OREJ_RESV_AB2);
+ break;
+
+ case SCU_TASK_OPEN_REJECT_RESERVED_ABANDON_3:
+
+ isci_request_set_open_reject_status(
+ request, task, response_ptr, status_ptr,
+ complete_to_host_ptr, SAS_OREJ_RESV_AB3);
+ break;
+
+ case SCU_TASK_OPEN_REJECT_BAD_DESTINATION:
+
+ isci_request_set_open_reject_status(
+ request, task, response_ptr, status_ptr,
+ complete_to_host_ptr, SAS_OREJ_BAD_DEST);
+ break;
+
+ case SCU_TASK_OPEN_REJECT_STP_RESOURCES_BUSY:
+
+ isci_request_set_open_reject_status(
+ request, task, response_ptr, status_ptr,
+ complete_to_host_ptr, SAS_OREJ_STP_NORES);
+ break;
+
+ case SCU_TASK_OPEN_REJECT_PROTOCOL_NOT_SUPPORTED:
+
+ isci_request_set_open_reject_status(
+ request, task, response_ptr, status_ptr,
+ complete_to_host_ptr, SAS_OREJ_EPROTO);
+ break;
+
+ case SCU_TASK_OPEN_REJECT_CONNECTION_RATE_NOT_SUPPORTED:
+
+ isci_request_set_open_reject_status(
+ request, task, response_ptr, status_ptr,
+ complete_to_host_ptr, SAS_OREJ_CONN_RATE);
+ break;
+
+ case SCU_TASK_DONE_LL_R_ERR:
+ /* Also SCU_TASK_DONE_ACK_NAK_TO: */
+ case SCU_TASK_DONE_LL_PERR:
+ case SCU_TASK_DONE_LL_SY_TERM:
+ /* Also SCU_TASK_DONE_NAK_ERR:*/
+ case SCU_TASK_DONE_LL_LF_TERM:
+ /* Also SCU_TASK_DONE_DATA_LEN_ERR: */
+ case SCU_TASK_DONE_LL_ABORT_ERR:
+ case SCU_TASK_DONE_SEQ_INV_TYPE:
+ /* Also SCU_TASK_DONE_UNEXP_XR: */
+ case SCU_TASK_DONE_XR_IU_LEN_ERR:
+ case SCU_TASK_DONE_INV_FIS_LEN:
+ /* Also SCU_TASK_DONE_XR_WD_LEN: */
+ case SCU_TASK_DONE_SDMA_ERR:
+ case SCU_TASK_DONE_OFFSET_ERR:
+ case SCU_TASK_DONE_MAX_PLD_ERR:
+ case SCU_TASK_DONE_LF_ERR:
+ case SCU_TASK_DONE_SMP_RESP_TO_ERR: /* Escalate to dev reset? */
+ case SCU_TASK_DONE_SMP_LL_RX_ERR:
+ case SCU_TASK_DONE_UNEXP_DATA:
+ case SCU_TASK_DONE_UNEXP_SDBFIS:
+ case SCU_TASK_DONE_REG_ERR:
+ case SCU_TASK_DONE_SDB_ERR:
+ case SCU_TASK_DONE_TASK_ABORT:
+ default:
+ /* Task in the target is not done. */
+ *response_ptr = SAS_TASK_UNDELIVERED;
+ *status_ptr = SAM_STAT_TASK_ABORTED;
+ request->complete_in_target = false;
+
+ *complete_to_host_ptr = isci_perform_error_io_completion;
+ break;
+ }
+}
+
+/**
+ * isci_task_save_for_upper_layer_completion() - This function saves the
+ * request for later completion to the upper layer driver.
+ * @host: This parameter is a pointer to the host on which the the request
+ * should be queued (either as an error or success).
+ * @request: This parameter is the completed request.
+ * @response: This parameter is the response code for the completed task.
+ * @status: This parameter is the status code for the completed task.
+ *
+ * none.
+ */
+static void isci_task_save_for_upper_layer_completion(
+ struct isci_host *host,
+ struct isci_request *request,
+ enum service_response response,
+ enum exec_status status,
+ enum isci_completion_selection task_notification_selection)
+{
+ struct sas_task *task = isci_request_access_task(request);
+
+ isci_task_set_completion_status(task, response, status,
+ task_notification_selection);
+
+
+ /* Tasks aborted specifically by a call to the lldd_abort_task
+ * function should not be completed to the host in the regular path.
+ */
+ switch (task_notification_selection) {
+
+ case isci_perform_normal_io_completion:
+
+ /* Normal notification (task_done) */
+ dev_dbg(&host->pdev->dev,
+ "%s: Normal - task = %p, response=%d, status=%d\n",
+ __func__,
+ task,
+ response,
+ status);
+ /* Add to the completed list. */
+ list_add(&request->completed_node,
+ &host->requests_to_complete);
+ break;
+
+ case isci_perform_aborted_io_completion:
+ /*
+ * No notification because this request is already
+ * in the abort path.
+ */
+ dev_warn(&host->pdev->dev,
+ "%s: Aborted - task = %p, response=%d, status=%d\n",
+ __func__,
+ task,
+ response,
+ status);
+ break;
+
+ case isci_perform_error_io_completion:
+ /* Use sas_task_abort */
+ dev_warn(&host->pdev->dev,
+ "%s: Error - task = %p, response=%d, status=%d\n",
+ __func__,
+ task,
+ response,
+ status);
+ /* Add to the aborted list. */
+ list_add(&request->completed_node,
+ &host->requests_to_abort);
+ break;
+
+ default:
+ dev_warn(&host->pdev->dev,
+ "%s: Unknown - task = %p, response=%d, status=%d\n",
+ __func__,
+ task,
+ response,
+ status);
+
+ /* Add to the aborted list. */
+ list_add(&request->completed_node,
+ &host->requests_to_abort);
+ break;
+ }
+}
+
+/**
+ * isci_request_io_request_complete() - This function is called by the sci core
+ * when an io request completes.
+ * @isci_host: This parameter specifies the ISCI host object
+ * @request: This parameter is the completed isci_request object.
+ * @completion_status: This parameter specifies the completion status from the
+ * sci core.
+ *
+ * none.
+ */
+void isci_request_io_request_complete(
+ struct isci_host *isci_host,
+ struct isci_request *request,
+ enum sci_io_status completion_status)
+{
+ struct sas_task *task = isci_request_access_task(request);
+ struct ssp_response_iu *resp_iu;
+ void *resp_buf;
+ unsigned long task_flags;
+ unsigned long state_flags;
+ struct completion *io_request_completion;
+ struct isci_remote_device *isci_device = request->isci_device;
+ enum service_response response = SAS_TASK_UNDELIVERED;
+ enum exec_status status = SAS_ABORTED_TASK;
+ enum isci_request_status request_status;
+ enum isci_completion_selection complete_to_host
+ = isci_perform_normal_io_completion;
+
+ dev_dbg(&isci_host->pdev->dev,
+ "%s: request = %p, task = %p,\n"
+ "task->data_dir = %d completion_status = 0x%x\n",
+ __func__,
+ request,
+ task,
+ task->data_dir,
+ completion_status);
+
+ spin_lock_irqsave(&request->state_lock, state_flags);
+ request_status = isci_request_get_state(request);
+ spin_unlock_irqrestore(&request->state_lock, state_flags);
+
+ /* Decode the request status. Note that if the request has been
+ * aborted by a task management function, we don't care
+ * what the status is.
+ */
+ switch (request_status) {
+
+ case aborted:
+ /* "aborted" indicates that the request was aborted by a task
+ * management function, since once a task management request is
+ * perfomed by the device, the request only completes because
+ * of the subsequent driver terminate.
+ *
+ * Aborted also means an external thread is explicitly managing
+ * this request, so that we do not complete it up the stack.
+ *
+ * The target is still there (since the TMF was successful).
+ */
+ request->complete_in_target = true;
+ response = SAS_TASK_COMPLETE;
+
+ /* See if the device has been/is being stopped. Note
+ * that we ignore the quiesce state, since we are
+ * concerned about the actual device state.
+ */
+ if ((isci_device->status == isci_stopping)
+ || (isci_device->status == isci_stopped)
+ )
+ status = SAS_DEVICE_UNKNOWN;
+ else
+ status = SAS_ABORTED_TASK;
+
+ complete_to_host = isci_perform_aborted_io_completion;
+ /* This was an aborted request. */
+ break;
+
+ case aborting:
+ /* aborting means that the task management function tried and
+ * failed to abort the request. We need to note the request
+ * as SAS_TASK_UNDELIVERED, so that the scsi mid layer marks the
+ * target as down.
+ *
+ * Aborting also means an external thread is explicitly managing
+ * this request, so that we do not complete it up the stack.
+ */
+ request->complete_in_target = true;
+ response = SAS_TASK_UNDELIVERED;
+
+ if ((isci_device->status == isci_stopping) ||
+ (isci_device->status == isci_stopped))
+ /* The device has been /is being stopped. Note that
+ * we ignore the quiesce state, since we are
+ * concerned about the actual device state.
+ */
+ status = SAS_DEVICE_UNKNOWN;
+ else
+ status = SAS_PHY_DOWN;
+
+ complete_to_host = isci_perform_aborted_io_completion;
+
+ /* This was an aborted request. */
+ break;
+
+ case terminating:
+
+ /* This was an terminated request. This happens when
+ * the I/O is being terminated because of an action on
+ * the device (reset, tear down, etc.), and the I/O needs
+ * to be completed up the stack.
+ */
+ request->complete_in_target = true;
+ response = SAS_TASK_UNDELIVERED;
+
+ /* See if the device has been/is being stopped. Note
+ * that we ignore the quiesce state, since we are
+ * concerned about the actual device state.
+ */
+ if ((isci_device->status == isci_stopping) ||
+ (isci_device->status == isci_stopped))
+ status = SAS_DEVICE_UNKNOWN;
+ else
+ status = SAS_ABORTED_TASK;
+
+ complete_to_host = isci_perform_normal_io_completion;
+
+ /* This was a terminated request. */
+ break;
+
+ default:
+
+ /* This is an active request being completed from the core. */
+ switch (completion_status) {
+
+ case SCI_IO_FAILURE_RESPONSE_VALID:
+ dev_dbg(&isci_host->pdev->dev,
+ "%s: SCI_IO_FAILURE_RESPONSE_VALID (%p/%p)\n",
+ __func__,
+ request,
+ task);
+
+ if (sas_protocol_ata(task->task_proto)) {
+ resp_buf
+ = scic_stp_io_request_get_d2h_reg_address(
+ request->sci_request_handle
+ );
+ isci_request_process_stp_response(task,
+ resp_buf
+ );
+
+ } else if (SAS_PROTOCOL_SSP == task->task_proto) {
+
+ /* crack the iu response buffer. */
+ resp_iu
+ = scic_io_request_get_response_iu_address(
+ request->sci_request_handle
+ );
+
+ isci_request_process_response_iu(task, resp_iu,
+ &isci_host->pdev->dev
+ );
+
+ } else if (SAS_PROTOCOL_SMP == task->task_proto) {
+
+ dev_err(&isci_host->pdev->dev,
+ "%s: SCI_IO_FAILURE_RESPONSE_VALID: "
+ "SAS_PROTOCOL_SMP protocol\n",
+ __func__);
+
+ } else
+ dev_err(&isci_host->pdev->dev,
+ "%s: unknown protocol\n", __func__);
+
+ /* use the task status set in the task struct by the
+ * isci_request_process_response_iu call.
+ */
+ request->complete_in_target = true;
+ response = task->task_status.resp;
+ status = task->task_status.stat;
+ break;
+
+ case SCI_IO_SUCCESS:
+ case SCI_IO_SUCCESS_IO_DONE_EARLY:
+
+ response = SAS_TASK_COMPLETE;
+ status = SAM_STAT_GOOD;
+ request->complete_in_target = true;
+
+ if (task->task_proto == SAS_PROTOCOL_SMP) {
+
+ u8 *command_iu_address
+ = scic_io_request_get_command_iu_address(
+ request->sci_request_handle
+ );
+
+ dev_dbg(&isci_host->pdev->dev,
+ "%s: SMP protocol completion\n",
+ __func__);
+
+ sg_copy_from_buffer(
+ &task->smp_task.smp_resp, 1,
+ command_iu_address
+ + sizeof(struct smp_request),
+ sizeof(struct smp_resp)
+ );
+ } else if (completion_status
+ == SCI_IO_SUCCESS_IO_DONE_EARLY) {
+
+ /* This was an SSP / STP / SATA transfer.
+ * There is a possibility that less data than
+ * the maximum was transferred.
+ */
+ u32 transferred_length
+ = scic_io_request_get_number_of_bytes_transferred(
+ request->sci_request_handle);
+
+ task->task_status.residual
+ = task->total_xfer_len - transferred_length;
+
+ /* If there were residual bytes, call this an
+ * underrun.
+ */
+ if (task->task_status.residual != 0)
+ status = SAS_DATA_UNDERRUN;
+
+ dev_dbg(&isci_host->pdev->dev,
+ "%s: SCI_IO_SUCCESS_IO_DONE_EARLY %d\n",
+ __func__,
+ status);
+
+ } else
+ dev_dbg(&isci_host->pdev->dev,
+ "%s: SCI_IO_SUCCESS\n",
+ __func__);
+
+ break;
+
+ case SCI_IO_FAILURE_TERMINATED:
+ dev_dbg(&isci_host->pdev->dev,
+ "%s: SCI_IO_FAILURE_TERMINATED (%p/%p)\n",
+ __func__,
+ request,
+ task);
+
+ /* The request was terminated explicitly. No handling
+ * is needed in the SCSI error handler path.
+ */
+ request->complete_in_target = true;
+ response = SAS_TASK_UNDELIVERED;
+
+ /* See if the device has been/is being stopped. Note
+ * that we ignore the quiesce state, since we are
+ * concerned about the actual device state.
+ */
+ if ((isci_device->status == isci_stopping) ||
+ (isci_device->status == isci_stopped))
+ status = SAS_DEVICE_UNKNOWN;
+ else
+ status = SAS_ABORTED_TASK;
+
+ complete_to_host = isci_perform_normal_io_completion;
+ break;
+
+ case SCI_FAILURE_CONTROLLER_SPECIFIC_IO_ERR:
+
+ isci_request_handle_controller_specific_errors(
+ isci_device, request, task, &response, &status,
+ &complete_to_host);
+
+ break;
+
+ case SCI_IO_FAILURE_REMOTE_DEVICE_RESET_REQUIRED:
+ /* This is a special case, in that the I/O completion
+ * is telling us that the device needs a reset.
+ * In order for the device reset condition to be
+ * noticed, the I/O has to be handled in the error
+ * handler. Set the reset flag and cause the
+ * SCSI error thread to be scheduled.
+ */
+ spin_lock_irqsave(&task->task_state_lock, task_flags);
+ task->task_state_flags |= SAS_TASK_NEED_DEV_RESET;
+ spin_unlock_irqrestore(&task->task_state_lock, task_flags);
+
+ complete_to_host = isci_perform_error_io_completion;
+ request->complete_in_target = false;
+ break;
+
+ default:
+ /* Catch any otherwise unhandled error codes here. */
+ dev_warn(&isci_host->pdev->dev,
+ "%s: invalid completion code: 0x%x - "
+ "isci_request = %p\n",
+ __func__, completion_status, request);
+
+ response = SAS_TASK_UNDELIVERED;
+
+ /* See if the device has been/is being stopped. Note
+ * that we ignore the quiesce state, since we are
+ * concerned about the actual device state.
+ */
+ if ((isci_device->status == isci_stopping) ||
+ (isci_device->status == isci_stopped))
+ status = SAS_DEVICE_UNKNOWN;
+ else
+ status = SAS_ABORTED_TASK;
+
+ complete_to_host = isci_perform_error_io_completion;
+ request->complete_in_target = false;
+ break;
+ }
+ break;
+ }
+
+ isci_request_unmap_sgl(request, isci_host->pdev);
+
+ /* Put the completed request on the correct list */
+ isci_task_save_for_upper_layer_completion(isci_host, request, response,
+ status, complete_to_host
+ );
+
+ /* complete the io request to the core. */
+ scic_controller_complete_io(
+ isci_host->core_controller,
+ isci_device->sci_device_handle,
+ request->sci_request_handle
+ );
+ /* NULL the request handle so it cannot be completed or
+ * terminated again, and to cause any calls into abort
+ * task to recognize the already completed case.
+ */
+ request->sci_request_handle = NULL;
+
+ /* Only remove the request from the remote device list
+ * of pending requests if we have not requested error
+ * handling on this request.
+ */
+ if (complete_to_host != isci_perform_error_io_completion)
+ list_del_init(&request->dev_node);
+
+
+ /* Save possible completion ptr. */
+ io_request_completion = request->io_request_completion;
+
+ if (io_request_completion) {
+
+ /* This is inherantly a regular I/O request,
+ * since we are currently in the regular
+ * I/O completion callback function.
+ * Signal whoever is waiting that this
+ * request is complete.
+ */
+ complete(io_request_completion);
+ }
+
+ isci_host_can_dequeue(isci_host, 1);
+}
+
+/**
+ * isci_request_io_request_get_transfer_length() - This function is called by
+ * the sci core to retrieve the transfer length for a given request.
+ * @request: This parameter is the isci_request object.
+ *
+ * length of transfer for specified request.
+ */
+u32 isci_request_io_request_get_transfer_length(struct isci_request *request)
+{
+ struct sas_task *task = isci_request_access_task(request);
+
+ dev_dbg(&request->isci_host->pdev->dev,
+ "%s: total_xfer_len: %d\n",
+ __func__,
+ task->total_xfer_len);
+ return task->total_xfer_len;
+}
+
+
+/**
+ * isci_request_io_request_get_data_direction() - This function is called by
+ * the sci core to retrieve the data direction for a given request.
+ * @request: This parameter is the isci_request object.
+ *
+ * data direction for specified request.
+ */
+SCI_IO_REQUEST_DATA_DIRECTION isci_request_io_request_get_data_direction(
+ struct isci_request *request)
+{
+ struct sas_task *task = isci_request_access_task(request);
+ SCI_IO_REQUEST_DATA_DIRECTION ret;
+
+ switch (task->data_dir) {
+
+ case DMA_FROM_DEVICE:
+ ret = SCI_IO_REQUEST_DATA_IN;
+ dev_dbg(&request->isci_host->pdev->dev,
+ "%s: request=%p, FROM_DEVICE\n",
+ __func__,
+ request);
+ break;
+
+ case DMA_TO_DEVICE:
+ ret = SCI_IO_REQUEST_DATA_OUT;
+ dev_dbg(&request->isci_host->pdev->dev,
+ "%s: request=%p, TO_DEVICE\n",
+ __func__,
+ request);
+ break;
+
+ case DMA_BIDIRECTIONAL:
+ case DMA_NONE:
+ default:
+ ret = SCI_IO_REQUEST_NO_DATA;
+ dev_dbg(&request->isci_host->pdev->dev,
+ "%s: request=%p, unhandled direction case, "
+ "data_dir=%d\n",
+ __func__,
+ request,
+ task->data_dir);
+ break;
+
+ }
+ return ret;
+}
+
+/**
+ * isci_request_sge_get_address_field() - This function is called by the sci
+ * core to retrieve the address field contents for a given sge.
+ * @request: This parameter is the isci_request object.
+ * @sge_address: This parameter is the sge.
+ *
+ * physical address in the specified sge.
+ */
+dma_addr_t isci_request_sge_get_address_field(
+ struct isci_request *request,
+ void *sge_address)
+{
+ struct sas_task *task = isci_request_access_task(request);
+ dma_addr_t ret;
+ struct isci_host *isci_host = isci_host_from_sas_ha(
+ task->dev->port->ha);
+
+ dev_dbg(&isci_host->pdev->dev,
+ "%s: request = %p, sge_address = %p\n",
+ __func__,
+ request,
+ sge_address);
+
+ if (task->data_dir == PCI_DMA_NONE)
+ return 0;
+
+ /* the case where num_scatter == 0 is special, in that
+ * task->scatter is the actual buffer address, not an sgl.
+ * so a map single is required here.
+ */
+ if ((task->num_scatter == 0) &&
+ !sas_protocol_ata(task->task_proto)) {
+ ret = dma_map_single(
+ &isci_host->pdev->dev,
+ task->scatter,
+ task->total_xfer_len,
+ task->data_dir
+ );
+ request->zero_scatter_daddr = ret;
+ } else
+ ret = sg_dma_address(((struct scatterlist *)sge_address));
+
+ dev_dbg(&isci_host->pdev->dev,
+ "%s: bus address = %lx\n",
+ __func__,
+ (unsigned long)ret);
+
+ return ret;
+}
+
+
+/**
+ * isci_request_sge_get_length_field() - This function is called by the sci
+ * core to retrieve the length field contents for a given sge.
+ * @request: This parameter is the isci_request object.
+ * @sge_address: This parameter is the sge.
+ *
+ * length field value in the specified sge.
+ */
+u32 isci_request_sge_get_length_field(
+ struct isci_request *request,
+ void *sge_address)
+{
+ struct sas_task *task = isci_request_access_task(request);
+ int ret;
+
+ dev_dbg(&request->isci_host->pdev->dev,
+ "%s: request = %p, sge_address = %p\n",
+ __func__,
+ request,
+ sge_address);
+
+ if (task->data_dir == PCI_DMA_NONE)
+ return 0;
+
+ /* the case where num_scatter == 0 is special, in that
+ * task->scatter is the actual buffer address, not an sgl.
+ * so we return total_xfer_len here.
+ */
+ if (task->num_scatter == 0)
+ ret = task->total_xfer_len;
+ else
+ ret = sg_dma_len((struct scatterlist *)sge_address);
+
+ dev_dbg(&request->isci_host->pdev->dev,
+ "%s: len = %d\n",
+ __func__,
+ ret);
+
+ return ret;
+}
+
+
+/**
+ * isci_request_ssp_io_request_get_cdb_address() - This function is called by
+ * the sci core to retrieve the cdb address for a given request.
+ * @request: This parameter is the isci_request object.
+ *
+ * cdb address for specified request.
+ */
+void *isci_request_ssp_io_request_get_cdb_address(
+ struct isci_request *request)
+{
+ struct sas_task *task = isci_request_access_task(request);
+
+ dev_dbg(&request->isci_host->pdev->dev,
+ "%s: request->task->ssp_task.cdb = %p\n",
+ __func__,
+ task->ssp_task.cdb);
+ return task->ssp_task.cdb;
+}
+
+
+/**
+ * isci_request_ssp_io_request_get_cdb_length() - This function is called by
+ * the sci core to retrieve the cdb length for a given request.
+ * @request: This parameter is the isci_request object.
+ *
+ * cdb length for specified request.
+ */
+u32 isci_request_ssp_io_request_get_cdb_length(
+ struct isci_request *request)
+{
+ return 16;
+}
+
+
+/**
+ * isci_request_ssp_io_request_get_lun() - This function is called by the sci
+ * core to retrieve the lun for a given request.
+ * @request: This parameter is the isci_request object.
+ *
+ * lun for specified request.
+ */
+u32 isci_request_ssp_io_request_get_lun(
+ struct isci_request *request)
+{
+ struct sas_task *task = isci_request_access_task(request);
+
+#ifdef DEBUG
+ int i;
+
+ for (i = 0; i < 8; i++)
+ dev_dbg(&request->isci_host->pdev->dev,
+ "%s: request->task->ssp_task.LUN[%d] = %x\n",
+ __func__, i, request->task->ssp_task.LUN[i]);
+
+#endif
+
+ return task->ssp_task.LUN[0];
+}
+
+
+/**
+ * isci_request_ssp_io_request_get_task_attribute() - This function is called
+ * by the sci core to retrieve the task attribute for a given request.
+ * @request: This parameter is the isci_request object.
+ *
+ * task attribute for specified request.
+ */
+u32 isci_request_ssp_io_request_get_task_attribute(
+ struct isci_request *request)
+{
+ struct sas_task *task = isci_request_access_task(request);
+
+ dev_dbg(&request->isci_host->pdev->dev,
+ "%s: request->task->ssp_task.task_attr = %x\n",
+ __func__,
+ task->ssp_task.task_attr);
+
+ return task->ssp_task.task_attr;
+}
+
+
+/**
+ * isci_request_ssp_io_request_get_command_priority() - This function is called
+ * by the sci core to retrieve the command priority for a given request.
+ * @request: This parameter is the isci_request object.
+ *
+ * command priority for specified request.
+ */
+u32 isci_request_ssp_io_request_get_command_priority(
+ struct isci_request *request)
+{
+ struct sas_task *task = isci_request_access_task(request);
+
+ dev_dbg(&request->isci_host->pdev->dev,
+ "%s: request->task->ssp_task.task_prio = %x\n",
+ __func__,
+ task->ssp_task.task_prio);
+
+ return task->ssp_task.task_prio;
+}
diff --git a/drivers/scsi/isci/request.h b/drivers/scsi/isci/request.h
new file mode 100644
index 000000000000..5079d4a7c41b
--- /dev/null
+++ b/drivers/scsi/isci/request.h
@@ -0,0 +1,429 @@
+/*
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Intel Corporation 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
+ * OWNER 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.
+ */
+
+#if !defined(_ISCI_REQUEST_H_)
+#define _ISCI_REQUEST_H_
+
+#include "isci.h"
+
+/**
+ * struct isci_request_status - This enum defines the possible states of an I/O
+ * request.
+ *
+ *
+ */
+enum isci_request_status {
+ unallocated = 0x00,
+ allocated = 0x01,
+ started = 0x02,
+ completed = 0x03,
+ aborting = 0x04,
+ aborted = 0x05,
+ terminating = 0x06
+};
+
+enum task_type {
+ io_task = 0,
+ tmf_task = 1
+};
+
+/**
+ * struct isci_request - This class represents the request object used to track
+ * IO, smp and TMF request internal. It wraps the SCIC request object.
+ *
+ *
+ */
+struct isci_request {
+
+ struct scic_sds_request *sci_request_handle;
+
+ enum isci_request_status status;
+ enum task_type ttype;
+ unsigned short io_tag;
+ bool complete_in_target;
+
+ union ttype_ptr_union {
+ struct sas_task *io_task_ptr; /* When ttype==io_task */
+ struct isci_tmf *tmf_task_ptr; /* When ttype==tmf_task */
+ } ttype_ptr;
+ struct isci_host *isci_host;
+ struct isci_remote_device *isci_device;
+ /* For use in the requests_to_{complete|abort} lists: */
+ struct list_head completed_node;
+ /* For use in the reqs_in_process list: */
+ struct list_head dev_node;
+ void *sci_request_mem_ptr;
+ spinlock_t state_lock;
+ dma_addr_t request_daddr;
+ dma_addr_t zero_scatter_daddr;
+
+ unsigned int num_sg_entries; /* returned by pci_alloc_sg */
+ unsigned int request_alloc_size; /* size of block from dma_pool_alloc */
+
+ /** Note: "io_request_completion" is completed in two different ways
+ * depending on whether this is a TMF or regular request.
+ * - TMF requests are completed in the thread that started them;
+ * - regular requests are completed in the request completion callback
+ * function.
+ * This difference in operation allows the aborter of a TMF request
+ * to be sure that once the TMF request completes, the I/O that the
+ * TMF was aborting is guaranteed to have completed.
+ */
+ struct completion *io_request_completion;
+};
+
+/**
+ * This function gets the status of the request object.
+ * @request: This parameter points to the isci_request object
+ *
+ * status of the object as a isci_request_status enum.
+ */
+static inline
+enum isci_request_status isci_request_get_state(
+ struct isci_request *isci_request)
+{
+ BUG_ON(isci_request == NULL);
+
+ /*probably a bad sign... */
+ if (isci_request->status == unallocated)
+ dev_warn(&isci_request->isci_host->pdev->dev,
+ "%s: isci_request->status == unallocated\n",
+ __func__);
+
+ return isci_request->status;
+}
+
+
+/**
+ * isci_request_change_state() - This function sets the status of the request
+ * object.
+ * @request: This parameter points to the isci_request object
+ * @status: This Parameter is the new status of the object
+ *
+ */
+static inline enum isci_request_status isci_request_change_state(
+ struct isci_request *isci_request,
+ enum isci_request_status status)
+{
+ enum isci_request_status old_state;
+ unsigned long flags;
+
+ dev_dbg(&isci_request->isci_host->pdev->dev,
+ "%s: isci_request = %p, state = 0x%x\n",
+ __func__,
+ isci_request,
+ status);
+
+ BUG_ON(isci_request == NULL);
+
+ spin_lock_irqsave(&isci_request->state_lock, flags);
+ old_state = isci_request->status;
+ isci_request->status = status;
+ spin_unlock_irqrestore(&isci_request->state_lock, flags);
+
+ return old_state;
+}
+
+/**
+ * isci_request_change_started_to_newstate() - This function sets the status of
+ * the request object.
+ * @request: This parameter points to the isci_request object
+ * @status: This Parameter is the new status of the object
+ *
+ * state previous to any change.
+ */
+static inline enum isci_request_status isci_request_change_started_to_newstate(
+ struct isci_request *isci_request,
+ struct completion *completion_ptr,
+ enum isci_request_status newstate)
+{
+ enum isci_request_status old_state;
+ unsigned long flags;
+
+ BUG_ON(isci_request == NULL);
+
+ spin_lock_irqsave(&isci_request->state_lock, flags);
+
+ old_state = isci_request->status;
+
+ if (old_state == started) {
+ BUG_ON(isci_request->io_request_completion != NULL);
+
+ isci_request->io_request_completion = completion_ptr;
+ isci_request->status = newstate;
+ }
+ spin_unlock_irqrestore(&isci_request->state_lock, flags);
+
+ dev_dbg(&isci_request->isci_host->pdev->dev,
+ "%s: isci_request = %p, old_state = 0x%x\n",
+ __func__,
+ isci_request,
+ old_state);
+
+ return old_state;
+}
+
+/**
+ * isci_request_change_started_to_aborted() - This function sets the status of
+ * the request object.
+ * @request: This parameter points to the isci_request object
+ * @completion_ptr: This parameter is saved as the kernel completion structure
+ * signalled when the old request completes.
+ *
+ * state previous to any change.
+ */
+static inline enum isci_request_status isci_request_change_started_to_aborted(
+ struct isci_request *isci_request,
+ struct completion *completion_ptr)
+{
+ return isci_request_change_started_to_newstate(
+ isci_request, completion_ptr, aborted
+ );
+}
+/**
+ * isci_request_free() - This function frees the request object.
+ * @isci_host: This parameter specifies the ISCI host object
+ * @isci_request: This parameter points to the isci_request object
+ *
+ */
+static inline void isci_request_free(
+ struct isci_host *isci_host,
+ struct isci_request *isci_request)
+{
+ BUG_ON(isci_request == NULL);
+
+ /* release the dma memory if we fail. */
+ dma_pool_free(isci_host->dma_pool, isci_request,
+ isci_request->request_daddr);
+}
+
+
+/* #define ISCI_REQUEST_VALIDATE_ACCESS
+ */
+
+#ifdef ISCI_REQUEST_VALIDATE_ACCESS
+
+static inline
+struct sas_task *isci_request_access_task(struct isci_request *isci_request)
+{
+ BUG_ON(isci_request->ttype != io_task);
+ return isci_request->ttype_ptr.io_task_ptr;
+}
+
+static inline
+struct isci_tmf *isci_request_access_tmf(struct isci_request *isci_request)
+{
+ BUG_ON(isci_request->ttype != tmf_task);
+ return isci_request->ttype_ptr.tmf_task_ptr;
+}
+
+#else /* not ISCI_REQUEST_VALIDATE_ACCESS */
+
+#define isci_request_access_task(RequestPtr) \
+ ((RequestPtr)->ttype_ptr.io_task_ptr)
+
+#define isci_request_access_tmf(RequestPtr) \
+ ((RequestPtr)->ttype_ptr.tmf_task_ptr)
+
+#endif /* not ISCI_REQUEST_VALIDATE_ACCESS */
+
+
+int isci_request_alloc_tmf(
+ struct isci_host *isci_host,
+ struct isci_tmf *isci_tmf,
+ struct isci_request **isci_request,
+ struct isci_remote_device *isci_device,
+ gfp_t gfp_flags);
+
+
+int isci_request_execute(
+ struct isci_host *isci_host,
+ struct sas_task *task,
+ struct isci_request **request,
+ gfp_t gfp_flags);
+
+/**
+ * isci_request_unmap_sgl() - This function unmaps the DMA address of a given
+ * sgl
+ * @request: This parameter points to the isci_request object
+ * @*pdev: This Parameter is the pci_device struct for the controller
+ *
+ */
+static inline void isci_request_unmap_sgl(
+ struct isci_request *request,
+ struct pci_dev *pdev)
+{
+ struct sas_task *task = isci_request_access_task(request);
+
+ dev_dbg(&request->isci_host->pdev->dev,
+ "%s: request = %p, task = %p,\n"
+ "task->data_dir = %d, is_sata = %d\n ",
+ __func__,
+ request,
+ task,
+ task->data_dir,
+ sas_protocol_ata(task->task_proto));
+
+ if ((task->data_dir != PCI_DMA_NONE) &&
+ !sas_protocol_ata(task->task_proto)) {
+ if (task->num_scatter == 0)
+ /* 0 indicates a single dma address */
+ dma_unmap_single(
+ &pdev->dev,
+ request->zero_scatter_daddr,
+ task->total_xfer_len,
+ task->data_dir
+ );
+
+ else /* unmap the sgl dma addresses */
+ dma_unmap_sg(
+ &pdev->dev,
+ task->scatter,
+ request->num_sg_entries,
+ task->data_dir
+ );
+ }
+}
+
+
+void isci_request_io_request_complete(
+ struct isci_host *isci_host,
+ struct isci_request *request,
+ enum sci_io_status completion_status);
+
+u32 isci_request_io_request_get_transfer_length(
+ struct isci_request *request);
+
+SCI_IO_REQUEST_DATA_DIRECTION isci_request_io_request_get_data_direction(
+ struct isci_request *request);
+
+/**
+ * isci_request_io_request_get_next_sge() - This function is called by the sci
+ * core to retrieve the next sge for a given request.
+ * @request: This parameter is the isci_request object.
+ * @current_sge_address: This parameter is the last sge retrieved by the sci
+ * core for this request.
+ *
+ * pointer to the next sge for specified request.
+ */
+static inline void *isci_request_io_request_get_next_sge(
+ struct isci_request *request,
+ void *current_sge_address)
+{
+ struct sas_task *task = isci_request_access_task(request);
+ void *ret = NULL;
+
+ dev_dbg(&request->isci_host->pdev->dev,
+ "%s: request = %p, "
+ "current_sge_address = %p, "
+ "num_scatter = %d\n",
+ __func__,
+ request,
+ current_sge_address,
+ task->num_scatter);
+
+ if (!current_sge_address) /* First time through.. */
+ ret = task->scatter; /* always task->scatter */
+ else if (task->num_scatter == 0) /* Next element, if num_scatter == 0 */
+ ret = NULL; /* there is only one element. */
+ else
+ ret = sg_next(current_sge_address); /* sg_next returns NULL
+ * for the last element
+ */
+
+ dev_dbg(&request->isci_host->pdev->dev,
+ "%s: next sge address = %p\n",
+ __func__,
+ ret);
+
+ return ret;
+}
+
+dma_addr_t isci_request_sge_get_address_field(
+ struct isci_request *request,
+ void *sge_address);
+
+u32 isci_request_sge_get_length_field(
+ struct isci_request *request,
+ void *sge_address);
+
+void *isci_request_ssp_io_request_get_cdb_address(
+ struct isci_request *request);
+
+u32 isci_request_ssp_io_request_get_cdb_length(
+ struct isci_request *request);
+
+u32 isci_request_ssp_io_request_get_lun(
+ struct isci_request *request);
+
+u32 isci_request_ssp_io_request_get_task_attribute(
+ struct isci_request *request);
+
+u32 isci_request_ssp_io_request_get_command_priority(
+ struct isci_request *request);
+
+
+
+
+
+void isci_terminate_pending_requests(
+ struct isci_host *isci_host,
+ struct isci_remote_device *isci_device,
+ enum isci_request_status new_request_state);
+
+
+
+
+#endif /* !defined(_ISCI_REQUEST_H_) */
diff --git a/drivers/scsi/isci/sata.c b/drivers/scsi/isci/sata.c
new file mode 100644
index 000000000000..19b0eea93ca7
--- /dev/null
+++ b/drivers/scsi/isci/sata.c
@@ -0,0 +1,356 @@
+/*
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Intel Corporation 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
+ * OWNER 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.
+ */
+
+#include "isci.h"
+#include "scic_remote_device.h"
+#include "scic_sds_remote_device.h"
+#include "scic_io_request.h"
+#include "scic_task_request.h"
+#include "task.h"
+#include "request.h"
+#include "sata.h"
+#include "intel_sat.h"
+#include "intel_ata.h"
+
+static u8 isci_sata_get_management_task_protocol(struct isci_tmf *tmf);
+
+
+/**
+ * isci_sata_task_to_fis_copy() - This function gets the host_to_dev_fis from
+ * the core and copies the fis from the task into it.
+ * @task: This parameter is a pointer to the task struct from libsas.
+ *
+ * pointer to the host_to_dev_fis from the core request object.
+ */
+struct host_to_dev_fis *isci_sata_task_to_fis_copy(struct sas_task *task)
+{
+ struct isci_request *request = task->lldd_task;
+ struct host_to_dev_fis *register_fis =
+ scic_stp_io_request_get_h2d_reg_address(
+ request->sci_request_handle
+ );
+
+ memcpy(
+ (u8 *)register_fis,
+ (u8 *)&task->ata_task.fis,
+ sizeof(struct host_to_dev_fis)
+ );
+
+ if (!task->ata_task.device_control_reg_update)
+ register_fis->flags |= 0x80;
+
+ register_fis->flags &= 0xF0;
+
+ return register_fis;
+}
+
+/**
+ * isci_sata_is_task_ncq() - This function determines if the given stp task is
+ * a ncq request.
+ * @task: This parameter is a pointer to the task struct from libsas.
+ *
+ * true if the task is ncq
+ */
+bool isci_sata_is_task_ncq(struct sas_task *task)
+{
+ struct ata_queued_cmd *qc = task->uldd_task;
+
+ bool ret = (qc &&
+ (qc->tf.command == ATA_CMD_FPDMA_WRITE ||
+ qc->tf.command == ATA_CMD_FPDMA_READ));
+
+ return ret;
+}
+
+/**
+ * isci_sata_set_ncq_tag() - This function sets the ncq tag field in the
+ * host_to_dev_fis equal to the tag in the queue command in the task.
+ * @task: This parameter is a pointer to the task struct from libsas.
+ * @register_fis: This parameter is a pointer to the host_to_dev_fis from the
+ * core request object.
+ *
+ */
+void isci_sata_set_ncq_tag(
+ struct host_to_dev_fis *register_fis,
+ struct sas_task *task)
+{
+ struct ata_queued_cmd *qc = task->uldd_task;
+ struct isci_request *request = task->lldd_task;
+
+ register_fis->sector_count = qc->tag << 3;
+ scic_stp_io_request_set_ncq_tag(request->sci_request_handle, qc->tag);
+}
+
+/**
+ * isci_request_process_stp_response() - This function sets the status and
+ * response, in the task struct, from the request object for the upper layer
+ * driver.
+ * @sas_task: This parameter is the task struct from the upper layer driver.
+ * @response_buffer: This parameter points to the response of the completed
+ * request.
+ *
+ * none.
+ */
+void isci_request_process_stp_response(
+ struct sas_task *task,
+ void *response_buffer)
+{
+ struct sata_fis_reg_d2h *d2h_reg_fis = (struct sata_fis_reg_d2h *)response_buffer;
+ struct task_status_struct *ts = &task->task_status;
+ struct ata_task_resp *resp = (void *)&ts->buf[0];
+
+ resp->frame_len = le16_to_cpu(*(__le16 *)(response_buffer + 6));
+ memcpy(&resp->ending_fis[0], response_buffer + 16, 24);
+ ts->buf_valid_size = sizeof(*resp);
+
+ /**
+ * If the device fault bit is set in the status register, then
+ * set the sense data and return.
+ */
+ if (d2h_reg_fis->status & ATA_STATUS_REG_DEVICE_FAULT_BIT)
+ ts->stat = SAS_PROTO_RESPONSE;
+ else
+ ts->stat = SAM_STAT_GOOD;
+
+ ts->resp = SAS_TASK_COMPLETE;
+}
+
+/**
+ * isci_sata_get_sat_protocol() - retrieve the sat protocol for the request
+ * @isci_request: ata request
+ *
+ * Note: temporary implementation until expert mode removes the callback
+ *
+ */
+u8 isci_sata_get_sat_protocol(struct isci_request *isci_request)
+{
+ struct sas_task *task;
+ struct domain_device *dev;
+
+ dev_dbg(&isci_request->isci_host->pdev->dev,
+ "%s: isci_request = %p, ttype = %d\n",
+ __func__, isci_request, isci_request->ttype);
+
+ if (tmf_task == isci_request->ttype) {
+ struct isci_tmf *tmf = isci_request_access_tmf(isci_request);
+
+ return isci_sata_get_management_task_protocol(tmf);
+ }
+
+ task = isci_request_access_task(isci_request);
+ dev = task->dev;
+
+ if (!sas_protocol_ata(task->task_proto)) {
+ WARN(1, "unhandled task protocol\n");
+ return SAT_PROTOCOL_NON_DATA;
+ }
+
+ if (task->data_dir == DMA_NONE)
+ return SAT_PROTOCOL_NON_DATA;
+
+ /* the "_IN" protocol types are equivalent to their "_OUT"
+ * analogs as far as the core is concerned
+ */
+ if (dev->sata_dev.command_set == ATAPI_COMMAND_SET) {
+ if (task->ata_task.dma_xfer)
+ return SAT_PROTOCOL_PACKET_DMA_DATA_IN;
+ else
+ return SAT_PROTOCOL_PACKET_PIO_DATA_IN;
+ }
+
+ if (task->ata_task.use_ncq)
+ return SAT_PROTOCOL_FPDMA;
+
+ if (task->ata_task.dma_xfer)
+ return SAT_PROTOCOL_UDMA_DATA_IN;
+ else
+ return SAT_PROTOCOL_PIO_DATA_IN;
+}
+
+static u8 isci_sata_get_management_task_protocol(
+ struct isci_tmf *tmf)
+{
+ u8 ret = 0;
+
+ pr_warn("tmf = %p, func = %d\n", tmf, tmf->tmf_code);
+
+ if ((tmf->tmf_code == isci_tmf_sata_srst_high) ||
+ (tmf->tmf_code == isci_tmf_sata_srst_low)) {
+ pr_warn("%s: tmf->tmf_code == TMF_LU_RESET\n", __func__);
+ ret = SAT_PROTOCOL_SOFT_RESET;
+ }
+
+ return ret;
+}
+
+enum sci_status isci_sata_management_task_request_build(
+ struct isci_request *isci_request)
+{
+ struct isci_tmf *isci_tmf;
+ enum sci_status status;
+
+ if (tmf_task != isci_request->ttype)
+ return SCI_FAILURE;
+
+ isci_tmf = isci_request_access_tmf(isci_request);
+
+ switch (isci_tmf->tmf_code) {
+
+ case isci_tmf_sata_srst_high:
+ case isci_tmf_sata_srst_low:
+ {
+ struct host_to_dev_fis *register_fis =
+ scic_stp_io_request_get_h2d_reg_address(
+ isci_request->sci_request_handle
+ );
+
+ memset(register_fis, 0, sizeof(*register_fis));
+
+ register_fis->fis_type = 0x27;
+ register_fis->flags &= ~0x80;
+ register_fis->flags &= 0xF0;
+ if (isci_tmf->tmf_code == isci_tmf_sata_srst_high)
+ register_fis->control |= ATA_SRST;
+ else
+ register_fis->control &= ~ATA_SRST;
+ break;
+ }
+ /* other management commnd go here... */
+ default:
+ return SCI_FAILURE;
+ }
+
+ /* core builds the protocol specific request
+ * based on the h2d fis.
+ */
+ status = scic_task_request_construct_sata(
+ isci_request->sci_request_handle
+ );
+
+ return status;
+}
+
+/**
+ * isci_task_send_lu_reset_sata() - This function is called by of the SAS
+ * Domain Template functions. This is one of the Task Management functoins
+ * called by libsas, to reset the given SAS lun. Note the assumption that
+ * while this call is executing, no I/O will be sent by the host to the
+ * device.
+ * @lun: This parameter specifies the lun to be reset.
+ *
+ * status, zero indicates success.
+ */
+int isci_task_send_lu_reset_sata(
+ struct isci_host *isci_host,
+ struct isci_remote_device *isci_device,
+ u8 *lun)
+{
+ struct isci_tmf tmf;
+ int ret = TMF_RESP_FUNC_FAILED;
+ unsigned long flags;
+
+ /* Send the initial SRST to the target */
+ #define ISCI_SRST_TIMEOUT_MS 20 /* 20 ms timeout. */
+ isci_task_build_tmf(&tmf, isci_device, isci_tmf_sata_srst_high,
+ NULL, NULL
+ );
+
+ ret = isci_task_execute_tmf(isci_host, &tmf, ISCI_SRST_TIMEOUT_MS);
+
+ if (ret != TMF_RESP_FUNC_COMPLETE) {
+ dev_warn(&isci_host->pdev->dev,
+ "%s: Assert SRST failed (%p) = %x",
+ __func__,
+ isci_device,
+ ret);
+
+ /* Return the failure so that the LUN reset is escalated
+ * to a target reset.
+ */
+ goto out;
+ }
+
+ /* Leave SRST high for a bit. */
+ #define ISCI_SRST_ASSERT_DELAY 100 /* usecs */
+ scic_cb_stall_execution(ISCI_SRST_ASSERT_DELAY);
+
+ /* Deassert SRST. */
+ isci_task_build_tmf(&tmf, isci_device, isci_tmf_sata_srst_low,
+ NULL, NULL
+ );
+ ret = isci_task_execute_tmf(isci_host, &tmf, ISCI_SRST_TIMEOUT_MS);
+
+ if (ret == TMF_RESP_FUNC_COMPLETE)
+ dev_dbg(&isci_host->pdev->dev,
+ "%s: SATA LUN reset passed (%p)\n",
+ __func__,
+ isci_device);
+ else
+ dev_warn(&isci_host->pdev->dev,
+ "%s: Deassert SRST failed (%p)=%x\n",
+ __func__,
+ isci_device,
+ ret);
+
+ out:
+ spin_lock_irqsave(&isci_host->scic_lock, flags);
+
+ /* Resume the device. */
+ scic_sds_remote_device_resume(isci_device->sci_device_handle);
+
+ spin_unlock_irqrestore(&isci_host->scic_lock, flags);
+
+ return ret;
+}
diff --git a/drivers/scsi/isci/sata.h b/drivers/scsi/isci/sata.h
new file mode 100644
index 000000000000..b6ba25b52d2c
--- /dev/null
+++ b/drivers/scsi/isci/sata.h
@@ -0,0 +1,83 @@
+/*
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Intel Corporation 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
+ * OWNER 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.
+ */
+
+#include "intel_sat.h"
+
+
+
+struct host_to_dev_fis *isci_sata_task_to_fis_copy(
+ struct sas_task *task);
+
+bool isci_sata_is_task_ncq(
+ struct sas_task *task);
+
+void isci_sata_set_ncq_tag(
+ struct host_to_dev_fis *register_fis,
+ struct sas_task *task);
+
+void isci_request_process_stp_response(
+ struct sas_task *task,
+ void *response_buffer);
+
+u8 isci_sata_get_sat_protocol(
+ struct isci_request *isci_request);
+
+enum sci_status isci_sata_management_task_request_build(
+ struct isci_request *isci_request);
+
+int isci_task_send_lu_reset_sata(
+ struct isci_host *isci_host,
+ struct isci_remote_device *isci_device,
+ u8 *lun);
diff --git a/drivers/scsi/isci/sci_environment.h b/drivers/scsi/isci/sci_environment.h
new file mode 100644
index 000000000000..e1020ee6c38e
--- /dev/null
+++ b/drivers/scsi/isci/sci_environment.h
@@ -0,0 +1,112 @@
+/*
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Intel Corporation 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
+ * OWNER 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.
+ */
+
+#ifndef _SCI_ENVIRONMENT_H_
+#define _SCI_ENVIRONMENT_H_
+
+#include "isci.h"
+
+struct scic_sds_controller;
+struct scic_sds_phy;
+struct scic_sds_port;
+struct scic_sds_remote_device;
+
+static inline struct device *scic_to_dev(struct scic_sds_controller *scic)
+{
+ struct isci_host *isci_host = sci_object_get_association(scic);
+
+ return &isci_host->pdev->dev;
+}
+
+static inline struct device *sciphy_to_dev(struct scic_sds_phy *sci_phy)
+{
+ struct isci_phy *iphy = sci_object_get_association(sci_phy);
+
+ if (!iphy || !iphy->isci_port || !iphy->isci_port->isci_host)
+ return NULL;
+
+ return &iphy->isci_port->isci_host->pdev->dev;
+}
+
+static inline struct device *sciport_to_dev(struct scic_sds_port *sci_port)
+{
+ struct isci_port *iport = sci_object_get_association(sci_port);
+
+ if (!iport || !iport->isci_host)
+ return NULL;
+
+ return &iport->isci_host->pdev->dev;
+}
+
+static inline struct device *scirdev_to_dev(struct scic_sds_remote_device *sci_dev)
+{
+ struct isci_remote_device *idev = sci_object_get_association(sci_dev);
+
+ if (!idev || !idev->isci_port || !idev->isci_port->isci_host)
+ return NULL;
+
+ return &idev->isci_port->isci_host->pdev->dev;
+}
+
+enum {
+ ISCI_SI_REVA0,
+ ISCI_SI_REVA2,
+ ISCI_SI_REVB0,
+};
+
+extern int isci_si_rev;
+
+
+#endif
diff --git a/drivers/scsi/isci/task.c b/drivers/scsi/isci/task.c
new file mode 100644
index 000000000000..5e6f55863407
--- /dev/null
+++ b/drivers/scsi/isci/task.c
@@ -0,0 +1,1691 @@
+/*
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Intel Corporation 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
+ * OWNER 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.
+ */
+
+#include <linux/completion.h>
+#include "scic_task_request.h"
+#include "scic_remote_device.h"
+#include "scic_io_request.h"
+#include "scic_sds_remote_device.h"
+#include "scic_sds_remote_node_context.h"
+#include "isci.h"
+#include "request.h"
+#include "sata.h"
+#include "task.h"
+
+
+/**
+ * isci_task_execute_task() - This function is one of the SAS Domain Template
+ * functions. This function is called by libsas to send a task down to
+ * hardware.
+ * @task: This parameter specifies the SAS task to send.
+ * @num: This parameter specifies the number of tasks to queue.
+ * @gfp_flags: This parameter specifies the context of this call.
+ *
+ * status, zero indicates success.
+ */
+int isci_task_execute_task(struct sas_task *task, int num, gfp_t gfp_flags)
+{
+ struct isci_host *isci_host;
+ struct isci_request *request = NULL;
+ struct isci_remote_device *device;
+ unsigned long flags;
+ unsigned long quiesce_flags = 0;
+ int ret;
+ enum sci_status status;
+
+
+ dev_dbg(task->dev->port->ha->dev, "%s: num=%d\n", __func__, num);
+
+ if (task->task_state_flags & SAS_TASK_STATE_ABORTED) {
+
+ isci_task_complete_for_upper_layer(
+ task,
+ SAS_TASK_UNDELIVERED,
+ SAM_STAT_TASK_ABORTED,
+ isci_perform_normal_io_completion
+ );
+
+ return 0; /* The I/O was accepted (and failed). */
+ }
+ if ((task->dev == NULL) || (task->dev->port == NULL)) {
+
+ /* Indicate SAS_TASK_UNDELIVERED, so that the scsi midlayer
+ * removes the target.
+ */
+ isci_task_complete_for_upper_layer(
+ task,
+ SAS_TASK_UNDELIVERED,
+ SAS_DEVICE_UNKNOWN,
+ isci_perform_normal_io_completion
+ );
+ return 0; /* The I/O was accepted (and failed). */
+ }
+ isci_host = isci_host_from_sas_ha(task->dev->port->ha);
+
+ /* Check if we have room for more tasks */
+ ret = isci_host_can_queue(isci_host, num);
+
+ if (ret) {
+ dev_warn(task->dev->port->ha->dev, "%s: queue full\n", __func__);
+ return ret;
+ }
+
+ do {
+ dev_dbg(task->dev->port->ha->dev,
+ "task = %p, num = %d; dev = %p; cmd = %p\n",
+ task, num, task->dev, task->uldd_task);
+
+ if ((task->dev == NULL) || (task->dev->port == NULL)) {
+ dev_warn(task->dev->port->ha->dev,
+ "%s: task %p's port or dev == NULL!\n",
+ __func__, task);
+
+ /* Indicate SAS_TASK_UNDELIVERED, so that the scsi
+ * midlayer removes the target.
+ */
+ isci_task_complete_for_upper_layer(
+ task,
+ SAS_TASK_UNDELIVERED,
+ SAS_DEVICE_UNKNOWN,
+ isci_perform_normal_io_completion
+ );
+ /* We don't have a valid host reference, so we
+ * can't control the host queueing condition.
+ */
+ continue;
+ }
+
+ device = isci_dev_from_domain_dev(task->dev);
+
+ isci_host = isci_host_from_sas_ha(task->dev->port->ha);
+
+ /* check if the controller hasn't started or if the device
+ * is ready but not accepting IO.
+ */
+ if (device) {
+
+ spin_lock_irqsave(&device->host_quiesce_lock,
+ quiesce_flags);
+ }
+ /* From this point onward, any process that needs to guarantee
+ * that there is no kernel I/O being started will have to wait
+ * for the quiesce spinlock.
+ */
+
+ if (isci_host_get_state(isci_host) == isci_starting ||
+ (device && ((isci_remote_device_get_state(device) == isci_ready) ||
+ (isci_remote_device_get_state(device) == isci_host_quiesce)))) {
+
+ /* Forces a retry from scsi mid layer. */
+ dev_warn(task->dev->port->ha->dev,
+ "%s: task %p: isci_host->status = %d, "
+ "device = %p\n",
+ __func__,
+ task,
+ isci_host_get_state(isci_host),
+ device);
+
+ if (device)
+ dev_dbg(task->dev->port->ha->dev,
+ "%s: device->status = 0x%x\n",
+ __func__,
+ isci_remote_device_get_state(device));
+
+ /* Indicate QUEUE_FULL so that the scsi midlayer
+ * retries.
+ */
+ isci_task_complete_for_upper_layer(
+ task,
+ SAS_TASK_COMPLETE,
+ SAS_QUEUE_FULL,
+ isci_perform_normal_io_completion
+ );
+ isci_host_can_dequeue(isci_host, 1);
+ }
+ /* the device is going down... */
+ else if (!device || (isci_ready_for_io != isci_remote_device_get_state(device))) {
+
+ dev_dbg(task->dev->port->ha->dev,
+ "%s: task %p: isci_host->status = %d, "
+ "device = %p\n",
+ __func__,
+ task,
+ isci_host_get_state(isci_host),
+ device);
+
+ if (device)
+ dev_dbg(task->dev->port->ha->dev,
+ "%s: device->status = 0x%x\n",
+ __func__,
+ isci_remote_device_get_state(device));
+
+ /* Indicate SAS_TASK_UNDELIVERED, so that the scsi
+ * midlayer removes the target.
+ */
+ isci_task_complete_for_upper_layer(
+ task,
+ SAS_TASK_UNDELIVERED,
+ SAS_DEVICE_UNKNOWN,
+ isci_perform_normal_io_completion
+ );
+ isci_host_can_dequeue(isci_host, 1);
+
+ } else {
+ /* build and send the request. */
+ status = isci_request_execute(isci_host, task, &request,
+ gfp_flags);
+
+ if (status == SCI_SUCCESS) {
+ spin_lock_irqsave(&task->task_state_lock, flags);
+ task->task_state_flags |= SAS_TASK_AT_INITIATOR;
+ spin_unlock_irqrestore(&task->task_state_lock, flags);
+ } else {
+ /* Indicate QUEUE_FULL so that the scsi
+ * midlayer retries. if the request
+ * failed for remote device reasons,
+ * it gets returned as
+ * SAS_TASK_UNDELIVERED next time
+ * through.
+ */
+ isci_task_complete_for_upper_layer(
+ task,
+ SAS_TASK_COMPLETE,
+ SAS_QUEUE_FULL,
+ isci_perform_normal_io_completion
+ );
+ isci_host_can_dequeue(isci_host, 1);
+ }
+ }
+ if (device) {
+ spin_unlock_irqrestore(&device->host_quiesce_lock,
+ quiesce_flags
+ );
+ }
+ task = list_entry(task->list.next, struct sas_task, list);
+ } while (--num > 0);
+ return 0;
+}
+
+
+
+/**
+ * isci_task_request_build() - This function builds the task request object.
+ * @isci_host: This parameter specifies the ISCI host object
+ * @request: This parameter points to the isci_request object allocated in the
+ * request construct function.
+ * @tmf: This parameter is the task management struct to be built
+ *
+ * SCI_SUCCESS on successfull completion, or specific failure code.
+ */
+static enum sci_status isci_task_request_build(
+ struct isci_host *isci_host,
+ struct isci_request **isci_request,
+ struct isci_tmf *isci_tmf)
+{
+ struct scic_sds_remote_device *sci_device;
+ enum sci_status status = SCI_FAILURE;
+ struct isci_request *request;
+ struct isci_remote_device *isci_device;
+/* struct sci_sas_identify_address_frame_protocols dev_protocols; */
+ struct smp_discover_response_protocols dev_protocols;
+
+
+ dev_dbg(&isci_host->pdev->dev,
+ "%s: isci_tmf = %p\n", __func__, isci_tmf);
+
+ isci_device = isci_tmf->device;
+ sci_device = isci_device->sci_device_handle;
+
+ /* do common allocation and init of request object. */
+ status = isci_request_alloc_tmf(
+ isci_host,
+ isci_tmf,
+ &request,
+ isci_device,
+ GFP_ATOMIC
+ );
+
+ if (status != SCI_SUCCESS)
+ goto out;
+
+ /* let the core do it's construct. */
+ status = scic_task_request_construct(
+ isci_host->core_controller,
+ sci_device,
+ SCI_CONTROLLER_INVALID_IO_TAG,
+ request,
+ request->sci_request_mem_ptr,
+ &request->sci_request_handle
+ );
+
+ if (status != SCI_SUCCESS) {
+ dev_warn(&isci_host->pdev->dev,
+ "%s: scic_task_request_construct failed - "
+ "status = 0x%x\n",
+ __func__,
+ status);
+ goto errout;
+ }
+
+ sci_object_set_association(
+ request->sci_request_handle,
+ request
+ );
+
+ scic_remote_device_get_protocols(
+ sci_device,
+ &dev_protocols
+ );
+
+ /* let the core do it's protocol
+ * specific construction.
+ */
+ if (dev_protocols.u.bits.attached_ssp_target) {
+
+ isci_tmf->proto = SAS_PROTOCOL_SSP;
+ status = scic_task_request_construct_ssp(
+ request->sci_request_handle
+ );
+ if (status != SCI_SUCCESS)
+ goto errout;
+ }
+
+ if (dev_protocols.u.bits.attached_stp_target) {
+
+ isci_tmf->proto = SAS_PROTOCOL_SATA;
+ status = isci_sata_management_task_request_build(request);
+
+ if (status != SCI_SUCCESS)
+ goto errout;
+ }
+
+ goto out;
+
+ errout:
+
+ /* release the dma memory if we fail. */
+ isci_request_free(isci_host, request);
+ request = NULL;
+
+ out:
+ *isci_request = request;
+ return status;
+}
+
+/**
+ * isci_tmf_timeout_cb() - This function is called as a kernel callback when
+ * the timeout period for the TMF has expired.
+ *
+ *
+ */
+static void isci_tmf_timeout_cb(void *tmf_request_arg)
+{
+ struct isci_request *request = (struct isci_request *)tmf_request_arg;
+ struct isci_tmf *tmf = isci_request_access_tmf(request);
+ enum sci_status status;
+
+ BUG_ON(request->ttype != tmf_task);
+
+ /* This task management request has timed-out. Terminate the request
+ * so that the request eventually completes to the requestor in the
+ * request completion callback path.
+ */
+ /* Note - the timer callback function itself has provided spinlock
+ * exclusion from the start and completion paths. No need to take
+ * the request->isci_host->scic_lock here.
+ */
+
+ if (tmf->timeout_timer != NULL) {
+ /* Call the users callback, if any. */
+ if (tmf->cb_state_func != NULL)
+ tmf->cb_state_func(isci_tmf_timed_out, tmf,
+ tmf->cb_data);
+
+ /* Terminate the TMF transmit request. */
+ status = scic_controller_terminate_request(
+ request->isci_host->core_controller,
+ request->isci_device->sci_device_handle,
+ request->sci_request_handle
+ );
+
+ dev_dbg(&request->isci_host->pdev->dev,
+ "%s: tmf_request = %p; tmf = %p; status = %d\n",
+ __func__, request, tmf, status);
+ } else
+ dev_dbg(&request->isci_host->pdev->dev,
+ "%s: timer already canceled! "
+ "tmf_request = %p; tmf = %p\n",
+ __func__, request, tmf);
+
+ /* No need to unlock since the caller to this callback is doing it for
+ * us.
+ * request->isci_host->scic_lock
+ */
+}
+
+/**
+ * isci_task_execute_tmf() - This function builds and sends a task request,
+ * then waits for the completion.
+ * @isci_host: This parameter specifies the ISCI host object
+ * @tmf: This parameter is the pointer to the task management structure for
+ * this request.
+ * @timeout_ms: This parameter specifies the timeout period for the task
+ * management request.
+ *
+ * TMF_RESP_FUNC_COMPLETE on successful completion of the TMF (this includes
+ * error conditions reported in the IU status), or TMF_RESP_FUNC_FAILED.
+ */
+int isci_task_execute_tmf(
+ struct isci_host *isci_host,
+ struct isci_tmf *tmf,
+ unsigned long timeout_ms)
+{
+ DECLARE_COMPLETION_ONSTACK(completion);
+ enum sci_status status = SCI_FAILURE;
+ struct scic_sds_remote_device *sci_device;
+ struct isci_remote_device *isci_device = tmf->device;
+ struct isci_request *request;
+ int ret = TMF_RESP_FUNC_FAILED;
+ unsigned long flags;
+
+ /* sanity check, return TMF_RESP_FUNC_FAILED
+ * if the device is not there and ready.
+ */
+ if (!isci_device ||
+ ((isci_ready_for_io != isci_remote_device_get_state(isci_device)) &&
+ (isci_host_quiesce != isci_remote_device_get_state(isci_device)))) {
+ dev_dbg(&isci_host->pdev->dev,
+ "%s: isci_device = %p not ready (%d)\n",
+ __func__,
+ isci_device,
+ isci_remote_device_get_state(isci_device));
+ return TMF_RESP_FUNC_FAILED;
+ } else
+ dev_dbg(&isci_host->pdev->dev,
+ "%s: isci_device = %p\n",
+ __func__, isci_device);
+
+ sci_device = isci_device->sci_device_handle;
+
+ /* Assign the pointer to the TMF's completion kernel wait structure. */
+ tmf->complete = &completion;
+
+ isci_task_request_build(
+ isci_host,
+ &request,
+ tmf
+ );
+
+ if (!request) {
+ dev_warn(&isci_host->pdev->dev,
+ "%s: isci_task_request_build failed\n",
+ __func__);
+ return TMF_RESP_FUNC_FAILED;
+ }
+
+ /* Allocate the TMF timeout timer. */
+ tmf->timeout_timer = isci_timer_create(
+ &isci_host->timer_list_struct,
+ isci_host,
+ request,
+ isci_tmf_timeout_cb
+ );
+
+ spin_lock_irqsave(&isci_host->scic_lock, flags);
+
+ /* Start the timer. */
+ if (tmf->timeout_timer)
+ isci_timer_start(tmf->timeout_timer, timeout_ms);
+ else
+ dev_warn(&isci_host->pdev->dev,
+ "%s: isci_timer_create failed!!!!\n",
+ __func__);
+
+ /* start the TMF io. */
+ status = scic_controller_start_task(
+ isci_host->core_controller,
+ sci_device,
+ request->sci_request_handle,
+ SCI_CONTROLLER_INVALID_IO_TAG
+ );
+
+ if (status != SCI_SUCCESS) {
+ dev_warn(&isci_host->pdev->dev,
+ "%s: start_io failed - status = 0x%x, request = %p\n",
+ __func__,
+ status,
+ request);
+ goto cleanup_request;
+ }
+
+ /* Call the users callback, if any. */
+ if (tmf->cb_state_func != NULL)
+ tmf->cb_state_func(isci_tmf_started, tmf, tmf->cb_data);
+
+ /* Change the state of the TMF-bearing request to "started". */
+ isci_request_change_state(request, started);
+
+ /* add the request to the remote device request list. */
+ list_add(&request->dev_node, &isci_device->reqs_in_process);
+
+ spin_unlock_irqrestore(&isci_host->scic_lock, flags);
+
+ /* Wait for the TMF to complete, or a timeout. */
+ wait_for_completion(&completion);
+
+ isci_print_tmf(tmf);
+
+ if (tmf->status == SCI_SUCCESS)
+ ret = TMF_RESP_FUNC_COMPLETE;
+ else if (tmf->status == SCI_FAILURE_IO_RESPONSE_VALID) {
+ dev_dbg(&isci_host->pdev->dev,
+ "%s: tmf.status == "
+ "SCI_FAILURE_IO_RESPONSE_VALID\n",
+ __func__);
+ ret = TMF_RESP_FUNC_COMPLETE;
+ }
+ /* Else - leave the default "failed" status alone. */
+
+ dev_dbg(&isci_host->pdev->dev,
+ "%s: completed request = %p\n",
+ __func__,
+ request);
+
+ if (request->io_request_completion != NULL) {
+
+ /* The fact that this is non-NULL for a TMF request
+ * means there is a thread waiting for this TMF to
+ * finish.
+ */
+ complete(request->io_request_completion);
+ }
+
+ spin_lock_irqsave(&isci_host->scic_lock, flags);
+
+ cleanup_request:
+
+ /* Clean up the timer if needed. */
+ if (tmf->timeout_timer) {
+ isci_timer_stop(tmf->timeout_timer);
+ isci_timer_free(&isci_host->timer_list_struct,
+ tmf->timeout_timer);
+ tmf->timeout_timer = NULL;
+ }
+
+ spin_unlock_irqrestore(&isci_host->scic_lock, flags);
+
+ isci_request_free(isci_host, request);
+
+ return ret;
+}
+
+void isci_task_build_tmf(
+ struct isci_tmf *tmf,
+ struct isci_remote_device *isci_device,
+ enum isci_tmf_function_codes code,
+ void (*tmf_sent_cb)(enum isci_tmf_cb_state,
+ struct isci_tmf *,
+ void *),
+ void *cb_data)
+{
+ dev_dbg(&isci_device->isci_port->isci_host->pdev->dev,
+ "%s: isci_device = %p\n", __func__, isci_device);
+
+ memset(tmf, 0, sizeof(*tmf));
+
+ tmf->device = isci_device;
+ tmf->tmf_code = code;
+ tmf->timeout_timer = NULL;
+ tmf->cb_state_func = tmf_sent_cb;
+ tmf->cb_data = cb_data;
+}
+
+static struct isci_request *isci_task_get_request_from_task(
+ struct sas_task *task,
+ struct isci_host **isci_host,
+ struct isci_remote_device **isci_device)
+{
+
+ struct isci_request *request = NULL;
+ unsigned long flags;
+
+ spin_lock_irqsave(&task->task_state_lock, flags);
+
+ request = task->lldd_task;
+
+ /* If task is already done, the request isn't valid */
+ if (!(task->task_state_flags & SAS_TASK_STATE_DONE) &&
+ (task->task_state_flags & SAS_TASK_AT_INITIATOR) &&
+ (request != NULL)) {
+
+ if (isci_host != NULL)
+ *isci_host = request->isci_host;
+
+ if (isci_device != NULL)
+ *isci_device = request->isci_device;
+ }
+
+ spin_unlock_irqrestore(&task->task_state_lock, flags);
+
+ return request;
+}
+
+/**
+ * isci_task_validate_request_to_abort() - This function checks the given I/O
+ * against the "started" state. If the request is still "started", it's
+ * state is changed to aborted. NOTE: isci_host->scic_lock MUST BE HELD
+ * BEFORE CALLING THIS FUNCTION.
+ * @isci_request: This parameter specifies the request object to control.
+ * @isci_host: This parameter specifies the ISCI host object
+ * @isci_device: This is the device to which the request is pending.
+ * @aborted_io_completion: This is a completion structure that will be added to
+ * the request in case it is changed to aborting; this completion is
+ * triggered when the request is fully completed.
+ *
+ * Either "started" on successful change of the task status to "aborted", or
+ * "unallocated" if the task cannot be controlled.
+ */
+static enum isci_request_status isci_task_validate_request_to_abort(
+ struct isci_request *isci_request,
+ struct isci_host *isci_host,
+ struct isci_remote_device *isci_device,
+ struct completion *aborted_io_completion)
+{
+ enum isci_request_status old_state = unallocated;
+
+ /* Only abort the task if it's in the
+ * device's request_in_process list
+ */
+ if (isci_request && !list_empty(&isci_request->dev_node)) {
+ old_state = isci_request_change_started_to_aborted(
+ isci_request, aborted_io_completion);
+
+ /* Only abort requests in the started state. */
+ if (old_state != started)
+ old_state = unallocated;
+ }
+
+ return old_state;
+}
+
+static void isci_request_cleanup_completed_loiterer(
+ struct isci_host *isci_host,
+ struct isci_remote_device *isci_device,
+ struct isci_request *isci_request)
+{
+ struct sas_task *task = isci_request_access_task(isci_request);
+ unsigned long flags;
+
+ dev_dbg(&isci_host->pdev->dev,
+ "%s: isci_device=%p, request=%p, task=%p\n",
+ __func__, isci_device, isci_request,
+ isci_request->ttype_ptr.io_task_ptr);
+
+ spin_lock_irqsave(&isci_host->scic_lock, flags);
+ list_del_init(&isci_request->dev_node);
+ if (task != NULL)
+ task->lldd_task = NULL;
+ spin_unlock_irqrestore(&isci_host->scic_lock, flags);
+
+ isci_request_free(isci_host, isci_request);
+}
+/**
+ * isci_terminate_request_core() - This function will terminate the given
+ * request, and wait for it to complete. This function must only be called
+ * from a thread that can wait. Note that the request is terminated and
+ * completed (back to the host, if started there).
+ * @isci_host: This SCU.
+ * @isci_device: The target.
+ * @isci_request: The I/O request to be terminated.
+ *
+ *
+ */
+static void isci_terminate_request_core(
+ struct isci_host *isci_host,
+ struct isci_remote_device *isci_device,
+ struct isci_request *isci_request,
+ struct completion *request_completion)
+{
+ enum sci_status status = SCI_SUCCESS;
+ bool was_terminated = false;
+ bool needs_cleanup_handling = false;
+ enum isci_request_status request_status;
+ unsigned long flags;
+
+ dev_dbg(&isci_host->pdev->dev,
+ "%s: device = %p; request = %p\n",
+ __func__, isci_device, isci_request);
+
+ /* Peek at the current status of the request. This will tell
+ * us if there was special handling on the request such that it
+ * needs to be detached and freed here.
+ */
+ spin_lock_irqsave(&isci_request->state_lock, flags);
+ request_status = isci_request_get_state(isci_request);
+
+ /* TMFs are in their own thread */
+ if ((isci_request->ttype == io_task) &&
+ ((request_status == aborted) ||
+ (request_status == aborting) ||
+ (request_status == terminating)))
+ /* The completion routine won't free a request in
+ * the aborted/aborting/terminating state, so we do
+ * it here.
+ */
+ needs_cleanup_handling = true;
+
+ spin_unlock_irqrestore(&isci_request->state_lock, flags);
+
+ spin_lock_irqsave(&isci_host->scic_lock, flags);
+ /* Make sure the request wasn't just sitting around signalling
+ * device condition (if the request handle is NULL, then the
+ * request completed but needed additional handling here).
+ */
+ if (isci_request->sci_request_handle != NULL) {
+ was_terminated = true;
+ status = scic_controller_terminate_request(
+ isci_host->core_controller,
+ isci_device->sci_device_handle,
+ isci_request->sci_request_handle
+ );
+ }
+ spin_unlock_irqrestore(&isci_host->scic_lock, flags);
+
+ /*
+ * The only time the request to terminate will
+ * fail is when the io request is completed and
+ * being aborted.
+ */
+ if (status != SCI_SUCCESS)
+ dev_err(&isci_host->pdev->dev,
+ "%s: scic_controller_terminate_request"
+ " returned = 0x%x\n",
+ __func__,
+ status);
+ else {
+ if (was_terminated) {
+ dev_dbg(&isci_host->pdev->dev,
+ "%s: before completion wait (%p)\n",
+ __func__,
+ request_completion);
+
+ /* Wait here for the request to complete. */
+ wait_for_completion(request_completion);
+
+ dev_dbg(&isci_host->pdev->dev,
+ "%s: after completion wait (%p)\n",
+ __func__,
+ request_completion);
+ }
+
+ if (needs_cleanup_handling)
+ isci_request_cleanup_completed_loiterer(
+ isci_host, isci_device, isci_request
+ );
+ }
+}
+static void isci_terminate_request(
+ struct isci_host *isci_host,
+ struct isci_remote_device *isci_device,
+ struct isci_request *isci_request,
+ enum isci_request_status new_request_state)
+{
+ enum isci_request_status old_state;
+
+ DECLARE_COMPLETION_ONSTACK(request_completion);
+ unsigned long flags;
+
+ spin_lock_irqsave(&isci_host->scic_lock, flags);
+
+ /* Change state to "new_request_state" if it is currently "started" */
+ old_state = isci_request_change_started_to_newstate(
+ isci_request,
+ &request_completion,
+ new_request_state
+ );
+
+ spin_unlock_irqrestore(&isci_host->scic_lock, flags);
+
+ if (old_state == started)
+ /* This request was not already being aborted. If it had been,
+ * then the aborting I/O (ie. the TMF request) would not be in
+ * the aborting state, and thus would be terminated here. Note
+ * that since the TMF completion's call to the kernel function
+ * "complete()" does not happen until the pending I/O request
+ * terminate fully completes, we do not have to implement a
+ * special wait here for already aborting requests - the
+ * termination of the TMF request will force the request
+ * to finish it's already started terminate.
+ */
+ isci_terminate_request_core(isci_host, isci_device,
+ isci_request, &request_completion);
+}
+
+/**
+ * isci_terminate_pending_requests() - This function will change the all of the
+ * requests on the given device's state to "aborting", will terminate the
+ * requests, and wait for them to complete. This function must only be
+ * called from a thread that can wait. Note that the requests are all
+ * terminated and completed (back to the host, if started there).
+ * @isci_host: This parameter specifies SCU.
+ * @isci_device: This parameter specifies the target.
+ *
+ *
+ */
+void isci_terminate_pending_requests(
+ struct isci_host *isci_host,
+ struct isci_remote_device *isci_device,
+ enum isci_request_status new_request_state)
+{
+ struct isci_request *isci_request;
+ struct sas_task *task;
+ bool done = false;
+ unsigned long flags;
+
+ dev_dbg(&isci_host->pdev->dev,
+ "%s: isci_device = %p (new request state = %d)\n",
+ __func__, isci_device, new_request_state);
+
+ #define ISCI_TERMINATE_SHOW_PENDING_REQUESTS
+ #ifdef ISCI_TERMINATE_SHOW_PENDING_REQUESTS
+ {
+ struct isci_request *request;
+
+ /* Only abort the task if it's in the
+ * device's request_in_process list
+ */
+ list_for_each_entry(request,
+ &isci_device->reqs_in_process,
+ dev_node)
+ dev_dbg(&isci_host->pdev->dev,
+ "%s: isci_device = %p; request is on "
+ "reqs_in_process list: %p\n",
+ __func__, isci_device, request);
+ }
+ #endif /* ISCI_TERMINATE_SHOW_PENDING_REQUESTS */
+
+ /* Clean up all pending requests. */
+ do {
+ spin_lock_irqsave(&isci_host->scic_lock, flags);
+
+ if (list_empty(&isci_device->reqs_in_process)) {
+
+ done = true;
+ spin_unlock_irqrestore(&isci_host->scic_lock, flags);
+
+ dev_dbg(&isci_host->pdev->dev,
+ "%s: isci_device = %p; done.\n",
+ __func__, isci_device);
+ } else {
+ /* The list was not empty - grab the first request. */
+ isci_request = list_first_entry(
+ &isci_device->reqs_in_process,
+ struct isci_request, dev_node
+ );
+ /* Note that we are not expecting to have to control
+ * the target to abort the request.
+ */
+ isci_request->complete_in_target = true;
+
+ spin_unlock_irqrestore(&isci_host->scic_lock, flags);
+
+ /* Get the libsas task reference. */
+ task = isci_request_access_task(isci_request);
+
+ dev_dbg(&isci_host->pdev->dev,
+ "%s: isci_device=%p request=%p; task=%p\n",
+ __func__, isci_device, isci_request, task);
+
+ /* Mark all still pending I/O with the selected next
+ * state.
+ */
+ isci_terminate_request(isci_host, isci_device,
+ isci_request, new_request_state
+ );
+
+ /* Set the 'done' state on the task. */
+ if (task)
+ isci_task_all_done(task);
+ }
+ } while (!done);
+}
+
+/**
+ * isci_task_send_lu_reset_sas() - This function is called by of the SAS Domain
+ * Template functions.
+ * @lun: This parameter specifies the lun to be reset.
+ *
+ * status, zero indicates success.
+ */
+static int isci_task_send_lu_reset_sas(
+ struct isci_host *isci_host,
+ struct isci_remote_device *isci_device,
+ u8 *lun)
+{
+ struct isci_tmf tmf;
+ int ret = TMF_RESP_FUNC_FAILED;
+
+ dev_dbg(&isci_host->pdev->dev,
+ "%s: isci_host = %p, isci_device = %p\n",
+ __func__, isci_host, isci_device);
+ /* Send the LUN reset to the target. By the time the call returns,
+ * the TMF has fully exected in the target (in which case the return
+ * value is "TMF_RESP_FUNC_COMPLETE", or the request timed-out (or
+ * was otherwise unable to be executed ("TMF_RESP_FUNC_FAILED").
+ */
+ isci_task_build_tmf(&tmf, isci_device, isci_tmf_ssp_lun_reset, NULL,
+ NULL);
+
+ #define ISCI_LU_RESET_TIMEOUT_MS 2000 /* 2 second timeout. */
+ ret = isci_task_execute_tmf(isci_host, &tmf, ISCI_LU_RESET_TIMEOUT_MS);
+
+ if (ret == TMF_RESP_FUNC_COMPLETE)
+ dev_dbg(&isci_host->pdev->dev,
+ "%s: %p: TMF_LU_RESET passed\n",
+ __func__, isci_device);
+ else
+ dev_dbg(&isci_host->pdev->dev,
+ "%s: %p: TMF_LU_RESET failed (%x)\n",
+ __func__, isci_device, ret);
+
+ return ret;
+}
+
+/**
+ * isci_task_lu_reset() - This function is one of the SAS Domain Template
+ * functions. This is one of the Task Management functoins called by libsas,
+ * to reset the given lun. Note the assumption that while this call is
+ * executing, no I/O will be sent by the host to the device.
+ * @lun: This parameter specifies the lun to be reset.
+ *
+ * status, zero indicates success.
+ */
+int isci_task_lu_reset(
+ struct domain_device *domain_device,
+ u8 *lun)
+{
+ struct isci_host *isci_host = NULL;
+ struct isci_remote_device *isci_device = NULL;
+ int ret;
+ bool device_stopping = false;
+
+ if (domain_device == NULL) {
+ pr_warn("%s: domain_device == NULL\n", __func__);
+ return TMF_RESP_FUNC_FAILED;
+ }
+
+ isci_device = isci_dev_from_domain_dev(domain_device);
+
+ if (domain_device->port != NULL)
+ isci_host = isci_host_from_sas_ha(domain_device->port->ha);
+
+ pr_debug("%s: domain_device=%p, isci_host=%p; isci_device=%p\n",
+ __func__, domain_device, isci_host, isci_device);
+
+ if (isci_device != NULL)
+ device_stopping = (isci_device->status == isci_stopping)
+ || (isci_device->status == isci_stopped);
+
+ /* If there is a device reset pending on any request in the
+ * device's list, fail this LUN reset request in order to
+ * escalate to the device reset.
+ */
+ if ((isci_device == NULL) ||
+ (isci_host == NULL) ||
+ ((isci_host != NULL) &&
+ (isci_device != NULL) &&
+ (device_stopping ||
+ (isci_device_is_reset_pending(isci_host, isci_device))))) {
+ dev_warn(&isci_host->pdev->dev,
+ "%s: No dev (%p), no host (%p), or "
+ "RESET PENDING: domain_device=%p\n",
+ __func__, isci_device, isci_host, domain_device);
+ return TMF_RESP_FUNC_FAILED;
+ }
+
+ /* Stop I/O to the remote device. */
+ isci_device_set_host_quiesce_lock_state(isci_device, true);
+
+ /* Send the task management part of the reset. */
+ if (sas_protocol_ata(domain_device->tproto)) {
+ ret = isci_task_send_lu_reset_sata(
+ isci_host, isci_device, lun
+ );
+ } else
+ ret = isci_task_send_lu_reset_sas(isci_host, isci_device, lun);
+
+ /* If the LUN reset worked, all the I/O can now be terminated. */
+ if (ret == TMF_RESP_FUNC_COMPLETE)
+ /* Terminate all I/O now. */
+ isci_terminate_pending_requests(isci_host,
+ isci_device,
+ terminating);
+
+ /* Resume I/O to the remote device. */
+ isci_device_set_host_quiesce_lock_state(isci_device, false);
+
+ return ret;
+}
+
+
+/* int (*lldd_clear_nexus_port)(struct asd_sas_port *); */
+int isci_task_clear_nexus_port(struct asd_sas_port *port)
+{
+ return TMF_RESP_FUNC_FAILED;
+}
+
+
+
+int isci_task_clear_nexus_ha(struct sas_ha_struct *ha)
+{
+ return TMF_RESP_FUNC_FAILED;
+}
+
+int isci_task_I_T_nexus_reset(struct domain_device *dev)
+{
+ return TMF_RESP_FUNC_FAILED;
+}
+
+
+/* Task Management Functions. Must be called from process context. */
+
+/**
+ * isci_abort_task_process_cb() - This is a helper function for the abort task
+ * TMF command. It manages the request state with respect to the successful
+ * transmission / completion of the abort task request.
+ * @cb_state: This parameter specifies when this function was called - after
+ * the TMF request has been started and after it has timed-out.
+ * @tmf: This parameter specifies the TMF in progress.
+ *
+ *
+ */
+static void isci_abort_task_process_cb(
+ enum isci_tmf_cb_state cb_state,
+ struct isci_tmf *tmf,
+ void *cb_data)
+{
+ struct isci_request *old_request;
+
+ old_request = (struct isci_request *)cb_data;
+
+ dev_dbg(&old_request->isci_host->pdev->dev,
+ "%s: tmf=%p, old_request=%p\n",
+ __func__, tmf, old_request);
+
+ switch (cb_state) {
+
+ case isci_tmf_started:
+ /* The TMF has been started. Nothing to do here, since the
+ * request state was already set to "aborted" by the abort
+ * task function.
+ */
+ BUG_ON(old_request->status != aborted);
+ break;
+
+ case isci_tmf_timed_out:
+
+ /* Set the task's state to "aborting", since the abort task
+ * function thread set it to "aborted" (above) in anticipation
+ * of the task management request working correctly. Since the
+ * timeout has now fired, the TMF request failed. We set the
+ * state such that the request completion will indicate the
+ * device is no longer present.
+ */
+ isci_request_change_state(old_request, aborting);
+ break;
+
+ default:
+ dev_err(&old_request->isci_host->pdev->dev,
+ "%s: Bad cb_state (%d): tmf=%p, old_request=%p\n",
+ __func__, cb_state, tmf, old_request);
+ break;
+ }
+}
+
+/**
+ * isci_task_abort_task() - This function is one of the SAS Domain Template
+ * functions. This function is called by libsas to abort a specified task.
+ * @task: This parameter specifies the SAS task to abort.
+ *
+ * status, zero indicates success.
+ */
+int isci_task_abort_task(struct sas_task *task)
+{
+ DECLARE_COMPLETION_ONSTACK(aborted_io_completion);
+ struct isci_request *old_request = NULL;
+ struct isci_remote_device *isci_device = NULL;
+ struct isci_host *isci_host = NULL;
+ struct isci_tmf tmf;
+ int ret = TMF_RESP_FUNC_FAILED;
+ unsigned long flags;
+ bool any_dev_reset, device_stopping;
+
+ /* Get the isci_request reference from the task. Note that
+ * this check does not depend on the pending request list
+ * in the device, because tasks driving resets may land here
+ * after completion in the core.
+ */
+ old_request = isci_task_get_request_from_task(task, &isci_host,
+ &isci_device);
+
+ dev_dbg(&isci_host->pdev->dev,
+ "%s: task = %p\n", __func__, task);
+
+ /* Check if the device has been / is currently being removed.
+ * If so, no task management will be done, and the I/O will
+ * be terminated.
+ */
+ device_stopping = (isci_device->status == isci_stopping)
+ || (isci_device->status == isci_stopped);
+
+#ifdef NOMORE
+ /* This abort task function is the first stop of the libsas error
+ * handler thread. Since libsas is executing in a thread with a
+ * referernce to the "task" parameter, that task cannot be completed
+ * directly back to the upper layers. In order to make sure that
+ * the task is managed correctly if this abort task fails, set the
+ * "SAS_TASK_STATE_ABORTED" bit now such that completions up the
+ * stack will be intercepted and only allowed to happen in the
+ * libsas SCSI error handler thread.
+ */
+ spin_lock_irqsave(&task->task_state_lock, flags);
+ task->task_state_flags |= SAS_TASK_STATE_ABORTED;
+ spin_unlock_irqrestore(&task->task_state_lock, flags);
+#endif /* NOMORE */
+
+ /* This version of the driver will fail abort requests for
+ * SATA/STP. Failing the abort request this way will cause the
+ * SCSI error handler thread to escalate to LUN reset
+ */
+ if (sas_protocol_ata(task->task_proto) && !device_stopping) {
+ dev_warn(&isci_host->pdev->dev,
+ " task %p is for a STP/SATA device;"
+ " returning TMF_RESP_FUNC_FAILED\n"
+ " to cause a LUN reset...\n", task);
+ return TMF_RESP_FUNC_FAILED;
+ }
+
+ dev_dbg(&isci_host->pdev->dev,
+ "%s: old_request == %p\n", __func__, old_request);
+
+ spin_lock_irqsave(&task->task_state_lock, flags);
+
+ /* Don't do resets to stopping devices. */
+ if (device_stopping)
+ task->task_state_flags &= ~SAS_TASK_NEED_DEV_RESET;
+
+ /* See if there is a pending device reset for this device. */
+ any_dev_reset = task->task_state_flags & SAS_TASK_NEED_DEV_RESET;
+
+ spin_unlock_irqrestore(&task->task_state_lock, flags);
+
+ if ((isci_device != NULL) && !device_stopping)
+ any_dev_reset = any_dev_reset
+ || isci_device_is_reset_pending(isci_host,
+ isci_device
+ );
+
+ /* If the extraction of the request reference from the task
+ * failed, then the request has been completed (or if there is a
+ * pending reset then this abort request function must be failed
+ * in order to escalate to the target reset).
+ */
+ if ((old_request == NULL) ||
+ ((old_request != NULL) &&
+ (old_request->sci_request_handle == NULL) &&
+ (old_request->complete_in_target)) ||
+ any_dev_reset) {
+
+ spin_lock_irqsave(&task->task_state_lock, flags);
+
+ /* If the device reset task flag is set, fail the task
+ * management request. Otherwise, the original request
+ * has completed.
+ */
+ if (any_dev_reset) {
+
+ /* Turn off the task's DONE to make sure this
+ * task is escalated to a target reset.
+ */
+ task->task_state_flags &= ~SAS_TASK_STATE_DONE;
+
+ /* Fail the task management request in order to
+ * escalate to the target reset.
+ */
+ ret = TMF_RESP_FUNC_FAILED;
+
+ dev_dbg(&isci_host->pdev->dev,
+ "%s: Failing task abort in order to "
+ "escalate to target reset because\n"
+ "SAS_TASK_NEED_DEV_RESET is set for "
+ "task %p on dev %p\n",
+ __func__, task, isci_device);
+
+ } else {
+ ret = TMF_RESP_FUNC_COMPLETE;
+
+ dev_dbg(&isci_host->pdev->dev,
+ "%s: abort task not needed for %p\n",
+ __func__, task);
+
+ /* The request has already completed and there
+ * is nothing to do here other than to set the task
+ * done bit, and indicate that the task abort function
+ * was sucessful.
+ */
+ isci_set_task_doneflags(task);
+
+ /* Set the abort bit to make sure that libsas sticks the
+ * task in the completed task queue.
+ */
+/* task->task_state_flags |= SAS_TASK_STATE_ABORTED; */
+
+ /* Check for the situation where the request was
+ * left around on the device list but the
+ * request already completed.
+ */
+ if (old_request && !old_request->sci_request_handle) {
+
+ isci_request_cleanup_completed_loiterer(
+ isci_host, isci_device, old_request
+ );
+ }
+ }
+ spin_unlock_irqrestore(&task->task_state_lock, flags);
+
+ return ret;
+ }
+
+ spin_lock_irqsave(&isci_host->scic_lock, flags);
+
+ /* Sanity check the request status, and set the I/O kernel completion
+ * struct that will be triggered when the request completes.
+ */
+ if (isci_task_validate_request_to_abort(
+ old_request,
+ isci_host,
+ isci_device,
+ &aborted_io_completion)
+ == unallocated) {
+ dev_dbg(&isci_host->pdev->dev,
+ "%s: old_request not valid for device = %p\n",
+ __func__,
+ isci_device);
+ old_request = NULL;
+ }
+
+ if (!old_request) {
+
+ /* There is no isci_request attached to the sas_task.
+ * It must have been completed and detached.
+ */
+ dev_dbg(&isci_host->pdev->dev,
+ "%s: old_request == NULL\n",
+ __func__);
+
+ spin_unlock_irqrestore(&isci_host->scic_lock, flags);
+
+ /* Set the state on the task. */
+ isci_task_all_done(task);
+
+ return TMF_RESP_FUNC_COMPLETE;
+ }
+ if (task->task_proto == SAS_PROTOCOL_SMP || device_stopping) {
+
+ if (device_stopping)
+ dev_dbg(&isci_host->pdev->dev,
+ "%s: device is stopping, thus no TMF\n",
+ __func__);
+ else
+ dev_dbg(&isci_host->pdev->dev,
+ "%s: request is SMP, thus no TMF\n",
+ __func__);
+
+ old_request->complete_in_target = true;
+
+ spin_unlock_irqrestore(&isci_host->scic_lock, flags);
+
+ /* Set the state on the task. */
+ isci_task_all_done(task);
+
+ ret = TMF_RESP_FUNC_COMPLETE;
+
+ /* Stopping and SMP devices are not sent a TMF, and are not
+ * reset, but the outstanding I/O request is terminated here.
+ *
+ * Clean up the request on our side, and wait for the aborted
+ * I/O to complete.
+ */
+ isci_terminate_request_core(isci_host, isci_device, old_request,
+ &aborted_io_completion);
+ } else {
+ /* Fill in the tmf stucture */
+ isci_task_build_tmf(&tmf, isci_device, isci_tmf_ssp_task_abort,
+ isci_abort_task_process_cb, old_request);
+
+ tmf.io_tag = scic_io_request_get_io_tag(
+ old_request->sci_request_handle
+ );
+
+ spin_unlock_irqrestore(&isci_host->scic_lock, flags);
+
+ #define ISCI_ABORT_TASK_TIMEOUT_MS 500 /* half second timeout. */
+ ret = isci_task_execute_tmf(isci_host, &tmf,
+ ISCI_ABORT_TASK_TIMEOUT_MS);
+
+ if (ret == TMF_RESP_FUNC_COMPLETE) {
+ old_request->complete_in_target = true;
+
+ /* Clean up the request on our side, and wait for the aborted I/O to
+ * complete.
+ */
+ isci_terminate_request_core(isci_host, isci_device, old_request,
+ &aborted_io_completion);
+
+ /* Set the state on the task. */
+ isci_task_all_done(task);
+ } else
+ dev_err(&isci_host->pdev->dev,
+ "%s: isci_task_send_tmf failed\n",
+ __func__);
+ }
+
+ return ret;
+}
+
+/**
+ * isci_task_abort_task_set() - This function is one of the SAS Domain Template
+ * functions. This is one of the Task Management functoins called by libsas,
+ * to abort all task for the given lun.
+ * @d_device: This parameter specifies the domain device associated with this
+ * request.
+ * @lun: This parameter specifies the lun associated with this request.
+ *
+ * status, zero indicates success.
+ */
+int isci_task_abort_task_set(
+ struct domain_device *d_device,
+ u8 *lun)
+{
+ return TMF_RESP_FUNC_FAILED;
+}
+
+
+/**
+ * isci_task_clear_aca() - This function is one of the SAS Domain Template
+ * functions. This is one of the Task Management functoins called by libsas.
+ * @d_device: This parameter specifies the domain device associated with this
+ * request.
+ * @lun: This parameter specifies the lun associated with this request.
+ *
+ * status, zero indicates success.
+ */
+int isci_task_clear_aca(
+ struct domain_device *d_device,
+ u8 *lun)
+{
+ return TMF_RESP_FUNC_FAILED;
+}
+
+
+
+/**
+ * isci_task_clear_task_set() - This function is one of the SAS Domain Template
+ * functions. This is one of the Task Management functoins called by libsas.
+ * @d_device: This parameter specifies the domain device associated with this
+ * request.
+ * @lun: This parameter specifies the lun associated with this request.
+ *
+ * status, zero indicates success.
+ */
+int isci_task_clear_task_set(
+ struct domain_device *d_device,
+ u8 *lun)
+{
+ return TMF_RESP_FUNC_FAILED;
+}
+
+
+/**
+ * isci_task_query_task() - This function is implemented to cause libsas to
+ * correctly escalate the failed abort to a LUN or target reset (this is
+ * because sas_scsi_find_task libsas function does not correctly interpret
+ * all return codes from the abort task call). When TMF_RESP_FUNC_SUCC is
+ * returned, libsas turns this into a LUN reset; when FUNC_FAILED is
+ * returned, libsas will turn this into a target reset
+ * @task: This parameter specifies the sas task being queried.
+ * @lun: This parameter specifies the lun associated with this request.
+ *
+ * status, zero indicates success.
+ */
+int isci_task_query_task(
+ struct sas_task *task)
+{
+ /* See if there is a pending device reset for this device. */
+ if (task->task_state_flags & SAS_TASK_NEED_DEV_RESET)
+ return TMF_RESP_FUNC_FAILED;
+ else
+ return TMF_RESP_FUNC_SUCC;
+}
+
+/**
+ * isci_task_request_complete() - This function is called by the sci core when
+ * an task request completes.
+ * @isci_host: This parameter specifies the ISCI host object
+ * @request: This parameter is the completed isci_request object.
+ * @completion_status: This parameter specifies the completion status from the
+ * sci core.
+ *
+ * none.
+ */
+void isci_task_request_complete(
+ struct isci_host *isci_host,
+ struct isci_request *request,
+ enum sci_task_status completion_status)
+{
+ struct isci_remote_device *isci_device = request->isci_device;
+ enum isci_request_status old_state;
+ struct isci_tmf *tmf = isci_request_access_tmf(request);
+ struct completion *tmf_complete;
+
+ dev_dbg(&isci_host->pdev->dev,
+ "%s: request = %p, status=%d\n",
+ __func__, request, completion_status);
+
+ old_state = isci_request_change_state(request, completed);
+
+ tmf->status = completion_status;
+ request->complete_in_target = true;
+
+ if (SAS_PROTOCOL_SSP == tmf->proto) {
+
+ memcpy(&tmf->resp.resp_iu,
+ scic_io_request_get_response_iu_address(
+ request->sci_request_handle
+ ),
+ sizeof(struct sci_ssp_response_iu));
+
+ } else if (SAS_PROTOCOL_SATA == tmf->proto) {
+
+ memcpy(&tmf->resp.d2h_fis,
+ scic_stp_io_request_get_d2h_reg_address(
+ request->sci_request_handle
+ ),
+ sizeof(struct sata_fis_reg_d2h)
+ );
+ }
+
+ /* Manage the timer if it is still running. */
+ if (tmf->timeout_timer) {
+
+ isci_timer_stop(tmf->timeout_timer);
+ isci_timer_free(&isci_host->timer_list_struct,
+ tmf->timeout_timer);
+ tmf->timeout_timer = NULL;
+ }
+
+ /* PRINT_TMF( ((struct isci_tmf *)request->task)); */
+ tmf_complete = tmf->complete;
+
+ scic_controller_complete_task(
+ isci_host->core_controller,
+ isci_device->sci_device_handle,
+ request->sci_request_handle
+ );
+ /* NULL the request handle to make sure it cannot be terminated
+ * or completed again.
+ */
+ request->sci_request_handle = NULL;
+
+ isci_request_change_state(request, unallocated);
+ list_del_init(&request->dev_node);
+
+ /* The task management part completes last. */
+ complete(tmf_complete);
+}
+
+
+/**
+ * isci_task_ssp_request_get_lun() - This function is called by the sci core to
+ * retrieve the lun for a given task request.
+ * @request: This parameter is the isci_request object.
+ *
+ * lun for specified task request.
+ */
+u32 isci_task_ssp_request_get_lun(struct isci_request *request)
+{
+ struct isci_tmf *isci_tmf = isci_request_access_tmf(request);
+
+ dev_dbg(&request->isci_host->pdev->dev,
+ "%s: lun = %d\n", __func__, isci_tmf->lun[0]);
+/* @todo: build lun from array of bytes to 32 bit */
+ return isci_tmf->lun[0];
+}
+
+/**
+ * isci_task_ssp_request_get_function() - This function is called by the sci
+ * core to retrieve the function for a given task request.
+ * @request: This parameter is the isci_request object.
+ *
+ * function code for specified task request.
+ */
+u8 isci_task_ssp_request_get_function(struct isci_request *request)
+{
+ struct isci_tmf *isci_tmf = isci_request_access_tmf(request);
+
+ dev_dbg(&request->isci_host->pdev->dev,
+ "%s: func = %d\n", __func__, isci_tmf->tmf_code);
+
+ return isci_tmf->tmf_code;
+}
+
+/**
+ * isci_task_ssp_request_get_io_tag_to_manage() - This function is called by
+ * the sci core to retrieve the io tag for a given task request.
+ * @request: This parameter is the isci_request object.
+ *
+ * io tag for specified task request.
+ */
+u16 isci_task_ssp_request_get_io_tag_to_manage(struct isci_request *request)
+{
+ u16 io_tag = SCI_CONTROLLER_INVALID_IO_TAG;
+
+ if (tmf_task == request->ttype) {
+ struct isci_tmf *tmf = isci_request_access_tmf(request);
+ io_tag = tmf->io_tag;
+ }
+
+ dev_dbg(&request->isci_host->pdev->dev,
+ "%s: request = %p, io_tag = %d\n",
+ __func__, request, io_tag);
+
+ return io_tag;
+}
+
+/**
+ * isci_task_ssp_request_get_response_data_address() - This function is called
+ * by the sci core to retrieve the response data address for a given task
+ * request.
+ * @request: This parameter is the isci_request object.
+ *
+ * response data address for specified task request.
+ */
+void *isci_task_ssp_request_get_response_data_address(
+ struct isci_request *request)
+{
+ struct isci_tmf *isci_tmf = isci_request_access_tmf(request);
+
+ return &isci_tmf->resp.resp_iu;
+}
+
+/**
+ * isci_task_ssp_request_get_response_data_length() - This function is called
+ * by the sci core to retrieve the response data length for a given task
+ * request.
+ * @request: This parameter is the isci_request object.
+ *
+ * response data length for specified task request.
+ */
+u32 isci_task_ssp_request_get_response_data_length(
+ struct isci_request *request)
+{
+ struct isci_tmf *isci_tmf = isci_request_access_tmf(request);
+
+ return sizeof(isci_tmf->resp.resp_iu);
+}
+
+/**
+ * isci_bus_reset_handler() - This function performs a target reset of the
+ * device referenced by "cmd'. This function is exported through the
+ * "struct scsi_host_template" structure such that it is called when an I/O
+ * recovery process has escalated to a target reset. Note that this function
+ * is called from the scsi error handler event thread, so may block on calls.
+ * @scsi_cmd: This parameter specifies the target to be reset.
+ *
+ * SUCCESS if the reset process was successful, else FAILED.
+ */
+int isci_bus_reset_handler(struct scsi_cmnd *cmd)
+{
+ unsigned long flags = 0;
+ struct isci_host *isci_host = NULL;
+ enum sci_status status;
+ int base_status;
+ struct isci_remote_device *isci_dev
+ = isci_dev_from_domain_dev(
+ sdev_to_domain_dev(cmd->device));
+
+ dev_dbg(&cmd->device->sdev_gendev,
+ "%s: cmd %p, isci_dev %p\n",
+ __func__, cmd, isci_dev);
+
+ if (!isci_dev) {
+ dev_warn(&cmd->device->sdev_gendev,
+ "%s: isci_dev is GONE!\n",
+ __func__);
+
+ return TMF_RESP_FUNC_COMPLETE; /* Nothing to reset. */
+ }
+
+ if (isci_dev->isci_port != NULL)
+ isci_host = isci_dev->isci_port->isci_host;
+
+ if (isci_host != NULL)
+ spin_lock_irqsave(&isci_host->scic_lock, flags);
+
+ status = scic_remote_device_reset(isci_dev->sci_device_handle);
+ if (status != SCI_SUCCESS) {
+
+ if (isci_host != NULL)
+ spin_unlock_irqrestore(&isci_host->scic_lock, flags);
+
+ scmd_printk(KERN_WARNING, cmd,
+ "%s: scic_remote_device_reset(%p) returned %d!\n",
+ __func__, isci_dev, status);
+
+ return TMF_RESP_FUNC_FAILED;
+ }
+ if (isci_host != NULL)
+ spin_unlock_irqrestore(&isci_host->scic_lock, flags);
+
+ /* Stop I/O to the remote device. */
+ isci_device_set_host_quiesce_lock_state(isci_dev, true);
+
+ /* Make sure all pending requests are able to be fully terminated. */
+ isci_device_clear_reset_pending(isci_dev);
+
+ /* Terminate in-progress I/O now. */
+ isci_remote_device_nuke_requests(isci_dev);
+
+ /* Call into the libsas default handler (which calls sas_phy_reset). */
+ base_status = sas_eh_bus_reset_handler(cmd);
+
+ if (base_status != SUCCESS) {
+
+ /* There can be cases where the resets to individual devices
+ * behind an expander will fail because of an unplug of the
+ * expander itself.
+ */
+ scmd_printk(KERN_WARNING, cmd,
+ "%s: sas_eh_bus_reset_handler(%p) returned %d!\n",
+ __func__, cmd, base_status);
+ }
+
+ /* WHAT TO DO HERE IF sas_phy_reset FAILS? */
+
+ if (isci_host != NULL)
+ spin_lock_irqsave(&isci_host->scic_lock, flags);
+ status
+ = scic_remote_device_reset_complete(isci_dev->sci_device_handle);
+
+ if (isci_host != NULL)
+ spin_unlock_irqrestore(&isci_host->scic_lock, flags);
+
+ if (status != SCI_SUCCESS) {
+ scmd_printk(KERN_WARNING, cmd,
+ "%s: scic_remote_device_reset_complete(%p) "
+ "returned %d!\n",
+ __func__, isci_dev, status);
+ }
+ /* WHAT TO DO HERE IF scic_remote_device_reset_complete FAILS? */
+
+ dev_dbg(&cmd->device->sdev_gendev,
+ "%s: cmd %p, isci_dev %p complete.\n",
+ __func__, cmd, isci_dev);
+
+ /* Resume I/O to the remote device. */
+ isci_device_set_host_quiesce_lock_state(isci_dev, false);
+
+ return TMF_RESP_FUNC_COMPLETE;
+}
diff --git a/drivers/scsi/isci/task.h b/drivers/scsi/isci/task.h
new file mode 100644
index 000000000000..ced6a8be1b31
--- /dev/null
+++ b/drivers/scsi/isci/task.h
@@ -0,0 +1,368 @@
+/*
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Intel Corporation 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
+ * OWNER 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.
+ */
+
+#if !defined(_ISCI_TASK_H_)
+#define _ISCI_TASK_H_
+
+struct isci_request;
+struct isci_host;
+
+/**
+ * enum isci_tmf_cb_state - This enum defines the possible states in which the
+ * TMF callback function is invoked during the TMF execution process.
+ *
+ *
+ */
+enum isci_tmf_cb_state {
+
+ isci_tmf_init_state = 0,
+ isci_tmf_started,
+ isci_tmf_timed_out
+};
+
+/**
+ * enum isci_tmf_function_codes - This enum defines the possible preparations
+ * of task management requests.
+ *
+ *
+ */
+enum isci_tmf_function_codes {
+
+ isci_tmf_func_none = 0,
+ isci_tmf_ssp_task_abort = TMF_ABORT_TASK,
+ isci_tmf_ssp_lun_reset = TMF_LU_RESET,
+ isci_tmf_sata_srst_high = TMF_LU_RESET + 0x100, /* Non SCSI */
+ isci_tmf_sata_srst_low = TMF_LU_RESET + 0x101 /* Non SCSI */
+};
+/**
+ * struct isci_tmf - This class represents the task management object which
+ * acts as an interface to libsas for processing task management requests
+ *
+ *
+ */
+struct isci_tmf {
+
+ struct completion *complete;
+ enum sas_protocol proto;
+ union {
+ struct sci_ssp_response_iu resp_iu;
+ struct dev_to_host_fis d2h_fis;
+ } resp;
+ unsigned char lun[8];
+ u16 io_tag;
+ struct isci_remote_device *device;
+ enum isci_tmf_function_codes tmf_code;
+ int status;
+
+ struct isci_timer *timeout_timer;
+
+ /* The optional callback function allows the user process to
+ * track the TMF transmit / timeout conditions.
+ */
+ void (*cb_state_func)(
+ enum isci_tmf_cb_state,
+ struct isci_tmf *, void *);
+ void *cb_data;
+
+};
+
+static inline void isci_print_tmf(
+ struct isci_tmf *tmf)
+{
+ if (SAS_PROTOCOL_SATA == tmf->proto)
+ dev_dbg(&tmf->device->isci_port->isci_host->pdev->dev,
+ "%s: status = %x\n"
+ "tmf->resp.d2h_fis.status = %x\n"
+ "tmf->resp.d2h_fis.error = %x\n",
+ __func__,
+ tmf->status,
+ tmf->resp.d2h_fis.status,
+ tmf->resp.d2h_fis.error);
+ else
+ dev_dbg(&tmf->device->isci_port->isci_host->pdev->dev,
+ "%s: status = %x\n"
+ "tmf->resp.resp_iu.data_present = %x\n"
+ "tmf->resp.resp_iu.status = %x\n"
+ "tmf->resp.resp_iu.data_length = %x\n"
+ "tmf->resp.resp_iu.data[0] = %x\n"
+ "tmf->resp.resp_iu.data[1] = %x\n"
+ "tmf->resp.resp_iu.data[2] = %x\n"
+ "tmf->resp.resp_iu.data[3] = %x\n",
+ __func__,
+ tmf->status,
+ tmf->resp.resp_iu.data_present,
+ tmf->resp.resp_iu.status,
+ (tmf->resp.resp_iu.response_data_length[0] << 24) +
+ (tmf->resp.resp_iu.response_data_length[1] << 16) +
+ (tmf->resp.resp_iu.response_data_length[2] << 8) +
+ tmf->resp.resp_iu.response_data_length[3],
+ tmf->resp.resp_iu.data[0],
+ tmf->resp.resp_iu.data[1],
+ tmf->resp.resp_iu.data[2],
+ tmf->resp.resp_iu.data[3]);
+}
+
+
+int isci_task_execute_task(
+ struct sas_task *task,
+ int num,
+ gfp_t gfp_flags);
+
+int isci_task_abort_task(
+ struct sas_task *task);
+
+int isci_task_abort_task_set(
+ struct domain_device *d_device,
+ u8 *lun);
+
+int isci_task_clear_aca(
+ struct domain_device *d_device,
+ u8 *lun);
+
+int isci_task_clear_task_set(
+ struct domain_device *d_device,
+ u8 *lun);
+
+int isci_task_query_task(
+ struct sas_task *task);
+
+int isci_task_lu_reset(
+ struct domain_device *d_device,
+ u8 *lun);
+
+int isci_task_clear_nexus_port(
+ struct asd_sas_port *port);
+
+int isci_task_clear_nexus_ha(
+ struct sas_ha_struct *ha);
+
+int isci_task_I_T_nexus_reset(
+ struct domain_device *d_device);
+
+void isci_task_request_complete(
+ struct isci_host *isci_host,
+ struct isci_request *request,
+ enum sci_task_status completion_status);
+
+u16 isci_task_ssp_request_get_io_tag_to_manage(
+ struct isci_request *request);
+
+u8 isci_task_ssp_request_get_function(
+ struct isci_request *request);
+
+u32 isci_task_ssp_request_get_lun(
+ struct isci_request *request);
+
+void *isci_task_ssp_request_get_response_data_address(
+ struct isci_request *request);
+
+u32 isci_task_ssp_request_get_response_data_length(
+ struct isci_request *request);
+
+int isci_queuecommand(
+ struct scsi_cmnd *scsi_cmd,
+ void (*donefunc)(struct scsi_cmnd *));
+
+int isci_bus_reset_handler(struct scsi_cmnd *cmd);
+
+void isci_task_build_tmf(
+ struct isci_tmf *tmf,
+ struct isci_remote_device *isci_device,
+ enum isci_tmf_function_codes code,
+ void (*tmf_sent_cb)(
+ enum isci_tmf_cb_state,
+ struct isci_tmf *, void *),
+ void *cb_data);
+
+int isci_task_execute_tmf(
+ struct isci_host *isci_host,
+ struct isci_tmf *tmf,
+ unsigned long timeout_ms);
+
+/**
+ * enum isci_completion_selection - This enum defines the possible actions to
+ * take with respect to a given request's notification back to libsas.
+ *
+ *
+ */
+enum isci_completion_selection {
+
+ isci_perform_normal_io_completion, /* Normal notify (task_done) */
+ isci_perform_aborted_io_completion, /* No notification. */
+ isci_perform_error_io_completion /* Use sas_task_abort */
+};
+
+static inline void isci_set_task_doneflags(
+ struct sas_task *task)
+{
+ /* Since no futher action will be taken on this task,
+ * make sure to mark it complete from the lldd perspective.
+ */
+ task->task_state_flags |= SAS_TASK_STATE_DONE;
+ task->task_state_flags &= ~SAS_TASK_AT_INITIATOR;
+ task->task_state_flags &= ~SAS_TASK_STATE_PENDING;
+}
+/**
+ * isci_task_all_done() - This function clears the task bits to indicate the
+ * LLDD is done with the task.
+ *
+ *
+ */
+static inline void isci_task_all_done(
+ struct sas_task *task)
+{
+ unsigned long flags;
+
+ /* Since no futher action will be taken on this task,
+ * make sure to mark it complete from the lldd perspective.
+ */
+ spin_lock_irqsave(&task->task_state_lock, flags);
+ isci_set_task_doneflags(task);
+ spin_unlock_irqrestore(&task->task_state_lock, flags);
+}
+
+/**
+ * isci_task_set_completion_status() - This function sets the completion status
+ * for the request.
+ * @task: This parameter is the completed request.
+ * @response: This parameter is the response code for the completed task.
+ * @status: This parameter is the status code for the completed task.
+ *
+ * none.
+ */
+static inline void isci_task_set_completion_status(
+ struct sas_task *task,
+ enum service_response response,
+ enum exec_status status,
+ enum isci_completion_selection task_notification_selection)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&task->task_state_lock, flags);
+
+ task->task_status.resp = response;
+ task->task_status.stat = status;
+
+ /* Don't set DONE (or clear AT_INITIATOR) for any task going into the
+ * error path, because the EH interprets that as a handled error condition.
+ * Also don't take action if there is a reset pending.
+ */
+ if ((task_notification_selection != isci_perform_error_io_completion)
+ && !(task->task_state_flags & SAS_TASK_NEED_DEV_RESET))
+ isci_set_task_doneflags(task);
+
+ spin_unlock_irqrestore(&task->task_state_lock, flags);
+}
+/**
+ * isci_task_complete_for_upper_layer() - This function completes the request
+ * to the upper layer driver.
+ * @host: This parameter is a pointer to the host on which the the request
+ * should be queued (either as an error or success).
+ * @request: This parameter is the completed request.
+ * @response: This parameter is the response code for the completed task.
+ * @status: This parameter is the status code for the completed task.
+ *
+ * none.
+ */
+static inline void isci_task_complete_for_upper_layer(
+ struct sas_task *task,
+ enum service_response response,
+ enum exec_status status,
+ enum isci_completion_selection task_notification_selection)
+{
+ isci_task_set_completion_status(task, response, status,
+ task_notification_selection);
+
+
+ /* Tasks aborted specifically by a call to the lldd_abort_task
+ * function should not be completed to the host in the regular path.
+ */
+ switch (task_notification_selection) {
+ case isci_perform_normal_io_completion:
+ /* Normal notification (task_done) */
+ dev_dbg(task->dev->port->ha->dev,
+ "%s: Normal - task = %p, response=%d, status=%d\n",
+ __func__, task, response, status);
+ task->task_done(task);
+ task->lldd_task = NULL;
+ break;
+
+ case isci_perform_aborted_io_completion:
+ /* No notification because this request is already in the
+ * abort path.
+ */
+ dev_warn(task->dev->port->ha->dev,
+ "%s: Aborted - task = %p, response=%d, status=%d\n",
+ __func__, task, response, status);
+ break;
+
+ case isci_perform_error_io_completion:
+ /* Use sas_task_abort */
+ dev_warn(task->dev->port->ha->dev,
+ "%s: Error - task = %p, response=%d, status=%d\n",
+ __func__, task, response, status);
+ sas_task_abort(task);
+ break;
+
+ default:
+ dev_warn(task->dev->port->ha->dev,
+ "%s: isci task notification default case!",
+ __func__);
+ sas_task_abort(task);
+ break;
+ }
+}
+
+#endif /* !defined(_SCI_TASK_H_) */
diff --git a/drivers/scsi/isci/timers.c b/drivers/scsi/isci/timers.c
new file mode 100644
index 000000000000..ca723089ee88
--- /dev/null
+++ b/drivers/scsi/isci/timers.c
@@ -0,0 +1,319 @@
+/*
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Intel Corporation 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
+ * OWNER 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.
+ */
+
+#include "isci.h"
+#include "timers.h"
+
+
+/**
+ * isci_timer_list_construct() - This method contrucst the SCI Timer List
+ * object used by the SCI Module class. The construction process involves
+ * creating isci_timer objects and adding them to the SCI Timer List
+ * object's list member. The number of isci_timer objects is determined by
+ * the timer_list_size parameter.
+ * @isci_timer_list: This parameter points to the SCI Timer List object being
+ * constructed. The calling routine is responsible for allocating the memory
+ * for isci_timer_list and initializing the timer list_head member of
+ * isci_timer_list.
+ * @timer_list_size: This parameter specifies the number of isci_timer objects
+ * contained by the SCI Timer List. which this timer is to be associated.
+ *
+ * This method returns an error code indicating sucess or failure. The user
+ * should check for possible memory allocation error return otherwise, a zero
+ * indicates success.
+ */
+int isci_timer_list_construct(
+ struct isci_timer_list *isci_timer_list,
+ int timer_list_size)
+{
+ struct isci_timer *isci_timer;
+ int i;
+ int err = 0;
+
+
+ for (i = 0; i < timer_list_size; i++) {
+
+ isci_timer = kzalloc(sizeof(*isci_timer), GFP_KERNEL);
+
+ if (!isci_timer) {
+
+ err = -ENOMEM;
+ break;
+ }
+ isci_timer->used = 0;
+ isci_timer->stopped = 1;
+ isci_timer->parent = isci_timer_list;
+ list_add(&isci_timer->node, &isci_timer_list->timers);
+ }
+
+ return 0;
+
+}
+
+
+/**
+ * isci_timer_list_destroy() - This method destroys the SCI Timer List object
+ * used by the SCI Module class. The destruction process involves freeing
+ * memory allocated for isci_timer objects on the SCI Timer List object's
+ * timers list_head member. If any isci_timer objects are mark as "in use",
+ * they are not freed and the function returns an error code of -EBUSY.
+ * @isci_timer_list: This parameter points to the SCI Timer List object being
+ * destroyed.
+ *
+ * This method returns an error code indicating sucess or failure. The user
+ * should check for possible -EBUSY error return, in the event of one or more
+ * isci_timers still "in use", otherwise, a zero indicates success.
+ */
+int isci_timer_list_destroy(
+ struct isci_timer_list *isci_timer_list)
+{
+ struct isci_timer *timer, *tmp;
+
+ list_for_each_entry_safe(timer, tmp, &isci_timer_list->timers, node) {
+ isci_timer_free(isci_timer_list, timer);
+ list_del(&timer->node);
+ kfree(timer);
+ }
+ return 0;
+}
+
+
+
+static void isci_timer_restart(struct isci_timer *isci_timer)
+{
+ struct timer_list *timer =
+ &isci_timer->timer;
+ unsigned long timeout;
+
+ dev_dbg(&isci_timer->isci_host->pdev->dev,
+ "%s: isci_timer = %p\n", __func__, isci_timer);
+
+ isci_timer->restart = 0;
+ isci_timer->stopped = 0;
+ timeout = isci_timer->timeout_value;
+ timeout = (timeout * HZ) / 1000;
+ timeout = timeout ? timeout : 1;
+ mod_timer(timer, jiffies + timeout);
+}
+
+/**
+ * This method pulls an isci_timer object off of the list for the SCI Timer
+ * List object specified, marks the isci_timer as "in use" and initializes
+ * it with user callback function and cookie data. The timer is not start at
+ * this time, just reserved for the user.
+ * @isci_timer_list: This parameter points to the SCI Timer List from which the
+ * timer is reserved.
+ * @cookie: This parameter specifies a piece of information that the user must
+ * retain. This cookie is to be supplied by the user anytime a timeout
+ * occurs for the created timer.
+ * @timer_callback: This parameter specifies the callback method to be invoked
+ * whenever the timer expires.
+ *
+ * This method returns a pointer to an isci_timer object reserved from the SCI
+ * Timer List. The pointer will be utilized for all further interactions
+ * relating to this timer.
+ */
+
+static void timer_function(unsigned long data)
+{
+
+ struct isci_timer *timer = (struct isci_timer *)data;
+ struct isci_host *isci_host = timer->isci_host;
+ unsigned long flags;
+
+ dev_dbg(&isci_host->pdev->dev,
+ "%s: isci_timer = %p\n", __func__, timer);
+
+ if (isci_stopped == isci_host_get_state(isci_host)) {
+ timer->stopped = 1;
+ return;
+ }
+
+ spin_lock_irqsave(&isci_host->scic_lock, flags);
+
+ if (!timer->stopped) {
+ timer->stopped = 1;
+ timer->timer_callback(timer->cookie);
+
+ if (timer->restart)
+ isci_timer_restart(timer);
+ }
+
+ spin_unlock_irqrestore(&isci_host->scic_lock, flags);
+}
+
+
+struct isci_timer *isci_timer_create(
+ struct isci_timer_list *isci_timer_list,
+ struct isci_host *isci_host,
+ void *cookie,
+ void (*timer_callback)(void *))
+{
+
+ struct timer_list *timer;
+ struct isci_timer *isci_timer;
+ struct list_head *timer_list =
+ &isci_timer_list->timers;
+ unsigned long flags;
+
+ spin_lock_irqsave(&isci_host->scic_lock, flags);
+
+ if (list_empty(timer_list)) {
+ spin_unlock_irqrestore(&isci_host->scic_lock, flags);
+ return NULL;
+ }
+
+ isci_timer = list_entry(timer_list->next, struct isci_timer, node);
+
+ if (isci_timer->used) {
+ spin_unlock_irqrestore(&isci_host->scic_lock, flags);
+ return NULL;
+ }
+ isci_timer->used = 1;
+ isci_timer->stopped = 1;
+ list_move_tail(&isci_timer->node, timer_list);
+
+ spin_unlock_irqrestore(&isci_host->scic_lock, flags);
+
+ timer = &isci_timer->timer;
+ timer->data = (unsigned long)isci_timer;
+ timer->function = timer_function;
+ isci_timer->cookie = cookie;
+ isci_timer->timer_callback = timer_callback;
+ isci_timer->isci_host = isci_host;
+
+ dev_dbg(&isci_host->pdev->dev,
+ "%s: isci_timer = %p\n", __func__, isci_timer);
+
+ return isci_timer;
+}
+
+/**
+ * isci_timer_free() - This method frees the isci_timer, marking it "free to
+ * use", then places its back at the head of the timers list for the SCI
+ * Timer List object specified.
+ * @isci_timer_list: This parameter points to the SCI Timer List from which the
+ * timer is reserved.
+ * @isci_timer: This parameter specifies the timer to be freed.
+ *
+ */
+void isci_timer_free(
+ struct isci_timer_list *isci_timer_list,
+ struct isci_timer *isci_timer)
+{
+ struct list_head *timer_list = &isci_timer_list->timers;
+
+ dev_dbg(&isci_timer->isci_host->pdev->dev,
+ "%s: isci_timer = %p\n", __func__, isci_timer);
+
+ if (list_empty(timer_list))
+ return;
+
+ isci_timer->used = 0;
+ list_move(&isci_timer->node, timer_list);
+
+ if (!isci_timer->stopped) {
+ del_timer(&isci_timer->timer);
+ isci_timer->stopped = 1;
+ }
+}
+
+/**
+ * isci_timer_start() - This method starts the specified isci_timer, with the
+ * specified timeout value.
+ * @isci_timer: This parameter specifies the timer to be started.
+ * @timeout: This parameter specifies the timeout, in milliseconds, after which
+ * the associated callback function will be called.
+ *
+ */
+void isci_timer_start(
+ struct isci_timer *isci_timer,
+ unsigned long timeout)
+{
+ struct timer_list *timer = &isci_timer->timer;
+
+ dev_dbg(&isci_timer->isci_host->pdev->dev,
+ "%s: isci_timer = %p\n", __func__, isci_timer);
+
+ isci_timer->timeout_value = timeout;
+ init_timer(timer);
+ timeout = (timeout * HZ) / 1000;
+ timeout = timeout ? timeout : 1;
+
+ timer->expires = jiffies + timeout;
+ timer->data = (unsigned long)isci_timer;
+ timer->function = timer_function;
+ isci_timer->stopped = 0;
+ isci_timer->restart = 0;
+ add_timer(timer);
+}
+
+/**
+ * isci_timer_stop() - This method stops the supplied isci_timer.
+ * @isci_timer: This parameter specifies the isci_timer to be stopped.
+ *
+ */
+void isci_timer_stop(struct isci_timer *isci_timer)
+{
+ dev_dbg(&isci_timer->isci_host->pdev->dev,
+ "%s: isci_timer = %p\n", __func__, isci_timer);
+
+ if (isci_timer->stopped)
+ return;
+
+ isci_timer->stopped = 1;
+
+ del_timer(&isci_timer->timer);
+}
diff --git a/drivers/scsi/isci/timers.h b/drivers/scsi/isci/timers.h
new file mode 100644
index 000000000000..ca5c2159a1c2
--- /dev/null
+++ b/drivers/scsi/isci/timers.h
@@ -0,0 +1,126 @@
+/*
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Intel Corporation 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
+ * OWNER 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.
+ */
+
+#if !defined(_SCI_TIMER_H_)
+#define _SCI_TIMER_H_
+
+#include <linux/timer.h>
+#include <linux/types.h>
+
+/***************************************************
+ * isci_timer
+ ***************************************************
+ */
+/**
+ * struct isci_timer_list - This class is the container for all isci_timer
+ * objects
+ *
+ *
+ */
+struct isci_timer_list {
+
+ struct list_head timers;
+};
+
+/**
+ * struct isci_timer - This class represents the timer object used by SCIC. It
+ * wraps the Linux timer_list object.
+ *
+ *
+ */
+struct isci_timer {
+ int used;
+ int stopped;
+ int restart;
+ int timeout_value;
+ void *cookie;
+ void (*timer_callback)(void *);
+ struct list_head node;
+ struct timer_list timer;
+ struct isci_timer_list *parent;
+ struct isci_host *isci_host;
+};
+
+#define to_isci_timer(t) \
+ container_of(t, struct isci_timer, timer);
+
+int isci_timer_list_construct(
+ struct isci_timer_list *isci_timer_list,
+ int timer_list_size);
+
+
+int isci_timer_list_destroy(
+ struct isci_timer_list *isci_timer_list);
+
+struct isci_timer *isci_timer_create(
+ struct isci_timer_list *isci_timer_list,
+ struct isci_host *isci_host,
+ void *cookie,
+ void (*timer_callback)(void *));
+
+void isci_timer_free(
+ struct isci_timer_list *isci_timer_list,
+ struct isci_timer *isci_timer);
+
+void isci_timer_start(
+ struct isci_timer *isci_timer,
+ unsigned long timeout);
+
+void isci_timer_stop(
+ struct isci_timer *isci_timer);
+
+
+#endif /* !defined (_SCI_TIMER_H_) */
+
diff --git a/firmware/Makefile b/firmware/Makefile
index 0d15a3d113a2..5f43bfba3c7a 100644
--- a/firmware/Makefile
+++ b/firmware/Makefile
@@ -82,6 +82,7 @@ fw-shipped-$(CONFIG_SERIAL_8250_CS) += cis/MT5634ZLX.cis cis/RS-COM-2P.cis \
fw-shipped-$(CONFIG_PCMCIA_SMC91C92) += ositech/Xilinx7OD.bin
fw-shipped-$(CONFIG_SCSI_ADVANSYS) += advansys/mcode.bin advansys/38C1600.bin \
advansys/3550.bin advansys/38C0800.bin
+fw-shipped-$(CONFIG_SCSI_ISCI) += isci/isci_firmware.bin
fw-shipped-$(CONFIG_SCSI_QLOGIC_1280) += qlogic/1040.bin qlogic/1280.bin \
qlogic/12160.bin
fw-shipped-$(CONFIG_SCSI_QLOGICPTI) += qlogic/isp1000.bin
diff --git a/firmware/isci/isci_firmware.bin.ihex b/firmware/isci/isci_firmware.bin.ihex
new file mode 100644
index 000000000000..9fc9e60f399c
--- /dev/null
+++ b/firmware/isci/isci_firmware.bin.ihex
@@ -0,0 +1,11 @@
+:1000000023534355204D4147494323000100010834
+:1000100001000000020000000400000008000000D1
+:1000200001000000020000000400000008000000C1
+:1000300002080300000003000000030000000300AA
+:1000400000000300000003000000030000000300A4
+:1000500000000308000000F0FFFFCF5F000000F188
+:10006000FFFFCF5F000000F2FFFFCF5F000000F353
+:10007000FFFFCF5F000000F4FFFFCF5F000000F53F
+:10008000FFFFCF5F000000F6FFFFCF5F000000F72B
+:05009000FFFFCF5FFF40
+:00000001FF