isci: Intel(R) C600 Series Chipset Storage Control Unit Driver
authorDan Williams <dan.j.williams@intel.com>
Sun, 3 Jul 2011 05:56:22 +0000 (22:56 -0700)
committerDan Williams <dan.j.williams@intel.com>
Sun, 3 Jul 2011 05:56:22 +0000 (22:56 -0700)
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>

104 files changed:
drivers/scsi/Kconfig
drivers/scsi/Makefile
drivers/scsi/isci/Makefile [new file with mode: 0644]
drivers/scsi/isci/core/intel_ata.h [new file with mode: 0644]
drivers/scsi/isci/core/intel_sas.h [new file with mode: 0644]
drivers/scsi/isci/core/intel_sat.h [new file with mode: 0644]
drivers/scsi/isci/core/intel_sata.h [new file with mode: 0644]
drivers/scsi/isci/core/intel_scsi.h [new file with mode: 0644]
drivers/scsi/isci/core/sati_device.h [new file with mode: 0644]
drivers/scsi/isci/core/sati_translator_sequence.h [new file with mode: 0644]
drivers/scsi/isci/core/sati_types.h [new file with mode: 0644]
drivers/scsi/isci/core/sci_base_controller.h [new file with mode: 0644]
drivers/scsi/isci/core/sci_base_memory_descriptor_list.c [new file with mode: 0644]
drivers/scsi/isci/core/sci_base_memory_descriptor_list.h [new file with mode: 0644]
drivers/scsi/isci/core/sci_base_phy.h [new file with mode: 0644]
drivers/scsi/isci/core/sci_base_port.h [new file with mode: 0644]
drivers/scsi/isci/core/sci_base_remote_device.h [new file with mode: 0644]
drivers/scsi/isci/core/sci_base_request.h [new file with mode: 0644]
drivers/scsi/isci/core/sci_base_state.h [new file with mode: 0644]
drivers/scsi/isci/core/sci_base_state_machine.c [new file with mode: 0644]
drivers/scsi/isci/core/sci_base_state_machine.h [new file with mode: 0644]
drivers/scsi/isci/core/sci_controller.h [new file with mode: 0644]
drivers/scsi/isci/core/sci_controller_constants.h [new file with mode: 0644]
drivers/scsi/isci/core/sci_memory_descriptor_list.h [new file with mode: 0644]
drivers/scsi/isci/core/sci_object.h [new file with mode: 0644]
drivers/scsi/isci/core/sci_pool.h [new file with mode: 0644]
drivers/scsi/isci/core/sci_status.h [new file with mode: 0644]
drivers/scsi/isci/core/sci_types.h [new file with mode: 0644]
drivers/scsi/isci/core/sci_util.c [new file with mode: 0644]
drivers/scsi/isci/core/sci_util.h [new file with mode: 0644]
drivers/scsi/isci/core/scic_config_parameters.h [new file with mode: 0644]
drivers/scsi/isci/core/scic_controller.h [new file with mode: 0644]
drivers/scsi/isci/core/scic_io_request.h [new file with mode: 0644]
drivers/scsi/isci/core/scic_phy.h [new file with mode: 0644]
drivers/scsi/isci/core/scic_port.h [new file with mode: 0644]
drivers/scsi/isci/core/scic_remote_device.h [new file with mode: 0644]
drivers/scsi/isci/core/scic_sds_controller.c [new file with mode: 0644]
drivers/scsi/isci/core/scic_sds_controller.h [new file with mode: 0644]
drivers/scsi/isci/core/scic_sds_controller_registers.h [new file with mode: 0644]
drivers/scsi/isci/core/scic_sds_pci.h [new file with mode: 0644]
drivers/scsi/isci/core/scic_sds_phy.c [new file with mode: 0644]
drivers/scsi/isci/core/scic_sds_phy.h [new file with mode: 0644]
drivers/scsi/isci/core/scic_sds_phy_registers.h [new file with mode: 0644]
drivers/scsi/isci/core/scic_sds_port.c [new file with mode: 0644]
drivers/scsi/isci/core/scic_sds_port.h [new file with mode: 0644]
drivers/scsi/isci/core/scic_sds_port_configuration_agent.c [new file with mode: 0644]
drivers/scsi/isci/core/scic_sds_port_configuration_agent.h [new file with mode: 0644]
drivers/scsi/isci/core/scic_sds_port_registers.h [new file with mode: 0644]
drivers/scsi/isci/core/scic_sds_remote_device.c [new file with mode: 0644]
drivers/scsi/isci/core/scic_sds_remote_device.h [new file with mode: 0644]
drivers/scsi/isci/core/scic_sds_remote_node_context.c [new file with mode: 0644]
drivers/scsi/isci/core/scic_sds_remote_node_context.h [new file with mode: 0644]
drivers/scsi/isci/core/scic_sds_remote_node_table.c [new file with mode: 0644]
drivers/scsi/isci/core/scic_sds_remote_node_table.h [new file with mode: 0644]
drivers/scsi/isci/core/scic_sds_request.c [new file with mode: 0644]
drivers/scsi/isci/core/scic_sds_request.h [new file with mode: 0644]
drivers/scsi/isci/core/scic_sds_smp_remote_device.c [new file with mode: 0644]
drivers/scsi/isci/core/scic_sds_smp_request.c [new file with mode: 0644]
drivers/scsi/isci/core/scic_sds_smp_request.h [new file with mode: 0644]
drivers/scsi/isci/core/scic_sds_ssp_request.c [new file with mode: 0644]
drivers/scsi/isci/core/scic_sds_stp_packet_request.c [new file with mode: 0644]
drivers/scsi/isci/core/scic_sds_stp_packet_request.h [new file with mode: 0644]
drivers/scsi/isci/core/scic_sds_stp_pio_request.h [new file with mode: 0644]
drivers/scsi/isci/core/scic_sds_stp_remote_device.c [new file with mode: 0644]
drivers/scsi/isci/core/scic_sds_stp_request.c [new file with mode: 0644]
drivers/scsi/isci/core/scic_sds_stp_request.h [new file with mode: 0644]
drivers/scsi/isci/core/scic_sds_unsolicited_frame_control.c [new file with mode: 0644]
drivers/scsi/isci/core/scic_sds_unsolicited_frame_control.h [new file with mode: 0644]
drivers/scsi/isci/core/scic_task_request.h [new file with mode: 0644]
drivers/scsi/isci/core/scic_user_callback.h [new file with mode: 0644]
drivers/scsi/isci/core/scu_completion_codes.h [new file with mode: 0644]
drivers/scsi/isci/core/scu_constants.h [new file with mode: 0644]
drivers/scsi/isci/core/scu_event_codes.h [new file with mode: 0644]
drivers/scsi/isci/core/scu_registers.h [new file with mode: 0644]
drivers/scsi/isci/core/scu_remote_node_context.h [new file with mode: 0644]
drivers/scsi/isci/core/scu_task_context.h [new file with mode: 0644]
drivers/scsi/isci/core/scu_unsolicited_frame.h [new file with mode: 0644]
drivers/scsi/isci/core/scu_viit_data.h [new file with mode: 0644]
drivers/scsi/isci/deprecated.c [new file with mode: 0644]
drivers/scsi/isci/events.c [new file with mode: 0644]
drivers/scsi/isci/firmware/Makefile [new file with mode: 0644]
drivers/scsi/isci/firmware/README [new file with mode: 0644]
drivers/scsi/isci/firmware/create_fw.c [new file with mode: 0644]
drivers/scsi/isci/host.c [new file with mode: 0644]
drivers/scsi/isci/host.h [new file with mode: 0644]
drivers/scsi/isci/init.c [new file with mode: 0644]
drivers/scsi/isci/isci.h [new file with mode: 0644]
drivers/scsi/isci/phy.c [new file with mode: 0644]
drivers/scsi/isci/phy.h [new file with mode: 0644]
drivers/scsi/isci/port.c [new file with mode: 0644]
drivers/scsi/isci/port.h [new file with mode: 0644]
drivers/scsi/isci/remote_device.c [new file with mode: 0644]
drivers/scsi/isci/remote_device.h [new file with mode: 0644]
drivers/scsi/isci/request.c [new file with mode: 0644]
drivers/scsi/isci/request.h [new file with mode: 0644]
drivers/scsi/isci/sata.c [new file with mode: 0644]
drivers/scsi/isci/sata.h [new file with mode: 0644]
drivers/scsi/isci/sci_environment.h [new file with mode: 0644]
drivers/scsi/isci/task.c [new file with mode: 0644]
drivers/scsi/isci/task.h [new file with mode: 0644]
drivers/scsi/isci/timers.c [new file with mode: 0644]
drivers/scsi/isci/timers.h [new file with mode: 0644]
firmware/Makefile
firmware/isci/isci_firmware.bin.ihex [new file with mode: 0644]

index 4a1f029..3aa664f 100644 (file)
@@ -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
index 7ad0b8a..3c08f53 100644 (file)
@@ -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 (file)
index 0000000..34f7af3
--- /dev/null
@@ -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 (file)
index 0000000..48b297e
--- /dev/null
@@ -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 (file)
index 0000000..eb9686e
--- /dev/null
@@ -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 (file)
index 0000000..c4d78ed
--- /dev/null
@@ -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 (file)
index 0000000..47390d5
--- /dev/null
@@ -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 (file)
index 0000000..1e45d3c
--- /dev/null
@@ -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 (file)
index 0000000..4d1cfde
--- /dev/null
@@ -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 (file)
index 0000000..592570d
--- /dev/null
@@ -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 (file)
index 0000000..b6159e0
--- /dev/null
@@ -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 (file)
index 0000000..36c5340
--- /dev/null
@@ -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 (file)
index 0000000..86ae6a8
--- /dev/null
@@ -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 (file)
index 0000000..257d6e3
--- /dev/null
@@ -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 (file)
index 0000000..6c0d9bb
--- /dev/null
@@ -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 (file)
index 0000000..4e2031d
--- /dev/null
@@ -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 (file)
index 0000000..fe6614b
--- /dev/null
@@ -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 (file)
index 0000000..d1b2195
--- /dev/null
@@ -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 (file)
index 0000000..d6b9c1a
--- /dev/null
@@ -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 (file)
index 0000000..5b1e8da
--- /dev/null
@@ -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 (file)
index 0000000..cee38bd
--- /dev/null
@@ -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 (file)
index 0000000..26c3548
--- /dev/null
@@ -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 (file)
index 0000000..06c34c7
--- /dev/null
@@ -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 (file)
index 0000000..44de1c1
--- /dev/null
@@ -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 (file)
index 0000000..9306942
--- /dev/null
@@ -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 (file)
index 0000000..c0d2ea3
--- /dev/null
@@ -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 (file)
index 0000000..72b6108
--- /dev/null
@@ -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 (file)
index 0000000..431735d
--- /dev/null
@@ -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 (file)
index 0000000..5cdd96f
--- /dev/null
@@ -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 (file)
index 0000000..67e2bad
--- /dev/null
@@ -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 (file)
index 0000000..4c16a50
--- /dev/null
@@ -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 (file)
index 0000000..756b14f
--- /dev/null
@@ -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 (file)
index 0000000..7378f33
--- /dev/null
@@ -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 (file)
index 0000000..25a6140
--- /dev/null
@@ -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 (file)
index 0000000..34d22c0
--- /dev/null
@@ -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 (file)
index 0000000..e8c0459
--- /dev/null
@@ -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 (file)
index 0000000..35f7796
--- /dev/null
@@ -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 (file)
index 0000000..afa45f9
--- /dev/null
@@ -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 (file)
index 0000000..b7bec92
--- /dev/null
@@ -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 (file)
index 0000000..2132677
--- /dev/null
@@ -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 (file)
index 0000000..7d012b5
--- /dev/null
@@ -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 (file)
index 0000000..d9691b3
--- /dev/null
@@ -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 (file)
index 0000000..7883819
--- /dev/null
@@ -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 (file)
index 0000000..1af3850
--- /dev/null
@@ -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 (file)
index 0000000..bbb9de5
--- /dev/null
@@ -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 (file)
index 0000000..37d4469
--- /dev/null
@@ -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 (file)
index 0000000..4146735
--- /dev/null
@@ -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 (file)
index 0000000..cf8bc07
--- /dev/null
@@ -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 (file)
index 0000000..21f03bc
--- /dev/null
@@ -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 (file)
index 0000000..44185a2
--- /dev/null
@@ -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 (file)
index 0000000..79fe9a8
--- /dev/null
@@ -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 (file)
index 0000000..59eacf8
--- /dev/null
@@ -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 (file)
index 0000000..77919a2
--- /dev/null
@@ -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 (file)
index 0000000..6ee5fba
--- /dev/null
@@ -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 (file)
index 0000000..c696d24
--- /dev/null
@@ -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 (file)
index 0000000..0691a75
--- /dev/null
@@ -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 (file)
index 0000000..7cf78d3
--- /dev/null
@@ -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 (file)
index 0000000..949d23e
--- /dev/null
@@ -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 (file)
index 0000000..b7c5b83
--- /dev/null
@@ -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 (file)
index 0000000..0d6441c
--- /dev/null
@@ -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 (file)
index 0000000..f52a8e3
--- /dev/null
@@ -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 (file)
index 0000000..fc18b3f
--- /dev/null
@@ -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 (file)
index 0000000..64bf40a
--- /dev/null
@@ -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 (file)
index 0000000..abe8f33
--- /dev/null
@@ -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 (file)
index 0000000..c14f6f1
--- /dev/null
@@ -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 (file)
index 0000000..5578d2b
--- /dev/null
@@ -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 (file)
index 0000000..7ca2f17
--- /dev/null
@@ -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 (file)
index 0000000..49db83f
--- /dev/null
@@ -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 (file)
index 0000000..ef76cb6
--- /dev/null
@@ -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 (file)
index 0000000..6eca5a9
--- /dev/null
@@ -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 (file)
index 0000000..17ee4c8
--- /dev/null
@@ -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 (file)
index 0000000..a99d110
--- /dev/null
@@ -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 (file)
index 0000000..36a945a
--- /dev/null
@@ -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 (file)
index 0000000..175d2b9
--- /dev/null
@@ -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 (file)
index 0000000..8006f2e
--- /dev/null
@@ -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 (file)
index 0000000..d08c51b
--- /dev/null
@@ -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 (file)
index 0000000..590ea02
--- /dev/null
@@ -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 (file)
index 0000000..4601d19
--- /dev/null
@@ -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 (file)
index 0000000..847e687
--- /dev/null
@@ -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 (file)
index 0000000..75f9cd5
--- /dev/null
@@ -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 (file)
index 0000000..5f54461
--- /dev/null
@@ -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 (file)
index 0000000..cf7e428
--- /dev/null
@@ -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 (file)
index 0000000..442caac
--- /dev/null
@@ -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 (file)
index 0000000..6f16f4d
--- /dev/null
@@ -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 (file)
index 0000000..3530076
--- /dev/null
@@ -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 (file)
index 0000000..07b072f
--- /dev/null
@@ -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 (file)
index 0000000..7d984f4
--- /dev/null
@@ -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 (file)
index 0000000..fbda570
--- /dev/null
@@ -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 (file)
index 0000000..44b727f
--- /dev/null
@@ -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 (file)
index 0000000..2343f65
--- /dev/null
@@ -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 (file)
index 0000000..b01b0c6
--- /dev/null
@@ -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 (file)
index 0000000..dbf3c82
--- /dev/null
@@ -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 (file)
index 0000000..a208f81
--- /dev/null
@@ -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 (file)
index 0000000..e564121
--- /dev/null
@@ -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 (file)
index 0000000..5079d4a
--- /dev/null
@@ -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 (file)
index 0000000..19b0eea
--- /dev/null
@@ -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 (file)
index 0000000..b6ba25b
--- /dev/null
@@ -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 (file)
index 0000000..e1020ee
--- /dev/null
@@ -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 (file)
index 0000000..5e6f558
--- /dev/null
@@ -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 (file)
index 0000000..ced6a8b
--- /dev/null
@@ -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 (file)
index 0000000..ca72308
--- /dev/null
@@ -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 (file)
index 0000000..ca5c215
--- /dev/null
@@ -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_) */
+
index 0d15a3d..5f43bfb 100644 (file)
@@ -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 (file)
index 0000000..9fc9e60
--- /dev/null
@@ -0,0 +1,11 @@
+:1000000023534355204D4147494323000100010834
+:1000100001000000020000000400000008000000D1
+:1000200001000000020000000400000008000000C1
+:1000300002080300000003000000030000000300AA
+:1000400000000300000003000000030000000300A4
+:1000500000000308000000F0FFFFCF5F000000F188
+:10006000FFFFCF5F000000F2FFFFCF5F000000F353
+:10007000FFFFCF5F000000F4FFFFCF5F000000F53F
+:10008000FFFFCF5F000000F6FFFFCF5F000000F72B
+:05009000FFFFCF5FFF40
+:00000001FF