summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sys/dev/isci/environment.h100
-rw-r--r--sys/dev/isci/isci.c650
-rw-r--r--sys/dev/isci/isci.h302
-rw-r--r--sys/dev/isci/isci_controller.c653
-rw-r--r--sys/dev/isci/isci_domain.c318
-rw-r--r--sys/dev/isci/isci_interrupt.c229
-rw-r--r--sys/dev/isci/isci_io_request.c923
-rw-r--r--sys/dev/isci/isci_logger.c351
-rw-r--r--sys/dev/isci/isci_oem_parameters.c176
-rw-r--r--sys/dev/isci/isci_remote_device.c298
-rw-r--r--sys/dev/isci/isci_sysctl.c229
-rw-r--r--sys/dev/isci/isci_task_request.c258
-rw-r--r--sys/dev/isci/isci_timer.c166
-rw-r--r--sys/dev/isci/sci_environment.h1
-rw-r--r--sys/dev/isci/scil/intel_ata.h654
-rw-r--r--sys/dev/isci/scil/intel_pci.h90
-rw-r--r--sys/dev/isci/scil/intel_sas.h977
-rw-r--r--sys/dev/isci/scil/intel_sat.h94
-rw-r--r--sys/dev/isci/scil/intel_sata.h284
-rw-r--r--sys/dev/isci/scil/intel_scsi.h540
-rw-r--r--sys/dev/isci/scil/sati.c1250
-rw-r--r--sys/dev/isci/scil/sati.h271
-rw-r--r--sys/dev/isci/scil/sati_abort_task_set.c177
-rw-r--r--sys/dev/isci/scil/sati_abort_task_set.h83
-rw-r--r--sys/dev/isci/scil/sati_atapi.c257
-rw-r--r--sys/dev/isci/scil/sati_atapi.h177
-rw-r--r--sys/dev/isci/scil/sati_callbacks.h481
-rw-r--r--sys/dev/isci/scil/sati_design.h169
-rw-r--r--sys/dev/isci/scil/sati_device.c245
-rw-r--r--sys/dev/isci/scil/sati_device.h203
-rw-r--r--sys/dev/isci/scil/sati_inquiry.c799
-rw-r--r--sys/dev/isci/scil/sati_inquiry.h114
-rw-r--r--sys/dev/isci/scil/sati_log_sense.c807
-rw-r--r--sys/dev/isci/scil/sati_log_sense.h87
-rw-r--r--sys/dev/isci/scil/sati_lun_reset.c122
-rw-r--r--sys/dev/isci/scil/sati_lun_reset.h79
-rw-r--r--sys/dev/isci/scil/sati_mode_pages.c372
-rw-r--r--sys/dev/isci/scil/sati_mode_pages.h144
-rw-r--r--sys/dev/isci/scil/sati_mode_select.c1115
-rw-r--r--sys/dev/isci/scil/sati_mode_select.h84
-rw-r--r--sys/dev/isci/scil/sati_mode_sense.c837
-rw-r--r--sys/dev/isci/scil/sati_mode_sense.h146
-rw-r--r--sys/dev/isci/scil/sati_mode_sense_10.c509
-rw-r--r--sys/dev/isci/scil/sati_mode_sense_10.h114
-rw-r--r--sys/dev/isci/scil/sati_mode_sense_6.c429
-rw-r--r--sys/dev/isci/scil/sati_mode_sense_6.h114
-rw-r--r--sys/dev/isci/scil/sati_move.c616
-rw-r--r--sys/dev/isci/scil/sati_move.h121
-rw-r--r--sys/dev/isci/scil/sati_passthrough.c465
-rw-r--r--sys/dev/isci/scil/sati_passthrough.h88
-rw-r--r--sys/dev/isci/scil/sati_read.c323
-rw-r--r--sys/dev/isci/scil/sati_read.h91
-rw-r--r--sys/dev/isci/scil/sati_read_buffer.c235
-rw-r--r--sys/dev/isci/scil/sati_read_buffer.h82
-rw-r--r--sys/dev/isci/scil/sati_read_capacity.c366
-rw-r--r--sys/dev/isci/scil/sati_read_capacity.h91
-rw-r--r--sys/dev/isci/scil/sati_reassign_blocks.c622
-rw-r--r--sys/dev/isci/scil/sati_reassign_blocks.h80
-rw-r--r--sys/dev/isci/scil/sati_report_luns.c124
-rw-r--r--sys/dev/isci/scil/sati_report_luns.h75
-rw-r--r--sys/dev/isci/scil/sati_request_sense.c353
-rw-r--r--sys/dev/isci/scil/sati_request_sense.h86
-rw-r--r--sys/dev/isci/scil/sati_start_stop_unit.c404
-rw-r--r--sys/dev/isci/scil/sati_start_stop_unit.h102
-rw-r--r--sys/dev/isci/scil/sati_synchronize_cache.c119
-rw-r--r--sys/dev/isci/scil/sati_synchronize_cache.h71
-rw-r--r--sys/dev/isci/scil/sati_test_unit_ready.c186
-rw-r--r--sys/dev/isci/scil/sati_test_unit_ready.h79
-rw-r--r--sys/dev/isci/scil/sati_translator_sequence.h361
-rw-r--r--sys/dev/isci/scil/sati_types.h152
-rw-r--r--sys/dev/isci/scil/sati_unmap.c609
-rw-r--r--sys/dev/isci/scil/sati_unmap.h135
-rw-r--r--sys/dev/isci/scil/sati_util.c2005
-rw-r--r--sys/dev/isci/scil/sati_util.h393
-rw-r--r--sys/dev/isci/scil/sati_verify.c273
-rw-r--r--sys/dev/isci/scil/sati_verify.h83
-rw-r--r--sys/dev/isci/scil/sati_write.c321
-rw-r--r--sys/dev/isci/scil/sati_write.h91
-rw-r--r--sys/dev/isci/scil/sati_write_and_verify.c243
-rw-r--r--sys/dev/isci/scil/sati_write_and_verify.h90
-rw-r--r--sys/dev/isci/scil/sati_write_buffer.c254
-rw-r--r--sys/dev/isci/scil/sati_write_buffer.h78
-rw-r--r--sys/dev/isci/scil/sati_write_long.c259
-rw-r--r--sys/dev/isci/scil/sati_write_long.h83
-rw-r--r--sys/dev/isci/scil/sci_abstract_list.c599
-rw-r--r--sys/dev/isci/scil/sci_abstract_list.h871
-rw-r--r--sys/dev/isci/scil/sci_base_controller.c105
-rw-r--r--sys/dev/isci/scil/sci_base_controller.h347
-rw-r--r--sys/dev/isci/scil/sci_base_domain.c89
-rw-r--r--sys/dev/isci/scil/sci_base_domain.h309
-rw-r--r--sys/dev/isci/scil/sci_base_iterator.c182
-rw-r--r--sys/dev/isci/scil/sci_base_iterator.h134
-rw-r--r--sys/dev/isci/scil/sci_base_library.c103
-rw-r--r--sys/dev/isci/scil/sci_base_library.h197
-rw-r--r--sys/dev/isci/scil/sci_base_logger.c291
-rw-r--r--sys/dev/isci/scil/sci_base_logger.h131
-rw-r--r--sys/dev/isci/scil/sci_base_memory_descriptor_list.c168
-rw-r--r--sys/dev/isci/scil/sci_base_memory_descriptor_list.h168
-rw-r--r--sys/dev/isci/scil/sci_base_memory_descriptor_list_decorator.c149
-rw-r--r--sys/dev/isci/scil/sci_base_object.c118
-rw-r--r--sys/dev/isci/scil/sci_base_object.h142
-rw-r--r--sys/dev/isci/scil/sci_base_observer.c107
-rw-r--r--sys/dev/isci/scil/sci_base_observer.h167
-rw-r--r--sys/dev/isci/scil/sci_base_phy.c89
-rw-r--r--sys/dev/isci/scil/sci_base_phy.h213
-rw-r--r--sys/dev/isci/scil/sci_base_port.c88
-rw-r--r--sys/dev/isci/scil/sci_base_port.h233
-rw-r--r--sys/dev/isci/scil/sci_base_remote_device.c80
-rw-r--r--sys/dev/isci/scil/sci_base_remote_device.h298
-rw-r--r--sys/dev/isci/scil/sci_base_request.c79
-rw-r--r--sys/dev/isci/scil/sci_base_request.h209
-rw-r--r--sys/dev/isci/scil/sci_base_state.h110
-rw-r--r--sys/dev/isci/scil/sci_base_state_machine.c212
-rw-r--r--sys/dev/isci/scil/sci_base_state_machine.h157
-rw-r--r--sys/dev/isci/scil/sci_base_state_machine_logger.c217
-rw-r--r--sys/dev/isci/scil/sci_base_state_machine_logger.h137
-rw-r--r--sys/dev/isci/scil/sci_base_state_machine_observer.c99
-rw-r--r--sys/dev/isci/scil/sci_base_state_machine_observer.h138
-rw-r--r--sys/dev/isci/scil/sci_base_subject.c149
-rw-r--r--sys/dev/isci/scil/sci_base_subject.h157
-rw-r--r--sys/dev/isci/scil/sci_controller.h113
-rw-r--r--sys/dev/isci/scil/sci_controller_constants.h217
-rw-r--r--sys/dev/isci/scil/sci_fast_list.h339
-rw-r--r--sys/dev/isci/scil/sci_iterator.h129
-rw-r--r--sys/dev/isci/scil/sci_library.h111
-rw-r--r--sys/dev/isci/scil/sci_logger.h250
-rw-r--r--sys/dev/isci/scil/sci_memory_descriptor_list.h181
-rw-r--r--sys/dev/isci/scil/sci_memory_descriptor_list_decorator.h129
-rw-r--r--sys/dev/isci/scil/sci_object.h139
-rw-r--r--sys/dev/isci/scil/sci_overview.h251
-rw-r--r--sys/dev/isci/scil/sci_pool.h188
-rw-r--r--sys/dev/isci/scil/sci_simple_list.h350
-rw-r--r--sys/dev/isci/scil/sci_status.h418
-rw-r--r--sys/dev/isci/scil/sci_types.h280
-rw-r--r--sys/dev/isci/scil/sci_util.c72
-rw-r--r--sys/dev/isci/scil/sci_util.h164
-rw-r--r--sys/dev/isci/scil/scic_config_parameters.h346
-rw-r--r--sys/dev/isci/scil/scic_controller.h856
-rw-r--r--sys/dev/isci/scil/scic_io_request.h761
-rw-r--r--sys/dev/isci/scil/scic_library.h275
-rw-r--r--sys/dev/isci/scil/scic_logger.h136
-rw-r--r--sys/dev/isci/scil/scic_overview.h88
-rw-r--r--sys/dev/isci/scil/scic_phy.h462
-rw-r--r--sys/dev/isci/scil/scic_port.h239
-rw-r--r--sys/dev/isci/scil/scic_remote_device.h442
-rw-r--r--sys/dev/isci/scil/scic_sds_controller.c7042
-rw-r--r--sys/dev/isci/scil/scic_sds_controller.h840
-rw-r--r--sys/dev/isci/scil/scic_sds_controller_registers.h598
-rw-r--r--sys/dev/isci/scil/scic_sds_library.c287
-rw-r--r--sys/dev/isci/scil/scic_sds_library.h118
-rw-r--r--sys/dev/isci/scil/scic_sds_logger.h93
-rw-r--r--sys/dev/isci/scil/scic_sds_pci.c247
-rw-r--r--sys/dev/isci/scil/scic_sds_pci.h138
-rw-r--r--sys/dev/isci/scil/scic_sds_phy.c4036
-rw-r--r--sys/dev/isci/scil/scic_sds_phy.h531
-rw-r--r--sys/dev/isci/scil/scic_sds_phy_registers.h270
-rw-r--r--sys/dev/isci/scil/scic_sds_port.c3662
-rw-r--r--sys/dev/isci/scil/scic_sds_port.h595
-rw-r--r--sys/dev/isci/scil/scic_sds_port_configuration_agent.c1133
-rw-r--r--sys/dev/isci/scil/scic_sds_port_configuration_agent.h128
-rw-r--r--sys/dev/isci/scil/scic_sds_port_registers.h139
-rw-r--r--sys/dev/isci/scil/scic_sds_remote_device.c2727
-rw-r--r--sys/dev/isci/scil/scic_sds_remote_device.h646
-rw-r--r--sys/dev/isci/scil/scic_sds_remote_node_context.c1500
-rw-r--r--sys/dev/isci/scil/scic_sds_remote_node_context.h382
-rw-r--r--sys/dev/isci/scil/scic_sds_remote_node_table.c660
-rw-r--r--sys/dev/isci/scil/scic_sds_remote_node_table.h190
-rw-r--r--sys/dev/isci/scil/scic_sds_request.c2890
-rw-r--r--sys/dev/isci/scil/scic_sds_request.h543
-rw-r--r--sys/dev/isci/scil/scic_sds_sgpio.c298
-rw-r--r--sys/dev/isci/scil/scic_sds_smp_remote_device.c371
-rw-r--r--sys/dev/isci/scil/scic_sds_smp_request.c872
-rw-r--r--sys/dev/isci/scil/scic_sds_smp_request.h83
-rw-r--r--sys/dev/isci/scil/scic_sds_ssp_request.c340
-rw-r--r--sys/dev/isci/scil/scic_sds_stp_packet_request.c978
-rw-r--r--sys/dev/isci/scil/scic_sds_stp_packet_request.h171
-rw-r--r--sys/dev/isci/scil/scic_sds_stp_pio_request.h131
-rw-r--r--sys/dev/isci/scil/scic_sds_stp_remote_device.c1098
-rw-r--r--sys/dev/isci/scil/scic_sds_stp_request.c2581
-rw-r--r--sys/dev/isci/scil/scic_sds_stp_request.h280
-rw-r--r--sys/dev/isci/scil/scic_sds_unsolicited_frame_control.c402
-rw-r--r--sys/dev/isci/scil/scic_sds_unsolicited_frame_control.h305
-rw-r--r--sys/dev/isci/scil/scic_sgpio.h299
-rw-r--r--sys/dev/isci/scil/scic_task_request.h181
-rw-r--r--sys/dev/isci/scil/scic_user_callback.h1146
-rw-r--r--sys/dev/isci/scil/scif_config_parameters.h181
-rw-r--r--sys/dev/isci/scil/scif_controller.h454
-rw-r--r--sys/dev/isci/scil/scif_domain.h185
-rw-r--r--sys/dev/isci/scil/scif_io_request.h243
-rw-r--r--sys/dev/isci/scil/scif_library.h196
-rw-r--r--sys/dev/isci/scil/scif_logger.h118
-rw-r--r--sys/dev/isci/scil/scif_overview.h116
-rw-r--r--sys/dev/isci/scil/scif_remote_device.h295
-rw-r--r--sys/dev/isci/scil/scif_sas_constants.h79
-rw-r--r--sys/dev/isci/scil/scif_sas_controller.c1249
-rw-r--r--sys/dev/isci/scil/scif_sas_controller.h308
-rw-r--r--sys/dev/isci/scil/scif_sas_controller_state_handlers.c1845
-rw-r--r--sys/dev/isci/scil/scif_sas_controller_states.c460
-rw-r--r--sys/dev/isci/scil/scif_sas_design.h348
-rw-r--r--sys/dev/isci/scil/scif_sas_domain.c1536
-rw-r--r--sys/dev/isci/scil/scif_sas_domain.h328
-rw-r--r--sys/dev/isci/scil/scif_sas_domain_state_handlers.c1630
-rw-r--r--sys/dev/isci/scil/scif_sas_domain_states.c612
-rw-r--r--sys/dev/isci/scil/scif_sas_high_priority_request_queue.c161
-rw-r--r--sys/dev/isci/scil/scif_sas_high_priority_request_queue.h123
-rw-r--r--sys/dev/isci/scil/scif_sas_internal_io_request.c282
-rw-r--r--sys/dev/isci/scil/scif_sas_internal_io_request.h157
-rw-r--r--sys/dev/isci/scil/scif_sas_io_request.c820
-rw-r--r--sys/dev/isci/scil/scif_sas_io_request.h152
-rw-r--r--sys/dev/isci/scil/scif_sas_io_request_state_handlers.c417
-rw-r--r--sys/dev/isci/scil/scif_sas_io_request_states.c286
-rw-r--r--sys/dev/isci/scil/scif_sas_library.c270
-rw-r--r--sys/dev/isci/scil/scif_sas_library.h105
-rw-r--r--sys/dev/isci/scil/scif_sas_logger.h94
-rw-r--r--sys/dev/isci/scil/scif_sas_remote_device.c794
-rw-r--r--sys/dev/isci/scil/scif_sas_remote_device.h502
-rw-r--r--sys/dev/isci/scil/scif_sas_remote_device_ready_substate_handlers.c779
-rw-r--r--sys/dev/isci/scil/scif_sas_remote_device_ready_substates.c290
-rw-r--r--sys/dev/isci/scil/scif_sas_remote_device_starting_substate_handlers.c317
-rw-r--r--sys/dev/isci/scil/scif_sas_remote_device_starting_substates.c143
-rw-r--r--sys/dev/isci/scil/scif_sas_remote_device_state_handlers.c1161
-rw-r--r--sys/dev/isci/scil/scif_sas_remote_device_states.c549
-rw-r--r--sys/dev/isci/scil/scif_sas_request.c183
-rw-r--r--sys/dev/isci/scil/scif_sas_request.h221
-rw-r--r--sys/dev/isci/scil/scif_sas_sati_binding.h253
-rw-r--r--sys/dev/isci/scil/scif_sas_smp_activity_clear_affiliation.c252
-rw-r--r--sys/dev/isci/scil/scif_sas_smp_io_request.c600
-rw-r--r--sys/dev/isci/scil/scif_sas_smp_io_request.h138
-rw-r--r--sys/dev/isci/scil/scif_sas_smp_phy.c335
-rw-r--r--sys/dev/isci/scil/scif_sas_smp_phy.h186
-rw-r--r--sys/dev/isci/scil/scif_sas_smp_remote_device.c2632
-rw-r--r--sys/dev/isci/scil/scif_sas_smp_remote_device.h431
-rw-r--r--sys/dev/isci/scil/scif_sas_stp_io_request.c623
-rw-r--r--sys/dev/isci/scil/scif_sas_stp_io_request.h101
-rw-r--r--sys/dev/isci/scil/scif_sas_stp_remote_device.c215
-rw-r--r--sys/dev/isci/scil/scif_sas_stp_remote_device.h119
-rw-r--r--sys/dev/isci/scil/scif_sas_stp_task_request.c265
-rw-r--r--sys/dev/isci/scil/scif_sas_stp_task_request.h106
-rw-r--r--sys/dev/isci/scil/scif_sas_task_request.c481
-rw-r--r--sys/dev/isci/scil/scif_sas_task_request.h143
-rw-r--r--sys/dev/isci/scil/scif_sas_task_request_state_handlers.c404
-rw-r--r--sys/dev/isci/scil/scif_sas_task_request_states.c287
-rw-r--r--sys/dev/isci/scil/scif_sas_timer.c123
-rw-r--r--sys/dev/isci/scil/scif_task_request.h129
-rw-r--r--sys/dev/isci/scil/scif_user_callback.h1049
-rw-r--r--sys/dev/isci/scil/scu_bios_definitions.h1002
-rw-r--r--sys/dev/isci/scil/scu_completion_codes.h263
-rw-r--r--sys/dev/isci/scil/scu_constants.h154
-rw-r--r--sys/dev/isci/scil/scu_event_codes.h343
-rw-r--r--sys/dev/isci/scil/scu_registers.h2121
-rw-r--r--sys/dev/isci/scil/scu_remote_node_context.h242
-rw-r--r--sys/dev/isci/scil/scu_task_context.h965
-rw-r--r--sys/dev/isci/scil/scu_unsolicited_frame.h122
-rw-r--r--sys/dev/isci/scil/scu_viit_data.h186
-rw-r--r--sys/dev/isci/types.h53
255 files changed, 111908 insertions, 0 deletions
diff --git a/sys/dev/isci/environment.h b/sys/dev/isci/environment.h
new file mode 100644
index 0000000..5c9374c
--- /dev/null
+++ b/sys/dev/isci/environment.h
@@ -0,0 +1,100 @@
+/*-
+ * 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.
+ *
+ * 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.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef ENVIRONMENT_H_
+#define ENVIRONMENT_H_
+
+/**
+ * @file
+ *
+ * @brief Types and macros specific to the FreeBSD environment.
+ */
+#include <sys/cdefs.h>
+#include <sys/types.h>
+#include <sys/libkern.h>
+#include <machine/bus.h>
+#include <opt_isci.h>
+
+typedef int8_t S8;
+typedef uint8_t U8;
+
+typedef int16_t S16;
+typedef uint16_t U16;
+
+typedef int32_t S32;
+typedef uint32_t U32;
+
+typedef int64_t S64;
+typedef uint64_t U64;
+
+/* Technically, this should be defined as bus_addr_t, but SCIL makes some
+ * incorrect assumptions in some of its physical address calculations which
+ * necessitate using uint64_t here to avoid compiler warnings. This is
+ * easier for now than modifying SCIL, and works just as well.
+ */
+typedef uint64_t SCI_PHYSICAL_ADDRESS;
+
+typedef U64 SATI_LBA;
+typedef void * FUNCPTR;
+
+#define sci_cb_physical_address_upper(address) ((uint32_t)((address)>>32))
+#define sci_cb_physical_address_lower(address) ((uint32_t)((address)&0xFFFFFFFF))
+#define sci_cb_make_physical_address(physical_address, address_upper, address_lower) \
+ ((physical_address) = ((U64)(address_upper))<<32 | (address_lower))
+
+#define INLINE __inline
+
+#define PLACEMENT_HINTS(...)
+
+#define SCIC_SDS_4_ENABLED 1
+#define PBG_BUILD 1
+#define PHY_MAX_LINK_SPEED_GENERATION 3
+
+/* SCIL defines logging as SCI_LOGGING, but the FreeBSD driver name is ISCI.
+ So we define ISCI_LOGGING as the option exported to the kernel, and
+ translate it here. */
+#ifdef ISCI_LOGGING
+#define SCI_LOGGING
+#endif
+
+#define __SCI_LIBRARY_MAJOR_VERSION__ 3
+#define __SCI_LIBRARY_MINOR_VERSION__ 1
+#define __SCI_LIBRARY_BUILD_VERSION__ 7142
+
+#define SATI_TRANSPORT_SUPPORTS_SATA
+#define SATI_TRANSPORT_SUPPORTS_SAS
+#define USE_ABSTRACT_LIST_FUNCTIONS
+
+#define ASSERT(cond)
+#define assert(cond)
+
+#endif /* ENVIRONMENT_H_ */
diff --git a/sys/dev/isci/isci.c b/sys/dev/isci/isci.c
new file mode 100644
index 0000000..a62f706
--- /dev/null
+++ b/sys/dev/isci/isci.c
@@ -0,0 +1,650 @@
+/*-
+ * 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.
+ *
+ * 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 <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <dev/isci/isci.h>
+
+#include <sys/sysctl.h>
+#include <sys/malloc.h>
+
+#include <cam/cam_periph.h>
+
+#include <dev/pci/pcireg.h>
+#include <dev/pci/pcivar.h>
+
+#include <dev/isci/scil/scic_logger.h>
+#include <dev/isci/scil/scic_library.h>
+#include <dev/isci/scil/scic_user_callback.h>
+
+#include <dev/isci/scil/scif_controller.h>
+#include <dev/isci/scil/scif_library.h>
+#include <dev/isci/scil/scif_logger.h>
+#include <dev/isci/scil/scif_user_callback.h>
+
+MALLOC_DEFINE(M_ISCI, "isci", "isci driver memory allocations");
+
+struct isci_softc *g_isci;
+uint32_t g_isci_debug_level = 0;
+
+static int isci_probe(device_t);
+static int isci_attach(device_t);
+static int isci_detach(device_t);
+
+int isci_initialize(struct isci_softc *isci);
+
+void isci_allocate_dma_buffer_callback(void *arg, bus_dma_segment_t *seg,
+ int nseg, int error);
+
+static devclass_t isci_devclass;
+
+static device_method_t isci_pci_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, isci_probe),
+ DEVMETHOD(device_attach, isci_attach),
+ DEVMETHOD(device_detach, isci_detach),
+ { 0, 0 }
+};
+
+static driver_t isci_pci_driver = {
+ "isci",
+ isci_pci_methods,
+ sizeof(struct isci_softc),
+};
+
+DRIVER_MODULE(isci, pci, isci_pci_driver, isci_devclass, 0, 0);
+
+static struct _pcsid
+{
+ u_int32_t type;
+ const char *desc;
+} pci_ids[] = {
+ { 0x1d608086, "Intel(R) C600 Series Chipset SAS Controller" },
+ { 0x1d618086, "Intel(R) C600 Series Chipset SAS Controller (SATA mode)" },
+ { 0x1d628086, "Intel(R) C600 Series Chipset SAS Controller" },
+ { 0x1d638086, "Intel(R) C600 Series Chipset SAS Controller" },
+ { 0x1d648086, "Intel(R) C600 Series Chipset SAS Controller" },
+ { 0x1d658086, "Intel(R) C600 Series Chipset SAS Controller" },
+ { 0x1d668086, "Intel(R) C600 Series Chipset SAS Controller" },
+ { 0x1d678086, "Intel(R) C600 Series Chipset SAS Controller" },
+ { 0x1d688086, "Intel(R) C600 Series Chipset SAS Controller" },
+ { 0x1d698086, "Intel(R) C600 Series Chipset SAS Controller" },
+ { 0x1d6a8086, "Intel(R) C600 Series Chipset SAS Controller (SATA mode)" },
+ { 0x1d6b8086, "Intel(R) C600 Series Chipset SAS Controller (SATA mode)" },
+ { 0x00000000, NULL }
+};
+
+static int
+isci_probe (device_t device)
+{
+ u_int32_t type = pci_get_devid(device);
+ struct _pcsid *ep = pci_ids;
+
+ while (ep->type && ep->type != type)
+ ++ep;
+
+ if (ep->desc)
+ {
+ device_set_desc(device, ep->desc);
+ return (0);
+ }
+ else
+ return (ENXIO);
+}
+
+static int
+isci_allocate_pci_memory(struct isci_softc *isci)
+{
+ int i;
+
+ for (i = 0; i < ISCI_NUM_PCI_BARS; i++)
+ {
+ struct ISCI_PCI_BAR *pci_bar = &isci->pci_bar[i];
+
+ pci_bar->resource_id = PCIR_BAR(i*2);
+ pci_bar->resource = bus_alloc_resource(isci->device,
+ SYS_RES_MEMORY, &pci_bar->resource_id, 0, ~0, 1,
+ RF_ACTIVE);
+
+ if(pci_bar->resource == NULL)
+ isci_log_message(0, "ISCI",
+ "unable to allocate pci resource\n");
+ else {
+ pci_bar->bus_tag = rman_get_bustag(pci_bar->resource);
+ pci_bar->bus_handle =
+ rman_get_bushandle(pci_bar->resource);
+ }
+ }
+
+ return (0);
+}
+
+static int
+isci_attach(device_t device)
+{
+ int error;
+ struct isci_softc *isci = DEVICE2SOFTC(device);
+
+ g_isci = isci;
+ isci->device = device;
+
+ isci_allocate_pci_memory(isci);
+
+ error = isci_initialize(isci);
+
+ if (error)
+ {
+ isci_detach(device);
+ return (error);
+ }
+
+ isci_interrupt_setup(isci);
+ isci_sysctl_initialize(isci);
+
+ return (0);
+}
+
+static int
+isci_detach(device_t device)
+{
+ struct isci_softc *isci = DEVICE2SOFTC(device);
+ int i;
+
+ for (i = 0; i < isci->controller_count; i++) {
+ struct ISCI_CONTROLLER *controller = &isci->controllers[i];
+ SCI_STATUS status;
+
+ if (controller->scif_controller_handle != NULL) {
+ scic_controller_disable_interrupts(
+ scif_controller_get_scic_handle(controller->scif_controller_handle));
+
+ mtx_lock(&controller->lock);
+ status = scif_controller_stop(controller->scif_controller_handle, 0);
+ mtx_unlock(&controller->lock);
+
+ while (controller->is_started == TRUE) {
+ /* Now poll for interrupts until the controller stop complete
+ * callback is received.
+ */
+ mtx_lock(&controller->lock);
+ isci_interrupt_poll_handler(controller);
+ mtx_unlock(&controller->lock);
+ pause("isci", 1);
+ }
+
+ if(controller->sim != NULL) {
+ mtx_lock(&controller->lock);
+ xpt_free_path(controller->path);
+ xpt_bus_deregister(cam_sim_path(controller->sim));
+ cam_sim_free(controller->sim, TRUE);
+ mtx_unlock(&controller->lock);
+ }
+ }
+
+ if (controller->timer_memory != NULL)
+ free(controller->timer_memory, M_ISCI);
+
+ if (controller->remote_device_memory != NULL)
+ free(controller->remote_device_memory, M_ISCI);
+ }
+
+ /* The SCIF controllers have been stopped, so we can now
+ * free the SCI library memory.
+ */
+ if (isci->sci_library_memory != NULL)
+ free(isci->sci_library_memory, M_ISCI);
+
+ for (i = 0; i < ISCI_NUM_PCI_BARS; i++)
+ {
+ struct ISCI_PCI_BAR *pci_bar = &isci->pci_bar[i];
+
+ if (pci_bar->resource != NULL)
+ bus_release_resource(device, SYS_RES_MEMORY,
+ pci_bar->resource_id, pci_bar->resource);
+ }
+
+ for (i = 0; i < isci->num_interrupts; i++)
+ {
+ struct ISCI_INTERRUPT_INFO *interrupt_info;
+
+ interrupt_info = &isci->interrupt_info[i];
+
+ if(interrupt_info->tag != NULL)
+ bus_teardown_intr(device, interrupt_info->res,
+ interrupt_info->tag);
+
+ if(interrupt_info->res != NULL)
+ bus_release_resource(device, SYS_RES_IRQ,
+ rman_get_rid(interrupt_info->res),
+ interrupt_info->res);
+
+ pci_release_msi(device);
+ }
+
+ return (0);
+}
+
+int
+isci_initialize(struct isci_softc *isci)
+{
+ int error;
+ uint32_t status = 0;
+ uint32_t library_object_size;
+ uint32_t verbosity_mask;
+ uint32_t scic_log_object_mask;
+ uint32_t scif_log_object_mask;
+ uint8_t *header_buffer;
+
+ library_object_size = scif_library_get_object_size(SCI_MAX_CONTROLLERS);
+
+ isci->sci_library_memory =
+ malloc(library_object_size, M_ISCI, M_NOWAIT | M_ZERO );
+
+ isci->sci_library_handle = scif_library_construct(
+ isci->sci_library_memory, SCI_MAX_CONTROLLERS);
+
+ sci_object_set_association( isci->sci_library_handle, (void *)isci);
+
+ verbosity_mask = (1<<SCI_LOG_VERBOSITY_ERROR) |
+ (1<<SCI_LOG_VERBOSITY_WARNING) | (1<<SCI_LOG_VERBOSITY_INFO) |
+ (1<<SCI_LOG_VERBOSITY_TRACE);
+
+ scic_log_object_mask = 0xFFFFFFFF;
+ scic_log_object_mask &= ~SCIC_LOG_OBJECT_COMPLETION_QUEUE;
+ scic_log_object_mask &= ~SCIC_LOG_OBJECT_SSP_IO_REQUEST;
+ scic_log_object_mask &= ~SCIC_LOG_OBJECT_STP_IO_REQUEST;
+ scic_log_object_mask &= ~SCIC_LOG_OBJECT_SMP_IO_REQUEST;
+ scic_log_object_mask &= ~SCIC_LOG_OBJECT_CONTROLLER;
+
+ scif_log_object_mask = 0xFFFFFFFF;
+ scif_log_object_mask &= ~SCIF_LOG_OBJECT_CONTROLLER;
+ scif_log_object_mask &= ~SCIF_LOG_OBJECT_IO_REQUEST;
+
+ TUNABLE_INT_FETCH("hw.isci.debug_level", &g_isci_debug_level);
+
+ sci_logger_enable(sci_object_get_logger(isci->sci_library_handle),
+ scif_log_object_mask, verbosity_mask);
+
+ sci_logger_enable(sci_object_get_logger(
+ scif_library_get_scic_handle(isci->sci_library_handle)),
+ scic_log_object_mask, verbosity_mask);
+
+ header_buffer = (uint8_t *)&isci->pci_common_header;
+ for (uint8_t i = 0; i < sizeof(isci->pci_common_header); i++)
+ header_buffer[i] = pci_read_config(isci->device, i, 1);
+
+ scic_library_set_pci_info(
+ scif_library_get_scic_handle(isci->sci_library_handle),
+ &isci->pci_common_header);
+
+ isci->oem_parameters_found = FALSE;
+
+ isci_get_oem_parameters(isci);
+
+ /* trigger interrupt if 32 completions occur before timeout expires */
+ isci->coalesce_number = 32;
+
+ /* trigger interrupt if 2 microseconds elapse after a completion occurs,
+ * regardless if "coalesce_number" completions have occurred
+ */
+ isci->coalesce_timeout = 2;
+
+ isci->controller_count = scic_library_get_pci_device_controller_count(
+ scif_library_get_scic_handle(isci->sci_library_handle));
+
+ for (int index = 0; index < isci->controller_count; index++) {
+ struct ISCI_CONTROLLER *controller = &isci->controllers[index];
+ SCI_CONTROLLER_HANDLE_T scif_controller_handle;
+
+ controller->index = index;
+ isci_controller_construct(controller, isci);
+
+ scif_controller_handle = controller->scif_controller_handle;
+
+ status = isci_controller_initialize(controller);
+
+ if(status != SCI_SUCCESS) {
+ isci_log_message(0, "ISCI",
+ "isci_controller_initialize FAILED: %x\n",
+ status);
+ return (status);
+ }
+
+ error = isci_controller_allocate_memory(controller);
+
+ if (error != 0)
+ return (error);
+
+ scif_controller_set_interrupt_coalescence(
+ scif_controller_handle, isci->coalesce_number,
+ isci->coalesce_timeout);
+ }
+
+ /* FreeBSD provides us a hook to ensure we get a chance to start
+ * our controllers and complete initial domain discovery before
+ * it searches for the boot device. Once we're done, we'll
+ * disestablish the hook, signaling the kernel that is can proceed
+ * with the boot process.
+ */
+ isci->config_hook.ich_func = &isci_controller_start;
+ isci->config_hook.ich_arg = &isci->controllers[0];
+
+ if (config_intrhook_establish(&isci->config_hook) != 0)
+ isci_log_message(0, "ISCI",
+ "config_intrhook_establish failed!\n");
+
+ return (status);
+}
+
+void
+isci_allocate_dma_buffer_callback(void *arg, bus_dma_segment_t *seg,
+ int nseg, int error)
+{
+ struct ISCI_MEMORY *memory = (struct ISCI_MEMORY *)arg;
+
+ memory->error = error;
+
+ if (nseg != 1 || error != 0)
+ isci_log_message(0, "ISCI",
+ "Failed to allocate physically contiguous memory!\n");
+ else
+ memory->physical_address = seg->ds_addr;
+}
+
+int
+isci_allocate_dma_buffer(device_t device, struct ISCI_MEMORY *memory)
+{
+ uint32_t status;
+
+ status = bus_dma_tag_create(bus_get_dma_tag(device),
+ 0x40 /* cacheline alignment */, 0x0, BUS_SPACE_MAXADDR,
+ BUS_SPACE_MAXADDR, NULL, NULL, memory->size,
+ 0x1 /* we want physically contiguous */,
+ memory->size, 0, NULL, NULL, &memory->dma_tag);
+
+ if(status == ENOMEM) {
+ isci_log_message(0, "ISCI", "bus_dma_tag_create failed\n");
+ return (status);
+ }
+
+ status = bus_dmamem_alloc(memory->dma_tag,
+ (void **)&memory->virtual_address, BUS_DMA_ZERO, &memory->dma_map);
+
+ if(status == ENOMEM)
+ {
+ isci_log_message(0, "ISCI", "bus_dmamem_alloc failed\n");
+ return (status);
+ }
+
+ status = bus_dmamap_load(memory->dma_tag, memory->dma_map,
+ (void *)memory->virtual_address, memory->size,
+ isci_allocate_dma_buffer_callback, memory, 0);
+
+ if(status == EINVAL)
+ {
+ isci_log_message(0, "ISCI", "bus_dmamap_load failed\n");
+ return (status);
+ }
+
+ return (0);
+}
+
+/**
+ * @brief This callback method asks the user to associate the supplied
+ * lock with an operating environment specific locking construct.
+ *
+ * @param[in] controller This parameter specifies the controller with
+ * which this lock is to be associated.
+ * @param[in] lock This parameter specifies the lock for which the
+ * user should associate an operating environment specific
+ * locking object.
+ *
+ * @see The SCI_LOCK_LEVEL enumeration for more information.
+ *
+ * @return none.
+ */
+void
+scif_cb_lock_associate(SCI_CONTROLLER_HANDLE_T controller,
+ SCI_LOCK_HANDLE_T lock)
+{
+
+}
+
+/**
+ * @brief This callback method asks the user to de-associate the supplied
+ * lock with an operating environment specific locking construct.
+ *
+ * @param[in] controller This parameter specifies the controller with
+ * which this lock is to be de-associated.
+ * @param[in] lock This parameter specifies the lock for which the
+ * user should de-associate an operating environment specific
+ * locking object.
+ *
+ * @see The SCI_LOCK_LEVEL enumeration for more information.
+ *
+ * @return none.
+ */
+void
+scif_cb_lock_disassociate(SCI_CONTROLLER_HANDLE_T controller,
+ SCI_LOCK_HANDLE_T lock)
+{
+
+}
+
+
+/**
+ * @brief This callback method asks the user to acquire/get the lock.
+ * This method should pend until the lock has been acquired.
+ *
+ * @param[in] controller This parameter specifies the controller with
+ * which this lock is associated.
+ * @param[in] lock This parameter specifies the lock to be acquired.
+ *
+ * @return none
+ */
+void
+scif_cb_lock_acquire(SCI_CONTROLLER_HANDLE_T controller,
+ SCI_LOCK_HANDLE_T lock)
+{
+
+}
+
+/**
+ * @brief This callback method asks the user to release a lock.
+ *
+ * @param[in] controller This parameter specifies the controller with
+ * which this lock is associated.
+ * @param[in] lock This parameter specifies the lock to be released.
+ *
+ * @return none
+ */
+void
+scif_cb_lock_release(SCI_CONTROLLER_HANDLE_T controller,
+ SCI_LOCK_HANDLE_T lock)
+{
+}
+
+/**
+ * @brief This callback method creates an OS specific deferred task
+ * for internal usage. The handler to deferred task is stored by OS
+ * driver.
+ *
+ * @param[in] controller This parameter specifies the controller object
+ * with which this callback is associated.
+ *
+ * @return none
+ */
+void
+scif_cb_start_internal_io_task_create(SCI_CONTROLLER_HANDLE_T controller)
+{
+
+}
+
+/**
+ * @brief This callback method schedules a OS specific deferred task.
+ *
+ * @param[in] controller This parameter specifies the controller
+ * object with which this callback is associated.
+ * @param[in] start_internal_io_task_routine This parameter specifies the
+ * sci start_internal_io routine.
+ * @param[in] context This parameter specifies a handle to a parameter
+ * that will be passed into the "start_internal_io_task_routine"
+ * when it is invoked.
+ *
+ * @return none
+ */
+void
+scif_cb_start_internal_io_task_schedule(SCI_CONTROLLER_HANDLE_T scif_controller,
+ FUNCPTR start_internal_io_task_routine, void *context)
+{
+ /** @todo Use FreeBSD tasklet to defer this routine to a later time,
+ * rather than calling the routine inline.
+ */
+ SCI_START_INTERNAL_IO_ROUTINE sci_start_internal_io_routine =
+ (SCI_START_INTERNAL_IO_ROUTINE)start_internal_io_task_routine;
+
+ sci_start_internal_io_routine(context);
+}
+
+/**
+ * @brief In this method the user must write to PCI memory via access.
+ * This method is used for access to memory space and IO space.
+ *
+ * @param[in] controller The controller for which to read a DWORD.
+ * @param[in] address This parameter depicts the address into
+ * which to write.
+ * @param[out] write_value This parameter depicts the value being written
+ * into the PCI memory location.
+ *
+ * @todo These PCI memory access calls likely needs to be optimized into macros?
+ */
+void
+scic_cb_pci_write_dword(SCI_CONTROLLER_HANDLE_T scic_controller,
+ void *address, uint32_t write_value)
+{
+ SCI_CONTROLLER_HANDLE_T scif_controller =
+ (SCI_CONTROLLER_HANDLE_T) sci_object_get_association(scic_controller);
+ struct ISCI_CONTROLLER *isci_controller =
+ (struct ISCI_CONTROLLER *) sci_object_get_association(scif_controller);
+ struct isci_softc *isci = isci_controller->isci;
+ uint32_t bar = (uint32_t)(((POINTER_UINT)address & 0xF0000000) >> 28);
+ bus_size_t offset = (bus_size_t)((POINTER_UINT)address & 0x0FFFFFFF);
+
+ bus_space_write_4(isci->pci_bar[bar].bus_tag,
+ isci->pci_bar[bar].bus_handle, offset, write_value);
+}
+
+/**
+ * @brief In this method the user must read from PCI memory via access.
+ * This method is used for access to memory space and IO space.
+ *
+ * @param[in] controller The controller for which to read a DWORD.
+ * @param[in] address This parameter depicts the address from
+ * which to read.
+ *
+ * @return The value being returned from the PCI memory location.
+ *
+ * @todo This PCI memory access calls likely need to be optimized into macro?
+ */
+uint32_t
+scic_cb_pci_read_dword(SCI_CONTROLLER_HANDLE_T scic_controller, void *address)
+{
+ SCI_CONTROLLER_HANDLE_T scif_controller =
+ (SCI_CONTROLLER_HANDLE_T)sci_object_get_association(scic_controller);
+ struct ISCI_CONTROLLER *isci_controller =
+ (struct ISCI_CONTROLLER *)sci_object_get_association(scif_controller);
+ struct isci_softc *isci = isci_controller->isci;
+ uint32_t bar = (uint32_t)(((POINTER_UINT)address & 0xF0000000) >> 28);
+ bus_size_t offset = (bus_size_t)((POINTER_UINT)address & 0x0FFFFFFF);
+
+ return (bus_space_read_4(isci->pci_bar[bar].bus_tag,
+ isci->pci_bar[bar].bus_handle, offset));
+}
+
+/**
+ * @brief 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.
+ *
+ * @param[in] 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.
+ *
+ * @return none.
+ */
+void
+scic_cb_stall_execution(uint32_t microseconds)
+{
+
+ DELAY(microseconds);
+}
+
+/**
+ * @brief In this method the user must return the base address register (BAR)
+ * value for the supplied base address register number.
+ *
+ * @param[in] controller The controller for which to retrieve the bar number.
+ * @param[in] bar_number This parameter depicts the BAR index/number to be read.
+ *
+ * @return Return a pointer value indicating the contents of the BAR.
+ * @retval NULL indicates an invalid BAR index/number was specified.
+ * @retval All other values indicate a valid VIRTUAL address from the BAR.
+ */
+void *
+scic_cb_pci_get_bar(SCI_CONTROLLER_HANDLE_T controller,
+ uint16_t bar_number)
+{
+
+ return ((void *)(POINTER_UINT)((uint32_t)bar_number << 28));
+}
+
+/**
+ * @brief 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.
+ *
+ * @param[in] controller This parameter represents the controller which
+ * contains the port.
+ * @param[in] port This parameter specifies the SCI port object for which
+ * the callback is being invoked.
+ * @param[in] phy This parameter specifies the phy that came ready, but the
+ * phy can't be a valid member of the port.
+ *
+ * @return none
+ */
+void
+scic_cb_port_invalid_link_up(SCI_CONTROLLER_HANDLE_T controller,
+ SCI_PORT_HANDLE_T port, SCI_PHY_HANDLE_T phy)
+{
+
+}
diff --git a/sys/dev/isci/isci.h b/sys/dev/isci/isci.h
new file mode 100644
index 0000000..fce5b72
--- /dev/null
+++ b/sys/dev/isci/isci.h
@@ -0,0 +1,302 @@
+/*-
+ * 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.
+ *
+ * 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.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/bus.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/types.h>
+#include <sys/malloc.h>
+#include <sys/rman.h>
+
+#include <machine/bus.h>
+#include <machine/resource.h>
+
+#include <cam/cam.h>
+#include <cam/cam_ccb.h>
+#include <cam/cam_sim.h>
+#include <cam/cam_xpt_sim.h>
+
+#include <dev/isci/environment.h>
+#include <dev/isci/scil/intel_pci.h>
+
+#include <dev/isci/scil/sci_types.h>
+#include <dev/isci/scil/sci_object.h>
+#include <dev/isci/scil/sci_status.h>
+#include <dev/isci/scil/sci_pool.h>
+#include <dev/isci/scil/sci_fast_list.h>
+
+#include <dev/isci/scil/sci_controller_constants.h>
+
+#include <dev/isci/scil/scic_controller.h>
+#include <dev/isci/scil/scic_config_parameters.h>
+
+#define DEVICE2SOFTC(dev) ((struct isci_softc *) device_get_softc(dev))
+
+#define DEVICE_TIMEOUT 1000
+#define SCI_MAX_TIMERS 32
+
+#define ISCI_NUM_PCI_BARS 2
+#define ISCI_MAX_LUN 8
+
+MALLOC_DECLARE(M_ISCI);
+
+struct ISCI_TIMER {
+ struct callout callout;
+ SCI_TIMER_CALLBACK_T callback;
+ void *cookie;
+ BOOL is_started;
+};
+
+struct ISCI_REMOTE_DEVICE {
+ uint32_t index;
+ struct ISCI_DOMAIN *domain;
+ SCI_REMOTE_DEVICE_HANDLE_T sci_object;
+ BOOL is_resetting;
+ uint32_t frozen_lun_mask;
+ SCI_FAST_LIST_ELEMENT_T pending_device_reset_element;
+};
+
+struct ISCI_DOMAIN {
+ struct ISCI_CONTROLLER *controller;
+ SCI_DOMAIN_HANDLE_T sci_object;
+ uint8_t index;
+
+};
+
+struct ISCI_MEMORY
+{
+ bus_addr_t physical_address;
+ bus_dma_tag_t dma_tag;
+ bus_dmamap_t dma_map;
+ POINTER_UINT virtual_address;
+ uint32_t size;
+ int error;
+};
+
+struct ISCI_INTERRUPT_INFO
+{
+ SCIC_CONTROLLER_HANDLER_METHODS_T *handlers;
+ void *interrupt_target_handle;
+ struct resource *res;
+ int rid;
+ void *tag;
+
+};
+
+struct ISCI_CONTROLLER
+{
+ struct isci_softc *isci;
+ uint8_t index;
+ SCI_CONTROLLER_HANDLE_T scif_controller_handle;
+ struct ISCI_DOMAIN domain[SCI_MAX_DOMAINS];
+ BOOL is_started;
+ uint32_t initial_discovery_mask;
+ BOOL is_frozen;
+ uint8_t *remote_device_memory;
+ struct ISCI_MEMORY cached_controller_memory;
+ struct ISCI_MEMORY uncached_controller_memory;
+ struct ISCI_MEMORY request_memory;
+ bus_dma_tag_t buffer_dma_tag;
+ struct mtx lock;
+ struct cam_sim *sim;
+ struct cam_path *path;
+ struct ISCI_REMOTE_DEVICE *remote_device[SCI_MAX_REMOTE_DEVICES];
+ void *timer_memory;
+ SCIC_OEM_PARAMETERS_T oem_parameters;
+ uint32_t oem_parameters_version;
+ uint32_t queue_depth;
+ uint32_t sim_queue_depth;
+ SCI_FAST_LIST_T pending_device_reset_list;
+
+ SCI_MEMORY_DESCRIPTOR_LIST_HANDLE_T mdl;
+
+ SCI_POOL_CREATE(remote_device_pool, struct ISCI_REMOTE_DEVICE *, SCI_MAX_REMOTE_DEVICES);
+ SCI_POOL_CREATE(request_pool, struct ISCI_REQUEST *, SCI_MAX_IO_REQUESTS);
+ SCI_POOL_CREATE(timer_pool, struct ISCI_TIMER *, SCI_MAX_TIMERS);
+};
+
+struct ISCI_REQUEST
+{
+ SCI_CONTROLLER_HANDLE_T controller_handle;
+ SCI_REMOTE_DEVICE_HANDLE_T remote_device_handle;
+ bus_dma_tag_t dma_tag;
+ bus_dmamap_t dma_map;
+ SCI_PHYSICAL_ADDRESS physical_address;
+ struct callout timer;
+};
+
+struct ISCI_IO_REQUEST
+{
+ struct ISCI_REQUEST parent;
+ SCI_STATUS status;
+ SCI_IO_REQUEST_HANDLE_T sci_object;
+ union ccb *ccb;
+ uint32_t num_segments;
+ uint32_t current_sge_index;
+ bus_dma_segment_t *sge;
+};
+
+struct ISCI_TASK_REQUEST
+{
+ struct ISCI_REQUEST parent;
+ struct scsi_sense_data sense_data;
+ SCI_TASK_REQUEST_HANDLE_T sci_object;
+ union ccb *ccb;
+
+};
+
+struct ISCI_PCI_BAR {
+
+ bus_space_tag_t bus_tag;
+ bus_space_handle_t bus_handle;
+ int resource_id;
+ struct resource *resource;
+
+};
+
+/*
+ * One of these per allocated PCI device.
+ */
+struct isci_softc {
+
+ struct ISCI_PCI_BAR pci_bar[ISCI_NUM_PCI_BARS];
+ struct ISCI_CONTROLLER controllers[SCI_MAX_CONTROLLERS];
+ SCI_LIBRARY_HANDLE_T sci_library_handle;
+ void * sci_library_memory;
+ SCIC_CONTROLLER_HANDLER_METHODS_T handlers[4];
+ struct ISCI_INTERRUPT_INFO interrupt_info[4];
+ uint32_t controller_count;
+ uint32_t num_interrupts;
+ uint32_t coalesce_number;
+ uint32_t coalesce_timeout;
+ device_t device;
+ SCI_PCI_COMMON_HEADER_T pci_common_header;
+ BOOL oem_parameters_found;
+ struct intr_config_hook config_hook;
+};
+
+int isci_allocate_resources(device_t device);
+
+int isci_allocate_dma_buffer(device_t device, struct ISCI_MEMORY *memory);
+
+void isci_remote_device_reset(struct ISCI_REMOTE_DEVICE *remote_device,
+ union ccb *ccb);
+
+/**
+ * Returns the negotiated link rate (in KB/s) for the associated
+ * remote device. Used to fill out bitrate field for GET_TRANS_SETTINGS.
+ * Will match the negotiated link rate for the lowest numbered local phy
+ * in the port/domain containing this remote device.
+ */
+uint32_t isci_remote_device_get_bitrate(
+ struct ISCI_REMOTE_DEVICE *remote_device);
+
+void isci_remote_device_freeze_lun_queue(
+ struct ISCI_REMOTE_DEVICE *remote_device, lun_id_t lun);
+
+void isci_remote_device_release_lun_queue(
+ struct ISCI_REMOTE_DEVICE *remote_device, lun_id_t lun);
+
+void isci_remote_device_release_device_queue(
+ struct ISCI_REMOTE_DEVICE * remote_device);
+
+void isci_request_construct(struct ISCI_REQUEST *request,
+ SCI_CONTROLLER_HANDLE_T scif_controller_handle,
+ bus_dma_tag_t io_buffer_dma_tag, bus_addr_t physical_address);
+
+#define isci_io_request_get_max_io_size() \
+ ((SCI_MAX_SCATTER_GATHER_ELEMENTS - 1) * PAGE_SIZE)
+
+#define isci_task_request_get_object_size() \
+ (sizeof(struct ISCI_TASK_REQUEST) + scif_task_request_get_object_size())
+
+#define isci_io_request_get_object_size() \
+ (sizeof(struct ISCI_IO_REQUEST) + scif_io_request_get_object_size())
+
+#define isci_request_get_object_size() \
+ max( \
+ isci_task_request_get_object_size(), \
+ isci_io_request_get_object_size() \
+ )
+
+
+void isci_io_request_execute_scsi_io(union ccb *ccb,
+ struct ISCI_CONTROLLER *controller);
+
+#if __FreeBSD_version >= 900026
+void isci_io_request_execute_smp_io(
+ union ccb *ccb, struct ISCI_CONTROLLER *controller);
+#endif
+
+void isci_io_request_timeout(void *);
+
+void isci_get_oem_parameters(struct isci_softc *isci);
+
+void isci_io_request_complete(
+ SCI_CONTROLLER_HANDLE_T scif_controller,
+ SCI_REMOTE_DEVICE_HANDLE_T remote_device,
+ struct ISCI_IO_REQUEST * isci_request, SCI_IO_STATUS completion_status);
+
+void isci_task_request_complete(
+ SCI_CONTROLLER_HANDLE_T scif_controller,
+ SCI_REMOTE_DEVICE_HANDLE_T remote_device,
+ SCI_TASK_REQUEST_HANDLE_T io_request, SCI_TASK_STATUS completion_status);
+
+void isci_sysctl_initialize(struct isci_softc *isci);
+
+void isci_controller_construct(struct ISCI_CONTROLLER *controller,
+ struct isci_softc *isci);
+
+SCI_STATUS isci_controller_initialize(struct ISCI_CONTROLLER *controller);
+
+int isci_controller_allocate_memory(struct ISCI_CONTROLLER *controller);
+
+void isci_controller_domain_discovery_complete(
+ struct ISCI_CONTROLLER *isci_controller, struct ISCI_DOMAIN *isci_domain);
+
+int isci_controller_attach_to_cam(struct ISCI_CONTROLLER *controller);
+
+void isci_controller_start(void *controller);
+
+void isci_domain_construct(struct ISCI_DOMAIN *domain, uint32_t domain_index,
+ struct ISCI_CONTROLLER *controller);
+
+void isci_interrupt_setup(struct isci_softc *isci);
+void isci_interrupt_poll_handler(struct ISCI_CONTROLLER *controller);
+
+void isci_log_message(uint32_t verbosity, char *log_message_prefix,
+ char *log_message, ...);
+
+extern uint32_t g_isci_debug_level;
diff --git a/sys/dev/isci/isci_controller.c b/sys/dev/isci/isci_controller.c
new file mode 100644
index 0000000..02d281f
--- /dev/null
+++ b/sys/dev/isci/isci_controller.c
@@ -0,0 +1,653 @@
+/*-
+ * 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.
+ *
+ * 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 <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <dev/isci/isci.h>
+
+#include <sys/conf.h>
+#include <sys/malloc.h>
+
+#include <dev/isci/scil/sci_memory_descriptor_list.h>
+#include <dev/isci/scil/sci_memory_descriptor_list_decorator.h>
+
+#include <dev/isci/scil/scif_controller.h>
+#include <dev/isci/scil/scif_library.h>
+#include <dev/isci/scil/scif_io_request.h>
+#include <dev/isci/scil/scif_task_request.h>
+#include <dev/isci/scil/scif_remote_device.h>
+#include <dev/isci/scil/scif_domain.h>
+#include <dev/isci/scil/scif_user_callback.h>
+
+void isci_action(struct cam_sim *sim, union ccb *ccb);
+void isci_poll(struct cam_sim *sim);
+
+#define ccb_sim_ptr sim_priv.entries[0].ptr
+
+/**
+ * @brief This user callback will inform the user that the controller has
+ * had a serious unexpected error. The user should not the error,
+ * disable interrupts, and wait for current ongoing processing to
+ * complete. Subsequently, the user should reset the controller.
+ *
+ * @param[in] controller This parameter specifies the controller that had
+ * an error.
+ *
+ * @return none
+ */
+void scif_cb_controller_error(SCI_CONTROLLER_HANDLE_T controller,
+ SCI_CONTROLLER_ERROR error)
+{
+
+ isci_log_message(0, "ISCI", "scif_cb_controller_error: 0x%x\n",
+ error);
+}
+
+/**
+ * @brief This user callback will inform the user that the controller has
+ * finished the start process.
+ *
+ * @param[in] controller This parameter specifies the controller that was
+ * started.
+ * @param[in] completion_status This parameter specifies the results of
+ * the start operation. SCI_SUCCESS indicates successful
+ * completion.
+ *
+ * @return none
+ */
+void scif_cb_controller_start_complete(SCI_CONTROLLER_HANDLE_T controller,
+ SCI_STATUS completion_status)
+{
+ uint32_t index;
+ struct ISCI_CONTROLLER *isci_controller = (struct ISCI_CONTROLLER *)
+ sci_object_get_association(controller);
+
+ isci_controller->is_started = TRUE;
+
+ /* Set bits for all domains. We will clear them one-by-one once
+ * the domains complete discovery, or return error when calling
+ * scif_domain_discover. Once all bits are clear, we will register
+ * the controller with CAM.
+ */
+ isci_controller->initial_discovery_mask = (1 << SCI_MAX_DOMAINS) - 1;
+
+ for(index = 0; index < SCI_MAX_DOMAINS; index++) {
+ SCI_STATUS status;
+ SCI_DOMAIN_HANDLE_T domain =
+ isci_controller->domain[index].sci_object;
+
+ status = scif_domain_discover(
+ domain,
+ scif_domain_get_suggested_discover_timeout(domain),
+ DEVICE_TIMEOUT
+ );
+
+ if (status != SCI_SUCCESS)
+ {
+ isci_controller_domain_discovery_complete(
+ isci_controller, &isci_controller->domain[index]);
+ }
+ }
+}
+
+/**
+ * @brief This user callback will inform the user that the controller has
+ * finished the stop process. Note, after user calls
+ * scif_controller_stop(), before user receives this controller stop
+ * complete callback, user should not expect any callback from
+ * framework, such like scif_cb_domain_change_notification().
+ *
+ * @param[in] controller This parameter specifies the controller that was
+ * stopped.
+ * @param[in] completion_status This parameter specifies the results of
+ * the stop operation. SCI_SUCCESS indicates successful
+ * completion.
+ *
+ * @return none
+ */
+void scif_cb_controller_stop_complete(SCI_CONTROLLER_HANDLE_T controller,
+ SCI_STATUS completion_status)
+{
+ struct ISCI_CONTROLLER *isci_controller = (struct ISCI_CONTROLLER *)
+ sci_object_get_association(controller);
+
+ isci_controller->is_started = FALSE;
+}
+
+/**
+ * @brief This method will be invoked to allocate memory dynamically.
+ *
+ * @param[in] controller This parameter represents the controller
+ * object for which to allocate memory.
+ * @param[out] mde This parameter represents the memory descriptor to
+ * be filled in by the user that will reference the newly
+ * allocated memory.
+ *
+ * @return none
+ */
+void scif_cb_controller_allocate_memory(SCI_CONTROLLER_HANDLE_T controller,
+ SCI_PHYSICAL_MEMORY_DESCRIPTOR_T *mde)
+{
+
+}
+
+/**
+ * @brief This method will be invoked to allocate memory dynamically.
+ *
+ * @param[in] controller This parameter represents the controller
+ * object for which to allocate memory.
+ * @param[out] mde This parameter represents the memory descriptor to
+ * be filled in by the user that will reference the newly
+ * allocated memory.
+ *
+ * @return none
+ */
+void scif_cb_controller_free_memory(SCI_CONTROLLER_HANDLE_T controller,
+ SCI_PHYSICAL_MEMORY_DESCRIPTOR_T * mde)
+{
+
+}
+
+void isci_controller_construct(struct ISCI_CONTROLLER *controller,
+ struct isci_softc *isci)
+{
+ SCI_CONTROLLER_HANDLE_T scif_controller_handle;
+
+ scif_library_allocate_controller(isci->sci_library_handle,
+ &scif_controller_handle);
+
+ scif_controller_construct(isci->sci_library_handle,
+ scif_controller_handle, NULL);
+
+ controller->isci = isci;
+ controller->scif_controller_handle = scif_controller_handle;
+
+ /* This allows us to later use
+ * sci_object_get_association(scif_controller_handle)
+ * inside of a callback routine to get our struct ISCI_CONTROLLER object
+ */
+ sci_object_set_association(scif_controller_handle, (void *)controller);
+
+ controller->is_started = FALSE;
+ controller->is_frozen = FALSE;
+ controller->sim = NULL;
+ controller->initial_discovery_mask = 0;
+
+ sci_fast_list_init(&controller->pending_device_reset_list);
+
+ mtx_init(&controller->lock, "isci", NULL, MTX_DEF);
+
+ uint32_t domain_index;
+
+ for(domain_index = 0; domain_index < SCI_MAX_DOMAINS; domain_index++) {
+ isci_domain_construct( &controller->domain[domain_index],
+ domain_index, controller);
+ }
+
+ controller->timer_memory = malloc(
+ sizeof(struct ISCI_TIMER) * SCI_MAX_TIMERS, M_ISCI,
+ M_NOWAIT | M_ZERO);
+
+ sci_pool_initialize(controller->timer_pool);
+
+ struct ISCI_TIMER *timer = (struct ISCI_TIMER *)
+ controller->timer_memory;
+
+ for ( int i = 0; i < SCI_MAX_TIMERS; i++ ) {
+ sci_pool_put(controller->timer_pool, timer++);
+ }
+}
+
+SCI_STATUS isci_controller_initialize(struct ISCI_CONTROLLER *controller)
+{
+ SCIC_USER_PARAMETERS_T scic_user_parameters;
+ SCI_CONTROLLER_HANDLE_T scic_controller_handle;
+ unsigned long tunable;
+ int i;
+
+ scic_controller_handle =
+ scif_controller_get_scic_handle(controller->scif_controller_handle);
+
+ if (controller->isci->oem_parameters_found == TRUE)
+ {
+ scic_oem_parameters_set(
+ scic_controller_handle,
+ &controller->oem_parameters,
+ (uint8_t)(controller->oem_parameters_version));
+ }
+
+ scic_user_parameters_get(scic_controller_handle, &scic_user_parameters);
+
+ if (TUNABLE_ULONG_FETCH("hw.isci.no_outbound_task_timeout", &tunable))
+ scic_user_parameters.sds1.no_outbound_task_timeout =
+ (uint8_t)tunable;
+
+ if (TUNABLE_ULONG_FETCH("hw.isci.ssp_max_occupancy_timeout", &tunable))
+ scic_user_parameters.sds1.ssp_max_occupancy_timeout =
+ (uint16_t)tunable;
+
+ if (TUNABLE_ULONG_FETCH("hw.isci.stp_max_occupancy_timeout", &tunable))
+ scic_user_parameters.sds1.stp_max_occupancy_timeout =
+ (uint16_t)tunable;
+
+ if (TUNABLE_ULONG_FETCH("hw.isci.ssp_inactivity_timeout", &tunable))
+ scic_user_parameters.sds1.ssp_inactivity_timeout =
+ (uint16_t)tunable;
+
+ if (TUNABLE_ULONG_FETCH("hw.isci.stp_inactivity_timeout", &tunable))
+ scic_user_parameters.sds1.stp_inactivity_timeout =
+ (uint16_t)tunable;
+
+ if (TUNABLE_ULONG_FETCH("hw.isci.max_speed_generation", &tunable))
+ for (i = 0; i < SCI_MAX_PHYS; i++)
+ scic_user_parameters.sds1.phys[i].max_speed_generation =
+ (uint8_t)tunable;
+
+ scic_user_parameters_set(scic_controller_handle, &scic_user_parameters);
+
+ /* Scheduler bug in SCU requires SCIL to reserve some task contexts as a
+ * a workaround - one per domain.
+ */
+ controller->queue_depth = SCI_MAX_IO_REQUESTS - SCI_MAX_DOMAINS;
+
+ if (TUNABLE_INT_FETCH("hw.isci.controller_queue_depth",
+ &controller->queue_depth)) {
+ controller->queue_depth = max(1, min(controller->queue_depth,
+ SCI_MAX_IO_REQUESTS - SCI_MAX_DOMAINS));
+ }
+
+ /* Reserve one request so that we can ensure we have one available TC
+ * to do internal device resets.
+ */
+ controller->sim_queue_depth = controller->queue_depth - 1;
+
+ /* Although we save one TC to do internal device resets, it is possible
+ * we could end up using several TCs for simultaneous device resets
+ * while at the same time having CAM fill our controller queue. To
+ * simulate this condition, and how our driver handles it, we can set
+ * this io_shortage parameter, which will tell CAM that we have a
+ * large queue depth than we really do.
+ */
+ uint32_t io_shortage = 0;
+ TUNABLE_INT_FETCH("hw.isci.io_shortage", &io_shortage);
+ controller->sim_queue_depth += io_shortage;
+
+ return (scif_controller_initialize(controller->scif_controller_handle));
+}
+
+int isci_controller_allocate_memory(struct ISCI_CONTROLLER *controller)
+{
+ int error;
+ device_t device = controller->isci->device;
+ uint32_t max_segment_size = isci_io_request_get_max_io_size();
+ uint32_t status = 0;
+ struct ISCI_MEMORY *uncached_controller_memory =
+ &controller->uncached_controller_memory;
+ struct ISCI_MEMORY *cached_controller_memory =
+ &controller->cached_controller_memory;
+ struct ISCI_MEMORY *request_memory =
+ &controller->request_memory;
+ POINTER_UINT virtual_address;
+ bus_addr_t physical_address;
+
+ controller->mdl = sci_controller_get_memory_descriptor_list_handle(
+ controller->scif_controller_handle);
+
+ uncached_controller_memory->size = sci_mdl_decorator_get_memory_size(
+ controller->mdl, SCI_MDE_ATTRIBUTE_PHYSICALLY_CONTIGUOUS);
+
+ error = isci_allocate_dma_buffer(device, uncached_controller_memory);
+
+ if (error != 0)
+ return (error);
+
+ sci_mdl_decorator_assign_memory( controller->mdl,
+ SCI_MDE_ATTRIBUTE_PHYSICALLY_CONTIGUOUS,
+ uncached_controller_memory->virtual_address,
+ uncached_controller_memory->physical_address);
+
+ cached_controller_memory->size = sci_mdl_decorator_get_memory_size(
+ controller->mdl,
+ SCI_MDE_ATTRIBUTE_CACHEABLE | SCI_MDE_ATTRIBUTE_PHYSICALLY_CONTIGUOUS
+ );
+
+ error = isci_allocate_dma_buffer(device, cached_controller_memory);
+
+ if (error != 0)
+ return (error);
+
+ sci_mdl_decorator_assign_memory(controller->mdl,
+ SCI_MDE_ATTRIBUTE_CACHEABLE | SCI_MDE_ATTRIBUTE_PHYSICALLY_CONTIGUOUS,
+ cached_controller_memory->virtual_address,
+ cached_controller_memory->physical_address);
+
+ request_memory->size =
+ controller->queue_depth * isci_io_request_get_object_size();
+
+ error = isci_allocate_dma_buffer(device, request_memory);
+
+ if (error != 0)
+ return (error);
+
+ /* For STP PIO testing, we want to ensure we can force multiple SGLs
+ * since this has been a problem area in SCIL. This tunable parameter
+ * will allow us to force DMA segments to a smaller size, ensuring
+ * that even if a physically contiguous buffer is attached to this
+ * I/O, the DMA subsystem will pass us multiple segments in our DMA
+ * load callback.
+ */
+ TUNABLE_INT_FETCH("hw.isci.max_segment_size", &max_segment_size);
+
+ /* Create DMA tag for our I/O requests. Then we can create DMA maps based off
+ * of this tag and store them in each of our ISCI_IO_REQUEST objects. This
+ * will enable better performance than creating the DMA maps everytime we get
+ * an I/O.
+ */
+ status = bus_dma_tag_create(bus_get_dma_tag(device), 0x1, 0x0,
+ BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, NULL, NULL,
+ isci_io_request_get_max_io_size(),
+ SCI_MAX_SCATTER_GATHER_ELEMENTS, max_segment_size, 0, NULL, NULL,
+ &controller->buffer_dma_tag);
+
+ sci_pool_initialize(controller->request_pool);
+
+ virtual_address = request_memory->virtual_address;
+ physical_address = request_memory->physical_address;
+
+ for (int i = 0; i < controller->queue_depth; i++) {
+ struct ISCI_REQUEST *request =
+ (struct ISCI_REQUEST *)virtual_address;
+
+ isci_request_construct(request,
+ controller->scif_controller_handle,
+ controller->buffer_dma_tag, physical_address);
+
+ sci_pool_put(controller->request_pool, request);
+
+ virtual_address += isci_request_get_object_size();
+ physical_address += isci_request_get_object_size();
+ }
+
+ uint32_t remote_device_size = sizeof(struct ISCI_REMOTE_DEVICE) +
+ scif_remote_device_get_object_size();
+
+ controller->remote_device_memory = (uint8_t *) malloc(
+ remote_device_size * SCI_MAX_REMOTE_DEVICES, M_ISCI,
+ M_NOWAIT | M_ZERO);
+
+ sci_pool_initialize(controller->remote_device_pool);
+
+ uint8_t *remote_device_memory_ptr = controller->remote_device_memory;
+
+ for (int i = 0; i < SCI_MAX_REMOTE_DEVICES; i++) {
+ struct ISCI_REMOTE_DEVICE *remote_device =
+ (struct ISCI_REMOTE_DEVICE *)remote_device_memory_ptr;
+
+ controller->remote_device[i] = NULL;
+ remote_device->index = i;
+ remote_device->is_resetting = FALSE;
+ remote_device->frozen_lun_mask = 0;
+ sci_fast_list_element_init(remote_device,
+ &remote_device->pending_device_reset_element);
+ sci_pool_put(controller->remote_device_pool, remote_device);
+ remote_device_memory_ptr += remote_device_size;
+ }
+
+ return (0);
+}
+
+void isci_controller_start(void *controller_handle)
+{
+ struct ISCI_CONTROLLER *controller =
+ (struct ISCI_CONTROLLER *)controller_handle;
+ SCI_CONTROLLER_HANDLE_T scif_controller_handle =
+ controller->scif_controller_handle;
+
+ scif_controller_start(scif_controller_handle,
+ scif_controller_get_suggested_start_timeout(scif_controller_handle));
+
+ scic_controller_enable_interrupts(
+ scif_controller_get_scic_handle(controller->scif_controller_handle));
+}
+
+void isci_controller_domain_discovery_complete(
+ struct ISCI_CONTROLLER *isci_controller, struct ISCI_DOMAIN *isci_domain)
+{
+ if (isci_controller->sim == NULL)
+ {
+ /* Controller has not been attached to CAM yet. We'll clear
+ * the discovery bit for this domain, then check if all bits
+ * are now clear. That would indicate that all domains are
+ * done with discovery and we can then attach the controller
+ * to CAM.
+ */
+
+ isci_controller->initial_discovery_mask &=
+ ~(1 << isci_domain->index);
+
+ if (isci_controller->initial_discovery_mask == 0) {
+ struct isci_softc *driver = isci_controller->isci;
+ uint8_t next_index = isci_controller->index + 1;
+
+ isci_controller_attach_to_cam(isci_controller);
+
+ if (next_index < driver->controller_count) {
+ /* There are more controllers that need to
+ * start. So start the next one.
+ */
+ isci_controller_start(
+ &driver->controllers[next_index]);
+ }
+ else
+ {
+ /* All controllers have been started and completed discovery.
+ * Disestablish the config hook while will signal to the
+ * kernel during boot that it is safe to try to find and
+ * mount the root partition.
+ */
+ config_intrhook_disestablish(
+ &driver->config_hook);
+ }
+ }
+ }
+}
+
+int isci_controller_attach_to_cam(struct ISCI_CONTROLLER *controller)
+{
+ struct isci_softc *isci = controller->isci;
+ device_t parent = device_get_parent(isci->device);
+ int unit = device_get_unit(isci->device);
+ struct cam_devq *isci_devq = cam_simq_alloc(controller->sim_queue_depth);
+
+ if(isci_devq == NULL) {
+ isci_log_message(0, "ISCI", "isci_devq is NULL \n");
+ return (-1);
+ }
+
+ controller->sim = cam_sim_alloc(isci_action, isci_poll, "isci",
+ controller, unit, &controller->lock, controller->sim_queue_depth,
+ controller->sim_queue_depth, isci_devq);
+
+ if(controller->sim == NULL) {
+ isci_log_message(0, "ISCI", "cam_sim_alloc... fails\n");
+ cam_simq_free(isci_devq);
+ return (-1);
+ }
+
+ if(xpt_bus_register(controller->sim, parent, controller->index)
+ != CAM_SUCCESS) {
+ isci_log_message(0, "ISCI", "xpt_bus_register...fails \n");
+ cam_sim_free(controller->sim, TRUE);
+ mtx_unlock(&controller->lock);
+ return (-1);
+ }
+
+ if(xpt_create_path(&controller->path, NULL,
+ cam_sim_path(controller->sim), CAM_TARGET_WILDCARD,
+ CAM_LUN_WILDCARD) != CAM_REQ_CMP) {
+ isci_log_message(0, "ISCI", "xpt_create_path....fails\n");
+ xpt_bus_deregister(cam_sim_path(controller->sim));
+ cam_sim_free(controller->sim, TRUE);
+ mtx_unlock(&controller->lock);
+ return (-1);
+ }
+
+ return (0);
+}
+
+void isci_poll(struct cam_sim *sim)
+{
+ struct ISCI_CONTROLLER *controller =
+ (struct ISCI_CONTROLLER *)cam_sim_softc(sim);
+
+ isci_interrupt_poll_handler(controller);
+}
+
+void isci_action(struct cam_sim *sim, union ccb *ccb)
+{
+ struct ISCI_CONTROLLER *controller =
+ (struct ISCI_CONTROLLER *)cam_sim_softc(sim);
+
+ switch ( ccb->ccb_h.func_code ) {
+ case XPT_PATH_INQ:
+ {
+ struct ccb_pathinq *cpi = &ccb->cpi;
+ int bus = cam_sim_bus(sim);
+ ccb->ccb_h.ccb_sim_ptr = sim;
+ cpi->version_num = 1;
+ cpi->hba_inquiry = PI_TAG_ABLE;
+ cpi->target_sprt = 0;
+ cpi->hba_misc = PIM_NOBUSRESET | PIM_SEQSCAN;
+ cpi->hba_eng_cnt = 0;
+ cpi->max_target = SCI_MAX_REMOTE_DEVICES - 1;
+ cpi->max_lun = ISCI_MAX_LUN;
+#if __FreeBSD_version >= 704100
+ cpi->maxio = isci_io_request_get_max_io_size();
+#endif
+ cpi->unit_number = cam_sim_unit(sim);
+ cpi->bus_id = bus;
+ cpi->initiator_id = SCI_MAX_REMOTE_DEVICES;
+ cpi->base_transfer_speed = 300000;
+ strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN);
+ strncpy(cpi->hba_vid, "Intel Corp.", HBA_IDLEN);
+ strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN);
+ cpi->transport = XPORT_SAS;
+ cpi->transport_version = 0;
+ cpi->protocol = PROTO_SCSI;
+ cpi->protocol_version = SCSI_REV_SPC2;
+ cpi->ccb_h.status = CAM_REQ_CMP;
+ xpt_done(ccb);
+ }
+ break;
+ case XPT_GET_TRAN_SETTINGS:
+ {
+ struct ccb_trans_settings *general_settings = &ccb->cts;
+ struct ccb_trans_settings_sas *sas_settings =
+ &general_settings->xport_specific.sas;
+ struct ccb_trans_settings_scsi *scsi_settings =
+ &general_settings->proto_specific.scsi;
+ struct ISCI_REMOTE_DEVICE *remote_device;
+
+ remote_device = controller->remote_device[ccb->ccb_h.target_id];
+
+ if (remote_device == NULL) {
+ ccb->ccb_h.status &= ~CAM_SIM_QUEUED;
+ ccb->ccb_h.status &= ~CAM_STATUS_MASK;
+ ccb->ccb_h.status |= CAM_DEV_NOT_THERE;
+ xpt_done(ccb);
+ break;
+ }
+
+ general_settings->protocol = PROTO_SCSI;
+ general_settings->transport = XPORT_SAS;
+ general_settings->protocol_version = SCSI_REV_SPC2;
+ general_settings->transport_version = 0;
+ scsi_settings->valid = CTS_SCSI_VALID_TQ;
+ scsi_settings->flags = CTS_SCSI_FLAGS_TAG_ENB;
+ ccb->ccb_h.status &= ~CAM_STATUS_MASK;
+ ccb->ccb_h.status |= CAM_REQ_CMP;
+
+ sas_settings->bitrate =
+ isci_remote_device_get_bitrate(remote_device);
+
+ if (sas_settings->bitrate != 0)
+ sas_settings->valid = CTS_SAS_VALID_SPEED;
+
+ xpt_done(ccb);
+ }
+ break;
+ case XPT_SCSI_IO:
+ isci_io_request_execute_scsi_io(ccb, controller);
+ break;
+#if __FreeBSD_version >= 900026
+ case XPT_SMP_IO:
+ isci_io_request_execute_smp_io(ccb, controller);
+ break;
+#endif
+ case XPT_SET_TRAN_SETTINGS:
+ ccb->ccb_h.status &= ~CAM_STATUS_MASK;
+ ccb->ccb_h.status |= CAM_REQ_CMP;
+ xpt_done(ccb);
+ break;
+ case XPT_CALC_GEOMETRY:
+ cam_calc_geometry(&ccb->ccg, /*extended*/1);
+ xpt_done(ccb);
+ break;
+ case XPT_RESET_DEV:
+ {
+ struct ISCI_REMOTE_DEVICE *remote_device =
+ controller->remote_device[ccb->ccb_h.target_id];
+
+ if (remote_device != NULL)
+ isci_remote_device_reset(remote_device, ccb);
+ else {
+ ccb->ccb_h.status &= ~CAM_SIM_QUEUED;
+ ccb->ccb_h.status &= ~CAM_STATUS_MASK;
+ ccb->ccb_h.status |= CAM_DEV_NOT_THERE;
+ xpt_done(ccb);
+ }
+ }
+ break;
+ case XPT_RESET_BUS:
+ ccb->ccb_h.status = CAM_REQ_CMP;
+ xpt_done(ccb);
+ break;
+ default:
+ isci_log_message(0, "ISCI", "Unhandled func_code 0x%x\n",
+ ccb->ccb_h.func_code);
+ ccb->ccb_h.status &= ~CAM_SIM_QUEUED;
+ ccb->ccb_h.status &= ~CAM_STATUS_MASK;
+ ccb->ccb_h.status |= CAM_REQ_INVALID;
+ xpt_done(ccb);
+ break;
+ }
+}
+
diff --git a/sys/dev/isci/isci_domain.c b/sys/dev/isci/isci_domain.c
new file mode 100644
index 0000000..1f79dfd
--- /dev/null
+++ b/sys/dev/isci/isci_domain.c
@@ -0,0 +1,318 @@
+/*-
+ * 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.
+ *
+ * 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 <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <dev/isci/isci.h>
+
+#include <cam/cam_periph.h>
+#include <cam/cam_xpt_periph.h>
+
+#include <dev/isci/scil/scif_domain.h>
+#include <dev/isci/scil/scif_remote_device.h>
+#include <dev/isci/scil/scif_controller.h>
+#include <dev/isci/scil/scif_user_callback.h>
+
+/**
+ * @brief This callback method informs the framework user that something
+ * in the supplied domain has changed (e.g. a device was added or
+ * removed).
+ *
+ * This callback is called by the framework outside of discovery or
+ * target reset processes. Specifically, domain changes occurring
+ * during these processes are handled by the framework. For example,
+ * in the case of Serial Attached SCSI, reception of a BROADCAST (CHANGE)
+ * during discovery will cause discovery to restart. Thus, discovery
+ * does not complete until all BCNs are processed. Note, during controller
+ * stopping/reset process, the framework user should not expect this call
+ * back.
+ *
+ * @param[in] controller This parameter specifies the controller object
+ * with which this callback is associated.
+ * @param[in] domain This parameter specifies the domain object with
+ * which this callback is associated.
+ *
+ * @return none
+ */
+void
+scif_cb_domain_change_notification(SCI_CONTROLLER_HANDLE_T controller,
+ SCI_DOMAIN_HANDLE_T domain)
+{
+ struct ISCI_CONTROLLER *isci_controller =
+ (struct ISCI_CONTROLLER *)sci_object_get_association(controller);
+
+ /* When the controller start is complete, we will explicitly discover
+ * all of the domains then. This is because SCIF will not allow
+ * any I/O to start until the controller is ready, meaning internal SMP
+ * requests triggered by domain discovery won't work until the controller
+ * is ready.
+ */
+ if (isci_controller->is_started == TRUE)
+ scif_domain_discover(domain,
+ scif_domain_get_suggested_discover_timeout(domain),
+ DEVICE_TIMEOUT);
+}
+
+/**
+ * @brief This callback method informs the framework user that a previously
+ * requested discovery operation on the domain has completed.
+ *
+ * @param[in] controller This parameter specifies the controller object
+ * with which this callback is associated.
+ * @param[in] domain This parameter specifies the domain object with
+ * which this callback is associated.
+ * @param[in] completion_status This parameter indicates the results of the
+ * discovery operation.
+ *
+ * @return none
+ */
+void
+scif_cb_domain_discovery_complete(SCI_CONTROLLER_HANDLE_T controller,
+ SCI_DOMAIN_HANDLE_T domain, SCI_STATUS completion_status)
+{
+
+ if(completion_status != SCI_SUCCESS)
+ isci_log_message(0, "ISCI",
+ "scif_cb_domain_discovery_complete status = 0x%x\n",
+ completion_status);
+
+ isci_controller_domain_discovery_complete(
+ (struct ISCI_CONTROLLER *)sci_object_get_association(controller),
+ (struct ISCI_DOMAIN *) sci_object_get_association(domain));
+}
+
+/**
+ * @brief This callback method informs the framework user that a previously
+ * requested reset operation on the domain has completed.
+ *
+ * @param[in] controller This parameter specifies the controller object
+ * with which this callback is associated.
+ * @param[in] domain This parameter specifies the domain object with
+ * which this callback is associated.
+ * @param[in] completion_status This parameter indicates the results of the
+ * reset operation.
+ *
+ * @return none
+ */
+void
+scif_cb_domain_reset_complete(SCI_CONTROLLER_HANDLE_T controller,
+ SCI_DOMAIN_HANDLE_T domain, SCI_STATUS completion_status)
+{
+
+}
+
+/**
+ * @brief This callback method informs the framework user that the domain
+ * is ready and capable of processing IO requests for devices found
+ * inside it.
+ *
+ * @param[in] controller This parameter specifies the controller object
+ * with which this callback is associated.
+ * @param[in] domain This parameter specifies the domain object with
+ * which this callback is associated.
+ *
+ * @return none
+ */
+void
+scif_cb_domain_ready(SCI_CONTROLLER_HANDLE_T controller,
+ SCI_DOMAIN_HANDLE_T domain)
+{
+ uint32_t i;
+ struct ISCI_DOMAIN *isci_domain = sci_object_get_association(domain);
+ struct ISCI_CONTROLLER *isci_controller =
+ sci_object_get_association(controller);
+
+ for (i = 0; i < SCI_MAX_REMOTE_DEVICES; i++) {
+ struct ISCI_REMOTE_DEVICE *remote_device =
+ isci_controller->remote_device[i];
+
+ if (remote_device != NULL &&
+ remote_device->domain == isci_domain)
+ isci_remote_device_release_device_queue(remote_device);
+ }
+}
+
+/**
+ * @brief This callback method informs the framework user that the domain
+ * is no longer ready. Thus, it is incapable of processing IO
+ * requests for devices found inside it.
+ *
+ * @param[in] controller This parameter specifies the controller object
+ * with which this callback is associated.
+ * @param[in] domain This parameter specifies the domain object with
+ * which this callback is associated.
+ *
+ * @return none
+ */
+void
+scif_cb_domain_not_ready(SCI_CONTROLLER_HANDLE_T controller,
+ SCI_DOMAIN_HANDLE_T domain)
+{
+
+}
+
+/**
+ * @brief This callback method informs the framework user that a new
+ * direct attached device was found in the domain.
+ *
+ * @param[in] controller This parameter specifies the controller object
+ * with which this callback is associated.
+ * @param[in] domain This parameter specifies the domain object with
+ * which this callback is associated.
+ * @param[in] sas_address This parameter specifies the SAS address of
+ * the new device.
+ * @param[in] protocols This parameter specifies the protocols
+ * supported by the newly discovered device.
+ *
+ * @return none
+ */
+void
+scif_cb_domain_da_device_added(SCI_CONTROLLER_HANDLE_T controller,
+ SCI_DOMAIN_HANDLE_T domain, SCI_SAS_ADDRESS_T *sas_address,
+ SCI_SAS_IDENTIFY_ADDRESS_FRAME_PROTOCOLS_T *protocols)
+{
+ struct ISCI_REMOTE_DEVICE *remote_device;
+ struct ISCI_DOMAIN *isci_domain =
+ (struct ISCI_DOMAIN *)sci_object_get_association(domain);
+ struct ISCI_CONTROLLER *isci_controller =
+ (struct ISCI_CONTROLLER *)sci_object_get_association(controller);
+
+ sci_pool_get(isci_controller->remote_device_pool, remote_device);
+
+ scif_remote_device_construct(domain,
+ (uint8_t*)remote_device + sizeof(struct ISCI_REMOTE_DEVICE),
+ &(remote_device->sci_object));
+
+ sci_object_set_association(remote_device->sci_object, remote_device);
+
+ scif_remote_device_da_construct(remote_device->sci_object, sas_address,
+ protocols);
+
+ /* We do not put the device in the ISCI_CONTROLLER's device array yet.
+ * That will happen once the device becomes ready (see
+ * scif_cb_remote_device_ready).
+ */
+
+ remote_device->domain = isci_domain;
+}
+
+/**
+ * @brief This callback method informs the framework user that a new
+ * expander attached device was found in the domain.
+ *
+ * @param[in] controller This parameter specifies the controller object
+ * with which this callback is associated.
+ * @param[in] domain This parameter specifies the domain object with
+ * which this callback is associated.
+ * @param[in] containing_device This parameter specifies the remote
+ * device that contains the device that was added.
+ * @param[in] smp_response This parameter specifies the SMP response
+ * data associated with the newly discovered device.
+ *
+ * @return none
+ */
+void
+scif_cb_domain_ea_device_added(SCI_CONTROLLER_HANDLE_T controller,
+ SCI_DOMAIN_HANDLE_T domain, SCI_REMOTE_DEVICE_HANDLE_T containing_device,
+ SMP_RESPONSE_DISCOVER_T *smp_response)
+{
+ struct ISCI_REMOTE_DEVICE *remote_device;
+ struct ISCI_DOMAIN *isci_domain =
+ (struct ISCI_DOMAIN *)sci_object_get_association(domain);
+ struct ISCI_CONTROLLER *isci_controller =
+ (struct ISCI_CONTROLLER *)sci_object_get_association(controller);
+
+ sci_pool_get(isci_controller->remote_device_pool, remote_device);
+
+ scif_remote_device_construct( domain,
+ (uint8_t*)remote_device + sizeof(struct ISCI_REMOTE_DEVICE),
+ &(remote_device->sci_object));
+
+ sci_object_set_association(remote_device->sci_object, remote_device);
+
+ scif_remote_device_ea_construct(remote_device->sci_object,
+ containing_device, smp_response);
+
+ /* We do not put the device in the ISCI_CONTROLLER's device array yet.
+ * That will happen once the device becomes ready (see
+ * scif_cb_remote_device_ready).
+ */
+ remote_device->domain = isci_domain;
+}
+
+/**
+ * @brief This callback method informs the framework user that a device
+ * has been removed from the domain.
+ *
+ * @param[in] controller This parameter specifies the controller object
+ * with which this callback is associated.
+ * @param[in] domain This parameter specifies the domain object with
+ * which this callback is associated.
+ * @param[in] remote_device This parameter specifies the device object with
+ * which this callback is associated.
+ *
+ * @return none
+ */
+void
+scif_cb_domain_device_removed(SCI_CONTROLLER_HANDLE_T controller,
+ SCI_DOMAIN_HANDLE_T domain, SCI_REMOTE_DEVICE_HANDLE_T remote_device)
+{
+ struct ISCI_REMOTE_DEVICE *isci_remote_device =
+ (struct ISCI_REMOTE_DEVICE *)sci_object_get_association(remote_device);
+ struct ISCI_CONTROLLER *isci_controller =
+ (struct ISCI_CONTROLLER *)sci_object_get_association(controller);
+ uint32_t path = cam_sim_path(isci_controller->sim);
+ union ccb *ccb = xpt_alloc_ccb_nowait();
+
+ isci_controller->remote_device[isci_remote_device->index] = NULL;
+
+ xpt_create_path(&ccb->ccb_h.path, xpt_periph, path,
+ isci_remote_device->index, CAM_LUN_WILDCARD);
+
+ xpt_rescan(ccb);
+
+ scif_remote_device_destruct(remote_device);
+
+ sci_pool_put(isci_controller->remote_device_pool, isci_remote_device);
+}
+
+void
+isci_domain_construct(struct ISCI_DOMAIN *domain, uint32_t domain_index,
+ struct ISCI_CONTROLLER *controller)
+{
+
+ scif_controller_get_domain_handle( controller->scif_controller_handle,
+ domain_index, &domain->sci_object);
+
+ domain->index = domain_index;
+ domain->controller = controller;
+ sci_object_set_association(domain->sci_object, (void *)domain);
+}
diff --git a/sys/dev/isci/isci_interrupt.c b/sys/dev/isci/isci_interrupt.c
new file mode 100644
index 0000000..e020f83
--- /dev/null
+++ b/sys/dev/isci/isci_interrupt.c
@@ -0,0 +1,229 @@
+/*-
+ * 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.
+ *
+ * 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 <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <dev/isci/isci.h>
+
+#include <dev/pci/pcireg.h>
+#include <dev/pci/pcivar.h>
+
+#include <dev/isci/scil/scif_controller.h>
+
+void isci_interrupt_legacy_handler(void *arg);
+void isci_interrupt_msix_handler(void *arg);
+
+static int
+isci_interrupt_setup_legacy(struct isci_softc *isci)
+{
+ struct ISCI_INTERRUPT_INFO *interrupt_info = &isci->interrupt_info[0];
+
+ isci->num_interrupts = 1;
+
+ scic_controller_get_handler_methods(SCIC_LEGACY_LINE_INTERRUPT_TYPE,
+ 0, &isci->handlers[0]);
+
+ interrupt_info->handlers = &isci->handlers[0];
+ interrupt_info->rid = 0;
+ interrupt_info->interrupt_target_handle = (void *)isci;
+
+ interrupt_info->res = bus_alloc_resource_any(isci->device, SYS_RES_IRQ,
+ &interrupt_info->rid, RF_SHAREABLE|RF_ACTIVE);
+
+ if (interrupt_info->res == NULL) {
+ isci_log_message(0, "ISCI", "bus_alloc_resource failed\n");
+ return (-1);
+ }
+
+ interrupt_info->tag = NULL;
+ if (bus_setup_intr(isci->device, interrupt_info->res,
+ INTR_TYPE_CAM | INTR_MPSAFE, NULL, isci_interrupt_legacy_handler,
+ interrupt_info, &interrupt_info->tag)) {
+ isci_log_message(0, "ISCI", "bus_setup_intr failed\n");
+ return (-1);
+ }
+
+ return (0);
+}
+
+static int
+isci_interrupt_setup_msix(struct isci_softc *isci)
+{
+ uint32_t controller_index;
+
+ scic_controller_get_handler_methods(SCIC_MSIX_INTERRUPT_TYPE,
+ SCI_MAX_MSIX_MESSAGES_PER_CONTROLLER, &isci->handlers[0]);
+
+ for (controller_index = 0; controller_index < isci->controller_count;
+ controller_index++) {
+ uint32_t msix_index;
+ uint8_t base_index = controller_index *
+ SCI_MAX_MSIX_MESSAGES_PER_CONTROLLER;
+
+ for (msix_index = 0; msix_index < SCI_MAX_MSIX_MESSAGES_PER_CONTROLLER;
+ msix_index++) {
+ struct ISCI_INTERRUPT_INFO *info =
+ &isci->interrupt_info[base_index+msix_index];
+
+ info->handlers = &isci->handlers[msix_index];
+ info->interrupt_target_handle =
+ &isci->controllers[controller_index];
+
+ info->rid = base_index+msix_index+1;
+
+ info->res = bus_alloc_resource_any(isci->device,
+ SYS_RES_IRQ, &info->rid, RF_ACTIVE);
+ if (info->res == NULL) {
+ isci_log_message(0, "ISCI",
+ "bus_alloc_resource failed\n");
+ return (-1);
+ }
+
+ info->tag = NULL;
+ if (bus_setup_intr(isci->device, info->res,
+ INTR_TYPE_CAM | INTR_MPSAFE, NULL,
+ isci_interrupt_msix_handler, info, &info->tag)) {
+ isci_log_message(0, "ISCI",
+ "bus_setup_intr failed\n");
+ return (-1);
+ }
+ }
+ }
+
+ return (0);
+}
+
+void
+isci_interrupt_setup(struct isci_softc *isci)
+{
+ uint8_t max_msix_messages = SCI_MAX_MSIX_MESSAGES_PER_CONTROLLER *
+ isci->controller_count;
+ BOOL use_msix = FALSE;
+ uint32_t force_legacy_interrupts = 0;
+
+ TUNABLE_INT_FETCH("hw.isci.force_legacy_interrupts",
+ &force_legacy_interrupts);
+
+ if (!force_legacy_interrupts &&
+ pci_msix_count(isci->device) >= max_msix_messages) {
+
+ isci->num_interrupts = max_msix_messages;
+ pci_alloc_msix(isci->device, &isci->num_interrupts);
+ if (isci->num_interrupts == max_msix_messages)
+ use_msix = TRUE;
+ }
+
+ if (use_msix == TRUE)
+ isci_interrupt_setup_msix(isci);
+ else
+ isci_interrupt_setup_legacy(isci);
+}
+
+void
+isci_interrupt_legacy_handler(void *arg)
+{
+ struct ISCI_INTERRUPT_INFO *interrupt_info =
+ (struct ISCI_INTERRUPT_INFO *)arg;
+ struct isci_softc *isci =
+ (struct isci_softc *)interrupt_info->interrupt_target_handle;
+ SCIC_CONTROLLER_INTERRUPT_HANDLER interrupt_handler;
+ SCIC_CONTROLLER_COMPLETION_HANDLER completion_handler;
+ int index;
+
+ interrupt_handler = interrupt_info->handlers->interrupt_handler;
+ completion_handler = interrupt_info->handlers->completion_handler;
+
+ for (index = 0; index < isci->controller_count; index++) {
+ struct ISCI_CONTROLLER *controller = &isci->controllers[index];
+
+ /* If controller_count > 0, we will get interrupts here for
+ * controller 0 before controller 1 has even started. So
+ * we need to make sure we don't call the completion handler
+ * for a non-started controller.
+ */
+ if (controller->is_started == TRUE) {
+ SCI_CONTROLLER_HANDLE_T scic_controller_handle =
+ scif_controller_get_scic_handle(
+ controller->scif_controller_handle);
+
+ if (interrupt_handler(scic_controller_handle)) {
+ mtx_lock(&controller->lock);
+ completion_handler(scic_controller_handle);
+ mtx_unlock(&controller->lock);
+ }
+ }
+ }
+}
+
+void
+isci_interrupt_msix_handler(void *arg)
+{
+ struct ISCI_INTERRUPT_INFO *interrupt_info =
+ (struct ISCI_INTERRUPT_INFO *)arg;
+ struct ISCI_CONTROLLER *controller =
+ (struct ISCI_CONTROLLER *)interrupt_info->interrupt_target_handle;
+ SCIC_CONTROLLER_INTERRUPT_HANDLER interrupt_handler;
+ SCIC_CONTROLLER_COMPLETION_HANDLER completion_handler;
+
+ interrupt_handler = interrupt_info->handlers->interrupt_handler;
+ completion_handler = interrupt_info->handlers->completion_handler;
+
+ SCI_CONTROLLER_HANDLE_T scic_controller_handle;
+
+ scic_controller_handle = scif_controller_get_scic_handle(
+ controller->scif_controller_handle);
+
+ if (interrupt_handler(scic_controller_handle)) {
+ mtx_lock(&controller->lock);
+ completion_handler(scic_controller_handle);
+ mtx_unlock(&controller->lock);
+ }
+}
+
+void
+isci_interrupt_poll_handler(struct ISCI_CONTROLLER *controller)
+{
+ SCI_CONTROLLER_HANDLE_T scic_controller =
+ scif_controller_get_scic_handle(controller->scif_controller_handle);
+ SCIC_CONTROLLER_HANDLER_METHODS_T handlers;
+
+ scic_controller_get_handler_methods(SCIC_NO_INTERRUPTS, 0x0, &handlers);
+
+ if(handlers.interrupt_handler(scic_controller) == TRUE) {
+ /* Do not acquire controller lock in this path. xpt
+ * poll routine will get called with this lock already
+ * held, so we can't acquire it again here. Other users
+ * of this function must acquire the lock explicitly
+ * before calling this handler.
+ */
+ handlers.completion_handler(scic_controller);
+ }
+}
diff --git a/sys/dev/isci/isci_io_request.c b/sys/dev/isci/isci_io_request.c
new file mode 100644
index 0000000..ae6830d
--- /dev/null
+++ b/sys/dev/isci/isci_io_request.c
@@ -0,0 +1,923 @@
+/*-
+ * 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.
+ *
+ * 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 <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <dev/isci/isci.h>
+
+#include <cam/scsi/scsi_all.h>
+#include <cam/scsi/scsi_message.h>
+
+#include <dev/isci/scil/intel_sas.h>
+
+#include <dev/isci/scil/sci_util.h>
+
+#include <dev/isci/scil/scif_io_request.h>
+#include <dev/isci/scil/scif_controller.h>
+#include <dev/isci/scil/scif_remote_device.h>
+#include <dev/isci/scil/scif_user_callback.h>
+
+#include <dev/isci/scil/scic_io_request.h>
+#include <dev/isci/scil/scic_user_callback.h>
+
+/**
+ * @brief This user callback will inform the user that an IO request has
+ * completed.
+ *
+ * @param[in] controller This parameter specifies the controller on
+ * which the IO request is completing.
+ * @param[in] remote_device This parameter specifies the remote device on
+ * which this request is completing.
+ * @param[in] io_request This parameter specifies the IO request that has
+ * completed.
+ * @param[in] completion_status This parameter specifies the results of
+ * the IO request operation. SCI_IO_SUCCESS indicates
+ * successful completion.
+ *
+ * @return none
+ */
+void
+scif_cb_io_request_complete(SCI_CONTROLLER_HANDLE_T scif_controller,
+ SCI_REMOTE_DEVICE_HANDLE_T remote_device,
+ SCI_IO_REQUEST_HANDLE_T io_request, SCI_IO_STATUS completion_status)
+{
+ struct ISCI_IO_REQUEST *isci_request =
+ (struct ISCI_IO_REQUEST *)sci_object_get_association(io_request);
+
+ scif_controller_complete_io(scif_controller, remote_device, io_request);
+ isci_io_request_complete(scif_controller, remote_device, isci_request,
+ completion_status);
+}
+
+void
+isci_io_request_complete(SCI_CONTROLLER_HANDLE_T scif_controller,
+ SCI_REMOTE_DEVICE_HANDLE_T remote_device,
+ struct ISCI_IO_REQUEST *isci_request, SCI_IO_STATUS completion_status)
+{
+ struct ISCI_CONTROLLER *isci_controller;
+ struct ISCI_REMOTE_DEVICE *isci_remote_device;
+ union ccb *ccb;
+
+ isci_controller = (struct ISCI_CONTROLLER *) sci_object_get_association(scif_controller);
+ isci_remote_device =
+ (struct ISCI_REMOTE_DEVICE *) sci_object_get_association(remote_device);
+
+ ccb = isci_request->ccb;
+
+ ccb->ccb_h.status &= ~CAM_STATUS_MASK;
+
+ switch (completion_status) {
+ case SCI_IO_SUCCESS:
+ case SCI_IO_SUCCESS_COMPLETE_BEFORE_START:
+#if __FreeBSD_version >= 900026
+ if (ccb->ccb_h.func_code == XPT_SMP_IO) {
+ void *smp_response =
+ scif_io_request_get_response_iu_address(
+ isci_request->sci_object);
+
+ memcpy(ccb->smpio.smp_response, smp_response,
+ ccb->smpio.smp_response_len);
+ }
+#endif
+ ccb->ccb_h.status |= CAM_REQ_CMP;
+ break;
+
+ case SCI_IO_SUCCESS_IO_DONE_EARLY:
+ ccb->ccb_h.status |= CAM_REQ_CMP;
+ ccb->csio.resid = ccb->csio.dxfer_len -
+ scif_io_request_get_number_of_bytes_transferred(
+ isci_request->sci_object);
+ break;
+
+ case SCI_IO_FAILURE_RESPONSE_VALID:
+ {
+ SCI_SSP_RESPONSE_IU_T * response_buffer;
+ uint32_t sense_length;
+ int error_code, sense_key, asc, ascq;
+ struct ccb_scsiio *csio = &ccb->csio;
+
+ response_buffer = (SCI_SSP_RESPONSE_IU_T *)
+ scif_io_request_get_response_iu_address(
+ isci_request->sci_object);
+
+ sense_length = sci_ssp_get_sense_data_length(
+ response_buffer->sense_data_length);
+
+ sense_length = MIN(csio->sense_len, sense_length);
+
+ memcpy(&csio->sense_data, response_buffer->data, sense_length);
+
+ csio->sense_resid = csio->sense_len - sense_length;
+ csio->scsi_status = response_buffer->status;
+ ccb->ccb_h.status |= CAM_SCSI_STATUS_ERROR;
+ ccb->ccb_h.status |= CAM_AUTOSNS_VALID;
+ scsi_extract_sense( &csio->sense_data, &error_code, &sense_key,
+ &asc, &ascq );
+ isci_log_message(1, "ISCI",
+ "isci: bus=%x target=%x lun=%x cdb[0]=%x status=%x key=%x asc=%x ascq=%x\n",
+ ccb->ccb_h.path_id, ccb->ccb_h.target_id,
+ ccb->ccb_h.target_lun, csio->cdb_io.cdb_bytes[0],
+ csio->scsi_status, sense_key, asc, ascq);
+ break;
+ }
+
+ case SCI_IO_FAILURE_REMOTE_DEVICE_RESET_REQUIRED:
+ isci_remote_device_reset(isci_remote_device, NULL);
+
+ /* drop through */
+ case SCI_IO_FAILURE_TERMINATED:
+ ccb->ccb_h.status |= CAM_REQ_TERMIO;
+ isci_log_message(1, "ISCI",
+ "isci: bus=%x target=%x lun=%x cdb[0]=%x terminated\n",
+ ccb->ccb_h.path_id, ccb->ccb_h.target_id,
+ ccb->ccb_h.target_lun, ccb->csio.cdb_io.cdb_bytes[0]);
+ break;
+
+ case SCI_IO_FAILURE_INVALID_STATE:
+ case SCI_IO_FAILURE_INSUFFICIENT_RESOURCES:
+ ccb->ccb_h.status |= CAM_REQUEUE_REQ;
+ isci_remote_device_freeze_lun_queue(isci_remote_device,
+ ccb->ccb_h.target_lun);
+ break;
+
+ case SCI_IO_FAILURE_INVALID_REMOTE_DEVICE:
+ ccb->ccb_h.status |= CAM_DEV_NOT_THERE;
+ break;
+
+ case SCI_IO_FAILURE_NO_NCQ_TAG_AVAILABLE:
+ {
+ struct ccb_relsim ccb_relsim;
+ struct cam_path *path;
+
+ xpt_create_path(&path, NULL,
+ cam_sim_path(isci_controller->sim),
+ isci_remote_device->index, 0);
+
+ xpt_setup_ccb(&ccb_relsim.ccb_h, path, 5);
+ ccb_relsim.ccb_h.func_code = XPT_REL_SIMQ;
+ ccb_relsim.ccb_h.flags = CAM_DEV_QFREEZE;
+ ccb_relsim.release_flags = RELSIM_ADJUST_OPENINGS;
+ ccb_relsim.openings =
+ scif_remote_device_get_max_queue_depth(remote_device);
+ xpt_action((union ccb *)&ccb_relsim);
+ xpt_free_path(path);
+ ccb->ccb_h.status |= CAM_REQUEUE_REQ;
+ }
+ break;
+
+ case SCI_IO_FAILURE:
+ case SCI_IO_FAILURE_REQUIRES_SCSI_ABORT:
+ case SCI_IO_FAILURE_UNSUPPORTED_PROTOCOL:
+ case SCI_IO_FAILURE_PROTOCOL_VIOLATION:
+ case SCI_IO_FAILURE_INVALID_PARAMETER_VALUE:
+ case SCI_IO_FAILURE_CONTROLLER_SPECIFIC_ERR:
+ default:
+ isci_log_message(1, "ISCI",
+ "isci: bus=%x target=%x lun=%x cdb[0]=%x completion status=%x\n",
+ ccb->ccb_h.path_id, ccb->ccb_h.target_id,
+ ccb->ccb_h.target_lun, ccb->csio.cdb_io.cdb_bytes[0],
+ completion_status);
+ ccb->ccb_h.status |= CAM_REQ_CMP_ERR;
+ break;
+ }
+
+ if (ccb->ccb_h.status != CAM_REQ_CMP) {
+ /* ccb will be completed with some type of non-success
+ * status. So temporarily freeze the queue until the
+ * upper layers can act on the status. The CAM_DEV_QFRZN
+ * flag will then release the queue after the status is
+ * acted upon.
+ */
+ ccb->ccb_h.status |= CAM_DEV_QFRZN;
+ xpt_freeze_devq(ccb->ccb_h.path, 1);
+ }
+
+ callout_stop(&isci_request->parent.timer);
+ bus_dmamap_sync(isci_request->parent.dma_tag,
+ isci_request->parent.dma_map,
+ BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
+
+ bus_dmamap_unload(isci_request->parent.dma_tag,
+ isci_request->parent.dma_map);
+
+ if (isci_remote_device->frozen_lun_mask != 0 &&
+ !(ccb->ccb_h.status & CAM_REQUEUE_REQ))
+ isci_remote_device_release_device_queue(isci_remote_device);
+
+ xpt_done(ccb);
+ isci_request->ccb = NULL;
+
+ if (isci_controller->is_frozen == TRUE) {
+ isci_controller->is_frozen = FALSE;
+ xpt_release_simq(isci_controller->sim, TRUE);
+ }
+
+ sci_pool_put(isci_controller->request_pool,
+ (struct ISCI_REQUEST *)isci_request);
+}
+
+/**
+ * @brief This callback method asks the user to provide the physical
+ * address for the supplied virtual address when building an
+ * io request object.
+ *
+ * @param[in] controller This parameter is the core controller object
+ * handle.
+ * @param[in] io_request This parameter is the io request object handle
+ * for which the physical address is being requested.
+ * @param[in] virtual_address This paramter is the virtual address which
+ * is to be returned as a physical address.
+ * @param[out] physical_address The physical address for the supplied virtual
+ * address.
+ *
+ * @return None.
+ */
+void
+scic_cb_io_request_get_physical_address(SCI_CONTROLLER_HANDLE_T controller,
+ SCI_IO_REQUEST_HANDLE_T io_request, void *virtual_address,
+ SCI_PHYSICAL_ADDRESS *physical_address)
+{
+ SCI_IO_REQUEST_HANDLE_T scif_request =
+ sci_object_get_association(io_request);
+ struct ISCI_REQUEST *isci_request =
+ sci_object_get_association(scif_request);
+
+ if(isci_request != NULL) {
+ /* isci_request is not NULL, meaning this is a request initiated
+ * by CAM or the isci layer (i.e. device reset for I/O
+ * timeout). Therefore we can calculate the physical address
+ * based on the address we stored in the struct ISCI_REQUEST
+ * object.
+ */
+ *physical_address = isci_request->physical_address +
+ (uintptr_t)virtual_address -
+ (uintptr_t)isci_request;
+ } else {
+ /* isci_request is NULL, meaning this is a request generated
+ * internally by SCIL (i.e. for SMP requests or NCQ error
+ * recovery). Therefore we calculate the physical address
+ * based on the controller's uncached controller memory buffer,
+ * since we know that this is what SCIL uses for internal
+ * framework requests.
+ */
+ SCI_CONTROLLER_HANDLE_T scif_controller =
+ (SCI_CONTROLLER_HANDLE_T) sci_object_get_association(controller);
+ struct ISCI_CONTROLLER *isci_controller =
+ (struct ISCI_CONTROLLER *)sci_object_get_association(scif_controller);
+ U64 virt_addr_offset = (uintptr_t)virtual_address -
+ (U64)isci_controller->uncached_controller_memory.virtual_address;
+
+ *physical_address =
+ isci_controller->uncached_controller_memory.physical_address
+ + virt_addr_offset;
+ }
+}
+
+/**
+ * @brief This callback method asks the user to provide the address for
+ * the command descriptor block (CDB) associated with this IO request.
+ *
+ * @param[in] scif_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.
+ *
+ * @return This method returns the virtual address of the CDB.
+ */
+void *
+scif_cb_io_request_get_cdb_address(void * scif_user_io_request)
+{
+ struct ISCI_IO_REQUEST *isci_request =
+ (struct ISCI_IO_REQUEST *)scif_user_io_request;
+
+ return (isci_request->ccb->csio.cdb_io.cdb_bytes);
+}
+
+/**
+ * @brief This callback method asks the user to provide the length of
+ * the command descriptor block (CDB) associated with this IO request.
+ *
+ * @param[in] scif_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.
+ *
+ * @return This method returns the length of the CDB.
+ */
+uint32_t
+scif_cb_io_request_get_cdb_length(void * scif_user_io_request)
+{
+ struct ISCI_IO_REQUEST *isci_request =
+ (struct ISCI_IO_REQUEST *)scif_user_io_request;
+
+ return (isci_request->ccb->csio.cdb_len);
+}
+
+/**
+ * @brief This callback method asks the user to provide the Logical Unit (LUN)
+ * associated with this IO request.
+ *
+ * @note 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.
+ *
+ * @param[in] scif_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.
+ *
+ * @return This method returns the LUN associated with this request.
+ */
+uint32_t
+scif_cb_io_request_get_lun(void * scif_user_io_request)
+{
+ struct ISCI_IO_REQUEST *isci_request =
+ (struct ISCI_IO_REQUEST *)scif_user_io_request;
+
+ return (isci_request->ccb->ccb_h.target_lun);
+}
+
+/**
+ * @brief This callback method asks the user to provide the task attribute
+ * associated with this IO request.
+ *
+ * @note 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.
+ *
+ * @param[in] scif_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.
+ *
+ * @return This method returns the task attribute associated with this
+ * IO request.
+ */
+uint32_t
+scif_cb_io_request_get_task_attribute(void * scif_user_io_request)
+{
+ struct ISCI_IO_REQUEST *isci_request =
+ (struct ISCI_IO_REQUEST *)scif_user_io_request;
+ uint32_t task_attribute;
+
+ if((isci_request->ccb->ccb_h.flags & CAM_TAG_ACTION_VALID) != 0)
+ switch(isci_request->ccb->csio.tag_action) {
+ case MSG_HEAD_OF_Q_TAG:
+ task_attribute = SCI_SAS_HEAD_OF_QUEUE_ATTRIBUTE;
+ break;
+
+ case MSG_ORDERED_Q_TAG:
+ task_attribute = SCI_SAS_ORDERED_ATTRIBUTE;
+ break;
+
+ case MSG_ACA_TASK:
+ task_attribute = SCI_SAS_ACA_ATTRIBUTE;
+ break;
+
+ default:
+ task_attribute = SCI_SAS_SIMPLE_ATTRIBUTE;
+ break;
+ }
+ else
+ task_attribute = SCI_SAS_SIMPLE_ATTRIBUTE;
+
+ return (task_attribute);
+}
+
+/**
+ * @brief This callback method asks the user to provide the command priority
+ * associated with this IO request.
+ *
+ * @note 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.
+ *
+ * @param[in] scif_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.
+ *
+ * @return This method returns the command priority associated with this
+ * IO request.
+ */
+uint32_t
+scif_cb_io_request_get_command_priority(void * scif_user_io_request)
+{
+ return (0);
+}
+
+/**
+ * @brief This method simply returns the virtual address associated
+ * with the scsi_io and byte_offset supplied parameters.
+ *
+ * @note This callback is not utilized in the fast path. The expectation
+ * is that this method is utilized for items such as SCSI to ATA
+ * translation for commands like INQUIRY, READ CAPACITY, etc.
+ *
+ * @param[in] scif_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.
+ * @param[in] byte_offset This parameter specifies the offset into the data
+ * buffers pointed to by the SGL. The byte offset starts at 0
+ * and continues until the last byte pointed to be the last SGL
+ * element.
+ *
+ * @return A virtual address pointer to the location specified by the
+ * parameters.
+ */
+uint8_t *
+scif_cb_io_request_get_virtual_address_from_sgl(void * scif_user_io_request,
+ uint32_t byte_offset)
+{
+ struct ISCI_IO_REQUEST *isci_request =
+ (struct ISCI_IO_REQUEST *)scif_user_io_request;
+
+ return (isci_request->ccb->csio.data_ptr + byte_offset);
+}
+
+/**
+ * @brief This callback method asks the user to provide the number of
+ * bytes to be transfered as part of this request.
+ *
+ * @param[in] scif_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.
+ *
+ * @return This method returns the number of payload data bytes to be
+ * transfered for this IO request.
+ */
+uint32_t
+scif_cb_io_request_get_transfer_length(void * scif_user_io_request)
+{
+ struct ISCI_IO_REQUEST *isci_request =
+ (struct ISCI_IO_REQUEST *)scif_user_io_request;
+
+ return (isci_request->ccb->csio.dxfer_len);
+
+}
+
+/**
+ * @brief This callback method asks the user to provide the data direction
+ * for this request.
+ *
+ * @param[in] scif_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.
+ *
+ * @return This method returns the value of SCI_IO_REQUEST_DATA_OUT,
+ * SCI_IO_REQUEST_DATA_IN, or SCI_IO_REQUEST_NO_DATA.
+ */
+SCI_IO_REQUEST_DATA_DIRECTION
+scif_cb_io_request_get_data_direction(void * scif_user_io_request)
+{
+ struct ISCI_IO_REQUEST *isci_request =
+ (struct ISCI_IO_REQUEST *)scif_user_io_request;
+
+ switch (isci_request->ccb->ccb_h.flags & CAM_DIR_MASK) {
+ case CAM_DIR_IN:
+ return (SCI_IO_REQUEST_DATA_IN);
+ case CAM_DIR_OUT:
+ return (SCI_IO_REQUEST_DATA_OUT);
+ default:
+ return (SCI_IO_REQUEST_NO_DATA);
+ }
+}
+
+/**
+ * @brief 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.
+ *
+ * @param[in] scif_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.
+ * @param[in] current_sge_address This parameter specifies the address for
+ * the current SGE (i.e. the one that has just processed).
+ * @param[out] next_sge An address specifying the location for the next scatter
+ * gather element to be processed.
+ *
+ * @return None.
+ */
+void
+scif_cb_io_request_get_next_sge(void * scif_user_io_request,
+ void * current_sge_address, void ** next_sge)
+{
+ struct ISCI_IO_REQUEST *isci_request =
+ (struct ISCI_IO_REQUEST *)scif_user_io_request;
+
+ if (isci_request->current_sge_index == isci_request->num_segments)
+ *next_sge = NULL;
+ else {
+ bus_dma_segment_t *sge =
+ &isci_request->sge[isci_request->current_sge_index];
+
+ isci_request->current_sge_index++;
+ *next_sge = sge;
+ }
+}
+
+/**
+ * @brief This callback method asks the user to provide the contents of the
+ * "address" field in the Scatter-Gather Element.
+ *
+ * @param[in] scif_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.
+ * @param[in] sge_address This parameter specifies the address for the
+ * SGE from which to retrieve the address field.
+ *
+ * @return A physical address specifying the contents of the SGE's address
+ * field.
+ */
+SCI_PHYSICAL_ADDRESS
+scif_cb_sge_get_address_field(void *scif_user_io_request, void *sge_address)
+{
+ bus_dma_segment_t *sge = (bus_dma_segment_t *)sge_address;
+
+ return ((SCI_PHYSICAL_ADDRESS)sge->ds_addr);
+}
+
+/**
+ * @brief This callback method asks the user to provide the contents of the
+ * "length" field in the Scatter-Gather Element.
+ *
+ * @param[in] scif_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.
+ * @param[in] sge_address This parameter specifies the address for the
+ * SGE from which to retrieve the address field.
+ *
+ * @return This method returns the length field specified inside the SGE
+ * referenced by the sge_address parameter.
+ */
+uint32_t
+scif_cb_sge_get_length_field(void *scif_user_io_request, void *sge_address)
+{
+ bus_dma_segment_t *sge = (bus_dma_segment_t *)sge_address;
+
+ return ((uint32_t)sge->ds_len);
+}
+
+void
+isci_request_construct(struct ISCI_REQUEST *request,
+ SCI_CONTROLLER_HANDLE_T scif_controller_handle,
+ bus_dma_tag_t io_buffer_dma_tag, bus_addr_t physical_address)
+{
+
+ request->controller_handle = scif_controller_handle;
+ request->dma_tag = io_buffer_dma_tag;
+ request->physical_address = physical_address;
+ bus_dmamap_create(request->dma_tag, 0, &request->dma_map);
+ callout_init(&request->timer, CALLOUT_MPSAFE);
+}
+
+static void
+isci_io_request_construct(void *arg, bus_dma_segment_t *seg, int nseg,
+ int error)
+{
+ union ccb *ccb;
+ struct ISCI_IO_REQUEST *io_request = (struct ISCI_IO_REQUEST *)arg;
+ SCI_REMOTE_DEVICE_HANDLE_T *device = io_request->parent.remote_device_handle;
+ SCI_STATUS status;
+
+ io_request->num_segments = nseg;
+ io_request->sge = seg;
+ ccb = io_request->ccb;
+
+ /* XXX More cleanup is needed here */
+ if ((nseg == 0) || (error != 0)) {
+ ccb->ccb_h.status = CAM_REQ_INVALID;
+ xpt_done(ccb);
+ return;
+ }
+
+ io_request->status = scif_io_request_construct(
+ io_request->parent.controller_handle,
+ io_request->parent.remote_device_handle,
+ SCI_CONTROLLER_INVALID_IO_TAG, (void *)io_request,
+ (void *)((char*)io_request + sizeof(struct ISCI_IO_REQUEST)),
+ &io_request->sci_object);
+
+ if (io_request->status != SCI_SUCCESS) {
+ isci_io_request_complete(io_request->parent.controller_handle,
+ device, io_request, io_request->status);
+ return;
+ }
+
+ sci_object_set_association(io_request->sci_object, io_request);
+
+ bus_dmamap_sync(io_request->parent.dma_tag, io_request->parent.dma_map,
+ BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
+
+ status = (SCI_STATUS)scif_controller_start_io(
+ io_request->parent.controller_handle, device,
+ io_request->sci_object, SCI_CONTROLLER_INVALID_IO_TAG);
+
+ if (status != SCI_SUCCESS) {
+ isci_io_request_complete(io_request->parent.controller_handle,
+ device, io_request, status);
+ return;
+ }
+
+ if (ccb->ccb_h.timeout != CAM_TIME_INFINITY)
+ callout_reset(&io_request->parent.timer, ccb->ccb_h.timeout,
+ isci_io_request_timeout, io_request);
+}
+
+void
+isci_io_request_execute_scsi_io(union ccb *ccb,
+ struct ISCI_CONTROLLER *controller)
+{
+ struct ccb_scsiio *csio = &ccb->csio;
+ target_id_t target_id = ccb->ccb_h.target_id;
+ struct ISCI_REQUEST *request;
+ struct ISCI_IO_REQUEST *io_request;
+ struct ISCI_REMOTE_DEVICE *device =
+ controller->remote_device[target_id];
+ int error;
+
+ if (device == NULL) {
+ ccb->ccb_h.status &= ~CAM_SIM_QUEUED;
+ ccb->ccb_h.status &= ~CAM_STATUS_MASK;
+ ccb->ccb_h.status |= CAM_DEV_NOT_THERE;
+ xpt_done(ccb);
+ return;
+ }
+
+ if (sci_pool_empty(controller->request_pool)) {
+ ccb->ccb_h.status &= ~CAM_SIM_QUEUED;
+ ccb->ccb_h.status &= ~CAM_STATUS_MASK;
+ ccb->ccb_h.status |= CAM_REQUEUE_REQ;
+ xpt_freeze_simq(controller->sim, 1);
+ controller->is_frozen = TRUE;
+ xpt_done(ccb);
+ return;
+ }
+
+ ASSERT(device->is_resetting == FALSE);
+
+ sci_pool_get(controller->request_pool, request);
+ io_request = (struct ISCI_IO_REQUEST *)request;
+
+ io_request->ccb = ccb;
+ io_request->current_sge_index = 0;
+ io_request->parent.remote_device_handle = device->sci_object;
+
+ if ((ccb->ccb_h.flags & CAM_SCATTER_VALID) != 0)
+ panic("Unexpected CAM_SCATTER_VALID flag! flags = 0x%x\n",
+ ccb->ccb_h.flags);
+
+ if ((ccb->ccb_h.flags & CAM_DATA_PHYS) != 0)
+ panic("Unexpected CAM_DATA_PHYS flag! flags = 0x%x\n",
+ ccb->ccb_h.flags);
+
+ error = bus_dmamap_load(io_request->parent.dma_tag,
+ io_request->parent.dma_map, csio->data_ptr, csio->dxfer_len,
+ isci_io_request_construct, io_request, 0x0);
+
+ /* A resource shortage from BUSDMA will be automatically
+ * continued at a later point, pushing the CCB processing
+ * forward, which will in turn unfreeze the simq.
+ */
+ if (error == EINPROGRESS) {
+ xpt_freeze_simq(controller->sim, 1);
+ ccb->ccb_h.flags |= CAM_RELEASE_SIMQ;
+ }
+}
+
+void
+isci_io_request_timeout(void *arg)
+{
+ struct ISCI_IO_REQUEST *request = (struct ISCI_IO_REQUEST *)arg;
+ struct ISCI_REMOTE_DEVICE *remote_device = (struct ISCI_REMOTE_DEVICE *)
+ sci_object_get_association(request->parent.remote_device_handle);
+ struct ISCI_CONTROLLER *controller = remote_device->domain->controller;
+
+ mtx_lock(&controller->lock);
+ isci_remote_device_reset(remote_device, NULL);
+ mtx_unlock(&controller->lock);
+}
+
+#if __FreeBSD_version >= 900026
+/**
+ * @brief This callback method gets the size of and pointer to the buffer
+ * (if any) containing the request buffer for an SMP request.
+ *
+ * @param[in] core_request This parameter specifies the SCI core's request
+ * object associated with the SMP request.
+ * @param[out] smp_request_buffer This parameter returns a pointer to the
+ * payload portion of the SMP request - i.e. everything after
+ * the SMP request header.
+ *
+ * @return Size of the request buffer in bytes. This does *not* include
+ * the size of the SMP request header.
+ */
+static uint32_t
+smp_io_request_cb_get_request_buffer(SCI_IO_REQUEST_HANDLE_T core_request,
+ uint8_t ** smp_request_buffer)
+{
+ struct ISCI_IO_REQUEST *isci_request = (struct ISCI_IO_REQUEST *)
+ sci_object_get_association(sci_object_get_association(core_request));
+
+ *smp_request_buffer = isci_request->ccb->smpio.smp_request +
+ sizeof(SMP_REQUEST_HEADER_T);
+
+ return (isci_request->ccb->smpio.smp_request_len -
+ sizeof(SMP_REQUEST_HEADER_T));
+}
+
+/**
+ * @brief This callback method gets the SMP function for an SMP request.
+ *
+ * @param[in] core_request This parameter specifies the SCI core's request
+ * object associated with the SMP request.
+ *
+ * @return SMP function for the SMP request.
+ */
+static uint8_t
+smp_io_request_cb_get_function(SCI_IO_REQUEST_HANDLE_T core_request)
+{
+ struct ISCI_IO_REQUEST *isci_request = (struct ISCI_IO_REQUEST *)
+ sci_object_get_association(sci_object_get_association(core_request));
+ SMP_REQUEST_HEADER_T *header =
+ (SMP_REQUEST_HEADER_T *)isci_request->ccb->smpio.smp_request;
+
+ return (header->function);
+}
+
+/**
+ * @brief This callback method gets the SMP frame type for an SMP request.
+ *
+ * @param[in] core_request This parameter specifies the SCI core's request
+ * object associated with the SMP request.
+ *
+ * @return SMP frame type for the SMP request.
+ */
+static uint8_t
+smp_io_request_cb_get_frame_type(SCI_IO_REQUEST_HANDLE_T core_request)
+{
+ struct ISCI_IO_REQUEST *isci_request = (struct ISCI_IO_REQUEST *)
+ sci_object_get_association(sci_object_get_association(core_request));
+ SMP_REQUEST_HEADER_T *header =
+ (SMP_REQUEST_HEADER_T *)isci_request->ccb->smpio.smp_request;
+
+ return (header->smp_frame_type);
+}
+
+/**
+ * @brief This callback method gets the allocated response length for an SMP request.
+ *
+ * @param[in] core_request This parameter specifies the SCI core's request
+ * object associated with the SMP request.
+ *
+ * @return Allocated response length for the SMP request.
+ */
+static uint8_t
+smp_io_request_cb_get_allocated_response_length(
+ SCI_IO_REQUEST_HANDLE_T core_request)
+{
+ struct ISCI_IO_REQUEST *isci_request = (struct ISCI_IO_REQUEST *)
+ sci_object_get_association(sci_object_get_association(core_request));
+ SMP_REQUEST_HEADER_T *header =
+ (SMP_REQUEST_HEADER_T *)isci_request->ccb->smpio.smp_request;
+
+ return (header->allocated_response_length);
+}
+
+static SCI_STATUS
+isci_smp_request_construct(struct ISCI_IO_REQUEST *request)
+{
+ SCI_STATUS status;
+ SCIC_SMP_PASSTHRU_REQUEST_CALLBACKS_T callbacks;
+
+ status = scif_request_construct(request->parent.controller_handle,
+ request->parent.remote_device_handle, SCI_CONTROLLER_INVALID_IO_TAG,
+ (void *)request,
+ (void *)((char*)request + sizeof(struct ISCI_IO_REQUEST)),
+ &request->sci_object);
+
+ if (status == SCI_SUCCESS) {
+ callbacks.scic_cb_smp_passthru_get_request =
+ &smp_io_request_cb_get_request_buffer;
+ callbacks.scic_cb_smp_passthru_get_function =
+ &smp_io_request_cb_get_function;
+ callbacks.scic_cb_smp_passthru_get_frame_type =
+ &smp_io_request_cb_get_frame_type;
+ callbacks.scic_cb_smp_passthru_get_allocated_response_length =
+ &smp_io_request_cb_get_allocated_response_length;
+
+ /* create the smp passthrough part of the io request */
+ status = scic_io_request_construct_smp_pass_through(
+ scif_io_request_get_scic_handle(request->sci_object),
+ &callbacks);
+ }
+
+ return (status);
+}
+
+void
+isci_io_request_execute_smp_io(union ccb *ccb,
+ struct ISCI_CONTROLLER *controller)
+{
+ SCI_STATUS status;
+ target_id_t target_id = ccb->ccb_h.target_id;
+ struct ISCI_REQUEST *request;
+ struct ISCI_IO_REQUEST *io_request;
+ SCI_REMOTE_DEVICE_HANDLE_T smp_device_handle;
+ struct ISCI_REMOTE_DEVICE *end_device = controller->remote_device[target_id];
+
+ /* SMP commands are sent to an end device, because SMP devices are not
+ * exposed to the kernel. It is our responsibility to use this method
+ * to get the SMP device that contains the specified end device. If
+ * the device is direct-attached, the handle will come back NULL, and
+ * we'll just fail the SMP_IO with DEV_NOT_THERE.
+ */
+ scif_remote_device_get_containing_device(end_device->sci_object,
+ &smp_device_handle);
+
+ if (smp_device_handle == NULL) {
+ ccb->ccb_h.status &= ~CAM_SIM_QUEUED;
+ ccb->ccb_h.status &= ~CAM_STATUS_MASK;
+ ccb->ccb_h.status |= CAM_DEV_NOT_THERE;
+ xpt_done(ccb);
+ return;
+ }
+
+ if (sci_pool_empty(controller->request_pool)) {
+ ccb->ccb_h.status &= ~CAM_SIM_QUEUED;
+ ccb->ccb_h.status &= ~CAM_STATUS_MASK;
+ ccb->ccb_h.status |= CAM_REQUEUE_REQ;
+ xpt_freeze_simq(controller->sim, 1);
+ controller->is_frozen = TRUE;
+ xpt_done(ccb);
+ return;
+ }
+
+ ASSERT(device->is_resetting == FALSE);
+
+ sci_pool_get(controller->request_pool, request);
+ io_request = (struct ISCI_IO_REQUEST *)request;
+
+ io_request->ccb = ccb;
+ io_request->parent.remote_device_handle = smp_device_handle;
+
+ status = isci_smp_request_construct(io_request);
+
+ if (status != SCI_SUCCESS) {
+ isci_io_request_complete(controller->scif_controller_handle,
+ smp_device_handle, io_request, status);
+ return;
+ }
+
+ sci_object_set_association(io_request->sci_object, io_request);
+
+ status = (SCI_STATUS) scif_controller_start_io(
+ controller->scif_controller_handle, smp_device_handle,
+ io_request->sci_object, SCI_CONTROLLER_INVALID_IO_TAG);
+
+ if (status != SCI_SUCCESS) {
+ isci_io_request_complete(controller->scif_controller_handle,
+ smp_device_handle, io_request, status);
+ return;
+ }
+
+ if (ccb->ccb_h.timeout != CAM_TIME_INFINITY)
+ callout_reset(&io_request->parent.timer, ccb->ccb_h.timeout,
+ isci_io_request_timeout, request);
+}
+#endif
diff --git a/sys/dev/isci/isci_logger.c b/sys/dev/isci/isci_logger.c
new file mode 100644
index 0000000..97df043
--- /dev/null
+++ b/sys/dev/isci/isci_logger.c
@@ -0,0 +1,351 @@
+/*-
+ * 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.
+ *
+ * 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 <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <dev/isci/isci.h>
+
+#include <dev/isci/scil/scif_user_callback.h>
+#include <dev/isci/scil/scic_user_callback.h>
+#include <dev/isci/scil/sci_logger.h>
+
+#include <machine/stdarg.h>
+#include <sys/time.h>
+
+#define ERROR_LEVEL 0
+#define WARNING_LEVEL 1
+#define TRACE_LEVEL 2
+#define INFO_LEVEL 3
+
+void
+isci_log_message(uint32_t verbosity, char *log_message_prefix,
+ char *log_message, ...)
+{
+ va_list argp;
+ char buffer[512];
+ struct timeval tv;
+
+ if (verbosity > g_isci_debug_level)
+ return;
+
+ va_start (argp, log_message);
+ vsnprintf(buffer, sizeof(buffer)-1, log_message, argp);
+ va_end(argp);
+ microtime(&tv);
+
+ printf("isci: %d:%06d %s %s", (int)tv.tv_sec, (int)tv.tv_usec,
+ log_message_prefix, buffer);
+}
+
+
+#ifdef SCI_LOGGING
+#define SCI_ENABLE_LOGGING_ERROR 1
+#define SCI_ENABLE_LOGGING_WARNING 1
+#define SCI_ENABLE_LOGGING_INFO 1
+#define SCI_ENABLE_LOGGING_TRACE 1
+#define SCI_ENABLE_LOGGING_STATES 1
+
+#define ISCI_LOG_MESSAGE( \
+ logger_object, \
+ log_object_mask, \
+ log_message, \
+ verbosity, \
+ log_message_prefix \
+) \
+{ \
+ va_list argp; \
+ char buffer[512]; \
+ \
+ if (!sci_logger_is_enabled(logger_object, log_object_mask, verbosity)) \
+ return; \
+ \
+ va_start (argp, log_message); \
+ vsnprintf(buffer, sizeof(buffer)-1, log_message, argp); \
+ va_end(argp); \
+ \
+ /* prepend the "object:verbosity_level:" */ \
+ isci_log_message(verbosity, log_message_prefix, buffer); \
+}
+#endif /* SCI_LOGGING */
+
+
+#ifdef SCI_ENABLE_LOGGING_ERROR
+/**
+ * @brief In this method the user is expected to log the supplied
+ * error information. The user must be capable of handling variable
+ * length argument lists and should consider prepending the fact
+ * that this is an error from the framework.
+ *
+ * @param[in] logger_object This parameter specifies the logger object
+ * associated with this message.
+ * @param[in] log_object_mask This parameter specifies the log objects
+ * for which this message is being generated.
+ * @param[in] log_message This parameter specifies the message to be logged.
+ *
+ * @return none
+ */
+void scif_cb_logger_log_error(SCI_LOGGER_HANDLE_T logger_object,
+ uint32_t log_object_mask, char *log_message, ...)
+{
+
+ ISCI_LOG_MESSAGE(logger_object, log_object_mask, log_message,
+ SCI_LOG_VERBOSITY_ERROR, "FRAMEWORK: ERROR: ");
+}
+#endif
+
+#ifdef SCI_ENABLE_LOGGING_WARNING
+/**
+ * @brief In this method the user is expected to log the supplied warning
+ * information. The user must be capable of handling variable
+ * length argument lists and should consider prepending the fact
+ * that this is a warning from the framework.
+ *
+ * @param[in] logger_object This parameter specifies the logger object
+ * associated with this message.
+ * @param[in] log_object_mask This parameter specifies the log objects
+ * for which this message is being generated.
+ * @param[in] log_message This parameter specifies the message to be logged.
+ *
+ * @return none
+ */
+void
+scif_cb_logger_log_warning(SCI_LOGGER_HANDLE_T logger_object,
+ uint32_t log_object_mask, char *log_message, ...)
+{
+
+ ISCI_LOG_MESSAGE(logger_object, log_object_mask, log_message,
+ SCI_LOG_VERBOSITY_WARNING, "FRAMEWORK: WARNING: ");
+}
+#endif
+
+#ifdef SCI_ENABLE_LOGGING_INFO
+/**
+ * @brief In this method the user is expected to log the supplied debug
+ * information. The user must be capable of handling variable
+ * length argument lists and should consider prepending the fact
+ * that this is a debug message from the framework.
+ *
+ * @param[in] logger_object This parameter specifies the logger object
+ * associated with this message.
+ * @param[in] log_object_mask This parameter specifies the log objects
+ * for which this message is being generated.
+ * @param[in] log_message This parameter specifies the message to be logged.
+ *
+ * @return none
+ */
+void
+scif_cb_logger_log_info(SCI_LOGGER_HANDLE_T logger_object,
+ uint32_t log_object_mask, char *log_message, ...)
+{
+
+ ISCI_LOG_MESSAGE(logger_object, log_object_mask, log_message,
+ SCI_LOG_VERBOSITY_INFO, "FRAMEWORK: INFO: ");
+}
+#endif
+
+#ifdef SCI_ENABLE_LOGGING_TRACE
+/**
+ * @brief In this method the user is expected to log the supplied function
+ * trace information. The user must be capable of handling variable
+ * length argument lists and should consider prepending the fact
+ * that this is a function trace (i.e. entry/exit) message from the
+ * framework.
+ *
+ * @param[in] logger_object This parameter specifies the logger object
+ * associated with this message.
+ * @param[in] log_object_mask This parameter specifies the log objects
+ * for which this message is being generated.
+ * @param[in] log_message This parameter specifies the message to be logged.
+ *
+ * @return none
+ */
+void
+scif_cb_logger_log_trace(SCI_LOGGER_HANDLE_T logger_object,
+ uint32_t log_object_mask, char *log_message, ...)
+{
+
+ ISCI_LOG_MESSAGE(logger_object, log_object_mask, log_message,
+ SCI_LOG_VERBOSITY_TRACE, "FRAMEWORK: TRACE: ");
+}
+#endif
+
+#ifdef SCI_ENABLE_LOGGING_STATES
+/**
+ * @brief In this method the user is expected to log the supplied function
+ * state transition information. The user must be capable of handling
+ * variable length argument lists and should consider prepending the
+ * fact that this is a function trace (i.e. entry/exit) message from
+ * the framework.
+ *
+ * @param[in] logger_object This parameter specifies the logger object
+ * associated with this message.
+ * @param[in] log_object_mask This parameter specifies the log objects
+ * for which this message is being generated.
+ * @param[in] log_message This parameter specifies the message to be logged.
+ *
+ * @return none
+ */
+void
+scif_cb_logger_log_states(SCI_LOGGER_HANDLE_T logger_object,
+ uint32_t log_object_mask, char *log_message, ...)
+{
+
+ ISCI_LOG_MESSAGE(logger_object, log_object_mask, log_message,
+ SCI_LOG_VERBOSITY_STATES, "FRAMEWORK: STATE TRANSITION: ");
+}
+#endif
+
+#ifdef SCI_ENABLE_LOGGING_ERROR
+/**
+ * @brief In this method the user is expected to log the supplied
+ * error information. The user must be capable of handling variable
+ * length argument lists and should consider prepending the fact
+ * that this is an error from the core.
+ *
+ * @param[in] logger_object This parameter specifies the logger object
+ * associated with this message.
+ * @param[in] log_object_mask This parameter specifies the log objects
+ * for which this message is being generated.
+ * @param[in] log_message This parameter specifies the message to be logged.
+ *
+ * @return none
+ */
+void
+scic_cb_logger_log_error(SCI_LOGGER_HANDLE_T logger_object,
+ uint32_t log_object_mask, char *log_message, ...)
+{
+
+ ISCI_LOG_MESSAGE(logger_object, log_object_mask, log_message,
+ SCI_LOG_VERBOSITY_ERROR, "CORE: ERROR: ");
+}
+#endif
+
+#ifdef SCI_ENABLE_LOGGING_WARNING
+/**
+ * @brief In this method the user is expected to log the supplied warning
+ * information. The user must be capable of handling variable
+ * length argument lists and should consider prepending the fact
+ * that this is a warning from the core.
+ *
+ * @param[in] logger_object This parameter specifies the logger object
+ * associated with this message.
+ * @param[in] log_object_mask This parameter specifies the log objects
+ * for which this message is being generated.
+ * @param[in] log_message This parameter specifies the message to be logged.
+ *
+ * @return none
+ */
+void
+scic_cb_logger_log_warning(SCI_LOGGER_HANDLE_T logger_object,
+ uint32_t log_object_mask, char *log_message, ...)
+{
+
+ ISCI_LOG_MESSAGE(logger_object, log_object_mask, log_message,
+ SCI_LOG_VERBOSITY_WARNING, "CORE: WARNING: ");
+}
+#endif
+
+#ifdef SCI_ENABLE_LOGGING_INFO
+/**
+ * @brief In this method the user is expected to log the supplied debug
+ * information. The user must be capable of handling variable
+ * length argument lists and should consider prepending the fact
+ * that this is a debug message from the core.
+ *
+ * @param[in] logger_object This parameter specifies the logger object
+ * associated with this message.
+ * @param[in] log_object_mask This parameter specifies the log objects
+ * for which this message is being generated.
+ * @param[in] log_message This parameter specifies the message to be logged.
+ *
+ * @return none
+ */
+void
+scic_cb_logger_log_info(SCI_LOGGER_HANDLE_T logger_object,
+ uint32_t log_object_mask, char *log_message, ...)
+{
+
+ ISCI_LOG_MESSAGE(logger_object, log_object_mask, log_message,
+ SCI_LOG_VERBOSITY_INFO, "CORE: INFO: ");
+}
+#endif
+
+#ifdef SCI_ENABLE_LOGGING_TRACE
+/**
+ * @brief In this method the user is expected to log the supplied function
+ * trace information. The user must be capable of handling variable
+ * length argument lists and should consider prepending the fact
+ * that this is a function trace (i.e. entry/exit) message from the
+ * core.
+ *
+ * @param[in] logger_object This parameter specifies the logger object
+ * associated with this message.
+ * @param[in] log_object_mask This parameter specifies the log objects
+ * for which this message is being generated.
+ * @param[in] log_message This parameter specifies the message to be logged.
+ *
+ * @return none
+ */
+void
+scic_cb_logger_log_trace(SCI_LOGGER_HANDLE_T logger_object,
+ uint32_t log_object_mask, char *log_message, ...)
+{
+
+ ISCI_LOG_MESSAGE(logger_object, log_object_mask, log_message,
+ SCI_LOG_VERBOSITY_TRACE, "CORE: TRACE: ");
+}
+#endif
+
+#ifdef SCI_ENABLE_LOGGING_STATES
+/**
+ * @brief In this method the user is expected to log the supplied function
+ * state transition information. The user must be capable of handling
+ * variable length argument lists and should consider prepending the
+ * fact that this is a function trace (i.e. entry/exit) message from
+ * the core.
+ *
+ * @param[in] logger_object This parameter specifies the logger object
+ * associated with this message.
+ * @param[in] log_object_mask This parameter specifies the log objects
+ * for which this message is being generated.
+ * @param[in] log_message This parameter specifies the message to be logged.
+ *
+ * @return none
+ */
+void
+scic_cb_logger_log_states(SCI_LOGGER_HANDLE_T logger_object,
+ uint32_t log_object_mask, char *log_message, ...)
+{
+
+ ISCI_LOG_MESSAGE(logger_object, log_object_mask, log_message,
+ SCI_LOG_VERBOSITY_STATES, "CORE: STATE TRANSITION: ");
+}
+#endif
diff --git a/sys/dev/isci/isci_oem_parameters.c b/sys/dev/isci/isci_oem_parameters.c
new file mode 100644
index 0000000..d17698f
--- /dev/null
+++ b/sys/dev/isci/isci_oem_parameters.c
@@ -0,0 +1,176 @@
+/*-
+ * 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.
+ *
+ * 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 <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <dev/isci/isci.h>
+#include <vm/vm.h>
+#include <vm/pmap.h>
+#include <machine/pmap.h>
+#include <machine/vmparam.h>
+#include <machine/pc/bios.h>
+#include <dev/isci/scil/scu_bios_definitions.h>
+
+struct pcir_header
+{
+ uint32_t signature;
+ uint16_t vendor_id;
+ uint16_t device_id;
+ uint16_t reserved;
+ uint16_t struct_length;
+ uint8_t struct_revision;
+ uint8_t cc_interface;
+ uint8_t cc_subclass;
+ uint8_t cc_baseclass;
+ uint16_t image_length;
+ uint16_t code_revision;
+ uint8_t code_type;
+ uint8_t indicator;
+ uint16_t reserved1;
+};
+
+struct rom_header
+{
+ uint8_t signature_byte[2];
+ uint8_t rom_length;
+ uint8_t jmp_code;
+ uint16_t entry_address;
+ uint8_t reserved[0x12];
+ uint16_t pcir_pointer;
+ uint16_t pnp_pointer;
+};
+
+struct oem_parameters_table
+{
+ uint8_t signature[4]; /* "$OEM" */
+ struct revision
+ {
+ uint16_t major:8; /* bits [7:0] */
+ uint16_t minor:8; /* bits [8:15] */
+ } revision;
+
+ uint16_t length;
+ uint8_t checksum;
+ uint8_t reserved1;
+ uint16_t reserved2;
+ uint8_t data[1];
+};
+
+void
+isci_get_oem_parameters(struct isci_softc *isci)
+{
+ uint32_t OROM_PHYSICAL_ADDRESS_START = 0xC0000;
+ uint32_t OROM_SEARCH_LENGTH = 0x30000;
+ uint16_t OROM_SIGNATURE = 0xAA55;
+ uint32_t OROM_SIZE = 512;
+ uint8_t *orom_start =
+ (uint8_t *)BIOS_PADDRTOVADDR(OROM_PHYSICAL_ADDRESS_START);
+ uint32_t offset = 0;
+
+ while (offset < OROM_SEARCH_LENGTH) {
+
+ /* Look for the OROM signature at the beginning of every
+ * 512-byte block in the OROM region
+ */
+ if (*(uint16_t*)(orom_start + offset) == OROM_SIGNATURE) {
+ uint32_t *rom;
+ struct rom_header *rom_header;
+ struct pcir_header *pcir_header;
+ uint16_t vendor_id = isci->pci_common_header.vendor_id;
+ uint16_t device_id = isci->pci_common_header.device_id;
+
+ rom = (uint32_t *)(orom_start + offset);
+ rom_header = (struct rom_header *)rom;
+ pcir_header = (struct pcir_header *)
+ ((uint8_t*)rom + rom_header->pcir_pointer);
+
+ /* OROM signature was found. Now check if the PCI
+ * device and vendor IDs match.
+ */
+ if (pcir_header->vendor_id == vendor_id &&
+ pcir_header->device_id == device_id)
+ {
+ /* OROM for this PCI device was found. Search
+ * this 512-byte block for the $OEM string,
+ * which will mark the beginning of the OEM
+ * parameter block.
+ */
+ uint8_t oem_sig[4] = {'$', 'O', 'E', 'M'};
+ int dword_index;
+
+ for (dword_index = 0;
+ dword_index < OROM_SIZE/sizeof(uint32_t);
+ dword_index++)
+ if (rom[dword_index] == *(uint32_t *)oem_sig) {
+ /* $OEM signature string was found. Now copy the OEM parameter block
+ * into the struct ISCI_CONTROLLER objects. After the controllers are
+ * constructed, we will pass this OEM parameter data to the SCI core
+ * controller.
+ */
+ struct oem_parameters_table *oem =
+ (struct oem_parameters_table *)&rom[dword_index];
+ SCI_BIOS_OEM_PARAM_BLOCK_T *oem_data =
+ (SCI_BIOS_OEM_PARAM_BLOCK_T *)oem->data;
+ int index;
+
+ isci->oem_parameters_found = TRUE;
+ isci_log_message(1, "ISCI", "oem_data->header.num_elements = %d\n",
+ oem_data->header.num_elements);
+
+ for (index = 0; index < oem_data->header.num_elements; index++)
+ {
+ memcpy(&isci->controllers[index].oem_parameters.sds1,
+ &oem_data->controller_element[index],
+ sizeof(SCIC_SDS_OEM_PARAMETERS_T));
+
+ isci_log_message(1, "ISCI", "OEM Parameter Data for controller %d\n",
+ index);
+
+ for (int i = 0; i < sizeof(SCIC_SDS_OEM_PARAMETERS_T); i++) {
+ uint8_t val = ((uint8_t *)&oem_data->controller_element[index])[i];
+ isci_log_message(1, "ISCI", "%02x ", val);
+ }
+ isci_log_message(1, "ISCI", "\n");
+ isci->controllers[index].oem_parameters_version = oem_data->header.version;
+ }
+ }
+
+ /* No need to continue searching for another
+ * OROM that matches this PCI device, so return
+ * immediately.
+ */
+ return;
+ }
+ }
+
+ offset += OROM_SIZE;
+ }
+}
diff --git a/sys/dev/isci/isci_remote_device.c b/sys/dev/isci/isci_remote_device.c
new file mode 100644
index 0000000..c751058
--- /dev/null
+++ b/sys/dev/isci/isci_remote_device.c
@@ -0,0 +1,298 @@
+/*-
+ * 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.
+ *
+ * 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 <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <dev/isci/isci.h>
+
+#include <cam/cam_periph.h>
+#include <cam/cam_xpt_periph.h>
+
+#include <dev/isci/scil/scif_task_request.h>
+#include <dev/isci/scil/scif_controller.h>
+#include <dev/isci/scil/scif_domain.h>
+#include <dev/isci/scil/scif_user_callback.h>
+
+#include <dev/isci/scil/scic_port.h>
+#include <dev/isci/scil/scic_phy.h>
+
+/**
+ * @brief This callback method informs the framework user that the remote
+ * device is ready and capable of processing IO requests.
+ *
+ * @param[in] controller This parameter specifies the controller object
+ * with which this callback is associated.
+ * @param[in] domain This parameter specifies the domain object with
+ * which this callback is associated.
+ * @param[in] remote_device This parameter specifies the device object with
+ * which this callback is associated.
+ *
+ * @return none
+ */
+void
+scif_cb_remote_device_ready(SCI_CONTROLLER_HANDLE_T controller,
+ SCI_DOMAIN_HANDLE_T domain, SCI_REMOTE_DEVICE_HANDLE_T remote_device)
+{
+ struct ISCI_REMOTE_DEVICE *isci_remote_device =
+ sci_object_get_association(remote_device);
+ struct ISCI_CONTROLLER *isci_controller =
+ sci_object_get_association(controller);
+ uint32_t device_index = isci_remote_device->index;
+
+ if (isci_controller->remote_device[device_index] == NULL) {
+ /* This new device is now ready, so put it in the controller's
+ * remote device list so it is visible to CAM.
+ */
+ isci_controller->remote_device[device_index] =
+ isci_remote_device;
+
+ if (isci_controller->sim != NULL) {
+ /* The sim object is not NULL, meaning we have attached
+ * the controller to CAM already. In that case, create
+ * a CCB to instruct CAM to rescan this device.
+ * If the sim object is NULL, this device will get
+ * scanned as part of the initial scan when the
+ * controller is attached to CAM.
+ */
+ union ccb *ccb = xpt_alloc_ccb_nowait();
+
+ xpt_create_path(&ccb->ccb_h.path, xpt_periph,
+ cam_sim_path(isci_controller->sim),
+ isci_remote_device->index, CAM_LUN_WILDCARD);
+
+ xpt_rescan(ccb);
+ }
+ }
+
+ isci_remote_device_release_device_queue(isci_remote_device);
+}
+
+/**
+ * @brief This callback method informs the framework user that the remote
+ * device is not ready. Thus, it is incapable of processing IO
+ * requests.
+ *
+ * @param[in] controller This parameter specifies the controller object
+ * with which this callback is associated.
+ * @param[in] domain This parameter specifies the domain object with
+ * which this callback is associated.
+ * @param[in] remote_device This parameter specifies the device object with
+ * which this callback is associated.
+ *
+ * @return none
+ */
+void
+scif_cb_remote_device_not_ready(SCI_CONTROLLER_HANDLE_T controller,
+ SCI_DOMAIN_HANDLE_T domain, SCI_REMOTE_DEVICE_HANDLE_T remote_device)
+{
+
+}
+
+/**
+ * @brief This callback method informs the framework user that the remote
+ * device failed. This typically occurs shortly after the device
+ * has been discovered, during the configuration phase for the device.
+ *
+ * @param[in] controller This parameter specifies the controller object
+ * with which this callback is associated.
+ * @param[in] domain This parameter specifies the domain object with
+ * which this callback is associated.
+ * @param[in] remote_device This parameter specifies the device object with
+ * which this callback is associated.
+ * @param[in] status This parameter specifies the specific failure condition
+ * associated with this device failure.
+ *
+ * @return none
+ */
+void
+scif_cb_remote_device_failed(SCI_CONTROLLER_HANDLE_T controller,
+ SCI_DOMAIN_HANDLE_T domain, SCI_REMOTE_DEVICE_HANDLE_T remote_device,
+ SCI_STATUS status)
+{
+
+}
+
+void
+isci_remote_device_reset(struct ISCI_REMOTE_DEVICE *remote_device,
+ union ccb *ccb)
+{
+ struct ISCI_CONTROLLER *controller = remote_device->domain->controller;
+ struct ISCI_REQUEST *request;
+ struct ISCI_TASK_REQUEST *task_request;
+ SCI_STATUS status;
+
+ if (remote_device->is_resetting == TRUE) {
+ /* device is already being reset, so return immediately */
+ return;
+ }
+
+ if (sci_pool_empty(controller->request_pool)) {
+ /* No requests are available in our request pool. If this reset is tied
+ * to a CCB, ask CAM to requeue it. Otherwise, we need to put it on our
+ * pending device reset list, so that the reset will occur when a request
+ * frees up.
+ */
+ if (ccb == NULL)
+ sci_fast_list_insert_tail(
+ &controller->pending_device_reset_list,
+ &remote_device->pending_device_reset_element);
+ else {
+ ccb->ccb_h.status &= ~CAM_STATUS_MASK;
+ ccb->ccb_h.status |= CAM_REQUEUE_REQ;
+ xpt_done(ccb);
+ }
+ return;
+ }
+
+ isci_log_message(0, "ISCI",
+ "Sending reset to device on controller %d domain %d CAM index %d\n",
+ controller->index, remote_device->domain->index,
+ remote_device->index
+ );
+
+ sci_pool_get(controller->request_pool, request);
+ task_request = (struct ISCI_TASK_REQUEST *)request;
+
+ task_request->parent.remote_device_handle = remote_device->sci_object;
+ task_request->ccb = ccb;
+
+ remote_device->is_resetting = TRUE;
+
+ status = (SCI_STATUS) scif_task_request_construct(
+ controller->scif_controller_handle, remote_device->sci_object,
+ SCI_CONTROLLER_INVALID_IO_TAG, (void *)task_request,
+ (void *)((char*)task_request + sizeof(struct ISCI_TASK_REQUEST)),
+ &task_request->sci_object);
+
+ if (status != SCI_SUCCESS) {
+ isci_task_request_complete(controller->scif_controller_handle,
+ remote_device->sci_object, task_request->sci_object,
+ status);
+ return;
+ }
+
+ status = (SCI_STATUS)scif_controller_start_task(
+ controller->scif_controller_handle, remote_device->sci_object,
+ task_request->sci_object, SCI_CONTROLLER_INVALID_IO_TAG);
+
+ if (status != SCI_SUCCESS) {
+ isci_task_request_complete(
+ controller->scif_controller_handle,
+ remote_device->sci_object, task_request->sci_object,
+ status);
+ return;
+ }
+}
+
+uint32_t
+isci_remote_device_get_bitrate(struct ISCI_REMOTE_DEVICE *remote_device)
+{
+ struct ISCI_DOMAIN *domain = remote_device->domain;
+ struct ISCI_CONTROLLER *controller = domain->controller;
+ SCI_PORT_HANDLE_T port_handle;
+ SCIC_PORT_PROPERTIES_T port_properties;
+ uint8_t phy_index;
+ SCI_PHY_HANDLE_T phy_handle;
+ SCIC_PHY_PROPERTIES_T phy_properties;
+
+ /* get a handle to the port associated with this remote device's
+ * domain
+ */
+ port_handle = scif_domain_get_scic_port_handle(domain->sci_object);
+ scic_port_get_properties(port_handle, &port_properties);
+
+ /* get the lowest numbered phy in the port */
+ phy_index = 0;
+ while ((port_properties.phy_mask != 0) &&
+ !(port_properties.phy_mask & 0x1)) {
+
+ phy_index++;
+ port_properties.phy_mask >>= 1;
+ }
+
+ /* get the properties for the lowest numbered phy */
+ scic_controller_get_phy_handle(
+ scif_controller_get_scic_handle(controller->scif_controller_handle),
+ phy_index, &phy_handle);
+ scic_phy_get_properties(phy_handle, &phy_properties);
+
+ switch (phy_properties.negotiated_link_rate) {
+ case SCI_SAS_150_GB:
+ return (150000);
+ case SCI_SAS_300_GB:
+ return (300000);
+ case SCI_SAS_600_GB:
+ return (600000);
+ default:
+ return (0);
+ }
+}
+
+void
+isci_remote_device_freeze_lun_queue(struct ISCI_REMOTE_DEVICE *remote_device,
+ lun_id_t lun)
+{
+ if (!(remote_device->frozen_lun_mask & (1 << lun))) {
+ struct cam_path *path;
+
+ xpt_create_path(&path, xpt_periph,
+ cam_sim_path(remote_device->domain->controller->sim),
+ remote_device->index, lun);
+ xpt_freeze_devq(path, 1);
+ xpt_free_path(path);
+ remote_device->frozen_lun_mask |= (1 << lun);
+ }
+}
+
+void
+isci_remote_device_release_lun_queue(struct ISCI_REMOTE_DEVICE *remote_device,
+ lun_id_t lun)
+{
+ if (remote_device->frozen_lun_mask & (1 << lun)) {
+ struct cam_path *path;
+
+ xpt_create_path(&path, xpt_periph,
+ cam_sim_path(remote_device->domain->controller->sim),
+ remote_device->index, lun);
+ xpt_release_devq(path, 1, TRUE);
+ xpt_free_path(path);
+ remote_device->frozen_lun_mask &= ~(1 << lun);
+ }
+}
+
+void
+isci_remote_device_release_device_queue(
+ struct ISCI_REMOTE_DEVICE *remote_device)
+{
+ lun_id_t lun;
+ for (lun = 0; lun < ISCI_MAX_LUN; lun++)
+ isci_remote_device_release_lun_queue(remote_device, lun);
+}
diff --git a/sys/dev/isci/isci_sysctl.c b/sys/dev/isci/isci_sysctl.c
new file mode 100644
index 0000000..6a22e38
--- /dev/null
+++ b/sys/dev/isci/isci_sysctl.c
@@ -0,0 +1,229 @@
+/*-
+ * 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.
+ *
+ * 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 <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <dev/isci/isci.h>
+
+#include <sys/sysctl.h>
+
+#include <dev/isci/scil/scif_controller.h>
+#include <dev/isci/scil/scic_phy.h>
+
+static int
+isci_sysctl_coalesce_timeout(SYSCTL_HANDLER_ARGS)
+{
+ struct isci_softc *isci = (struct isci_softc *)arg1;
+ int error = sysctl_handle_int(oidp, &isci->coalesce_timeout, 0, req);
+ int i;
+
+ if (error)
+ return (error);
+
+ for (i = 0; i < isci->controller_count; i++)
+ scif_controller_set_interrupt_coalescence(
+ isci->controllers[i].scif_controller_handle,
+ isci->coalesce_number, isci->coalesce_timeout);
+
+ return (0);
+}
+
+static int
+isci_sysctl_coalesce_number(SYSCTL_HANDLER_ARGS)
+{
+ struct isci_softc *isci = (struct isci_softc *)arg1;
+ int error = sysctl_handle_int(oidp, &isci->coalesce_number, 0, req);
+ int i;
+
+ if (error)
+ return (error);
+
+ for (i = 0; i < isci->controller_count; i++)
+ scif_controller_set_interrupt_coalescence(
+ isci->controllers[i].scif_controller_handle,
+ isci->coalesce_number, isci->coalesce_timeout);
+
+ return (0);
+}
+
+static void
+isci_sysctl_reset_remote_devices(struct ISCI_CONTROLLER *controller,
+ uint32_t remote_devices_to_be_reset)
+{
+ uint32_t i = 0;
+
+ while (remote_devices_to_be_reset != 0) {
+ if (remote_devices_to_be_reset & 0x1) {
+ struct ISCI_REMOTE_DEVICE *remote_device =
+ controller->remote_device[i];
+
+ if (remote_device != NULL) {
+ mtx_lock(&controller->lock);
+ isci_remote_device_reset(remote_device, NULL);
+ mtx_unlock(&controller->lock);
+ }
+ }
+ remote_devices_to_be_reset >>= 1;
+ i++;
+ }
+}
+
+static int
+isci_sysctl_reset_remote_device_on_controller0(SYSCTL_HANDLER_ARGS)
+{
+ struct isci_softc *isci = (struct isci_softc *)arg1;
+ uint32_t remote_devices_to_be_reset = 0;
+ struct ISCI_CONTROLLER *controller = &isci->controllers[0];
+ int error = sysctl_handle_int(oidp, &remote_devices_to_be_reset, 0, req);
+
+ if (error || remote_devices_to_be_reset == 0)
+ return (error);
+
+ isci_sysctl_reset_remote_devices(controller, remote_devices_to_be_reset);
+
+ return (0);
+}
+
+static int
+isci_sysctl_reset_remote_device_on_controller1(SYSCTL_HANDLER_ARGS)
+{
+ struct isci_softc *isci = (struct isci_softc *)arg1;
+ uint32_t remote_devices_to_be_reset = 0;
+ struct ISCI_CONTROLLER *controller = &isci->controllers[1];
+ int error =
+ sysctl_handle_int(oidp, &remote_devices_to_be_reset, 0, req);
+
+ if (error || remote_devices_to_be_reset == 0)
+ return (error);
+
+ isci_sysctl_reset_remote_devices(controller,
+ remote_devices_to_be_reset);
+
+ return (0);
+}
+
+static void
+isci_sysctl_stop(struct ISCI_CONTROLLER *controller, uint32_t phy_to_be_stopped)
+{
+ SCI_PHY_HANDLE_T phy_handle = NULL;
+
+ scic_controller_get_phy_handle(
+ scif_controller_get_scic_handle(controller->scif_controller_handle),
+ phy_to_be_stopped, &phy_handle);
+
+ scic_phy_stop(phy_handle);
+}
+
+static int
+isci_sysctl_stop_phy(SYSCTL_HANDLER_ARGS)
+{
+ struct isci_softc *isci = (struct isci_softc *)arg1;
+ uint32_t phy_to_be_stopped = 0xff;
+ uint32_t controller_index, phy_index;
+ int error = sysctl_handle_int(oidp, &phy_to_be_stopped, 0, req);
+
+ controller_index = phy_to_be_stopped / SCI_MAX_PHYS;
+ phy_index = phy_to_be_stopped % SCI_MAX_PHYS;
+
+ if(error || controller_index >= isci->controller_count)
+ return (error);
+
+ isci_sysctl_stop(&isci->controllers[controller_index], phy_index);
+
+ return (0);
+}
+
+static void
+isci_sysctl_start(struct ISCI_CONTROLLER *controller,
+ uint32_t phy_to_be_started)
+{
+ SCI_PHY_HANDLE_T phy_handle = NULL;
+
+ scic_controller_get_phy_handle(
+ scif_controller_get_scic_handle(controller->scif_controller_handle),
+ phy_to_be_started, &phy_handle);
+
+ scic_phy_start(phy_handle);
+}
+
+static int
+isci_sysctl_start_phy(SYSCTL_HANDLER_ARGS)
+{
+ struct isci_softc *isci = (struct isci_softc *)arg1;
+ uint32_t phy_to_be_started = 0xff;
+ uint32_t controller_index, phy_index;
+ int error = sysctl_handle_int(oidp, &phy_to_be_started, 0, req);
+
+ controller_index = phy_to_be_started / SCI_MAX_PHYS;
+ phy_index = phy_to_be_started % SCI_MAX_PHYS;
+
+ if(error || controller_index >= isci->controller_count)
+ return error;
+
+ isci_sysctl_start(&isci->controllers[controller_index], phy_index);
+
+ return 0;
+}
+
+void isci_sysctl_initialize(struct isci_softc *isci)
+{
+ struct sysctl_ctx_list *sysctl_ctx = device_get_sysctl_ctx(isci->device);
+ struct sysctl_oid *sysctl_tree = device_get_sysctl_tree(isci->device);
+
+ SYSCTL_ADD_PROC(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree), OID_AUTO,
+ "coalesce_timeout", CTLTYPE_UINT | CTLFLAG_RW, isci, 0,
+ isci_sysctl_coalesce_timeout, "IU",
+ "Interrupt coalescing timeout (in microseconds)");
+
+ SYSCTL_ADD_PROC(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree), OID_AUTO,
+ "coalesce_number", CTLTYPE_UINT | CTLFLAG_RW, isci, 0,
+ isci_sysctl_coalesce_number, "IU",
+ "Interrupt coalescing number");
+
+ SYSCTL_ADD_PROC(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree), OID_AUTO,
+ "reset_remote_device_on_controller0", CTLTYPE_UINT| CTLFLAG_RW,
+ isci, 0, isci_sysctl_reset_remote_device_on_controller0, "IU",
+ "Reset remote device on controller 0");
+
+ SYSCTL_ADD_PROC(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree), OID_AUTO,
+ "reset_remote_device_on_controller1", CTLTYPE_UINT| CTLFLAG_RW,
+ isci, 0, isci_sysctl_reset_remote_device_on_controller1, "IU",
+ "Reset remote device on controller 1");
+
+ SYSCTL_ADD_PROC(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree), OID_AUTO,
+ "stop_phy", CTLTYPE_UINT| CTLFLAG_RW, isci, 0, isci_sysctl_stop_phy,
+ "IU", "Stop PHY on a controller");
+
+ SYSCTL_ADD_PROC(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree), OID_AUTO,
+ "start_phy", CTLTYPE_UINT| CTLFLAG_RW, isci, 0,
+ isci_sysctl_start_phy, "IU", "Start PHY on a controller");
+}
+
diff --git a/sys/dev/isci/isci_task_request.c b/sys/dev/isci/isci_task_request.c
new file mode 100644
index 0000000..25995ad
--- /dev/null
+++ b/sys/dev/isci/isci_task_request.c
@@ -0,0 +1,258 @@
+/*-
+ * 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.
+ *
+ * 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 <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <dev/isci/isci.h>
+
+#include <dev/isci/scil/scif_controller.h>
+#include <dev/isci/scil/scif_user_callback.h>
+
+/**
+ * @brief This user callback will inform the user that a task management
+ * request completed.
+ *
+ * @param[in] controller This parameter specifies the controller on
+ * which the task management request is completing.
+ * @param[in] remote_device This parameter specifies the remote device on
+ * which this task management request is completing.
+ * @param[in] task_request This parameter specifies the task management
+ * request that has completed.
+ * @param[in] completion_status This parameter specifies the results of
+ * the IO request operation. SCI_TASK_SUCCESS indicates
+ * successful completion.
+ *
+ * @return none
+ */
+void
+scif_cb_task_request_complete(SCI_CONTROLLER_HANDLE_T controller,
+ SCI_REMOTE_DEVICE_HANDLE_T remote_device,
+ SCI_TASK_REQUEST_HANDLE_T task_request, SCI_TASK_STATUS completion_status)
+{
+
+ scif_controller_complete_task(controller, remote_device, task_request);
+ isci_task_request_complete(controller, remote_device, task_request,
+ completion_status);
+}
+
+/**
+ * @brief This method returns the Logical Unit to be utilized for this
+ * task management request.
+ *
+ * @note 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.
+ *
+ * @param[in] scif_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.
+ *
+ * @return This method returns the LUN associated with this request.
+ * @todo This should be U64?
+ */
+uint32_t
+scif_cb_task_request_get_lun(void * scif_user_task_request)
+{
+
+ /* Currently we are only doing hard resets, not LUN resets. So
+ * always returning 0 is OK here, since LUN doesn't matter for
+ * a hard device reset.
+ */
+ return (0);
+}
+
+/**
+ * @brief This method returns the task management function to be utilized
+ * for this task request.
+ *
+ * @note 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.
+ *
+ * @param[in] scif_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.
+ *
+ * @return This method returns an unsigned byte representing the task
+ * management function to be performed.
+ */
+uint8_t scif_cb_task_request_get_function(void * scif_user_task_request)
+{
+ /* SCIL supports many types of task management functions, but this
+ * driver only uses HARD_RESET.
+ */
+ return (SCI_SAS_HARD_RESET);
+}
+
+/**
+ * @brief 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.
+ *
+ * @param[in] scif_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.
+ *
+ * @return This method returns an unsigned 16-bit word depicting the IO
+ * tag to be managed.
+ */
+uint16_t
+scif_cb_task_request_get_io_tag_to_manage(void * scif_user_task_request)
+{
+
+ return (0);
+}
+
+/**
+ * @brief This callback method asks the user to provide the virtual
+ * address of the response data buffer for the supplied IO request.
+ *
+ * @param[in] scif_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.
+ *
+ * @return This method returns the virtual address for the response data buffer
+ * associated with this IO request.
+ */
+void *
+scif_cb_task_request_get_response_data_address(void * scif_user_task_request)
+{
+ struct ISCI_TASK_REQUEST *task_request =
+ (struct ISCI_TASK_REQUEST *)scif_user_task_request;
+
+ return (&task_request->sense_data);
+}
+
+/**
+ * @brief This callback method asks the user to provide the length of the
+ * response data buffer for the supplied IO request.
+ *
+ * @param[in] scif_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.
+ *
+ * @return This method returns the length of the response buffer data
+ * associated with this IO request.
+ */
+uint32_t
+scif_cb_task_request_get_response_data_length(void * scif_user_task_request)
+{
+
+ return (sizeof(struct scsi_sense_data));
+}
+
+void
+isci_task_request_complete(SCI_CONTROLLER_HANDLE_T scif_controller,
+ SCI_REMOTE_DEVICE_HANDLE_T remote_device,
+ SCI_TASK_REQUEST_HANDLE_T task_request, SCI_TASK_STATUS completion_status)
+{
+ struct ISCI_TASK_REQUEST *isci_task_request =
+ (struct ISCI_TASK_REQUEST *)sci_object_get_association(task_request);
+ struct ISCI_CONTROLLER *isci_controller =
+ (struct ISCI_CONTROLLER *)sci_object_get_association(scif_controller);
+ struct ISCI_REMOTE_DEVICE *isci_remote_device =
+ (struct ISCI_REMOTE_DEVICE *)sci_object_get_association(remote_device);
+ struct ISCI_REMOTE_DEVICE *pending_remote_device;
+ BOOL retry_task = FALSE;
+ union ccb *ccb = isci_task_request->ccb;
+
+ isci_remote_device->is_resetting = FALSE;
+
+ switch (completion_status) {
+ case SCI_TASK_SUCCESS:
+ case SCI_TASK_FAILURE_RESPONSE_VALID:
+ break;
+
+ case SCI_TASK_FAILURE_INVALID_STATE:
+ case SCI_TASK_FAILURE_INSUFFICIENT_RESOURCES:
+ case SCI_FAILURE_TIMEOUT:
+ retry_task = TRUE;
+ isci_log_message(0, "ISCI",
+ "unhandled task completion code 0x%x\n", completion_status);
+ break;
+
+ case SCI_TASK_FAILURE:
+ case SCI_TASK_FAILURE_UNSUPPORTED_PROTOCOL:
+ case SCI_TASK_FAILURE_INVALID_TAG:
+ case SCI_TASK_FAILURE_CONTROLLER_SPECIFIC_ERR:
+ case SCI_TASK_FAILURE_TERMINATED:
+ case SCI_TASK_FAILURE_INVALID_PARAMETER_VALUE:
+ isci_log_message(0, "ISCI",
+ "unhandled task completion code 0x%x\n", completion_status);
+ break;
+
+ default:
+ isci_log_message(0, "ISCI",
+ "unhandled task completion code 0x%x\n", completion_status);
+ break;
+ }
+
+ if (isci_controller->is_frozen == TRUE) {
+ isci_controller->is_frozen = FALSE;
+ xpt_release_simq(isci_controller->sim, TRUE);
+ }
+
+ sci_pool_put(isci_controller->request_pool,
+ (struct ISCI_REQUEST *)isci_task_request);
+
+ /* Make sure we release the device queue, since it may have been frozen
+ * if someone tried to start an I/O while the task was in progress.
+ */
+ isci_remote_device_release_device_queue(isci_remote_device);
+
+ if (retry_task == TRUE)
+ isci_remote_device_reset(isci_remote_device, ccb);
+ else {
+ pending_remote_device = sci_fast_list_remove_head(
+ &isci_controller->pending_device_reset_list);
+
+ if (pending_remote_device != NULL) {
+ /* Any resets that were triggered from an XPT_RESET_DEV
+ * CCB are never put in the pending list if the request
+ * pool is empty - they are given back to CAM to be
+ * requeued. So we will alawys pass NULL here,
+ * denoting that there is no CCB associated with the
+ * device reset.
+ */
+ isci_remote_device_reset(pending_remote_device, NULL);
+ } else if (ccb != NULL) {
+ /* There was a CCB associated with this reset, so mark
+ * it complete and return it to CAM.
+ */
+ ccb->ccb_h.status &= ~CAM_STATUS_MASK;
+ ccb->ccb_h.status |= CAM_REQ_CMP;
+ xpt_done(ccb);
+ }
+ }
+}
+
diff --git a/sys/dev/isci/isci_timer.c b/sys/dev/isci/isci_timer.c
new file mode 100644
index 0000000..58ee223
--- /dev/null
+++ b/sys/dev/isci/isci_timer.c
@@ -0,0 +1,166 @@
+/*-
+ * 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.
+ *
+ * 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 <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <dev/isci/isci.h>
+
+#include <dev/isci/scil/scif_user_callback.h>
+
+static void
+isci_timer_timeout(void *arg)
+{
+ struct ISCI_TIMER *timer = (struct ISCI_TIMER *)arg;
+
+ isci_log_message(3, "TIMER", "timeout %p\n", timer);
+
+ /* callout_stop() will *not* keep the timer from running if it is
+ * pending. callout_drain() cannot be called from interrupt context,
+ * because it may cause thread to sleep which is not allowed in
+ * interrupt context. So instead, check the is_started flag to see if
+ * the timer routine should actually be run or not.
+ */
+ if (timer->is_started == TRUE)
+ timer->callback(timer->cookie);
+}
+
+/**
+ * @brief This callback method asks the user to start the supplied timer.
+ *
+ * @warning All timers in the system started by the SCI Framework 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 Framework user's should be able to handle
+ * calls from the SCI Framework to stop a timer that may already
+ * be stopped.
+ *
+ * @param[in] controller This parameter specifies the controller with
+ * which this timer is to associated.
+ * @param[in] timer This parameter specifies the timer to be started.
+ * @param[in] 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.
+ *
+ * @return none
+ */
+void
+scif_cb_timer_start(SCI_CONTROLLER_HANDLE_T controller, void *timer,
+ uint32_t milliseconds)
+{
+ struct ISCI_TIMER *isci_timer = (struct ISCI_TIMER *)timer;
+
+ isci_timer->is_started = TRUE;
+ isci_log_message(3, "TIMER", "start %p %d\n", timer, milliseconds);
+ callout_reset(&isci_timer->callout, (milliseconds * hz)/1000,
+ isci_timer_timeout, timer);
+}
+
+/**
+ * @brief This callback method asks the user to stop the supplied timer.
+ *
+ * @param[in] controller This parameter specifies the controller with
+ * which this timer is to associated.
+ * @param[in] timer This parameter specifies the timer to be stopped.
+ *
+ * @return none
+ */
+void
+scif_cb_timer_stop(SCI_CONTROLLER_HANDLE_T controller, void *timer)
+{
+ struct ISCI_TIMER *isci_timer = (struct ISCI_TIMER *)timer;
+
+ isci_log_message(3, "TIMER", "stop %p\n", timer);
+ isci_timer->is_started = FALSE;
+ callout_stop(&isci_timer->callout);
+}
+
+/**
+ * @brief This callback method asks the user to create a timer and provide
+ * a handle for this timer for use in further timer interactions.
+ *
+ * @warning 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()).
+ *
+ * @param[in] timer_callback This parameter specifies the callback method
+ * to be invoked whenever the timer expires.
+ * @param[in] controller This parameter specifies the controller with
+ * which this timer is to be associated.
+ * @param[in] 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.
+ *
+ * @return 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 *
+scif_cb_timer_create(SCI_CONTROLLER_HANDLE_T scif_controller,
+ SCI_TIMER_CALLBACK_T timer_callback, void *cookie)
+{
+ struct ISCI_CONTROLLER *isci_controller = (struct ISCI_CONTROLLER *)
+ sci_object_get_association(scif_controller);
+ struct ISCI_TIMER *timer;
+
+ sci_pool_get(isci_controller->timer_pool, timer);
+
+ callout_init_mtx(&timer->callout, &isci_controller->lock, FALSE);
+
+ timer->callback = timer_callback;
+ timer->cookie = cookie;
+ timer->is_started = FALSE;
+
+ isci_log_message(3, "TIMER", "create %p %p %p\n", timer, timer_callback, cookie);
+
+ return (timer);
+}
+
+/**
+ * @brief This callback method asks the user to destory the supplied timer.
+ *
+ * @param[in] controller This parameter specifies the controller with
+ * which this timer is to associated.
+ * @param[in] timer This parameter specifies the timer to be destroyed.
+ *
+ * @return none
+ */
+void
+scif_cb_timer_destroy(SCI_CONTROLLER_HANDLE_T scif_controller,
+ void *timer_handle)
+{
+ struct ISCI_CONTROLLER *isci_controller = (struct ISCI_CONTROLLER *)
+ sci_object_get_association(scif_controller);
+
+ scif_cb_timer_stop(scif_controller, timer_handle);
+ sci_pool_put(isci_controller->timer_pool, (struct ISCI_TIMER *)timer_handle);
+
+ isci_log_message(3, "TIMER", "destroy %p\n", timer_handle);
+}
diff --git a/sys/dev/isci/sci_environment.h b/sys/dev/isci/sci_environment.h
new file mode 100644
index 0000000..bae1ee5
--- /dev/null
+++ b/sys/dev/isci/sci_environment.h
@@ -0,0 +1 @@
+/* empty file for now. compiler needs it */
diff --git a/sys/dev/isci/scil/intel_ata.h b/sys/dev/isci/scil/intel_ata.h
new file mode 100644
index 0000000..9e1cbb7
--- /dev/null
+++ b/sys/dev/isci/scil/intel_ata.h
@@ -0,0 +1,654 @@
+/*-
+ * 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 - 2010 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.
+ *
+ * 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.
+ *
+ * $FreeBSD$
+ */
+/**
+ * @file
+ * @brief 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 <dev/isci/types.h>
+
+/**
+ * @name 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
+#define ATA_SECURITY_UNLOCK 0xF2
+#define ATA_SECURITY_FREEZE_LOCK 0xF5
+#define ATA_DATA_SET_MANAGEMENT 0x06
+#define ATA_DOWNLOAD_MICROCODE 0x92
+#define ATA_WRITE_STREAM_DMA_EXT 0x3A
+#define ATA_READ_LOG_DMA_EXT 0x47
+#define ATA_READ_STREAM_DMA_EXT 0x2A
+#define ATA_WRITE_DMA_FUA 0x3D
+#define ATA_WRITE_LOG_DMA_EXT 0x57
+#define ATA_READ_DMA_QUEUED 0xC7
+#define ATA_READ_DMA_QUEUED_EXT 0x26
+#define ATA_WRITE_DMA_QUEUED 0xCC
+#define ATA_WRITE_DMA_QUEUED_EXT 0x36
+#define ATA_WRITE_DMA_QUEUED_FUA_EXT 0x3E
+#define ATA_READ_MULTIPLE 0xC4
+#define ATA_READ_MULTIPLE_EXT 0x29
+#define ATA_WRITE_MULTIPLE 0xC5
+#define ATA_WRITE_MULTIPLE_EXT 0x39
+#define ATA_WRITE_MULTIPLE_FUA_EXT 0xCE
+
+
+/*@}*/
+
+/**
+ * @name 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
+/*@}*/
+
+/**
+ * @name 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
+/*@}*/
+
+/**
+ * @name 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
+/*@}*/
+
+/**
+ * @name 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
+/*@}*/
+
+/**
+ * @name 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
+/*@}*/
+
+/**
+ * @name 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
+/*@}*/
+
+/**
+ * @name 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
+/*@}*/
+
+/**
+ * @name 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
+/*@}*/
+
+/**
+ * @name 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
+/*@}*/
+
+/**
+ * @name 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
+#define ATA_IDENTIFY_COMMAND_SET_DSM_TRIM_SUPPORTED 0x0001
+#define ATA_IDENTIFY_COMMAND_ADDL_SUPPORTED_DETERMINISTIC_READ 0x4000
+#define ATA_IDENTIFY_COMMAND_ADDL_SUPPORTED_READ_ZERO 0x0020
+/*@}*/
+
+/**
+ * @name 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
+/*@}*/
+
+/**
+ * @name 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
+/*@}*/
+
+/**
+ * @name 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
+/*@}*/
+
+/**
+ * @name 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
+/*@}*/
+
+
+
+/**
+ * @name ATA_SECURITY_STATUS field values
+ *
+ * These constants define the mask of the securityStatus field and the various bits within it
+ */
+/*@{*/
+#define ATA_SECURITY_STATUS_SUPPORTED 0x0001
+#define ATA_SECURITY_STATUS_ENABLED 0x0002
+#define ATA_SECURITY_STATUS_LOCKED 0x0004
+#define ATA_SECURITY_STATUS_FROZEN 0x0008
+#define ATA_SECURITY_STATUS_EXPIRED 0x0010
+#define ATA_SECURITY_STATUS_ERASESUPPORTED 0x0020
+#define ATA_SECURITY_STATUS_RESERVED 0xFEC0
+#define ATA_SECURITY_STATUS_SECURITYLEVEL 0x0100
+/*@}*/
+
+/**
+ * @struct ATA_IDENTIFY_DEVICE
+ *
+ * @brief This structure depicts the ATA IDENTIFY DEVICE data format.
+ */
+typedef 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 additional_supported; // word 69
+ U16 reserved1; // word 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 max_lba_range_entry_blocks; // 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 data_set_management; // word 169
+ U16 reserved_for_compact_flash3[6]; // words 170-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[16]; // words 218-233
+ U16 min_num_blocks_per_microcode; // word 234
+ U16 max_num_blocks_per_microcode; // word 235
+ U16 reserved9[19]; // words 236-254
+ U16 integrity_word; // word 255
+
+} ATA_IDENTIFY_DEVICE_DATA_T;
+
+#define ATA_IDENTIFY_DEVICE_GET_OFFSET(field_name) \
+ ((POINTER_UINT)&(((ATA_IDENTIFY_DEVICE_DATA_T*)0)->field_name))
+#define ATA_IDENTIFY_DEVICE_WCE_ENABLE 0x20
+#define ATA_IDENTIFY_DEVICE_RA_ENABLE 0x40
+
+/**
+ * @struct ATAPI_IDENTIFY_PACKET_DATA
+ *
+ * @brief The following structure depicts the ATA-ATAPI 7 version of the
+ * IDENTIFY PACKET DEVICE data structure.
+ */
+typedef 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
+} ATAPI_IDENTIFY_PACKET_DEVICE_T;
+
+/**
+* @struct ATA_EXTENDED_SMART_SELF_TEST_LOG
+*
+* @brief The following structure depicts the ATA-8 version of the
+* Extended SMART self test log page descriptor entry.
+*/
+typedef 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];
+
+} ATA_DESCRIPTOR_ENTRY_T;
+
+/**
+* @struct ATA_EXTENDED_SMART_SELF_TEST_LOG
+*
+* @brief The following structure depicts the ATA-8 version of the
+* SMART self test log page descriptor entry.
+*/
+typedef 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];
+
+} ATA_SMART_DESCRIPTOR_ENTRY_T;
+
+/**
+* @struct ATA_EXTENDED_SMART_SELF_TEST_LOG
+*
+* @brief The following structure depicts the ATA-8 version of the
+* Extended SMART self test log page.
+*/
+typedef 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
+
+ ATA_DESCRIPTOR_ENTRY_T 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
+
+} ATA_EXTENDED_SMART_SELF_TEST_LOG_T;
+
+/**
+* @struct ATA_EXTENDED_SMART_SELF_TEST_LOG
+*
+* @brief The following structure depicts the ATA-8 version of the
+* SMART self test log page.
+*/
+typedef struct ATA_SMART_SELF_TEST_LOG
+{
+ U8 self_test_log_data_structure_revision_number[2]; //bytes 0-1
+
+ ATA_SMART_DESCRIPTOR_ENTRY_T 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
+
+} ATA_SMART_SELF_TEST_LOG_T;
+
+/**
+* @struct ATA_NCQ_COMMAND_ERROR_LOG
+*
+* @brief The following structure depicts the ATA-8 version of the
+* NCQ command error log page.
+*/
+typedef struct ATA_NCQ_COMMAND_ERROR_LOG
+{
+ U8 ncq_tag : 5;
+ U8 reserved1 : 2;
+ U8 nq : 1;
+ U8 reserved2;
+ U8 status;
+ U8 error;
+ U8 lba_7_0;
+ U8 lba_15_8;
+ U8 lba_23_16;
+ U8 device;
+ U8 lba_31_24;
+ U8 lba_39_32;
+ U8 lba_47_40;
+ U8 reserved3;
+ U8 count_7_0;
+ U8 count_15_8;
+ U8 reserved4[242];
+ U8 vendor_specific[255];
+ U8 checksum;
+} ATA_NCQ_COMMAND_ERROR_LOG_T;
+
+#endif // _ATA_H_
+
diff --git a/sys/dev/isci/scil/intel_pci.h b/sys/dev/isci/scil/intel_pci.h
new file mode 100644
index 0000000..08f6d1d
--- /dev/null
+++ b/sys/dev/isci/scil/intel_pci.h
@@ -0,0 +1,90 @@
+/*-
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2008 - 2010 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.
+ *
+ * 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.
+ *
+ * $FreeBSD$
+ */
+#ifndef _INTEL_PCI_H_
+#define _INTEL_PCI_H_
+
+/**
+ * @file
+ *
+ * @brief This file contains all of the definitions relating to structures,
+ * constants, etc. defined by the PCI specification.
+ */
+
+#include <dev/isci/types.h>
+
+typedef struct sci_pci_common_header
+{
+ // Offset 0x00
+ U16 vendor_id;
+ U16 device_id;
+
+ // Offset 0x04
+ U16 command;
+ U16 status;
+
+ // Offset 0x08
+ U8 revision;
+ U8 program_interface;
+ U8 sub_class;
+ U8 base_class;
+
+ // Offset 0x0C
+ U8 cache_line_size;
+ U8 master_latency_timer;
+ U8 header_type;
+ U8 built_in_self_test;
+
+} SCI_PCI_COMMON_HEADER_T;
+
+#endif // _INTEL_PCI_H_
diff --git a/sys/dev/isci/scil/intel_sas.h b/sys/dev/isci/scil/intel_sas.h
new file mode 100644
index 0000000..18fa8d3
--- /dev/null
+++ b/sys/dev/isci/scil/intel_sas.h
@@ -0,0 +1,977 @@
+/*-
+ * 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 - 2010 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.
+ *
+ * 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.
+ *
+ * $FreeBSD$
+ */
+#ifndef _INTEL_SAS_H_
+#define _INTEL_SAS_H_
+
+/**
+ * @file
+ *
+ * @brief This file contains all of the definitions relating to structures,
+ * constants, etc. defined by the SAS specification.
+ */
+
+#include <dev/isci/types.h>
+#include <dev/isci/scil/intel_sata.h>
+#include <dev/isci/scil/intel_scsi.h>
+
+/**
+ * @struct SCI_SAS_ADDRESS
+ * @brief This structure depicts how a SAS address is represented by SCI.
+ */
+typedef 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;
+
+} SCI_SAS_ADDRESS_T;
+
+/**
+ * @struct SCI_SAS_IDENTIFY_ADDRESS_FRAME_PROTOCOLS
+ * @brief This structure depicts the contents of bytes 2 and 3 in the
+ * SAS IDENTIFY ADDRESS FRAME (IAF).
+ * @note For specific information on each of these
+ * individual fields please reference the SAS specification
+ * Link layer section on address frames.
+ */
+typedef 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;
+
+} SCI_SAS_IDENTIFY_ADDRESS_FRAME_PROTOCOLS_T;
+
+/**
+ * @struct SCI_SAS_IDENTIFY_ADDRESS_FRAME
+ * @brief This structure depicts the contents of the SAS IDENTIFY ADDRESS
+ * FRAME (IAF).
+ * @note For specific information on each of these
+ * individual fields please reference the SAS specification
+ * Link layer section on address frames.
+ */
+typedef struct SCI_SAS_IDENTIFY_ADDRESS_FRAME
+{
+ U16 address_frame_type : 4;
+ U16 device_type : 3;
+ U16 reserved1 : 1;
+ U16 reason : 4;
+ U16 reserved2 : 4;
+
+ SCI_SAS_IDENTIFY_ADDRESS_FRAME_PROTOCOLS_T protocols;
+
+ SCI_SAS_ADDRESS_T device_name;
+ SCI_SAS_ADDRESS_T 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];
+
+} SCI_SAS_IDENTIFY_ADDRESS_FRAME_T;
+
+/**
+ * @struct SAS_CAPABILITIES
+ * @brief 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.
+ */
+typedef 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;
+
+} SAS_CAPABILITIES_T;
+
+/**
+ * @enum _SCI_SAS_LINK_RATE
+ * @brief This enumeration depicts the SAS specification defined link speeds.
+ */
+typedef 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
+} SCI_SAS_LINK_RATE;
+
+/**
+ * @enum _SCI_SAS_TASK_ATTRIBUTE
+ * @brief This enumeration depicts the SAM/SAS specification defined task
+ * attribute values for a command information unit.
+ */
+typedef 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,
+} SCI_SAS_TASK_ATTRIBUTE;
+
+/**
+ * @enum _SCI_SAS_TASK_MGMT_FUNCTION
+ * @brief This enumeration depicts the SAM/SAS specification defined task
+ * management functions.
+ * @note This HARD_RESET function listed here is not actually defined
+ * as a task management function in the industry standard.
+ */
+typedef 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
+} SCI_SAS_TASK_MGMT_FUNCTION_T;
+
+
+/**
+ * @enum _SCI_SAS_FRAME_TYPE
+ * @brief This enumeration depicts the SAS specification defined SSP frame
+ * types.
+ */
+typedef 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
+} SCI_SAS_FRAME_TYPE_T;
+
+
+/**
+ * @struct SCI_SSP_COMMAND_IU
+ * @brief 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.
+ */
+typedef struct SCI_SSP_COMMAND_IU
+{
+
+ U32 lun[2];
+
+ 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];
+
+} SCI_SSP_COMMAND_IU_T;
+
+/**
+ * @struct SCI_SSP_TASK_IU
+ * @brief 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.
+ */
+typedef 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];
+
+} SCI_SSP_TASK_IU_T;
+
+#define SSP_RESPONSE_IU_MAX_DATA 64
+
+#define SCI_SSP_RESPONSE_IU_DATA_PRESENT_MASK (0x03)
+
+/**
+ * @struct SCI_SSP_RESPONSE_IU
+ * @brief 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.
+ */
+typedef 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];
+
+} SCI_SSP_RESPONSE_IU_T;
+
+/**
+ * @enum _SCI_SAS_DATA_PRESENT_TYPE
+ * @brief This enumeration depicts the SAS specification defined SSP data present
+ * types in SCI_SSP_RESPONSE_IU.
+ */
+typedef 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
+} SCI_SSP_RESPONSE_IU_DATA_PRESENT_TYPE_T;
+
+/**
+ * @struct SCI_SSP_FRAME_HEADER
+ *
+ * @brief 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.
+ */
+typedef 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;
+
+} SCI_SSP_FRAME_HEADER_T;
+
+/**
+ * @struct SMP_REQUEST_HEADER
+ * @brief This structure defines the contents of an SMP Request header.
+ * @note For specific information on each of these
+ * individual fields please reference the SAS specification.
+ */
+typedef 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
+} SMP_REQUEST_HEADER_T;
+
+/**
+ * @struct SMP_RESPONSE_HEADER
+ * @brief 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.
+ */
+typedef struct SMP_RESPONSE_HEADER
+{
+ U8 smp_frame_type; // byte 0
+ U8 function; // byte 1
+ U8 function_result; // byte 2
+ U8 response_length; // byte 3
+} SMP_RESPONSE_HEADER_T;
+
+/**
+ * @struct SMP_REQUEST_GENERAL
+ * @brief This structure defines the contents of an SMP Request that
+ * is comprised of the SMP_REQUEST_HEADER and a CRC.
+ * @note For specific information on each of these
+ * individual fields please reference the SAS specification.
+ */
+typedef struct SMP_REQUEST_GENERAL
+{
+ U32 crc; // bytes 4-7
+
+} SMP_REQUEST_GENERAL_T;
+
+/**
+ * @struct SMP_REQUEST_PHY_IDENTIFIER
+ * @brief This structure defines the contents of an SMP Request that
+ * is comprised of the SMP_REQUEST_HEADER and a phy identifier.
+ * Examples: SMP_REQUEST_DISCOVER, SMP_REQUEST_REPORT_PHY_SATA.
+ * @note For specific information on each of these
+ * individual fields please reference the SAS specification.
+ */
+typedef 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
+
+} SMP_REQUEST_PHY_IDENTIFIER_T;
+
+/**
+ * @struct SMP_REQUEST_CONFIGURE_ROUTE_INFORMATION
+ * @brief This structure defines the contents of an SMP Configure Route
+ * Information request.
+ * @note For specific information on each of these
+ * individual fields please reference the SAS specification.
+ */
+typedef 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
+
+} SMP_REQUEST_CONFIGURE_ROUTE_INFORMATION_T;
+
+/**
+ * @struct SMP_REQUEST_PHY_CONTROL
+ * @brief This structure defines the contents of an SMP Phy Controler
+ * request.
+ * @note For specific information on each of these
+ * individual fields please reference the SAS specification.
+ */
+typedef 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
+
+} SMP_REQUEST_PHY_CONTROL_T;
+
+/**
+ * @struct SMP_REQUEST_VENDOR_SPECIFIC
+ * @brief This structure depicts the vendor specific space for SMP request.
+ */
+ #define SMP_REQUEST_VENDOR_SPECIFIC_MAX_LENGTH 1016
+typedef struct SMP_REQUEST_VENDOR_SPECIFIC
+{
+ U8 request_bytes[SMP_REQUEST_VENDOR_SPECIFIC_MAX_LENGTH];
+}SMP_REQUEST_VENDOR_SPECIFIC_T;
+
+/**
+ * @struct SMP_REQUEST
+ * @brief This structure simply unionizes the existing request
+ * structures into a common request type.
+ */
+typedef struct _SMP_REQUEST
+{
+ SMP_REQUEST_HEADER_T header;
+
+ union
+ { // bytes 4-N
+ SMP_REQUEST_GENERAL_T report_general;
+ SMP_REQUEST_PHY_IDENTIFIER_T discover;
+ SMP_REQUEST_GENERAL_T report_manufacturer_information;
+ SMP_REQUEST_PHY_IDENTIFIER_T report_phy_sata;
+ SMP_REQUEST_PHY_CONTROL_T phy_control;
+ SMP_REQUEST_PHY_IDENTIFIER_T report_phy_error_log;
+ SMP_REQUEST_PHY_IDENTIFIER_T report_route_information;
+ SMP_REQUEST_CONFIGURE_ROUTE_INFORMATION_T configure_route_information;
+ SMP_REQUEST_VENDOR_SPECIFIC_T vendor_specific_request;
+ } request;
+
+} SMP_REQUEST_T;
+
+
+/**
+ * @struct SMP_RESPONSE_REPORT_GENERAL
+ * @brief This structure depicts the SMP Report General for
+ * expander devices. It adheres to the SAS-2.1 specification.
+ * @note For specific information on each of these
+ * individual fields please reference the SAS specification
+ * Application layer section on SMP.
+ */
+typedef 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;
+
+} SMP_RESPONSE_REPORT_GENERAL_T;
+
+typedef struct SMP_RESPONSE_REPORT_GENERAL_LONG
+{
+ SMP_RESPONSE_REPORT_GENERAL_T 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;
+
+ SCI_SAS_ADDRESS_T 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;
+
+} SMP_RESPONSE_REPORT_GENERAL_LONG_T;
+
+/**
+ * @struct SMP_RESPONSE_REPORT_MANUFACTURER_INFORMATION
+ * @brief This structure depicts the SMP report manufacturer
+ * information for expander devices. It adheres to the
+ * SAS-2.1 specification.
+ * @note For specific information on each of these
+ * individual fields please reference the SAS specification
+ * Application layer section on SMP.
+ */
+typedef 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];
+
+} SMP_RESPONSE_REPORT_MANUFACTURER_INFORMATION_T;
+
+#define SMP_RESPONSE_DISCOVER_FORMAT_1_1_SIZE 52
+#define SMP_RESPONSE_DISCOVER_FORMAT_2_SIZE 116
+
+/**
+ * @struct SMP_DISCOVER_RESPONSE_PROTOCOLS
+ * @brief This structure depicts the discover response where the
+ * supported protocols by the remote phy are specified.
+ * @note For specific information on each of these
+ * individual fields please reference the SAS specification
+ * Link layer section on address frames.
+ */
+typedef 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;
+
+} SMP_DISCOVER_RESPONSE_PROTOCOLS_T;
+
+/**
+ * @struct SMP_RESPONSE_DISCOVER_FORMAT
+ * @brief 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.
+ */
+typedef 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;
+
+ SMP_DISCOVER_RESPONSE_PROTOCOLS_T protocols;
+ SCI_SAS_ADDRESS_T sas_address;
+ SCI_SAS_ADDRESS_T 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
+ {
+ SCI_SAS_ADDRESS_T 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;
+
+ SCI_SAS_ADDRESS_T 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;
+
+} SMP_RESPONSE_DISCOVER_T;
+
+/**
+ * @struct SMP_RESPONSE_REPORT_PHY_SATA
+ * @brief 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.
+ */
+typedef 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];
+
+} SMP_RESPONSE_REPORT_PHY_SATA_T;
+
+typedef struct SMP_RESPONSE_VENDOR_SPECIFIC
+{
+ U8 response_bytes[SMP_REQUEST_VENDOR_SPECIFIC_MAX_LENGTH];
+}SMP_RESPONSE_VENDOR_SPECIFIC_T;
+
+typedef union SMP_RESPONSE_BODY
+{
+ SMP_RESPONSE_REPORT_GENERAL_T report_general;
+ SMP_RESPONSE_REPORT_MANUFACTURER_INFORMATION_T report_manufacturer_information;
+ SMP_RESPONSE_DISCOVER_T discover;
+ SMP_RESPONSE_REPORT_PHY_SATA_T report_phy_sata;
+ SMP_RESPONSE_VENDOR_SPECIFIC_T vendor_specific_response;
+} SMP_RESPONSE_BODY_T;
+
+/**
+ * @struct SMP_RESPONSE
+ * @brief This structure simply unionizes the existing response
+ * structures into a common response type.
+ */
+typedef struct _SMP_RESPONSE
+{
+ SMP_RESPONSE_HEADER_T header;
+
+ SMP_RESPONSE_BODY_T response;
+
+} SMP_RESPONSE_T;
+
+// 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/sys/dev/isci/scil/intel_sat.h b/sys/dev/isci/scil/intel_sat.h
new file mode 100644
index 0000000..c85482d
--- /dev/null
+++ b/sys/dev/isci/scil/intel_sat.h
@@ -0,0 +1,94 @@
+/*-
+ * 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 - 2010 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.
+ *
+ * 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.
+ *
+ * $FreeBSD$
+ */
+#ifndef _SAT_H_
+#define _SAT_H_
+
+/**
+ * @file
+ * @brief 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.
+ */
+
+/**
+ * @name 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/sys/dev/isci/scil/intel_sata.h b/sys/dev/isci/scil/intel_sata.h
new file mode 100644
index 0000000..bde7100
--- /dev/null
+++ b/sys/dev/isci/scil/intel_sata.h
@@ -0,0 +1,284 @@
+/*-
+ * 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 - 2010 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.
+ *
+ * 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.
+ *
+ * $FreeBSD$
+ */
+#ifndef _SATA_H_
+#define _SATA_H_
+
+#include <dev/isci/types.h>
+
+/**
+ * @file
+ *
+ * @brief 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.
+ */
+
+/**
+ * @name 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
+ *
+ * @brief 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.
+ */
+typedef 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;
+} SATA_FIS_HEADER_T;
+
+
+/**
+ * @struct SATA_FIS_REG_H2D
+ *
+ * @brief This is the definition for a SATA Host to Device Register FIS.
+ */
+typedef 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
+} SATA_FIS_REG_H2D_T;
+
+/**
+ * @struct SATA_FIS_REG_D2H
+ *
+ * @brief SATA Device To Host FIS
+ */
+typedef 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;
+} SATA_FIS_REG_D2H_T;
+
+/**
+ * Status field bit definitions
+ */
+#define SATA_FIS_STATUS_DEVBITS_MASK (0x77)
+
+/**
+ * @struct SATA_FIS_SET_DEV_BITS
+ *
+ * @brief SATA Set Device Bits FIS
+ */
+typedef 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
+} SATA_FIS_SET_DEV_BITS_T;
+
+/**
+ * @struct SATA_FIS_DMA_ACTIVATE
+ *
+ * @brief SATA DMA Activate FIS
+ */
+typedef struct SATA_FIS_DMA_ACTIVATE
+{
+ U32 fis_type :8; // word 0
+ U32 pm_port :4;
+ U32 reserved0 :24;
+} SATA_FIS_DMA_ACTIVATE_T;
+
+/**
+ * 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
+ *
+ * @brief SATA DMA Setup FIS
+ */
+typedef 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
+} SATA_FIS_DMA_SETUP_T;
+
+/**
+ * @struct SATA_FIS_BIST_ACTIVATE
+ *
+ * @brief SATA BIST Activate FIS
+ */
+typedef 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_FIS_BIST_ACTIVATE_T;
+
+/*
+ * SATA PIO Setup FIS
+ */
+typedef 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;
+} SATA_FIS_PIO_SETUP_T;
+
+/**
+ * @struct SATA_FIS_DATA
+ *
+ * @brief SATA Data FIS
+ */
+typedef struct SATA_FIS_DATA
+{
+ U32 fis_type :8; // word 0
+ U32 pm_port :4;
+ U32 reserved0 :24;
+ U8 data[4]; // word 1
+} SATA_FIS_DATA_T;
+
+#endif // _SATA_H_
diff --git a/sys/dev/isci/scil/intel_scsi.h b/sys/dev/isci/scil/intel_scsi.h
new file mode 100644
index 0000000..658876c
--- /dev/null
+++ b/sys/dev/isci/scil/intel_scsi.h
@@ -0,0 +1,540 @@
+/*-
+ * 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 - 2010 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.
+ *
+ * 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.
+ *
+ * $FreeBSD$
+ */
+/**
+ * @file
+ * @brief 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
+ *
+ * @brief 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.
+ */
+typedef 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,
+
+} SCSI_TASK_MGMT_REQUEST_CODES;
+
+/**
+ * @enum _SCSI_TASK_MGMT_RESPONSE_CODES
+ *
+ * @brief This enumeration contains all of the SCSI task management response
+ * codes.
+ */
+typedef 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
+} SCSI_TASK_MGMT_RESPONSE_CODES;
+
+/**
+ * @enum _SCSI_SENSE_RESPONSE_CODE
+ *
+ * @brief this enumeration depicts the types of sense data responses as
+ * per SPC-3.
+ */
+typedef 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
+
+} SCSI_SENSE_RESPONSE_CODE;
+
+/**
+ * @enum _SCSI_SENSE_DATA_DESCRIPTOR_TYPE
+ *
+ * @brief this enumeration depicts the types of sense data descriptor as
+ * per SPC-4.
+ */
+typedef enum _SCSI_SENSE_DATA_DESCRIPTOR_TYPE
+{
+ SCSI_INFORMATION_DESCRIPTOR_TYPE = 0x00,
+ SCSI_CMD_SPECIFIC_DESCRIPTOR_TYPE = 0x01,
+ SCSI_KEY_SPECIFIC_DESCRIPTOR_TYPE = 0x02,
+ SCSI_FIELD_REPLACEABLE_UNIT_DESCRIPTOR_TYPE = 0x03,
+ SCSI_STREAM_CMD_DESCRIPTOR_TYPE = 0x04,
+ SCSI_BLOCK_DESCRIPTOR_TYPE = 0x05,
+ SCSI_OSD_OBJ_IDENTIFICATION_DESCRIPTOR_TYPE = 0x06,
+ SCSI_OSC_RESPONSE_INTEGRITY_DESCRIPTOR_TYPE = 0x07,
+ SCSI_OSD_ATTR_IDENTIFICATION_DESCRIPTOR_TYPE = 0x08,
+ SCSI_ATA_STATUS_RETURN_DESCRIPTOR_TYPE = 0x09,
+ SCSI_PROGRESS_INDICATION_DESCRIPTOR_TYPE = 0x0a,
+ SCSI_USER_DATA_SEGEMNT_REF_DESCRIPTOR_TYPE = 0x0b
+} SCSI_SENSE_DATA_DESCRIPTOR_TYPE;
+
+#define SCSI_CMD_SPECIFIC_DESCRIPTOR_ADDITIONAL_LENGTH 0x0a
+#define SCSI_CMD_SPECIFIC_DESCRIPTOR_LENGTH 0x0c
+#define SCSI_INFORMATION_DESCRIPTOR_ADDITIONAL_LENGTH 0x0a
+#define SCSI_INFORMATION_DESCRIPTOR_LENGTH 0x0c
+#define SCSI_BLOCK_DESCRIPTOR_ADDITIONAL_LENGTH 0x2
+#define SCSI_BLOCK_DESCRIPTOR_LENGTH 0x4
+
+#define SCSI_SENSE_DATA_DESC_BIT 0x01
+
+// 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
+
+/**
+ * @name 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
+/*@}*/
+
+/**
+ * @name 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_LOGICAL_UNIT_NOT_SUPPORTED 0x25
+#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_MEDIUM_FORMAT_CORRUPTED 0x31
+#define SCSI_ASC_ENCLOSURE_SERVICES_UNAVAILABLE 0x35
+#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_LOGICAL_UNIT_FAILED 0x4C
+#define SCSI_ASC_ATA_DEVICE_FEATURE_NOT_ENABLED 0x67
+#define SCSI_ASC_MICROCODE_HAS_CHANGED 0x3F
+/*@}*/
+
+/**
+ * @name 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
+#define SCSI_ASCQ_ATA_PASS_THROUGH_INFORMATION_AVAILABLE 0x1D
+#define SCSI_ASCQ_MICROCODE_HAS_CHANGED 0x01
+/*@}*/
+
+/**
+ * @name 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
+/*@}*/
+
+/**
+ * @name 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
+#define SCSI_SECURITY_PROTOCOL_IN 0xA2
+#define SCSI_SECURITY_PROTOCOL_OUT 0xB5
+#define SCSI_UNMAP 0x42
+#define SCSI_WRITE_AND_VERIFY_10 0x2E
+#define SCSI_WRITE_AND_VERIFY_12 0xAE
+#define SCSI_WRITE_AND_VERIFY_16 0x8E
+/*@}*/
+
+/**
+ * @name SCSI_SERVICE_ACTION_IN_CODES
+ *
+ * Service action in operations.
+ */
+/*@{*/
+#define SCSI_SERVICE_ACTION_IN_CODES_READ_CAPACITY_16 0x10
+/*@}*/
+
+/**
+*
+* Service action mask.
+ */
+/*@{*/
+#define SCSI_SERVICE_ACTION_MASK 0x1f
+/*@}*/
+
+/**
+ * @name SCSI_MAINTENANCE_IN_SERVICE_ACTION_CODES
+ *
+ * MAINTENANCE IN service action codes.
+ */
+/*@{*/
+#define SCSI_REPORT_TASK_MGMT 0x0D
+#define SCSI_REPORT_OP_CODES 0x0C
+/*@}*/
+
+/**
+ * @name 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
+
+#define SCSI_MODE_PAGE_CONTROL_D_SENSE_DISABLE 0x0
+#define SCSI_MODE_PAGE_CONTROL_D_SENSE_ENABLE 0x1
+/**
+ * @name 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 0xE0
+#define SCSI_MODE_SELECT_MODE_PAGE_0A_UA_SWP 0x38
+#define SCSI_MODE_SELECT_MODE_PAGE_0A_TAS_AUTO 0x47
+#define SCSI_MODE_SELECT_MODE_PAGE_D_SENSE 0x4
+
+#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
+
+/**
+ * @name 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
+/**
+ * @name 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
+
+/**
+ * @name 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/sys/dev/isci/scil/sati.c b/sys/dev/isci/scil/sati.c
new file mode 100644
index 0000000..17df017
--- /dev/null
+++ b/sys/dev/isci/scil/sati.c
@@ -0,0 +1,1250 @@
+/*-
+ * 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.
+ *
+ * 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 <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/**
+ * @file
+ * @brief This file contains all of the method implementations that
+ * can be utilized by a user to perform SCSI-to-ATA Translation.
+ * SATI adheres to the www.t10.org SAT specification.
+ *
+ * For situations where compliance is not observed, the SATI will
+ * return an error indication (most likely INVALID FIELD IN CDB sense data).
+ */
+
+#include <dev/isci/scil/sati.h>
+#include <dev/isci/scil/sati_callbacks.h>
+#include <dev/isci/scil/sati_util.h>
+#include <dev/isci/scil/sati_report_luns.h>
+#include <dev/isci/scil/sati_inquiry.h>
+#include <dev/isci/scil/sati_mode_sense_6.h>
+#include <dev/isci/scil/sati_mode_sense_10.h>
+#include <dev/isci/scil/sati_mode_select.h>
+#include <dev/isci/scil/sati_test_unit_ready.h>
+#include <dev/isci/scil/sati_read_capacity.h>
+#include <dev/isci/scil/sati_read.h>
+#include <dev/isci/scil/sati_write.h>
+#include <dev/isci/scil/sati_verify.h>
+#include <dev/isci/scil/sati_synchronize_cache.h>
+#include <dev/isci/scil/sati_lun_reset.h>
+#include <dev/isci/scil/sati_start_stop_unit.h>
+#include <dev/isci/scil/sati_request_sense.h>
+#include <dev/isci/scil/sati_write_long.h>
+#include <dev/isci/scil/sati_reassign_blocks.h>
+#include <dev/isci/scil/sati_log_sense.h>
+#include <dev/isci/scil/sati_abort_task_set.h>
+#include <dev/isci/scil/sati_unmap.h>
+#include <dev/isci/scil/sati_passthrough.h>
+#include <dev/isci/scil/sati_write_and_verify.h>
+#include <dev/isci/scil/sati_read_buffer.h>
+#include <dev/isci/scil/sati_write_buffer.h>
+#include <dev/isci/scil/intel_ata.h>
+#include <dev/isci/scil/intel_scsi.h>
+#include <dev/isci/scil/intel_sat.h>
+
+//******************************************************************************
+//* P R I V A T E M E T H O D S
+//******************************************************************************
+
+/**
+ * @brief This method performs the translation of ATA error register values
+ * into SCSI sense data.
+ * For more information on the parameter passed to this method please
+ * reference the sati_translate_response() method.
+ *
+ * @param[in] error This parameter specifies the contents of the ATA error
+ * register to be translated.
+ *
+ * @return none
+ */
+void sati_translate_error(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ U8 error
+)
+{
+ if (error & ATA_ERROR_REG_NO_MEDIA_BIT)
+ {
+ sati_scsi_sense_data_construct(
+ sequence,
+ scsi_io,
+ SCSI_STATUS_CHECK_CONDITION,
+ SCSI_SENSE_NOT_READY,
+ SCSI_ASC_MEDIUM_NOT_PRESENT,
+ SCSI_ASCQ_MEDIUM_NOT_PRESENT
+ );
+ }
+ else if (error & ATA_ERROR_REG_MEDIA_CHANGE_BIT)
+ {
+ sati_scsi_sense_data_construct(
+ sequence,
+ scsi_io,
+ SCSI_STATUS_CHECK_CONDITION,
+ SCSI_SENSE_UNIT_ATTENTION,
+ SCSI_ASC_NOT_READY_TO_READY_CHANGE,
+ SCSI_ASCQ_NOT_READY_TO_READY_CHANGE
+ );
+ }
+ else if (error & ATA_ERROR_REG_MEDIA_CHANGE_REQUEST_BIT)
+ {
+ sati_scsi_sense_data_construct(
+ sequence,
+ scsi_io,
+ SCSI_STATUS_CHECK_CONDITION,
+ SCSI_SENSE_UNIT_ATTENTION,
+ SCSI_ASC_MEDIUM_REMOVAL_REQUEST,
+ SCSI_ASCQ_MEDIUM_REMOVAL_REQUEST
+ );
+ }
+ else if (error & ATA_ERROR_REG_ID_NOT_FOUND_BIT)
+ {
+ sati_scsi_sense_data_construct(
+ sequence,
+ scsi_io,
+ SCSI_STATUS_CHECK_CONDITION,
+ SCSI_SENSE_ILLEGAL_REQUEST,
+ SCSI_ASC_LBA_OUT_OF_RANGE,
+ SCSI_ASCQ_LBA_OUT_OF_RANGE
+ );
+ }
+ else if (error & ATA_ERROR_REG_UNCORRECTABLE_BIT)
+ {
+ //Mark the Sequence state as a read error so more sense data
+ //can be returned later
+ sequence->state = SATI_SEQUENCE_STATE_READ_ERROR;
+ sati_scsi_sense_data_construct(
+ sequence,
+ scsi_io,
+ SCSI_STATUS_CHECK_CONDITION,
+ SCSI_SENSE_MEDIUM_ERROR,
+ SCSI_ASC_UNRECOVERED_READ_ERROR,
+ SCSI_ASCQ_UNRECOVERED_READ_ERROR
+ );
+ }
+ else if ( (sequence->data_direction == SATI_DATA_DIRECTION_OUT)
+ && (error & ATA_ERROR_REG_WRITE_PROTECTED_BIT) )
+ {
+ sati_scsi_sense_data_construct(
+ sequence,
+ scsi_io,
+ SCSI_STATUS_CHECK_CONDITION,
+ SCSI_SENSE_DATA_PROTECT,
+ SCSI_ASC_WRITE_PROTECTED,
+ SCSI_ASCQ_WRITE_PROTECTED
+ );
+ }
+ else if (error & ATA_ERROR_REG_ICRC_BIT)
+ {
+ sati_scsi_sense_data_construct(
+ sequence,
+ scsi_io,
+ SCSI_STATUS_CHECK_CONDITION,
+ SCSI_SENSE_ABORTED_COMMAND,
+ SCSI_ASC_IU_CRC_ERROR_DETECTED,
+ SCSI_ASCQ_IU_CRC_ERROR_DETECTED
+ );
+ }
+ else // (error & ATA_ERROR_REG_ABORT_BIT)
+ {
+ // The ABORT bit has the lowest precedence of all errors.
+ // As a result, it is at the bottom of the conditional
+ // statement.
+ sati_scsi_sense_data_construct(
+ sequence,
+ scsi_io,
+ SCSI_STATUS_CHECK_CONDITION,
+ SCSI_SENSE_ABORTED_COMMAND,
+ SCSI_ASC_NO_ADDITIONAL_SENSE,
+ SCSI_ASCQ_NO_ADDITIONAL_SENSE
+ );
+ }
+}
+
+/**
+ * @brief This method translates the supplied ATA payload data into the
+ * corresponding SCSI data. This is necessary for SCSI commands
+ * that have well-defined payload data associated with them (e.g.
+ * READ CAPACITY).
+ *
+ * @param[in] sequence This parameter specifies the sequence
+ * data associated with the translation.
+ * @param[in] ata_io This parameter specifies the ATA payload
+ * buffer location and size to be translated.
+ * @param[out] scsi_output_data This parameter specifies the SCSI payload
+ * memory area into which the translator is to write.
+ *
+ * @return none
+ */
+static
+void sati_translate_data(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * ata_input_data,
+ void * scsi_io
+)
+{
+ // Update the device capabilities in the odd/crazy event something changed.
+ sati_device_update_capabilities(
+ sequence->device, (ATA_IDENTIFY_DEVICE_DATA_T*) ata_input_data
+ );
+
+ // Look at the first byte to determine the SCSI command to translate.
+ switch (sequence->type)
+ {
+#if !defined(DISABLE_SATI_INQUIRY)
+ case SATI_SEQUENCE_INQUIRY_STANDARD:
+ sati_inquiry_standard_translate_data(
+ sequence, ata_input_data, scsi_io
+ );
+ break;
+
+ case SATI_SEQUENCE_INQUIRY_SERIAL_NUMBER:
+ sati_inquiry_serial_number_translate_data(
+ sequence, ata_input_data, scsi_io
+ );
+ break;
+
+ case SATI_SEQUENCE_INQUIRY_DEVICE_ID:
+ sati_inquiry_device_id_translate_data(
+ sequence, ata_input_data, scsi_io
+ );
+ break;
+
+ case SATI_SEQUENCE_INQUIRY_BLOCK_DEVICE:
+ sati_inquiry_block_device_translate_data(
+ sequence, ata_input_data, scsi_io
+ );
+ break;
+
+ case SATI_SEQUENCE_INQUIRY_ATA_INFORMATION:
+ sati_inquiry_ata_information_translate_data(
+ sequence, ata_input_data, scsi_io
+ );
+ break;
+
+#endif // !defined(DISABLE_SATI_INQUIRY)
+
+#if !defined(DISABLE_SATI_READ_CAPACITY)
+ case SATI_SEQUENCE_READ_CAPACITY_10:
+ sati_read_capacity_10_translate_data(sequence, ata_input_data, scsi_io);
+ break;
+
+ case SATI_SEQUENCE_READ_CAPACITY_16:
+ sati_read_capacity_16_translate_data(sequence, ata_input_data, scsi_io);
+ break;
+#endif // !defined(DISABLE_SATI_READ_CAPACITY)
+
+#if !defined(DISABLE_SATI_MODE_SENSE)
+ case SATI_SEQUENCE_MODE_SENSE_6_CACHING:
+ sati_mode_sense_6_caching_translate_data(
+ sequence, ata_input_data, scsi_io
+ );
+ break;
+
+ case SATI_SEQUENCE_MODE_SENSE_6_INFORMATIONAL_EXCP_CONTROL:
+ sati_mode_sense_6_informational_excp_control_translate_data(
+ sequence, ata_input_data, scsi_io
+ );
+ break;
+
+ case SATI_SEQUENCE_MODE_SENSE_6_READ_WRITE_ERROR:
+ sati_mode_sense_6_read_write_error_translate_data(
+ sequence, ata_input_data, scsi_io
+ );
+ break;
+
+ case SATI_SEQUENCE_MODE_SENSE_6_DISCONNECT_RECONNECT:
+ sati_mode_sense_6_disconnect_reconnect_translate_data(
+ sequence, ata_input_data, scsi_io
+ );
+ break;
+
+ case SATI_SEQUENCE_MODE_SENSE_6_CONTROL:
+ sati_mode_sense_6_control_translate_data(
+ sequence, ata_input_data, scsi_io
+ );
+ break;
+
+ case SATI_SEQUENCE_MODE_SENSE_6_ALL_PAGES:
+ sati_mode_sense_6_all_pages_translate_data(
+ sequence, ata_input_data, scsi_io
+ );
+ break;
+
+ case SATI_SEQUENCE_MODE_SENSE_6_POWER_CONDITION:
+ sati_mode_sense_6_power_condition_translate_data(
+ sequence, ata_input_data, scsi_io
+ );
+ break;
+
+ case SATI_SEQUENCE_MODE_SENSE_10_POWER_CONDITION:
+ sati_mode_sense_10_power_condition_translate_data(
+ sequence, ata_input_data, scsi_io
+ );
+ break;
+
+ case SATI_SEQUENCE_MODE_SENSE_10_CACHING:
+ sati_mode_sense_10_caching_translate_data(
+ sequence, ata_input_data, scsi_io
+ );
+ break;
+
+ case SATI_SEQUENCE_MODE_SENSE_10_INFORMATIONAL_EXCP_CONTROL:
+ sati_mode_sense_10_informational_excp_control_translate_data(
+ sequence, ata_input_data, scsi_io
+ );
+ break;
+
+ case SATI_SEQUENCE_MODE_SENSE_10_READ_WRITE_ERROR:
+ sati_mode_sense_10_read_write_error_translate_data(
+ sequence, ata_input_data, scsi_io
+ );
+ break;
+
+ case SATI_SEQUENCE_MODE_SENSE_10_DISCONNECT_RECONNECT:
+ sati_mode_sense_10_disconnect_reconnect_translate_data(
+ sequence, ata_input_data, scsi_io
+ );
+ break;
+
+ case SATI_SEQUENCE_MODE_SENSE_10_CONTROL:
+ sati_mode_sense_10_control_translate_data(
+ sequence, ata_input_data, scsi_io
+ );
+ break;
+
+ case SATI_SEQUENCE_MODE_SENSE_10_ALL_PAGES:
+ sati_mode_sense_10_all_pages_translate_data(
+ sequence, ata_input_data, scsi_io
+ );
+ break;
+#endif // !defined(DISABLE_SATI_MODE_SENSE)
+
+ default:
+ break;
+ }
+}
+
+//******************************************************************************
+//* P U B L I C M E T H O D S
+//******************************************************************************
+
+SATI_STATUS sati_translate_command(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ SATI_DEVICE_T * sati_device,
+ void * scsi_io,
+ void * ata_io
+)
+{
+ SATI_STATUS status = SATI_FAILURE;
+ U8 * cdb = sati_cb_get_cdb_address(scsi_io);
+
+ //No sense response has been set for the translation sequence yet
+ sequence->is_sense_response_set = FALSE;
+ // Default to no translation response required
+ sequence->is_translate_response_required = FALSE;
+ // Assign sati_device to sequence
+ sequence->device = sati_device;
+
+ /**
+ * Fail any I/O request with LUN != 0
+ */
+ if (sati_cb_get_lun(scsi_io) != 0)
+ {
+ sati_scsi_sense_data_construct(
+ sequence,
+ scsi_io,
+ SCSI_STATUS_CHECK_CONDITION,
+ SCSI_SENSE_ILLEGAL_REQUEST,
+ SCSI_ASC_LOGICAL_UNIT_NOT_SUPPORTED,
+ 0
+ );
+ return SATI_FAILURE_CHECK_RESPONSE_DATA;
+ }
+
+ /**
+ * SAT dictates:
+ * - the NACA bit in the control byte (last byte) must be 0
+ */
+ if ( (sati_get_cdb_byte(cdb, sati_cb_get_cdb_length(scsi_io) - 1)
+ & SCSI_CONTROL_BYTE_NACA_BIT_ENABLE))
+ {
+ sati_scsi_sense_data_construct(
+ sequence,
+ scsi_io,
+ SCSI_STATUS_CHECK_CONDITION,
+ SCSI_SENSE_ILLEGAL_REQUEST,
+ SCSI_ASC_INVALID_FIELD_IN_CDB,
+ SCSI_ASCQ_INVALID_FIELD_IN_CDB
+ );
+ return SATI_FAILURE_CHECK_RESPONSE_DATA;
+ }
+
+ /**
+ * Per SAT "Error and sense reporting" section. All subsequent IOs after
+ * a device fault should receive INTERNAL TARGET FAILURE sense data.
+ */
+ if (sati_device->state == SATI_DEVICE_STATE_DEVICE_FAULT_OCCURRED)
+ {
+ sati_scsi_sense_data_construct(
+ sequence,
+ scsi_io,
+ SCSI_STATUS_CHECK_CONDITION,
+ SCSI_SENSE_HARDWARE_ERROR,
+ SCSI_ASC_INTERNAL_TARGET_FAILURE,
+ SCSI_ASCQ_INTERNAL_TARGET_FAILURE
+ );
+ return SATI_FAILURE_CHECK_RESPONSE_DATA;
+ }
+
+ if(sequence->state == SATI_SEQUENCE_STATE_INITIAL)
+ {
+ sequence->command_specific_data.scratch = 0;
+ sequence->number_data_bytes_set = 0;
+ }
+
+
+#ifdef SATI_TRANSPORT_SUPPORTS_SATA
+ {
+ U8 * register_fis = sati_cb_get_h2d_register_fis_address(ata_io);
+ sati_set_sata_command_flag(register_fis);
+ sati_set_sata_fis_type(register_fis, SATA_FIS_TYPE_REGH2D);
+ }
+#endif // SATI_TRANSPORT_SUPPORTS_SATA
+
+ // Look at the first byte to determine the SCSI command to translate.
+ switch (sati_get_cdb_byte(cdb, 0))
+ {
+#if !defined(DISABLE_SATI_REPORT_LUNS)
+ case SCSI_REPORT_LUNS:
+ status = sati_report_luns_translate_command(
+ sequence, scsi_io, ata_io
+ );
+ break;
+#endif // !defined(DISABLE_SATI_REPORT_LUNS)
+
+#if !defined(DISABLE_SATI_INQUIRY)
+ case SCSI_INQUIRY:
+ status = sati_inquiry_translate_command(
+ sequence, scsi_io, ata_io
+ );
+ break;
+#endif // !defined(DISABLE_SATI_INQUIRY)
+
+#if !defined(DISABLE_SATI_MODE_SENSE)
+ case SCSI_MODE_SENSE_6:
+ status = sati_mode_sense_6_translate_command(
+ sequence, scsi_io, ata_io
+ );
+ break;
+
+ case SCSI_MODE_SENSE_10:
+ status = sati_mode_sense_10_translate_command(
+ sequence, scsi_io, ata_io
+ );
+ break;
+#endif // !defined(DISABLE_SATI_MODE_SENSE)
+
+#if !defined(DISABLE_SATI_MODE_SELECT)
+ case SCSI_MODE_SELECT_6:
+ status = sati_mode_select_6_translate_command(
+ sequence, scsi_io, ata_io
+ );
+ break;
+
+ case SCSI_MODE_SELECT_10:
+ status = sati_mode_select_10_translate_command(
+ sequence, scsi_io, ata_io
+ );
+ break;
+#endif // !defined(DISABLE_SATI_MODE_SELECT)
+
+#if !defined(DISABLE_SATI_TEST_UNIT_READY)
+ case SCSI_TEST_UNIT_READY:
+ status = sati_test_unit_ready_translate_command(
+ sequence, scsi_io, ata_io
+ );
+ break;
+#endif // !defined(DISABLE_SATI_TEST_UNIT_READY)
+
+#if !defined(DISABLE_SATI_READ_CAPACITY)
+ case SCSI_READ_CAPACITY_10:
+ status = sati_read_capacity_10_translate_command(
+ sequence, scsi_io, ata_io
+ );
+ break;
+
+ case SCSI_SERVICE_ACTION_IN_16:
+ if ( (sati_get_cdb_byte(cdb, 1) & SCSI_SERVICE_ACTION_MASK)
+ == SCSI_SERVICE_ACTION_IN_CODES_READ_CAPACITY_16)
+ status = sati_read_capacity_16_translate_command(
+ sequence, scsi_io, ata_io
+ );
+ else
+ status = SATI_FAILURE_CHECK_RESPONSE_DATA;
+ break;
+#endif // !defined(DISABLE_SATI_READ_CAPACITY)
+
+#if !defined(DISABLE_SATI_REQUEST_SENSE)
+ case SCSI_REQUEST_SENSE:
+ status = sati_request_sense_translate_command(
+ sequence, scsi_io, ata_io
+ );
+ break;
+#endif // !defined(DISABLE_SATI_REQUEST_SENSE)
+
+ case SCSI_READ_6:
+ status = sati_read_6_translate_command(sequence, scsi_io, ata_io);
+ break;
+
+ case SCSI_READ_10:
+ status = sati_read_10_translate_command(sequence, scsi_io, ata_io);
+ break;
+
+ case SCSI_READ_12:
+ status = sati_read_12_translate_command(sequence, scsi_io, ata_io);
+ break;
+
+ case SCSI_READ_16:
+ status = sati_read_16_translate_command(sequence, scsi_io, ata_io);
+ break;
+
+ case SCSI_WRITE_6:
+ status = sati_write_6_translate_command(sequence, scsi_io, ata_io);
+ break;
+
+ case SCSI_WRITE_10:
+ status = sati_write_10_translate_command(sequence, scsi_io, ata_io);
+ break;
+
+ case SCSI_WRITE_12:
+ status = sati_write_12_translate_command(sequence, scsi_io, ata_io);
+ break;
+
+ case SCSI_WRITE_16:
+ status = sati_write_16_translate_command(sequence, scsi_io, ata_io);
+ break;
+
+#if !defined(DISABLE_SATI_VERIFY)
+ case SCSI_VERIFY_10:
+ status = sati_verify_10_translate_command(sequence, scsi_io, ata_io);
+ break;
+
+ case SCSI_VERIFY_12:
+ status = sati_verify_12_translate_command(sequence, scsi_io, ata_io);
+ break;
+
+ case SCSI_VERIFY_16:
+ status = sati_verify_16_translate_command(sequence, scsi_io, ata_io);
+ break;
+#endif // !defined(DISABLE_SATI_VERIFY)
+
+#if !defined(DISABLE_SATI_WRITE_AND_VERIFY) \
+ && !defined(DISABLE_SATI_VERIFY) \
+ && !defined(DISABLE_SATI_WRITE)
+
+ case SCSI_WRITE_AND_VERIFY_10:
+ status = sati_write_and_verify_10_translate_command(sequence, scsi_io, ata_io);
+ break;
+
+ case SCSI_WRITE_AND_VERIFY_12:
+ status = sati_write_and_verify_12_translate_command(sequence, scsi_io, ata_io);
+ break;
+
+ case SCSI_WRITE_AND_VERIFY_16:
+ status = sati_write_and_verify_16_translate_command(sequence, scsi_io, ata_io);
+ break;
+#endif // !defined(DISABLE_SATI_WRITE_AND_VERIFY)
+ // && !defined(DISABLE_SATI_VERIFY)
+ // && !defined(DISABLE_SATI_WRITE)
+
+#if !defined(DISABLE_SATI_REASSIGN_BLOCKS)
+ case SCSI_REASSIGN_BLOCKS:
+ status = sati_reassign_blocks_translate_command(sequence, scsi_io, ata_io);
+ break;
+#endif // !defined(DISABLE_SATI_REASSIGN_BLOCKS)
+
+#if !defined(DISABLE_SATI_SYNCHRONIZE_CACHE)
+ case SCSI_SYNCHRONIZE_CACHE_10:
+ case SCSI_SYNCHRONIZE_CACHE_16:
+ status = sati_synchronize_cache_translate_command(sequence, scsi_io, ata_io);
+ break;
+#endif // !defined(DISABLE_SATI_SYNCHRONIZE_CACHE)
+
+#if !defined(DISABLE_SATI_START_STOP_UNIT)
+ case SCSI_START_STOP_UNIT:
+ status = sati_start_stop_unit_translate_command(
+ sequence, scsi_io, ata_io
+ );
+ break;
+#endif // !defined(DISABLE_SATI_START_STOP_UNIT)
+
+#if !defined(DISABLE_SATI_WRITE_LONG)
+ case SCSI_WRITE_LONG_10:
+ case SCSI_WRITE_LONG_16:
+ status = sati_write_long_translate_command(sequence, scsi_io, ata_io);
+ break;
+#endif // !defined(DISABLE_SATI_WRITE_LONG)
+
+#if !defined(DISABLE_SATI_LOG_SENSE)
+ case SCSI_LOG_SENSE:
+ status = sati_log_sense_translate_command(sequence, scsi_io, ata_io);
+ break;
+#endif // !defined(DISABLE_SATI_LOG_SENSE)
+
+ case SCSI_PERSISTENT_RESERVE_IN:
+ case SCSI_PERSISTENT_RESERVE_OUT:
+ //These commands are not supported by SATI
+ sati_scsi_sense_data_construct(
+ sequence,
+ scsi_io,
+ SCSI_STATUS_CHECK_CONDITION,
+ SCSI_SENSE_ILLEGAL_REQUEST,
+ SCSI_ASC_INVALID_COMMAND_OPERATION_CODE,
+ SCSI_ASCQ_INVALID_COMMAND_OPERATION_CODE
+ );
+ //returning status now to keep sense data set above
+ return SATI_FAILURE_CHECK_RESPONSE_DATA;
+ break;
+
+#if !defined(DISABLE_SATI_UNMAP)
+ case SCSI_UNMAP:
+ status = sati_unmap_translate_command(sequence, scsi_io, ata_io);
+ break;
+#endif // !defined(DISABLE_SATI_UNMAP)
+
+#if !defined(DISABLE_SATI_ATA_PASSTHROUGH)
+ case SCSI_ATA_PASSTHRU_12:
+ status = sati_passthrough_12_translate_command(sequence, scsi_io, ata_io);
+ break;
+
+ case SCSI_ATA_PASSTHRU_16:
+ status = sati_passthrough_16_translate_command(sequence, scsi_io, ata_io);
+ break;
+
+#endif // !define(DISABLE_SATI_ATA_PASSTHRU)
+
+#if !defined(DISABLE_SATI_READ_BUFFER)
+ case SCSI_READ_BUFFER:
+ status = sati_read_buffer_translate_command(sequence, scsi_io, ata_io);
+ break;
+#endif //!defined(DISABLE_SATI_READ_BUFFER)
+
+#if !defined(DISABLE_SATI_WRITE_BUFFER)
+ case SCSI_WRITE_BUFFER:
+ status = sati_write_buffer_translate_command(sequence, scsi_io, ata_io);
+ break;
+#endif //!defined(DISABLE_SATI_WRITE_BUFFER)
+ default:
+ status = SATI_FAILURE_CHECK_RESPONSE_DATA;
+ break;
+ }
+
+ if( (status == SATI_FAILURE_CHECK_RESPONSE_DATA) &&
+ !(sequence->is_sense_response_set) )
+ {
+ sati_scsi_sense_data_construct(
+ sequence,
+ scsi_io,
+ SCSI_STATUS_CHECK_CONDITION,
+ SCSI_SENSE_ILLEGAL_REQUEST,
+ SCSI_ASC_INVALID_FIELD_IN_CDB,
+ SCSI_ASCQ_INVALID_FIELD_IN_CDB
+ );
+ }
+ return status;
+}
+
+// -----------------------------------------------------------------------------
+
+#if !defined(DISABLE_SATI_TASK_MANAGEMENT)
+SATI_STATUS sati_translate_task_management(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ SATI_DEVICE_T * sati_device,
+ void * scsi_task,
+ void * ata_io
+)
+{
+ SATI_STATUS status=SATI_FAILURE;
+ U8 task_function = sati_cb_get_task_function(scsi_task);
+
+ sequence->device = sati_device;
+
+ switch (task_function)
+ {
+ /**
+ * @todo We need to update the ABORT_TASK and ABORT_TASK_SET to be
+ * SAT compliant.
+ */
+ case SCSI_TASK_REQUEST_ABORT_TASK:
+ case SCSI_TASK_REQUEST_LOGICAL_UNIT_RESET:
+ status = sati_lun_reset_translate_command(sequence, scsi_task, ata_io);
+ break;
+
+ case SCSI_TASK_REQUEST_ABORT_TASK_SET:
+#if !defined(DISABLE_SATI_ABORT_TASK_SET)
+ status = sati_abort_task_set_translate_command(sequence, scsi_task, ata_io);
+#else
+ status = SATI_FAILURE;
+#endif
+ break;
+ default:
+ status = SATI_FAILURE;
+ break;
+ }
+
+ return status;
+}
+#endif // !defined(DISABLE_SATI_TASK_MANAGEMENT)
+
+// -----------------------------------------------------------------------------
+#if !defined(DISABLE_SATI_INQUIRY) \
+ || !defined(DISABLE_SATI_READY_CAPACITY) \
+ || !defined(DISABLE_SATI_MODE_SENSE) \
+ || !defined(DISABLE_SATI_MODE_SELECT) \
+ || !defined(DISABLE_SATI_REASSIGN_BLOCKS) \
+ || !defined(DISABLE_SATI_START_STOP_UNIT) \
+ || !defined(DISABLE_SATI_REQUEST_SENSE) \
+ || !defined(DISABLE_SATI_WRITE_LONG) \
+ || !defined(DISABLE_SATI_LOG_SENSE) \
+ || !defined(DISABLE_SATI_UNMAP)
+
+static
+SATI_STATUS sati_check_data_io(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence
+)
+{
+ if(sequence->state == SATI_SEQUENCE_STATE_INCOMPLETE)
+ {
+ return SATI_SEQUENCE_INCOMPLETE;
+ }
+ else if(sequence->number_data_bytes_set < sequence->allocation_length)
+ {
+ return SATI_COMPLETE_IO_DONE_EARLY;
+ }
+ else
+ {
+ return SATI_COMPLETE;
+ }
+}
+#endif // !defined(DISABLE_SATI_INQUIRY)
+ // || !defined(DISABLE_SATI_READY_CAPACITY)
+ // || !defined(DISABLE_SATI_MODE_SENSE)
+ // || !defined(DISABLE_SATI_MODE_SELECT)
+ // || !defined(DISABLE_SATI_REASSIGN_BLOCKS)
+ // || !defined(DISABLE_SATI_START_STOP_UNIT)
+ // || !defined(DISABLE_SATI_REQUEST_SENSE)
+ // || !defined(DISABLE_SATI_WRITE_LONG)
+ // || !defined(DISABLE_SATI_LOG_SENSE)
+ // || !defined(DISABLE_SATI_UNMAP)
+// -----------------------------------------------------------------------------
+SATI_STATUS sati_translate_command_response(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ void * ata_io
+)
+{
+ SATI_STATUS status = SATI_COMPLETE;
+ U8 * register_fis = sati_cb_get_d2h_register_fis_address(ata_io);
+ U8 ata_status;
+
+ /**
+ * If the device fault bit is set in the status register, then
+ * set the sense data and return.
+ */
+ ata_status = (U8) sati_get_ata_status(register_fis);
+ if (ata_status & ATA_STATUS_REG_DEVICE_FAULT_BIT)
+ {
+ sati_scsi_sense_data_construct(
+ sequence,
+ scsi_io,
+ SCSI_STATUS_CHECK_CONDITION,
+ SCSI_SENSE_HARDWARE_ERROR,
+ SCSI_ASC_INTERNAL_TARGET_FAILURE,
+ SCSI_ASCQ_INTERNAL_TARGET_FAILURE
+ );
+
+ sequence->device->state = SATI_DEVICE_STATE_DEVICE_FAULT_OCCURRED;
+
+ // Make sure that the terminate sequence is called to allow
+ // translation logic to perform any cleanup before the IO is completed.
+ sati_sequence_terminate(sequence,
+ scsi_io,
+ ata_io);
+
+ return SATI_FAILURE_CHECK_RESPONSE_DATA;
+ }
+
+ // Look at the sequence type to determine the response translation method
+ // to invoke.
+ switch (sequence->type)
+ {
+#if !defined(DISABLE_SATI_TEST_UNIT_READY)
+ case SATI_SEQUENCE_TEST_UNIT_READY:
+ status = sati_test_unit_ready_translate_response(
+ sequence, scsi_io, ata_io
+ );
+ break;
+#endif // !defined(DISABLE_SATI_TEST_UNIT_READY)
+
+#if !defined(DISABLE_SATI_INQUIRY) \
+ || !defined(DISABLE_SATI_READY_CAPACITY) \
+ || !defined(DISABLE_SATI_MODE_SENSE)
+
+ case SATI_SEQUENCE_INQUIRY_EXECUTE_DEVICE_DIAG:
+
+ if (ata_status & ATA_STATUS_REG_ERROR_BIT)
+ {
+ U8 error = (U8) sati_get_ata_error(register_fis);
+ status = SATI_FAILURE_CHECK_RESPONSE_DATA;
+ sati_translate_error(sequence, scsi_io, error);
+ }
+ else
+ {
+ sati_inquiry_ata_information_finish_translation(
+ sequence,
+ scsi_io,
+ ata_io
+ );
+ status = sati_check_data_io(sequence);
+ }
+ break;
+
+ case SATI_SEQUENCE_INQUIRY_STANDARD:
+ case SATI_SEQUENCE_INQUIRY_SUPPORTED_PAGES:
+ case SATI_SEQUENCE_INQUIRY_SERIAL_NUMBER:
+ case SATI_SEQUENCE_INQUIRY_BLOCK_DEVICE:
+ case SATI_SEQUENCE_INQUIRY_ATA_INFORMATION:
+ case SATI_SEQUENCE_INQUIRY_DEVICE_ID:
+ case SATI_SEQUENCE_READ_CAPACITY_10:
+ case SATI_SEQUENCE_READ_CAPACITY_16:
+ case SATI_SEQUENCE_MODE_SENSE_6_CACHING:
+ case SATI_SEQUENCE_MODE_SENSE_6_INFORMATIONAL_EXCP_CONTROL:
+ case SATI_SEQUENCE_MODE_SENSE_6_READ_WRITE_ERROR:
+ case SATI_SEQUENCE_MODE_SENSE_6_DISCONNECT_RECONNECT:
+ case SATI_SEQUENCE_MODE_SENSE_6_CONTROL:
+ case SATI_SEQUENCE_MODE_SENSE_6_POWER_CONDITION:
+ case SATI_SEQUENCE_MODE_SENSE_6_ALL_PAGES:
+ case SATI_SEQUENCE_MODE_SENSE_10_CACHING:
+ case SATI_SEQUENCE_MODE_SENSE_10_INFORMATIONAL_EXCP_CONTROL:
+ case SATI_SEQUENCE_MODE_SENSE_10_READ_WRITE_ERROR:
+ case SATI_SEQUENCE_MODE_SENSE_10_CONTROL:
+ case SATI_SEQUENCE_MODE_SENSE_10_POWER_CONDITION:
+ case SATI_SEQUENCE_MODE_SENSE_10_DISCONNECT_RECONNECT:
+ case SATI_SEQUENCE_MODE_SENSE_10_ALL_PAGES:
+ // Did an error occur during the IO request?
+ if (ata_status & ATA_STATUS_REG_ERROR_BIT)
+ {
+ U8 error = (U8) sati_get_ata_error(register_fis);
+ status = SATI_FAILURE_CHECK_RESPONSE_DATA;
+ sati_translate_error(sequence, scsi_io, error);
+ }
+ else
+ {
+ void * ata_data = sati_cb_get_ata_data_address(ata_io);
+
+ if(ata_data == NULL)
+ {
+ status = SATI_FAILURE;
+ }
+ else
+ {
+ sati_translate_data(sequence, ata_data, scsi_io);
+ status = sati_check_data_io(sequence);
+ }
+ }
+ break;
+#endif // !defined(DISABLE_SATI_INQUIRY)
+ // && !defined(DISABLE_SATI_READY_CAPACITY)
+ // && !defined(DISABLE_SATI_MODE_SENSE)
+
+#if !defined(DISABLE_SATI_MODE_SELECT)
+ case SATI_SEQUENCE_MODE_SELECT_MODE_PAGE_CACHING:
+
+ status = sati_mode_select_translate_response(
+ sequence, scsi_io, ata_io
+ );
+ if(status == SATI_COMPLETE)
+ {
+ status = sati_check_data_io(sequence);
+ }
+ break;
+
+ case SATI_SEQUENCE_MODE_SELECT_MODE_POWER_CONDITION:
+ case SATI_SEQUENCE_MODE_SELECT_MODE_INFORMATION_EXCEPT_CONTROL:
+ // Did an error occur during the IO request?
+ if (ata_status & ATA_STATUS_REG_ERROR_BIT)
+ {
+ U8 error = (U8) sati_get_ata_error(register_fis);
+ status = SATI_FAILURE_CHECK_RESPONSE_DATA;
+ sati_translate_error(sequence, scsi_io, error);
+ }
+ else
+ {
+ status = sati_check_data_io(sequence);
+ }
+ break;
+#endif // !defined(DISABLE_SATI_MODE_SELECT)
+
+#if !defined(DISABLE_SATI_WRITE_AND_VERIFY)
+ case SATI_SEQUENCE_WRITE_AND_VERIFY:
+
+ if (ata_status & ATA_STATUS_REG_ERROR_BIT)
+ {
+ U8 error = (U8) sati_get_ata_error(register_fis);
+ sati_translate_error(sequence, scsi_io, error);
+
+ return SATI_FAILURE_CHECK_RESPONSE_DATA;
+ }
+ else
+ {
+ status = sati_write_and_verify_translate_response(
+ sequence,
+ scsi_io,
+ ata_io
+ );
+ }
+ break;
+#endif // !defined(DISABLE_SATI_WRITE_AND_VERIFY)
+
+ case SATI_SEQUENCE_READ_6:
+ case SATI_SEQUENCE_READ_10:
+ case SATI_SEQUENCE_READ_12:
+ case SATI_SEQUENCE_READ_16:
+ case SATI_SEQUENCE_WRITE_6:
+ case SATI_SEQUENCE_WRITE_10:
+ case SATI_SEQUENCE_WRITE_12:
+ case SATI_SEQUENCE_WRITE_16:
+ case SATI_SEQUENCE_VERIFY_10:
+ case SATI_SEQUENCE_VERIFY_12:
+ case SATI_SEQUENCE_VERIFY_16:
+ case SATI_SEQUENCE_SYNCHRONIZE_CACHE:
+ if (ata_status & ATA_STATUS_REG_ERROR_BIT)
+ {
+ U8 error = (U8) sati_get_ata_error(register_fis);
+ status = SATI_FAILURE_CHECK_RESPONSE_DATA;
+ sati_translate_error(sequence, scsi_io, error);
+
+ if(sequence->state == SATI_SEQUENCE_STATE_READ_ERROR )
+ {
+ sati_scsi_read_error_sense_construct(
+ sequence,
+ scsi_io,
+ ata_io,
+ SCSI_STATUS_CHECK_CONDITION,
+ SCSI_SENSE_MEDIUM_ERROR,
+ SCSI_ASC_UNRECOVERED_READ_ERROR,
+ SCSI_ASCQ_UNRECOVERED_READ_ERROR
+ );
+ sequence->state = SATI_SEQUENCE_STATE_FINAL;
+ }
+ }
+ else
+ {
+ // We haven't satisified the transfer count from the original
+ // SCSI CDB. As a result, we need to re-issue the command
+ // with updated logical block address and transfer count.
+ if (sequence->command_specific_data.scratch)
+ {
+ /** @todo update the contents of the CDB directly? Should be
+ * done during previous command translation?
+ */
+ status = SATI_SEQUENCE_INCOMPLETE;
+ }
+ }
+ break;
+
+#if !defined(DISABLE_SATI_READ_BUFFER)
+ case SATI_SEQUENCE_READ_BUFFER:
+ status = sati_read_buffer_translate_response(
+ sequence, scsi_io, ata_io
+ );
+
+ if(status == SATI_COMPLETE)
+ {
+ status = sati_check_data_io(sequence);
+ }
+ break;
+#endif //!defined(DISABLE_SATI_READ_BUFFER)
+
+#if !defined(DISABLE_SATI_WRITE_BUFFER)
+ case SATI_SEQUENCE_WRITE_BUFFER:
+ case SATI_SEQUENCE_WRITE_BUFFER_MICROCODE:
+ status = sati_write_buffer_translate_response(
+ sequence, scsi_io, ata_io
+ );
+ break;
+#endif //!defined(DISABLE_SATI_WRITE_BUFFER)
+
+#if !defined(DISABLE_SATI_REASSIGN_BLOCKS)
+ case SATI_SEQUENCE_REASSIGN_BLOCKS:
+ status = sati_reassign_blocks_translate_response(
+ sequence, scsi_io, ata_io
+ );
+ if(status == SATI_COMPLETE)
+ {
+ status = sati_check_data_io(sequence);
+ }
+ break;
+#endif // !defined(DISABLE_SATI_REASSIGN_BLOCKS)
+
+#if !defined(DISABLE_SATI_START_STOP_UNIT)
+ case SATI_SEQUENCE_START_STOP_UNIT:
+ status = sati_start_stop_unit_translate_response(
+ sequence, scsi_io, ata_io
+ );
+ if(status == SATI_COMPLETE)
+ {
+ status = sati_check_data_io(sequence);
+ }
+ break;
+#endif // !defined(DISABLE_SATI_START_STOP_UNIT)
+
+#if !defined(DISABLE_SATI_REQUEST_SENSE)
+ case SATI_SEQUENCE_REQUEST_SENSE_SMART_RETURN_STATUS:
+ case SATI_SEQUENCE_REQUEST_SENSE_CHECK_POWER_MODE:
+ status = sati_request_sense_translate_response(
+ sequence, scsi_io, ata_io
+ );
+ if(status == SATI_COMPLETE)
+ {
+ status = sati_check_data_io(sequence);
+ }
+ break;
+#endif // !defined(DISABLE_SATI_REQUEST_SENSE)
+
+#if !defined(DISABLE_SATI_WRITE_LONG)
+ case SATI_SEQUENCE_WRITE_LONG:
+ status = sati_write_long_translate_response(
+ sequence, scsi_io, ata_io
+ );
+ if(status == SATI_COMPLETE)
+ {
+ status = sati_check_data_io(sequence);
+ }
+ break;
+#endif // !defined(DISABLE_SATI_WRITE_LONG)
+
+#if !defined(DISABLE_SATI_LOG_SENSE)
+ case SATI_SEQUENCE_LOG_SENSE_SUPPORTED_LOG_PAGE:
+ case SATI_SEQUENCE_LOG_SENSE_SELF_TEST_LOG_PAGE:
+ case SATI_SEQUENCE_LOG_SENSE_EXTENDED_SELF_TEST_LOG_PAGE:
+ case SATI_SEQUENCE_LOG_SENSE_INFO_EXCEPTION_LOG_PAGE:
+ status = sati_log_sense_translate_response(
+ sequence, scsi_io, ata_io
+ );
+ if(status == SATI_COMPLETE)
+ {
+ status = sati_check_data_io(sequence);
+ }
+ break;
+#endif // !defined(DISABLE_SATI_LOG_SENSE)
+
+#if !defined(DISABLE_SATI_UNMAP)
+ case SATI_SEQUENCE_UNMAP:
+ status = sati_unmap_translate_response(
+ sequence, scsi_io, ata_io
+ );
+ if(status == SATI_COMPLETE)
+ {
+ status = sati_check_data_io(sequence);
+ }
+ break;
+#endif // !defined(DISABLE_SATI_UNMAP)
+
+#if !defined(DISABLE_SATI_ATA_PASSTHROUGH)
+ case SATI_SEQUENCE_ATA_PASSTHROUGH_12:
+ case SATI_SEQUENCE_ATA_PASSTHROUGH_16:
+ status = sati_passthrough_translate_response(
+ sequence, scsi_io, ata_io
+ );
+ break;
+#endif // !defined(DISABLE_SATI_ATA_PASSTHROUGH)
+
+ default:
+ status = SATI_FAILURE_INVALID_SEQUENCE_TYPE;
+ break;
+ }
+
+ return status;
+}
+
+// -----------------------------------------------------------------------------
+
+#if !defined(DISABLE_SATI_TASK_MANAGEMENT)
+SATI_STATUS sati_translate_task_response(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ void * ata_io
+)
+{
+ SATI_STATUS status = SATI_FAILURE_CHECK_RESPONSE_DATA;
+ U8 * register_fis = sati_cb_get_d2h_register_fis_address(ata_io);
+ U8 ata_status;
+
+ /**
+ * If the device fault bit is set in the status register, then
+ * set the sense data and return.
+ */
+ ata_status = (U8) sati_get_ata_status(register_fis);
+ if (ata_status & ATA_STATUS_REG_DEVICE_FAULT_BIT)
+ {
+ sati_scsi_response_data_construct(
+ sequence,
+ scsi_io,
+ SCSI_TASK_MGMT_FUNC_FAILED
+ );
+ return SATI_FAILURE_CHECK_RESPONSE_DATA;
+ }
+
+ // Look at the sequence type to determine the response translation method
+ // to invoke.
+ switch (sequence->type)
+ {
+ case SATI_SEQUENCE_LUN_RESET:
+ if (ata_status & ATA_STATUS_REG_ERROR_BIT)
+ {
+ sati_scsi_response_data_construct(
+ sequence, scsi_io, SCSI_TASK_MGMT_FUNC_FAILED);
+ }
+ else
+ {
+ sati_scsi_response_data_construct(
+ sequence, scsi_io, SCSI_TASK_MGMT_FUNC_COMPLETE);
+ }
+
+ status = SATI_COMPLETE;
+ break;
+
+#if !defined(DISABLE_SATI_ABORT_TASK_SET)
+ case SATI_SEQUENCE_ABORT_TASK_SET:
+ if (ata_status & ATA_STATUS_REG_ERROR_BIT)
+ {
+ sati_scsi_response_data_construct(
+ sequence, scsi_io, SCSI_TASK_MGMT_FUNC_FAILED);
+ }
+ else
+ {
+ void * ata_data = sati_cb_get_ata_data_address(ata_io);
+
+ if(ata_data == NULL)
+ {
+ status = SATI_FAILURE;
+ }
+ else
+ {
+ status = sati_abort_task_set_translate_data(
+ sequence,
+ ata_data,
+ scsi_io
+ );
+ }
+ }
+ break;
+#endif // !defined(DISABLE_SATI_ABORT_TASK_SET)
+
+ default:
+ status = SATI_FAILURE_INVALID_SEQUENCE_TYPE;
+ break;
+ }
+
+ return status;
+}
+#endif // !defined(DISABLE_SATI_TASK_MANAGEMENT)
+
+#if !defined(ENABLE_MINIMUM_MEMORY_MODE)
+U32 sati_get_sat_compliance_version(
+ void
+)
+{
+ return 2; // Compliant with SAT-2.
+}
+
+U32 sati_get_sat_compliance_version_revision(
+ void
+)
+{
+ return 7; // Compliant with SAT-2 revision 7.
+}
+
+#endif // !defined(ENABLE_MINIMUM_MEMORY_MODE)
+
+U16 sati_get_number_data_bytes_set(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence
+)
+{
+ return sequence->number_data_bytes_set;
+}
+
+void sati_sequence_construct(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence
+)
+{
+ sequence->state = SATI_SEQUENCE_STATE_INITIAL;
+}
+
+void sati_sequence_terminate(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ void * ata_io
+)
+{
+ // Decode the sequence type to determine how to handle the termination
+ // of the the translation method.
+ switch (sequence->type)
+ {
+ case SATI_SEQUENCE_UNMAP:
+ sati_unmap_terminate(sequence,scsi_io,ata_io);
+ break;
+ }
+}
diff --git a/sys/dev/isci/scil/sati.h b/sys/dev/isci/scil/sati.h
new file mode 100644
index 0000000..9b3eafa
--- /dev/null
+++ b/sys/dev/isci/scil/sati.h
@@ -0,0 +1,271 @@
+/*-
+ * 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.
+ *
+ * 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.
+ *
+ * $FreeBSD$
+ */
+#ifndef _SATI_H_
+#define _SATI_H_
+
+/**
+ * @file
+ * @brief This file contains all of the interface methods, macros, structures
+ * that can be utilized by a user to perform SCSI-to-ATA Translation.
+ * SATI adheres to the www.t10.org SAT specification.
+ *
+ * For specific compliance information please refer to:
+ * - sati_get_sat_compliance_version() and
+ * - sati_get_sat_compliance_version_revision()
+ *
+ * For situations where compliance is not observed, the SATI will
+ * return an error indication (most likely INVALID FIELD IN CDB sense).
+ */
+
+#include <dev/isci/scil/sati_types.h>
+#include <dev/isci/scil/sati_translator_sequence.h>
+
+/**
+ * @brief This method will be called by the core to indicate the start of a
+ * new translation sequence. Set up the initial sequence state.
+ *
+ * @return None
+ */
+void sati_sequence_construct(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence
+);
+
+/**
+ * @brief This method will be called by the core to request the current translation
+ * sequence be terminated.
+ *
+ * @param[in] sequence This parameter specifies the sequence
+ * data associated with the translation.
+ * @param[in,out] scsi_io This parameter specifies the user's SCSI IO request
+ * object. SATI expects that the user can access the SCSI CDB,
+ * response, and data from this pointer. For example, if there
+ * is a failure in translation resulting in sense data, then
+ * SATI will call sati_cb_set_status() and pass the scsi_io
+ * pointer as a parameter.
+ * @param[out] ata_io This parameter specifies the location of the
+ * ATA register FIS into which the translator can write the
+ * resultant ATA command if translation is successful. This
+ * parameter is passed back to the user through the
+ * SATI_SATA_CALLBACKS when it is necessary to write fields
+ * in the ata_io.
+ *
+ * @return None
+ */
+void sati_sequence_terminate(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ void * ata_io
+);
+
+/**
+ * @brief This method translates the supplied SCSI command into a
+ * corresponding ATA command.
+ *
+ * @param[in] sequence This parameter specifies the sequence
+ * data associated with the translation.
+ * @param[in] sati_device This parameter specifies the remote device
+ * for which the translated request is destined.
+ * @param[in,out] scsi_io This parameter specifies the user's SCSI IO request
+ * object. SATI expects that the user can access the SCSI CDB,
+ * response, and data from this pointer. For example, if there
+ * is a failure in translation resulting in sense data, then
+ * SATI will call sati_cb_set_status() and pass the scsi_io
+ * pointer as a parameter.
+ * @param[out] ata_io This parameter specifies the location of the
+ * ATA register FIS into which the translator can write the
+ * resultant ATA command if translation is successful. This
+ * parameter is passed back to the user through the
+ * SATI_SATA_CALLBACKS when it is necessary to write fields
+ * in the ata_io.
+ *
+ * @return Indicate if the translation was successful.
+ * @retval SATI_SUCCESS
+ * @retval SATI_FAILURE_CHECK_RESPONSE_DATA
+ */
+SATI_STATUS sati_translate_command(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ SATI_DEVICE_T * sati_device,
+ void * scsi_io,
+ void * ata_io
+);
+
+/**
+ * @brief This method translates the supplied SCSI task management request
+ * into a corresponding ATA command/control FIS.
+ *
+ * @param[in] sequence This parameter specifies the sequence
+ * data associated with the translation.
+ * @param[in] sati_device This parameter specifies the remote device
+ * for which the translated request is destined.
+ * @param[in,out] scsi_io This parameter specifies the user's SCSI IO request
+ * object. SATI expects that the user can access the SCSI CDB,
+ * response, and data from this pointer. For example, if there
+ * is a failure in translation resulting in sense data, then
+ * SATI will call sati_cb_set_status() and pass the scsi_io
+ * pointer as a parameter.
+ * @param[out] ata_io This parameter specifies the location of the
+ * ATA register FIS into which the translator can write the
+ * resultant ATA command if translation is successful. This
+ * parameter is passed back to the user through the
+ * SATI_SATA_CALLBACKS when it is necessary to write fields
+ * in the ata_io.
+ *
+ * @return Indicate if the translation was successful.
+ * @retval SATI_SUCCESS
+ * @retval SATI_FAILURE_CHECK_RESPONSE_DATA
+ */
+SATI_STATUS sati_translate_task_management(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ SATI_DEVICE_T * sati_device,
+ void * scsi_task,
+ void * ata_io
+);
+
+/**
+ * @brief This method translates the supplied ATA response into the
+ * corresponding SCSI command response.
+ *
+ * @param[in] sequence This parameter specifies the sequence
+ * data associated with the translation.
+ * @param[out] scsi_io This parameter specifies the user's SCSI IO request
+ * object. SATI expects that the user can access the SCSI CDB,
+ * response, and data from this pointer. For example, if there
+ * is a failure in translation resulting in sense data, then
+ * SATI will call sati_cb_set_status() and pass the scsi_io
+ * pointer as a parameter.
+ * @param[out] ata_io This parameter specifies the location of the
+ * ATA IO request (e.g. register FIS, PIO Setup etc.) from which
+ * the translator can read the received ATA status and error
+ * fields.
+ *
+ * @return Indicate if the translation was successful.
+ * @retval SATI_SUCCESS
+ * @retval SATI_FAILURE_CHECK_RESPONSE_DATA
+ */
+SATI_STATUS sati_translate_command_response(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ void * ata_io
+);
+
+/**
+ * @brief This method translates the supplied ATA response into the
+ * corresponding SCSI task response.
+ *
+ * @param[in] sequence This parameter specifies the sequence
+ * data associated with the translation.
+ * @param[out] scsi_io This parameter specifies the user's SCSI IO request
+ * object. SATI expects that the user can access the SCSI CDB,
+ * response, and data from this pointer. For example, if there
+ * is a failure in translation resulting in sense data, then
+ * SATI will call sati_cb_set_status() and pass the scsi_io
+ * pointer as a parameter.
+ * @param[out] ata_io This parameter specifies the location of the
+ * ATA IO request (e.g. register FIS, PIO Setup etc.) from which
+ * the translator can read the received ATA status and error
+ * fields.
+ *
+ * @return Indicate if the translation was successful.
+ * @retval SATI_FAILURE_CHECK_RESPONSE_DATA
+ */
+SATI_STATUS sati_translate_task_response(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ void * ata_io
+);
+
+/**
+ * @brief This method simply returns the SAT major compliance version number
+ * for which the implementation is compliant.
+ *
+ * @return Return the specification identifier with which this translator
+ * is compliant.
+ */
+U32 sati_get_sat_compliance_version(
+ void
+);
+
+/**
+ * @brief This method simply returns the SAT version revision identifier
+ * for which the implementation is compliant.
+ *
+ * @return Return the specification revision identifier with which this
+ * translator is compliant.
+ */
+U32 sati_get_sat_compliance_version_revision(
+ void
+);
+
+/**
+* @brief This method returns the number of data bytes written
+* by the translation sequence.
+*
+* @param[in] sequence This parameter specifies the sequence data
+* associated with the translation.
+*
+* @return Return the U16 number_data_bytes_set in the
+* SATI_TRANSLATOR_SEQUENCE.
+*/
+U16 sati_get_number_data_bytes_set(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence
+);
+
+void sati_translate_error(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ U8 error
+);
+
+#endif // _SATI_H_
+
diff --git a/sys/dev/isci/scil/sati_abort_task_set.c b/sys/dev/isci/scil/sati_abort_task_set.c
new file mode 100644
index 0000000..e7a3b41
--- /dev/null
+++ b/sys/dev/isci/scil/sati_abort_task_set.c
@@ -0,0 +1,177 @@
+/*-
+ * 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.
+ *
+ * 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 <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/**
+ * @file
+ *
+ * @brief This file contains the method implementations required to
+ * translate the SCSI abort task set command.
+ */
+
+#if !defined(DISABLE_SATI_TASK_MANAGEMENT)
+
+#include <dev/isci/scil/sati_abort_task_set.h>
+#include <dev/isci/scil/sati_callbacks.h>
+#include <dev/isci/scil/sati_util.h>
+#include <dev/isci/scil/sati.h>
+#include <dev/isci/scil/intel_ata.h>
+#include <dev/isci/scil/intel_scsi.h>
+#include <dev/isci/scil/intel_sat.h>
+
+//******************************************************************************
+//* P U B L I C M E T H O D S
+//******************************************************************************
+
+#if !defined(DISABLE_SATI_ABORT_TASK_SET)
+
+/**
+ * @brief This method will translate the abort task set SCSI task request into an
+ * ATA READ LOG EXT command. For more information on the parameters
+ * passed to this method, please reference sati_translate_command().
+ *
+ * @return Indicate if the command translation succeeded.
+ * @retval SCI_SUCCESS This is returned if the command translation was
+ * successful.
+ */
+SATI_STATUS sati_abort_task_set_translate_command(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ void * ata_io
+)
+{
+ U8 * register_fis;
+
+ //ATA Read Log Ext with log address set to 0x10
+ sati_ata_read_log_ext_construct(
+ ata_io,
+ sequence,
+ ATA_LOG_PAGE_NCQ_ERROR,
+ sizeof(ATA_NCQ_COMMAND_ERROR_LOG_T)
+ );
+
+ register_fis = sati_cb_get_h2d_register_fis_address(ata_io);
+ sati_set_sata_command_flag(register_fis);
+
+ sequence->type = SATI_SEQUENCE_ABORT_TASK_SET;
+ sequence->state = SATI_SEQUENCE_STATE_AWAIT_RESPONSE;
+
+ return SATI_SUCCESS;
+}
+
+SATI_STATUS sati_abort_task_set_translate_data(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * ata_input_data,
+ void * scsi_task
+)
+{
+ ATA_NCQ_COMMAND_ERROR_LOG_T * log =
+ (ATA_NCQ_COMMAND_ERROR_LOG_T *)ata_input_data;
+ U8 tag_index;
+
+ sequence->state = SATI_SEQUENCE_STATE_TRANSLATE_DATA;
+
+ for (tag_index = 0; tag_index < 32; tag_index++)
+ {
+ void * matching_command;
+ SCI_STATUS completion_status;
+ sati_cb_device_get_request_by_ncq_tag(
+ scsi_task,
+ tag_index,
+ matching_command
+ );
+
+ if (matching_command != NULL)
+ {
+ if (
+ (log->ncq_tag == tag_index) &&
+ (log->nq == 0) // nq==1 means a non-queued command
+ // caused this failure
+ )
+ {
+ sati_translate_error(sequence, matching_command, log->error);
+ completion_status = SCI_FAILURE_IO_RESPONSE_VALID;
+
+ if(sequence->state == SATI_SEQUENCE_STATE_READ_ERROR)
+ {
+ //Uncorrectable read error, return additional sense data
+ sati_scsi_read_ncq_error_sense_construct(
+ sequence,
+ matching_command,
+ ata_input_data,
+ SCSI_STATUS_CHECK_CONDITION,
+ SCSI_SENSE_MEDIUM_ERROR,
+ SCSI_ASC_UNRECOVERED_READ_ERROR,
+ SCSI_ASCQ_UNRECOVERED_READ_ERROR
+ );
+ }
+ }
+ else
+ {
+ completion_status = SCI_FAILURE_IO_TERMINATED;
+ }
+
+ sati_cb_io_request_complete(matching_command, completion_status);
+ }
+ }
+
+ sequence->state = SATI_SEQUENCE_STATE_FINAL;
+
+ return SATI_COMPLETE;
+}
+
+#endif // !defined(DISABLE_SATI_ABORT_TASK_SET)
+
+#endif // !defined(DISABLE_SATI_TASK_MANAGEMENT)
+
diff --git a/sys/dev/isci/scil/sati_abort_task_set.h b/sys/dev/isci/scil/sati_abort_task_set.h
new file mode 100644
index 0000000..33a6425
--- /dev/null
+++ b/sys/dev/isci/scil/sati_abort_task_set.h
@@ -0,0 +1,83 @@
+/*-
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 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.
+ *
+ * $FreeBSD$
+ */
+#ifndef _SATI_ABORT_TASK_SET_H_
+#define _SATI_ABORT_TASK_SET_H_
+
+/**
+ * @file
+ * @brief This file contains the method interfaces required to translate the
+ * SCSI abort task set task request as well as translate response
+ * for the task request.
+ */
+
+#include <dev/isci/scil/sati_types.h>
+#include <dev/isci/scil/sati_translator_sequence.h>
+
+#if !defined(DISABLE_SATI_ABORT_TASK_SET)
+
+SATI_STATUS sati_abort_task_set_translate_command(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_task,
+ void * ata_io
+);
+
+SATI_STATUS sati_abort_task_set_translate_data(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * ata_input_data,
+ void * scsi_task
+);
+
+#endif // !defined(DISABLE_SATI_ABORT_TASK_SET)
+
+#endif // _SATI_ABORT_TASK_SET_H_
diff --git a/sys/dev/isci/scil/sati_atapi.c b/sys/dev/isci/scil/sati_atapi.c
new file mode 100644
index 0000000..f2158ae
--- /dev/null
+++ b/sys/dev/isci/scil/sati_atapi.c
@@ -0,0 +1,257 @@
+/*-
+ * 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.
+ *
+ * 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 <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/**
+ * @file
+ * @brief This file contains all of the method implementations that
+ * can be utilized by a user to perform SCSI-to-ATA Translation.
+ * SATI adheres to the www.t10.org SAT specification.
+ *
+ * For situations where compliance is not observed, the SATI will
+ * return an error indication (most likely INVALID FIELD IN CDB sense data).
+ */
+
+#include <dev/isci/scil/sati.h>
+#include <dev/isci/scil/sati_util.h>
+#include <dev/isci/scil/sati_atapi.h>
+#include <dev/isci/scil/sati_callbacks.h>
+#include <dev/isci/scil/intel_ata.h>
+#include <dev/isci/scil/intel_scsi.h>
+#include <dev/isci/scil/intel_sat.h>
+#include <dev/isci/scil/sati_report_luns.h>
+
+
+//******************************************************************************
+//* P U B L I C M E T H O D S
+//******************************************************************************
+
+SATI_STATUS sati_atapi_translate_command(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ SATI_DEVICE_T * sati_device,
+ void * scsi_io,
+ void * atapi_io
+)
+{
+ SATI_STATUS status;
+ U8 * cdb = sati_cb_get_cdb_address(scsi_io);
+
+ SATA_FIS_REG_H2D_T * register_fis =
+ (SATA_FIS_REG_H2D_T *)sati_cb_get_h2d_register_fis_address(atapi_io);
+
+ U8 io_direction = SATI_DATA_DIRECTION_IN;
+
+ //No sense response has been set for the translation sequence yet
+ sequence->is_sense_response_set = FALSE;
+ // Default to no translation response required
+ sequence->is_translate_response_required = FALSE;
+
+ sequence->number_data_bytes_set = 0;
+ sequence->device = sati_device;
+ sequence->command_specific_data.scratch = 0;
+
+ sati_cb_get_data_direction(scsi_io, &io_direction);
+
+ //set sat protocol.
+ if (io_direction == SATI_DATA_DIRECTION_NONE)
+ sequence->protocol = SAT_PROTOCOL_PACKET_NON_DATA;
+ else if (io_direction == SATI_DATA_DIRECTION_IN)
+ sequence->protocol = SAT_PROTOCOL_PACKET_DMA_DATA_IN;
+ else if (io_direction == SATI_DATA_DIRECTION_OUT)
+ sequence->protocol = SAT_PROTOCOL_PACKET_DMA_DATA_OUT;
+
+ // We don't send Report Luns command out.
+ if (sati_get_cdb_byte(cdb, 0) == SCSI_REPORT_LUNS)
+ {
+ status = sati_report_luns_translate_command(
+ sequence, scsi_io, atapi_io
+ );
+ }
+ else if (sati_cb_get_lun(scsi_io) != 0)
+ {
+ sati_scsi_sense_data_construct(
+ sequence,
+ scsi_io,
+ SCSI_STATUS_CHECK_CONDITION,
+ SCSI_SENSE_ILLEGAL_REQUEST,
+ SCSI_ASC_LOGICAL_UNIT_NOT_SUPPORTED,
+ 0
+ );
+ status = SATI_FAILURE_CHECK_RESPONSE_DATA;
+ }
+ else
+ {
+ if (sequence->state == SATI_SEQUENCE_STATE_INCOMPLETE)
+ { //Request Sense command is required.
+ U8 request_sense_cdb[SATI_ATAPI_REQUEST_SENSE_CDB_LENGTH] =
+ {0x3, 0x0, 0x0, 0x0, 0x12, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0};
+
+ //set the sequence->protocol to DATA_IN anyway;
+ sequence->protocol = SAT_PROTOCOL_PACKET_DMA_DATA_IN;
+
+ //set the cdb for Request Sense using command_specific_data field.
+ memcpy(sequence->command_specific_data.sati_atapi_data.request_sense_cdb,
+ request_sense_cdb,
+ SATI_ATAPI_REQUEST_SENSE_CDB_LENGTH
+ );
+ }
+
+ //build Packet Fis for any other command translation.
+ register_fis->command = ATA_PACKET;
+ register_fis->features |= ATA_PACKET_FEATURE_DMA;
+
+ register_fis->fis_type = SATA_FIS_TYPE_REGH2D;
+ register_fis->command_flag = 1;
+
+ status = SATI_SUCCESS;
+ }
+
+ return status;
+}
+
+
+SATI_STATUS sati_atapi_translate_command_response(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ void * atapi_io
+)
+{
+ SATI_STATUS status = SATI_COMPLETE;
+ U8 * register_fis = sati_cb_get_d2h_register_fis_address(atapi_io);
+ U8 ata_status;
+
+ /**
+ * If the device fault bit is set in the status register, then
+ * set the sense data and return.
+ */
+ ata_status = (U8) sati_get_ata_status(register_fis);
+ if (ata_status & ATA_STATUS_REG_DEVICE_FAULT_BIT)
+ {
+ sati_scsi_sense_data_construct(
+ sequence,
+ scsi_io,
+ SCSI_STATUS_CHECK_CONDITION,
+ SCSI_SENSE_HARDWARE_ERROR,
+ SCSI_ASC_INTERNAL_TARGET_FAILURE,
+ SCSI_ASCQ_INTERNAL_TARGET_FAILURE
+ );
+
+ sequence->device->state = SATI_DEVICE_STATE_DEVICE_FAULT_OCCURRED;
+
+ return SATI_FAILURE_CHECK_RESPONSE_DATA;
+ }
+ else if (ata_status & ATA_STATUS_REG_ERROR_BIT)
+ {
+ //reset the register_fis.
+ memset(register_fis, 0, sizeof(SATA_FIS_REG_D2H_T));
+
+ //Internal Request Sense command is needed.
+ sequence->state = SATI_SEQUENCE_STATE_INCOMPLETE;
+ return SATI_SEQUENCE_INCOMPLETE;
+ }
+
+ return status;
+}
+
+void sati_atapi_translate_request_sense_response(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ void * atapi_io
+)
+{
+ //sense data is already in place.
+ SCI_SSP_RESPONSE_IU_T * rsp_iu = (SCI_SSP_RESPONSE_IU_T*)
+ sati_cb_get_response_iu_address(scsi_io);
+
+ sati_scsi_common_response_iu_construct(
+ rsp_iu,
+ SCSI_STATUS_CHECK_CONDITION,
+ sati_scsi_get_sense_data_length(sequence, scsi_io),
+ SCSI_RESPONSE_DATA_PRES_SENSE_DATA
+ );
+
+ sequence->is_sense_response_set = TRUE;
+
+ sequence->state = SATI_SEQUENCE_STATE_FINAL;
+}
+
+
+U32 sati_atapi_translate_number_of_bytes_transferred(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ void * atapi_io
+)
+{
+ U8* cdb = sati_cb_get_cdb_address(scsi_io);
+ U8 response_data;
+ U32 data_length = 0;
+
+ switch(cdb[0])
+ {
+ case SCSI_MODE_SENSE_10:
+ sati_cb_get_data_byte(scsi_io, 1, &response_data);
+ data_length = response_data+2;
+ break;
+
+ case 0x51: //READ DISC INFORMATION
+ sati_cb_get_data_byte(scsi_io, 1, &response_data);
+ data_length = response_data+2;
+ break;
+
+ default:
+ break;
+ }
+
+ return data_length;
+}
diff --git a/sys/dev/isci/scil/sati_atapi.h b/sys/dev/isci/scil/sati_atapi.h
new file mode 100644
index 0000000..e22e682
--- /dev/null
+++ b/sys/dev/isci/scil/sati_atapi.h
@@ -0,0 +1,177 @@
+/*-
+ * 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.
+ *
+ * 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.
+ *
+ * $FreeBSD$
+ */
+#ifndef _SATI_ATAPI_H_
+#define _SATI_ATAPI_H_
+
+/**
+ * @file
+ * @brief This file contains all of the interface methods, macros, structures
+ * that can be utilized by a user to perform SCSI-to-ATA PACKET IO
+ * Translation.
+ */
+#include <dev/isci/scil/sati_types.h>
+#include <dev/isci/scil/sati_translator_sequence.h>
+
+/**
+ * @brief This method translates the supplied SCSI command into a
+ * corresponding ATA packet protocol command.
+ *
+ * @param[in] sequence This parameter specifies the sequence
+ * data associated with the translation.
+ * @param[in] sati_device This parameter specifies the remote device
+ * for which the translated request is destined.
+ * @param[in,out] scsi_io This parameter specifies the user's SCSI IO request
+ * object. SATI expects that the user can access the SCSI CDB,
+ * response, and data from this pointer. For example, if there
+ * is a failure in translation resulting in sense data, then
+ * SATI will call sati_cb_set_status() and pass the scsi_io
+ * pointer as a parameter.
+ * @param[out] atapi_io This parameter specifies the location of the
+ * ATA Packet FIS into which the translator can write the resultant
+ * ATA command if translation is successful. This parameter is
+ * passed back to the user through the SATI_SATA_CALLBACKS when it
+ * is necessary to write fields in the ata_io.
+ *
+ * @return Indicate if the translation was successful.
+ * @retval SATI_SUCCESS
+ * @retval SATI_FAILURE_CHECK_RESPONSE_DATA
+ */
+SATI_STATUS sati_atapi_translate_command(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ SATI_DEVICE_T * sati_device,
+ void * scsi_io,
+ void * atapi_io
+);
+
+
+/**
+ * @brief This method translates the supplied ATA packet IO response into the
+ * corresponding SCSI command response.
+ *
+ * @param[out] sequence This parameter specifies the sequence
+ * data associated with the translation and will be updated
+ * according to the command response.
+ * @param[out] scsi_io This parameter specifies the user's SCSI IO request
+ * object. SATI expects that the user can access the SCSI CDB,
+ * response, and data from this pointer. For example, if there
+ * is a failure in translation resulting in sense data, then
+ * SATI will call sati_cb_set_status() and pass the scsi_io
+ * pointer as a parameter.
+ * @param[in] atapi_io This parameter specifies the location of the
+ * ATAPI IO request (e.g. register FIS, PIO Setup etc.) from which
+ * the translator can read the received ATA status and error
+ * fields.
+ *
+ * @return Indicate if the translation was successful.
+ * @retval SATI_SUCCESS
+ * @retval SATI_FAILURE_CHECK_RESPONSE_DATA
+ */
+SATI_STATUS sati_atapi_translate_command_response(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ void * atapi_io
+);
+
+
+/**
+ * @brief This method translates the internal Request Sense command response
+ * and set the sense data for the previous failed SCSI command.
+ *
+ * @param[out] sequence This parameter specifies the sequence
+ * data associated with the translation and to be updated to
+ * final state.
+ * @param[out] scsi_io This parameter specifies the user's SCSI IO request
+ * object. SATI expects that the user can access the SCSI CDB,
+ * response, and data from this pointer. For example, if there
+ * is a failure in translation resulting in sense data, then
+ * SATI will call sati_cb_set_status() and pass the scsi_io
+ * pointer as a parameter.
+ * @param[in] atapi_io This parameter specifies the location of the
+ * ATAPI IO request (e.g. register FIS, PIO Setup etc.) from which
+ * the translator can read the received ATA status and error
+ * fields.
+ *
+ * @return None.
+ */
+void sati_atapi_translate_request_sense_response(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ void * atapi_io
+);
+
+
+/**
+ * @brief This method retrieve ATA packet IO actual transferred data length.
+ *
+ * @param[in] sequence This parameter specifies the sequence
+ * data associated with the translation.
+ * @param[out] scsi_io This parameter specifies the user's SCSI IO request
+ * object. SATI expects that the user can access the SCSI CDB,
+ * response, and data from this pointer. For example, if there
+ * is a failure in translation resulting in sense data, then
+ * SATI will call sati_cb_set_status() and pass the scsi_io
+ * pointer as a parameter.
+ * @param[out] atapi_io This parameter specifies the location of the
+ * ATAPI IO request (e.g. register FIS, PIO Setup etc.) from which
+ * the translator can read the received ATA status and error
+ * fields.
+ *
+ * @return Actual data transfer length.
+ */
+U32 sati_atapi_translate_number_of_bytes_transferred(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ void * atapi_io
+);
+#endif
diff --git a/sys/dev/isci/scil/sati_callbacks.h b/sys/dev/isci/scil/sati_callbacks.h
new file mode 100644
index 0000000..61dad4d
--- /dev/null
+++ b/sys/dev/isci/scil/sati_callbacks.h
@@ -0,0 +1,481 @@
+/*-
+ * 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.
+ *
+ * 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.
+ *
+ * $FreeBSD$
+ */
+#ifndef _SATI_CALLBACKS_H_
+#define _SATI_CALLBACKS_H_
+
+/**
+ * @file
+ * @brief This file contains the default callback bindings for SATI. These
+ * must be overridden by the SATI user to ensure successful operation.
+ */
+
+#include <dev/isci/scil/sati_types.h>
+#include <dev/isci/scil/intel_sas.h>
+
+#ifdef SATI_DEFAULT_DECLARATION
+
+/**
+ * @brief This callback method asks the user to provide the address for
+ * the command descriptor block (CDB) associated with this IO request.
+ *
+ * @param[in] scsi_io 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.
+ *
+ * @return This method returns the virtual address of the CDB.
+ */
+void * sati_cb_get_cdb_address(
+ void * scsi_io
+);
+
+/**
+ * @brief This callback method asks the user to provide the length of
+ * the command descriptor block (CDB) associated with this IO request.
+ *
+ * @param[in] scsi_io 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.
+ *
+ * @return This method returns the length of the CDB.
+ */
+U32 sati_cb_get_cdb_length(
+ void * scsi_io
+);
+
+/**
+ * @brief This callback method asks the user to provide the data transfer
+ * direction of this IO request.
+ *
+ * @param[in] scsi_io 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.
+ * @param[in] io_direction to return
+ * @return This method returns the length of the CDB.
+ */
+void sati_cb_get_data_direction(
+ void * scsi_io,
+ U8 * io_direction
+);
+
+/**
+ * @brief This callback method sets a value into the data buffer associated
+ * with the supplied user SCSI IO request at the supplied byte offset.
+ *
+ * @note SATI does not manage the user scatter-gather-list. As a result,
+ * the user must ensure that data is written according to the SGL.
+ *
+ * @param[in] scsi_io This parameter specifies the user's SCSI IO request
+ * for which to set the data buffer byte.
+ * @param[in] byte_offset This parameter specifies the offset into the
+ * data buffer at which to set the value.
+ * @param[in] value This parameter specifies the new value to be set into
+ * the data buffer.
+ *
+ * @return none
+ */
+void sati_cb_set_data_byte(
+ void * scsi_io,
+ U32 byte_offset,
+ U8 value
+);
+
+/**
+ * @brief This callback method gets a value from the data buffer associated
+ * with the supplied user SCSI IO request at the supplied byte offset.
+ *
+ * @note SATI does not manage the user scatter-gather-list. As a result,
+ * the user must ensure that data is written according to the SGL.
+ *
+ * @param[in] scsi_io This parameter specifies the user's SCSI IO request
+ * for which to get the data buffer byte.
+ * @param[in] byte_offset This parameter specifies the offset into the
+ * data buffer at which to get the value.
+ * @param[in] value This parameter specifies the new value to be get into
+ * the data buffer.
+ *
+ * @return none
+ */
+void sati_cb_get_data_byte(
+ void * scsi_io,
+ U32 byte_offset,
+ U8 * value
+);
+
+/**
+ * @brief This callback method gets the the task type for the SCSI task
+ * request.
+ *
+ * @param[in] scsi_task This parameter specifies the user's SCSI Task request.
+ * It is a cookie that allows the user to provide the necessary
+ * information for this callback.
+ *
+ * @return This method returns one of the enumeration values for
+ * SCSI_TASK_MGMT_REQUEST_CODES
+ */
+U8 sati_cb_get_task_function(
+ void * scsi_task
+);
+
+#ifdef SATI_TRANSPORT_SUPPORTS_SAS
+/**
+ * @brief This callback method retrieves the address of the user's SSP
+ * response IU buffer.
+ *
+ * @param[in] scsi_io This parameter specifies the user's SCSI IO request
+ * for which to retreive the location of the response buffer to
+ * be written.
+ *
+ * @return This method returns the address of the response data buffer.
+ */
+void * sati_cb_get_response_iu_address(
+ void * scsi_io
+);
+
+#else // SATI_TRANSPORT_SUPPORTS_SAS
+
+/**
+ * @brief This callback method retrieves the address of the user's sense data
+ * buffer.
+ *
+ * @param[in] scsi_io This parameter specifies the user's SCSI IO request
+ * for which to retreive the location of the sense buffer to
+ * be written.
+ *
+ * @return This method returns the address of the sense data buffer.
+ */
+U8* sati_cb_get_sense_data_address(
+ void * scsi_io
+);
+
+/**
+ * @brief This callback method retrieves the length of the user's sense data
+ * buffer.
+ *
+ * @param[in] scsi_io This parameter specifies the user's SCSI IO request
+ * for which to retreive the location of the sense buffer to
+ * be written.
+ *
+ * @return This method returns the length of the sense data buffer.
+ */
+U32 sati_cb_get_sense_data_length(
+ void * scsi_io
+);
+
+/**
+ * @brief This callback method sets the SCSI status to be associated with
+ * the supplied user's SCSI IO request.
+ *
+ * @param[in] scsi_io This parameter specifies the user's SCSI IO request
+ * for which to set the SCSI status.
+ * @param[in] status This parameter specifies the SCSI status to be
+ * associated with the supplied user's SCSI IO request.
+ *
+ * @return none
+ */
+void sati_cb_set_scsi_status(
+ void * scsi_io,
+ U8 status
+);
+
+#endif // SATI_TRANSPORT_SUPPORTS_SAS
+
+/**
+ * @brief This method retrieves the ATA task file (register FIS) relating to
+ * the host to device command values.
+ *
+ * @param[in] ata_io This parameter specifies the user's ATA IO request
+ * from which to retrieve the h2d register FIS address.
+ *
+ * @return This method returns the address for the host to device register
+ * FIS.
+ */
+U8 * sati_cb_get_h2d_register_fis_address(
+ void * ata_io
+);
+
+/**
+ * @brief This method retrieves the ATA task file (register FIS) relating to
+ * the device to host reponse values.
+ *
+ * @param[in] ata_io This parameter specifies the user's ATA IO request
+ * from which to retrieve the d2h register FIS address.
+ *
+ * @return This method returns the address for the device to host register
+ * FIS.
+ */
+U8 * sati_cb_get_d2h_register_fis_address(
+ void * ata_io
+);
+
+/**
+ * @brief This method retrieves the address where the ATA data received
+ * from the device is stored.
+ *
+ * @param[in] ata_io This parameter specifies the user's ATA IO request
+ * from which to retrieve the received data address.
+ *
+ * @return This method returns the address for the data received from
+ * the remote device.
+ */
+void * sati_cb_get_ata_data_address(
+ void * ata_io
+);
+
+/**
+ * @brief This method allocates a DMA buffer
+ * that can be utilized for small (<=4K) DMA sequences.
+ * This is utilized to translate SCSI UNMAP requests.
+ *
+ * @param[in] scsi_io This parameter specifies the user's SCSI IO request
+ * for which to set the SCSI status.
+ * @param[in] length in bytes of the buffer to be allocated
+ * @param[in] virtual address of the allocated DMA buffer.
+ * @param[in] low 32 bits of the physical DMA address.
+ * @param[in] high 32 bits of the physical DMA address.
+ *
+ * @return This method returns the virtual and physical address
+ * of the allocated DMA buffer.
+ */
+void sati_cb_allocate_dma_buffer(
+ void * scsi_io,
+ U32 length,
+ void ** virt_address,
+ U32 * phys_address_low,
+ U32 * phys_address_high
+);
+
+/**
+ * @brief This method frees a previously allocated DMA buffer
+ *
+ * @param[in] scsi_io This parameter specifies the user's SCSI IO request
+ * for which to set the SCSI status.
+ * @param[in] address - write buffer address being freed
+ *
+ * @return This method returns the address for the data received from
+ * the remote device.
+ */
+void sati_cb_free_dma_buffer(
+ void * scsi_io,
+ void * virt_address
+);
+
+/**
+ * @brief This method retrieves a pointer to the next scatter gather
+ * list element.
+ *
+ * @param[in] scsi_io This parameter specifies the user's SCSI IO request
+ * from which to retrieve the scatter gather list.
+ * @param[in] ata_io This parameter specifies the user's ATA IO request
+ * from which to retrieve the scatter gather list.
+ * @param[in] current_sge This parameter specifies the current SG element
+ * being pointed to. If retrieving the first element,
+ * then this value should be NULL.
+ * @param[in] next_sge This parameter is the returned SGL element
+ * based on current_sge.
+ *
+ * @return This method returns a pointer to the scatter gather element.
+ */
+void sati_cb_sgl_next_sge(
+ void * scsi_io,
+ void * ata_io,
+ void * current_sge,
+ void ** next_sge
+);
+
+/**
+ * @brief This method will set the next scatter-gather elements address
+ * low field.
+ *
+ * @param[in] current_sge This parameter specifies the current SG element
+ * being pointed to.
+ * @param[in] address_low This parameter specifies the lower 32-bits
+ * of address to be programmed into the SG element.
+ * @param[in] address_high This parameter specifies the upper 32-bits
+ * of address to be programmed into the SG element.
+ * @param[in] length This parameter specifies the number of bytes
+ * to be programmed into the SG element.
+ *
+ * @return none
+ */
+void sati_cb_sge_write(
+ void * current_sge,
+ U32 phys_address_low,
+ U32 phys_address_high,
+ U32 byte_length
+);
+
+/**
+ * @brief This method will check to see if the translation requires
+ * a translation response callback. Some translations need to be alerted on all
+ * failures so sequence cleanup can be completed for halting the translation.
+ *
+ * @param[in] the current SCIC request under going translation.
+ *
+ * @return TRUE A response callback will be required to complete this translation sequence.
+ */
+BOOL sati_cb_do_translate_response(
+ void * request
+);
+
+/**
+ * @brief This method retrieves the SAS address for the device associated
+ * with the supplied SCSI IO request. This method assumes that the
+ * associated device is contained in a SAS Domain.
+ *
+ * @param[in] scsi_io This parameter specifies the user's SCSI IO request
+ * for which to retreive the SAS address of the device.
+ * @param[out] sas_address This parameter specifies the SAS address memory
+ * to be contain the retrieved value.
+ *
+ * @return none
+ */
+void sati_cb_device_get_sas_address(
+ void * scsi_io,
+ SCI_SAS_ADDRESS_T * sas_address
+);
+
+/**
+ * @brief In this method the user is expected to log the supplied
+ * error information. The user must be capable of handling variable
+ * length argument lists and should consider prepending the fact
+ * that this is an error from the core.
+ *
+ * @param[in] logger_object This parameter specifies the logger object
+ * associated with this message.
+ * @param[in] log_object_mask This parameter specifies the log objects
+ * for which this message is being generated.
+ * @param[in] log_message This parameter specifies the message to be logged.
+ *
+ * @return none
+ */
+void sati_cb_logger_log_error(
+ void * logger_object,
+ U32 log_object_mask,
+ char * log_message,
+ ...
+);
+
+/**
+ * @brief In this method the user is expected to log the supplied warning
+ * information. The user must be capable of handling variable
+ * length argument lists and should consider prepending the fact
+ * that this is a warning from the core.
+ *
+ * @param[in] logger_object This parameter specifies the logger object
+ * associated with this message.
+ * @param[in] log_object_mask This parameter specifies the log objects
+ * for which this message is being generated.
+ * @param[in] log_message This parameter specifies the message to be logged.
+ *
+ * @return none
+ */
+void sati_cb_logger_log_warning(
+ void * logger_object,
+ U32 log_object_mask,
+ char * log_message,
+ ...
+);
+
+/**
+ * @brief In this method the user is expected to log the supplied debug
+ * information. The user must be capable of handling variable
+ * length argument lists and should consider prepending the fact
+ * that this is a debug message from the core.
+ *
+ * @param[in] logger_object This parameter specifies the logger object
+ * associated with this message.
+ * @param[in] log_object_mask This parameter specifies the log objects
+ * for which this message is being generated.
+ * @param[in] log_message This parameter specifies the message to be logged.
+ *
+ * @return none
+ */
+void sati_cb_logger_log_info(
+ void * logger_object,
+ U32 log_object_mask,
+ char * log_message,
+ ...
+);
+
+/**
+ * @brief In this method the user is expected to log the supplied function
+ * trace information. The user must be capable of handling variable
+ * length argument lists and should consider prepending the fact
+ * that this is a function trace (i.e. entry/exit) message from the
+ * core.
+ *
+ * @param[in] logger_object This parameter specifies the logger object
+ * associated with this message.
+ * @param[in] log_object_mask This parameter specifies the log objects
+ * for which this message is being generated.
+ * @param[in] log_message This parameter specifies the message to be logged.
+ *
+ * @return none
+ */
+void sati_cb_logger_log_trace(
+ void * logger_object,
+ U32 log_object_mask,
+ char * log_message,
+ ...
+);
+
+#include <dev/isci/scil/sati_callbacks_implementation.h>
+
+#else // SATI_DEFAULT_DECLARATION
+
+#include <dev/isci/scil/scif_sas_sati_binding.h>
+#endif // SATI_DEFAULT_DECLARATION
+
+#endif // _SATI_CALLBACKS_H_
+
diff --git a/sys/dev/isci/scil/sati_design.h b/sys/dev/isci/scil/sati_design.h
new file mode 100644
index 0000000..f4f2248
--- /dev/null
+++ b/sys/dev/isci/scil/sati_design.h
@@ -0,0 +1,169 @@
+/*-
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 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.
+ *
+ * $FreeBSD$
+ */
+#ifndef _SATI_DESIGN_H_
+#define _SATI_DESIGN_H_
+
+/**
+@page sati_design_page SATI High Level Design
+
+<b>Authors:</b>
+- Nathan Marushak
+
+@section scif_sas_scope_and_audience Scope and Audience
+
+This document provides design information relating to the SCSI to ATA
+Translation Implementation (SATI). Driver developers are the primary
+audience for this document. The reader is expected to have an understanding
+of SCSI (Simple Computer Storage Interface), ATA (Advanced Technology
+Attachment), and SAT (SCSI-to-ATA Translation).
+
+Please refer to www.t10.org for specifications relating to SCSI and SAT.
+Please refer to www.t13.org for specifications relating to ATA.
+
+@section overview Overview
+
+SATI provides environment agnostic functionality for translating SCSI
+commands, data, and responses into ATA commands, data, and responses. As
+a result, in some instances the user must fill out callbacks to set data.
+This ensures that user isn't forced to have to copy the data an additional
+time due to memory access restrictions.
+
+SATI complies with the t10 SAT specification where possible. In cases where
+there are variances the design and implementation will make note.
+Additionally, for parameters, pages, functionality, or commands for which
+SATI is unable to translate, SATI will return sense data indicating
+INVALID FIELD IN CDB.
+
+SATI has two primary entry points from which the user can enter:
+- sati_translate_command()
+- sati_translate_response() (this method performs data translation).
+
+Additionally, SATI provides a means through which the user can query to
+determine the t10 specification revision with which SATI is compliant. For
+more information please refer to:
+- sati_get_sat_compliance_version()
+- sati_get_sat_compliance_version_revision()
+
+@section sati_definitions Definitions
+
+- scsi_io: The SCSI IO is considered to be the user's SCSI IO request object
+(e.g. the windows driver IO request object and SRB). It is passed back to
+the user via callback methods to retrieve required SCSI information (e.g. CDB,
+response IU address, etc.). The SCSI IO is just a cookie and can represent
+any value the caller desires, but the user must be able to utilize this value
+when it is passed back through callback methods during translation.
+- ata_io: The ATA IO is considered to be the user's ATA IO request object. If
+you are utilizing the SCI Framework, then the SCI Framework is the ATA IO.
+The ATA IO is just a cookie and can represent any value the caller desires,
+but the user must be able to utilize this value when it is passed back
+through callback methods during translation.
+
+@section sati_use_cases Use Cases
+
+The SCSI Primary Command (SPC) set is comprised of commands that are valid
+for all device types defined in SCSI. Some of these commands have
+sub-commands or parameter data defined in another specification (e.g. SBC, SAT).
+These separate sub-commands or parameter data are captured in the SPC use
+case diagram for simplicity.
+
+@note
+- For simplicify the association between the actor and the use cases
+has not been drawn, but is assumed.
+- The use cases in green indicate the use case has been implemented in
+ source.
+
+@image html Use_Case_Diagram__SATI__SATI_-_SPC.jpg "SCSI Primary Command Translation Use Cases"
+
+The SCSI Block Command (SBC) set is comprised of commands that are valid for
+block devices (e.g. disks).
+
+@image html Use_Case_Diagram__SATI__SATI_-_SBC.jpg "SCSI Block Command Translation Use Cases"
+
+The SCSI-to-ATA Translation (SAT) specification defines a few of it's own
+commands, parameter data, and log pages. This use case diagram, however, only
+captures the SAT specific commands being translated.
+
+@image html Use_Case_Diagram__SATI__SATI_-_SAT_Specific.jpg "SCSI-to-ATA Translation Specific Use Cases"
+
+@section sati_class_hierarchy Class Hierarchy
+
+@image html Class_Diagram__SATI__Class_Diagram.jpg "SATI Class Diagram"
+
+@section sati_sequences Sequence Diagrams
+
+@note These sequence diagrams are currently a little out of date. An
+ update is required.
+
+This sequence diagram simply depicts the high-level translation sequence to
+be followed for command translations.
+
+@image html Sequence_Diagram__General_Cmd_Translation_Sequence__General_Cmd_Translation_Sequence.jpg "General Command Translation Sequence"
+
+This sequence diagram simply depicts the high-level translation sequence to
+be followed for reponse translations.
+
+@image html Sequence_Diagram__General_Rsp_Translation_Sequence__General_Rsp_Translation_Sequence.jpg "General Response Translation Sequence"
+
+This sequence diagram simply depicts the high-level translation sequence to
+be followed for data translations. Some SCSI commands such as READ CAPACITY,
+INQUIRY, etc. have payload data associated with them. As a result, it is
+necessary for the ATA payload data to be translated to meet the expected SCSI
+output.
+
+@image html Sequence_Diagram__General_Data_Translation_Sequence__General_Data_Translation_Sequence.jpg "General Data Translation Sequence"
+
+*/
+
+#endif // _SATI_DESIGN_H_
+
diff --git a/sys/dev/isci/scil/sati_device.c b/sys/dev/isci/scil/sati_device.c
new file mode 100644
index 0000000..1fbcf6c
--- /dev/null
+++ b/sys/dev/isci/scil/sati_device.c
@@ -0,0 +1,245 @@
+/*-
+ * 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.
+ *
+ * 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 <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/**
+ * @file
+ * @brief 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 <dev/isci/scil/sati_device.h>
+#include <dev/isci/scil/sci_util.h> // Move this file.
+#include <dev/isci/scil/sati_unmap.h>
+#include <dev/isci/scil/intel_scsi.h>
+
+/**
+ * @brief This method simply initializes the data members in the device
+ * object to their appropriate values.
+ *
+ * @param[in] device This parameter specifies the device for which to
+ * initialize the data members.
+ * @param[in] is_ncq_enabled This parameter specifies if NCQ is to be
+ * utilized for this particular SATI device.
+ * @param[in] max_ncq_depth This parameter specifies the maximum desired
+ * NCQ depth. Once this value is set it can never be increased.
+ * @param[in] ignore_fua This parameter specifies FUA is to be ignored and not
+ * sent to the end device. Some OS (Windows) has quirky behaviors with FUA
+ * and recommend driver developers ignore the bit.
+ *
+ * @return none
+ */
+void sati_device_construct(
+ SATI_DEVICE_T * device,
+ BOOL is_ncq_enabled,
+ U8 max_ncq_depth,
+ BOOL ignore_fua
+)
+{
+ device->state = SATI_DEVICE_STATE_OPERATIONAL;
+ device->capabilities = 0;
+ device->descriptor_sense_enable = SCSI_MODE_PAGE_CONTROL_D_SENSE_DISABLE;
+
+ // The user requested that NCQ be utilized if it is supported by
+ // the device.
+ if (is_ncq_enabled == TRUE)
+ device->capabilities |= SATI_DEVICE_CAP_NCQ_REQUESTED_ENABLE;
+
+ device->ncq_depth = max_ncq_depth;
+
+ // The user requested that FUA is ignored (windows performance issue)
+ if (ignore_fua == TRUE)
+ device->capabilities |= SATI_DEVICE_CAP_IGNORE_FUA;
+
+}
+
+/**
+ * @brief This method will update the SATI_DEVICE capabilities based on
+ * the supplied ATA_IDENTIFY_DEVICE_DATA.
+ *
+ * @param[in] device This parameter specifies the device for which to update
+ * the supported capabilities.
+ * @param[in] identify This parameter specifies the ata identify device
+ * information from which to extract the capabilities of the
+ * device.
+ *
+ * @return none
+ */
+void sati_device_update_capabilities(
+ SATI_DEVICE_T * device,
+ ATA_IDENTIFY_DEVICE_DATA_T * identify
+)
+{
+ U16 capabilities = 0;
+
+ if (identify->capabilities1 & ATA_IDENTIFY_CAPABILITIES1_NORMAL_DMA_ENABLE)
+ capabilities |= SATI_DEVICE_CAP_UDMA_ENABLE;
+
+ if (identify->command_set_supported1
+ & ATA_IDENTIFY_COMMAND_SET_SUPPORTED1_48BIT_ENABLE)
+ {
+ capabilities |= SATI_DEVICE_CAP_48BIT_ENABLE;
+ }
+
+ if (identify->command_set_supported0
+ & ATA_IDENTIFY_COMMAND_SET_SUPPORTED0_SMART_ENABLE)
+ {
+ capabilities |= SATI_DEVICE_CAP_SMART_SUPPORT;
+ }
+
+ if (identify->command_set_enabled0
+ & ATA_IDENTIFY_COMMAND_SET_SUPPORTED0_SMART_ENABLE)
+ {
+ capabilities |= SATI_DEVICE_CAP_SMART_ENABLE;
+ }
+
+ // Save the NCQ related capabilities information.
+ if (identify->serial_ata_capabilities
+ & ATA_IDENTIFY_SATA_CAPABILITIES_NCQ_ENABLE)
+ {
+ if (device->capabilities & SATI_DEVICE_CAP_NCQ_REQUESTED_ENABLE)
+ {
+ capabilities |= SATI_DEVICE_CAP_NCQ_REQUESTED_ENABLE;
+ capabilities |= SATI_DEVICE_CAP_NCQ_SUPPORTED_ENABLE;
+ capabilities |= SATI_DEVICE_CAP_DMA_FUA_ENABLE;
+ device->ncq_depth = MIN(
+ device->ncq_depth,
+ (U8) (identify->queue_depth
+ & ATA_IDENTIFY_NCQ_QUEUE_DEPTH_ENABLE) + 1
+ );
+ }
+ }
+
+ // if the user requested that FUA is ignored; transfer it so we don't lose on update.
+ if (device->capabilities & SATI_DEVICE_CAP_IGNORE_FUA)
+ capabilities |= SATI_DEVICE_CAP_IGNORE_FUA;
+
+ if (identify->general_config_bits & ATA_IDENTIFY_REMOVABLE_MEDIA_ENABLE)
+ capabilities |= SATI_DEVICE_CAP_REMOVABLE_MEDIA;
+
+ if(identify->command_set_supported2 & ATA_IDENTIFY_WRITE_UNCORRECTABLE_SUPPORT )
+ {
+ capabilities |= SATI_DEVICE_CAP_WRITE_UNCORRECTABLE_ENABLE;
+ }
+
+ if(identify->physical_logical_sector_info &
+ ATA_IDENTIFY_LOGICAL_SECTOR_PER_PHYSICAL_SECTOR_ENABLE)
+ {
+ capabilities |= SATI_DEVICE_CAP_MULTIPLE_SECTORS_PER_PHYSCIAL_SECTOR;
+ }
+
+ if(identify->command_set_supported_extention &
+ ATA_IDENTIFY_COMMAND_SET_SMART_SELF_TEST_SUPPORTED)
+ {
+ capabilities |= SATI_DEVICE_CAP_SMART_SELF_TEST_SUPPORT;
+ }
+
+ if (identify->nominal_media_rotation_rate == 1)
+ {
+ capabilities |= SATI_DEVICE_CAP_SSD;
+ }
+
+ // Save off the logical block size reported by the drive
+ // See if Word 106 is valid and reports a logical sector size
+ if ((identify->physical_logical_sector_info & 0x5000) == 0x5000)
+ {
+ device->logical_block_size = (identify->words_per_logical_sector[3] << 24) |
+ (identify->words_per_logical_sector[2] << 16) |
+ (identify->words_per_logical_sector[1] << 8) |
+ (identify->words_per_logical_sector[0]);
+ }
+ else
+ {
+ device->logical_block_size = 512;
+ }
+
+ // Determine DSM TRIM capabilities
+ // Defend against SSDs which report TRIM support, but set
+ // max_lba_range_entry_blocks to zero, by disabling TRIM for
+ // those SSDs.
+ if (
+ (identify->data_set_management & ATA_IDENTIFY_COMMAND_SET_DSM_TRIM_SUPPORTED)
+ && (identify->max_lba_range_entry_blocks > 0)
+ )
+ {
+ capabilities |= SATI_DEVICE_CAP_DSM_TRIM_SUPPORT;
+ device->max_lba_range_entry_blocks = identify->max_lba_range_entry_blocks;
+ }
+
+ if (identify->additional_supported
+ & ATA_IDENTIFY_COMMAND_ADDL_SUPPORTED_DETERMINISTIC_READ)
+ {
+ capabilities |= SATI_DEVICE_CAP_DETERMINISTIC_READ_AFTER_TRIM;
+ }
+
+ if (identify->additional_supported
+ & ATA_IDENTIFY_COMMAND_ADDL_SUPPORTED_READ_ZERO)
+ {
+ capabilities |= SATI_DEVICE_CAP_READ_ZERO_AFTER_TRIM;
+ }
+
+ if (identify->capabilities1
+ & ATA_IDENTIFY_CAPABILITIES1_STANDBY_ENABLE)
+ {
+ capabilities |= SATI_DEVICE_CAP_STANDBY_ENABLE;
+ }
+
+ device->min_blocks_per_microcode_command = identify->min_num_blocks_per_microcode;
+ device->max_blocks_per_microcode_command = identify->max_num_blocks_per_microcode;
+
+ device->capabilities = capabilities;
+}
+
diff --git a/sys/dev/isci/scil/sati_device.h b/sys/dev/isci/scil/sati_device.h
new file mode 100644
index 0000000..980ca44
--- /dev/null
+++ b/sys/dev/isci/scil/sati_device.h
@@ -0,0 +1,203 @@
+/*-
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 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.
+ *
+ * $FreeBSD$
+ */
+#ifndef _SATI_DEVICE_H_
+#define _SATI_DEVICE_H_
+
+/**
+ * @file
+ * @brief 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 <dev/isci/scil/sati_types.h>
+#include <dev/isci/scil/intel_ata.h>
+
+/**
+ * @enum _SATI_DEVICE_STATE
+ *
+ * @brief This enumeration depicts the various states possible for the a
+ * translation remote device object.
+ */
+typedef 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_STATE;
+
+/**
+ * @name 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
+#define SATI_DEVICE_CAP_SSD 0x00000800
+#define SATI_DEVICE_CAP_DSM_TRIM_SUPPORT 0x00001000
+#define SATI_DEVICE_CAP_DETERMINISTIC_READ_AFTER_TRIM 0x00002000
+#define SATI_DEVICE_CAP_READ_ZERO_AFTER_TRIM 0x00004000
+#define SATI_DEVICE_CAP_STANDBY_ENABLE 0x00008000
+#define SATI_DEVICE_CAP_IGNORE_FUA 0x00010000
+
+
+/*@}*/
+
+/**
+ * @struct SATI_DEVICE
+ *
+ * @brief The SATI_DEVICE structure define the state of the remote device
+ * with respect to translation.
+ */
+typedef struct SATI_DEVICE
+{
+ /**
+ * This field simply dictates the state of the SATI device.
+ */
+ 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;
+
+ /**
+ * This field indicates the ATA standby timer value set throught the
+ * ATA IDLE and ATA Standby commands
+ */
+ U8 ata_standby_timer;
+
+ /**
+ * This field indicates the maximum number of data set management
+ * descriptor entries the device supports in blocks.
+ */
+ U16 max_lba_range_entry_blocks;
+
+ /**
+ * The field is the reported logical block size for the device
+ */
+ U32 logical_block_size;
+
+ /**
+ * This field is the maximum number of blocks per Download Microcode command
+ * for this device.
+ */
+ U16 max_blocks_per_microcode_command;
+
+ /**
+ * This field is the minimum number of blocks per Download Microcode command
+ * for this device.
+ */
+ U16 min_blocks_per_microcode_command;
+
+ /**
+ * This field indicates the type of constructed sense data if enabled descriptor
+ * sense data will be constructed
+ */
+ U8 descriptor_sense_enable;
+
+} SATI_DEVICE_T;
+
+void sati_device_construct(
+ SATI_DEVICE_T * device,
+ BOOL is_ncq_enabled,
+ U8 max_ncq_depth,
+ BOOL ignore_fua
+);
+
+void sati_device_update_capabilities(
+ SATI_DEVICE_T * device,
+ ATA_IDENTIFY_DEVICE_DATA_T * identify
+);
+
+#endif // _SATI_TRANSLATOR_SEQUENCE_H_
+
diff --git a/sys/dev/isci/scil/sati_inquiry.c b/sys/dev/isci/scil/sati_inquiry.c
new file mode 100644
index 0000000..8da6325
--- /dev/null
+++ b/sys/dev/isci/scil/sati_inquiry.c
@@ -0,0 +1,799 @@
+/*-
+ * 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.
+ *
+ * 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 <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/**
+ * @file
+ *
+ * @brief This file contains the method implementations required to
+ * translate the SCSI inquiry command.
+ * The following (VPD) pages are currently supported:
+ * - Standard
+ * - Supported Pages
+ * - Unit Serial Number
+ * - Device Identification
+ */
+
+#if !defined(DISABLE_SATI_INQUIRY)
+
+#include <dev/isci/scil/sati_inquiry.h>
+#include <dev/isci/scil/sati_callbacks.h>
+#include <dev/isci/scil/sati_util.h>
+#include <dev/isci/scil/intel_ata.h>
+#include <dev/isci/scil/intel_scsi.h>
+
+//******************************************************************************
+//* P R I V A T E M E T H O D S
+//******************************************************************************
+/**
+* @brief This method builds the SCSI data associated with the SATI product
+* revision that is commonly used on the Standard inquiry response and
+* the ATA information page.
+*
+* @param[in] sequence This parameter specifies the translator sequence
+* object to be utilized during data translation.
+* @param[in] ata_input_data This parameter specifies ata data received from
+* the remote device.
+* @param[out] scsi_io This parameter specifies the user IO request for
+* which to construct the standard inquiry data.
+*
+* @return none
+*/
+static
+void sati_inquiry_construct_product_revision(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * ata_input_data,
+ void * scsi_io
+)
+{
+ ATA_IDENTIFY_DEVICE_DATA_T * identify = (ATA_IDENTIFY_DEVICE_DATA_T*)
+ ata_input_data;
+
+ // Fill in the product revision level field.
+ // Per SAT, copy portions of the firmware revision that is not filled
+ // with spaces. Some devices left-align their firmware rev ID, while
+ // others right-align.
+ if ( (identify->firmware_revision[4] == 0x20)
+ && (identify->firmware_revision[5] == 0x20)
+ && (identify->firmware_revision[6] == 0x20)
+ && (identify->firmware_revision[7] == 0x20) )
+ {
+ sati_ata_identify_device_copy_data(
+ sequence,
+ scsi_io,
+ 32,
+ ata_input_data,
+ ATA_IDENTIFY_DEVICE_GET_OFFSET(firmware_revision),
+ 4,
+ TRUE
+ );
+ }
+ else
+ {
+ // Since the last 4 bytes of the firmware revision are not spaces,
+ // utilize these bytes as the firmware revision in the inquiry data.
+ sati_ata_identify_device_copy_data(
+ sequence,
+ scsi_io,
+ 32,
+ ata_input_data,
+ ATA_IDENTIFY_DEVICE_GET_OFFSET(firmware_revision)+4,
+ 4,
+ TRUE
+ );
+ }
+}
+
+
+//******************************************************************************
+//* P U B L I C M E T H O D S
+//******************************************************************************
+
+/**
+ * @brief This method builds the SCSI data associated with a SCSI standard
+ * inquiry request.
+ *
+ * @param[in] sequence This parameter specifies the translator sequence
+ * object to be utilized during data translation.
+ * @param[in] ata_input_data This parameter specifies ata data received from
+ * the remote device.
+ * @param[out] scsi_io This parameter specifies the user IO request for
+ * which to construct the standard inquiry data.
+ *
+ * @return none
+ */
+void sati_inquiry_standard_translate_data(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * ata_input_data,
+ void * scsi_io
+)
+{
+ ATA_IDENTIFY_DEVICE_DATA_T * identify = (ATA_IDENTIFY_DEVICE_DATA_T*)
+ ata_input_data;
+ U32 index;
+
+ // Device type is disk, attached to this lun.
+ sati_set_data_byte(sequence, scsi_io, 0, 0x00);
+
+ // If the device indicates it's a removable media device, then set the
+ // RMB bit
+ if (identify->general_config_bits & ATA_IDENTIFY_REMOVABLE_MEDIA_ENABLE)
+ sati_set_data_byte(sequence, scsi_io, 1, 0x80);
+ else
+ sati_set_data_byte(sequence, scsi_io, 1, 0x00);
+
+ sati_set_data_byte(sequence, scsi_io, 2, 0x05); // Indicate SPC-3 support
+ sati_set_data_byte(sequence, scsi_io, 3, 0x02); // Response Format SPC-3
+
+ sati_set_data_byte(sequence, scsi_io, 4, 62); // 62 Additional Data Bytes.
+ // n-4 per the spec, we end at
+ // byte 66, so 66-4.
+ sati_set_data_byte(sequence, scsi_io, 5, 0x00);
+ sati_set_data_byte(sequence, scsi_io, 6, 0x00);
+ sati_set_data_byte(sequence, scsi_io, 7, 0x02); // Enable Cmd Queueing
+
+ // The Vender identification field is set to "ATA "
+ sati_set_data_byte(sequence, scsi_io, 8, 0x41);
+ sati_set_data_byte(sequence, scsi_io, 9, 0x54);
+ sati_set_data_byte(sequence, scsi_io, 10, 0x41);
+ sati_set_data_byte(sequence, scsi_io, 11, 0x20);
+ sati_set_data_byte(sequence, scsi_io, 12, 0x20);
+ sati_set_data_byte(sequence, scsi_io, 13, 0x20);
+ sati_set_data_byte(sequence, scsi_io, 14, 0x20);
+ sati_set_data_byte(sequence, scsi_io, 15, 0x20);
+
+ // Fill in the product ID field.
+ sati_ata_identify_device_copy_data(
+ sequence,
+ scsi_io,
+ 16,
+ ata_input_data,
+ ATA_IDENTIFY_DEVICE_GET_OFFSET(model_number),
+ 16,
+ TRUE
+ );
+
+ sati_inquiry_construct_product_revision(
+ sequence,
+ ata_input_data,
+ scsi_io
+ );
+
+ // Set the remaining fields up to the version descriptors to 0.
+ for (index = 36; index < 58; index++)
+ sati_set_data_byte(sequence, scsi_io, index, 0);
+
+ // Add version descriptors for the various protocols in play.
+
+ // SAM-4
+ sati_set_data_byte(sequence, scsi_io, 58, 0);
+ sati_set_data_byte(sequence, scsi_io, 59, 0x80);
+
+ // SAS-2
+ sati_set_data_byte(sequence, scsi_io, 60, 0x0C);
+ sati_set_data_byte(sequence, scsi_io, 61, 0x20);
+
+ // SPC-4
+ sati_set_data_byte(sequence, scsi_io, 62, 0x04);
+ sati_set_data_byte(sequence, scsi_io, 63, 0x60);
+
+ // SBC-3
+ sati_set_data_byte(sequence, scsi_io, 64, 0x04);
+ sati_set_data_byte(sequence, scsi_io, 65, 0xC0);
+
+ // ATA/ATAPI-8 ACS
+ sati_set_data_byte(sequence, scsi_io, 66, 0x16);
+ sati_set_data_byte(sequence, scsi_io, 67, 0x23);
+}
+
+/**
+ * @brief This method builds the SCSI data associated with an SCSI inquiry
+ * for the supported VPD pages page.
+ *
+ * @param[in] sequence This parameter specifies the translator sequence
+ * object to be utilized during data translation.
+ * @param[out] scsi_io This parameter specifies the user IO request for
+ * which to construct the supported VPD page information.
+ *
+ * @return none
+ */
+static
+void sati_inquiry_supported_pages_translate_data(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io
+)
+{
+ // Formulate the SCSI output data for the caller.
+ sati_set_data_byte(sequence, scsi_io, 0, 0); // Qualifier and Device Type
+ sati_set_data_byte(sequence, scsi_io, 1, SCSI_INQUIRY_SUPPORTED_PAGES_PAGE);
+ sati_set_data_byte(sequence, scsi_io, 2, 0); // Reserved.
+ sati_set_data_byte(sequence, scsi_io, 3, 4); // # VPD pages supported
+ sati_set_data_byte(sequence, scsi_io, 4, SCSI_INQUIRY_SUPPORTED_PAGES_PAGE);
+ sati_set_data_byte(sequence, scsi_io, 5, SCSI_INQUIRY_UNIT_SERIAL_NUM_PAGE);
+ sati_set_data_byte(sequence, scsi_io, 6, SCSI_INQUIRY_DEVICE_ID_PAGE);
+ sati_set_data_byte(sequence, scsi_io, 7, SCSI_INQUIRY_ATA_INFORMATION_PAGE);
+ sati_set_data_byte(sequence, scsi_io, 8, SCSI_INQUIRY_BLOCK_DEVICE_PAGE);
+ sati_set_data_byte(sequence, scsi_io, 9, 0); // End of the list
+}
+
+/**
+ * @brief This method builds the SCSI data associated with a request for
+ * the unit serial number vital product data (VPD) page.
+ *
+ * @param[in] sequence This parameter specifies the translator sequence
+ * object to be utilized during data translation.
+ * @param[in] ata_input_data This parameter specifies ata data received from
+ * the remote device.
+ * @param[out] scsi_io This parameter specifies the user IO request for
+ * which to construct the unit serial number data.
+ *
+ * @return none
+ */
+void sati_inquiry_serial_number_translate_data(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * ata_input_data,
+ void * scsi_io
+)
+{
+ // Peripheral qualifier (0x0, currently connected)
+ // Peripheral device type (0x0 direct-access block device)
+ sati_set_data_byte(sequence, scsi_io, 0, 0x00);
+
+ sati_set_data_byte(sequence, scsi_io, 1, SCSI_INQUIRY_UNIT_SERIAL_NUM_PAGE);
+ sati_set_data_byte(sequence, scsi_io, 2, 0x00); // Reserved
+ sati_set_data_byte(sequence, scsi_io, 3, ATA_IDENTIFY_SERIAL_NUMBER_LEN);
+
+ sati_ata_identify_device_copy_data(
+ sequence,
+ scsi_io,
+ 4,
+ ata_input_data,
+ ATA_IDENTIFY_DEVICE_GET_OFFSET(serial_number),
+ ATA_IDENTIFY_SERIAL_NUMBER_LEN,
+ TRUE
+ );
+}
+
+/**
+* @brief This method builds the SCSI data associated with a request for
+* the Block Device Characteristics vital product data (VPD) page.
+*
+* @param[in] sequence This parameter specifies the translator sequence
+* object to be utilized during data translation.
+* @param[in] ata_input_data This parameter specifies ata data received from
+* the remote device.
+* @param[out] scsi_io This parameter specifies the user IO request for
+* which to construct the unit serial number data.
+*
+* @return none
+*/
+void sati_inquiry_block_device_translate_data(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * ata_input_data,
+ void * scsi_io
+)
+{
+ ATA_IDENTIFY_DEVICE_DATA_T * identify = (ATA_IDENTIFY_DEVICE_DATA_T*)
+ ata_input_data;
+
+ U32 offset;
+
+ // Peripheral qualifier (0x0, currently connected)
+ // Peripheral device type (0x0 direct-access block device)
+ sati_set_data_byte(sequence, scsi_io, 0, 0x00);
+
+ sati_set_data_byte(sequence, scsi_io, 1, SCSI_INQUIRY_BLOCK_DEVICE_PAGE);
+
+ //PAGE LENGTH 0x003C
+ sati_set_data_byte(sequence, scsi_io, 2, 0x00);
+ sati_set_data_byte(sequence, scsi_io, 3, SCSI_INQUIRY_BLOCK_DEVICE_LENGTH);
+
+ sati_ata_identify_device_copy_data(
+ sequence,
+ scsi_io,
+ 4,
+ ata_input_data,
+ ATA_IDENTIFY_DEVICE_GET_OFFSET(nominal_media_rotation_rate),
+ 2,
+ FALSE
+ );
+
+ sati_set_data_byte(sequence, scsi_io, 6, 0x00);
+
+ sati_set_data_byte(
+ sequence,
+ scsi_io,
+ 7,
+ (identify->device_nominal_form_factor & 0x0F) // only need bits 0-3
+ );
+
+ //bytes 8-63 are reserved
+ for(offset = 8; offset < 63; offset++)
+ {
+ sati_set_data_byte(sequence, scsi_io, offset, 0x00);
+ }
+}
+
+/**
+ * @brief This method builds the SCSI data associated with a request for
+ * the device identification vital product data (VPD) page.
+ *
+ * @param[in] sequence This parameter specifies the translator sequence
+ * object to be utilized during data translation.
+ * @param[in] ata_input_data This parameter specifies ata data received from
+ * the remote device.
+ * @param[out] scsi_io This parameter specifies the user IO request for
+ * which to construct the device ID page.
+ *
+ * @return none
+ */
+void sati_inquiry_device_id_translate_data(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * ata_input_data,
+ void * scsi_io
+)
+{
+ ATA_IDENTIFY_DEVICE_DATA_T * identify = (ATA_IDENTIFY_DEVICE_DATA_T*)
+ ata_input_data;
+ U16 byte_offset = 4;
+ U16 page_length;
+
+ // Peripheral qualifier (0x0, currently connected)
+ // Peripheral device type (0x0 direct-access block device)
+ sati_set_data_byte(sequence, scsi_io, 0, 0x00);
+
+ sati_set_data_byte(sequence, scsi_io, 1, SCSI_INQUIRY_DEVICE_ID_PAGE);
+
+ /**
+ * If World Wide Names are supported by this target, then build an
+ * identification descriptor using the WWN.
+ */
+
+ if (identify->command_set_supported_extention
+ & ATA_IDENTIFY_COMMAND_SET_WWN_SUPPORT_ENABLE)
+ {
+
+ sati_set_data_byte(sequence,
+ scsi_io, 4, SCSI_FC_PROTOCOL_IDENTIFIER | SCSI_BINARY_CODE_SET
+ );
+
+
+ sati_set_data_byte(sequence,
+ scsi_io, 5, SCSI_LUN_ASSOCIATION | SCSI_NAA_IDENTIFIER_TYPE
+ );
+
+ sati_set_data_byte(sequence, scsi_io, 6, 0);
+ sati_set_data_byte(sequence, scsi_io, 7, 0x08); // WWN are 8 bytes long
+
+ // Copy data from the identify device world wide name field into the
+ // buffer.
+ sati_ata_identify_device_copy_data(
+ sequence,
+ scsi_io,
+ 8,
+ ata_input_data,
+ ATA_IDENTIFY_DEVICE_GET_OFFSET(world_wide_name),
+ ATA_IDENTIFY_WWN_LEN,
+ FALSE
+ );
+
+ byte_offset = 16;
+ }
+
+ /**
+ * Build a identification descriptor using the model number & serial number.
+ */
+
+ sati_set_data_byte(sequence,
+ scsi_io, byte_offset, SCSI_FC_PROTOCOL_IDENTIFIER | SCSI_ASCII_CODE_SET
+ );
+ byte_offset++;
+ sati_set_data_byte(sequence,
+ scsi_io, byte_offset, SCSI_LUN_ASSOCIATION | SCSI_T10_IDENTIFIER_TYPE
+ );
+ byte_offset++;
+ sati_set_data_byte(sequence, scsi_io, byte_offset, 0);
+ byte_offset++;
+
+ // Identifier length (8 bytes for "ATA " + 40 bytes from ATA IDENTIFY
+ // model number field + 20 bytes from ATA IDENTIFY serial number field.
+ sati_set_data_byte(
+ sequence,
+ scsi_io,
+ byte_offset,
+ 8 + (ATA_IDENTIFY_SERIAL_NUMBER_LEN) + (ATA_IDENTIFY_MODEL_NUMBER_LEN)
+ );
+ byte_offset++;
+
+ // Per SAT, write "ATA ".
+ sati_set_data_byte(sequence, scsi_io, byte_offset, 0x41);
+ byte_offset++;
+ sati_set_data_byte(sequence, scsi_io, byte_offset, 0x54);
+ byte_offset++;
+ sati_set_data_byte(sequence, scsi_io, byte_offset, 0x41);
+ byte_offset++;
+ sati_set_data_byte(sequence, scsi_io, byte_offset, 0x20);
+ byte_offset++;
+ sati_set_data_byte(sequence, scsi_io, byte_offset, 0x20);
+ byte_offset++;
+ sati_set_data_byte(sequence, scsi_io, byte_offset, 0x20);
+ byte_offset++;
+ sati_set_data_byte(sequence, scsi_io, byte_offset, 0x20);
+ byte_offset++;
+ sati_set_data_byte(sequence, scsi_io, byte_offset, 0x20);
+ byte_offset++;
+
+ // Copy data from the identify device model number field into the
+ // buffer and update the byte_offset.
+ sati_ata_identify_device_copy_data(
+ sequence,
+ scsi_io,
+ byte_offset,
+ ata_input_data,
+ ATA_IDENTIFY_DEVICE_GET_OFFSET(model_number),
+ ATA_IDENTIFY_MODEL_NUMBER_LEN,
+ TRUE
+ );
+
+ byte_offset += ATA_IDENTIFY_MODEL_NUMBER_LEN;
+
+ // Copy data from the identify device serial number field into the
+ // buffer and update the byte_offset.
+ sati_ata_identify_device_copy_data(
+ sequence,
+ scsi_io,
+ byte_offset,
+ ata_input_data,
+ ATA_IDENTIFY_DEVICE_GET_OFFSET(serial_number),
+ ATA_IDENTIFY_SERIAL_NUMBER_LEN,
+ TRUE
+ );
+
+ byte_offset += ATA_IDENTIFY_SERIAL_NUMBER_LEN;
+
+ /**
+ * If the target is contained in a SAS Domain, then build a target port
+ * ID descriptor using the SAS address.
+ */
+
+#if defined(SATI_TRANSPORT_SUPPORTS_SAS) \
+ && defined(DISABLE_MSFT_SCSI_COMPLIANCE_SUPPORT)
+ {
+ SCI_SAS_ADDRESS_T sas_address;
+
+ sati_set_data_byte(
+ sequence,
+ scsi_io,
+ byte_offset,
+ SCSI_SAS_PROTOCOL_IDENTIFIER | SCSI_BINARY_CODE_SET
+ );
+ byte_offset++;
+
+ sati_set_data_byte(
+ sequence,
+ scsi_io,
+ byte_offset,
+ SCSI_PIV_ENABLE | SCSI_TARGET_PORT_ASSOCIATION |
+ SCSI_NAA_IDENTIFIER_TYPE
+ );
+
+ byte_offset++;
+ sati_set_data_byte(sequence, scsi_io, byte_offset, 0);
+ byte_offset++;
+ sati_set_data_byte(sequence, scsi_io, byte_offset, 8); // SAS Addr=8 bytes
+ byte_offset++;
+
+ sati_cb_device_get_sas_address(scsi_io, &sas_address);
+
+ // Store the SAS address in the target port descriptor.
+ sati_set_data_dword(sequence, scsi_io, byte_offset, sas_address.high);
+ byte_offset += 4;
+ sati_set_data_dword(sequence, scsi_io, byte_offset, sas_address.low);
+ byte_offset += 4;
+ }
+#endif // SATI_TRANSPORT_SUPPORTS_SAS && DISABLE_MSFT_SCSI_COMPLIANCE_SUPPORT
+
+ /**
+ * Set the Page length field. The page length is n-3, where n is the
+ * last offset in the page (considered page length - 4).
+ */
+
+ page_length = byte_offset - 4;
+ sati_set_data_byte(sequence, scsi_io, 2, (U8)((page_length & 0xFF00) >> 8));
+ sati_set_data_byte(sequence, scsi_io, 3, (U8)(page_length & 0x00FF));
+}
+
+/**
+* @brief This method builds the SCSI data associated with a request for
+* the ATA information vital product data (VPD) page.
+*
+* @param[in] sequence This parameter specifies the translator sequence
+* object to be utilized during data translation.
+* @param[in] ata_input_data This parameter specifies ata data received from
+* a identify device command processed by the remote device.
+* @param[out] scsi_io This parameter specifies the user IO request for
+* which to construct the ATA information page.
+*
+* @return none
+*/
+SATI_STATUS sati_inquiry_ata_information_translate_data(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * ata_input_data,
+ void * scsi_io
+)
+{
+ sati_set_data_byte(sequence, scsi_io, 0, 0x00);
+ sati_set_data_byte(sequence, scsi_io, 1, SCSI_INQUIRY_ATA_INFORMATION_PAGE);
+ sati_set_data_byte(sequence, scsi_io, 2, 0x02);
+ sati_set_data_byte(sequence, scsi_io, 3, 0x38);
+
+ //Reserved SAT2r07
+ sati_set_data_byte(sequence, scsi_io, 4, 0x00);
+ sati_set_data_byte(sequence, scsi_io, 5, 0x00);
+ sati_set_data_byte(sequence, scsi_io, 6, 0x00);
+ sati_set_data_byte(sequence, scsi_io, 7, 0x00);
+
+ // The Vender identification field is set to "ATA "
+ sati_set_data_byte(sequence, scsi_io, 8, 0x41);
+ sati_set_data_byte(sequence, scsi_io, 9, 0x54);
+ sati_set_data_byte(sequence, scsi_io, 10, 0x41);
+ sati_set_data_byte(sequence, scsi_io, 11, 0x20);
+ sati_set_data_byte(sequence, scsi_io, 12, 0x20);
+ sati_set_data_byte(sequence, scsi_io, 13, 0x20);
+ sati_set_data_byte(sequence, scsi_io, 14, 0x20);
+ sati_set_data_byte(sequence, scsi_io, 15, 0x20);
+
+ //SAT Product identification
+ sati_ata_identify_device_copy_data(
+ sequence,
+ scsi_io,
+ 16,
+ ata_input_data,
+ ATA_IDENTIFY_DEVICE_GET_OFFSET(model_number),
+ 16,
+ TRUE
+ );
+
+ //SAT Product Revision level bytes 32-35
+ sati_inquiry_construct_product_revision(
+ sequence,
+ ata_input_data,
+ scsi_io
+ );
+
+ //skipping ATA device signature for now
+
+ //Command code
+ sati_set_data_byte(sequence, scsi_io, 56, 0xEC);
+
+ //Reserved SAT2r07
+ sati_set_data_byte(sequence, scsi_io, 57, 0x00);
+ sati_set_data_byte(sequence, scsi_io, 58, 0x00);
+ sati_set_data_byte(sequence, scsi_io, 59, 0x00);
+
+ //copy all ATA identify device data
+ sati_ata_identify_device_copy_data(
+ sequence,
+ scsi_io,
+ 60,
+ ata_input_data,
+ 0,
+ sizeof(ATA_IDENTIFY_DEVICE_DATA_T),
+ FALSE
+ );
+
+ //Need to send ATA Execute Device Diagnostic command still
+ sequence->state = SATI_SEQUENCE_STATE_INCOMPLETE;
+
+ return SATI_SEQUENCE_INCOMPLETE;
+}
+
+/**
+ * @brief This method will translate the inquiry SCSI command into
+ * an ATA IDENTIFY DEVICE command. It will handle several different
+ * VPD pages and the standard inquiry page.
+ * For more information on the parameters passed to this method,
+ * please reference sati_translate_command().
+ *
+ * @return Indicate if the command translation succeeded.
+ * @retval SCI_SUCCESS This is returned if the command translation was
+ * successful.
+ * @retval SATI_FAILURE_CHECK_RESPONSE_DATA This value is returned if
+ * the page isn't supported, or the page code
+ * field is not zero when the EVPD bit is 0.
+ */
+SATI_STATUS sati_inquiry_translate_command(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ void * ata_io
+)
+{
+ U8 * cdb = sati_cb_get_cdb_address(scsi_io);
+
+ /**
+ * SPC dictates:
+ * - that the page code field must be 0, if VPD enable is 0.
+ */
+ if ( ((sati_get_cdb_byte(cdb, 1) & SCSI_INQUIRY_EVPD_ENABLE) == 0)
+ && (sati_get_cdb_byte(cdb, 2) != 0) )
+ {
+ sati_scsi_sense_data_construct(
+ sequence,
+ scsi_io,
+ SCSI_STATUS_CHECK_CONDITION,
+ SCSI_SENSE_ILLEGAL_REQUEST,
+ SCSI_ASC_INVALID_FIELD_IN_CDB,
+ SCSI_ASCQ_INVALID_FIELD_IN_CDB
+ );
+ return SATI_FAILURE_CHECK_RESPONSE_DATA;
+ }
+
+ // Set the data length based on the allocation length field in the CDB.
+ sequence->allocation_length = (sati_get_cdb_byte(cdb, 3) << 8) |
+ (sati_get_cdb_byte(cdb, 4));
+
+ // Check to see if there was a request for the vital product data or just
+ // the standard inquiry.
+ if (sati_get_cdb_byte(cdb, 1) & SCSI_INQUIRY_EVPD_ENABLE)
+ {
+ // Parse the page code to determine which translator to invoke.
+ switch (sati_get_cdb_byte(cdb, 2))
+ {
+ case SCSI_INQUIRY_SUPPORTED_PAGES_PAGE:
+ sequence->type = SATI_SEQUENCE_INQUIRY_SUPPORTED_PAGES;
+ sati_inquiry_supported_pages_translate_data(sequence, scsi_io);
+ return SATI_COMPLETE;
+ break;
+
+ case SCSI_INQUIRY_UNIT_SERIAL_NUM_PAGE:
+ sequence->type = SATI_SEQUENCE_INQUIRY_SERIAL_NUMBER;
+ break;
+
+ case SCSI_INQUIRY_DEVICE_ID_PAGE:
+ sequence->type = SATI_SEQUENCE_INQUIRY_DEVICE_ID;
+ break;
+
+ case SCSI_INQUIRY_ATA_INFORMATION_PAGE:
+
+ if(sequence->state == SATI_SEQUENCE_STATE_INCOMPLETE)
+ {
+ sati_ata_execute_device_diagnostic_construct(
+ ata_io,
+ sequence
+ );
+ sequence->type = SATI_SEQUENCE_INQUIRY_EXECUTE_DEVICE_DIAG;
+ }
+ else
+ {
+ sequence->type = SATI_SEQUENCE_INQUIRY_ATA_INFORMATION;
+ }
+ break;
+
+ case SCSI_INQUIRY_BLOCK_DEVICE_PAGE:
+ sequence->type = SATI_SEQUENCE_INQUIRY_BLOCK_DEVICE;
+ break;
+
+ default:
+ sati_scsi_sense_data_construct(
+ sequence,
+ scsi_io,
+ SCSI_STATUS_CHECK_CONDITION,
+ SCSI_SENSE_ILLEGAL_REQUEST,
+ SCSI_ASC_INVALID_FIELD_IN_CDB,
+ SCSI_ASCQ_INVALID_FIELD_IN_CDB
+ );
+ return SATI_FAILURE_CHECK_RESPONSE_DATA;
+ break;
+ }
+ }
+ else
+ {
+ sequence->type = SATI_SEQUENCE_INQUIRY_STANDARD;
+ }
+
+ sati_ata_identify_device_construct(ata_io, sequence);
+
+ return SATI_SUCCESS;
+}
+
+/**
+* @brief This method finishes the construction of the SCSI data associated
+ with a request for the ATA information vital product data (VPD) page.
+ The ATA device signature is written into the data response from the
+ task fle registers after issuing a Execute Device Diagnostic command.
+*
+* @param[in] sequence This parameter specifies the translator sequence
+* object to be utilized during data translation.
+* @param[out] scsi_io This parameter specifies the user IO request for
+* which to construct the ATA information page.
+* @param[in] ata_io This parameter specifies the ATA payload
+* buffer location and size to be translated.
+*
+* @return none
+*/
+void sati_inquiry_ata_information_finish_translation(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ void * ata_io
+)
+{
+ U8 * register_fis = sati_cb_get_d2h_register_fis_address(ata_io);
+ U32 offset;
+
+ //SATA transport
+ sati_set_data_byte(sequence, scsi_io, 36, 0x34);
+ sati_set_data_byte(sequence, scsi_io, 37, 0x00);
+ sati_set_data_byte(sequence, scsi_io, 38, (U8) sati_get_ata_status(register_fis));
+ sati_set_data_byte(sequence, scsi_io, 39, (U8) sati_get_ata_error(register_fis));
+ sati_set_data_byte(sequence, scsi_io, 40, sati_get_ata_lba_low(register_fis));
+ sati_set_data_byte(sequence, scsi_io, 41, sati_get_ata_lba_mid(register_fis));
+ sati_set_data_byte(sequence, scsi_io, 42, sati_get_ata_lba_high(register_fis));
+ sati_set_data_byte(sequence, scsi_io, 43, sati_get_ata_device(register_fis));
+ sati_set_data_byte(sequence, scsi_io, 44, sati_get_ata_lba_low_ext(register_fis));
+ sati_set_data_byte(sequence, scsi_io, 45, sati_get_ata_lba_mid_ext(register_fis));
+ sati_set_data_byte(sequence, scsi_io, 46, sati_get_ata_lba_high_ext(register_fis));
+ sati_set_data_byte(sequence, scsi_io, 47, 0x00);
+ sati_set_data_byte(sequence, scsi_io, 48, sati_get_ata_sector_count(register_fis));
+ sati_set_data_byte(sequence, scsi_io, 49, sati_get_ata_sector_count_exp(register_fis));
+
+ for(offset = 50; offset < 56; offset++)
+ {
+ sati_set_data_byte(sequence, scsi_io, offset, 0x00);
+ }
+
+ sequence->state = SATI_SEQUENCE_STATE_FINAL;
+}
+
+#endif // !defined(DISABLE_SATI_INQUIRY)
+
diff --git a/sys/dev/isci/scil/sati_inquiry.h b/sys/dev/isci/scil/sati_inquiry.h
new file mode 100644
index 0000000..e3fc861
--- /dev/null
+++ b/sys/dev/isci/scil/sati_inquiry.h
@@ -0,0 +1,114 @@
+/*-
+ * 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.
+ *
+ * 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.
+ *
+ * $FreeBSD$
+ */
+#ifndef _SATI_INQUIRY_H_
+#define _SATI_INQUIRY_H_
+
+/**
+ * @file
+ *
+ * @brief This file contains the method prototypes required to
+ * translate the SCSI inquiry command.
+ * The following (VPD) pages are currently supported:
+ * - Standard
+ * - Supported Pages
+ * - Unit Serial Number
+ * - Device Identification
+ */
+
+#include <dev/isci/scil/sati_types.h>
+#include <dev/isci/scil/sati_translator_sequence.h>
+
+void sati_inquiry_standard_translate_data(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * ata_input_data,
+ void * scsi_io
+);
+
+void sati_inquiry_serial_number_translate_data(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * ata_input_data,
+ void * scsi_io
+);
+
+void sati_inquiry_device_id_translate_data(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * ata_input_data,
+ void * scsi_io
+);
+
+void sati_inquiry_block_device_translate_data(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * ata_input_data,
+ void * scsi_io
+);
+
+SATI_STATUS sati_inquiry_ata_information_translate_data(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * ata_input_data,
+ void * scsi_io
+);
+
+SATI_STATUS sati_inquiry_translate_command(
+ SATI_TRANSLATOR_SEQUENCE_T * translator_sequence,
+ void * scsi_io,
+ void * ata_io
+);
+
+void sati_inquiry_ata_information_finish_translation(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ void * ata_io
+);
+
+#endif // _SATI_INQUIRY_H_
diff --git a/sys/dev/isci/scil/sati_log_sense.c b/sys/dev/isci/scil/sati_log_sense.c
new file mode 100644
index 0000000..44bc4e9
--- /dev/null
+++ b/sys/dev/isci/scil/sati_log_sense.c
@@ -0,0 +1,807 @@
+/*-
+ * 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.
+ *
+ * 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 <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/**
+* @file
+* @brief This file contains the method definitions to translate
+* SCSI Log Sense command based of the SATv2 spec.
+*/
+
+#if !defined(DISABLE_SATI_LOG_SENSE)
+
+#include <dev/isci/scil/sati_log_sense.h>
+#include <dev/isci/scil/sati_callbacks.h>
+#include <dev/isci/scil/sati_util.h>
+
+//******************************************************************************
+//* P R I V A T E M E T H O D S
+//******************************************************************************
+
+/**
+ * @brief This method constructs the SATI supported log page. This is a log
+ * containing the page codes of all the SATI supported log pages.
+ *
+ * @return n/a
+ *
+ */
+static
+void sati_supported_log_page_construct(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io
+)
+{
+ U32 next_byte;
+ //set SPF = 0 and PAGE_CODE = 0
+ sati_set_data_byte(sequence, scsi_io, 0, 0x00);
+
+ //set SUBPAGE_CODE = 0
+ sati_set_data_byte(sequence, scsi_io, 1, 0x00);
+
+ //set the Page Length to (n-3) or 2 because only two log pages are supported
+ sati_set_data_byte(sequence, scsi_io, 2, 0x00);
+ sati_set_data_byte(sequence, scsi_io, 3, 0x02);
+
+ //specify the next byte to be set
+ next_byte = 4;
+
+ if(sequence->device->capabilities & SATI_DEVICE_CAP_SMART_SUPPORT)
+ {
+ sati_set_data_byte(
+ sequence,
+ scsi_io,
+ next_byte,
+ SCSI_LOG_PAGE_INFORMATION_EXCEPTION
+ );
+ next_byte = 5;
+ }
+
+ if(sequence->device->capabilities & SATI_DEVICE_CAP_SMART_SELF_TEST_SUPPORT)
+ {
+ sati_set_data_byte(
+ sequence,
+ scsi_io,
+ next_byte,
+ SCSI_LOG_PAGE_SELF_TEST
+ );
+ }
+}
+
+/**
+ * @brief This method sets bytes 4-19 of the self-test log parameter to zero.
+ *
+ * @return n/a
+ *
+ */
+static
+void sati_set_parameters_to_zero(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io
+)
+{
+ sati_set_data_byte(sequence, scsi_io, 8, 0x00); //log_parameter byte 4
+ sati_set_data_byte(sequence, scsi_io, 9, 0x00); //log_parameter byte 5
+ sati_set_data_byte(sequence, scsi_io, 10, 0x00); //log_parameter byte 6
+ sati_set_data_byte(sequence, scsi_io, 11, 0x00); //log_parameter byte 7
+ sati_set_data_byte(sequence, scsi_io, 12, 0x00); //log_parameter byte 8
+ sati_set_data_byte(sequence, scsi_io, 13, 0x00); //log_parameter byte 9
+ sati_set_data_byte(sequence, scsi_io, 14, 0x00); //log_parameter byte 10
+ sati_set_data_byte(sequence, scsi_io, 15, 0x00); //log_parameter byte 11
+ sati_set_data_byte(sequence, scsi_io, 16, 0x00); //log_parameter byte 12
+ sati_set_data_byte(sequence, scsi_io, 17, 0x00); //log_parameter byte 13
+ sati_set_data_byte(sequence, scsi_io, 18, 0x00); //log_parameter byte 14
+ sati_set_data_byte(sequence, scsi_io, 19, 0x00); //log_parameter byte 15
+ sati_set_data_byte(sequence, scsi_io, 20, 0x00); //log_parameter byte 16
+ sati_set_data_byte(sequence, scsi_io, 21, 0x00); //log_parameter byte 17
+ sati_set_data_byte(sequence, scsi_io, 22, 0x00); //log_parameter byte 18
+ sati_set_data_byte(sequence, scsi_io, 23, 0x00); //log_parameter byte 19
+}
+
+/**
+ * @brief This method translates the ATA Extended SMART self-test log into
+ * SCSI Sense Key, Additional Sense Code, and Additional Sense code
+ * qualifiers based on the self test status byte in the appropriate
+ * descriptor entry.
+ *
+ * @return n/a
+ *
+ */
+static
+void sati_translate_sense_values(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ U8 self_test_status_byte
+)
+{
+ //byte 17
+ sati_set_data_byte(
+ sequence,
+ scsi_io,
+ 21,
+ SCSI_DIAGNOSTIC_FAILURE_ON_COMPONENT
+ );
+
+ switch(self_test_status_byte)
+ {
+ case 1:
+ //byte 16
+ sati_set_data_byte(sequence, scsi_io, 20, SCSI_SENSE_ABORTED_COMMAND);
+
+ //byte 18
+ sati_set_data_byte(sequence, scsi_io, 22, 0x81);
+ break;
+
+ case 2:
+ //byte 16
+ sati_set_data_byte(sequence, scsi_io, 20, SCSI_SENSE_ABORTED_COMMAND);
+
+ //byte 18
+ sati_set_data_byte(sequence, scsi_io, 22, 0x82);
+ break;
+
+ case 3:
+ //byte 16
+ sati_set_data_byte(sequence, scsi_io, 20, SCSI_SENSE_ABORTED_COMMAND);
+
+ //byte 18
+ sati_set_data_byte(sequence, scsi_io, 22, 0x83);
+ break;
+
+ case 4:
+ //byte 16
+ sati_set_data_byte(sequence, scsi_io, 20, SCSI_SENSE_HARDWARE_ERROR);
+
+ //byte 18
+ sati_set_data_byte(sequence, scsi_io, 22, 0x84);
+ break;
+
+ case 5:
+ //byte 16
+ sati_set_data_byte(sequence, scsi_io, 20, SCSI_SENSE_HARDWARE_ERROR);
+
+ //byte 18
+ sati_set_data_byte(sequence, scsi_io, 22, 0x85);
+ break;
+
+ case 6:
+ //byte 16
+ sati_set_data_byte(sequence, scsi_io, 20, SCSI_SENSE_HARDWARE_ERROR);
+
+ //byte 18
+ sati_set_data_byte(sequence, scsi_io, 22, 0x86);
+ break;
+
+ case 7:
+ //byte 16
+ sati_set_data_byte(sequence, scsi_io, 20, SCSI_SENSE_MEDIUM_ERROR);
+
+ //byte 18
+ sati_set_data_byte(sequence, scsi_io, 22, 0x87);
+ break;
+
+ case 8:
+ //byte 16
+ sati_set_data_byte(sequence, scsi_io, 20, SCSI_SENSE_HARDWARE_ERROR);
+
+ //byte 18
+ sati_set_data_byte(sequence, scsi_io, 22, 0x88);
+ break;
+
+ default:
+ //byte 16
+ sati_set_data_byte(sequence, scsi_io, 20, SCSI_SENSE_NO_SENSE);
+ //byte 17
+ sati_set_data_byte(sequence, scsi_io, 21, SCSI_ASC_NO_ADDITIONAL_SENSE);
+ //byte 18
+ sati_set_data_byte(sequence, scsi_io, 22, 0x00);
+ break;
+ }
+
+}
+
+/**
+ * @brief This method retrieves the correct self-test results by checking the
+ * descriptor index in the extended SMART self-test log. The index is
+ * used to determine the appropriate descriptor entry.
+ *
+ * @return n/a
+ *
+ */
+static
+void sati_get_self_test_results(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ ATA_EXTENDED_SMART_SELF_TEST_LOG_T * ata_log
+)
+{
+ U16 descriptor_index = *((U16 *)(&ata_log->self_test_descriptor_index[0]));
+
+ /*
+ * SATv2 wants data from descriptor N where N is equal to
+ * (descriptor_index - parameter_code) + 1. Since parameter
+ * code is always 0x0001 just checking descriptor_index.
+ */
+
+ if(descriptor_index <= 0)
+ {
+ sati_set_parameters_to_zero(sequence, scsi_io);
+ }
+ else
+ {
+ sati_set_data_byte(
+ sequence,
+ scsi_io,
+ 8,
+ ata_log->descriptor_entrys[descriptor_index].DESCRIPTOR_ENTRY.status_byte
+ );
+
+ //Sef-test number unspecified per satv2
+ sati_set_data_byte(sequence, scsi_io, 9, 0x00);
+ sati_set_data_byte(
+ sequence,
+ scsi_io,
+ 10,
+ ata_log->descriptor_entrys[descriptor_index].DESCRIPTOR_ENTRY.time_stamp_high
+ );
+
+ sati_set_data_byte(
+ sequence,
+ scsi_io,
+ 11,
+ ata_log->descriptor_entrys[descriptor_index].DESCRIPTOR_ENTRY.time_stamp_low
+ );
+
+ //set to zero because it's a 48bit address
+ sati_set_data_byte(sequence, scsi_io, 12, 0x00);
+ sati_set_data_byte(sequence, scsi_io, 13, 0x00);
+
+ sati_set_data_byte(
+ sequence,
+ scsi_io,
+ 14,
+ ata_log->descriptor_entrys[descriptor_index].DESCRIPTOR_ENTRY.failing_lba_high_ext
+ );
+
+ sati_set_data_byte(
+ sequence,
+ scsi_io,
+ 15,
+ ata_log->descriptor_entrys[descriptor_index].DESCRIPTOR_ENTRY.failing_lba_mid_ext
+ );
+
+ sati_set_data_byte(
+ sequence,
+ scsi_io,
+ 16,
+ ata_log->descriptor_entrys[descriptor_index].DESCRIPTOR_ENTRY.failing_lba_low_ext
+ );
+
+ sati_set_data_byte(
+ sequence,
+ scsi_io,
+ 17,
+ ata_log->descriptor_entrys[descriptor_index].DESCRIPTOR_ENTRY.failing_lba_high
+ );
+
+ sati_set_data_byte(
+ sequence,
+ scsi_io,
+ 18,
+ ata_log->descriptor_entrys[descriptor_index].DESCRIPTOR_ENTRY.failing_lba_mid
+ );
+
+ sati_set_data_byte(
+ sequence,
+ scsi_io,
+ 19,
+ ata_log->descriptor_entrys[descriptor_index].DESCRIPTOR_ENTRY.failing_lba_low
+ );
+
+ sati_translate_sense_values(
+ sequence,
+ scsi_io,
+ ata_log->descriptor_entrys[descriptor_index].DESCRIPTOR_ENTRY.status_byte
+ );
+ }
+}
+
+/**
+* @brief This method will construct the first eight bytes of the SCSI self test
+* log page for both cases when SATI sends a ATA read log ext and a smart
+* read log command.
+*
+* @return n/a
+*
+*/
+static
+void sati_self_test_log_header_construct(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io
+)
+{
+ //PAGE CODE for Self-Test Log Page
+ sati_set_data_byte(sequence, scsi_io, 0, 0x10);
+ sati_set_data_byte(sequence, scsi_io, 1, 0x00);
+
+ //PAGE LENGTH is 0x14 instead of 0x190, not returning 20/0x190 log perameters
+ sati_set_data_byte(sequence, scsi_io, 2, 0x00);
+ sati_set_data_byte(sequence, scsi_io, 3, 0x14);
+
+ /*
+ * Log PARAMETER 0x0001
+ * Only sending one log parameter per self-test request.
+ */
+ sati_set_data_byte(sequence, scsi_io, 4, 0x00); //log_parameter byte 0
+ sati_set_data_byte(sequence, scsi_io, 5, 0x01); //log_parameter byte 1
+
+ //Set to 0x03 per SATv2 spec
+ sati_set_data_byte(sequence, scsi_io, 6, 0x03); //log_parameter byte 2
+
+ //Parameter Length set to 0x10 per SATv2 spec
+ sati_set_data_byte(sequence, scsi_io, 7, 0x10); //log_parameter byte 3
+}
+
+/**
+ * @brief This method will construct the SCSI self test log page from
+ * the Extended SMART self-test log response recieved from the
+ * ATA device. The response is from a ATA_Read_Log_EXT command
+ * issued by SATI.
+ *
+ * @return n/a
+ *
+ */
+static
+void sati_extended_self_test_log_page_construct(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ void * ata_data
+)
+{
+ ATA_EXTENDED_SMART_SELF_TEST_LOG_T * ata_log =
+ (ATA_EXTENDED_SMART_SELF_TEST_LOG_T*) ata_data;
+
+ sati_self_test_log_header_construct(sequence, scsi_io);
+
+ //bytes 4-19
+ if( (ata_log->self_test_descriptor_index[0] == 0) &&
+ (ata_log->self_test_descriptor_index[1] == 0))
+ {
+ sati_set_parameters_to_zero(sequence, scsi_io);
+ }
+ else
+ {
+ sati_get_self_test_results(sequence, scsi_io, ata_log);
+ }
+}
+
+/**
+* @brief This method will construct the SCSI self test log page from
+* the SMART self-test log response recieved from the ATA device.
+* The response is from a ATA_SMART_Read_Log command issued by SATI.
+*
+* @return n/a
+*
+*/
+static
+void sati_self_test_log_page_construct(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ void * ata_data
+)
+{
+ ATA_SMART_SELF_TEST_LOG_T * ata_log =
+ (ATA_SMART_SELF_TEST_LOG_T*) ata_data;
+
+ sati_self_test_log_header_construct(sequence, scsi_io);
+
+ //first descriptor entry(index == 0) is always used because scsi_parameter_code == 1
+ sati_set_data_byte(
+ sequence,
+ scsi_io,
+ 8,
+ ata_log->descriptor_entrys[0].SMART_DESCRIPTOR_ENTRY.status_byte
+ );
+
+ //Sef-test number unspecified per satv2
+ sati_set_data_byte(sequence, scsi_io, 9, 0x00);
+
+ sati_set_data_byte(
+ sequence,
+ scsi_io,
+ 10,
+ ata_log->descriptor_entrys[0].SMART_DESCRIPTOR_ENTRY.time_stamp_high
+ );
+
+ sati_set_data_byte(
+ sequence,
+ scsi_io,
+ 11,
+ ata_log->descriptor_entrys[0].SMART_DESCRIPTOR_ENTRY.time_stamp_low
+ );
+
+ //set to zero because it's a 28bit address
+ sati_set_data_byte(sequence, scsi_io, 12, 0x00);
+ sati_set_data_byte(sequence, scsi_io, 13, 0x00);
+ sati_set_data_byte(sequence, scsi_io, 14, 0x00);
+ sati_set_data_byte(sequence, scsi_io, 15, 0x00);
+
+ sati_set_data_byte(
+ sequence,
+ scsi_io,
+ 16,
+ ata_log->descriptor_entrys[0].SMART_DESCRIPTOR_ENTRY.failing_lba_low_ext
+ );
+
+ sati_set_data_byte(
+ sequence,
+ scsi_io,
+ 17,
+ ata_log->descriptor_entrys[0].SMART_DESCRIPTOR_ENTRY.failing_lba_high
+ );
+
+ sati_set_data_byte(
+ sequence,
+ scsi_io,
+ 18,
+ ata_log->descriptor_entrys[0].SMART_DESCRIPTOR_ENTRY.failing_lba_mid
+ );
+
+ sati_set_data_byte(
+ sequence,
+ scsi_io,
+ 19,
+ ata_log->descriptor_entrys[0].SMART_DESCRIPTOR_ENTRY.failing_lba_low
+ );
+
+ sati_translate_sense_values(
+ sequence,
+ scsi_io,
+ ata_log->descriptor_entrys[0].SMART_DESCRIPTOR_ENTRY.status_byte
+ );
+}
+
+/**
+* @brief This method will construct the SCSI information exception log page from
+* the ATA SMART response recieved from the ATA device. The response is
+* from a ATA SMART return status command issued by SATI.
+*
+* @return n/a
+*
+*/
+static
+void sati_information_exception_log_page_contruct(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ void * ata_io
+)
+{
+ U8 * register_fis = sati_cb_get_d2h_register_fis_address(ata_io);
+ U32 mid_register = sati_get_ata_lba_mid(register_fis);
+ U32 high_register = sati_get_ata_lba_high(register_fis);
+
+ //Information Exception Page code
+ sati_set_data_byte(
+ sequence,
+ scsi_io,
+ 0,
+ SCSI_LOG_PAGE_INFORMATION_EXCEPTION
+ );
+
+ //Sub-page code
+ sati_set_data_byte(sequence, scsi_io, 1, 0x00);
+
+ //Page length of log parameters
+ sati_set_data_byte(sequence, scsi_io, 2, 0x00);
+ sati_set_data_byte(sequence, scsi_io, 3, 0x08);
+
+ //parameter code
+ sati_set_data_byte(sequence, scsi_io, 4, 0x00);
+ sati_set_data_byte(sequence, scsi_io, 5, 0x00);
+
+ //Format and Linking
+ sati_set_data_byte(sequence, scsi_io, 6, 0x03);
+ //Parameter Length
+ sati_set_data_byte(sequence, scsi_io, 7, 0x04);
+
+ if(mid_register == ATA_MID_REGISTER_THRESHOLD_EXCEEDED
+ && high_register == ATA_HIGH_REGISTER_THRESHOLD_EXCEEDED)
+ {
+ sati_set_data_byte(
+ sequence,
+ scsi_io,
+ 8,
+ SCSI_ASC_HARDWARE_IMPENDING_FAILURE
+ );
+
+ sati_set_data_byte(
+ sequence,
+ scsi_io,
+ 9,
+ SCSI_ASCQ_GENERAL_HARD_DRIVE_FAILURE
+ );
+ }
+ else
+ {
+ sati_set_data_byte(sequence, scsi_io, 8, SCSI_ASC_NO_ADDITIONAL_SENSE);
+ sati_set_data_byte(sequence, scsi_io, 9, SCSI_ASCQ_NO_ADDITIONAL_SENSE);
+ }
+ //setting most recent temperature reading to 0xFF(not supported) for now.
+ sati_set_data_byte(sequence, scsi_io, 10, 0xFF);
+}
+
+//******************************************************************************
+//* P U B L I C M E T H O D S
+//******************************************************************************
+
+/**
+ * @brief This method will translate the SCSI Log Sense command into ATA commands
+ * specified by SATv2. ATA commands Read Log EXT and SMART Read Log will
+ * be issued by this translation.
+ *
+ * @return SATI_STATUS Indicates if the command translation succeeded.
+ *
+ */
+SATI_STATUS sati_log_sense_translate_command(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ void * ata_io
+)
+{
+ U8 * cdb = sati_cb_get_cdb_address(scsi_io);
+ SATI_STATUS status = SATI_FAILURE;
+
+ if(SATI_LOG_SENSE_GET_PC_FIELD(cdb) == 1 &&
+ (sati_get_cdb_byte(cdb, 3) == 0))
+ {
+ sequence->allocation_length = (sati_get_cdb_byte(cdb, 7) << 8) |
+ (sati_get_cdb_byte(cdb, 8));
+
+ switch(SATI_LOG_SENSE_GET_PAGE_CODE(cdb))
+ {
+ //Return Supported Log Pages log page
+ case SCSI_LOG_PAGE_SUPPORTED_PAGES :
+ sati_supported_log_page_construct(sequence, scsi_io);
+ sequence->type = SATI_SEQUENCE_LOG_SENSE_SUPPORTED_LOG_PAGE;
+ status = SATI_COMPLETE;
+ break;
+
+ //Return Self-Test Results log page
+ case SCSI_LOG_PAGE_SELF_TEST :
+
+ if((sequence->device->capabilities &
+ SATI_DEVICE_CAP_SMART_SELF_TEST_SUPPORT) == 0)
+ {
+ sati_scsi_sense_data_construct(
+ sequence,
+ scsi_io,
+ SCSI_STATUS_CHECK_CONDITION,
+ SCSI_SENSE_ILLEGAL_REQUEST,
+ SCSI_ASC_INVALID_FIELD_IN_CDB,
+ SCSI_ASCQ_INVALID_FIELD_IN_CDB
+ );
+ status = SATI_FAILURE_CHECK_RESPONSE_DATA;
+ }
+ else
+ {
+ //check if 48-bit Address feature set is supported
+ if((sequence->device->capabilities &
+ SATI_DEVICE_CAP_48BIT_ENABLE))
+ {
+ //ATA Read Log Ext with log address set to 0x07
+ sati_ata_read_log_ext_construct(
+ ata_io,
+ sequence,
+ ATA_LOG_PAGE_EXTENDED_SMART_SELF_TEST,
+ sizeof(ATA_EXTENDED_SMART_SELF_TEST_LOG_T)
+ );
+ sequence->type =
+ SATI_SEQUENCE_LOG_SENSE_EXTENDED_SELF_TEST_LOG_PAGE;
+ status = SATI_SUCCESS;
+ }
+ else
+ {
+ //ATA Smart Read Log with log address set to 0x06
+ sati_ata_smart_read_log_construct(
+ ata_io,
+ sequence,
+ ATA_LOG_PAGE_SMART_SELF_TEST,
+ sizeof(ATA_SMART_SELF_TEST_LOG_T)
+ );
+ sequence->type = SATI_SEQUENCE_LOG_SENSE_SELF_TEST_LOG_PAGE;
+ status = SATI_SUCCESS;
+ }
+ }
+ break;
+
+ //Return Informational Exceptions log page
+ case SCSI_LOG_PAGE_INFORMATION_EXCEPTION :
+ if(sequence->device->capabilities & SATI_DEVICE_CAP_SMART_SUPPORT)
+ {
+ if(sequence->device->capabilities & SATI_DEVICE_CAP_SMART_ENABLE)
+ {
+ sati_ata_smart_return_status_construct(
+ ata_io,
+ sequence,
+ ATA_SMART_SUB_CMD_RETURN_STATUS
+ );
+ sequence->type =
+ SATI_SEQUENCE_LOG_SENSE_INFO_EXCEPTION_LOG_PAGE;
+ status = SATI_SUCCESS;
+ }
+ else
+ {
+ sati_scsi_sense_data_construct(
+ sequence,
+ scsi_io,
+ SCSI_STATUS_CHECK_CONDITION,
+ SCSI_SENSE_ABORTED_COMMAND,
+ SCSI_ASC_ATA_DEVICE_FEATURE_NOT_ENABLED,
+ SCSI_ASCQ_ATA_DEVICE_FEATURE_NOT_ENABLED
+ );
+
+ status = SATI_FAILURE_CHECK_RESPONSE_DATA;
+ }
+ }
+ else
+ {
+ sati_scsi_sense_data_construct(
+ sequence,
+ scsi_io,
+ SCSI_STATUS_CHECK_CONDITION,
+ SCSI_SENSE_ILLEGAL_REQUEST,
+ SCSI_ASC_INVALID_FIELD_IN_CDB,
+ SCSI_ASCQ_INVALID_FIELD_IN_CDB
+ );
+
+ status = SATI_FAILURE_CHECK_RESPONSE_DATA;
+ }
+ break;
+ default :
+ //UNSPECIFIED SATv2r9
+ sati_scsi_sense_data_construct(
+ sequence,
+ scsi_io,
+ SCSI_STATUS_CHECK_CONDITION,
+ SCSI_SENSE_ILLEGAL_REQUEST,
+ SCSI_ASC_NO_ADDITIONAL_SENSE ,
+ SCSI_ASCQ_NO_ADDITIONAL_SENSE
+ );
+ status = SATI_FAILURE_CHECK_RESPONSE_DATA;
+ break;
+ }
+ }
+ return status;
+}
+
+/**
+ * @brief This method will translate the response to the SATI Log Sense
+ * translation. ATA command responses will be translated into the
+ * correct SCSI log pages to be returned by SATI.
+ *
+ * @return SATI_STATUS Indicates if the response translation succeeded.
+ *
+ */
+SATI_STATUS sati_log_sense_translate_response(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ void * ata_io
+)
+{
+ U8 * register_fis = sati_cb_get_d2h_register_fis_address(ata_io);
+ SATI_STATUS status = SATI_FAILURE;
+
+ if(sati_get_ata_status(register_fis) & ATA_STATUS_REG_ERROR_BIT)
+ {
+ sati_scsi_sense_data_construct(
+ sequence,
+ scsi_io,
+ SCSI_STATUS_CHECK_CONDITION,
+ SCSI_SENSE_ABORTED_COMMAND,
+ SCSI_ASC_NO_ADDITIONAL_SENSE ,
+ SCSI_ASCQ_NO_ADDITIONAL_SENSE
+ );
+ status = SATI_FAILURE_CHECK_RESPONSE_DATA;
+ }
+ else
+ {
+
+ void * ata_data = sati_cb_get_ata_data_address(ata_io);
+
+ if(ata_data == NULL)
+ {
+ return SATI_FAILURE;
+ }
+
+ switch(sequence->type)
+ {
+ case SATI_SEQUENCE_LOG_SENSE_EXTENDED_SELF_TEST_LOG_PAGE:
+ sati_extended_self_test_log_page_construct(
+ sequence, scsi_io, ata_data
+ );
+
+ status = SATI_COMPLETE;
+ break;
+
+ case SATI_SEQUENCE_LOG_SENSE_SELF_TEST_LOG_PAGE:
+ sati_self_test_log_page_construct(sequence, scsi_io, ata_data);
+ status = SATI_COMPLETE;
+ break;
+
+ case SATI_SEQUENCE_LOG_SENSE_INFO_EXCEPTION_LOG_PAGE:
+ //This function needs a d->h register fis, not ata data
+ sati_information_exception_log_page_contruct(
+ sequence, scsi_io, ata_io
+ );
+
+ status = SATI_COMPLETE;
+ break;
+
+ default:
+ sati_scsi_sense_data_construct(
+ sequence,
+ scsi_io,
+ SCSI_STATUS_CHECK_CONDITION,
+ SCSI_SENSE_ABORTED_COMMAND,
+ SCSI_ASC_NO_ADDITIONAL_SENSE ,
+ SCSI_ASCQ_NO_ADDITIONAL_SENSE
+ );
+ status = SATI_FAILURE_CHECK_RESPONSE_DATA;
+ break;
+ }
+ }
+ return status;
+}
+
+#endif // !defined(DISABLE_SATI_LOG_SENSE)
+
diff --git a/sys/dev/isci/scil/sati_log_sense.h b/sys/dev/isci/scil/sati_log_sense.h
new file mode 100644
index 0000000..d35f949
--- /dev/null
+++ b/sys/dev/isci/scil/sati_log_sense.h
@@ -0,0 +1,87 @@
+/*-
+ * 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.
+ *
+ * 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.
+ *
+ * $FreeBSD$
+ */
+/**
+ * @file
+ * @brief This file contains the method declarations to translate
+ * SCSI Log Sense command based of the SATv2 spec.
+ */
+
+#ifndef _SATI_LOG_SENSE_H_
+#define _SATI_LOG_SENSE_H_
+
+#include <dev/isci/scil/intel_scsi.h>
+#include <dev/isci/scil/sati_types.h>
+#include <dev/isci/scil/sati_translator_sequence.h>
+
+#define SATI_LOG_SENSE_GET_PC_FIELD(cdb) \
+ (( sati_get_cdb_byte((cdb), 2) & SCSI_LOG_SENSE_PC_FIELD_MASK ) \
+ >> SCSI_LOG_SENSE_PC_FIELD_SHIFT )
+
+#define SATI_LOG_SENSE_GET_PAGE_CODE(cdb) \
+ (( sati_get_cdb_byte((cdb), 2) & SCSI_LOG_SENSE_PAGE_CODE_FIELD_MASK ) \
+ >> SCSI_LOG_SENSE_PAGE_CODE_FIELD_SHIFT )
+
+SATI_STATUS sati_log_sense_translate_command(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ void * ata_io
+);
+
+SATI_STATUS sati_log_sense_translate_response(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ void * ata_io
+);
+#endif // _SATI_LOG_SENSE_H_
+
diff --git a/sys/dev/isci/scil/sati_lun_reset.c b/sys/dev/isci/scil/sati_lun_reset.c
new file mode 100644
index 0000000..6696a16
--- /dev/null
+++ b/sys/dev/isci/scil/sati_lun_reset.c
@@ -0,0 +1,122 @@
+/*-
+ * 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.
+ *
+ * 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 <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/**
+ * @file
+ *
+ * @brief This file contains the method implementations required to
+ * translate the SCSI lun reset command.
+ */
+
+#if !defined(DISABLE_SATI_TASK_MANAGEMENT)
+
+#include <dev/isci/scil/sati_lun_reset.h>
+#include <dev/isci/scil/sati_callbacks.h>
+#include <dev/isci/scil/sati_util.h>
+#include <dev/isci/scil/intel_ata.h>
+#include <dev/isci/scil/intel_scsi.h>
+#include <dev/isci/scil/intel_sat.h>
+
+//******************************************************************************
+//* P U B L I C M E T H O D S
+//******************************************************************************
+
+/**
+ * @brief This method will translate the lun reset SCSI task request into an
+ * ATA SOFT RESET command. For more information on the parameters
+ * passed to this method, please reference sati_translate_command().
+ *
+ * @return Indicate if the command translation succeeded.
+ * @retval SCI_SUCCESS This is returned if the command translation was
+ * successful.
+ *
+ * @note It is up to the user of the sata translator to set the command bit
+ * and clear the control softreset bit and send the second register fis.
+ */
+SATI_STATUS sati_lun_reset_translate_command(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ void * ata_io
+)
+{
+ U8* register_fis = sati_cb_get_h2d_register_fis_address(ata_io);
+
+ sati_set_ata_command(register_fis, ATA_NOP);
+ sati_set_ata_control(register_fis, ATA_CONTROL_REG_SOFT_RESET_BIT);
+
+ //set all other fields to zero.
+ sati_clear_sata_command_flag(register_fis);
+ sati_set_ata_features(register_fis, 0);
+ sati_set_ata_features_exp(register_fis, 0);
+ sati_set_ata_sector_count(register_fis, 0);
+ sati_set_ata_sector_count_exp(register_fis, 0);
+ sati_set_ata_lba_low(register_fis, 0);
+ sati_set_ata_lba_mid(register_fis, 0);
+ sati_set_ata_lba_high(register_fis, 0);
+ sati_set_ata_lba_low_exp(register_fis, 0);
+ sati_set_ata_lba_mid_exp(register_fis, 0);
+ sati_set_ata_lba_high_exp(register_fis, 0);
+ sati_set_ata_device_head(register_fis, 0);
+
+ sequence->type = SATI_SEQUENCE_LUN_RESET;
+ sequence->data_direction = SATI_DATA_DIRECTION_NONE;
+ sequence->protocol = SAT_PROTOCOL_SOFT_RESET;
+ sequence->ata_transfer_length = 0;
+
+ return SATI_SUCCESS;
+}
+
+#endif // !defined(DISABLE_SATI_TASK_MANAGEMENT)
+
diff --git a/sys/dev/isci/scil/sati_lun_reset.h b/sys/dev/isci/scil/sati_lun_reset.h
new file mode 100644
index 0000000..9e79e6f
--- /dev/null
+++ b/sys/dev/isci/scil/sati_lun_reset.h
@@ -0,0 +1,79 @@
+/*-
+ * 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.
+ *
+ * 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.
+ *
+ * $FreeBSD$
+ */
+#ifndef _SATI_LUN_RESET_H_
+#define _SATI_LUN_RESET_H_
+
+/**
+ * @file
+ * @brief This file contains the method interfaces required to translate the
+ * SCSI logical unit reset task request as well as translate response
+ * for the task request.
+ */
+
+#include <dev/isci/scil/sati_types.h>
+#include <dev/isci/scil/sati_translator_sequence.h>
+
+SATI_STATUS sati_lun_reset_translate_command(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_task,
+ void * ata_io
+);
+
+void sati_lun_reset_translate_resposne(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * ata_input_data,
+ void * scsi_task
+);
+
+#endif // _SATI_LUN_RESET_H_
diff --git a/sys/dev/isci/scil/sati_mode_pages.c b/sys/dev/isci/scil/sati_mode_pages.c
new file mode 100644
index 0000000..0189c05
--- /dev/null
+++ b/sys/dev/isci/scil/sati_mode_pages.c
@@ -0,0 +1,372 @@
+/*-
+ * 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.
+ *
+ * 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 <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/**
+ * @file
+ * @brief This file contains the mode page constants and data for the mode
+ * pages supported by this translation implementation.
+ */
+
+// DO NOT MOVE THIS INCLUDE STATEMENT! This include must occur before
+// the below check for ENABLE_SATI_MODE_PAGES.
+#include <dev/isci/scil/sati_types.h>
+
+#if defined(ENABLE_SATI_MODE_PAGES)
+
+#include <dev/isci/scil/sati_mode_pages.h>
+#include <dev/isci/scil/intel_scsi.h>
+
+//******************************************************************************
+//* C O N S T A N T S
+//******************************************************************************
+
+#define SCSI_MODE_PAGE19_SAS_ID 0x6
+#define SCSI_MODE_PAGE19_SUB1_PAGE_NUM 0x1
+#define SCSI_MODE_PAGE19_SUB1_PC 0x59
+
+//******************************************************************************
+//* M O D E P A G E S
+//******************************************************************************
+
+U8 sat_default_mode_page_01[] =
+{
+ SCSI_MODE_PAGE_READ_WRITE_ERROR, // Byte 0 - Page Code, SPF(0), PS(0)
+ SCSI_MODE_PAGE_01_LENGTH-2, // Byte 1 - Page Length
+ 0x80, // Byte 2 - AWRE, ARRE, TB, RC, EER, PER, DTE, DCR
+ 0x00, // Byte 3 - Read Retry Count
+
+ 0x00, // Byte 4 - Obsolete
+ 0x00, // Byte 5 - Obsolete
+ 0x00, // Byte 6 - Obsolete
+ 0x00, // Byte 7 - Restricted for MMC-4
+
+ 0x00, // Byte 8 - Write Retry Count
+ 0x00, // Byte 9 - Reserved
+ 0x00, // Byte 10 - Recovery Time Limit
+ 0x00, // Byte 11
+};
+
+U8 sat_changeable_mode_page_01[] =
+{
+ SCSI_MODE_PAGE_READ_WRITE_ERROR,
+ SCSI_MODE_PAGE_01_LENGTH-2,
+ 0x00,
+ 0x00,
+
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+};
+
+U8 sat_default_mode_page_02[] =
+{
+ SCSI_MODE_PAGE_DISCONNECT_RECONNECT, // Byte 0 - Page Code, SPF(0), PS(0)
+ SCSI_MODE_PAGE_02_LENGTH-2, // Byte 1 - Page Length
+ 0x00, // Byte 2 - Buffer Full Ratio
+ 0x00, // Byte 3 - Buffer Empty Ratio
+
+ 0x00, // Byte 4 - Bus Inactivity Limit
+ 0x00, // Byte 5
+ 0x00, // Byte 6 - Disconnect Time Limit
+ 0x00, // Byte 7
+
+ 0x00, // Byte 8 - Connect Time Limit
+ 0x00, // Byte 9
+ 0x00, // Byte 10 - Maximum Burst Size
+ 0x00, // Byte 11
+
+ 0x00, // Byte 12 - EMDP, FAIR_ARB, DIMM, DTDC
+ 0x00, // Byte 13
+ 0x00, // Byte 14 - First Burst Size
+ 0x00, // Byte 15
+};
+
+U8 sat_changeable_mode_page_02[] =
+{
+ SCSI_MODE_PAGE_DISCONNECT_RECONNECT,
+ SCSI_MODE_PAGE_02_LENGTH-2,
+ 0x00,
+ 0x00,
+
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+};
+
+U8 sat_default_mode_page_08[] =
+{
+ SCSI_MODE_PAGE_CACHING, // Byte 0 - Page Code, SPF(0), PS(0)
+ SCSI_MODE_PAGE_08_LENGTH-2, // Byte 1 - Page Length
+ 0x00, // Byte 2 - IC, ABPF, CAP, DISC, SIZE, WCE(1), MF, RCD
+ 0x00, // Byte 3 - Demand Read Retention Priority, Write Retention Priority
+
+ 0x00, // Byte 4 - Disable Pre-Fetch Transfer Length
+ 0x00, // Byte 5
+ 0x00, // Byte 6 - Minimum Pre-Fetch
+ 0x00, // Byte 7
+
+ 0x00, // Byte 8 - Maximum Pre-Fetch
+ 0x00, // Byte 9
+ 0x00, // Byte 10 - Maximum Pre-Fetch Ceiling
+ 0x00, // Byte 11
+
+ 0x00, // Byte 12 - FSW, LBCSS, DRA(0), Vendor Specific, NV_DIS
+ 0x00, // Byte 13 - Number of Cache Segments
+ 0x00, // Byte 14 - Cache Segment Size
+ 0x00, // Byte 15
+
+ 0x00, // Byte 16 - Reserved
+ 0x00, // Byte 17 - Non-Cache Segment Size
+ 0x00, // Byte 18
+ 0x00, // PAD
+};
+
+U8 sat_changeable_mode_page_08[] =
+{
+ SCSI_MODE_PAGE_CACHING,
+ SCSI_MODE_PAGE_08_LENGTH-2,
+ SCSI_MODE_PAGE_CACHE_PAGE_WCE_BIT,
+ 0x00,
+
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+
+ SCSI_MODE_PAGE_CACHE_PAGE_DRA_BIT,
+ 0x00,
+ 0x00,
+ 0x00,
+
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00, // PAD
+};
+
+U8 sat_default_mode_page_0A[] =
+{
+ SCSI_MODE_PAGE_CONTROL, // Byte 0 - Page Code, SPF(0), PS(0)
+ SCSI_MODE_PAGE_0A_LENGTH-2, // Byte 1 - Page Length
+ 0x00, // Byte 2 - TST(0), TMF_ONLY(0), D_SENSE(0), GLTSD(0), RLEC(0)
+ 0x10, // Byte 3 - Queue Algorithm(0), QErr(0)
+
+ 0x00, // Byte 4 - TAS(0), RAC(0), UA_(0), SWP(0)
+ 0x00, // Byte 5 - ATO(0), AUTOLOAD(0)
+ 0x00, // Byte 6
+ 0x00, // Byte 7
+
+ 0xFF, // Byte 8 - Unlimited Busy timeout
+ 0xFF, // Byte 9
+ 0x00, // Byte 10 - do not support self time compl time xlation
+ 0x00, // Byte 11
+};
+
+U8 sat_changeable_mode_page_0A[] =
+{
+ SCSI_MODE_PAGE_CONTROL,
+ SCSI_MODE_PAGE_0A_LENGTH-2,
+ 0x00,
+ 0x00,
+
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+};
+
+U8 sat_default_mode_page_19[] =
+{
+ SCSI_MODE_PAGE_PROTOCOL_SPECIFIC_PORT, // Byte 0 - PS, SPF, Page Code
+ SCSI_MODE_PAGE_19_LENGTH-2, // Byte 1 - Page Length
+ SCSI_MODE_PAGE19_SAS_ID, // Byte 2 - Rsvd, READY_LED, ProtoID
+ 0x00, // PAD
+
+ 0xFF, // Byte 4 - IT NLT MSB, 0xFF retry forever
+ 0xFF, // Byte 5 - IT NLT LSB, 0xFF retry forever
+ 0x00, // Byte 6 - IRT MSB, 0x0 disable init resp timer
+ 0x00, // Byte 7 - IRT LSB, 0x0 disable init resp timer
+};
+
+U8 sat_changeable_mode_page_19[] =
+{
+ SCSI_MODE_PAGE_PROTOCOL_SPECIFIC_PORT,
+ SCSI_MODE_PAGE_19_LENGTH-2,
+ 0x00,
+ 0x00,
+
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+};
+
+U8 sat_default_mode_page_1C[] =
+{
+ SCSI_MODE_PAGE_INFORMATIONAL_EXCP_CONTROL, // Byte 0 - Page Code,
+ // SPF(0), PS(0)
+ SCSI_MODE_PAGE_1C_LENGTH-2, // Byte 1 - Page Length
+ SCSI_MODE_PAGE_DEXCPT_ENABLE, // Byte 2 - Perf, EBF, EWasc,
+ // DExcpt(1), Test, LogErr
+ 0x06, // Byte 3 -- MRIE (6 == values only available upon request)
+
+ 0x00, // Byte 4 -- Interval Timer
+ 0x00, // Byte 5
+ 0x00, // Byte 6
+ 0x00, // Byte 7
+
+ 0x00, // Byte 8 -- Report Count
+ 0x00, // Byte 9
+ 0x00, // Byte 10
+ 0x00, // Byte 11
+};
+
+U8 sat_changeable_mode_page_1C[] =
+{
+ SCSI_MODE_PAGE_INFORMATIONAL_EXCP_CONTROL,
+ SCSI_MODE_PAGE_1C_LENGTH-2,
+ SCSI_MODE_PAGE_DEXCPT_ENABLE,
+ 0x00,
+
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+};
+
+U8 sat_supported_mode_pages[] =
+{
+ SCSI_MODE_PAGE_READ_WRITE_ERROR,
+ SCSI_MODE_PAGE_DISCONNECT_RECONNECT,
+ SCSI_MODE_PAGE_CACHING,
+ SCSI_MODE_PAGE_CONTROL,
+ SCSI_MODE_PAGE_INFORMATIONAL_EXCP_CONTROL
+};
+
+U8 *sat_changeable_mode_pages[] =
+{
+ sat_changeable_mode_page_01,
+ sat_changeable_mode_page_02,
+ sat_changeable_mode_page_08,
+ sat_changeable_mode_page_0A,
+ sat_changeable_mode_page_1C
+};
+
+U8 *sat_default_mode_pages[] =
+{
+ sat_default_mode_page_01,
+ sat_default_mode_page_02,
+ sat_default_mode_page_08,
+ sat_default_mode_page_0A,
+ sat_default_mode_page_1C
+};
+
+U16 sat_mode_page_sizes[] =
+{
+ sizeof(sat_default_mode_page_01),
+ sizeof(sat_default_mode_page_02),
+ sizeof(sat_default_mode_page_08),
+ sizeof(sat_default_mode_page_0A),
+ sizeof(sat_default_mode_page_1C)
+};
+
+U16 sati_mode_page_get_page_index(
+ U8 page_code
+)
+{
+ U16 index;
+ for (index = 0; index < SAT_SUPPORTED_MODE_PAGES_LENGTH; index++)
+ {
+ if (sat_supported_mode_pages[index] == page_code)
+ return index;
+ }
+
+ return SATI_MODE_PAGE_UNSUPPORTED_INDEX;
+}
+
+#endif // defined(ENABLE_SATI_MODE_PAGES)
+
diff --git a/sys/dev/isci/scil/sati_mode_pages.h b/sys/dev/isci/scil/sati_mode_pages.h
new file mode 100644
index 0000000..d8cbe8c
--- /dev/null
+++ b/sys/dev/isci/scil/sati_mode_pages.h
@@ -0,0 +1,144 @@
+/*-
+ * 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.
+ *
+ * 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.
+ *
+ * $FreeBSD$
+ */
+/**
+ * @file
+ * @brief This file contains the mode page constants and members that are
+ * supported by this translation implementation.
+ */
+
+#include <dev/isci/scil/sati_types.h>
+
+// These values represent the mode page (not including header and block
+// descriptor). The page length fields in the mode sense data are equivalent
+// to the constant values below less 2. The minus 2 is due to not including
+// the page code byte (byte 0) and the page length byte (byte 1).
+#define SCSI_MODE_PAGE_01_LENGTH 0x0C
+#define SCSI_MODE_PAGE_02_LENGTH 0x10
+#define SCSI_MODE_PAGE_08_LENGTH 0x14
+#define SCSI_MODE_PAGE_0A_LENGTH 0x0C
+#define SCSI_MODE_PAGE_19_LENGTH 0x8
+#define SCSI_MODE_PAGE_1A_LENGTH 0x0C
+#define SCSI_MODE_PAGE_1C_LENGTH 0x0C
+#define SCSI_MODE_PAGE_3F_LENGTH SCSI_MODE_PAGE_08_LENGTH \
+ + SCSI_MODE_PAGE_1C_LENGTH \
+
+#define SATI_MODE_PAGE_UNSUPPORTED_INDEX 0xFFFF
+
+#define SAT_SUPPORTED_MODE_PAGES_LENGTH sizeof(sat_supported_mode_pages)/sizeof(U8)
+
+typedef enum _RETURN_PAGE{
+ CHANGEABLE_PAGE,
+ DEFAULT_PAGE
+}RETURN_PAGE;
+
+
+/**
+ * @struct SCSI_MODE_SELECT_MODE_PARAMETER_HEADER_6
+ *
+ * @brief This structure contains mode parameter header fields for 6 byte
+ * mode select command.
+ */
+typedef struct SCSI_MODE_SELECT_MODE_PARAMETER_HEADER_6
+{
+ U8 mode_data_length;
+ U8 medium_type; //Should be 0
+ U8 device_specific_parameter;
+ U8 block_descriptor_length;
+
+}SCSI_MODE_SELECT_MODE_PARAMETER_HEADER_6_T;
+
+/**
+ * @struct MODE_PARAMETER_HEADER_10
+ *
+ * @brief This structure contains mode parameter header fields for 10 byte
+ * mode select command.
+ */
+typedef struct SCSI_MODE_SELECT_MODE_PARAMETER_HEADER_10
+{
+ U8 mode_data_length[2];
+ U8 medium_type; //Should be 0
+ U8 device_specific_parameter;
+ U8 long_lba;
+ U8 reserve;
+ U8 block_descriptor_length[2];
+
+}SCSI_MODE_SELECT_MODE_PARAMETER_HEADER_10_T;
+
+/**
+ * @struct MODE_PARAMETER_BLOCK_DESCRIPTOR
+ *
+ * @brief This structure contains mode parameter block descriptor fields.
+ */
+typedef struct SCSI_MODE_SELECT_MODE_PARAMETER_BLOCK_DESCRIPTOR
+{
+ U8 density_code;
+ U8 number_of_blocks[3];
+ U8 reserved;
+ U8 block_length[3];
+
+}SCSI_MODE_SELECT_MODE_PARAMETER_BLOCK_DESCRIPTOR_T;
+
+U16 sati_mode_page_get_page_index(
+ U8 page_code
+);
+
+U8 * sati_mode_page_get_mode_page(
+ U8 page_code,
+ RETURN_PAGE page
+);
+
+extern U8 * sat_changeable_mode_pages[];
+extern U8 * sat_default_mode_pages[];
+extern U16 sat_mode_page_sizes[];
+
diff --git a/sys/dev/isci/scil/sati_mode_select.c b/sys/dev/isci/scil/sati_mode_select.c
new file mode 100644
index 0000000..dc83bfd
--- /dev/null
+++ b/sys/dev/isci/scil/sati_mode_select.c
@@ -0,0 +1,1115 @@
+/*-
+ * 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.
+ *
+ * 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 <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/**
+ * @file
+ * @brief This file contains the method implementations required to
+ * translate the SCSI mode select (6 and 10-byte) commands with 5
+ * supported mode parameter pages (0x01, 0x02, 0x08, 0x0A, 0x1C).
+ */
+
+#if !defined(DISABLE_SATI_MODE_SELECT)
+
+#include <dev/isci/scil/sati_mode_select.h>
+#include <dev/isci/scil/sati_mode_pages.h>
+#include <dev/isci/scil/sati_callbacks.h>
+#include <dev/isci/scil/sci_object.h>
+#include <dev/isci/scil/sati_translator_sequence.h>
+#include <dev/isci/scil/sati_util.h>
+
+//******************************************************************************
+//* P R I V A T E M E T H O D S
+//******************************************************************************
+
+/**
+ * @brief This method will get medium type parameter field per CDB size.
+ *
+ * @param[in] scsi_io This parameter specifies the user's SCSI IO object
+ * for which to calculate the mode page header.
+ * @param[in] cdb_size This parameter specifies the number of bytes
+ * associated with the CDB for which to calculate the header.
+ *
+ * @return This method returns the medium type for the mode page header.
+ */
+static
+U8 sati_mode_select_get_medium_type(
+ U8 * mode_parameters,
+ U32 cdb_size
+)
+{
+ U8 medium_type =0xFF;
+ SCSI_MODE_SELECT_MODE_PARAMETER_HEADER_6_T * mode_parameters_6;
+ SCSI_MODE_SELECT_MODE_PARAMETER_HEADER_10_T * mode_parameters_10;
+
+ if(cdb_size == 6)
+ {
+ mode_parameters_6 = (SCSI_MODE_SELECT_MODE_PARAMETER_HEADER_6_T *) mode_parameters;
+ medium_type = mode_parameters_6->medium_type;
+ }
+ else if(cdb_size == 10)
+ {
+ mode_parameters_10 = (SCSI_MODE_SELECT_MODE_PARAMETER_HEADER_10_T *) mode_parameters;
+ medium_type = mode_parameters_10->medium_type;
+ }
+
+ return medium_type;
+}
+
+/**
+ * @brief This method will retrieve Block Descriptor Length.
+ *
+ * @param[in] mode_parameters This parameter contains the address to the mode parameters.
+ * @param[in] cdb_size This parameter specifies the number of bytes
+ * associated with the CDB for which to process the block descriptor.
+ *
+ * @return This method returns the size, in bytes, for the mode parameter block descriptor.
+ */
+static
+U32 sati_mode_select_get_mode_block_descriptor_length(
+ U8 * mode_parameters,
+ U32 cdb_size
+)
+{
+ U32 mode_block_descriptor_length = 0;
+ SCSI_MODE_SELECT_MODE_PARAMETER_HEADER_6_T * mode_parameters_6;
+ SCSI_MODE_SELECT_MODE_PARAMETER_HEADER_10_T * mode_parameters_10;
+
+ if(cdb_size == 6)
+ {
+ mode_parameters_6 = (SCSI_MODE_SELECT_MODE_PARAMETER_HEADER_6_T *) mode_parameters;
+ mode_block_descriptor_length = mode_parameters_6->block_descriptor_length;
+ }
+ else if(cdb_size == 10)
+ {
+ mode_parameters_10 = (SCSI_MODE_SELECT_MODE_PARAMETER_HEADER_10_T *) mode_parameters;
+ //Long LBA bit is the bit0 of the byte
+ //Spec says another way to get the block descriptor length to multiply the block number
+ // with block length (8 or 16), but we can get it directly.
+ mode_block_descriptor_length =(((U16)mode_parameters_10->block_descriptor_length[0]) << 8) +
+ mode_parameters_10->block_descriptor_length[1];
+
+ }
+
+ return mode_block_descriptor_length;
+
+}
+
+/**
+ * @brief This method will find the starting byte location for a page.
+ *
+ * @param[in] block_descriptor_length This parameter passes in the length of
+ * block descriptor.
+ * @param[in] cdb_size This parameter specifies the number of bytes
+ * associated with the CDB for which to calculate the header.
+ *
+ * @return This method returns the offset, for the mode page.
+ */
+static
+U32 sati_mode_select_get_mode_page_offset(
+ U32 block_descriptor_length,
+ U32 cdb_size
+ )
+{
+ U32 mode_page_offset;
+
+ if(cdb_size == 6)
+ {
+ mode_page_offset = sizeof(SCSI_MODE_SELECT_MODE_PARAMETER_HEADER_6_T) + block_descriptor_length;
+ }
+ else if(cdb_size == 10)
+ {
+ mode_page_offset = sizeof(SCSI_MODE_SELECT_MODE_PARAMETER_HEADER_10_T) + block_descriptor_length;
+ }
+ else
+ {
+ mode_page_offset = 0;
+ }
+
+ return mode_page_offset;
+}
+
+/**
+ * @brief This method will set the initial Mode Select processing state.
+ */
+static
+void sati_mode_select_initialize_mode_sel_processing_state(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ void * ata_io,
+ U32 data_transfer_length,
+ U32 mode_page_offset
+ )
+{
+ sequence->command_specific_data.process_state.ata_command_sent_for_cmp = 0;
+ sequence->command_specific_data.process_state.mode_page_offset=mode_page_offset;
+ sequence->command_specific_data.process_state.mode_pages_size = data_transfer_length - mode_page_offset;
+ sequence->command_specific_data.process_state.size_of_data_processed = 0;
+ sequence->command_specific_data.process_state.current_mode_page_processed = FALSE;
+}
+
+/**
+ * @brief This method will get mode page size.
+ *
+ * @param[in] page_code This parameter contains page code for the current mode page.
+ *
+ * @return This method returns the size of current mode page.
+ */
+static
+U32 sati_mode_select_get_mode_page_size(
+ U8 page_code
+)
+{
+ U32 page_size=0;
+
+ switch (page_code)
+ {
+ case SCSI_MODE_PAGE_READ_WRITE_ERROR:
+ page_size=SCSI_MODE_PAGE_01_LENGTH;
+ break;
+
+ case SCSI_MODE_PAGE_DISCONNECT_RECONNECT:
+ page_size=SCSI_MODE_PAGE_02_LENGTH;
+ break;
+
+ case SCSI_MODE_PAGE_CACHING:
+ page_size=SCSI_MODE_PAGE_08_LENGTH;
+ break;
+
+ case SCSI_MODE_PAGE_CONTROL:
+ page_size=SCSI_MODE_PAGE_0A_LENGTH;
+ break;
+
+ case SCSI_MODE_PAGE_INFORMATIONAL_EXCP_CONTROL:
+ page_size=SCSI_MODE_PAGE_1C_LENGTH;
+ break;
+
+ case SCSI_MODE_PAGE_POWER_CONDITION:
+ page_size=SCSI_MODE_PAGE_1A_LENGTH;
+ break;
+ default:
+ page_size=0;
+ break;
+ }
+
+ return page_size;
+}
+
+/**
+ * @brief This method will check the validity of parameter data of Read Write Error Recovery
+ * page and further processing the page data if necessary.
+ *
+ * @param[in] page_size This parameter specifies page size of current mode page.
+ *
+ * @return Indicate if the translation was successful.
+ * @retval SATI_SUCCESS
+ * @retval SATI_COMPLETE
+ * @retval SATI_FAILURE_CHECK_RESPONSE_DATA
+ */
+static
+SATI_STATUS sati_mode_select_process_mode_page_read_write_error_recovery(
+ SATI_TRANSLATOR_SEQUENCE_T* sequence,
+ void * scsi_io,
+ U32 page_size
+ )
+{
+ SATI_STATUS status = SATI_FAILURE_CHECK_RESPONSE_DATA;
+
+ U8 current_mode_page[SCSI_MODE_PAGE_01_LENGTH]={0,0,0,0,0,0,0,0,0,0,0,0};
+ U32 mode_page_offset;
+
+ mode_page_offset = sequence->command_specific_data.process_state.mode_page_offset;
+
+ //Check all the defined bits for this page
+ //SPF(0b); Page length 0x0A;AWRE 1; ARRE 0; Error recovery bits 0; RC 0;
+ //Recovery time limit last two bytes 0
+
+ sati_get_data_byte(sequence, scsi_io, mode_page_offset, &current_mode_page[0]);
+ sati_get_data_byte(sequence, scsi_io, mode_page_offset+1, &current_mode_page[1]);
+ sati_get_data_byte(sequence, scsi_io, mode_page_offset+2, &current_mode_page[2]);
+ sati_get_data_byte(sequence, scsi_io, mode_page_offset+10, &current_mode_page[10]);
+ sati_get_data_byte(sequence, scsi_io, mode_page_offset+11, &current_mode_page[11]);
+
+ if ( ((current_mode_page[0] & SCSI_MODE_SELECT_MODE_PAGE_SPF_MASK)!= 0) ||
+ (current_mode_page[1] != (SCSI_MODE_PAGE_01_LENGTH - 2)) ||
+ ((current_mode_page[2] & SCSI_MODE_SELECT_MODE_PAGE_01_AWRE_MASK) == 0) ||
+ ((current_mode_page[2] & SCSI_MODE_SELECT_MODE_PAGE_01_ARRE_MASK) != 0) ||
+ ((current_mode_page[2] & SCSI_MODE_SELECT_MODE_PAGE_01_RC_ERBITS_MASK) != 0) ||
+ (current_mode_page[10] != 0 ) ||
+ (current_mode_page[11] != 0 ) )
+ {
+ status = SATI_FAILURE_CHECK_RESPONSE_DATA;
+ return status;
+ }
+
+ //no need to send any command
+ {
+ sequence->command_specific_data.process_state.size_of_data_processed += page_size;
+ sequence->command_specific_data.process_state.mode_page_offset += page_size;
+ sequence->command_specific_data.process_state.current_mode_page_processed = TRUE;
+ }
+
+ status = SATI_COMPLETE;
+
+ return status;
+}
+
+/**
+ * @brief This method will check the validity of parameter data of Disconnect Reconnect mode
+ * page and further processing the page data if necessary.
+ *
+ * @param[in] page_size This parameter specifies page size of current mode page.
+ *
+ * @return Indicate if the translation was successful.
+ * @retval SATI_SUCCESS
+ * @retval SATI_COMPLETE
+ * @retval SATI_FAILURE_CHECK_RESPONSE_DATA
+ */
+static
+SATI_STATUS sati_mode_select_process_mode_page_disconnect_reconnect(
+ SATI_MODE_SELECT_PROCESSING_STATE_T * mode_select_process_state,
+ U32 page_size
+ )
+{
+ SATI_STATUS status = SATI_FAILURE_CHECK_RESPONSE_DATA;
+
+ // No need to check data for valid or invalid this page (undefined)
+ // No ata command to send
+ {
+ mode_select_process_state->size_of_data_processed += page_size;
+ mode_select_process_state->mode_page_offset += page_size;
+ mode_select_process_state->current_mode_page_processed = TRUE;
+ }
+
+ // No further interaction with remote devices
+ status = SATI_COMPLETE;
+
+ return status;
+}
+
+/**
+ * @brief This method will check the validity of parameter data of Caching mode
+ * page and issue multiple ATA set feature commands to complete the translation.
+ *
+ * @param[in] page_size This parameter specifies page size of current mode page.
+ *
+ * @return Indicate if the translation was successful.
+ * @retval SATI_SUCCESS
+ * @retval SATI_COMPLETE
+ * @retval SATI_FAILURE_CHECK_RESPONSE_DATA
+ */
+static
+SATI_STATUS sati_mode_select_process_mode_page_caching(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ void * ata_io,
+ U32 page_size
+ )
+{
+ SATI_STATUS status = SATI_FAILURE_CHECK_RESPONSE_DATA;
+
+ //SCSI_MODE_PAGE_08_LENGTH 0x14= 20
+ U8 current_mode_page[SCSI_MODE_PAGE_08_LENGTH] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
+ U32 mode_page_offset;
+ U32 index;
+
+ mode_page_offset = sequence->command_specific_data.process_state.mode_page_offset;
+ sequence->type = SATI_SEQUENCE_MODE_SELECT_MODE_PAGE_CACHING;
+
+ for(index = 0; index < SCSI_MODE_PAGE_08_LENGTH; index++)
+ {
+ sati_get_data_byte(sequence, scsi_io, mode_page_offset+index, &current_mode_page[index]);
+ }
+
+ //Check for data validity
+ //SPF(0b); Page length 0x12;Byte2 to Byte15 all 0 with exception DRA and WCE changeable
+
+ if (((current_mode_page[0] & SCSI_MODE_SELECT_MODE_PAGE_SPF_MASK)!= 0) ||
+ (current_mode_page[1] != (SCSI_MODE_PAGE_08_LENGTH-2)) ||
+ ((current_mode_page[2] | SCSI_MODE_PAGE_CACHE_PAGE_WCE_BIT)!=SCSI_MODE_PAGE_CACHE_PAGE_WCE_BIT) ||
+ (current_mode_page[3] != 0 ) ||
+ (current_mode_page[4] != 0 ) ||
+ (current_mode_page[5] != 0 ) ||
+ (current_mode_page[6] != 0 ) ||
+ (current_mode_page[7] != 0 ) ||
+ (current_mode_page[8] != 0 ) ||
+ (current_mode_page[9] != 0 ) ||
+ (current_mode_page[10] != 0 ) ||
+ (current_mode_page[11] != 0 ) ||
+ ((current_mode_page[12] & SCSI_MODE_SELECT_MODE_PAGE_08_FSW_LBCSS_NVDIS) != 0) ||
+ (current_mode_page[13] != 0 ) ||
+ (current_mode_page[14] != 0 ) ||
+ (current_mode_page[15] != 0 ))
+ {
+ //parameter data passed in containing data that doesn't meet the SAT-2 requirement
+ return SATI_FAILURE_CHECK_RESPONSE_DATA;
+ }
+
+ if(sequence->command_specific_data.process_state.ata_command_sent_for_cmp == 0)
+ {
+ //byte2 bit2 WCE==0 disable write cache WCE==1 enable write cache
+ //SCSI_MODE_PAGE_CACHE_PAGE_WCE_BIT ==0x4,
+
+ if ( (current_mode_page[2] & SCSI_MODE_PAGE_CACHE_PAGE_WCE_BIT) == 0)
+ sati_ata_set_features_construct(ata_io, sequence, ATA_SET_FEATURES_SUB_CMD_DISABLE_CACHE);
+ else
+ sati_ata_set_features_construct(ata_io, sequence, ATA_SET_FEATURES_SUB_CMD_ENABLE_CACHE);
+
+ }
+ else if(sequence->command_specific_data.process_state.ata_command_sent_for_cmp == 1)
+ {
+ // DRA bit is set to 0, enable Read look ahead AAh;
+ // DRA bit is set to 1, disable with set feature command 55h
+ // SCSI_MODE_PAGE_CACHE_PAGE_DRA_BIT== 0x20
+
+ if ( (current_mode_page[12] & SCSI_MODE_PAGE_CACHE_PAGE_DRA_BIT) == 0)
+ sati_ata_set_features_construct(ata_io, sequence,ATA_SET_FEATURES_SUB_CMD_ENABLE_READ_AHEAD);
+ else
+ sati_ata_set_features_construct(ata_io, sequence,ATA_SET_FEATURES_SUB_CMD_DISABLE_READ_AHEAD);
+
+ sequence->command_specific_data.process_state.size_of_data_processed += page_size;
+ sequence->command_specific_data.process_state.mode_page_offset += page_size;
+ sequence->command_specific_data.process_state.current_mode_page_processed = TRUE;
+
+
+ }
+ // No more ata commands to send
+
+ sequence->command_specific_data.process_state.ata_command_sent_for_cmp++;
+
+ status = SATI_SUCCESS;
+
+ return status;
+}
+
+/**
+ * @brief This method will check the validity of parameter data of Control mode
+ * page and further processing the page data if necessary.
+ *
+ * @param[in] mode_select_process_state This parameter points to the processing state fields
+ * of current mode page.
+ * @param[in] page_size This parameter specifies page size of current mode page.
+ *
+ * @return Indicate if the translation was successful.
+ * @retval SATI_SUCCESS
+ * @retval SATI_COMPLETE
+ * @retval SATI_FAILURE_CHECK_RESPONSE_DATA
+ */
+static
+SATI_STATUS sati_mode_select_process_mode_page_control(
+ SATI_TRANSLATOR_SEQUENCE_T* sequence,
+ void * scsi_io,
+ void * ata_io,
+ U32 page_size
+ )
+{
+ SATI_STATUS status = SATI_FAILURE_CHECK_RESPONSE_DATA;
+
+ //SCSI_MODE_PAGE_0A_LENGTH 12
+ U8 current_mode_page[SCSI_MODE_PAGE_0A_LENGTH]={0,0,0,0,0,0,0,0,0,0};
+ U32 mode_page_offset;
+ U32 index;
+
+ mode_page_offset = sequence->command_specific_data.process_state.mode_page_offset;
+
+ for(index = 0; index < SCSI_MODE_PAGE_0A_LENGTH; index++)
+ {
+ sati_get_data_byte(sequence, scsi_io, mode_page_offset+index, &current_mode_page[index]);
+ }
+
+ //bit 1 and 2 of byte3 Qerr full task management model etc. then both bits 0
+ //byte 8 and 9 busy time out period variable if not ffff setable?
+ //check for page data validity
+ //Byte2: 0000???0b Byte3: Queued Algorithm Modifier should be set to 1 QErr?
+ //Byte4: ??000??? Byte5: ?0???000
+
+ if (((current_mode_page[0] & SCSI_MODE_SELECT_MODE_PAGE_SPF_MASK)!= 0) ||
+ (current_mode_page[1] != (SCSI_MODE_PAGE_0A_LENGTH - 2)) ||
+ ((current_mode_page[2] & SCSI_MODE_SELECT_MODE_PAGE_0A_TST_TMF_RLEC) != 0) ||
+ ((current_mode_page[3] & SCSI_MODE_SELECT_MODE_PAGE_0A_MODIFIER) != 0) ||
+ ((current_mode_page[4] & SCSI_MODE_SELECT_MODE_PAGE_0A_UA_SWP ) != 0) ||
+ ((current_mode_page[5] & SCSI_MODE_SELECT_MODE_PAGE_0A_TAS_AUTO ) != 0 ) )
+ {
+ return SATI_FAILURE_CHECK_RESPONSE_DATA;
+ }
+
+ if ((current_mode_page[2] & SCSI_MODE_SELECT_MODE_PAGE_D_SENSE) != 0)
+ sequence->device->descriptor_sense_enable = SCSI_MODE_PAGE_CONTROL_D_SENSE_ENABLE;
+ else
+ sequence->device->descriptor_sense_enable = SCSI_MODE_PAGE_CONTROL_D_SENSE_DISABLE;
+
+ // no ata command need to be comfirmed
+ {
+ sequence->command_specific_data.process_state.size_of_data_processed += page_size;
+ sequence->command_specific_data.process_state.mode_page_offset += page_size;
+ sequence->command_specific_data.process_state.current_mode_page_processed = TRUE;
+ }
+
+ status = SATI_COMPLETE;
+
+ return status;
+}
+
+/**
+ * @brief This method will check the validity of parameter data of Information Exception Control
+ * mode page and further processing the page data if necessary.
+ *
+ * @param[in] page_size This parameter specifies page size of current mode page.
+ *
+ * @return Indicate if the translation was successful.
+ * @retval SATI_SUCCESS
+ * @retval SATI_COMPLETE
+ * @retval SATI_FAILURE_CHECK_RESPONSE_DATA
+ */
+static
+SATI_STATUS sati_mode_select_process_mode_page_informational_exception_control(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ void * ata_io,
+ U32 page_size
+ )
+{
+ SATI_STATUS status = SATI_FAILURE_CHECK_RESPONSE_DATA;
+
+ //SCSI_MODE_PAGE_1C_LENGTH 12
+ U8 current_mode_page[SCSI_MODE_PAGE_1C_LENGTH]={0,0,0,0,0,0,0,0,0,0,0,0};
+ U32 mode_page_offset;
+ U32 index;
+
+ mode_page_offset = sequence->command_specific_data.process_state.mode_page_offset;
+ sequence->type = SATI_SEQUENCE_MODE_SELECT_MODE_INFORMATION_EXCEPT_CONTROL;
+
+ for(index = 0; index < 4; index++)
+ {
+ sati_get_data_byte(sequence, scsi_io, mode_page_offset+index, &current_mode_page[index]);
+ }
+
+ //Check for data validity
+ //SPF(0b); Page length 0x0A; Byte2 0????0?? Byte3: ????1100
+ //SCSI_MODE_SELECT_MODE_PAGE_MRIE_BYTE same as REPORT_INFO_EXCEPTION_CONDITION_ON_REQUEST 0x6
+ //SCSI_MODE_PAGE_DEXCPT_ENABLE
+
+ if (((current_mode_page[0] & SCSI_MODE_SELECT_MODE_PAGE_SPF_MASK)!= 0) ||
+ (current_mode_page[1] != (SCSI_MODE_PAGE_1C_LENGTH - 2)) ||
+ ((current_mode_page[2] & SCSI_MODE_SELECT_MODE_PAGE_1C_PERF_TEST)!= 0 ) ||
+ ((current_mode_page[3] & SCSI_MODE_SELECT_MODE_PAGE_MRIE_MASK) !=
+ SCSI_MODE_SELECT_MODE_PAGE_MRIE_BYTE ))
+ {
+ return SATI_FAILURE_CHECK_RESPONSE_DATA;
+ }
+
+ // DEXCPT bit is set to 0, enable SMART reporting D8h;
+ // DEXCPT bit is set to 1, disable SMART reporting D9h
+ // SCSI_MODE_PAGE_DEXCPT_ENABLE== 0x08
+
+ if ( (current_mode_page[2] & SCSI_MODE_PAGE_DEXCPT_ENABLE) == 0)
+ sati_ata_smart_return_status_construct(ata_io, sequence, ATA_SMART_SUB_CMD_ENABLE);
+ else
+ sati_ata_smart_return_status_construct(ata_io, sequence, ATA_SMART_SUB_CMD_DISABLE);
+
+ sequence->command_specific_data.process_state.size_of_data_processed += page_size;
+ sequence->command_specific_data.process_state.mode_page_offset += page_size;
+ sequence->command_specific_data.process_state.current_mode_page_processed = TRUE;
+ // No more ata commands to send
+
+ status = SATI_SUCCESS;
+
+ return status;
+}
+
+/**
+ * @brief This method will check the validity of parameter data of Power Condition mode
+ * page and issue multiple ATA set feature commands to complete the translation.
+ *
+ * @param[in] mode_select_process_state This parameter points to the processing state fields
+ * of current mode page.
+ * @param[in] page_size This parameter specifies page size of current mode page.
+ *
+ * @return Indicate if the translation was successful.
+ * @retval SATI_SUCCESS
+ * @retval SATI_COMPLETE
+ * @retval SATI_FAILURE_CHECK_RESPONSE_DATA
+ */
+static
+SATI_STATUS sati_mode_select_process_mode_page_power_condition(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ void * ata_io,
+ U32 page_size
+ )
+{
+ SATI_STATUS status = SATI_FAILURE_CHECK_RESPONSE_DATA;
+
+ //SCSI_MODE_PAGE_1A_LENGTH 10
+ U8 current_mode_page[SCSI_MODE_PAGE_1A_LENGTH] = {0,0,0,0,0,0,0,0,0,0};
+ U32 mode_page_offset;
+ U32 index;
+
+ U32 timer = 0;
+ U16 count = 0;
+
+ mode_page_offset = sequence->command_specific_data.process_state.mode_page_offset;
+
+ sequence->type = SATI_SEQUENCE_MODE_SELECT_MODE_POWER_CONDITION;
+
+ for(index = 0; index < SCSI_MODE_PAGE_1A_LENGTH; index++)
+ {
+ sati_get_data_byte(sequence, scsi_io, mode_page_offset+index, &current_mode_page[index]);
+ }
+
+ //Check for data validity
+ //SPF(0b); Page length 0x0A;
+
+ if (((current_mode_page[0] & SCSI_MODE_SELECT_MODE_PAGE_SPF_MASK)!= 0) ||
+ (current_mode_page[1] != (SCSI_MODE_PAGE_1A_LENGTH - 2) ) ||
+ ((current_mode_page[3] & SCSI_MODE_PAGE_POWER_CONDITION_IDLE)!= 0)
+ )
+ {
+ //parameter data passed in containing data that doesn't meet the SAT-2 requirement
+ return SATI_FAILURE_CHECK_RESPONSE_DATA;
+ }
+
+ // STANDBY bit is set to 0, do nothing since the standby timer can't be set;
+ // STANDBY bit is set to 1, translate the standby timer
+ // SCSI_MODE_PAGE_POWER_CONDITION_STANDBY== 0x01
+ if (current_mode_page[3] & SCSI_MODE_PAGE_POWER_CONDITION_STANDBY)
+ {
+ timer = (current_mode_page[8]<<24) + (current_mode_page[9]<<16) + (current_mode_page[10]<<8) + current_mode_page[11];
+
+ //If the ATA IDENTIFY DEVICE data word 49, bit 13 is set to one,
+ if (sequence->device->capabilities & SATI_DEVICE_CAP_STANDBY_ENABLE)
+ {
+ if (timer == 0)
+ {
+ //TPV=0 send ATA STANDBY_IMMEDIATE
+ sati_ata_standby_immediate_construct(ata_io, sequence);
+ sequence->command_specific_data.translated_command = ATA_STANDBY_IMMED;
+ }
+ else if ((timer > 0) && (timer <= 12000))
+ {
+ //1 to 12 000 INT((z - 1) / 50) + 1
+ count = (U16)((timer -1) / 50) + 1;
+ sati_ata_standby_construct(ata_io, sequence, count);
+ }
+ else if ((timer > 12000) && (timer <= 12600))
+ {
+ //12 001 to 12 600 FCh
+ sati_ata_standby_construct(ata_io, sequence, 0xFC);
+ }
+ else if ((timer > 12600) && (timer <= 12750))
+ {
+ //12 601 to 12 750 FFh
+ sati_ata_standby_construct(ata_io, sequence, 0xFF);
+ }
+ else if ((timer > 12750) && (timer < 18000))
+ {
+ //12 751 to 17 999 F1h
+ sati_ata_standby_construct(ata_io, sequence, 0xF1);
+ }
+ else if ((timer >= 18000) && (timer <= 198000))
+ {
+ //18 000 to 198 000 INT(z / 18 000) + 240
+ count = (U16)(timer / 18000) + 240;
+ sati_ata_standby_construct(ata_io, sequence, count);
+ }
+ else
+ {
+ //All other values FDh
+ sati_ata_standby_construct(ata_io, sequence, 0xFD);
+ }
+ status = SATI_SUCCESS ;
+ }
+ else
+ {
+ status = SATI_FAILURE_CHECK_RESPONSE_DATA;
+ //If the ATA IDENTIFY DEVICE data word 49, bit 13 is set to 0
+ }
+ }
+ else
+ {
+ status = SATI_COMPLETE;
+ }
+
+ sequence->command_specific_data.process_state.size_of_data_processed += page_size;
+ sequence->command_specific_data.process_state.mode_page_offset += page_size;
+ sequence->command_specific_data.process_state.current_mode_page_processed = TRUE;
+
+ return status;
+}
+
+/**
+ * @brief This method will process the mode page.
+ *
+ *
+ * @return Indicate if the translation was successful.
+ * @retval SATI_SUCCESS
+ * @retval SATI_COMPLETE
+ * @retval SATI_FAILURE_CHECK_RESPONSE_DATA
+ */
+static
+SATI_STATUS sati_mode_select_process_mode_page(
+ SATI_TRANSLATOR_SEQUENCE_T* sequence,
+ void * scsi_io,
+ void * ata_io
+)
+{
+ SATI_STATUS status = SATI_FAILURE_CHECK_RESPONSE_DATA;
+
+ U8 page_code;
+ U32 page_size = 0; // in bytes
+ U32 size_of_data_to_be_processed;
+
+ U8 page_code_byte;
+ U32 mode_page_offset;
+
+ mode_page_offset = sequence->command_specific_data.process_state.mode_page_offset;
+
+ sati_get_data_byte(sequence, scsi_io, mode_page_offset, &page_code_byte);
+
+ // No more pages.
+ if(sequence->command_specific_data.process_state.mode_pages_size >
+ sequence->command_specific_data.process_state.size_of_data_processed)
+ {
+ //SCSI_MODE_SENSE_PAGE_CODE_ENABLE==0x3f same for Mode Select
+ page_code = page_code_byte & SCSI_MODE_SENSE_PAGE_CODE_ENABLE;
+ page_size = sati_mode_select_get_mode_page_size(page_code);
+ size_of_data_to_be_processed = sequence->command_specific_data.process_state.mode_pages_size
+ - sequence->command_specific_data.process_state.size_of_data_processed;
+
+ if( page_size == 0 )
+ {
+ status = SATI_FAILURE_CHECK_RESPONSE_DATA;
+ }
+ else
+ {
+ // process mode page
+ switch(page_code)
+ {
+ case SCSI_MODE_PAGE_READ_WRITE_ERROR:
+ status = sati_mode_select_process_mode_page_read_write_error_recovery(
+ sequence,
+ scsi_io,
+ page_size
+ );
+ break;
+
+ case SCSI_MODE_PAGE_DISCONNECT_RECONNECT:
+ status = sati_mode_select_process_mode_page_disconnect_reconnect(
+ &sequence->command_specific_data.process_state,
+ page_size
+ );
+ break;
+
+ case SCSI_MODE_PAGE_CACHING:
+ status = sati_mode_select_process_mode_page_caching(
+ sequence,
+ scsi_io,
+ ata_io,
+ page_size
+ );
+ break;
+
+ case SCSI_MODE_PAGE_CONTROL:
+ status = sati_mode_select_process_mode_page_control(
+ sequence,
+ scsi_io,
+ ata_io,
+ page_size
+ );
+ break;
+
+ case SCSI_MODE_PAGE_INFORMATIONAL_EXCP_CONTROL:
+ status = sati_mode_select_process_mode_page_informational_exception_control(
+ sequence,
+ scsi_io,
+ ata_io,
+ page_size
+ );
+ break;
+
+ case SCSI_MODE_PAGE_POWER_CONDITION:
+ status = sati_mode_select_process_mode_page_power_condition(
+ sequence,
+ scsi_io,
+ ata_io,
+ page_size
+ );
+
+ break;
+
+ default:
+ break;
+ }
+
+ }
+ }
+
+ return status;
+}
+
+//******************************************************************************
+//* P U B L I C M E T H O D S
+//******************************************************************************
+
+/**
+ * @brief This method will translate the SCSI Mode Select 6 byte or 10 byte command
+ * into corresponding ATA commands. Depending upon the capabilities
+ * supported by the target different ATA commands can be selected.
+ * Additionally, in some cases more than a single ATA command may
+ * be required.
+ *
+ * @return Indicate if the command translation succeeded.
+ * @retval SCI_SUCCESS This is returned if the command translation was
+ * successful.
+ * @retval SCI_COMPLETE This is returned if the command translation was
+ * successful and no ATA commands need to be set.
+ * @retval SATI_FAILURE_CHECK_RESPONSE_DATA This value is returned if
+ * sense data has been created as a result of something specified
+ * in the parameter data fields.
+ */
+static
+SATI_STATUS sati_mode_select_translate_command(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ void * ata_io,
+ U32 cdb_size
+)
+{
+ SATI_STATUS status = SATI_FAILURE_CHECK_RESPONSE_DATA;
+ U32 mode_page_offset;
+ U32 block_descriptor_length;
+ U32 index;
+ U16 data_transfer_length;
+ U8 current_mode_parameters[8]={0,0,0,0,0,0,0,0};
+ U8 * cdb = sati_cb_get_cdb_address(scsi_io);
+
+ // cdb_size must be 6 or 10
+ if(FALSE == (cdb_size == 6 || cdb_size == 10))
+ {
+ return status;
+ }
+
+ if(sequence->state == SATI_SEQUENCE_STATE_INITIAL)
+ {
+ sequence->command_specific_data.process_state.ata_command_sent_for_cmp = 0;
+ sequence->state = SATI_SEQUENCE_STATE_TRANSLATE_DATA;
+ }
+
+ //First, initializes mode_sel_processing_state
+ if ( sequence->command_specific_data.process_state.ata_command_sent_for_cmp == 0 )
+ {
+ if (cdb_size == 6)
+ {
+ //CDB byte 4 is the parameter length
+ data_transfer_length = sati_get_cdb_byte(cdb, 4);
+ }
+ else
+ {
+ //CDB byte 7 and 8 for Mode Select 10
+ data_transfer_length = (sati_get_cdb_byte(cdb, 7) << 8) + sati_get_cdb_byte(cdb, 8);
+ }
+
+ sequence->allocation_length = data_transfer_length;
+
+ //Get 8 bytes for headers (4 bytes for Mode Select 6 and 8 bytes for Mode Select 10)
+ for( index = 0; index < 8; index++ )
+ {
+ sati_get_data_byte(sequence, scsi_io, index, &current_mode_parameters[index]);
+ }
+
+ //medium type should be 0
+ if ( sati_mode_select_get_medium_type(current_mode_parameters, cdb_size) != 0 )
+ {
+ sati_scsi_sense_data_construct(
+ sequence,
+ scsi_io,
+ SCSI_STATUS_CHECK_CONDITION,
+ SCSI_SENSE_ILLEGAL_REQUEST,
+ SCSI_ASC_INVALID_FIELD_IN_PARM_LIST,
+ SCSI_ASCQ_INVALID_FIELD_IN_PARM_LIST
+ );
+ return status;
+ }
+
+ block_descriptor_length = sati_mode_select_get_mode_block_descriptor_length(
+ current_mode_parameters,
+ cdb_size
+ );
+
+ mode_page_offset = sati_mode_select_get_mode_page_offset(
+ block_descriptor_length,
+ cdb_size
+ );
+
+ if(mode_page_offset > data_transfer_length)
+ {
+ sequence->state = SATI_SEQUENCE_STATE_FINAL;
+ status = SATI_FAILURE_CHECK_RESPONSE_DATA;
+ }
+ else
+ {
+ sati_mode_select_initialize_mode_sel_processing_state(
+ sequence,
+ scsi_io,
+ ata_io,
+ data_transfer_length,
+ mode_page_offset
+ );
+
+ }
+ }
+
+ // move to next mode page
+ if(sequence->command_specific_data.process_state.current_mode_page_processed)
+ {
+ sequence->command_specific_data.process_state.ata_command_sent_for_cmp = 0;
+ sequence->command_specific_data.process_state.current_mode_page_processed = FALSE;
+ }
+
+ status = sati_mode_select_process_mode_page(sequence, scsi_io, ata_io);
+
+ if(sequence->command_specific_data.process_state.current_mode_page_processed != FALSE)
+ {
+ // Done this page
+ sequence->state = SATI_SEQUENCE_STATE_FINAL;
+ }
+ else
+ {
+ sequence->state = SATI_SEQUENCE_STATE_INCOMPLETE;
+ }
+
+ if(status == SATI_FAILURE_CHECK_RESPONSE_DATA)
+ {
+ sequence->state = SATI_SEQUENCE_STATE_FINAL;
+ sati_scsi_sense_data_construct(
+ sequence,
+ scsi_io,
+ SCSI_STATUS_CHECK_CONDITION,
+ SCSI_SENSE_ILLEGAL_REQUEST,
+ SCSI_ASC_INVALID_FIELD_IN_PARM_LIST,
+ SCSI_ASCQ_INVALID_FIELD_IN_PARM_LIST
+ );
+ }
+
+ return status;
+}
+
+/**
+ * @brief This method will call Mode Select 6 Translation command
+ * For more information on the parameters passed to this method,
+ * please reference sati_translate_command().
+ *
+ * @return Indicate if the command translation succeeded.
+ * @retval SCI_SUCCESS This is returned if the command translation was
+ * successful.
+ * @retval SCI_COMPLETE This is returned if the command translation was
+ * successful and no ATA commands need to be set.
+ * @retval SATI_FAILURE_CHECK_RESPONSE_DATA This value is returned if
+ * sense data has been created as a result of something specified
+ * in the parameter data fields.
+ */
+SATI_STATUS sati_mode_select_6_translate_command(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ void * ata_io
+)
+{
+ SATI_STATUS status=SATI_FAILURE;
+ U8 * cdb = sati_cb_get_cdb_address(scsi_io);
+
+ //PF bit needs to be 1 byte1 bit ???1????
+ if ((sati_get_cdb_byte(cdb, 1) & SCSI_MODE_SELECT_PF_MASK) == !SCSI_MODE_SELECT_PF_BIT)
+ {
+ sati_scsi_sense_data_construct(
+ sequence,
+ scsi_io,
+ SCSI_STATUS_CHECK_CONDITION,
+ SCSI_SENSE_ILLEGAL_REQUEST,
+ SCSI_ASC_INVALID_FIELD_IN_CDB,
+ SCSI_ASCQ_INVALID_FIELD_IN_CDB
+ );
+ status = SATI_FAILURE_CHECK_RESPONSE_DATA;
+ return status;
+ }
+
+ status=sati_mode_select_translate_command(
+ sequence,
+ scsi_io,
+ ata_io,
+ 6
+ );
+
+ if(status == SATI_FAILURE_CHECK_RESPONSE_DATA)
+ {
+ sati_scsi_sense_data_construct(
+ sequence,
+ scsi_io,
+ SCSI_STATUS_CHECK_CONDITION,
+ SCSI_SENSE_ILLEGAL_REQUEST,
+ SCSI_ASC_INVALID_FIELD_IN_PARM_LIST,
+ SCSI_ASCQ_INVALID_FIELD_IN_PARM_LIST
+ );
+ }
+ return status;
+
+}
+
+/**
+ * @brief This method will call Mode Select 10 translation command
+ * For more information on the parameters passed to this method,
+ * please reference sati_translate_command().
+ *
+ * @return Indicate if the command translation succeeded.
+ * @retval SCI_SUCCESS This is returned if the command translation was
+ * successful.
+ * @retval SCI_COMPLETE This is returned if the command translation was
+ * successful and no ATA commands need to be set.
+ * @retval SATI_FAILURE_CHECK_RESPONSE_DATA This value is returned if
+ * sense data has been created as a result of something specified
+ * in the parameter data fields.
+ */
+SATI_STATUS sati_mode_select_10_translate_command(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ void * ata_io
+)
+{
+ SATI_STATUS status=SATI_FAILURE;
+ U8 * cdb = sati_cb_get_cdb_address(scsi_io);
+
+ //PF bit needs to be 1 byte1 bit ???1????
+ if ((sati_get_cdb_byte(cdb, 1) & SCSI_MODE_SELECT_PF_MASK) == !SCSI_MODE_SELECT_PF_BIT)
+ {
+ sati_scsi_sense_data_construct(
+ sequence,
+ scsi_io,
+ SCSI_STATUS_CHECK_CONDITION,
+ SCSI_SENSE_ILLEGAL_REQUEST,
+ SCSI_ASC_INVALID_FIELD_IN_CDB,
+ SCSI_ASCQ_INVALID_FIELD_IN_CDB
+ );
+ status = SATI_FAILURE_CHECK_RESPONSE_DATA;
+ return status;
+ }
+
+ status=sati_mode_select_translate_command(
+ sequence,
+ scsi_io,
+ ata_io,
+ 10
+ );
+
+ if(status == SATI_FAILURE_CHECK_RESPONSE_DATA)
+ {
+ sati_scsi_sense_data_construct(
+ sequence,
+ scsi_io,
+ SCSI_STATUS_CHECK_CONDITION,
+ SCSI_SENSE_ILLEGAL_REQUEST,
+ SCSI_ASC_INVALID_FIELD_IN_PARM_LIST,
+ SCSI_ASCQ_INVALID_FIELD_IN_PARM_LIST
+ );
+ }
+ return status;
+}
+
+/**
+* @brief This method will conduct error handling for the ATA Set Features command
+* that is issued during a Mode Select translation for the Caching Mode
+* page.
+*
+*
+* @return Indicate if the command translation succeeded.
+*
+* @retval SCI_COMPLETE This is returned if the command translation was
+* successful and no additional ATA commands need to be set.
+* @retval SATI_FAILURE_CHECK_RESPONSE_DATA This value is returned if
+* sense data has been created as a result of an error returned
+*/
+SATI_STATUS sati_mode_select_translate_response(
+SATI_TRANSLATOR_SEQUENCE_T * sequence,
+void * scsi_io,
+void * ata_io
+)
+{
+ U8 * register_fis = sati_cb_get_d2h_register_fis_address(ata_io);
+ SATI_STATUS status = SATI_FAILURE;
+
+ if(sati_get_ata_status(register_fis) & ATA_STATUS_REG_ERROR_BIT)
+ {
+ sati_scsi_sense_data_construct(
+ sequence,
+ scsi_io,
+ SCSI_STATUS_CHECK_CONDITION,
+ SCSI_SENSE_ABORTED_COMMAND,
+ SCSI_ASC_NO_ADDITIONAL_SENSE,
+ SCSI_ASCQ_NO_ADDITIONAL_SENSE
+ );
+ status = SATI_FAILURE_CHECK_RESPONSE_DATA;
+ }
+ else
+ {
+ if (sequence->state == SATI_SEQUENCE_STATE_INCOMPLETE)
+ {
+ status = SATI_SEQUENCE_INCOMPLETE;
+ }
+ else
+ {
+ status = SATI_COMPLETE;
+ }
+ }
+ return status;
+}
+
+#endif // !defined(DISABLE_SATI_MODE_SELECT)
diff --git a/sys/dev/isci/scil/sati_mode_select.h b/sys/dev/isci/scil/sati_mode_select.h
new file mode 100644
index 0000000..ce0e5d4
--- /dev/null
+++ b/sys/dev/isci/scil/sati_mode_select.h
@@ -0,0 +1,84 @@
+/*-
+ * 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.
+ *
+ * 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.
+ *
+ * $FreeBSD$
+ */
+#ifndef _SATI_MODE_SELECT_H_
+#define _SATI_MODE_SELECT_H_
+
+/**
+ * @file
+ * @brief This file contains the method implementations required to
+ * translate the SCSI mode select (6 and 10-byte) commands.
+ */
+
+#include <dev/isci/scil/sati_types.h>
+#include <dev/isci/scil/sati_translator_sequence.h>
+
+SATI_STATUS sati_mode_select_6_translate_command(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ void * ata_io
+);
+
+SATI_STATUS sati_mode_select_10_translate_command(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ void * ata_io
+);
+
+SATI_STATUS sati_mode_select_translate_response(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ void * ata_io
+);
+
+#endif // _SATI_MODE_SELECT_H_
diff --git a/sys/dev/isci/scil/sati_mode_sense.c b/sys/dev/isci/scil/sati_mode_sense.c
new file mode 100644
index 0000000..e03cbdb
--- /dev/null
+++ b/sys/dev/isci/scil/sati_mode_sense.c
@@ -0,0 +1,837 @@
+ /*-
+ * 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.
+ *
+ * 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 <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/**
+ * @file
+ * @brief This file contains the method implementations required to
+ * translate the SCSI mode sense (6 and 10-byte) commands.
+ */
+
+#if !defined(DISABLE_SATI_MODE_SENSE)
+
+#include <dev/isci/scil/sati_mode_sense.h>
+#include <dev/isci/scil/sati_mode_pages.h>
+#include <dev/isci/scil/sati_callbacks.h>
+#include <dev/isci/scil/sati_util.h>
+#include <dev/isci/scil/intel_scsi.h>
+#include <dev/isci/scil/intel_ata.h>
+
+//******************************************************************************
+//* P R I V A T E M E T H O D S
+//******************************************************************************
+
+#define STANDBY_TIMER_DISABLED 0x00
+#define STANDBY_TIMER_ENABLED 0x01
+#define STANDBY_TIMER_SUPPORTED 0x2000
+
+
+
+/**
+ * @brief This method indicates if the supplied page control is supported
+ * by this translation implementation. Currently savable parameters
+ * (i.e. non-volatile) are not supported.
+ * For more information on the parameters passed to this method,
+ * please reference sati_translate_command().
+ *
+ * @return This method returns an indication of whether the page control
+ * specified in the SCSI CDB is supported.
+ * @retval SATI_SUCCESS This value is returned if the page control is
+ * supported.
+ * @retval SATI_FAILURE_CHECK_RESPONSE_DATA This value is returned if the
+ * page control is not supported.
+ */
+static
+SATI_STATUS sati_mode_sense_is_page_control_supported(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io
+)
+{
+ U8 * cdb = sati_cb_get_cdb_address(scsi_io);
+
+ switch (sati_get_cdb_byte(cdb, 2) >> SCSI_MODE_SENSE_PC_SHIFT)
+ {
+ case SCSI_MODE_SENSE_PC_CURRENT:
+ case SCSI_MODE_SENSE_PC_DEFAULT:
+ case SCSI_MODE_SENSE_PC_CHANGEABLE:
+ return SATI_SUCCESS;
+ break;
+
+ default:
+ case SCSI_MODE_SENSE_PC_SAVED:
+ sati_scsi_sense_data_construct(
+ sequence,
+ scsi_io,
+ SCSI_STATUS_CHECK_CONDITION,
+ SCSI_SENSE_ILLEGAL_REQUEST,
+ SCSI_ASC_SAVING_PARMS_NOT_SUPPORTED,
+ SCSI_ASCQ_SAVING_PARMS_NOT_SUPPORTED
+ );
+ return SATI_FAILURE_CHECK_RESPONSE_DATA;
+ break;
+ }
+}
+
+/**
+ * @brief This method indicates if the page code field in the SCSI CDB
+ * is supported by this translation.
+ * For more information on the parameters passed to this method,
+ * please reference sati_translate_command().
+ *
+ * @param[in] cdb_length This parameter specifies the length of the SCSI
+ * CDB being translated (e.g. 6-byte, 10-byte, 12-byte, etc.)
+ *
+ * @return This method returns an indication as to whether the page code
+ * in the CDB is supported.
+ * @retval SATI_SUCCESS This value is returned if the page code is
+ * supported.
+ * @retval SATI_FAILURE_CHECK_RESPONSE_DATA This value is returned if the
+ * page code is not supported.
+ */
+static
+SATI_STATUS sati_mode_sense_is_page_code_supported(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ U8 cdb_length
+)
+{
+ U8 * cdb = sati_cb_get_cdb_address(scsi_io);
+
+ switch (sati_get_cdb_byte(cdb, 2) & SCSI_MODE_SENSE_PAGE_CODE_ENABLE)
+ {
+ case SCSI_MODE_PAGE_CACHING:
+ if (sati_get_cdb_byte(cdb, 0) == SCSI_MODE_SENSE_6)
+ sequence->type = SATI_SEQUENCE_MODE_SENSE_6_CACHING;
+ else
+ sequence->type = SATI_SEQUENCE_MODE_SENSE_10_CACHING;
+ break;
+
+ case SCSI_MODE_PAGE_ALL_PAGES:
+ if (sati_get_cdb_byte(cdb, 0) == SCSI_MODE_SENSE_6)
+ sequence->type = SATI_SEQUENCE_MODE_SENSE_6_ALL_PAGES;
+ else
+ sequence->type = SATI_SEQUENCE_MODE_SENSE_10_ALL_PAGES;
+ break;
+
+ case SCSI_MODE_PAGE_READ_WRITE_ERROR:
+ if (sati_get_cdb_byte(cdb, 0) == SCSI_MODE_SENSE_6)
+ sequence->type = SATI_SEQUENCE_MODE_SENSE_6_READ_WRITE_ERROR;
+ else
+ sequence->type = SATI_SEQUENCE_MODE_SENSE_10_READ_WRITE_ERROR;
+ break;
+
+ case SCSI_MODE_PAGE_DISCONNECT_RECONNECT:
+ if (sati_get_cdb_byte(cdb, 0) == SCSI_MODE_SENSE_6)
+ sequence->type = SATI_SEQUENCE_MODE_SENSE_6_DISCONNECT_RECONNECT;
+ else
+ sequence->type = SATI_SEQUENCE_MODE_SENSE_10_DISCONNECT_RECONNECT;
+ break;
+
+ case SCSI_MODE_PAGE_CONTROL:
+ if (sati_get_cdb_byte(cdb, 0) == SCSI_MODE_SENSE_6)
+ sequence->type = SATI_SEQUENCE_MODE_SENSE_6_CONTROL;
+ else
+ sequence->type = SATI_SEQUENCE_MODE_SENSE_10_CONTROL;
+ break;
+
+ case SCSI_MODE_PAGE_POWER_CONDITION:
+ if (sati_get_cdb_byte(cdb, 0) == SCSI_MODE_SENSE_6)
+ sequence->type = SATI_SEQUENCE_MODE_SENSE_6_POWER_CONDITION;
+ else
+ sequence->type = SATI_SEQUENCE_MODE_SENSE_10_POWER_CONDITION;
+ break;
+
+ case SCSI_MODE_PAGE_INFORMATIONAL_EXCP_CONTROL:
+ // The informational exceptions control page is only useful
+ // if SMART is supported.
+ if ((sequence->device->capabilities | SATI_DEVICE_CAP_SMART_SUPPORT)
+ == 0)
+ {
+ // For a MODE SENSE, utilize INVALID FIELD IN CDB,
+ // For a MODE SELECT, utilize INVALID FIELD IN PARAMETER LIST.
+ if (sati_get_cdb_byte(cdb, 0) == SCSI_MODE_SENSE_6)
+ {
+ sati_scsi_sense_data_construct(
+ sequence,
+ scsi_io,
+ SCSI_STATUS_CHECK_CONDITION,
+ SCSI_SENSE_ILLEGAL_REQUEST,
+ SCSI_ASC_INVALID_FIELD_IN_CDB,
+ SCSI_ASCQ_INVALID_FIELD_IN_CDB
+ );
+ }
+ else
+ {
+ sati_scsi_sense_data_construct(
+ sequence,
+ scsi_io,
+ SCSI_STATUS_CHECK_CONDITION,
+ SCSI_SENSE_ILLEGAL_REQUEST,
+ SCSI_ASC_INVALID_FIELD_IN_PARM_LIST,
+ SCSI_ASCQ_INVALID_FIELD_IN_PARM_LIST
+ );
+ }
+
+ return SATI_FAILURE_CHECK_RESPONSE_DATA;
+ }
+
+ if (sati_get_cdb_byte(cdb, 0) == SCSI_MODE_SENSE_6)
+ sequence->type = SATI_SEQUENCE_MODE_SENSE_6_INFORMATIONAL_EXCP_CONTROL;
+ else
+ sequence->type = SATI_SEQUENCE_MODE_SENSE_10_INFORMATIONAL_EXCP_CONTROL;
+ break;
+
+ default:
+ sati_scsi_sense_data_construct(
+ sequence,
+ scsi_io,
+ SCSI_STATUS_CHECK_CONDITION,
+ SCSI_SENSE_ILLEGAL_REQUEST,
+ SCSI_ASC_INVALID_FIELD_IN_CDB,
+ SCSI_ASCQ_INVALID_FIELD_IN_CDB
+ );
+ return SATI_FAILURE_CHECK_RESPONSE_DATA;
+ break;
+ }
+
+ return SATI_SUCCESS;
+}
+
+//******************************************************************************
+//* P R O T E C T E D M E T H O D S
+//******************************************************************************
+
+/**
+ * @brief This method will calculate the size of the mode sense data header.
+ * This includes the block descriptor if one is requested.
+ *
+ * @param[in] scsi_io This parameter specifies the user's SCSI IO object
+ * for which to calculate the mode page header.
+ * @param[in] cdb_size This parameter specifies the number of bytes
+ * associated with the CDB for which to calculate the header.
+ *
+ * @return This method returns the size, in bytes, for the mode page header.
+ */
+U16 sati_mode_sense_calculate_page_header(
+ void * scsi_io,
+ U8 cdb_size
+)
+{
+ U8 * cdb = sati_cb_get_cdb_address(scsi_io);
+ U16 page_length = 0;
+
+ // The Mode page header length is different for 6-byte vs. 10-byte CDBs.
+ if (cdb_size == 6)
+ page_length += SCSI_MODE_SENSE_6_HEADER_LENGTH;
+ else
+ page_length += SCSI_MODE_SENSE_10_HEADER_LENGTH;
+
+ // Are block descriptors disabled (DBD)? 0 indicates they are enabled.
+ if ((sati_get_cdb_byte(cdb, 1) & SCSI_MODE_SENSE_DBD_ENABLE) == 0)
+ {
+ // The LLBAA bit is not defined for 6-byte mode sense requests.
+ if ( (cdb_size == 10)
+ && (sati_get_cdb_byte(cdb, 1) & SCSI_MODE_SENSE_LLBAA_ENABLE) )
+ page_length += SCSI_MODE_SENSE_LLBA_BLOCK_DESCRIPTOR_LENGTH;
+ else
+ page_length += SCSI_MODE_SENSE_STD_BLOCK_DESCRIPTOR_LENGTH;
+ }
+
+ return page_length;
+}
+
+/**
+ * @brief This method performs command translation common to all mode sense
+ * requests (6 or 10 byte).
+ * For more information on the parameters passed to this method,
+ * please reference sati_translate_command().
+ *
+ * @param[in] cdb_length This parameter specifies the number of bytes
+ * in the CDB (6 or 10).
+ *
+ * @return This method returns an indication as to whether the translation
+ * succeeded.
+ * @retval SCI_SUCCESS This value is returned if translation succeeded.
+ * @see sati_mode_sense_is_page_control_supported() or
+ * sati_mode_sense_is_page_code_supported() for more information.
+ */
+SATI_STATUS sati_mode_sense_translate_command(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ void * ata_io,
+ U8 cdb_length
+)
+{
+ SATI_STATUS status;
+
+ /**
+ * Validate that the supplied page control (PC) field is supported.
+ */
+ status = sati_mode_sense_is_page_control_supported(sequence, scsi_io);
+ if (status != SATI_SUCCESS)
+ return status;
+
+ /**
+ * Validate that the supplied page code is supported.
+ */
+ status = sati_mode_sense_is_page_code_supported(sequence,scsi_io,cdb_length);
+ if (status != SATI_SUCCESS)
+ return status;
+
+ sati_ata_identify_device_construct(ata_io, sequence);
+
+ return SATI_SUCCESS;
+}
+
+/**
+ * @brief This method will build the standard block descriptor for a MODE
+ * SENSE 6 or 10 byte request.
+ * For more information on the parameters passed to this method,
+ * please reference sati_translate_command().
+ *
+ * @param[in] identify This parameter specifies the IDENTIFY DEVICE data
+ * associated with the SCSI IO.
+ * @param[in] offset This parameter specifies the offset into the data
+ * buffer at which to build the block descriptor.
+ *
+ * @return This method returns the size of the block descriptor built.
+ */
+U32 sati_mode_sense_build_std_block_descriptor(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ ATA_IDENTIFY_DEVICE_DATA_T * identify,
+ U32 offset
+)
+{
+ U32 lba_low = 0;
+ U32 lba_high = 0;
+ U32 sector_size = 0;
+
+ // Extract the sector information (sector size, logical blocks) from
+ // the retrieved ATA identify device data.
+ sati_ata_identify_device_get_sector_info(
+ identify, &lba_high, &lba_low, &sector_size
+ );
+
+ // Fill in the 4-byte logical block address field.
+ sati_set_data_byte(sequence, scsi_io, offset, (U8)((lba_low>>24) & 0xFF));
+ sati_set_data_byte(sequence, scsi_io, offset+1, (U8)((lba_low>>16) & 0xFF));
+ sati_set_data_byte(sequence, scsi_io, offset+2, (U8)((lba_low>>8) & 0xFF));
+ sati_set_data_byte(sequence, scsi_io, offset+3, (U8)(lba_low & 0xFF));
+
+ // Clear the reserved field.
+ sati_set_data_byte(sequence, scsi_io, offset+4, 0);
+
+ // Fill in the three byte Block Length field
+ sati_set_data_byte(sequence,scsi_io, offset+5, (U8)((sector_size>>16) & 0xFF));
+ sati_set_data_byte(sequence,scsi_io, offset+6, (U8)((sector_size>>8) & 0xFF));
+ sati_set_data_byte(sequence,scsi_io, offset+7, (U8)(sector_size & 0xFF));
+
+ return SCSI_MODE_SENSE_STD_BLOCK_DESCRIPTOR_LENGTH;
+}
+
+/**
+ * @brief This method simply copies the mode sense data into the buffer
+ * at the location specified by page_start. The buffer copied is
+ * determined by page_control (e.g. current, default, or changeable
+ * values).
+ * For more information on the parameters passed to this method,
+ * please reference sati_translate_command().
+ *
+ * @param[in] page_start This parameter specifies the starting offset at
+ * which to copy the mode page data.
+ * @param[in] page_control This parameter specifies the page control
+ * indicating the source buffer to be copied.
+ * @param[in] page_code This specifies the mode sense page to copy.
+ *
+ * @return This method returns the size of the mode page data being copied.
+ */
+U32 sati_mode_sense_copy_initial_data(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ U32 page_start,
+ U8 page_control,
+ U8 page_code
+)
+{
+ U16 page_index = sati_mode_page_get_page_index(page_code);
+ U32 page_length = sat_mode_page_sizes[page_index];
+
+ // Find out if the current values are requested or if the default
+ // values are being requested.
+ if (page_control == SCSI_MODE_SENSE_PC_CHANGEABLE)
+ {
+ // Copy the changeable mode page information.
+ sati_copy_data(
+ sequence,
+ scsi_io,
+ page_start,
+ sat_changeable_mode_pages[page_index],
+ page_length
+ );
+ }
+ else
+ {
+ // Copy the default static values template to the user data area.
+ sati_copy_data(
+ sequence,
+ scsi_io,
+ page_start,
+ sat_default_mode_pages[page_index],
+ page_length
+ );
+ }
+
+ return page_length;
+}
+
+/**
+ * @brief This method performs the read/write error recovery mode page
+ * specific data translation based upon the contents of the remote
+ * device IDENTIFY DEVICE data.
+ * For more information on the parameters passed to this method,
+ * please reference sati_translate_command().
+ *
+ * @param[in] identify This parameter specifies the remote device's
+ * IDENTIFY DEVICE data received as part of the IO request.
+ * @param[in] offset This parameter specifies the offset into the data
+ * buffer where the translated data is to be written.
+ *
+ * @return This method returns the size of the mode page data that was
+ * translated.
+ */
+U32 sati_mode_sense_read_write_error_translate_data(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ ATA_IDENTIFY_DEVICE_DATA_T * identify,
+ U32 offset
+)
+{
+ U8 * cdb = sati_cb_get_cdb_address(scsi_io);
+ U8 page_control = sati_get_cdb_byte(cdb, 2) >> SCSI_MODE_SENSE_PC_SHIFT;
+ U32 page_length;
+
+ page_length = sati_mode_sense_copy_initial_data(
+ sequence,
+ scsi_io,
+ offset,
+ page_control,
+ SCSI_MODE_PAGE_READ_WRITE_ERROR
+ );
+
+ // Currently we do not override any bits in this mode page from the
+ // identify data.
+
+ return page_length;
+}
+
+/**
+ * @brief This method performs the disconnect/reconnect mode page
+ * specific data translation based upon the contents of the remote
+ * device IDENTIFY DEVICE data.
+ * For more information on the parameters passed to this method,
+ * please reference sati_translate_command().
+ *
+ * @param[in] identify This parameter specifies the remote device's
+ * IDENTIFY DEVICE data received as part of the IO request.
+ * @param[in] offset This parameter specifies the offset into the data
+ * buffer where the translated data is to be written.
+ *
+ * @return This method returns the size of the mode page data that was
+ * translated.
+ */
+U32 sati_mode_sense_disconnect_reconnect_translate_data(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ ATA_IDENTIFY_DEVICE_DATA_T * identify,
+ U32 offset
+)
+{
+ U8 * cdb = sati_cb_get_cdb_address(scsi_io);
+ U8 page_control = sati_get_cdb_byte(cdb, 2) >> SCSI_MODE_SENSE_PC_SHIFT;
+ U32 page_length;
+
+ page_length = sati_mode_sense_copy_initial_data(
+ sequence,
+ scsi_io,
+ offset,
+ page_control,
+ SCSI_MODE_PAGE_DISCONNECT_RECONNECT
+ );
+
+ // Currently we do not override any bits in this mode page from the
+ // identify data.
+
+ return page_length;
+}
+
+/**
+ * @brief This method performs the caching mode page specific data
+ * translation based upon the contents of the remote device IDENTIFY
+ * DEVICE data.
+ * For more information on the parameters passed to this method,
+ * please reference sati_translate_command().
+ *
+ * @param[in] identify This parameter specifies the remote device's
+ * IDENTIFY DEVICE data received as part of the IO request.
+ * @param[in] offset This parameter specifies the offset into the data
+ * buffer where the translated data is to be written.
+ *
+ * @return This method returns the size of the mode page data that was
+ * translated.
+ */
+U32 sati_mode_sense_caching_translate_data(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ ATA_IDENTIFY_DEVICE_DATA_T * identify,
+ U32 offset
+)
+{
+ U8 * cdb = sati_cb_get_cdb_address(scsi_io);
+ U8 page_control = sati_get_cdb_byte(cdb, 2) >> SCSI_MODE_SENSE_PC_SHIFT;
+ U32 page_length;
+
+ page_length = sati_mode_sense_copy_initial_data(
+ sequence,
+ scsi_io,
+ offset,
+ page_control,
+ SCSI_MODE_PAGE_CACHING
+ );
+
+ // If the request queried for the current values, then
+ // we need to translate the data from the IDENTIFY DEVICE request.
+ if (page_control == SCSI_MODE_SENSE_PC_CURRENT)
+ {
+ U8 value;
+
+ // Update the Write Cache Enabled (WCE) bit in the mode page data
+ // buffer based on the identify response.
+ if ((identify->command_set_enabled0 & ATA_IDENTIFY_DEVICE_WCE_ENABLE) != 0)
+ {
+ sati_get_data_byte(sequence, scsi_io, offset+2, &value);
+ value |= SCSI_MODE_PAGE_CACHE_PAGE_WCE_BIT;
+ sati_set_data_byte(sequence, scsi_io, offset+2, value);
+ //This byte has been set twice and needs to be decremented
+ sequence->number_data_bytes_set--;
+ }
+
+ // Update the Disable Read Ahead (DRA) bit in the mode page data
+ // buffer based on the identify response.
+ if ((identify->command_set_enabled0 & ATA_IDENTIFY_DEVICE_RA_ENABLE) == 0)
+ {
+ // In SATA the polarity of the bits is inverse.
+ // - SCSI = Disable Read Ahead
+ // - ATA = Read Ahead
+ sati_get_data_byte(sequence, scsi_io, offset+12, &value);
+ value |= SCSI_MODE_PAGE_CACHE_PAGE_DRA_BIT;
+ sati_set_data_byte(sequence, scsi_io, offset+12, value);
+
+ //This byte has been set twice, the first time in
+ //sati_mode_sense_copy_initial_data. number_data_bytes_set
+ //needs to be decremented
+ sequence->number_data_bytes_set--;
+ }
+ }
+
+ return page_length;
+}
+
+/**
+ * @brief This method performs the control mode page specific data
+ * translation based upon the contents of the remote device
+ * IDENTIFY DEVICE data.
+ * For more information on the parameters passed to this method,
+ * please reference sati_translate_command().
+ *
+ * @param[in] identify This parameter specifies the remote device's
+ * IDENTIFY DEVICE data received as part of the IO request.
+ * @param[in] offset This parameter specifies the offset into the data
+ * buffer where the translated data is to be written.
+ *
+ * @return This method returns the size of the mode page data that was
+ * translated.
+ */
+U32 sati_mode_sense_control_translate_data(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ ATA_IDENTIFY_DEVICE_DATA_T * identify,
+ U32 offset
+)
+{
+ U8 * cdb = sati_cb_get_cdb_address(scsi_io);
+ U8 page_control = sati_get_cdb_byte(cdb, 2) >> SCSI_MODE_SENSE_PC_SHIFT;
+ U32 page_length;
+ U8 value;
+
+ page_length = sati_mode_sense_copy_initial_data(
+ sequence,
+ scsi_io,
+ offset,
+ page_control,
+ SCSI_MODE_PAGE_CONTROL
+ );
+
+ if (sequence->device->descriptor_sense_enable)
+ {
+ sati_get_data_byte(sequence, scsi_io, offset+2,
+ &value);
+
+ sati_set_data_byte(sequence, scsi_io, offset+2,
+ value | SCSI_MODE_SELECT_MODE_PAGE_D_SENSE);
+ }
+
+ return page_length;
+}
+
+/**
+ * @brief This method performs the informational exceptions control mode
+ * page specific data translation based upon the contents of the
+ * remote device IDENTIFY DEVICE data.
+ * For more information on the parameters passed to this method,
+ * please reference sati_translate_command().
+ *
+ * @param[in] identify This parameter specifies the remote device's
+ * IDENTIFY DEVICE data received as part of the IO request.
+ * @param[in] offset This parameter specifies the offset into the data
+ * buffer where the translated data is to be written.
+ *
+ * @return This method returns the size of the mode page data that was
+ * translated.
+ */
+U32 sati_mode_sense_informational_excp_control_translate_data(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ ATA_IDENTIFY_DEVICE_DATA_T * identify,
+ U32 offset
+)
+{
+ U8 * cdb = sati_cb_get_cdb_address(scsi_io);
+ U8 page_control = sati_get_cdb_byte(cdb, 2) >> SCSI_MODE_SENSE_PC_SHIFT;
+ U32 page_length;
+
+ page_length = sati_mode_sense_copy_initial_data(
+ sequence,
+ scsi_io,
+ offset,
+ page_control,
+ SCSI_MODE_PAGE_INFORMATIONAL_EXCP_CONTROL
+ );
+
+ // If the request queried for the current values, then
+ // we need to translate the data from the IDENTIFY DEVICE request.
+ if (page_control == SCSI_MODE_SENSE_PC_CURRENT)
+ {
+ U8 value;
+
+ sati_get_data_byte(sequence, scsi_io, offset+2, &value);
+
+ // Determine if the SMART feature set is supported and enabled.
+ if ( (identify->command_set_supported0
+ & ATA_IDENTIFY_COMMAND_SET_SUPPORTED0_SMART_ENABLE)
+ && (identify->command_set_enabled0
+ & ATA_IDENTIFY_COMMAND_SET_ENABLED0_SMART_ENABLE) )
+ {
+ // Clear the DXCPT field since the SMART feature is supported/enabled.
+ value &= ~SCSI_MODE_PAGE_INFORMATIONAL_EXCP_DXCPT_ENABLE;
+ }
+ else
+ {
+ // Set the Disable Exception Control (DXCPT) field since the SMART
+ // feature is not supported or enabled.
+ value |= SCSI_MODE_PAGE_INFORMATIONAL_EXCP_DXCPT_ENABLE;
+ }
+
+ sati_set_data_byte(sequence, scsi_io, offset+2, value);
+
+ //This byte has been set twice, the first time in
+ //sati_mode_sense_copy_initial_data. number_data_bytes_set
+ //needs to be decremented
+ sequence->number_data_bytes_set--;
+ }
+
+ return page_length;
+}
+
+/**
+* @brief This method performs the Power Condition mode page
+* specific data translation based upon the contents of the
+* remote device IDENTIFY DEVICE data.
+* For more information on the parameters passed to this method,
+* please reference sati_translate_command().
+*
+* @param[in] identify This parameter specifies the remote device's
+* IDENTIFY DEVICE data received as part of the IO request.
+* @param[in] offset This parameter specifies the offset into the data
+* buffer where the translated data is to be written.
+*
+* @return This method returns the size of the mode page data that was
+* translated.
+*/
+U32 sati_mode_sense_power_condition_translate_data(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ ATA_IDENTIFY_DEVICE_DATA_T * identify,
+ U32 offset
+)
+{
+ U8 * cdb = sati_cb_get_cdb_address(scsi_io);
+ U8 page_control = sati_get_cdb_byte(cdb, 2) >> SCSI_MODE_SENSE_PC_SHIFT;
+
+ U8 ata_sb_timer;
+
+ //Represents tenths of seconds
+ U32 standby_timer = 0x00000000;
+
+ U8 standby_enabled = STANDBY_TIMER_DISABLED;
+
+ if ((page_control == SCSI_MODE_SENSE_PC_CURRENT) &&
+ (identify->capabilities1 & STANDBY_TIMER_SUPPORTED))
+ {
+ standby_enabled = STANDBY_TIMER_ENABLED;
+
+ ata_sb_timer = sequence->device->ata_standby_timer;
+
+ //converting ATA timer values into SCSI timer values
+ if(ata_sb_timer <= 0xF0)
+ {
+ standby_timer = ata_sb_timer * 50;
+ }
+ else if(ata_sb_timer <= 0xFB)
+ {
+ standby_timer = ((ata_sb_timer - 240) * 18000);
+ }
+ else if(ata_sb_timer == 0xFC)
+ {
+ standby_timer = 12600;
+ }
+ else if(ata_sb_timer == 0xFD)
+ {
+ standby_timer = 432000;
+ }
+ else if(ata_sb_timer == 0xFF)
+ {
+ standby_timer = 12750;
+ }
+ else
+ {
+ standby_timer = 0xFFFFFFFF;
+ }
+ }
+
+ sati_set_data_byte(sequence, scsi_io, offset, SCSI_MODE_PAGE_POWER_CONDITION);
+ sati_set_data_byte(sequence, scsi_io, offset + 1, (SCSI_MODE_PAGE_1A_LENGTH - 2));
+ sati_set_data_byte(sequence, scsi_io, offset + 2, 0x00);
+ sati_set_data_byte(sequence, scsi_io, offset + 3, standby_enabled);
+ sati_set_data_byte(sequence, scsi_io, offset + 4, 0x00);
+ sati_set_data_byte(sequence, scsi_io, offset + 5, 0x00);
+ sati_set_data_byte(sequence, scsi_io, offset + 6, 0x00);
+ sati_set_data_byte(sequence, scsi_io, offset + 7, 0x00);
+ sati_set_data_byte(sequence, scsi_io, offset + 8, (U8) (standby_timer >> 24));
+ sati_set_data_byte(sequence, scsi_io, offset + 9, (U8) (standby_timer >> 16));
+ sati_set_data_byte(sequence, scsi_io, offset + 10, (U8) (standby_timer >> 8));
+ sati_set_data_byte(sequence, scsi_io, offset + 11, (U8) standby_timer);
+
+ return SCSI_MODE_PAGE_1A_LENGTH;
+}
+
+/**
+ * @brief This method performs the all pages mode page specific data
+ * translation based upon the contents of the remote device
+ * IDENTIFY DEVICE data. The ALL PAGES mode sense request asks
+ * for all of mode pages and sub-pages in a single page.
+ * The mode pages are added in ascending order.
+ * For more information on the parameters passed to this method,
+ * please reference sati_translate_command().
+ *
+ * @param[in] identify This parameter specifies the remote device's
+ * IDENTIFY DEVICE data received as part of the IO request.
+ * @param[in] offset This parameter specifies the offset into the data
+ * buffer where the translated data is to be written.
+ *
+ * @return This method returns the size of the mode page data that was
+ * translated.
+ */
+U32 sati_mode_sense_all_pages_translate_data(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ ATA_IDENTIFY_DEVICE_DATA_T * identify,
+ U32 offset
+)
+{
+ offset += sati_mode_sense_read_write_error_translate_data(
+ sequence, scsi_io, identify, offset
+ );
+
+ offset += sati_mode_sense_disconnect_reconnect_translate_data(
+ sequence, scsi_io, identify, offset
+ );
+
+ offset += sati_mode_sense_caching_translate_data(
+ sequence, scsi_io, identify, offset
+ );
+
+ offset += sati_mode_sense_control_translate_data(
+ sequence, scsi_io, identify, offset
+ );
+
+ offset += sati_mode_sense_informational_excp_control_translate_data(
+ sequence, scsi_io, identify, offset
+ );
+
+ return offset;
+}
+
+#endif // !defined(DISABLE_SATI_MODE_SENSE)
+
diff --git a/sys/dev/isci/scil/sati_mode_sense.h b/sys/dev/isci/scil/sati_mode_sense.h
new file mode 100644
index 0000000..e87701e
--- /dev/null
+++ b/sys/dev/isci/scil/sati_mode_sense.h
@@ -0,0 +1,146 @@
+/*-
+ * 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.
+ *
+ * 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.
+ *
+ * $FreeBSD$
+ */
+#ifndef _SATI_MODE_SENSE_H_
+#define _SATI_MODE_SENSE_H_
+
+/**
+ * @file
+ * @brief This file contains the method declarations and type defintions
+ * common to translations of the SCSI mode sense (6 and 10-byte)
+ * commands.
+ */
+
+#include <dev/isci/scil/sati_types.h>
+#include <dev/isci/scil/sati_translator_sequence.h>
+#include <dev/isci/scil/intel_ata.h>
+
+U16 sati_mode_sense_calculate_page_header(
+ void * scsi_io,
+ U8 cdb_size
+);
+
+SATI_STATUS sati_mode_sense_translate_command(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ void * ata_io,
+ U8 cdb_length
+);
+
+U32 sati_mode_sense_build_std_block_descriptor(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ ATA_IDENTIFY_DEVICE_DATA_T * identify,
+ U32 offset
+);
+
+U32 sati_mode_sense_copy_initial_data(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ U32 page_start,
+ U8 page_control,
+ U8 page_code
+);
+
+U32 sati_mode_sense_caching_translate_data(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ ATA_IDENTIFY_DEVICE_DATA_T * identify,
+ U32 offset
+);
+
+U32 sati_mode_sense_informational_excp_control_translate_data(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ ATA_IDENTIFY_DEVICE_DATA_T * identify,
+ U32 offset
+);
+
+U32 sati_mode_sense_all_pages_translate_data(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ ATA_IDENTIFY_DEVICE_DATA_T * identify,
+ U32 offset
+);
+
+U32 sati_mode_sense_read_write_error_translate_data(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ ATA_IDENTIFY_DEVICE_DATA_T * identify,
+ U32 offset
+);
+
+U32 sati_mode_sense_control_translate_data(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ ATA_IDENTIFY_DEVICE_DATA_T * identify,
+ U32 offset
+);
+
+U32 sati_mode_sense_disconnect_reconnect_translate_data(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ ATA_IDENTIFY_DEVICE_DATA_T * identify,
+ U32 offset
+);
+
+U32 sati_mode_sense_power_condition_translate_data(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ ATA_IDENTIFY_DEVICE_DATA_T * identify,
+ U32 offset
+);
+
+
+#endif // _SATI_MODE_SENSE_H_
+
diff --git a/sys/dev/isci/scil/sati_mode_sense_10.c b/sys/dev/isci/scil/sati_mode_sense_10.c
new file mode 100644
index 0000000..3e8a84f
--- /dev/null
+++ b/sys/dev/isci/scil/sati_mode_sense_10.c
@@ -0,0 +1,509 @@
+/*-
+ * 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.
+ *
+ * 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 <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/**
+ * @file
+ * @brief This file contains the method implementations required to
+ * translate the SCSI mode sense 10-byte commands.
+ */
+
+#if !defined(DISABLE_SATI_MODE_SENSE)
+
+#include <dev/isci/scil/sati_mode_sense.h>
+#include <dev/isci/scil/sati_mode_sense_10.h>
+#include <dev/isci/scil/sati_mode_pages.h>
+#include <dev/isci/scil/sati_callbacks.h>
+#include <dev/isci/scil/sati_util.h>
+#include <dev/isci/scil/intel_scsi.h>
+#include <dev/isci/scil/intel_ata.h>
+
+//******************************************************************************
+//* P R I V A T E M E T H O D S
+//******************************************************************************
+
+/**
+ * @brief This method builds the mode parameter header for a 10-byte SCSI
+ * mode sense data response. The parameter header is 4 bytes in
+ * size.
+ * For more information on the parameters passed to this method,
+ * please reference sati_translate_command().
+ *
+ * @param[in] identify This parameter specifies the ATA remote device's
+ * received IDENTIFY DEVICE data.
+ * @param[in] mode_data_length This parameter specifies the amount of data
+ * to be returned as part of this mode sense request.
+ *
+ * @return This method returns the number of bytes written into the
+ * mode sense data buffer.
+ */
+static
+U32 sati_mode_sense_10_build_header(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ ATA_IDENTIFY_DEVICE_DATA_T * identify,
+ U16 mode_data_length
+)
+{
+ U8 * cdb = sati_cb_get_cdb_address(scsi_io);
+
+ // Fill in the length of the mode parameter data returned (do not include
+ // the size of the mode data length field in the total). Adjust the
+ // mode data length to not include the mode data length fields itself
+ // (i.e. subtract 2).
+ mode_data_length -= 2;
+ sati_set_data_byte(sequence, scsi_io, 0, (U8)(mode_data_length >> 8) & 0xFF);
+ sati_set_data_byte(sequence, scsi_io, 1, (U8)(mode_data_length & 0xFF));
+
+ // Medium Type is 0 for SBC devices
+ sati_set_data_byte(sequence, scsi_io, 2, SCSI_MODE_HEADER_MEDIUM_TYPE_SBC);
+
+ // Write Protect (WP), Rsvd, DPOFUA, Rsvd
+ if (sequence->device->capabilities & SATI_DEVICE_CAP_DMA_FUA_ENABLE)
+ sati_set_data_byte(sequence,scsi_io,3,SCSI_MODE_SENSE_HEADER_FUA_ENABLE);
+ else
+ sati_set_data_byte(sequence, scsi_io, 3, 0);
+
+ // Set the reserved bytes to 0. The LONGLBA field in byte 4 is overridden
+ // later in this method if LLBAA is enabled.
+ sati_set_data_byte(sequence, scsi_io, 4, 0);
+ sati_set_data_byte(sequence, scsi_io, 5, 0);
+
+ // The MSB for the block descriptor length is never used since the
+ // largest block descriptor in this translator is 16-bytes in size.
+ sati_set_data_byte(sequence, scsi_io, 6, 0);
+
+ // Set the LSB block descriptor length if block descriptors are utilized.
+ if (sati_get_cdb_byte(cdb, 1) & SCSI_MODE_SENSE_DBD_ENABLE)
+ sati_set_data_byte(sequence, scsi_io, 7, 0);
+ else
+ {
+ // If Long Logical Block Address are allowed, then the block descriptor
+ // is larger (16 bytes total).
+ if (sati_get_cdb_byte(cdb, 1) & SCSI_MODE_SENSE_LLBAA_ENABLE)
+ {
+ sati_set_data_byte(sequence, scsi_io, 4, 1);
+ sati_set_data_byte(
+ sequence, scsi_io, 7, SCSI_MODE_SENSE_LLBA_BLOCK_DESCRIPTOR_LENGTH
+ );
+ }
+ else
+ {
+ sati_set_data_byte(
+ sequence, scsi_io, 7, SCSI_MODE_SENSE_STD_BLOCK_DESCRIPTOR_LENGTH
+ );
+ }
+ }
+
+ return SCSI_MODE_SENSE_10_HEADER_LENGTH;
+}
+
+static
+U32 sati_mode_sense_10_build_llba_block_descriptor(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ ATA_IDENTIFY_DEVICE_DATA_T * identify,
+ U32 offset
+)
+{
+ U32 lba_low = 0;
+ U32 lba_high = 0;
+ U32 sector_size = 0;
+
+ // Extract the sector information (sector size, logical blocks) from
+ // the retrieved ATA identify device data.
+ sati_ata_identify_device_get_sector_info(
+ identify, &lba_low, &lba_high, &sector_size
+ );
+
+ // Fill in the 8-byte logical block area
+ sati_set_data_byte(sequence, scsi_io, offset, (U8)((lba_high>>24) & 0xFF));
+ sati_set_data_byte(sequence, scsi_io, offset+1, (U8)((lba_high>>16) & 0xFF));
+ sati_set_data_byte(sequence, scsi_io, offset+2, (U8)((lba_high>>8) & 0xFF));
+ sati_set_data_byte(sequence, scsi_io, offset+3, (U8)(lba_high & 0xFF));
+ sati_set_data_byte(sequence, scsi_io, offset+4, (U8)((lba_low>>24) & 0xFF));
+ sati_set_data_byte(sequence, scsi_io, offset+5, (U8)((lba_low>>16) & 0xFF));
+ sati_set_data_byte(sequence, scsi_io, offset+6, (U8)((lba_low>>8) & 0xFF));
+ sati_set_data_byte(sequence, scsi_io, offset+7, (U8)(lba_low & 0xFF));
+
+ // Clear the reserved fields.
+ sati_set_data_byte(sequence, scsi_io, offset+8, 0);
+ sati_set_data_byte(sequence, scsi_io, offset+9, 0);
+ sati_set_data_byte(sequence, scsi_io, offset+10, 0);
+ sati_set_data_byte(sequence, scsi_io, offset+11, 0);
+
+ // Fill in the four byte Block Length field
+ sati_set_data_byte(sequence,scsi_io, offset+12, (U8)((sector_size>>24) & 0xFF));
+ sati_set_data_byte(sequence,scsi_io, offset+13, (U8)((sector_size>>16) & 0xFF));
+ sati_set_data_byte(sequence,scsi_io, offset+14, (U8)((sector_size>>8) & 0xFF));
+ sati_set_data_byte(sequence,scsi_io, offset+15, (U8)(sector_size & 0xFF));
+
+ return SCSI_MODE_SENSE_LLBA_BLOCK_DESCRIPTOR_LENGTH;
+}
+
+/**
+ * @brief This method perform the data translation common to all SCSI MODE
+ * SENSE 10 byte commands. This includes building the mode page
+ * header and block descriptor (if requested).
+ * For more information on the parameters passed to this method,
+ * please reference sati_translate_command().
+ *
+ * @param[in] identify This parameter specifies the remote device's IDENTIFY
+ * DEVICE data to be used during translation.
+ * @param[in] transfer_length This parameter specifies the size of the
+ * mode page (including header & block descriptor).
+ *
+ * @return This method returns the number of bytes written into the user's
+ * mode page data buffer.
+ */
+static
+U32 sati_mode_sense_10_translate_data(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ ATA_IDENTIFY_DEVICE_DATA_T * identify,
+ void * scsi_io,
+ U16 transfer_length
+)
+{
+ U8 * cdb = sati_cb_get_cdb_address(scsi_io);
+ U32 offset;
+
+ offset = sati_mode_sense_10_build_header(
+ sequence, scsi_io, identify, transfer_length
+ );
+
+ // Determine if the caller disabled block descriptors (DBD). If not,
+ // then generate a block descriptor.
+ if ((sati_get_cdb_byte(cdb, 1) & SCSI_MODE_SENSE_DBD_ENABLE) == 0)
+ {
+ // If the user requested the Long LBA format descriptor, then build
+ // it
+ if (sati_get_cdb_byte(cdb, 1) & SCSI_MODE_SENSE_LLBAA_ENABLE)
+ offset += sati_mode_sense_10_build_llba_block_descriptor(
+ sequence, scsi_io, identify, offset
+ );
+ else
+ offset += sati_mode_sense_build_std_block_descriptor(
+ sequence, scsi_io, identify, offset
+ );
+ }
+
+ return offset;
+}
+
+//******************************************************************************
+//* P R O T E C T E D M E T H O D S
+//******************************************************************************
+
+/**
+ * @brief This method will translate the SCSI mode sense 6 byte command
+ * into corresponding ATA commands. If the command is well-formed,
+ * then the translation will result in an ATA IDENTIFY DEVICE
+ * command.
+ * For more information on the parameters passed to this method,
+ * please reference sati_translate_command().
+ *
+ * @return Indicate if the command translation succeeded.
+ * @retval SCI_SUCCESS This is returned if the command translation was
+ * successful.
+ * @retval SATI_FAILURE_CHECK_RESPONSE_DATA This value is returned if
+ * sense data has been created as a result of something specified
+ * in the CDB.
+ */
+SATI_STATUS sati_mode_sense_10_translate_command(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ void * ata_io
+)
+{
+ U8 * cdb = sati_cb_get_cdb_address(scsi_io);
+
+ sequence->command_specific_data.scratch = 0;
+
+ // Set the data length based on the allocation length field in the CDB.
+ sequence->allocation_length = (sati_get_cdb_byte(cdb, 7) << 8) |
+ (sati_get_cdb_byte(cdb, 8));
+
+ return sati_mode_sense_translate_command(sequence, scsi_io, ata_io, 10);
+}
+
+/**
+ * @brief This method will perform data translation from the supplied ATA
+ * input data (i.e. an ATA IDENTIFY DEVICE block) into a CACHING
+ * mode page format. The data will be written into the user's mode
+ * page data buffer. This function operates specifically for MODE
+ * SENSE 10 commands.
+ * For more information on the parameters passed to this method,
+ * please reference sati_translate_data().
+ *
+ * @return none.
+ */
+void sati_mode_sense_10_caching_translate_data(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * ata_input_data,
+ void * scsi_io
+)
+{
+ ATA_IDENTIFY_DEVICE_DATA_T * identify = (ATA_IDENTIFY_DEVICE_DATA_T*)
+ ata_input_data;
+ U16 data_length = sati_mode_sense_calculate_page_header(scsi_io, 10)
+ + SCSI_MODE_PAGE_08_LENGTH;
+ U32 page_offset = sati_mode_sense_10_translate_data(
+ sequence, identify, scsi_io, data_length
+ );
+
+ sati_mode_sense_caching_translate_data(
+ sequence, scsi_io, identify, page_offset
+ );
+}
+
+/**
+ * @brief This method will perform data translation from the supplied ATA
+ * input data (i.e. an ATA IDENTIFY DEVICE block) into a INFORMATIONAL
+ * EXCEPTIONS CONTROL mode page format. The data will be written
+ * into the user's mode page data buffer. This function operates
+ * specifically for MODE SENSE 10 commands.
+ * For more information on the parameters passed to this method,
+ * please reference sati_translate_data().
+ *
+ * @return none.
+ */
+void sati_mode_sense_10_informational_excp_control_translate_data(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * ata_input_data,
+ void * scsi_io
+)
+{
+ ATA_IDENTIFY_DEVICE_DATA_T * identify = (ATA_IDENTIFY_DEVICE_DATA_T*)
+ ata_input_data;
+ U16 data_length = sati_mode_sense_calculate_page_header(scsi_io, 10)
+ + SCSI_MODE_PAGE_1C_LENGTH;
+ U32 page_offset = sati_mode_sense_10_translate_data(
+ sequence, identify, scsi_io, data_length
+ );
+
+ sati_mode_sense_informational_excp_control_translate_data(
+ sequence, scsi_io, identify, page_offset
+ );
+}
+
+/**
+* @brief This method will perform data translation from the supplied ATA
+* input data (i.e. an ATA IDENTIFY DEVICE block) into a Read Write Error
+* mode page format. The data will be written
+* into the user's mode page data buffer. This function operates
+* specifically for MODE SENSE 10 commands.
+* For more information on the parameters passed to this method,
+* please reference sati_translate_data().
+*
+* @return none.
+*/
+void sati_mode_sense_10_read_write_error_translate_data(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * ata_input_data,
+ void * scsi_io
+)
+{
+ ATA_IDENTIFY_DEVICE_DATA_T * identify = (ATA_IDENTIFY_DEVICE_DATA_T*)
+ ata_input_data;
+
+ U16 data_length = sati_mode_sense_calculate_page_header(scsi_io, 10)
+ + SCSI_MODE_PAGE_01_LENGTH;
+
+ U32 page_offset = sati_mode_sense_10_translate_data(
+ sequence, identify, scsi_io, data_length
+ );
+
+ sati_mode_sense_read_write_error_translate_data(
+ sequence, scsi_io, identify, page_offset
+ );
+}
+
+/**
+* @brief This method will perform data translation from the supplied ATA
+* input data (i.e. an ATA IDENTIFY DEVICE block) into a Disconnect
+* Reconnect mode page format. The data will be written
+* into the user's mode page data buffer. This function operates
+* specifically for MODE SENSE 10 commands.
+* For more information on the parameters passed to this method,
+* please reference sati_translate_data().
+*
+* @return none.
+*/
+void sati_mode_sense_10_disconnect_reconnect_translate_data(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * ata_input_data,
+ void * scsi_io
+)
+{
+ ATA_IDENTIFY_DEVICE_DATA_T * identify = (ATA_IDENTIFY_DEVICE_DATA_T*)
+ ata_input_data;
+
+ U8 data_length = (U8) sati_mode_sense_calculate_page_header(scsi_io, 10)
+ + SCSI_MODE_PAGE_02_LENGTH;
+
+ U32 page_offset = sati_mode_sense_10_translate_data(
+ sequence, identify, scsi_io, data_length
+ );
+
+ sati_mode_sense_disconnect_reconnect_translate_data(
+ sequence, scsi_io, identify, page_offset
+ );
+}
+
+/**
+* @brief This method will perform data translation from the supplied ATA
+* input data (i.e. an ATA IDENTIFY DEVICE block) into a Control
+* mode page format. The data will be written
+* into the user's mode page data buffer. This function operates
+* specifically for MODE SENSE 10 commands.
+* For more information on the parameters passed to this method,
+* please reference sati_translate_data().
+*
+* @return none.
+*/
+void sati_mode_sense_10_control_translate_data(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * ata_input_data,
+ void * scsi_io
+)
+{
+ ATA_IDENTIFY_DEVICE_DATA_T * identify = (ATA_IDENTIFY_DEVICE_DATA_T*)
+ ata_input_data;
+
+ U8 data_length = (U8) sati_mode_sense_calculate_page_header(scsi_io, 10)
+ + SCSI_MODE_PAGE_0A_LENGTH;
+
+ U32 page_offset = sati_mode_sense_10_translate_data(
+ sequence, identify, scsi_io, data_length
+ );
+
+ sati_mode_sense_control_translate_data(
+ sequence, scsi_io, identify, page_offset
+ );
+}
+
+/**
+* @brief This method will perform data translation from the supplied ATA
+* input data (i.e. an ATA IDENTIFY DEVICE block) into a Power
+* Condition mode page format. The data will be written
+* into the user's mode page data buffer. This function operates
+* specifically for MODE SENSE 10 commands.
+* For more information on the parameters passed to this method,
+* please reference sati_translate_data().
+*
+* @return none.
+*/
+void sati_mode_sense_10_power_condition_translate_data(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * ata_input_data,
+ void * scsi_io
+)
+{
+ ATA_IDENTIFY_DEVICE_DATA_T * identify = (ATA_IDENTIFY_DEVICE_DATA_T*)
+ ata_input_data;
+
+ U8 data_length;
+ U32 page_offset;
+
+ data_length = (U8) sati_mode_sense_calculate_page_header(scsi_io, 10)
+ + SCSI_MODE_PAGE_1A_LENGTH;
+
+ page_offset = sati_mode_sense_10_translate_data(
+ sequence, identify, scsi_io, data_length
+ );
+
+ sati_mode_sense_power_condition_translate_data(
+ sequence, scsi_io, identify, page_offset
+ );
+}
+
+
+/**
+ * @brief This method will perform data translation from the supplied ATA
+ * input data (i.e. an ATA IDENTIFY DEVICE block) into an ALL
+ * PAGES mode page format. The ALL PAGES mode page is basically a
+ * conglomeration of all mode pages and sub-pages into a single
+ * page. The data will be written into the user's mode page
+ * data buffer. This function operates specifically for MODE
+ * SENSE 10 commands.
+ * For more information on the parameters passed to this method,
+ * please reference sati_translate_data().
+ *
+ * @return none.
+ */
+void sati_mode_sense_10_all_pages_translate_data(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * ata_input_data,
+ void * scsi_io
+)
+{
+ ATA_IDENTIFY_DEVICE_DATA_T * identify = (ATA_IDENTIFY_DEVICE_DATA_T*)
+ ata_input_data;
+ U8 data_length = (U8) sati_mode_sense_calculate_page_header(scsi_io, 10)
+ + SCSI_MODE_PAGE_01_LENGTH
+ + SCSI_MODE_PAGE_02_LENGTH
+ + SCSI_MODE_PAGE_08_LENGTH
+ + SCSI_MODE_PAGE_0A_LENGTH
+ + SCSI_MODE_PAGE_1C_LENGTH;
+ U32 page_offset = sati_mode_sense_10_translate_data(
+ sequence, identify, scsi_io, data_length
+ );
+
+ sati_mode_sense_all_pages_translate_data(
+ sequence, scsi_io, identify, page_offset
+ );
+}
+
+#endif // !defined(DISABLE_SATI_MODE_SENSE)
+
diff --git a/sys/dev/isci/scil/sati_mode_sense_10.h b/sys/dev/isci/scil/sati_mode_sense_10.h
new file mode 100644
index 0000000..1840777
--- /dev/null
+++ b/sys/dev/isci/scil/sati_mode_sense_10.h
@@ -0,0 +1,114 @@
+/*-
+ * 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.
+ *
+ * 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.
+ *
+ * $FreeBSD$
+ */
+#ifndef _SATI_MODE_SENSE_10_H_
+#define _SATI_MODE_SENSE_10_H_
+
+/**
+ * @file
+ * @brief This file contains the method prototypes required to
+ * translate the SCSI mode sense 10-byte commands.
+ */
+
+#include <dev/isci/scil/sati_types.h>
+#include <dev/isci/scil/sati_translator_sequence.h>
+
+SATI_STATUS sati_mode_sense_10_translate_command(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ void * ata_io
+);
+
+void sati_mode_sense_10_caching_translate_data(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * ata_input_data,
+ void * scsi_io
+);
+
+void sati_mode_sense_10_informational_excp_control_translate_data(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * ata_input_data,
+ void * scsi_io
+);
+
+void sati_mode_sense_10_read_write_error_translate_data(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * ata_input_data,
+ void * scsi_io
+);
+
+void sati_mode_sense_10_disconnect_reconnect_translate_data(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * ata_input_data,
+ void * scsi_io
+);
+
+void sati_mode_sense_10_control_translate_data(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * ata_input_data,
+ void * scsi_io
+);
+
+void sati_mode_sense_10_power_condition_translate_data(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * ata_input_data,
+ void * scsi_io
+);
+
+void sati_mode_sense_10_all_pages_translate_data(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * ata_input_data,
+ void * scsi_io
+);
+
+#endif // _SATI_MODE_SENSE_10_H_
diff --git a/sys/dev/isci/scil/sati_mode_sense_6.c b/sys/dev/isci/scil/sati_mode_sense_6.c
new file mode 100644
index 0000000..3100c22
--- /dev/null
+++ b/sys/dev/isci/scil/sati_mode_sense_6.c
@@ -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.
+ *
+ * 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 <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/**
+ * @file
+ * @brief This file contains the method implementations required to
+ * translate the SCSI mode sense 6-byte commands.
+ */
+
+#if !defined(DISABLE_SATI_MODE_SENSE)
+
+#include <dev/isci/scil/sati_mode_sense.h>
+#include <dev/isci/scil/sati_mode_sense_6.h>
+#include <dev/isci/scil/sati_mode_pages.h>
+#include <dev/isci/scil/sati_callbacks.h>
+#include <dev/isci/scil/sati_util.h>
+#include <dev/isci/scil/intel_scsi.h>
+#include <dev/isci/scil/intel_ata.h>
+
+//******************************************************************************
+//* P R I V A T E M E T H O D S
+//******************************************************************************
+
+/**
+ * @brief This method builds the mode parameter header for a 6-byte SCSI
+ * mode sense data response. The parameter header is 4 bytes in
+ * size.
+ * For more information on the parameters passed to this method,
+ * please reference sati_translate_command().
+ *
+ * @param[in] identify This parameter specifies the ATA remote device's
+ * received IDENTIFY DEVICE data.
+ * @param[in] mode_data_length This parameter specifies the amount of data
+ * to be returned as part of this mode sense request.
+ *
+ * @return This method returns the number of bytes written into the
+ * data buffer.
+ */
+static
+U32 sati_mode_sense_6_build_header(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ ATA_IDENTIFY_DEVICE_DATA_T * identify,
+ U8 mode_data_length
+)
+{
+ U8 * cdb = sati_cb_get_cdb_address(scsi_io);
+
+ // Fill in the length of the mode parameter data returned (do not include
+ // the size of the mode data length field in the total).
+ sati_set_data_byte(sequence, scsi_io, 0, (U8)mode_data_length-1);
+
+ // Medium Type is 0 for SBC devices
+ sati_set_data_byte(sequence, scsi_io, 1, SCSI_MODE_HEADER_MEDIUM_TYPE_SBC);
+
+ // Write Protect (WP), Rsvd, DPOFUA, Rsvd
+ if (sequence->device->capabilities & SATI_DEVICE_CAP_DMA_FUA_ENABLE)
+ sati_set_data_byte(sequence,scsi_io,2,SCSI_MODE_SENSE_HEADER_FUA_ENABLE);
+ else
+ sati_set_data_byte(sequence, scsi_io, 2, 0);
+
+ // Set the block descriptor length if block descriptors are utilized.
+ if (sati_get_cdb_byte(cdb, 1) & SCSI_MODE_SENSE_DBD_ENABLE)
+ sati_set_data_byte(sequence, scsi_io, 3, 0);
+ else
+ sati_set_data_byte(
+ sequence, scsi_io, 3, SCSI_MODE_SENSE_STD_BLOCK_DESCRIPTOR_LENGTH
+ );
+
+ return SCSI_MODE_SENSE_6_HEADER_LENGTH;
+}
+
+/**
+ * @brief This method perform the data translation common to all SCSI MODE
+ * SENSE 6 byte commands. This includes building the mode page
+ * header and block descriptor (if requested).
+ * For more information on the parameters passed to this method,
+ * please reference sati_translate_command().
+ *
+ * @param[in] identify This parameter specifies the remote device's IDENTIFY
+ * DEVICE data to be used during translation.
+ * @param[in] transfer_length This parameter specifies the size of the
+ * mode page (including header & block descriptor).
+ *
+ * @return This method returns the number of bytes written into the user's
+ * mode page data buffer.
+ */
+static
+U32 sati_mode_sense_6_translate_data(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ ATA_IDENTIFY_DEVICE_DATA_T * identify,
+ void * scsi_io,
+ U8 transfer_length
+)
+{
+ U8 * cdb = sati_cb_get_cdb_address(scsi_io);
+ U32 offset;
+
+ offset = sati_mode_sense_6_build_header(
+ sequence, scsi_io, identify, transfer_length
+ );
+
+ // Determine if the caller disabled block descriptors (DBD). If not,
+ // then generate a block descriptor.
+ if ((sati_get_cdb_byte(cdb, 1) & SCSI_MODE_SENSE_DBD_ENABLE) == 0)
+ offset += sati_mode_sense_build_std_block_descriptor(
+ sequence, scsi_io, identify, offset
+ );
+
+ return offset;
+}
+
+//******************************************************************************
+//* P R O T E C T E D M E T H O D S
+//******************************************************************************
+
+/**
+ * @brief This method will translate the SCSI mode sense 6 byte command
+ * into corresponding ATA commands. If the command is well-formed,
+ * then the translation will result in an ATA IDENTIFY DEVICE
+ * command.
+ * For more information on the parameters passed to this method,
+ * please reference sati_translate_command().
+ *
+ * @return Indicate if the command translation succeeded.
+ * @retval SCI_SUCCESS This is returned if the command translation was
+ * successful.
+ * @retval SATI_FAILURE_CHECK_RESPONSE_DATA This value is returned if
+ * sense data has been created as a result of something specified
+ * in the CDB.
+ */
+SATI_STATUS sati_mode_sense_6_translate_command(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ void * ata_io
+)
+{
+ U8 * cdb = sati_cb_get_cdb_address(scsi_io);
+
+ // Set the data length based on the allocation length field in the CDB.
+ sequence->allocation_length = sati_get_cdb_byte(cdb, 4);
+
+ return sati_mode_sense_translate_command(sequence, scsi_io, ata_io, 6);
+}
+
+/**
+ * @brief This method will perform data translation from the supplied ATA
+ * input data (i.e. an ATA IDENTIFY DEVICE block) into a CACHING
+ * mode page format. The data will be written into the user's mode
+ * page data buffer. This function operates specifically for MODE
+ * SENSE 6 commands.
+ * For more information on the parameters passed to this method,
+ * please reference sati_translate_data().
+ *
+ * @return none.
+ */
+void sati_mode_sense_6_caching_translate_data(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * ata_input_data,
+ void * scsi_io
+)
+{
+ ATA_IDENTIFY_DEVICE_DATA_T * identify = (ATA_IDENTIFY_DEVICE_DATA_T*)
+ ata_input_data;
+ U8 data_length = (U8) sati_mode_sense_calculate_page_header(scsi_io, 6)
+ + SCSI_MODE_PAGE_08_LENGTH;
+ U32 page_offset = sati_mode_sense_6_translate_data(
+ sequence, identify, scsi_io, data_length
+ );
+
+ sati_mode_sense_caching_translate_data(
+ sequence, scsi_io, identify, page_offset
+ );
+}
+
+/**
+ * @brief This method will perform data translation from the supplied ATA
+ * input data (i.e. an ATA IDENTIFY DEVICE block) into a INFORMATIONAL
+ * EXCEPTIONS CONTROL mode page format. The data will be written
+ * into the user's mode page data buffer. This function operates
+ * specifically for MODE SENSE 6 commands.
+ * For more information on the parameters passed to this method,
+ * please reference sati_translate_data().
+ *
+ * @return none.
+ */
+void sati_mode_sense_6_informational_excp_control_translate_data(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * ata_input_data,
+ void * scsi_io
+)
+{
+ ATA_IDENTIFY_DEVICE_DATA_T * identify = (ATA_IDENTIFY_DEVICE_DATA_T*)
+ ata_input_data;
+ U8 data_length = (U8) sati_mode_sense_calculate_page_header(scsi_io, 6)
+ + SCSI_MODE_PAGE_1C_LENGTH;
+ U32 page_offset = sati_mode_sense_6_translate_data(
+ sequence, identify, scsi_io, data_length
+ );
+
+ sati_mode_sense_informational_excp_control_translate_data(
+ sequence, scsi_io, identify, page_offset
+ );
+}
+
+/**
+* @brief This method will perform data translation from the supplied ATA
+* input data (i.e. an ATA IDENTIFY DEVICE block) into a DISCONNECT
+* RECONNECT mode page format. The data will be written
+* into the user's mode page data buffer. This function operates
+* specifically for MODE SENSE 6 commands.
+* For more information on the parameters passed to this method,
+* please reference sati_translate_data().
+*
+* @return none.
+*/
+void sati_mode_sense_6_disconnect_reconnect_translate_data(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * ata_input_data,
+ void * scsi_io
+)
+{
+ ATA_IDENTIFY_DEVICE_DATA_T * identify = (ATA_IDENTIFY_DEVICE_DATA_T*)
+ ata_input_data;
+
+ U8 data_length = (U8) sati_mode_sense_calculate_page_header(scsi_io, 6)
+ + SCSI_MODE_PAGE_02_LENGTH ;
+
+ U32 page_offset = sati_mode_sense_6_translate_data(
+ sequence, identify, scsi_io, data_length
+ );
+
+ sati_mode_sense_disconnect_reconnect_translate_data(
+ sequence, scsi_io, identify, page_offset
+ );
+}
+
+/**
+* @brief This method will perform data translation from the supplied ATA
+* input data (i.e. an ATA IDENTIFY DEVICE block) into a READ WRITE ERROR
+* mode page format. The data will be written
+* into the user's mode page data buffer. This function operates
+* specifically for MODE SENSE 6 commands.
+* For more information on the parameters passed to this method,
+* please reference sati_translate_data().
+*
+* @return none.
+*/
+void sati_mode_sense_6_read_write_error_translate_data(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * ata_input_data,
+ void * scsi_io
+)
+{
+ ATA_IDENTIFY_DEVICE_DATA_T * identify = (ATA_IDENTIFY_DEVICE_DATA_T*)
+ ata_input_data;
+
+ U8 data_length = (U8) sati_mode_sense_calculate_page_header(scsi_io, 6)
+ + SCSI_MODE_PAGE_01_LENGTH;
+
+ U32 page_offset = sati_mode_sense_6_translate_data(
+ sequence, identify, scsi_io, data_length
+ );
+
+ sati_mode_sense_read_write_error_translate_data(
+ sequence, scsi_io, identify, page_offset
+ );
+}
+
+/**
+* @brief This method will perform data translation from the supplied ATA
+* input data (i.e. an ATA IDENTIFY DEVICE block) into a CONTROL
+* mode page format. The data will be written
+* into the user's mode page data buffer. This function operates
+* specifically for MODE SENSE 6 commands.
+* For more information on the parameters passed to this method,
+* please reference sati_translate_data().
+*
+* @return none.
+*/
+void sati_mode_sense_6_control_translate_data(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * ata_input_data,
+ void * scsi_io
+)
+{
+ ATA_IDENTIFY_DEVICE_DATA_T * identify = (ATA_IDENTIFY_DEVICE_DATA_T*)
+ ata_input_data;
+
+ U8 data_length = (U8) sati_mode_sense_calculate_page_header(scsi_io, 6)
+ + SCSI_MODE_PAGE_0A_LENGTH;
+
+ U32 page_offset = sati_mode_sense_6_translate_data(
+ sequence, identify, scsi_io, data_length
+ );
+
+ sati_mode_sense_control_translate_data(
+ sequence, scsi_io, identify, page_offset
+ );
+}
+
+/**
+* @brief This method will perform data translation from the supplied ATA
+* input data (i.e. an ATA IDENTIFY DEVICE block) into a Power
+* Condition mode page format. The data will be written
+* into the user's mode page data buffer. This function operates
+* specifically for MODE SENSE 6 commands.
+* For more information on the parameters passed to this method,
+* please reference sati_translate_data().
+*
+* @return none.
+*/
+void sati_mode_sense_6_power_condition_translate_data(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * ata_input_data,
+ void * scsi_io
+)
+{
+ ATA_IDENTIFY_DEVICE_DATA_T * identify = (ATA_IDENTIFY_DEVICE_DATA_T*)
+ ata_input_data;
+
+ U8 data_length;
+ U32 page_offset;
+
+ data_length = (U8) sati_mode_sense_calculate_page_header(scsi_io, 6)
+ + SCSI_MODE_PAGE_1A_LENGTH;
+
+ page_offset = sati_mode_sense_6_translate_data(
+ sequence, identify, scsi_io, data_length
+ );
+
+ sati_mode_sense_power_condition_translate_data(
+ sequence, scsi_io, identify, page_offset
+ );
+}
+
+
+
+/**
+ * @brief This method will perform data translation from the supplied ATA
+ * input data (i.e. an ATA IDENTIFY DEVICE block) into an ALL
+ * PAGES mode page format. The ALL PAGES mode page is basically a
+ * conglomeration of all mode pages and sub-pages into a single
+ * page. The data will be written into the user's mode page
+ * data buffer. This function operates specifically for MODE
+ * SENSE 6 commands.
+ * For more information on the parameters passed to this method,
+ * please reference sati_translate_data().
+ *
+ * @return none.
+ */
+void sati_mode_sense_6_all_pages_translate_data(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * ata_input_data,
+ void * scsi_io
+)
+{
+ ATA_IDENTIFY_DEVICE_DATA_T * identify = (ATA_IDENTIFY_DEVICE_DATA_T*)
+ ata_input_data;
+ U8 data_length = (U8) sati_mode_sense_calculate_page_header(scsi_io, 6)
+ + SCSI_MODE_PAGE_01_LENGTH
+ + SCSI_MODE_PAGE_02_LENGTH
+ + SCSI_MODE_PAGE_08_LENGTH
+ + SCSI_MODE_PAGE_0A_LENGTH
+ + SCSI_MODE_PAGE_1C_LENGTH;
+
+ U32 page_offset = sati_mode_sense_6_translate_data(
+ sequence, identify, scsi_io, data_length
+ );
+
+ sati_mode_sense_all_pages_translate_data(
+ sequence, scsi_io, identify, page_offset
+ );
+}
+
+#endif // !defined(DISABLE_SATI_MODE_SENSE)
+
diff --git a/sys/dev/isci/scil/sati_mode_sense_6.h b/sys/dev/isci/scil/sati_mode_sense_6.h
new file mode 100644
index 0000000..64afebc
--- /dev/null
+++ b/sys/dev/isci/scil/sati_mode_sense_6.h
@@ -0,0 +1,114 @@
+/*-
+ * 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.
+ *
+ * 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.
+ *
+ * $FreeBSD$
+ */
+#ifndef _SATI_MODE_SENSE_6_H_
+#define _SATI_MODE_SENSE_6_H_
+
+/**
+ * @file
+ * @brief This file contains the method prototypes required to
+ * translate the SCSI mode sense 6-byte commands.
+ */
+
+#include <dev/isci/scil/sati_types.h>
+#include <dev/isci/scil/sati_translator_sequence.h>
+
+SATI_STATUS sati_mode_sense_6_translate_command(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ void * ata_io
+);
+
+void sati_mode_sense_6_caching_translate_data(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * ata_input_data,
+ void * scsi_io
+);
+
+void sati_mode_sense_6_informational_excp_control_translate_data(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * ata_input_data,
+ void * scsi_io
+);
+
+void sati_mode_sense_6_read_write_error_translate_data(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * ata_input_data,
+ void * scsi_io
+);
+
+void sati_mode_sense_6_disconnect_reconnect_translate_data(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * ata_input_data,
+ void * scsi_io
+);
+
+void sati_mode_sense_6_control_translate_data(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * ata_input_data,
+ void * scsi_io
+);
+
+void sati_mode_sense_6_power_condition_translate_data(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * ata_input_data,
+ void * scsi_io
+);
+
+void sati_mode_sense_6_all_pages_translate_data(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * ata_input_data,
+ void * scsi_io
+);
+
+#endif // _SATI_MODE_SENSE_6_H_
diff --git a/sys/dev/isci/scil/sati_move.c b/sys/dev/isci/scil/sati_move.c
new file mode 100644
index 0000000..630a9f8
--- /dev/null
+++ b/sys/dev/isci/scil/sati_move.c
@@ -0,0 +1,616 @@
+/*-
+ * 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.
+ *
+ * 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 <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/**
+ * @file
+ * @brief This file contains the method implementations common to
+ * translations that move data (i.e. read, write). It has code for
+ * the various different size CDBs (6, 10, 12, 16).
+ */
+
+#include <dev/isci/scil/sati_move.h>
+#include <dev/isci/scil/sati_callbacks.h>
+#include <dev/isci/scil/sati_translator_sequence.h>
+#include <dev/isci/scil/sati_util.h>
+#include <dev/isci/scil/intel_ata.h>
+#include <dev/isci/scil/intel_scsi.h>
+#include <dev/isci/scil/intel_sat.h>
+
+//******************************************************************************
+//* P R I V A T E M E T H O D S
+//******************************************************************************
+
+/**
+ * @brief This method simply sets the command register based upon the
+ * supplied opcodes and the data direction.
+ * For more information on the parameters passed to this method,
+ * please reference sati_translate_command()
+ *
+ * @param[in] write_opcode This parameter specifies the value to be written
+ * to the ATA command register for a write (data out) operation.
+ * @param[in] read_opcode This parameter specifies the value to be written
+ * to the ATA command register for a read (data in) operation.
+ *
+ * @return none.
+ */
+static
+void sati_move_set_ata_command(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * ata_io,
+ U8 write_opcode,
+ U8 read_opcode
+)
+{
+ U8 * register_fis = sati_cb_get_h2d_register_fis_address(ata_io);
+
+ if (sequence->data_direction == SATI_DATA_DIRECTION_OUT)
+ sati_set_ata_command(register_fis, write_opcode);
+ else
+ sati_set_ata_command(register_fis, read_opcode);
+}
+
+/**
+ * @brief This method will translate the SCSI transfer count from the 6-byte
+ * CDB into the appropriate amount in the ATA register FIS. Please
+ * note for 48-bit UDMA requests, the caller must set the sector
+ * count extended field. This method also sets protocol and
+ * command fields.
+ * For more information on the parameters passed to this method,
+ * please reference sati_translate_command()
+ *
+ * @param[in] write_opcode This parameter specifies the value to be written
+ * to the ATA command register for a write (data out) operation.
+ * @param[in] read_opcode This parameter specifies the value to be written
+ * to the ATA command register for a read (data in) operation.
+ *
+ * @return none
+ */
+static
+void sati_move_small_udma_translate_command(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ void * ata_io,
+ U8 write_opcode,
+ U8 read_opcode
+)
+{
+ U8 * cdb = sati_cb_get_cdb_address(scsi_io);
+ U8 * register_fis = sati_cb_get_h2d_register_fis_address(ata_io);
+
+ sati_move_set_ata_command(sequence, ata_io, write_opcode, read_opcode);
+ sati_set_ata_sector_count(register_fis, sati_get_cdb_byte(cdb, 4));
+
+ if (sequence->data_direction == SATI_DATA_DIRECTION_IN)
+ sequence->protocol = SAT_PROTOCOL_UDMA_DATA_IN;
+ else
+ sequence->protocol = SAT_PROTOCOL_UDMA_DATA_OUT;
+}
+
+/**
+ * @brief This method will translate the SCSI transfer count from the
+ * supplied sector_count parameter into the ATA register FIS.
+ * The translation is specific to 10,12, 16 byte CDBs.
+ * This method also sets protocol and command fields.
+ * For more information on the parameters passed to this method,
+ * please reference sati_translate_command()
+ *
+ * @param[in] sector_count This parameter specifies the number of sectors
+ * to be transfered.
+ * @param[in] write_opcode This parameter specifies the value to be written
+ * to the ATA command register for a write (data out) operation.
+ * @param[in] read_opcode This parameter specifies the value to be written
+ * to the ATA command register for a read (data in) operation.
+ *
+ * @return Please reference sati_move_set_sector_count() for information
+ * on return codes from this method.
+ */
+static
+SATI_STATUS sati_move_large_udma_translate_command(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ void * ata_io,
+ U32 sector_count,
+ U8 write_opcode,
+ U8 read_opcode
+)
+{
+ sati_move_set_ata_command(sequence, ata_io, write_opcode, read_opcode);
+
+ if (sequence->data_direction == SATI_DATA_DIRECTION_IN)
+ sequence->protocol = SAT_PROTOCOL_UDMA_DATA_IN;
+ else
+ sequence->protocol = SAT_PROTOCOL_UDMA_DATA_OUT;
+
+ return sati_move_set_sector_count(
+ sequence, scsi_io, ata_io, sector_count, FALSE
+ );
+}
+
+/**
+ * @brief This method will translate the SCSI transfer count from the 6-byte
+ * CDB into the appropriate amount in the ATA register FIS.
+ * This is only used for translation of 6-byte SCSI CDBs.
+ * For more information on the parameters passed to this method,
+ * please reference sati_translate_command()
+ *
+ * @return none
+ */
+static
+void sati_move_ncq_translate_8_bit_sector_count(
+ void * scsi_io,
+ void * ata_io
+)
+{
+ U8 * cdb = sati_cb_get_cdb_address(scsi_io);
+ U8 * register_fis = sati_cb_get_h2d_register_fis_address(ata_io);
+
+ sati_set_ata_features(register_fis, sati_get_cdb_byte(cdb, 4));
+
+ // A read 6 with a 0 sector count indicates a transfer of 256 sectors.
+ // As a result update the MSB (features expanded register) to indicate
+ // 256 sectors (0x100).
+ if (sati_get_cdb_byte(cdb, 4) == 0)
+ sati_set_ata_features_exp(register_fis, 1);
+}
+
+//******************************************************************************
+//* P U B L I C M E T H O D S
+//******************************************************************************
+
+/**
+ * @brief This method will process a 32-bit sector into the appropriate fields
+ * in a register FIS. This method works for both 8-bit and 16-bit sector
+ * counts.
+ * This is used for translation of 10, 12, and 16-byte SCSI CDBs.
+ * For more information on the parameters passed to this method,
+ * please reference sati_translate_command().
+ *
+ * @note This method should only be called for CDB sizes of 10-bytes or larger.
+ *
+ * @param[in] sector_count This parameter specifies the number of sectors
+ * to be transfered.
+ * @param[in] is_fpdma_command This parameter indicates if the supplied
+ * ata_io is a first party DMA request (NCQ).
+ *
+ * @return none
+ */
+SATI_STATUS sati_move_set_sector_count(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ void * ata_io,
+ U32 sector_count,
+ U8 is_fpdma_command
+)
+{
+ U32 max_sector_count;
+ U8 * register_fis = sati_cb_get_h2d_register_fis_address(ata_io);
+
+ if (sequence->device->capabilities & SATI_DEVICE_CAP_48BIT_ENABLE)
+ max_sector_count = 65536;
+ else
+ max_sector_count = 256;
+
+ // Check the CDB transfer length count and set the register FIS sector
+ // count fields
+ if (0 == sector_count)
+ {
+ // A SCSI sector count of 0 for 10-byte CDBs and larger indicate no data
+ // transfer, so simply complete the command immediately.
+ return SATI_COMPLETE;
+ }
+ else if (sector_count >= max_sector_count)
+ {
+ // We have to perform multiple SATA commands to satisfy the sector
+ // count specified in the SCSI command.
+ sequence->command_specific_data.move_sector_count =
+ sector_count - max_sector_count;
+
+ // In ATA a sector count of 0 indicates use the maximum allowed for
+ // the command (i.e. 0 == 2^16 or 2^8).
+ sector_count = 0;
+ }
+
+ if (is_fpdma_command)
+ {
+ sati_set_ata_features(register_fis, sector_count & 0xFF);
+ sati_set_ata_features_exp(register_fis, (sector_count >> 8) & 0xFF);
+ }
+ else
+ {
+ sati_set_ata_sector_count(register_fis, sector_count & 0xFF);
+ sati_set_ata_sector_count_exp(register_fis, (sector_count >> 8) & 0xFF);
+ }
+
+ return SATI_SUCCESS;
+}
+
+/**
+ * @brief This method simply translates the 32-bit logical block address
+ * field from the SCSI CDB (10 or 12-byte) into the ATA task
+ * file (register FIS).
+ * For more information on the parameters passed to this method,
+ * please reference sati_translate_command()
+ *
+ * @return none
+ */
+void sati_move_translate_32_bit_lba(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ void * ata_io
+)
+{
+ U8 * cdb = sati_cb_get_cdb_address(scsi_io);
+ U8 * register_fis = sati_cb_get_h2d_register_fis_address(ata_io);
+
+ sati_set_ata_lba_low(register_fis, sati_get_cdb_byte(cdb, 5));
+ sati_set_ata_lba_mid(register_fis, sati_get_cdb_byte(cdb, 4));
+ sati_set_ata_lba_high(register_fis, sati_get_cdb_byte(cdb, 3));
+ sati_set_ata_lba_low_exp(register_fis, sati_get_cdb_byte(cdb, 2));
+ sati_set_ata_lba_mid_exp(register_fis, 0);
+ sati_set_ata_lba_high_exp(register_fis, 0);
+}
+
+/**
+ * @brief This method simply translates the 64-bit logical block address
+ * field from the SCSI CDB (16 byte) into the ATA task
+ * file (register FIS). The 2 most significant bytes must be 0,
+ * since ATA devices can, at most, support 48-bits of LBA.
+ * For more information on the parameters passed to this method,
+ * please reference sati_translate_command()
+ *
+ * @return Indicate if the LBA translation succeeded.
+ * @return SATI_SUCCESS This is returned if translation was successful.
+ * @return SATI_FAILURE_CHECK_RESPONSE_DATA This is returned if either
+ * of the 2 most significant bytes contain a non-zero value.
+ */
+SATI_STATUS sati_move_translate_64_bit_lba(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ void * ata_io
+)
+{
+ U8 * cdb = sati_cb_get_cdb_address(scsi_io);
+ U8 * register_fis = sati_cb_get_h2d_register_fis_address(ata_io);
+
+ // Ensure we receive a logical block address that is within range of
+ // addressibility per the ATA specification (i.e. 48-bit or 28-bit).
+ if ( (sati_get_cdb_byte(cdb, 2) == 0) && (sati_get_cdb_byte(cdb, 3) == 0) )
+ {
+ sati_set_ata_lba_low(register_fis, sati_get_cdb_byte(cdb, 9));
+ sati_set_ata_lba_mid(register_fis, sati_get_cdb_byte(cdb, 8));
+ sati_set_ata_lba_high(register_fis, sati_get_cdb_byte(cdb, 7));
+ sati_set_ata_lba_low_exp(register_fis, sati_get_cdb_byte(cdb, 6));
+ sati_set_ata_lba_mid_exp(register_fis, sati_get_cdb_byte(cdb, 5));
+ sati_set_ata_lba_high_exp(register_fis, sati_get_cdb_byte(cdb, 4));
+ return SATI_SUCCESS;
+ }
+ else
+ {
+ sati_scsi_sense_data_construct(
+ sequence,
+ scsi_io,
+ SCSI_STATUS_CHECK_CONDITION,
+ SCSI_SENSE_ILLEGAL_REQUEST,
+ SCSI_ASC_LBA_OUT_OF_RANGE,
+ SCSI_ASCQ_LBA_OUT_OF_RANGE
+ );
+ return SATI_FAILURE_CHECK_RESPONSE_DATA;
+ }
+}
+
+/**
+ * @brief This method will translate the pieces common to SCSI read and
+ * write 6 byte commands. Depending upon the capabilities
+ * supported by the target different ATA commands can be selected.
+ * For more information on the parameters passed to this method,
+ * please reference sati_translate_command().
+ *
+ * @return Indicate if the command translation succeeded.
+ * @retval SCI_SUCCESS This is returned if the command translation was
+ * successful.
+ */
+SATI_STATUS sati_move_6_translate_command(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ void * ata_io
+)
+{
+ U8 * cdb = sati_cb_get_cdb_address(scsi_io);
+ U8 * register_fis = sati_cb_get_h2d_register_fis_address(ata_io);
+
+ // Translate the logical block address information from the SCSI CDB.
+ // There is only 5 bits of MSB located in byte 1 of the CDB.
+ sati_set_ata_lba_low(register_fis, sati_get_cdb_byte(cdb, 3));
+ sati_set_ata_lba_mid(register_fis, sati_get_cdb_byte(cdb, 2));
+ sati_set_ata_lba_high(register_fis, sati_get_cdb_byte(cdb, 1) & 0x1F);
+
+ sati_move_translate_command(sequence, scsi_io, ata_io, 0);
+
+ return SATI_SUCCESS;
+}
+
+/**
+ * @brief This method will translate the pieces common to SCSI read and
+ * write 10/12 byte commands. Depending upon the capabilities
+ * supported by the target different ATA commands can be selected.
+ * For more information on the parameters passed to this method,
+ * please reference sati_translate_command().
+ *
+ * @param[in] device_head This parameter specifies the contents to be
+ * written to the device head register.
+ *
+ * @return Indicate if the command translation succeeded.
+ * @retval SCI_SUCCESS This is returned if the command translation was
+ * successful.
+ */
+SATI_STATUS sati_move_32_bit_lba_translate_command(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ void * ata_io,
+ U8 device_head
+)
+{
+ sati_move_translate_32_bit_lba(sequence, scsi_io, ata_io);
+ sati_move_translate_command(sequence, scsi_io, ata_io, device_head);
+
+ return SATI_SUCCESS;
+}
+
+/**
+ * @brief This method provides the common translation functionality for
+ * the 6-byte move command descriptor blocks (CDBs).
+ * This method will ensure that the following is performed:
+ * - command register is set
+ * - the SATI_TRANSLATOR_SEQUENCE::protocol field is set
+ * - the sector count field(s) are set
+ * - sati_move_6_translate_command() is invoked.
+ * For more information on the parameters passed to this method,
+ * please reference sati_translate_command().
+ *
+ * @pre The caller must ensure that the
+ * SATI_TRANSLATOR_SEQUENCE::data_direction field has already been set.
+ *
+ * @return Indicate if the command translation succeeded.
+ * @see sati_move_6_translate_command() for additional return codes.
+ */
+SATI_STATUS sati_move_small_translate_command(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ void * ata_io
+)
+{
+ // Translation of the sector count is performed differently for NCQ vs.
+ // other protocols.
+ if (sequence->device->capabilities & SATI_DEVICE_CAP_NCQ_SUPPORTED_ENABLE)
+ {
+ sati_move_set_ata_command(
+ sequence, ata_io, ATA_WRITE_FPDMA, ATA_READ_FPDMA
+ );
+ sati_move_ncq_translate_8_bit_sector_count(scsi_io, ata_io);
+ sequence->protocol = SAT_PROTOCOL_FPDMA;
+ }
+ else if (sequence->device->capabilities & SATI_DEVICE_CAP_48BIT_ENABLE)
+ {
+ U8 * cdb = sati_cb_get_cdb_address(scsi_io);
+
+ sati_move_small_udma_translate_command(
+ sequence, scsi_io, ata_io, ATA_WRITE_DMA_EXT, ATA_READ_DMA_EXT
+ );
+
+ // A read/write 6 with a 0 sector count indicates a transfer of 256
+ // sectors. As a result update the MSB (features expanded register)
+ // to indicate 256 sectors (0x100).
+ if (sati_get_cdb_byte(cdb, 4) == 0)
+ {
+ U8 * register_fis = sati_cb_get_h2d_register_fis_address(ata_io);
+ sati_set_ata_sector_count_exp(register_fis, 1);
+ }
+ }
+ else if (sequence->device->capabilities & SATI_DEVICE_CAP_UDMA_ENABLE)
+ {
+ sati_move_small_udma_translate_command(
+ sequence, scsi_io, ata_io, ATA_WRITE_DMA, ATA_READ_DMA
+ );
+ }
+ else
+ {
+ /**
+ * Currently the translation does not support devices incapable of
+ * handling the 48-bit feature set (i.e. 16 bits of sector count).
+ */
+ sati_scsi_sense_data_construct(
+ sequence,
+ scsi_io,
+ SCSI_STATUS_CHECK_CONDITION,
+ SCSI_SENSE_ILLEGAL_REQUEST,
+ SCSI_ASC_INVALID_FIELD_IN_CDB,
+ SCSI_ASCQ_INVALID_FIELD_IN_CDB
+ );
+ return SATI_FAILURE_CHECK_RESPONSE_DATA;
+ }
+
+ return sati_move_6_translate_command(sequence, scsi_io, ata_io);
+}
+
+/**
+ * @brief This method provides the common translation functionality for
+ * the larger command descriptor blocks (10, 12, 16-byte CDBs).
+ * For more information on the parameters passed to this method,
+ * please reference sati_translate_command().
+ *
+ * @param[in] sector_count This parameter specifies the number of sectors
+ * to be transfered.
+ * @param[in] device_head This parameter specifies the contents to be
+ * written to the device head register.
+ *
+ * @return Indicate if the command translation succeeded.
+ * @retval SATI_FAILURE This value is returned if neither NCQ or DMA is
+ * supported by the target device.
+ * @see sati_move_set_sector_count() for additional return codes.
+ */
+SATI_STATUS sati_move_large_translate_command(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ void * ata_io,
+ U32 sector_count,
+ U8 * ata_device_head
+)
+{
+ SATI_STATUS status = SATI_SUCCESS;
+ U8 * cdb = sati_cb_get_cdb_address(scsi_io);
+
+ // Parts of translation (e.g. sector count) is performed differently
+ // for NCQ vs. other protocols.
+ if (sequence->device->capabilities & SATI_DEVICE_CAP_NCQ_SUPPORTED_ENABLE)
+ {
+ // if the user did not request to ignore FUA
+ if((sequence->device->capabilities & SATI_DEVICE_CAP_IGNORE_FUA)==0)
+ {
+ // Is the Force Unit Access bit set?
+ if (sati_get_cdb_byte(cdb, 1) & SCSI_MOVE_FUA_BIT_ENABLE)
+ *ata_device_head = ATA_DEV_HEAD_REG_FUA_ENABLE;
+ }
+
+ sati_move_set_ata_command(
+ sequence, ata_io, ATA_WRITE_FPDMA, ATA_READ_FPDMA
+ );
+ status = sati_move_set_sector_count(
+ sequence, scsi_io, ata_io, sector_count, TRUE
+ );
+ sequence->protocol = SAT_PROTOCOL_FPDMA;
+ }
+ else if (sequence->device->capabilities & SATI_DEVICE_CAP_48BIT_ENABLE)
+ {
+ // Is the Force Unit Access bit set? If it is, then error. We
+ // aren't supporting this yet for normal DMA.
+ if (sati_get_cdb_byte(cdb, 1) & SCSI_MOVE_FUA_BIT_ENABLE)
+ {
+ sati_scsi_sense_data_construct(
+ sequence,
+ scsi_io,
+ SCSI_STATUS_CHECK_CONDITION,
+ SCSI_SENSE_ILLEGAL_REQUEST,
+ SCSI_ASC_INVALID_FIELD_IN_CDB,
+ SCSI_ASCQ_INVALID_FIELD_IN_CDB
+ );
+ return SATI_FAILURE_CHECK_RESPONSE_DATA;
+ }
+
+ status = sati_move_large_udma_translate_command(
+ sequence,
+ scsi_io,
+ ata_io,
+ sector_count,
+ ATA_WRITE_DMA_EXT,
+ ATA_READ_DMA_EXT
+ );
+ }
+ else if (sequence->device->capabilities & SATI_DEVICE_CAP_UDMA_ENABLE)
+ {
+ status = sati_move_large_udma_translate_command(
+ sequence,
+ scsi_io,
+ ata_io,
+ sector_count,
+ ATA_WRITE_DMA,
+ ATA_READ_DMA
+ );
+ }
+ else
+ {
+ /**
+ * Currently the translation does not support devices incapable of
+ * handling the 48-bit feature set (i.e. 16 bits of sector count).
+ */
+ sati_scsi_sense_data_construct(
+ sequence,
+ scsi_io,
+ SCSI_STATUS_CHECK_CONDITION,
+ SCSI_SENSE_ILLEGAL_REQUEST,
+ SCSI_ASC_INVALID_FIELD_IN_CDB,
+ SCSI_ASCQ_INVALID_FIELD_IN_CDB
+ );
+ return SATI_FAILURE_CHECK_RESPONSE_DATA;
+ }
+
+ return status;
+}
+
+/**
+ * @brief This method simply performs the functionality common to all
+ * payload data movement translations (i.e. READ/WRITE).
+ * For more information on the parameters passed to this method,
+ * please reference sati_translate_command().
+ *
+ * @param[in] device_head This parameter specifies the current contents
+ * to be written to the ATA task file (register FIS) device
+ * head register.
+ *
+ * @return none
+ */
+void sati_move_translate_command(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ void * ata_io,
+ U8 device_head
+)
+{
+ U8 * register_fis = sati_cb_get_h2d_register_fis_address(ata_io);
+
+ sati_set_ata_device_head(
+ register_fis, device_head | ATA_DEV_HEAD_REG_LBA_MODE_ENABLE
+ );
+}
+
diff --git a/sys/dev/isci/scil/sati_move.h b/sys/dev/isci/scil/sati_move.h
new file mode 100644
index 0000000..b0985a2
--- /dev/null
+++ b/sys/dev/isci/scil/sati_move.h
@@ -0,0 +1,121 @@
+/*-
+ * 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.
+ *
+ * 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.
+ *
+ * $FreeBSD$
+ */
+#ifndef _SATI_MOVE_H_
+#define _SATI_MOVE_H_
+
+/**
+ * @file
+ * @brief This file contains the method declarations and type definitions
+ * common to translations that move data (i.e. read, write). It
+ * has code for the various different size CDBs (6, 10, 12, 16).
+ */
+
+#include <dev/isci/scil/sati_types.h>
+#include <dev/isci/scil/sati_translator_sequence.h>
+
+SATI_STATUS sati_move_set_sector_count(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ void * ata_io,
+ U32 sector_count,
+ U8 is_fpdma_command
+);
+
+void sati_move_translate_32_bit_lba(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ void * ata_io
+);
+
+SATI_STATUS sati_move_translate_64_bit_lba(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ void * ata_io
+);
+
+SATI_STATUS sati_move_6_translate_command(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ void * ata_io
+);
+
+SATI_STATUS sati_move_32_bit_lba_translate_command(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ void * ata_io,
+ U8 device_head
+);
+
+SATI_STATUS sati_move_small_translate_command(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ void * ata_io
+);
+
+SATI_STATUS sati_move_large_translate_command(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ void * ata_io,
+ U32 sector_count,
+ U8 * ata_device_head
+);
+
+void sati_move_translate_command(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ void * ata_io,
+ U8 device_head
+);
+
+#endif // _SATI_MOVE_H_
diff --git a/sys/dev/isci/scil/sati_passthrough.c b/sys/dev/isci/scil/sati_passthrough.c
new file mode 100644
index 0000000..e35b5ea
--- /dev/null
+++ b/sys/dev/isci/scil/sati_passthrough.c
@@ -0,0 +1,465 @@
+/*-
+ * 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.
+ *
+ * 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 <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/**
+ * @file
+ * @brief This file contains the method implementations required to
+ * translate the SCSI passthru command.
+ */
+
+#if !defined(DISABLE_SATI_PASSTHROUGH)
+
+#include <dev/isci/scil/sati.h>
+#include <dev/isci/scil/sati_passthrough.h>
+#include <dev/isci/scil/sati_util.h>
+#include <dev/isci/scil/sati_callbacks.h>
+#include <dev/isci/scil/intel_ata.h>
+
+#define PASSTHROUGH_CDB_PROTOCOL_MASK 0x1E
+#define PASSTHROUGH_CDB_EXTEND_MASK 0x1
+#define PASSTHROUGH_CDB_CK_COND_MASK 0x20
+#define PASSTHROUGH_CDB_T_DIR_MASK 0x8
+
+#define PASSTHROUGH_ISOLATE_BITS(cdb, index, mask, shift) (((sati_get_cdb_byte(cdb, index) & mask) >> shift))
+
+#define PASSTHROUGH_CDB_PROTOCOL(cdb) PASSTHROUGH_ISOLATE_BITS(cdb, 1, PASSTHROUGH_CDB_PROTOCOL_MASK, 1)
+#define PASSTHROUGH_CDB_EXTEND(cdb) PASSTHROUGH_ISOLATE_BITS(cdb, 1, PASSTHROUGH_CDB_EXTEND_MASK, 0)
+#define PASSTHROUGH_CDB_CK_COND(cdb) PASSTHROUGH_ISOLATE_BITS(cdb, 2, PASSTHROUGH_CDB_CK_COND_MASK, 5)
+#define PASSTHROUGH_CDB_T_DIR(cdb) PASSTHROUGH_ISOLATE_BITS(cdb, 2, PASSTHROUGH_CDB_T_DIR_MASK, 3)
+
+#define PASSTHROUGH_CDB_MULTIPLE_COUNT(cdb) (sati_get_cdb_byte(cdb, 1) >> 5)
+#define PASSTHROUGH_CDB_COMMAND(cdb, index) sati_get_cdb_byte(cdb, index)
+
+// Protocols
+#define PASSTHROUGH_PIO_DATA_IN 0x4
+#define PASSTHROUGH_PIO_DATA_OUT 0x5
+#define PASSTHROUGH_UDMA_DATA_IN 0xA
+#define PASSTHROUGH_UDMA_DATA_OUT 0xB
+#define PASSTHROUGH_RETURN_RESPONSE 0xF
+
+/**
+* @brief This function will check the multiple_count field in the SCSI CDB
+* and if multiple_count is nonzero the function will check the
+* ATA command code. Only Read and Write Multiple commands are allowed
+* when multiple_count is a nonzero value.
+*
+* @param[in] cdb The SCSI cdb for the ATA pass-through command
+*
+* @return BOOL
+ @retval TRUE - multiple_count is nonzero with a unsupported command
+ @retval FALSE - multiple_count is zero or the command supports a nonzero value
+*/
+static
+BOOL sati_passthrough_multiple_count_error(
+ U8 * cdb
+)
+{
+ U8 ata_command_code;
+
+ if(PASSTHROUGH_CDB_MULTIPLE_COUNT(cdb) > 0)
+ {
+ if(sati_get_cdb_byte(cdb, 0 ) == SCSI_ATA_PASSTHRU_12)
+ {
+ ata_command_code = PASSTHROUGH_CDB_COMMAND(cdb, 9);
+ }
+ else
+ {
+ ata_command_code = PASSTHROUGH_CDB_COMMAND(cdb, 14);
+ }
+
+ switch(ata_command_code)
+ { //MULTICOUNT bit is supported
+ case ATA_READ_MULTIPLE:
+ case ATA_READ_MULTIPLE_EXT:
+ case ATA_WRITE_MULTIPLE:
+ case ATA_WRITE_MULTIPLE_EXT:
+ case ATA_WRITE_MULTIPLE_FUA_EXT:
+ return FALSE;
+ break;
+
+ default:
+ return TRUE;
+ }
+ }
+ //MULTICOUNT bit is not set
+ return FALSE;
+}
+
+/**
+ * @brief This method will construct the sense data buffer in the user's
+ * sense data buffer location. Additionally, it will set the user's
+ * SCSI status.
+ *
+ * @param[in] sequence This parameter specifies the translation sequence
+ * for which to construct the sense data.
+ * @param[in] register_fis This parameter specifies the fis from which
+ * to get the data.
+ * @param[in,out] scsi_io This parameter specifies the user's IO request
+ * for which to construct the sense data.
+ * @param[in] scsi_status This parameter specifies the SCSI status
+ * value for the user's IO request.
+ * @param[in] sense_key This parameter specifies the sense key to
+ * be set for the user's IO request.
+ * @param[in] additional_sense_code This parameter specifies the
+ * additional sense code (ASC) key to be set for the user's
+ * IO request.
+ * @param[in] additional_sense_code_qualifier This parameter specifies
+ * the additional sense code qualifier (ASCQ) key to be set
+ * for the user's IO request.
+ *
+ * @return none
+ */
+static
+void sati_passthrough_construct_sense(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ U8 * register_fis,
+ void * scsi_io,
+ U8 scsi_status,
+ U8 sense_key,
+ U8 additional_sense_code,
+ U8 additional_sense_code_qualifier
+)
+{
+ U8 * sense_data;
+ U32 sense_len;
+ U8 * cdb;
+ unsigned char sector_count_upper;
+ unsigned char lba_upper;
+
+#ifdef SATI_TRANSPORT_SUPPORTS_SAS
+ SCI_SSP_RESPONSE_IU_T * rsp_iu = (SCI_SSP_RESPONSE_IU_T*)
+ sati_cb_get_response_iu_address(scsi_io);
+
+ sati_scsi_common_response_iu_construct(
+ rsp_iu,
+ scsi_status,
+ SCSI_FIXED_SENSE_DATA_BASE_LENGTH,
+ SCSI_RESPONSE_DATA_PRES_SENSE_DATA
+ );
+
+ sense_data = (U8*) rsp_iu->data;
+ sense_len = SSP_RESPONSE_IU_MAX_DATA * 4; // dwords to bytes
+#else
+ sense_data = sati_cb_get_sense_data_address(scsi_io);
+ sense_len = sati_cb_get_sense_data_length(scsi_io);
+#endif // SATI_TRANSPORT_SUPPORTS_SAS
+
+ sati_scsi_sense_data_construct(
+ sequence,
+ scsi_io,
+ scsi_status,
+ sense_key,
+ additional_sense_code,
+ additional_sense_code_qualifier
+ );
+
+ cdb = sati_cb_get_cdb_address(scsi_io);
+
+ if (sati_get_ata_sector_count_ext(register_fis) != 0) {
+ sector_count_upper = 1;
+ } else {
+ sector_count_upper = 0;
+ }
+
+ if (sati_get_ata_lba_high_ext(register_fis) != 0 ||
+ sati_get_ata_lba_mid_ext(register_fis) != 0 ||
+ sati_get_ata_lba_low_ext(register_fis) != 0) {
+ lba_upper = 1;
+ } else {
+ lba_upper = 0;
+ }
+
+ // Information section
+ sati_set_sense_data_byte(sense_data, sense_len, 3, (U8)sati_get_ata_error(register_fis));
+ sati_set_sense_data_byte(sense_data, sense_len, 4, (U8)sati_get_ata_status(register_fis));
+ sati_set_sense_data_byte(sense_data, sense_len, 5, sati_get_ata_device(register_fis));
+ sati_set_sense_data_byte(sense_data, sense_len, 6, sati_get_ata_sector_count(register_fis));
+
+ // Command specific section
+ sati_set_sense_data_byte(sense_data, sense_len, 8, (PASSTHROUGH_CDB_EXTEND(cdb) << 7) | (sector_count_upper << 6) | (lba_upper << 5));
+ sati_set_sense_data_byte(sense_data, sense_len, 9, sati_get_ata_lba_high(register_fis));
+ sati_set_sense_data_byte(sense_data, sense_len, 10, sati_get_ata_lba_mid(register_fis));
+ sati_set_sense_data_byte(sense_data, sense_len, 11, sati_get_ata_lba_low(register_fis));
+
+ sequence->is_sense_response_set = TRUE;
+}
+
+/**
+ * @brief This method will verify that the T_DIR bit matches the protocol bit.
+ * It will additionally set the direction on the sequence.
+ *
+ * @param[in,out] sequence This parameter specifies the translation sequence
+ * for which to construct the sense data.
+ * @param[in] cdb The CDB containing the passthrough command
+ *
+ * @return none
+ */
+static
+SATI_STATUS sati_passthrough_check_direction(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ U8 * cdb
+)
+{
+ if ((PASSTHROUGH_CDB_PROTOCOL(cdb) == PASSTHROUGH_PIO_DATA_IN) ||
+ (PASSTHROUGH_CDB_PROTOCOL(cdb) == PASSTHROUGH_UDMA_DATA_IN))
+ {
+ if (PASSTHROUGH_CDB_T_DIR(cdb) == 0x0)
+ {
+ return SATI_FAILURE;
+ }
+ else
+ {
+ sequence->data_direction = SATI_DATA_DIRECTION_IN;
+ }
+ }
+ else if ((PASSTHROUGH_CDB_PROTOCOL(cdb) == PASSTHROUGH_PIO_DATA_OUT) ||
+ (PASSTHROUGH_CDB_PROTOCOL(cdb) == PASSTHROUGH_UDMA_DATA_OUT))
+ {
+ if (PASSTHROUGH_CDB_T_DIR(cdb) == 0x1)
+ {
+ return SATI_FAILURE;
+ }
+ else
+ {
+ sequence->data_direction = SATI_DATA_DIRECTION_OUT;
+ }
+ }
+ else
+ {
+ sequence->data_direction = SATI_DATA_DIRECTION_NONE;
+ }
+
+ return SATI_COMPLETE;
+}
+
+//******************************************************************************
+//* P U B L I C M E T H O D S
+//******************************************************************************
+
+/**
+ * @brief This method will translate the SCSI Passthrough command
+ * into the corresponding ATA command.
+ *
+ * @return Indicate if the command translation succeeded.
+ * @retval SATI_SUCCESS This is returned if the command translation was
+ * successful.
+ * @retval SATI_FAILURE This is returned if the command translation was
+ * unsuccessful
+ */
+
+SATI_STATUS sati_passthrough_12_translate_command(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ void * ata_io
+)
+{
+ SATI_STATUS status;
+ U8 * cdb;
+ U8 * register_fis;
+
+ status = SATI_FAILURE;
+
+ sequence->type = SATI_SEQUENCE_ATA_PASSTHROUGH_12;
+ sequence->state = SATI_SEQUENCE_STATE_TRANSLATE_DATA;
+
+ cdb = sati_cb_get_cdb_address(scsi_io);
+ sequence->protocol = PASSTHROUGH_CDB_PROTOCOL (cdb);
+ register_fis = sati_cb_get_h2d_register_fis_address(ata_io);
+
+ if (sati_passthrough_check_direction(sequence, cdb) != SATI_COMPLETE
+ || sati_passthrough_multiple_count_error(cdb)
+ )
+ {
+ // Fail due to mismatch
+ sati_scsi_sense_data_construct(
+ sequence,
+ scsi_io,
+ SCSI_STATUS_CHECK_CONDITION,
+ SCSI_SENSE_ILLEGAL_REQUEST,
+ SCSI_ASC_INVALID_FIELD_IN_CDB,
+ SCSI_ASCQ_INVALID_FIELD_IN_CDB
+ );
+ return SATI_FAILURE_CHECK_RESPONSE_DATA;
+ }
+
+ sati_set_ata_features(register_fis, sati_get_cdb_byte(cdb, 3));
+ sati_set_ata_sector_count(register_fis, sati_get_cdb_byte(cdb, 4));
+ sati_set_ata_lba_low(register_fis, sati_get_cdb_byte(cdb, 5));
+ sati_set_ata_lba_mid(register_fis, sati_get_cdb_byte(cdb, 6));
+ sati_set_ata_lba_high(register_fis, sati_get_cdb_byte(cdb, 7));
+ sati_set_ata_device_head(register_fis, sati_get_cdb_byte(cdb, 8));
+ sati_set_ata_command(register_fis, sati_get_cdb_byte(cdb, 9));
+
+ sequence->state = SATI_SEQUENCE_STATE_AWAIT_RESPONSE;
+
+ return SATI_SUCCESS;
+}
+
+/**
+ * @brief This method will translate the SCSI Passthrough command
+ * into the corresponding ATA command.
+ *
+ * @return Indicate if the command translation succeeded.
+ * @retval SATI_SUCCESS This is returned if the command translation was
+ * successful.
+ * @retval SATI_FAILURE This is returned if the command translation was
+ * unsuccessful
+ */
+SATI_STATUS sati_passthrough_16_translate_command(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ void * ata_io
+)
+{
+ SATI_STATUS status;
+ U8 * cdb;
+ U8 * register_fis;
+
+ status = SATI_FAILURE;
+
+ sequence->type = SATI_SEQUENCE_ATA_PASSTHROUGH_16;
+ sequence->state = SATI_SEQUENCE_STATE_TRANSLATE_DATA;
+
+ cdb = sati_cb_get_cdb_address(scsi_io);
+ sequence->protocol = PASSTHROUGH_CDB_PROTOCOL(cdb);
+ register_fis = sati_cb_get_h2d_register_fis_address(ata_io);
+
+ if (sati_passthrough_check_direction(sequence, cdb) != SATI_COMPLETE
+ || sati_passthrough_multiple_count_error(cdb)
+ )
+ {
+ // Fail due to mismatch
+ sati_scsi_sense_data_construct(
+ sequence,
+ scsi_io,
+ SCSI_STATUS_CHECK_CONDITION,
+ SCSI_SENSE_ILLEGAL_REQUEST,
+ SCSI_ASC_INVALID_FIELD_IN_CDB,
+ SCSI_ASCQ_INVALID_FIELD_IN_CDB
+ );
+ return SATI_FAILURE_CHECK_RESPONSE_DATA;
+ }
+
+ if (PASSTHROUGH_CDB_EXTEND(cdb) == 1)
+ {
+ sati_set_ata_features_exp(register_fis, sati_get_cdb_byte(cdb, 3));
+ sati_set_ata_sector_count_exp(register_fis, sati_get_cdb_byte(cdb, 5));
+ sati_set_ata_lba_low_exp(register_fis, sati_get_cdb_byte(cdb, 7));
+ sati_set_ata_lba_mid_exp(register_fis, sati_get_cdb_byte(cdb, 9));
+ sati_set_ata_lba_high_exp(register_fis, sati_get_cdb_byte(cdb, 11));
+ }
+ sati_set_ata_features(register_fis, sati_get_cdb_byte(cdb, 4));
+ sati_set_ata_sector_count(register_fis, sati_get_cdb_byte(cdb, 6));
+ sati_set_ata_lba_low(register_fis, sati_get_cdb_byte(cdb, 8));
+ sati_set_ata_lba_mid(register_fis, sati_get_cdb_byte(cdb, 10));
+ sati_set_ata_lba_high(register_fis, sati_get_cdb_byte(cdb, 12));
+ sati_set_ata_device_head(register_fis, sati_get_cdb_byte(cdb, 13));
+ sati_set_ata_command(register_fis, sati_get_cdb_byte(cdb, 14));
+
+ sequence->state = SATI_SEQUENCE_STATE_AWAIT_RESPONSE;
+
+ return SATI_SUCCESS;
+}
+
+/**
+ * @brief This method will translate the ATA command
+ * response
+ *
+ * @return Indicate if the command translation succeeded.
+ * @retval SATI_COMPLETE This is returned if the command translation was
+ * successful.
+ * @retval SATI_FAILURE This is returned if the command translation was
+ * unsuccessful
+ */
+SATI_STATUS sati_passthrough_translate_response(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ void * ata_io
+)
+{
+ U8 * cdb;
+ U8 * register_fis;
+
+ cdb = sati_cb_get_cdb_address(scsi_io);
+ register_fis = sati_cb_get_d2h_register_fis_address(ata_io);
+
+ // Check for device errors
+ if (sati_get_ata_status(register_fis) & ATA_STATUS_REG_ERROR_BIT)
+ {
+ sati_translate_error(sequence, scsi_io, (U8)sati_get_ata_error(register_fis));
+ return SATI_FAILURE_CHECK_RESPONSE_DATA;
+ }
+
+ // If the user set the check condition bit, fill out the sense data
+ if (PASSTHROUGH_CDB_CK_COND(cdb) ||
+ PASSTHROUGH_CDB_PROTOCOL(cdb) == PASSTHROUGH_RETURN_RESPONSE)
+ {
+ sati_passthrough_construct_sense(
+ sequence,
+ register_fis,
+ scsi_io,
+ SCSI_STATUS_CHECK_CONDITION,
+ SCSI_SENSE_RECOVERED_ERROR,
+ SCSI_ASC_NO_ADDITIONAL_SENSE,
+ SCSI_ASCQ_ATA_PASS_THROUGH_INFORMATION_AVAILABLE
+ );
+ }
+
+ sequence->state = SATI_SEQUENCE_STATE_FINAL;
+
+ return SATI_COMPLETE;
+}
+
+#endif // !defined(DISABLE_SATI_PASSTHROUGH)
diff --git a/sys/dev/isci/scil/sati_passthrough.h b/sys/dev/isci/scil/sati_passthrough.h
new file mode 100644
index 0000000..110664b
--- /dev/null
+++ b/sys/dev/isci/scil/sati_passthrough.h
@@ -0,0 +1,88 @@
+/*-
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 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.
+ *
+ * $FreeBSD$
+ */
+#ifndef _SATI_PASSTHROUGH_H_
+#define _SATI_PASSTHROUGH_H_
+
+/**
+ * @file
+ * @brief This file contains the method implementations required to
+ * translate the SCSI passthrough command.
+ */
+
+#if !defined(DISABLE_SATI_PASSTHROUGH)
+
+#include <dev/isci/scil/sati_types.h>
+#include <dev/isci/scil/sati_translator_sequence.h>
+
+SATI_STATUS sati_passthrough_12_translate_command(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ void * ata_io
+);
+
+SATI_STATUS sati_passthrough_16_translate_command(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ void * ata_io
+);
+
+SATI_STATUS sati_passthrough_translate_response(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ void * ata_io
+);
+
+#endif // !defined(DISABLE_SATI_PASSTHROUGH)
+
+#endif // _SATI_PASSTHROUGH_H_
diff --git a/sys/dev/isci/scil/sati_read.c b/sys/dev/isci/scil/sati_read.c
new file mode 100644
index 0000000..ce32d25
--- /dev/null
+++ b/sys/dev/isci/scil/sati_read.c
@@ -0,0 +1,323 @@
+/*-
+ * 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.
+ *
+ * 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 <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/**
+ * @file
+ * @brief This file contains the method implementations required to
+ * translate the SCSI read (6, 10, 12, or 16-byte) commands.
+ */
+
+#include <dev/isci/scil/sati_move.h>
+#include <dev/isci/scil/sati_read.h>
+#include <dev/isci/scil/sati_callbacks.h>
+#include <dev/isci/scil/sati_util.h>
+
+#include <dev/isci/scil/intel_ata.h>
+#include <dev/isci/scil/intel_scsi.h>
+
+//******************************************************************************
+//* P R I V A T E M E T H O D S
+//******************************************************************************
+
+/**
+ * @brief This method performs the common translation functionality for
+ * all SCSI read operations that are 10 bytes in size or larger.
+ * Translated/Written items include:
+ * - Force Unit Access (FUA)
+ * - Sector Count/Transfer Length
+ * - Command register
+ *
+ * @param[in] sector_count This parameter specifies the number of sectors
+ * to be transferred by this request.
+ * @param[in] device_head This parameter points to device head register
+ * that is to be written into the ATA task file (register FIS).
+ *
+ * @return Indicate if the command translation succeeded.
+ * @see sati_move_set_sector_count() for additional return values.
+ */
+static
+SATI_STATUS sati_read_large_translate_command(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ void * ata_io,
+ U32 sector_count,
+ U8 * device_head
+)
+{
+ sequence->data_direction = SATI_DATA_DIRECTION_IN;
+
+ return sati_move_large_translate_command(
+ sequence,
+ scsi_io,
+ ata_io,
+ sector_count,
+ device_head
+ );
+}
+
+/**
+ * @brief This method performs the common translation functionality for
+ * all SCSI read operations containing a 32-bit logical block
+ * address.
+ * Translated/Written items include:
+ * - Logical Block Address (LBA)
+ * - Force Unit Access (FUA)
+ * - Sector Count/Transfer Length
+ * - Command register
+ * For more information on the parameters passed to this method,
+ * please reference sati_translate_command().
+ *
+ * @param[in] sector_count This parameter specifies the number of sectors
+ * to be transferred by this request.
+ * @param[in] control_byte_offset This parameter specifies the byte offset
+ * into the command descriptor block at which the control byte
+ * is located.
+ *
+ * @return Indicate if the command translation succeeded.
+ * @see sati_move_32_bit_lba_translate_command(), sati_move_set_sector_count()
+ * for additional return values.
+ */
+static
+SATI_STATUS sati_read_32_bit_lba_translate_command(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ void * ata_io,
+ U32 sector_count,
+ U8 control_byte_offset
+)
+{
+ U8 device_head = 0;
+ SATI_STATUS status;
+
+ status = sati_read_large_translate_command(
+ sequence, scsi_io, ata_io, sector_count, &device_head
+ );
+
+ if (status == SATI_SUCCESS)
+ {
+ status = sati_move_32_bit_lba_translate_command(
+ sequence, scsi_io, ata_io, device_head
+ );
+ }
+
+ return status;
+}
+
+//******************************************************************************
+//* P U B L I C M E T H O D S
+//******************************************************************************
+
+/**
+ * @brief This method will translate the SCSI read command into a
+ * corresponding ATA read 6 command. Depending upon the capabilities
+ * supported by the target different ATA commands can be selected.
+ * For more information on the parameters passed to this method,
+ * please reference sati_translate_command().
+ *
+ * @return Indicate if the command translation succeeded.
+ * @retval SCI_SUCCESS This is returned if the command translation was
+ * successful.
+ * @retval SATI_FAILURE_CHECK_RESPONSE_DATA This value is returned if
+ * sense data has been created as a result of something specified
+ * in the CDB.
+ */
+SATI_STATUS sati_read_6_translate_command(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ void * ata_io
+)
+{
+ if(sati_device_state_stopped(sequence, scsi_io))
+ {
+ return SATI_FAILURE_CHECK_RESPONSE_DATA;
+ }
+ else
+ {
+ sequence->data_direction = SATI_DATA_DIRECTION_IN;
+ sequence->type = SATI_SEQUENCE_READ_6;
+
+ return sati_move_small_translate_command(sequence, scsi_io, ata_io);
+ }
+}
+
+/**
+ * @brief This method will translate the SCSI read 10 command into a
+ * corresponding ATA read command. Depending upon the capabilities
+ * supported by the target different ATA commands can be selected.
+ * It ensures that all translation required for this command is
+ * performed successfully.
+ * For more information on the parameters passed to this method,
+ * please reference sati_translate_command().
+ *
+ * @return Indicate if the command translation succeeded.
+ * @see sati_read_32_bit_lba_translate_command() for return values.
+ */
+SATI_STATUS sati_read_10_translate_command(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ void * ata_io
+)
+{
+
+ U8 * cdb = sati_cb_get_cdb_address(scsi_io);
+
+ U32 sector_count = (sati_get_cdb_byte(cdb, 7) << 8) |
+ (sati_get_cdb_byte(cdb, 8));
+
+ if(sati_device_state_stopped(sequence, scsi_io))
+ {
+ return SATI_FAILURE_CHECK_RESPONSE_DATA;
+ }
+ else
+ {
+ sequence->type = SATI_SEQUENCE_READ_10;
+
+ return sati_read_32_bit_lba_translate_command(
+ sequence, scsi_io, ata_io, sector_count, 9
+ );
+ }
+}
+
+/**
+ * @brief This method will translate the SCSI read 12 command into a
+ * corresponding ATA read command. Depending upon the capabilities
+ * supported by the target different ATA commands can be selected.
+ * It ensures that all translation required for this command is
+ * performed successfully.
+ * For more information on the parameters passed to this method,
+ * please reference sati_translate_command().
+ *
+ * @return Indicate if the command translation succeeded.
+ * @see sati_read_32_bit_lba_translate_command() for return values.
+ */
+SATI_STATUS sati_read_12_translate_command(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ void * ata_io
+)
+{
+ U8 * cdb = sati_cb_get_cdb_address(scsi_io);
+ U32 sector_count = (sati_get_cdb_byte(cdb, 6) << 24) |
+ (sati_get_cdb_byte(cdb, 7) << 16) |
+ (sati_get_cdb_byte(cdb, 8) << 8) |
+ (sati_get_cdb_byte(cdb, 9));
+
+ if(sati_device_state_stopped(sequence, scsi_io))
+ {
+ return SATI_FAILURE_CHECK_RESPONSE_DATA;
+ }
+ else
+ {
+ sequence->type = SATI_SEQUENCE_READ_12;
+
+ return sati_read_32_bit_lba_translate_command(
+ sequence, scsi_io, ata_io, sector_count, 11
+ );
+ }
+}
+
+/**
+ * @brief This method will translate the SCSI read 16 command into a
+ * corresponding ATA read command. Depending upon the capabilities
+ * supported by the target different ATA commands can be selected.
+ * It ensures that all translation required for this command is
+ * performed successfully.
+ * For more information on the parameters passed to this method,
+ * please reference sati_translate_command().
+ *
+ * @return Indicate if the command translation succeeded.
+ * @see sati_read_large_translate_command(), sati_move_translate_64_bit_lba()
+ * for additional return values.
+ */
+SATI_STATUS sati_read_16_translate_command(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ void * ata_io
+)
+{
+ SATI_STATUS status;
+ U8 device_head = 0;
+ U8 * cdb = sati_cb_get_cdb_address(scsi_io);
+ U32 sector_count = (sati_get_cdb_byte(cdb, 10) << 24) |
+ (sati_get_cdb_byte(cdb, 11) << 16) |
+ (sati_get_cdb_byte(cdb, 12) << 8) |
+ (sati_get_cdb_byte(cdb, 13));
+
+ if(sati_device_state_stopped(sequence, scsi_io))
+ {
+ return SATI_FAILURE_CHECK_RESPONSE_DATA;
+ }
+ else
+ {
+ sequence->type = SATI_SEQUENCE_READ_16;
+
+ // Translate the sector count, write command register, and check various
+ // other parts of the CDB.
+ status = sati_read_large_translate_command(
+ sequence, scsi_io, ata_io, sector_count, &device_head
+ );
+
+ // Attempt to translate the 64-bit LBA field from the SCSI request
+ // into the 48-bits of LBA in the ATA register FIS.
+ if (status == SATI_SUCCESS)
+ {
+ sati_move_translate_command(sequence, scsi_io, ata_io, device_head);
+ status = sati_move_translate_64_bit_lba(sequence, scsi_io, ata_io);
+ }
+
+ return status;
+ }
+}
+
diff --git a/sys/dev/isci/scil/sati_read.h b/sys/dev/isci/scil/sati_read.h
new file mode 100644
index 0000000..016700c
--- /dev/null
+++ b/sys/dev/isci/scil/sati_read.h
@@ -0,0 +1,91 @@
+/*-
+ * 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.
+ *
+ * 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.
+ *
+ * $FreeBSD$
+ */
+#ifndef _SATI_READ_H_
+#define _SATI_READ_H_
+
+/**
+ * @file
+ * @brief This file contains the method declarations and type definitions
+ * required to translate the SCSI read (6, 10, 12, or 16-byte)
+ * commands.
+ */
+
+#include <dev/isci/scil/sati_types.h>
+#include <dev/isci/scil/sati_translator_sequence.h>
+
+SATI_STATUS sati_read_6_translate_command(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ void * ata_io
+);
+
+SATI_STATUS sati_read_10_translate_command(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ void * ata_io
+);
+
+SATI_STATUS sati_read_12_translate_command(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ void * ata_io
+);
+
+SATI_STATUS sati_read_16_translate_command(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ void * ata_io
+);
+
+#endif // _SATI_READ_H_
diff --git a/sys/dev/isci/scil/sati_read_buffer.c b/sys/dev/isci/scil/sati_read_buffer.c
new file mode 100644
index 0000000..329e763
--- /dev/null
+++ b/sys/dev/isci/scil/sati_read_buffer.c
@@ -0,0 +1,235 @@
+/*-
+ * 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.
+*
+* 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 <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/**
+* @file
+* @brief This file contains the implementation to translate
+* SCSI Read Buffer command based on the SAT spec.
+*/
+
+#if !defined(DISABLE_SATI_READ_BUFFER)
+
+#include <dev/isci/scil/sati_read_buffer.h>
+#include <dev/isci/scil/sati_callbacks.h>
+#include <dev/isci/scil/sati_util.h>
+
+
+/**
+* @brief This method will translate the SCSI Read Buffer command
+* into a corresponding ATA Read Buffer command.
+* For more information on the parameters passed to this method,
+* please reference sati_translate_command().
+*
+* @return Indicates if the command translation succeeded.
+* @retval SATI_SUCCESS indicates that the translation was supported and occurred
+* without error.
+* @retval SATI_FAILURE_CHECK_RESPONSE_DATA This value is returned if
+* there is a translation failure.
+* @retval SATI_COMPLETE indicates that the translation was supported, occurred without
+* error, and no additional translation is necessary.
+*/
+SATI_STATUS sati_read_buffer_translate_command(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ void * ata_io
+)
+{
+ U8 * cdb = sati_cb_get_cdb_address(scsi_io);
+ SATI_STATUS status = SATI_FAILURE;
+ U32 allocation_length;
+ U32 buffer_offset;
+
+ allocation_length = ((sati_get_cdb_byte(cdb, 6) << 16) |
+ (sati_get_cdb_byte(cdb, 7) << 8) |
+ (sati_get_cdb_byte(cdb, 8)));
+
+ buffer_offset = ((sati_get_cdb_byte(cdb, 3) << 16) |
+ (sati_get_cdb_byte(cdb, 4) << 8) |
+ (sati_get_cdb_byte(cdb, 5)));
+
+ sequence->allocation_length = allocation_length;
+
+ switch(sati_get_cdb_byte(cdb, 1))
+ {
+ case SATI_READ_BUFFER_MODE_DATA:
+ if((allocation_length == 512) && (buffer_offset == 0) &&
+ (sati_get_cdb_byte(cdb, 2) == 0))
+ {
+ sati_ata_read_buffer_construct(ata_io, sequence);
+ sequence->type = SATI_SEQUENCE_READ_BUFFER;
+ sequence->state = SATI_SEQUENCE_STATE_AWAIT_RESPONSE;
+ status = SATI_SUCCESS;
+ }
+ else
+ {
+ sati_scsi_sense_data_construct(
+ sequence,
+ scsi_io,
+ SCSI_STATUS_CHECK_CONDITION,
+ SCSI_SENSE_ILLEGAL_REQUEST,
+ SCSI_ASC_INVALID_FIELD_IN_CDB,
+ SCSI_ASCQ_INVALID_FIELD_IN_CDB
+ );
+ sequence->state = SATI_SEQUENCE_STATE_FINAL;
+ status = SATI_FAILURE_CHECK_RESPONSE_DATA;
+ }
+ break;
+
+ case SATI_READ_BUFFER_MODE_DESCRIPTOR:
+
+ //allocation legnth must be at least four to return translated data
+ if(allocation_length < 4)
+ {
+ sati_scsi_sense_data_construct(
+ sequence,
+ scsi_io,
+ SCSI_STATUS_CHECK_CONDITION,
+ SCSI_SENSE_ILLEGAL_REQUEST,
+ SCSI_ASC_INVALID_FIELD_IN_CDB,
+ SCSI_ASCQ_INVALID_FIELD_IN_CDB
+ );
+ sequence->state = SATI_SEQUENCE_STATE_FINAL;
+ status = SATI_FAILURE_CHECK_RESPONSE_DATA;
+ }
+ else
+ {
+ //figure out if we support other buffer id's
+ sati_set_data_byte(sequence, scsi_io, 0, 0x09); //offset boundary
+ sati_set_data_byte(sequence, scsi_io, 1, 0x00);
+ sati_set_data_byte(sequence, scsi_io, 2, 0x02); //buffer capacity 0x200
+ sati_set_data_byte(sequence, scsi_io, 3, 0x00);
+ sequence->state = SATI_SEQUENCE_STATE_FINAL;
+ status = SATI_COMPLETE;
+ }
+ break;
+
+ default:
+ //Unspecified sat2v7, returning invalid cdb
+ sati_scsi_sense_data_construct(
+ sequence,
+ scsi_io,
+ SCSI_STATUS_CHECK_CONDITION,
+ SCSI_SENSE_ILLEGAL_REQUEST,
+ SCSI_ASC_INVALID_FIELD_IN_CDB,
+ SCSI_ASCQ_INVALID_FIELD_IN_CDB
+ );
+ sequence->state = SATI_SEQUENCE_STATE_FINAL;
+ status = SATI_FAILURE_CHECK_RESPONSE_DATA;
+ }
+ return status;
+}
+
+/**
+* @brief This method will complete the Read Buffer Translation by copying the
+ ATA response data into the SCSI request DATA buffer.
+* For more information on the parameters passed to this method,
+* please reference sati_translate_command().
+*
+* @return Indicates if the command translation succeeded.
+* @retval SATI_FAILURE_CHECK_RESPONSE_DATA This value is returned if
+* there is a translation failure.
+* @retval SATI_COMPLETE indicates that the translation was supported, occurred without
+* error, and no additional translation is necessary.
+*/
+SATI_STATUS sati_read_buffer_translate_response(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ void * ata_io
+)
+{
+ U8 * register_fis = sati_cb_get_d2h_register_fis_address(ata_io);
+ U8 ata_status = (U8) sati_get_ata_status(register_fis);
+ SATI_STATUS status = SATI_COMPLETE;
+
+ if (ata_status & ATA_STATUS_REG_ERROR_BIT)
+ {
+ sati_scsi_sense_data_construct(
+ sequence,
+ scsi_io,
+ SCSI_STATUS_CHECK_CONDITION,
+ SCSI_SENSE_ABORTED_COMMAND,
+ SCSI_ASC_NO_ADDITIONAL_SENSE,
+ SCSI_ASCQ_NO_ADDITIONAL_SENSE
+ );
+
+ status = SATI_FAILURE_CHECK_RESPONSE_DATA;
+ }
+ else
+ {
+ void * ata_data = sati_cb_get_ata_data_address(ata_io);
+
+ if(ata_data == NULL)
+ {
+ status = SATI_FAILURE;
+ }
+ else
+ {
+ //copy ATA data into SCSI data buffer
+ sati_copy_data(
+ sequence,
+ scsi_io,
+ 0,
+ ata_data,
+ 512
+ );
+ }
+ }
+
+ sequence->state = SATI_SEQUENCE_STATE_FINAL;
+ return status;
+}
+
+
+#endif //!defined(DISABLE_SATI_READ_BUFFER)
diff --git a/sys/dev/isci/scil/sati_read_buffer.h b/sys/dev/isci/scil/sati_read_buffer.h
new file mode 100644
index 0000000..8bcb17b
--- /dev/null
+++ b/sys/dev/isci/scil/sati_read_buffer.h
@@ -0,0 +1,82 @@
+/*-
+ * 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.
+*
+* 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.
+ *
+ * $FreeBSD$
+ */
+/**
+* @file
+* @brief This file contains the method definitions to translate
+* SCSI Read Buffer command based of the SAT spec.
+*/
+
+#ifndef _SATI_READ_BUFFER_H_
+#define _SATI_READ_BUFFER_H_
+
+#include <dev/isci/scil/sati_types.h>
+#include <dev/isci/scil/sati_translator_sequence.h>
+
+#define SATI_READ_BUFFER_MODE_DATA 0x02
+#define SATI_READ_BUFFER_MODE_DESCRIPTOR 0x03
+
+
+SATI_STATUS sati_read_buffer_translate_command(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ void * ata_io
+);
+
+SATI_STATUS sati_read_buffer_translate_response(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ void * ata_io
+);
+
+#endif // _SATI_READ_BUFFER_H_
diff --git a/sys/dev/isci/scil/sati_read_capacity.c b/sys/dev/isci/scil/sati_read_capacity.c
new file mode 100644
index 0000000..6a73374
--- /dev/null
+++ b/sys/dev/isci/scil/sati_read_capacity.c
@@ -0,0 +1,366 @@
+/*-
+ * 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.
+ *
+ * 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 <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/**
+ * @file
+ * @brief This file contains the method implementations required to
+ * translate the SCSI read capacity (10 byte) command.
+ */
+
+#if !defined(DISABLE_SATI_READ_CAPACITY)
+
+#include <dev/isci/scil/sati_read_capacity.h>
+#include <dev/isci/scil/sati_callbacks.h>
+#include <dev/isci/scil/sati_util.h>
+#include <dev/isci/scil/intel_ata.h>
+#include <dev/isci/scil/intel_scsi.h>
+
+/**
+ * @brief This method will translate the read capacity 10 SCSI command into
+ * an ATA IDENTIFY DEVICE command.
+ * For more information on the parameters passed to this method,
+ * please reference sati_translate_command().
+ *
+ * @return Indicate if the command translation succeeded.
+ * @retval SCI_SUCCESS This is returned if the command translation was
+ * successful.
+ * @retval SATI_FAILURE_CHECK_RESPONSE_DATA This value is returned if the
+ * LBA field is not 0, the PMI bit is not 0.
+ */
+SATI_STATUS sati_read_capacity_10_translate_command(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ void * ata_io
+)
+{
+ U8 * cdb = sati_cb_get_cdb_address(scsi_io);
+
+ /**
+ * SAT dictates:
+ * - the LBA field must be 0
+ * - the PMI bit must be 0
+ */
+ if (
+ (
+ (sati_get_cdb_byte(cdb, 2) != 0)
+ || (sati_get_cdb_byte(cdb, 3) != 0)
+ || (sati_get_cdb_byte(cdb, 4) != 0)
+ || (sati_get_cdb_byte(cdb, 5) != 0)
+ )
+ || ((sati_get_cdb_byte(cdb, 8) & SCSI_READ_CAPACITY_PMI_BIT_ENABLE)
+ == 1)
+ )
+ {
+ sati_scsi_sense_data_construct(
+ sequence,
+ scsi_io,
+ SCSI_STATUS_CHECK_CONDITION,
+ SCSI_SENSE_ILLEGAL_REQUEST,
+ SCSI_ASC_INVALID_FIELD_IN_CDB,
+ SCSI_ASCQ_INVALID_FIELD_IN_CDB
+ );
+ return SATI_FAILURE_CHECK_RESPONSE_DATA;
+ }
+
+ // The CDB is properly formed.
+ sequence->allocation_length = SCSI_READ_CAPACITY_10_DATA_LENGTH;
+ sequence->type = SATI_SEQUENCE_READ_CAPACITY_10;
+
+ sati_ata_identify_device_construct(ata_io, sequence);
+ return SATI_SUCCESS;
+}
+
+
+
+/**
+ * @brief This method will translate the read capacity 16 SCSI command into
+ * an ATA IDENTIFY DEVICE command.
+ * For more information on the parameters passed to this method,
+ * please reference sati_translate_command().
+ *
+ * @return Indicate if the command translation succeeded.
+ * @retval SCI_SUCCESS This is returned if the command translation was
+ * successful.
+ * @retval SATI_FAILURE_CHECK_RESPONSE_DATA This value is returned if the
+ * LBA field is not 0, the PMI bit is not 0.
+ */
+SATI_STATUS sati_read_capacity_16_translate_command(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ void * ata_io
+)
+{
+ U8 * cdb = sati_cb_get_cdb_address(scsi_io);
+
+ /**
+ * SAT dictates:
+ * - the LBA field must be 0
+ * - the PMI bit must be 0
+ */
+ if (
+ (
+ (sati_get_cdb_byte(cdb, 2) != 0)
+ || (sati_get_cdb_byte(cdb, 3) != 0)
+ || (sati_get_cdb_byte(cdb, 4) != 0)
+ || (sati_get_cdb_byte(cdb, 5) != 0)
+ || (sati_get_cdb_byte(cdb, 6) != 0)
+ || (sati_get_cdb_byte(cdb, 7) != 0)
+ || (sati_get_cdb_byte(cdb, 8) != 0)
+ || (sati_get_cdb_byte(cdb, 9) != 0)
+ )
+ || ((sati_get_cdb_byte(cdb, 14) & SCSI_READ_CAPACITY_PMI_BIT_ENABLE)
+ == 1)
+ )
+ {
+ sati_scsi_sense_data_construct(
+ sequence,
+ scsi_io,
+ SCSI_STATUS_CHECK_CONDITION,
+ SCSI_SENSE_ILLEGAL_REQUEST,
+ SCSI_ASC_INVALID_FIELD_IN_CDB,
+ SCSI_ASCQ_INVALID_FIELD_IN_CDB
+ );
+ return SATI_FAILURE_CHECK_RESPONSE_DATA;
+ }
+
+ // The CDB is properly formed.
+ sequence->allocation_length = (sati_get_cdb_byte(cdb, 10) << 24) |
+ (sati_get_cdb_byte(cdb, 11) << 16) |
+ (sati_get_cdb_byte(cdb, 12) << 8) |
+ (sati_get_cdb_byte(cdb, 13));
+
+ sequence->type = SATI_SEQUENCE_READ_CAPACITY_16;
+
+ sati_ata_identify_device_construct(ata_io, sequence);
+ return SATI_SUCCESS;
+}
+
+/**
+ * @brief This method will translate the ATA Identify Device data into
+ * SCSI read capacity 10 data.
+ * For more information on the parameters passed to this method,
+ * please reference sati_translate_data().
+ *
+ * @return none
+ */
+void sati_read_capacity_10_translate_data(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * ata_input_data,
+ void * scsi_io
+)
+{
+ U32 lba_low = 0;
+ U32 lba_high = 0;
+ U32 sector_size = 0;
+
+ // Extract the sector information (sector size, logical blocks) from
+ // the retrieved ATA identify device data.
+ sati_ata_identify_device_get_sector_info(
+ (ATA_IDENTIFY_DEVICE_DATA_T*)ata_input_data,
+ &lba_high,
+ &lba_low,
+ &sector_size
+ );
+
+ // SATA drives report a value that is one LBA larger than the last LBA.
+ // SCSI wants the last LBA. Make the correction here. lba_low is
+ // always decremented since it is an unsigned long the value 0 will
+ // wrap to 0xFFFFFFFF.
+ if ((lba_low == 0) && (lba_high == 0))
+ lba_high -= 1;
+ lba_low -= 1;
+
+ if(lba_high != 0)
+ {
+ sati_set_data_byte(sequence, scsi_io, 0, 0xFF);
+ sati_set_data_byte(sequence, scsi_io, 1, 0xFF);
+ sati_set_data_byte(sequence, scsi_io, 2, 0xFF);
+ sati_set_data_byte(sequence, scsi_io, 3, 0xFF);
+ }
+ else
+ {
+ // Build CDB for Read Capacity 10
+ // Fill in the Logical Block Address bytes.
+ sati_set_data_byte(sequence, scsi_io, 0, (U8)((lba_low >> 24) & 0xFF));
+ sati_set_data_byte(sequence, scsi_io, 1, (U8)((lba_low >> 16) & 0xFF));
+ sati_set_data_byte(sequence, scsi_io, 2, (U8)((lba_low >> 8) & 0xFF));
+ sati_set_data_byte(sequence, scsi_io, 3, (U8)(lba_low & 0xFF));
+ }
+ // Fill in the sector size field.
+ sati_set_data_byte(sequence, scsi_io, 4, (U8)((sector_size >> 24) & 0xFF));
+ sati_set_data_byte(sequence, scsi_io, 5, (U8)((sector_size >> 16) & 0xFF));
+ sati_set_data_byte(sequence, scsi_io, 6, (U8)((sector_size >> 8) & 0xFF));
+ sati_set_data_byte(sequence, scsi_io, 7, (U8)(sector_size & 0xFF));
+}
+
+/**
+ * @brief This method will translate the ATA Identify Device data into
+ * SCSI read capacity 16 data.
+ * For more information on the parameters passed to this method,
+ * please reference sati_translate_data().
+ *
+ * @return none
+ */
+void sati_read_capacity_16_translate_data(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * ata_input_data,
+ void * scsi_io
+)
+{
+ U32 lba_low = 0;
+ U32 lba_high = 0;
+ U32 sector_size = 0;
+ ATA_IDENTIFY_DEVICE_DATA_T * identify_device_data;
+ U16 physical_per_logical_enable_bit = 0;
+ U8 physical_per_logical_sector_exponent = 0;
+ U16 physical_per_logical_sector = 0;
+ U16 logical_sector_alignment = 0;
+ U16 scsi_logical_sector_alignment = 0;
+ U8 byte14 = 0;
+
+ //A number of data fields need to be extracted from ATA identify device data
+ identify_device_data = (ATA_IDENTIFY_DEVICE_DATA_T*)ata_input_data;
+
+ // Extract the sector information (sector size, logical blocks) from
+ // the retrieved ATA identify device data.
+ sati_ata_identify_device_get_sector_info(
+ (ATA_IDENTIFY_DEVICE_DATA_T*)ata_input_data,
+ &lba_high,
+ &lba_low,
+ &sector_size
+ );
+
+ // SATA drives report a value that is one LBA larger than the last LBA.
+ // SCSI wants the last LBA. Make the correction here. lba_low is
+ // always decremented since it is an unsigned long the value 0 will
+ // wrap to 0xFFFFFFFF.
+ if ((lba_low == 0) && (lba_high == 0))
+ lba_high -= 1;
+ lba_low -= 1;
+
+ // Build the CDB for Read Capacity 16
+ // Fill in the Logical Block Address bytes.
+ sati_set_data_byte(sequence, scsi_io, 0, (U8)((lba_high >> 24) & 0xFF));
+ sati_set_data_byte(sequence, scsi_io, 1, (U8)((lba_high >> 16) & 0xFF));
+ sati_set_data_byte(sequence, scsi_io, 2, (U8)((lba_high >> 8) & 0xFF));
+ sati_set_data_byte(sequence, scsi_io, 3, (U8)(lba_high & 0xFF));
+
+ sati_set_data_byte(sequence, scsi_io, 4, (U8)((lba_low >> 24) & 0xFF));
+ sati_set_data_byte(sequence, scsi_io, 5, (U8)((lba_low >> 16) & 0xFF));
+ sati_set_data_byte(sequence, scsi_io, 6, (U8)((lba_low >> 8) & 0xFF));
+ sati_set_data_byte(sequence, scsi_io, 7, (U8)(lba_low & 0xFF));
+
+ //Fill in the sector size field.
+ sati_set_data_byte(sequence, scsi_io, 8, (U8)((sector_size >> 24) & 0xFF));
+ sati_set_data_byte(sequence, scsi_io, 9, (U8)((sector_size >> 16) & 0xFF));
+ sati_set_data_byte(sequence, scsi_io, 10, (U8)((sector_size >> 8) & 0xFF));
+ sati_set_data_byte(sequence, scsi_io, 11, (U8)(sector_size & 0xFF));
+
+ //Check Bit 13 of ATA_IDENTIFY_DEVICE_DATA physical_logical_sector_info
+ //(Word 106) is enabled
+ physical_per_logical_enable_bit = (identify_device_data->physical_logical_sector_info
+ & ATA_IDENTIFY_LOGICAL_SECTOR_PER_PHYSICAL_SECTOR_ENABLE);
+
+ //Extract the Physical per logical sector exponent field and calculate
+ //Physical per logical sector value
+ physical_per_logical_sector_exponent = (U8) (identify_device_data->physical_logical_sector_info
+ & ATA_IDENTIFY_LOGICAL_SECTOR_PER_PHYSICAL_SECTOR_MASK);
+ physical_per_logical_sector = 1 << (physical_per_logical_sector_exponent);
+
+ //If the data is valid, fill in the logical blocks per physical block exponent field.
+ //Else set logical blocks per physical block exponent to 1
+ if (physical_per_logical_enable_bit != 0)
+ sati_set_data_byte(
+ sequence,
+ scsi_io,
+ 13,
+ (U8)(physical_per_logical_sector_exponent & 0xFF)
+ );
+ else
+ sati_set_data_byte(sequence, scsi_io, 13, 0);
+
+ //Fill in the lowest aligned logical block address field.
+ logical_sector_alignment = identify_device_data->logical_sector_alignment;
+ if (logical_sector_alignment == 0)
+ scsi_logical_sector_alignment = 0;
+ else
+ scsi_logical_sector_alignment = (physical_per_logical_sector - logical_sector_alignment)
+ % physical_per_logical_sector;
+
+ //Follow SAT for reporting tprz and tpe
+ if ((sequence->device->capabilities & SATI_DEVICE_CAP_DSM_TRIM_SUPPORT) &&
+ (sequence->device->capabilities & SATI_DEVICE_CAP_DETERMINISTIC_READ_AFTER_TRIM))
+ {
+ // tpe
+ byte14 |= 0x80;
+ // tprz
+ if (sequence->device->capabilities & SATI_DEVICE_CAP_READ_ZERO_AFTER_TRIM)
+ byte14 |= 0x40;
+ }
+ sati_set_data_byte(
+ sequence,
+ scsi_io,
+ 14,
+ (U8)(((scsi_logical_sector_alignment >>8) & 0x3F) | byte14));
+
+ sati_set_data_byte(
+ sequence,
+ scsi_io,
+ 15,
+ (U8)(scsi_logical_sector_alignment & 0xFF));
+}
+
+#endif // !defined(DISABLE_SATI_READ_CAPACITY)
+
diff --git a/sys/dev/isci/scil/sati_read_capacity.h b/sys/dev/isci/scil/sati_read_capacity.h
new file mode 100644
index 0000000..41660de
--- /dev/null
+++ b/sys/dev/isci/scil/sati_read_capacity.h
@@ -0,0 +1,91 @@
+/*-
+ * 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.
+ *
+ * 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.
+ *
+ * $FreeBSD$
+ */
+#ifndef _SATI_READ_CAPACITY_H_
+#define _SATI_READ_CAPACITY_H_
+
+/**
+ * @file
+ * @brief This file contains the method interfaces required to
+ * translate the SCSI read capacity (10 byte) command as well as
+ * translate data for both 10 byte and 16 byte read capacity flavors.
+ */
+
+#include <dev/isci/scil/sati_types.h>
+#include <dev/isci/scil/sati_translator_sequence.h>
+
+SATI_STATUS sati_read_capacity_10_translate_command(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ void * ata_io
+);
+
+SATI_STATUS sati_read_capacity_16_translate_command(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ void * ata_io
+);
+
+void sati_read_capacity_10_translate_data(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * ata_input_data,
+ void * scsi_io
+);
+
+void sati_read_capacity_16_translate_data(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * ata_input_data,
+ void * scsi_io
+);
+
+#endif // _SATI_READ_CAPACITY_H_
diff --git a/sys/dev/isci/scil/sati_reassign_blocks.c b/sys/dev/isci/scil/sati_reassign_blocks.c
new file mode 100644
index 0000000..ebe16b7
--- /dev/null
+++ b/sys/dev/isci/scil/sati_reassign_blocks.c
@@ -0,0 +1,622 @@
+/*-
+ * 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.
+ *
+ * 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 <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/**
+ * @file
+ * @brief This file contains the method implementations required to
+ * translate the SCSI reassign blocks command.
+ */
+
+#if !defined(DISABLE_SATI_REASSIGN_BLOCKS)
+
+#include <dev/isci/scil/sati_reassign_blocks.h>
+#include <dev/isci/scil/sati_callbacks.h>
+#include <dev/isci/scil/sati_move.h>
+#include <dev/isci/scil/sati_write.h>
+#include <dev/isci/scil/sati_translator_sequence.h>
+#include <dev/isci/scil/sati_util.h>
+#include <dev/isci/scil/intel_scsi.h>
+
+
+//******************************************************************************
+//* P R I V A T E M E T H O D S
+//******************************************************************************
+// static SATI_REASSIGN_BLOCKS_PROCESSING_STATE_T reassign_blocks_processing_state;
+
+/**
+ * @brief This method copies short 24bits LBA bytes to the command register
+ * @return Indicate if the method was successfully completed.
+ * @retval SATI_SUCCESS This is returned in all other cases.
+ */
+static
+void set_current_lba(U8 * lba, void * ata_io)
+{
+ U8 * register_fis = sati_cb_get_h2d_register_fis_address(ata_io);
+
+ sati_set_ata_lba_low(register_fis, lba[0]);
+ sati_set_ata_lba_mid(register_fis, lba[1]);
+ sati_set_ata_lba_high(register_fis, lba[2]);
+ sati_set_ata_device_head(register_fis, ATA_DEV_HEAD_REG_LBA_MODE_ENABLE | (lba[3] & 0x0F));
+
+
+}
+
+/**
+ * @brief This method copies short 48bits LBA bytes to the command register
+ * @return Indicate if the method was successfully completed.
+ * @retval SATI_SUCCESS This is returned in all other cases.
+ */
+static
+void set_current_long_lba(U8 * lba, void * ata_io)
+{
+ U8 * register_fis = sati_cb_get_h2d_register_fis_address(ata_io);
+
+ sati_set_ata_lba_low(register_fis, lba[0]);
+ sati_set_ata_lba_mid(register_fis, lba[1]);
+ sati_set_ata_lba_high(register_fis, lba[2]);
+ sati_set_ata_lba_low_exp(register_fis, lba[3]);
+ sati_set_ata_lba_mid_exp(register_fis, lba[4]);
+ sati_set_ata_lba_high_exp(register_fis, lba[5]);
+}
+
+/**
+ * @brief This method performs the SCSI VERIFY command translation
+ * functionality.
+ * This includes:
+ * - setting the command register
+ * - setting the device head register
+ * - filling in fields in the SATI_TRANSLATOR_SEQUENCE object.
+ * For more information on the parameters passed to this method,
+ * please reference sati_translate_command().
+ *
+ * @return Indicate if the method was successfully completed.
+ * @retval SATI_SUCCESS This is returned in all other cases.
+ */
+static
+SATI_STATUS sati_reassign_blocks_verify_command(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ void * ata_io
+)
+{
+ U8 * register_fis = sati_cb_get_h2d_register_fis_address(ata_io);
+
+ sati_ata_non_data_command(ata_io, sequence);
+
+ // Ensure the device supports the 48 bit feature set.
+ if (sequence->device->capabilities & SATI_DEVICE_CAP_48BIT_ENABLE)
+ sati_set_ata_command(register_fis, ATA_READ_VERIFY_SECTORS_EXT);
+ else
+ sati_set_ata_command(register_fis, ATA_READ_VERIFY_SECTORS);
+
+ return SATI_SUCCESS;
+}
+
+/**
+ * @brief This method performs the SCSI Write sector command translation
+ * functionality.
+ * This includes:
+ * - setting the command register
+ * - setting the device head register
+ * - filling in fields in the SATI_TRANSLATOR_SEQUENCE object.
+ * For more information on the parameters passed to this method,
+ * please reference sati_translate_command().
+ *
+ * @return Indicate if the method was successfully completed.
+ * @retval SATI_SUCCESS This is returned in all other cases.
+ */
+static
+SATI_STATUS sati_reassign_blocks_write_command(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ void * ata_io
+)
+{
+ U8 * register_fis = sati_cb_get_h2d_register_fis_address(ata_io);
+
+ sati_ata_non_data_command(ata_io, sequence);
+ sequence->data_direction = SATI_DATA_DIRECTION_OUT;
+
+// sati_set_ata_sector_count(register_fis, 1);
+// status=sati_move_set_sector_count(sequence,scsi_io,ata_io,1,0);
+
+ // Ensure the device supports the 48 bit feature set.
+ if (sequence->device->capabilities & SATI_DEVICE_CAP_48BIT_ENABLE)
+ sati_set_ata_command(register_fis, ATA_WRITE_DMA_EXT);
+ else
+ sati_set_ata_command(register_fis, ATA_WRITE_DMA);
+
+ return SATI_SUCCESS; //sati_move_set_sector_count(sequence,scsi_io,ata_io,1,0);
+}
+
+/**
+ * @brief This method performs the retrieving of parameter LBA praparation and setting
+ * processing flags before/after calling SCSI Verify sector command.
+ * @return Indicate if the method was successfully completed.
+ * @retval SATI_SUCCESS This is returned in all other cases.
+ */
+static
+SATI_STATUS sati_reassign_blocks_verify_condition(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ void * ata_io
+)
+{
+ U8 current_lba_bytes[8] = {0,0,0,0,0,0,0,0};
+ U32 lba_offset;
+ U8 page_size;
+ U32 index;
+ SATI_STATUS status = SATI_FAILURE_CHECK_RESPONSE_DATA;
+
+ lba_offset = sequence->command_specific_data.reassign_blocks_process_state.lba_offset;
+ page_size = sequence->command_specific_data.reassign_blocks_process_state.lba_size;
+
+ for(index = 0; index < page_size; index++)
+ {
+ sati_get_data_byte(sequence, scsi_io, lba_offset+index, &current_lba_bytes[index]);
+ }
+
+ if (page_size == 4)
+ set_current_lba(current_lba_bytes, ata_io);
+ else
+ set_current_long_lba(current_lba_bytes, ata_io);
+
+ status = sati_reassign_blocks_verify_command(sequence, scsi_io, ata_io);
+ sequence->command_specific_data.reassign_blocks_process_state.ata_command_sent_for_current_lba++;
+ sequence->command_specific_data.reassign_blocks_process_state.ata_command_status = SATI_REASSIGN_BLOCKS_READY_TO_SEND;
+ return status;
+}
+
+/**
+ * @brief This method performs the retrieving of parameter LBA praparation and setting
+ * processing flags before/after calling SCSI Write sector command.
+ * @return Indicate if the method was successfully completed.
+ * @retval SATI_SUCCESS This is returned in all other cases.
+ */
+static
+SATI_STATUS sati_reassign_blocks_write_condition(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ void * ata_io
+)
+{
+ U8 current_lba_bytes[8] = {0,0,0,0,0,0,0,0};
+ U32 lba_offset;
+ U8 page_size;
+ U32 index;
+ SATI_STATUS status = SATI_FAILURE_CHECK_RESPONSE_DATA;
+
+ lba_offset = sequence->command_specific_data.reassign_blocks_process_state.lba_offset;
+ page_size = sequence->command_specific_data.reassign_blocks_process_state.lba_size;
+
+ for(index = 0; index < page_size; index++)
+ {
+ sati_get_data_byte(sequence, scsi_io, lba_offset+index, &current_lba_bytes[index]);
+ }
+
+ if (page_size == 4)
+ set_current_lba(current_lba_bytes, ata_io);
+ else
+ set_current_long_lba(current_lba_bytes, ata_io);
+
+ status = sati_reassign_blocks_write_command(sequence, scsi_io, ata_io);
+ sequence->command_specific_data.reassign_blocks_process_state.ata_command_sent_for_current_lba++;
+ sequence->command_specific_data.reassign_blocks_process_state.ata_command_status = SATI_REASSIGN_BLOCKS_READY_TO_SEND;
+ return status ;
+}
+
+
+/**
+ * @brief This method will perform the pre-processing of Reassign Blocks command and parameter.
+ */
+static
+void sati_reassign_blocks_initial_processing(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ void * ata_io
+)
+{
+ U32 index;
+ U8 long_lba_bit;
+ U8 long_list_bit;
+ U8 lba_offset;
+ U8 page_size;
+ U32 data_transfer_length;
+ U8 header_bytes[4]={0,0,0,0};
+
+ U8 * cdb = sati_cb_get_cdb_address(scsi_io);
+
+ //A long LBA (LONGLBA) bit set to zero specifies that the REASSIGN BLOCKS defective LBA list contains four-byte LBAs.
+ //A LONGLBA bit set to one specifies that the REASSIGN BLOCKS defective LBA list contains eight-byte LBAs.
+ if ((sati_get_cdb_byte(cdb, 1) & SCSI_REASSIGN_BLOCKS_LONGLBA_BIT) == 0)
+ {
+ long_lba_bit=0;
+ page_size = 4; //beginning of lba list
+ }
+ else
+ {
+ long_lba_bit=1;
+ page_size = 8;
+ }
+
+ //The long list (LONGLIST) bit specifies which parameter list header
+ if ((sati_get_cdb_byte(cdb, 1) & SCSI_REASSIGN_BLOCKS_LONGLIST_BIT) == 0)
+ {
+ long_list_bit=0;
+ }
+ else
+ {
+ long_list_bit=1;
+ }
+
+ sequence->allocation_length = 4; //Pre-set allocation_length so that the header can be retrieved
+
+ //Get 4 bytes for headers (byte 2 & byte 3 for short header; long header all 4 bytes)
+ for(index = 0; index < 4; index++)
+ {
+ sati_get_data_byte(sequence, scsi_io, index, &header_bytes[index]);
+ }
+
+ lba_offset = 4; //beginning of lba list
+
+ if (long_list_bit==0)
+ {
+ //Header byte 2 and 3 is the parameter list length
+ data_transfer_length = (header_bytes[2]<<8) + header_bytes[3] + lba_offset;
+ }
+ else
+ {
+ //Header byte 0, 1, 2 and 3 contain the parameter list length
+ data_transfer_length = (header_bytes[0]<<24) + (header_bytes[1]<<16) +
+ (header_bytes[2]<<8) + header_bytes[3] + lba_offset;
+ }
+
+ sequence->allocation_length = data_transfer_length;
+
+ //Initialized the global processing state
+ sequence->command_specific_data.reassign_blocks_process_state.lba_size = page_size;
+ sequence->command_specific_data.reassign_blocks_process_state.lba_offset = lba_offset;
+ sequence->command_specific_data.reassign_blocks_process_state.ata_command_sent_for_current_lba = 0;
+ sequence->command_specific_data.reassign_blocks_process_state.block_lists_size = data_transfer_length - lba_offset;
+ sequence->command_specific_data.reassign_blocks_process_state.size_of_data_processed = 0;
+ sequence->command_specific_data.reassign_blocks_process_state.current_lba_processed = FALSE;
+ sequence->command_specific_data.reassign_blocks_process_state.ata_command_status = SATI_REASSIGN_BLOCKS_COMMAND_FAIL;
+}
+
+/**
+ * @brief This method will get the data size of not yet processed data.
+ *
+ * @param[in] lba_process_state This parameter points to the processing state fields
+ * of current block lba.
+ *
+ * @return This method returns the sizeof not yet processed data.
+ */
+static
+U32 sati_reassign_blocks_unprocessed_data_size(
+ SATI_REASSIGN_BLOCKS_PROCESSING_STATE_T * lba_process_state
+)
+{
+ U32 unprocessed_data_size;
+
+ if(lba_process_state->block_lists_size >= lba_process_state->size_of_data_processed)
+ {
+ unprocessed_data_size = lba_process_state->block_lists_size -
+ lba_process_state->size_of_data_processed;
+ }
+ else
+ {
+ unprocessed_data_size = 0;
+ }
+
+ return unprocessed_data_size;
+}
+
+
+/**
+ * @brief This method will check verify the sector and issue multiple ATA set feature commands to complete the translation.
+ *
+ * @param[in] reassign_blocks_process_state This parameter points to the processing state fields
+ * of current lba block.
+ *
+ *
+ * @return Indicate if the translation was successful.
+ * @retval SATI_SUCCESS
+ * @retval SATI_COMPLETE
+ * @retval SATI_FAILURE_CHECK_RESPONSE_DATA
+ */
+static
+SATI_STATUS sati_reassign_blocks_process_each_lba(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ void * ata_io
+ )
+{
+ SATI_STATUS status = SATI_FAILURE_CHECK_RESPONSE_DATA;
+ SATI_REASSIGN_BLOCKS_PROCESSING_STATE_T * reassign_blocks_process_state;
+
+ reassign_blocks_process_state = &sequence->command_specific_data.reassign_blocks_process_state;
+
+ if((reassign_blocks_process_state->ata_command_sent_for_current_lba == 0)&&
+ (reassign_blocks_process_state->ata_command_status == SATI_REASSIGN_BLOCKS_COMMAND_FAIL))
+ {
+ reassign_blocks_process_state->size_of_data_processed += reassign_blocks_process_state->lba_size;
+ status = sati_reassign_blocks_verify_condition(sequence, scsi_io, ata_io);
+ }
+ else if((reassign_blocks_process_state->ata_command_sent_for_current_lba == 0)&&
+ (reassign_blocks_process_state->ata_command_status == SATI_REASSIGN_BLOCKS_COMMAND_SUCCESS))
+ {
+ // point to next lba
+ reassign_blocks_process_state->size_of_data_processed += reassign_blocks_process_state->lba_size;
+ reassign_blocks_process_state->lba_offset += reassign_blocks_process_state->lba_size;
+ status = sati_reassign_blocks_verify_condition(sequence, scsi_io, ata_io);
+ }
+ else if((reassign_blocks_process_state->ata_command_sent_for_current_lba == 1)&&
+ (reassign_blocks_process_state->ata_command_status == SATI_REASSIGN_BLOCKS_COMMAND_FAIL))
+ {
+ reassign_blocks_process_state->size_of_data_processed += reassign_blocks_process_state->lba_size;
+ status = sati_reassign_blocks_write_condition(sequence, scsi_io, ata_io);
+ }
+ else if((reassign_blocks_process_state->ata_command_sent_for_current_lba == 2) &&
+ (reassign_blocks_process_state->ata_command_status == SATI_REASSIGN_BLOCKS_COMMAND_SUCCESS))
+ {
+ reassign_blocks_process_state->size_of_data_processed += reassign_blocks_process_state->lba_size;
+ status = sati_reassign_blocks_verify_condition(sequence, scsi_io, ata_io);
+ }
+ else //commands sent is 2; SATI_REASSIGN_BLOCKS_COMMAND_FAIL
+ {
+ status = SATI_FAILURE_CHECK_RESPONSE_DATA;
+ }
+
+ return status;
+}
+
+/**
+ * @brief This method will process the each lba.
+ *
+ * @param[in] reassign_blocks_process_state This parameter points to the processing state fields
+ * of current lba.
+ *
+ * @return Indicate if the translation was successful.
+ * @retval SATI_SUCCESS
+ * @retval SATI_COMPLETE
+ * @retval SATI_FAILURE_CHECK_RESPONSE_DATA
+ */
+static
+SATI_STATUS sati_reassign_blocks_process(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ void * ata_io
+)
+{
+ SATI_STATUS status = SATI_FAILURE_CHECK_RESPONSE_DATA;
+
+ U32 page_size = 0; // in bytes
+ U32 size_of_data_to_be_processed;
+ U32 lba_offset;
+ SATI_REASSIGN_BLOCKS_PROCESSING_STATE_T * reassign_blocks_process_state;
+
+ reassign_blocks_process_state = &sequence->command_specific_data.reassign_blocks_process_state;
+
+ lba_offset = reassign_blocks_process_state->lba_offset;
+ page_size = reassign_blocks_process_state->lba_size;
+
+
+ if(sati_reassign_blocks_unprocessed_data_size(reassign_blocks_process_state) < page_size)
+ {
+ return status;
+ }
+
+ // Any more lba blocks? If not, done.
+ if(reassign_blocks_process_state->block_lists_size ==
+ reassign_blocks_process_state->size_of_data_processed)
+ {
+ sequence->state = SATI_SEQUENCE_STATE_FINAL;
+ status = SATI_COMPLETE;
+ }
+ //start processing next lba
+ else
+ {
+ size_of_data_to_be_processed = reassign_blocks_process_state->block_lists_size
+ - reassign_blocks_process_state->size_of_data_processed;
+
+ status = sati_reassign_blocks_process_each_lba(sequence, scsi_io, ata_io);
+
+ }
+
+ return status;
+}
+
+//******************************************************************************
+//* P U B L I C M E T H O D S
+//******************************************************************************
+
+/**
+ * @brief This method will translate the SCSI Reassign Blocks command
+ * into corresponding ATA commands. Depending upon the capabilities
+ * supported by the target different ATA commands can be selected.
+ * Additionally, in some cases more than a single ATA command may
+ * be required.
+ *
+ * @return Indicate if the command translation succeeded.
+ * @retval SCI_SUCCESS This is returned if the command translation was
+ * successful.
+ * @retval SCI_COMPLETE This is returned if the command translation was
+ * successful and no ATA commands need to be set.
+ * @retval SATI_FAILURE_CHECK_RESPONSE_DATA This value is returned if
+ * sense data has been created as a result of something specified
+ * in the parameter data fields.
+ */
+SATI_STATUS sati_reassign_blocks_translate_command(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ void * ata_io
+)
+{
+ SATI_STATUS status = SATI_FAILURE_CHECK_RESPONSE_DATA;
+ SATI_REASSIGN_BLOCKS_PROCESSING_STATE_T * reassign_blocks_process_state;
+
+ reassign_blocks_process_state = &sequence->command_specific_data.reassign_blocks_process_state;
+
+ sequence->type = SATI_SEQUENCE_REASSIGN_BLOCKS;
+
+ //Initial processing if
+ if ( sequence->state != SATI_SEQUENCE_STATE_INCOMPLETE )
+ {
+ sati_reassign_blocks_initial_processing(
+ sequence,
+ scsi_io,
+ ata_io
+ );
+ }
+
+ // start processing current lba
+ if(reassign_blocks_process_state->current_lba_processed)
+ {
+ reassign_blocks_process_state->ata_command_sent_for_current_lba = 0;
+ reassign_blocks_process_state->current_lba_processed = FALSE;
+ }
+
+ status = sati_reassign_blocks_process(sequence, scsi_io, ata_io);
+
+ if(reassign_blocks_process_state->block_lists_size ==
+ reassign_blocks_process_state->size_of_data_processed)
+ {
+ // Done this lba
+ sequence->state = SATI_SEQUENCE_STATE_FINAL;
+ }
+ else
+ {
+ sequence->state = SATI_SEQUENCE_STATE_INCOMPLETE;
+ }
+
+ if(status == SATI_FAILURE_CHECK_RESPONSE_DATA)
+ {
+ sequence->state = SATI_SEQUENCE_STATE_FINAL;
+ sati_scsi_sense_data_construct(
+ sequence,
+ scsi_io,
+ SCSI_STATUS_CHECK_CONDITION,
+ SCSI_SENSE_MEDIUM_ERROR,
+ SCSI_ASC_UNRECOVERED_READ_ERROR,
+ SCSI_ASCQ_UNRECOVERED_READ_ERROR_AUTO_REALLOCATE_FAIL
+ );
+ }
+
+ return status;
+}
+
+/**
+ * @brief This method will translate the ATA command register FIS
+ * response into an appropriate SCSI response for Reassign Blocks
+ * For more information on the parameters passed to this method,
+ * please reference sati_translate_response().
+ *
+ * @return Indicate if the response translation succeeded.
+ * @retval SCI_SUCCESS This is returned if the data translation was
+ * successful.
+ */
+SATI_STATUS sati_reassign_blocks_translate_response(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ void * ata_io
+)
+{
+ U8 * register_fis = sati_cb_get_d2h_register_fis_address(ata_io);
+ SATI_REASSIGN_BLOCKS_PROCESSING_STATE_T * reassign_blocks_process_state;
+
+ reassign_blocks_process_state = &sequence->command_specific_data.reassign_blocks_process_state;
+
+ if (sati_get_ata_status(register_fis) & ATA_STATUS_REG_ERROR_BIT)
+ {
+ reassign_blocks_process_state->ata_command_status = SATI_REASSIGN_BLOCKS_COMMAND_FAIL;
+
+ //Checking for the number of ATA commands attempted on current LBA, stop
+ //the seaquence after 2 commands have returned errors.
+ if(reassign_blocks_process_state->ata_command_sent_for_current_lba < 2)
+ {
+ sequence->state = SATI_SEQUENCE_STATE_INCOMPLETE;
+ reassign_blocks_process_state->size_of_data_processed -= reassign_blocks_process_state->lba_size;
+ return SATI_SEQUENCE_INCOMPLETE;
+ }
+ else
+ {
+ sati_scsi_sense_data_construct(
+ sequence,
+ scsi_io,
+ SCSI_STATUS_CHECK_CONDITION,
+ SCSI_SENSE_MEDIUM_ERROR,
+ SCSI_ASC_UNRECOVERED_READ_ERROR,
+ SCSI_ASCQ_UNRECOVERED_READ_ERROR_AUTO_REALLOCATE_FAIL
+ );
+ }
+
+ return SATI_FAILURE_CHECK_RESPONSE_DATA;
+ }
+ else
+ {
+ reassign_blocks_process_state->ata_command_status = SATI_REASSIGN_BLOCKS_COMMAND_SUCCESS;
+ if (reassign_blocks_process_state->ata_command_sent_for_current_lba != 2)
+ reassign_blocks_process_state->current_lba_processed = TRUE;
+
+ if (sequence->state == SATI_SEQUENCE_STATE_INCOMPLETE)
+ {
+ return SATI_SEQUENCE_INCOMPLETE;
+ }
+ }
+ return SATI_COMPLETE;
+}
+
+#endif // !defined(DISABLE_SATI_REASSIGN_BLOCKS)
+
diff --git a/sys/dev/isci/scil/sati_reassign_blocks.h b/sys/dev/isci/scil/sati_reassign_blocks.h
new file mode 100644
index 0000000..7531fd8
--- /dev/null
+++ b/sys/dev/isci/scil/sati_reassign_blocks.h
@@ -0,0 +1,80 @@
+/*-
+ * 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.
+ *
+ * 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.
+ *
+ * $FreeBSD$
+ */
+#ifndef _SATI_REASSIGN_BLOCKS_H_
+#define _SATI_REASSIGN_BLOCKS_H_
+
+/**
+ * @file
+ * @brief This file contains the method implementations required to
+ * translate the SCSI reassign blocks command.
+ */
+
+#include <dev/isci/scil/sati_types.h>
+#include <dev/isci/scil/sati_translator_sequence.h>
+
+
+
+SATI_STATUS sati_reassign_blocks_translate_command(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ void * ata_io
+);
+
+SATI_STATUS sati_reassign_blocks_translate_response(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ void * ata_io
+);
+
+#endif // _SATI_REASSIGN_BLOCKS_H_
diff --git a/sys/dev/isci/scil/sati_report_luns.c b/sys/dev/isci/scil/sati_report_luns.c
new file mode 100644
index 0000000..6aaad4d
--- /dev/null
+++ b/sys/dev/isci/scil/sati_report_luns.c
@@ -0,0 +1,124 @@
+/*-
+ * 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.
+ *
+ * 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 <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/**
+ * @file
+ * @brief This file contains the method implementations required to
+ * translate the SCSI REPORT LUNS command.
+ */
+
+#if !defined(DISABLE_SATI_REPORT_LUNS)
+
+#include <dev/isci/scil/sati_report_luns.h>
+#include <dev/isci/scil/sati_callbacks.h>
+#include <dev/isci/scil/sati_util.h>
+#include <dev/isci/scil/intel_ata.h>
+#include <dev/isci/scil/intel_scsi.h>
+
+/**
+ * @brief This method will translate the REPORT LUN SCSI command. This
+ * command is immediately completed, since there is no applicable
+ * ATA/ATAPI command. The data payload is written and SATI_COMPLETE
+ * is always returned.
+ * For more information on the parameters passed to this method,
+ * please reference sati_translate_command().
+ *
+ * @return This method always indicates the translation is complete.
+ * @retval SATI_COMPLETE This value is always returned.
+ */
+SATI_STATUS sati_report_luns_translate_command(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ void * ata_io
+)
+{
+ U8 * cdb = sati_cb_get_cdb_address(scsi_io);
+
+ // Set the data length based on the allocation length field in the CDB.
+ sequence->allocation_length = (sati_get_cdb_byte(cdb, 6) << 24) |
+ (sati_get_cdb_byte(cdb, 7) << 16) |
+ (sati_get_cdb_byte(cdb, 8) << 8) |
+ (sati_get_cdb_byte(cdb, 9));
+
+ // The first 4 bytes indicate the length of the LUN list. Each
+ // LUN entry is 8 bytes. There is only ever LUN 0 for ATA/ATAPI
+ // devices. The value reported is: n-7, where n is the last byte
+ // offset (i.e. 15) in the REPORT LUN data.
+ sati_set_data_byte(sequence, scsi_io, 0, 0);
+ sati_set_data_byte(sequence, scsi_io, 1, 0);
+ sati_set_data_byte(sequence, scsi_io, 2, 0);
+ sati_set_data_byte(sequence, scsi_io, 3, 8);
+
+ // Bytes 4-7 are reserved.
+ sati_set_data_byte(sequence, scsi_io, 4, 0);
+ sati_set_data_byte(sequence, scsi_io, 5, 0);
+ sati_set_data_byte(sequence, scsi_io, 6, 0);
+ sati_set_data_byte(sequence, scsi_io, 7, 0);
+
+ // Add in our single LUN of zero.
+ sati_set_data_byte(sequence, scsi_io, 8, 0);
+ sati_set_data_byte(sequence, scsi_io, 9, 0);
+ sati_set_data_byte(sequence, scsi_io, 10, 0);
+ sati_set_data_byte(sequence, scsi_io, 11, 0);
+ sati_set_data_byte(sequence, scsi_io, 12, 0);
+ sati_set_data_byte(sequence, scsi_io, 13, 0);
+ sati_set_data_byte(sequence, scsi_io, 14, 0);
+ sati_set_data_byte(sequence, scsi_io, 15, 0);
+
+ return SATI_COMPLETE;
+}
+
+#endif // !defined(DISABLE_SATI_REPORT_LUNS)
+
diff --git a/sys/dev/isci/scil/sati_report_luns.h b/sys/dev/isci/scil/sati_report_luns.h
new file mode 100644
index 0000000..4aef3a4
--- /dev/null
+++ b/sys/dev/isci/scil/sati_report_luns.h
@@ -0,0 +1,75 @@
+/*-
+ * 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.
+ *
+ * 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.
+ *
+ * $FreeBSD$
+ */
+#ifndef _SATI_REPORT_LUNS_H_
+#define _SATI_REPORT_LUNS_H_
+
+/**
+ * @file
+ * @brief This file contains the method declarations and type defintions
+ * required to translate the SCSI REPORT LUNS command.
+ */
+
+#include <dev/isci/scil/sati_translator_sequence.h>
+
+#if !defined(DISABLE_SATI_REPORT_LUNS)
+SATI_STATUS sati_report_luns_translate_command(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ void * ata_io
+);
+#else // !(defined)DISABLE_SATI_REPORT_LUNS
+#define sati_report_luns_translate_command(sequence, scsi_io, ata_io) SATI_FAILURE
+#endif // !(defined)DISABLE_SATI_REPORT_LUNS
+
+#endif // _SATI_REPORT_LUNS_H_
diff --git a/sys/dev/isci/scil/sati_request_sense.c b/sys/dev/isci/scil/sati_request_sense.c
new file mode 100644
index 0000000..a247fa3
--- /dev/null
+++ b/sys/dev/isci/scil/sati_request_sense.c
@@ -0,0 +1,353 @@
+/*-
+ * 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.
+ *
+ * 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 <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/**
+ * @file
+ * @brief This file contains the implementation to translate
+ * SCSI Request Sense command based of the SAT spec.
+ */
+
+#if !defined(DISABLE_SATI_REQUEST_SENSE)
+
+#include <dev/isci/scil/sati_request_sense.h>
+#include <dev/isci/scil/sati_device.h>
+#include <dev/isci/scil/sati_util.h>
+#include <dev/isci/scil/intel_scsi.h>
+#include <dev/isci/scil/intel_ata.h>
+#include <dev/isci/scil/intel_sat.h>
+#include <dev/isci/scil/sati_callbacks.h>
+#include <dev/isci/scil/sati_mode_pages.h>
+
+#define MRIE_BYTE 3
+#define DEXCPT_BYTE 2
+
+/**
+ * @brief This method will translate the SCSI request sense command
+ * into corresponding ATA commands. Depending on supported and enabled
+ * capabilities like SMART, different ATA commands can be selected.
+ * For more information on the parameters passed to this method,
+ * please reference sati_translate_command().
+ *
+ * @return Indicates if the command translation succeeded.
+ * @retval SATI_SUCCESS indicates that the translation was supported and occurred
+ * without error.
+ * @retval SATI_FAILURE_CHECK_RESPONSE_DATA This value is returned if
+ * the SATII is processing a format unit commmand.
+ * @retval SATI_COMPLETE indicates that the translation was supported, occurred without
+ * error, and no additional translation is necessary.
+ */
+SATI_STATUS sati_request_sense_translate_command(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ void * ata_io
+)
+{
+ U8 * cdb = sati_cb_get_cdb_address(scsi_io);
+
+ //check if SATI is processing format unit command
+ switch(sequence->device->state)
+ {
+ case SATI_DEVICE_STATE_FORMAT_UNIT_IN_PROGRESS:
+ sati_scsi_sense_data_construct(
+ sequence,
+ scsi_io,
+ SCSI_STATUS_GOOD,
+ SCSI_SENSE_NOT_READY,
+ SCSI_ASC_LUN_FORMAT_IN_PROGRESS,
+ SCSI_ASCQ_LUN_FORMAT_IN_PROGRESS
+ );
+ return SATI_COMPLETE;
+ break;
+
+ case SATI_DEVICE_STATE_UNIT_ATTENTION_CONDITION:
+ sati_scsi_sense_data_construct(
+ sequence,
+ scsi_io,
+ SCSI_STATUS_GOOD,
+ SCSI_SENSE_UNIT_ATTENTION,
+ sequence->device->unit_attention_asc,
+ sequence->device->unit_attention_ascq
+ );
+ return SATI_COMPLETE;
+ break;
+ //sending sense data status Idle, this is set by start_stop_unit
+ case SATI_DEVICE_STATE_IDLE:
+ sati_scsi_sense_data_construct(
+ sequence,
+ scsi_io,
+ SCSI_STATUS_GOOD,
+ SCSI_SENSE_NO_SENSE,
+ SCSI_ASC_POWER_STATE_CHANGE,
+ SCSI_ASCQ_IDLE_CONDITION_ACTIVATE_BY_COMMAND
+ );
+ return SATI_COMPLETE;
+ break;
+ //sending sense data status Standby, this is set by start_stop_unit
+ case SATI_DEVICE_STATE_STANDBY:
+ sati_scsi_sense_data_construct(
+ sequence,
+ scsi_io,
+ SCSI_STATUS_GOOD,
+ SCSI_SENSE_NO_SENSE,
+ SCSI_ASC_POWER_STATE_CHANGE,
+ SCSI_ASCQ_STANDBY_CONDITION_ACTIVATE_BY_COMMAND
+ );
+ return SATI_COMPLETE;
+ break;
+
+ case SATI_DEVICE_STATE_STOPPED:
+ sati_scsi_sense_data_construct(
+ sequence,
+ scsi_io,
+ SCSI_STATUS_GOOD,
+ SCSI_SENSE_NO_SENSE,
+ SCSI_ASC_NO_ADDITIONAL_SENSE,
+ SCSI_ASCQ_NO_ADDITIONAL_SENSE
+ );
+ return SATI_COMPLETE;
+ break;
+
+ default:
+ break;
+ }
+
+ sequence->allocation_length = sati_get_cdb_byte(cdb, 4);
+
+ //Check if the device has SMART support & SMART enabled
+ if(sequence->device->capabilities & SATI_DEVICE_CAP_SMART_SUPPORT)
+ {
+ if(sequence->device->capabilities & SATI_DEVICE_CAP_SMART_ENABLE)
+ {
+ sati_ata_smart_return_status_construct(
+ ata_io,
+ sequence,
+ ATA_SMART_SUB_CMD_RETURN_STATUS
+ );
+
+ sequence->type = SATI_SEQUENCE_REQUEST_SENSE_SMART_RETURN_STATUS;
+ return SATI_SUCCESS;
+ }
+ }
+ sati_ata_check_power_mode_construct(ata_io, sequence);
+ sequence->type = SATI_SEQUENCE_REQUEST_SENSE_CHECK_POWER_MODE;
+ return SATI_SUCCESS;
+}
+
+/**
+ * @brief This method will translate the response to the SATI Request Sense
+ * translation. ATA_Check_Power_Mode and ATA_SMART_Return_Status will
+ * be translated into a SCSI sense data response.
+ *
+ * @return SATI_STATUS Indicates if the response translation succeeded.
+ *
+ */
+SATI_STATUS sati_request_sense_translate_response(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ void * ata_io
+)
+{
+ U8 * register_fis = sati_cb_get_d2h_register_fis_address(ata_io);
+ U32 mid_register;
+ U32 high_register;
+ U32 sector_count;
+ SATI_STATUS status = SATI_FAILURE;
+
+ if(sati_get_ata_status(register_fis) & ATA_STATUS_REG_ERROR_BIT)
+ {
+ sati_scsi_sense_data_construct(
+ sequence,
+ scsi_io,
+ SCSI_STATUS_CHECK_CONDITION,
+ SCSI_SENSE_ABORTED_COMMAND,
+ SCSI_ASC_NO_ADDITIONAL_SENSE ,
+ SCSI_ASCQ_NO_ADDITIONAL_SENSE
+ );
+ status = SATI_FAILURE_CHECK_RESPONSE_DATA;
+ }
+ else
+ {
+ switch(sequence->type)
+ {
+ case SATI_SEQUENCE_REQUEST_SENSE_SMART_RETURN_STATUS:
+
+ mid_register = sati_get_ata_lba_mid(register_fis);
+ high_register = sati_get_ata_lba_high(register_fis);
+ if(mid_register == ATA_MID_REGISTER_THRESHOLD_EXCEEDED
+ && high_register == ATA_HIGH_REGISTER_THRESHOLD_EXCEEDED)
+ {
+ sati_request_sense_data_response_construct(
+ sequence,
+ scsi_io,
+ SCSI_SENSE_NO_SENSE,
+ SCSI_ASC_HARDWARE_IMPENDING_FAILURE,
+ SCSI_ASCQ_GENERAL_HARD_DRIVE_FAILURE
+ );
+ status = SATI_COMPLETE;
+ }
+ else
+ {
+ sati_request_sense_data_response_construct(
+ sequence,
+ scsi_io,
+ SCSI_SENSE_NO_SENSE,
+ SCSI_ASC_NO_ADDITIONAL_SENSE,
+ SCSI_ASCQ_NO_ADDITIONAL_SENSE
+ );
+ status = SATI_COMPLETE;
+ }
+ break;
+
+ case SATI_SEQUENCE_REQUEST_SENSE_CHECK_POWER_MODE:
+
+ sector_count = sati_get_ata_sector_count(register_fis);
+
+ switch(sector_count)
+ {
+ case ATA_STANDBY_POWER_MODE:
+ sati_request_sense_data_response_construct(
+ sequence,
+ scsi_io,
+ SCSI_SENSE_NO_SENSE,
+ SCSI_ASC_POWER_STATE_CHANGE,
+ SCSI_ASCQ_POWER_STATE_CHANGE_TO_STANDBY
+ );
+ status = SATI_COMPLETE;
+ break;
+
+ case ATA_IDLE_POWER_MODE:
+ sati_request_sense_data_response_construct(
+ sequence,
+ scsi_io,
+ SCSI_SENSE_NO_SENSE,
+ SCSI_ASC_POWER_STATE_CHANGE,
+ SCSI_ASCQ_POWER_STATE_CHANGE_TO_IDLE
+ );
+ status = SATI_COMPLETE;
+ break;
+
+ case ATA_ACTIVE_POWER_MODE:
+ sati_request_sense_data_response_construct(
+ sequence,
+ scsi_io,
+ SCSI_SENSE_NO_SENSE,
+ SCSI_ASC_NO_ADDITIONAL_SENSE,
+ SCSI_ASCQ_NO_ADDITIONAL_SENSE
+ );
+ status = SATI_COMPLETE;
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ default:
+ sati_request_sense_data_response_construct(
+ sequence,
+ scsi_io,
+ SCSI_SENSE_NO_SENSE,
+ SCSI_ASC_NO_ADDITIONAL_SENSE,
+ SCSI_ASCQ_NO_ADDITIONAL_SENSE
+ );
+ status = SATI_COMPLETE;
+ }
+ }
+
+ return status;
+}
+
+/**
+ * @brief This method will construct a response for the sati_request_sense
+ * translation. The response will be returned in the data buffer instead
+ * of the response buffer, using sense data format described in SPC-4.
+ *
+ */
+void sati_request_sense_data_response_construct(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ U8 sense_key,
+ U8 additional_sense_code,
+ U8 additional_sense_code_qualifier
+)
+{
+ sati_set_data_byte(
+ sequence,
+ scsi_io,
+ 0,
+ SCSI_FIXED_CURRENT_RESPONSE_CODE | SCSI_FIXED_SENSE_DATA_VALID_BIT
+ );
+
+ sati_set_data_byte(sequence, scsi_io, 1, 0);
+ sati_set_data_byte(sequence, scsi_io, 2, sense_key);
+ sati_set_data_byte(sequence, scsi_io, 3, 0);
+ sati_set_data_byte(sequence, scsi_io, 4, 0);
+ sati_set_data_byte(sequence, scsi_io, 5, 0);
+ sati_set_data_byte(sequence, scsi_io, 6, 0);
+ sati_set_data_byte(sequence, scsi_io, 7, 0);
+ sati_set_data_byte(sequence, scsi_io, 8, 0);
+ sati_set_data_byte(sequence, scsi_io, 9, 0);
+ sati_set_data_byte(sequence, scsi_io, 10, 0);
+ sati_set_data_byte(sequence, scsi_io, 11, 0);
+ sati_set_data_byte(sequence, scsi_io, 12, additional_sense_code);
+ sati_set_data_byte(sequence, scsi_io, 13, additional_sense_code_qualifier);
+ sati_set_data_byte(sequence, scsi_io, 14, 0);
+ sati_set_data_byte(sequence, scsi_io, 15, 0);
+ sati_set_data_byte(sequence, scsi_io, 16, 0);
+ sati_set_data_byte(sequence, scsi_io, 17, 0);
+}
+
+#endif // !defined(DISABLE_SATI_REQUEST_SENSE)
+
diff --git a/sys/dev/isci/scil/sati_request_sense.h b/sys/dev/isci/scil/sati_request_sense.h
new file mode 100644
index 0000000..6348bd9
--- /dev/null
+++ b/sys/dev/isci/scil/sati_request_sense.h
@@ -0,0 +1,86 @@
+/*-
+ * 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.
+ *
+ * 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.
+ *
+ * $FreeBSD$
+ */
+/**
+ * @file
+ * @brief This file contains the method definitions to translate
+ * SCSI Request Sense command based of the SAT spec.
+ */
+
+#ifndef _SATI_REQUEST_SENSE_H_
+#define _SATI_REQUEST_SENSE_H_
+
+#include <dev/isci/scil/sati_types.h>
+#include <dev/isci/scil/sati_translator_sequence.h>
+
+SATI_STATUS sati_request_sense_translate_command(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ void * ata_io
+);
+
+SATI_STATUS sati_request_sense_translate_response(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ void * ata_io
+);
+
+void sati_request_sense_data_response_construct(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ U8 sense_key,
+ U8 additional_sense_code,
+ U8 additional_sense_code_qualifier
+);
+
+#endif // _SATI_REQUEST_SENSE_H_
diff --git a/sys/dev/isci/scil/sati_start_stop_unit.c b/sys/dev/isci/scil/sati_start_stop_unit.c
new file mode 100644
index 0000000..04139e2
--- /dev/null
+++ b/sys/dev/isci/scil/sati_start_stop_unit.c
@@ -0,0 +1,404 @@
+/*-
+ * 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.
+ *
+ * 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 <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/**
+ * @file
+ * @brief This file contains the method implementations required to
+ * translate the SCSI start stop unit command.
+ */
+
+#if !defined(DISABLE_SATI_START_STOP_UNIT)
+
+#include <dev/isci/scil/sati_start_stop_unit.h>
+#include <dev/isci/scil/sati_util.h>
+#include <dev/isci/scil/sati_callbacks.h>
+#include <dev/isci/scil/intel_ata.h>
+#include <dev/isci/scil/intel_scsi.h>
+
+/**
+ * @brief This method will translate the start stop unit SCSI command into
+ * various ATA commands depends on the value in POWER CONTIDTION, LOEJ
+ * and START fields.
+ * For more information on the parameters passed to this method,
+ * please reference sati_translate_command().
+ *
+ * @return Indicate if the command translation succeeded.
+ * @retval SCI_SUCCESS This is returned if the command translation was
+ * successful.
+ * @retval SATI_FAILURE_CHECK_RESPONSE_DATA Please refer to spec.
+ *
+ */
+SATI_STATUS sati_start_stop_unit_translate_command(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ void * ata_io
+)
+{
+ U8 * cdb = sati_cb_get_cdb_address(scsi_io);
+
+ switch ( SATI_START_STOP_UNIT_POWER_CONDITION(cdb) )
+ {
+ case SCSI_START_STOP_UNIT_POWER_CONDITION_START_VALID:
+ if ( SATI_START_STOP_UNIT_START_BIT(cdb) == 0
+ && SATI_START_STOP_UNIT_LOEJ_BIT(cdb) == 0 )
+ {
+ if ( SATI_START_STOP_UNIT_NO_FLUSH_BIT(cdb) == 1 )
+ {
+ //directly send ATA STANDBY_IMMEDIATE
+ sati_ata_standby_immediate_construct(ata_io, sequence);
+ sequence->command_specific_data.translated_command = ATA_STANDBY_IMMED;
+ }
+ else
+ {
+ if ( sequence->state != SATI_SEQUENCE_STATE_INCOMPLETE )
+ {
+ //First, send ATA flush command.
+ sati_ata_flush_cache_construct(ata_io, sequence);
+ sequence->command_specific_data.translated_command = ATA_FLUSH_CACHE;
+
+ //remember there is next step.
+ sequence->state = SATI_SEQUENCE_STATE_INCOMPLETE;
+ }
+ else
+ {
+ //the first step, flush cache command, has completed.
+ //Send standby immediate now.
+ sati_ata_standby_immediate_construct(ata_io, sequence);
+ sequence->command_specific_data.translated_command = ATA_STANDBY_IMMED;
+
+ }
+ }
+ }
+ else if ( SATI_START_STOP_UNIT_START_BIT(cdb) == 0
+ && SATI_START_STOP_UNIT_LOEJ_BIT(cdb) == 1 )
+ {
+ //need to know whether the device supports removable medial feature set.
+ if (sequence->device->capabilities & SATI_DEVICE_CAP_REMOVABLE_MEDIA)
+ {
+ //send ATA MEDIA EJECT command.
+ sati_ata_media_eject_construct(ata_io, sequence);
+ sequence->command_specific_data.translated_command = ATA_MEDIA_EJECT;
+ }
+ else
+ {
+ sati_scsi_sense_data_construct(
+ sequence,
+ scsi_io,
+ SCSI_STATUS_CHECK_CONDITION,
+ SCSI_SENSE_ILLEGAL_REQUEST,
+ SCSI_ASC_INVALID_FIELD_IN_CDB,
+ SCSI_ASCQ_INVALID_FIELD_IN_CDB
+ );
+ return SATI_FAILURE_CHECK_RESPONSE_DATA;
+ }
+ }
+ else if ( SATI_START_STOP_UNIT_START_BIT(cdb) == 1
+ && SATI_START_STOP_UNIT_LOEJ_BIT(cdb) == 0 )
+ {
+ //send an ATA verify command
+ sati_ata_read_verify_sectors_construct(ata_io, sequence);
+ sequence->command_specific_data.translated_command = ATA_READ_VERIFY_SECTORS;
+ }
+ else if ( SATI_START_STOP_UNIT_START_BIT(cdb) == 1
+ && SATI_START_STOP_UNIT_LOEJ_BIT(cdb) == 1 )
+ {
+ sati_scsi_sense_data_construct(
+ sequence,
+ scsi_io,
+ SCSI_STATUS_CHECK_CONDITION,
+ SCSI_SENSE_ILLEGAL_REQUEST,
+ SCSI_ASC_INVALID_FIELD_IN_CDB,
+ SCSI_ASCQ_INVALID_FIELD_IN_CDB
+ );
+ return SATI_FAILURE_CHECK_RESPONSE_DATA;
+ }
+
+ break;
+ //Power Condition Field is set to 0x01(Device to transition to Active state)
+ case SCSI_START_STOP_UNIT_POWER_CONDITION_ACTIVE:
+
+ if( sequence->state != SATI_SEQUENCE_STATE_INCOMPLETE )
+ {
+ sati_ata_idle_construct(ata_io, sequence);
+ sequence->state = SATI_SEQUENCE_STATE_INCOMPLETE;
+ sequence->command_specific_data.translated_command = ATA_IDLE;
+ }
+ else
+ {
+ sati_ata_read_verify_sectors_construct(ata_io, sequence);
+ sequence->command_specific_data.translated_command = ATA_READ_VERIFY_SECTORS;
+ }
+ break;
+
+ //Power Condition Field is set to 0x02(Device to transition to Idle state)
+ case SCSI_START_STOP_UNIT_POWER_CONDITION_IDLE:
+
+ if( SATI_START_STOP_UNIT_NO_FLUSH_BIT(cdb) == 0 &&
+ sequence->state != SATI_SEQUENCE_STATE_INCOMPLETE )
+ {
+ sati_ata_flush_cache_construct(ata_io, sequence);
+ sequence->command_specific_data.translated_command = ATA_FLUSH_CACHE;
+ sequence->state = SATI_SEQUENCE_STATE_INCOMPLETE;
+ }
+ else
+ {
+ if( SATI_START_STOP_UNIT_POWER_CONDITION_MODIFIER(cdb) == 0 )
+ {
+ sati_ata_idle_immediate_construct(ata_io, sequence);
+ }
+ else
+ {
+ sati_ata_idle_immediate_unload_construct(ata_io, sequence);
+ }
+ sequence->command_specific_data.translated_command = ATA_IDLE_IMMED;
+ }
+ break;
+
+ //Power Condition Field is set to 0x03(Device to transition to Standby state)
+ case SCSI_START_STOP_UNIT_POWER_CONDITION_STANDBY:
+ if( SATI_START_STOP_UNIT_NO_FLUSH_BIT(cdb) == 0 &&
+ sequence->state != SATI_SEQUENCE_STATE_INCOMPLETE )
+ {
+ sati_ata_flush_cache_construct(ata_io, sequence);
+ sequence->command_specific_data.translated_command = ATA_FLUSH_CACHE;
+ sequence->state = SATI_SEQUENCE_STATE_INCOMPLETE;
+ }
+ else
+ {
+ sati_ata_standby_immediate_construct(ata_io, sequence);
+ sequence->command_specific_data.translated_command = ATA_STANDBY_IMMED;
+ }
+ break;
+
+ //Power Condition Field is set to 0xB(force Standby state)
+ case SCSI_START_STOP_UNIT_POWER_CONDITION_FORCE_S_CONTROL:
+
+ if( SATI_START_STOP_UNIT_NO_FLUSH_BIT(cdb) == 0 &&
+ sequence->state != SATI_SEQUENCE_STATE_INCOMPLETE )
+ {
+ sati_ata_flush_cache_construct(ata_io, sequence);
+ sequence->command_specific_data.translated_command = ATA_FLUSH_CACHE;
+ sequence->state = SATI_SEQUENCE_STATE_INCOMPLETE;
+ }
+ else
+ {
+ sati_ata_standby_construct(ata_io, sequence, 0);
+ sequence->command_specific_data.translated_command = ATA_STANDBY;
+ }
+ break;
+
+ case SCSI_START_STOP_UNIT_POWER_CONDITION_LU_CONTROL:
+ default: //TBD.
+ sati_scsi_sense_data_construct(
+ sequence,
+ scsi_io,
+ SCSI_STATUS_CHECK_CONDITION,
+ SCSI_SENSE_ILLEGAL_REQUEST,
+ SCSI_ASC_INVALID_FIELD_IN_CDB,
+ SCSI_ASCQ_INVALID_FIELD_IN_CDB
+ );
+ return SATI_FAILURE_CHECK_RESPONSE_DATA;
+ break;
+ }
+
+ if ( SATI_START_STOP_UNIT_IMMED_BIT(cdb) == 1 )
+ {
+ //@todo: return good status now.
+ ;
+ }
+ sequence->type = SATI_SEQUENCE_START_STOP_UNIT;
+ return SATI_SUCCESS;
+}
+
+
+/**
+ * @brief This method will translate the ATA command register FIS
+ * response into an appropriate SCSI response for START STOP UNIT.
+ * For more information on the parameters passed to this method,
+ * please reference sati_translate_response().
+ *
+ * @return Indicate if the response translation succeeded.
+ * @retval SCI_SUCCESS This is returned if the data translation was
+ * successful.
+ */
+SATI_STATUS sati_start_stop_unit_translate_response(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ void * ata_io
+)
+{
+ U8 * register_fis = sati_cb_get_d2h_register_fis_address(ata_io);
+ U8 * cdb = sati_cb_get_cdb_address(scsi_io);
+
+ if (sati_get_ata_status(register_fis) & ATA_STATUS_REG_ERROR_BIT)
+ {
+ switch ( sequence->command_specific_data.translated_command )
+ {
+ case ATA_FLUSH_CACHE:
+ case ATA_STANDBY_IMMED:
+ case ATA_IDLE_IMMED:
+ case ATA_IDLE:
+ case ATA_STANDBY:
+ //Note: There is lack of reference in spec of the error handling for
+ //READ_VERIFY command.
+ case ATA_READ_VERIFY_SECTORS:
+ sati_scsi_sense_data_construct(
+ sequence,
+ scsi_io,
+ SCSI_STATUS_CHECK_CONDITION,
+ SCSI_SENSE_ABORTED_COMMAND,
+ SCSI_ASC_COMMAND_SEQUENCE_ERROR,
+ SCSI_ASCQ_NO_ADDITIONAL_SENSE
+ );
+ break;
+
+ case ATA_MEDIA_EJECT:
+ sati_scsi_sense_data_construct(
+ sequence,
+ scsi_io,
+ SCSI_STATUS_CHECK_CONDITION,
+ SCSI_SENSE_ABORTED_COMMAND,
+ SCSI_ASC_MEDIA_LOAD_OR_EJECT_FAILED,
+ SCSI_ASCQ_NO_ADDITIONAL_SENSE
+ );
+ break;
+
+ default:
+ sati_scsi_sense_data_construct(
+ sequence,
+ scsi_io,
+ SCSI_STATUS_CHECK_CONDITION,
+ SCSI_SENSE_ILLEGAL_REQUEST,
+ SCSI_ASC_INVALID_FIELD_IN_CDB,
+ SCSI_ASCQ_INVALID_FIELD_IN_CDB
+ );
+ break;
+ }
+ sequence->state = SATI_SEQUENCE_STATE_FINAL;
+ return SATI_FAILURE_CHECK_RESPONSE_DATA;
+ }
+ else
+ {
+ switch ( sequence->command_specific_data.translated_command )
+ {
+ case ATA_READ_VERIFY_SECTORS:
+
+ sati_scsi_sense_data_construct(
+ sequence,
+ scsi_io,
+ SCSI_STATUS_GOOD,
+ SCSI_SENSE_NO_SENSE,
+ SCSI_ASC_NO_ADDITIONAL_SENSE,
+ SCSI_ASCQ_NO_ADDITIONAL_SENSE
+ );
+ //device state is now operational(active)
+ sequence->device->state = SATI_DEVICE_STATE_OPERATIONAL;
+ sequence->state = SATI_SEQUENCE_STATE_FINAL;
+ break;
+
+ case ATA_IDLE_IMMED:
+
+ sati_scsi_sense_data_construct(
+ sequence,
+ scsi_io,
+ SCSI_STATUS_GOOD,
+ SCSI_SENSE_NO_SENSE,
+ SCSI_ASC_NO_ADDITIONAL_SENSE,
+ SCSI_ASCQ_NO_ADDITIONAL_SENSE
+ );
+ sequence->device->state = SATI_DEVICE_STATE_IDLE;
+ sequence->state = SATI_SEQUENCE_STATE_FINAL;
+ break;
+
+ //These three commands will be issued when the power condition is 0x00 or 0x03
+ case ATA_MEDIA_EJECT:
+ case ATA_STANDBY:
+ case ATA_STANDBY_IMMED:
+
+ sati_scsi_sense_data_construct(
+ sequence,
+ scsi_io,
+ SCSI_STATUS_GOOD,
+ SCSI_SENSE_NO_SENSE,
+ SCSI_ASC_NO_ADDITIONAL_SENSE,
+ SCSI_ASCQ_NO_ADDITIONAL_SENSE
+ );
+
+ if( SATI_START_STOP_UNIT_POWER_CONDITION(cdb) == 0 )
+ {
+ sequence->device->state = SATI_DEVICE_STATE_STOPPED;
+ }
+ else
+ {
+ sequence->device->state = SATI_DEVICE_STATE_STANDBY;
+ }
+ sequence->state = SATI_SEQUENCE_STATE_FINAL;
+ break;
+
+ default:
+ //FLUSH Cache command does not require any success handling
+ break;
+ }
+
+ if (sequence->state == SATI_SEQUENCE_STATE_INCOMPLETE)
+ {
+ return SATI_SEQUENCE_INCOMPLETE;
+ }
+ }
+ return SATI_COMPLETE;
+}
+
+#endif // !defined(DISABLE_SATI_START_STOP_UNIT)
+
diff --git a/sys/dev/isci/scil/sati_start_stop_unit.h b/sys/dev/isci/scil/sati_start_stop_unit.h
new file mode 100644
index 0000000..8235c4b
--- /dev/null
+++ b/sys/dev/isci/scil/sati_start_stop_unit.h
@@ -0,0 +1,102 @@
+/*-
+ * 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.
+ *
+ * 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.
+ *
+ * $FreeBSD$
+ */
+#ifndef _SATI_START_STOP_UNIT_H_
+#define _SATI_START_STOP_UNIT_H_
+
+/**
+ * @file
+ * @brief This file contains the method declarations and type definitions
+ * required to translate the SCSI start_stop_unit commands.
+ */
+
+#include <dev/isci/scil/intel_scsi.h>
+#include <dev/isci/scil/sati_types.h>
+#include <dev/isci/scil/sati_translator_sequence.h>
+
+#define SATI_START_STOP_UNIT_POWER_CONDITION(cdb) \
+ (( sati_get_cdb_byte(cdb, 4) & SCSI_START_STOP_UNIT_POWER_CONDITION_MASK ) \
+ >> SCSI_START_STOP_UNIT_POWER_CONDITION_SHIFT)
+
+#define SATI_START_STOP_UNIT_START_BIT(cdb) \
+ (( sati_get_cdb_byte(cdb, 4) & SCSI_START_STOP_UNIT_START_BIT_MASK ) \
+ >> SCSI_START_STOP_UNIT_START_BIT_SHIFT)
+
+#define SATI_START_STOP_UNIT_LOEJ_BIT(cdb) \
+ (( sati_get_cdb_byte(cdb, 4) & SCSI_START_STOP_UNIT_LOEJ_BIT_MASK ) \
+ >> SCSI_START_STOP_UNIT_LOEJ_BIT_SHIFT)
+
+#define SATI_START_STOP_UNIT_NO_FLUSH_BIT(cdb) \
+ (( sati_get_cdb_byte(cdb, 4) & SCSI_START_STOP_UNIT_NO_FLUSH_MASK ) \
+ >> SCSI_START_STOP_UNIT_NO_FLUSH_SHIFT)
+
+#define SATI_START_STOP_UNIT_IMMED_BIT(cdb) \
+ (( sati_get_cdb_byte(cdb, 1) & SCSI_START_STOP_UNIT_IMMED_MASK ) \
+ >> SCSI_START_STOP_UNIT_IMMED_SHIFT)
+
+#define SATI_START_STOP_UNIT_POWER_CONDITION_MODIFIER(cdb) \
+ (( sati_get_cdb_byte(cdb, 3) & SCSI_START_STOP_UNIT_POWER_CONDITION_MODIFIER_MASK) \
+ >> SCSI_START_STOP_UNIT_POWER_CONDITION_MODIFIER_SHIFT)
+
+SATI_STATUS sati_start_stop_unit_translate_command(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ void * ata_io
+);
+
+SATI_STATUS sati_start_stop_unit_translate_response(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ void * ata_io
+);
+#endif // _SATI_START_STOP_UNIT_H_
diff --git a/sys/dev/isci/scil/sati_synchronize_cache.c b/sys/dev/isci/scil/sati_synchronize_cache.c
new file mode 100644
index 0000000..3c97471
--- /dev/null
+++ b/sys/dev/isci/scil/sati_synchronize_cache.c
@@ -0,0 +1,119 @@
+/*-
+ * 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.
+ *
+ * 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 <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/**
+ * @file
+ * @brief This file contains the method implementations for translating
+ * the SCSI SYNCHRONIZE_CACHE (10, 16-byte) commands.
+ */
+
+#if !defined(DISABLE_SATI_SYNCHRONIZE_CACHE)
+
+#include <dev/isci/scil/sati_synchronize_cache.h>
+#include <dev/isci/scil/sati_callbacks.h>
+#include <dev/isci/scil/sati_util.h>
+#include <dev/isci/scil/sati_translator_sequence.h>
+
+#include <dev/isci/scil/intel_ata.h>
+#include <dev/isci/scil/intel_scsi.h>
+#include <dev/isci/scil/intel_sat.h>
+
+//******************************************************************************
+//* P R I V A T E M E T H O D S
+//******************************************************************************
+
+/**
+ * @brief This method performs the SCSI SYNCHRONIZE_CACHE 10 and 16 command translation
+ * functionality common to all SYNCHRONIZE_CACHE command sizes.
+ * This includes:
+ * - setting the command register
+ * - setting the device head register
+ * - filling in fields in the SATI_TRANSLATOR_SEQUENCE object.
+ * For more information on the parameters passed to this method,
+ * please reference sati_translate_command().
+ *
+ * @return Indicate if the method was successfully completed.
+ * @retval SATI_SUCCESS This is returned in all other cases.
+ */
+SATI_STATUS sati_synchronize_cache_translate_command(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ void * ata_io
+)
+{
+ U8 * cdb = sati_cb_get_cdb_address(scsi_io);
+ U8 * register_fis = sati_cb_get_h2d_register_fis_address(ata_io);
+
+ sequence->type = SATI_SEQUENCE_SYNCHRONIZE_CACHE;
+ sequence->protocol = SAT_PROTOCOL_NON_DATA;
+ sequence->data_direction = SATI_DATA_DIRECTION_NONE;
+
+ if (sati_get_cdb_byte(cdb, 1) & SCSI_SYNCHRONIZE_CACHE_IMMED_ENABLED)
+ {
+ //currently we ignore immed bit.
+ ;
+ }
+
+ // Ensure the device supports the 48 bit feature set.
+ if (sequence->device->capabilities & SATI_DEVICE_CAP_48BIT_ENABLE)
+ sati_set_ata_command(register_fis, ATA_FLUSH_CACHE_EXT);
+ else
+ sati_set_ata_command(register_fis, ATA_FLUSH_CACHE);
+
+ return SATI_SUCCESS;
+}
+
+#endif // !defined(DISABLE_SATI_SYNCHRONIZE_CACHE)
+
diff --git a/sys/dev/isci/scil/sati_synchronize_cache.h b/sys/dev/isci/scil/sati_synchronize_cache.h
new file mode 100644
index 0000000..58d6026
--- /dev/null
+++ b/sys/dev/isci/scil/sati_synchronize_cache.h
@@ -0,0 +1,71 @@
+/*-
+ * 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.
+ *
+ * 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.
+ *
+ * $FreeBSD$
+ */
+#ifndef _SATI_SYNCHRONIZE_CACHE_H_
+#define _SATI_SYNCHRONIZE_CACHE_H_
+
+/**
+ * @file
+ * @brief This file contains the method prototypes and constructs
+ * for translating the SCSI SYNCHRONIZE CACHE (10, 16-byte) commands.
+ */
+
+#include <dev/isci/scil/sati_translator_sequence.h>
+
+SATI_STATUS sati_synchronize_cache_translate_command(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ void * ata_io
+);
+
+#endif // _SATI_SYNCHRONIZE_CACHE_H_
diff --git a/sys/dev/isci/scil/sati_test_unit_ready.c b/sys/dev/isci/scil/sati_test_unit_ready.c
new file mode 100644
index 0000000..e5e781b
--- /dev/null
+++ b/sys/dev/isci/scil/sati_test_unit_ready.c
@@ -0,0 +1,186 @@
+/*-
+ * 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.
+ *
+ * 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 <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/**
+ * @file
+ * @brief This file contains the method implementations required to
+ * translate the SCSI test unit ready command.
+ */
+
+#if !defined(DISABLE_SATI_TEST_UNIT_READY)
+
+#include <dev/isci/scil/sati_test_unit_ready.h>
+#include <dev/isci/scil/sati_util.h>
+#include <dev/isci/scil/sati_callbacks.h>
+#include <dev/isci/scil/intel_ata.h>
+#include <dev/isci/scil/intel_scsi.h>
+
+/**
+ * @brief This method will translate the test unit ready SCSI command into
+ * an ATA CHECK POWER MODE command.
+ * For more information on the parameters passed to this method,
+ * please reference sati_translate_command().
+ *
+ * @return Indicate if the command translation succeeded.
+ * @retval SCI_SUCCESS This is returned if the command translation was
+ * successful.
+ * @retval SATI_FAILURE_CHECK_RESPONSE_DATA This value is returned if the
+ * LBA field is not 0, the PMI bit is not 0.
+ */
+SATI_STATUS sati_test_unit_ready_translate_command(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ void * ata_io
+)
+{
+ /**
+ * SAT dictates:
+ * - the device should be in a state to receive commands
+ * - a stopped device should cause sense data.
+ * - a format unit in progresss should cause sense data.
+ * - a self-test in progress should cause sense data.
+ * - a device fault occurred on previous request should cause sense data.
+ * - handling the removable media feature set isn't supported according to
+ * SAT specifications.
+ */
+ if (sequence->device->state == SATI_DEVICE_STATE_STOPPED)
+ {
+ sati_scsi_sense_data_construct(
+ sequence,
+ scsi_io,
+ SCSI_STATUS_CHECK_CONDITION,
+ SCSI_SENSE_NOT_READY,
+ SCSI_ASC_INITIALIZING_COMMAND_REQUIRED,
+ SCSI_ASCQ_INITIALIZING_COMMAND_REQUIRED
+ );
+ return SATI_FAILURE_CHECK_RESPONSE_DATA;
+ }
+ else if (sequence->device->state
+ == SATI_DEVICE_STATE_SELF_TEST_IN_PROGRESS)
+ {
+ sati_scsi_sense_data_construct(
+ sequence,
+ scsi_io,
+ SCSI_STATUS_CHECK_CONDITION,
+ SCSI_SENSE_NOT_READY,
+ SCSI_ASC_LUN_SELF_TEST_IN_PROGRESS,
+ SCSI_ASCQ_LUN_SELF_TEST_IN_PROGRESS
+ );
+ return SATI_FAILURE_CHECK_RESPONSE_DATA;
+ }
+ else if (sequence->device->state
+ == SATI_DEVICE_STATE_FORMAT_UNIT_IN_PROGRESS)
+ {
+ sati_scsi_sense_data_construct(
+ sequence,
+ scsi_io,
+ SCSI_STATUS_CHECK_CONDITION,
+ SCSI_SENSE_NOT_READY,
+ SCSI_ASC_LUN_FORMAT_IN_PROGRESS,
+ SCSI_ASCQ_LUN_FORMAT_IN_PROGRESS
+ );
+ return SATI_FAILURE_CHECK_RESPONSE_DATA;
+ }
+
+ // The CDB is properly formed and the device is ready.
+ sequence->type = SATI_SEQUENCE_TEST_UNIT_READY;
+
+ sati_ata_check_power_mode_construct(ata_io, sequence);
+ return SATI_SUCCESS;
+}
+
+/**
+ * @brief This method will translate the ATA CHECK POWER MODE register FIS
+ * response into an appropriate SCSI response.
+ * For more information on the parameters passed to this method,
+ * please reference sati_translate_response().
+ *
+ * @return Indicate if the response translation succeeded.
+ * @retval SCI_SUCCESS This is returned if the data translation was
+ * successful.
+ */
+SATI_STATUS sati_test_unit_ready_translate_response(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ void * ata_io
+)
+{
+ U8 * register_fis = sati_cb_get_d2h_register_fis_address(ata_io);
+
+ /**
+ * SAT dictates:
+ * - If the ATA CHECK POWER MODE command returns an error, then
+ * return sense data indicating the LOGICAL UNIT DOES NOT RESPONSE
+ * TO SELECTION.
+ * - All other cases are considered successful.
+ */
+ if (sati_get_ata_status(register_fis) & ATA_STATUS_REG_ERROR_BIT)
+ {
+ sati_scsi_sense_data_construct(
+ sequence,
+ scsi_io,
+ SCSI_STATUS_CHECK_CONDITION,
+ SCSI_SENSE_NOT_READY,
+ SCSI_ASC_LUN_NOT_RESPOND_TO_SELECTION,
+ SCSI_ASCQ_LUN_NOT_RESPOND_TO_SELECTION
+ );
+ return SATI_FAILURE_CHECK_RESPONSE_DATA;
+ }
+
+ return SATI_COMPLETE;
+}
+
+#endif // !defined(DISABLE_SATI_TEST_UNIT_READY)
+
diff --git a/sys/dev/isci/scil/sati_test_unit_ready.h b/sys/dev/isci/scil/sati_test_unit_ready.h
new file mode 100644
index 0000000..50360c7
--- /dev/null
+++ b/sys/dev/isci/scil/sati_test_unit_ready.h
@@ -0,0 +1,79 @@
+/*-
+ * 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.
+ *
+ * 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.
+ *
+ * $FreeBSD$
+ */
+#ifndef _SATI_TEST_UNIT_READY_H_
+#define _SATI_TEST_UNIT_READY_H_
+
+/**
+ * @file
+ * @brief This file contains the method interfaces required to
+ * translate the SCSI test unit ready command and corresponding
+ * ATA responses.
+ */
+
+#include <dev/isci/scil/sati_types.h>
+#include <dev/isci/scil/sati_translator_sequence.h>
+
+SATI_STATUS sati_test_unit_ready_translate_command(
+ SATI_TRANSLATOR_SEQUENCE_T * translator_sequence,
+ void * scsi_io,
+ void * ata_io
+);
+
+SATI_STATUS sati_test_unit_ready_translate_response(
+ SATI_TRANSLATOR_SEQUENCE_T * translator_sequence,
+ void * scsi_io,
+ void * ata_io
+);
+
+#endif // _SATI_TEST_UNIT_READY_H_
diff --git a/sys/dev/isci/scil/sati_translator_sequence.h b/sys/dev/isci/scil/sati_translator_sequence.h
new file mode 100644
index 0000000..4bd63a7
--- /dev/null
+++ b/sys/dev/isci/scil/sati_translator_sequence.h
@@ -0,0 +1,361 @@
+/*-
+ * 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.
+ *
+ * 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.
+ *
+ * $FreeBSD$
+ */
+#ifndef _SATI_TRANSLATOR_SEQUENCE_H_
+#define _SATI_TRANSLATOR_SEQUENCE_H_
+
+/**
+ * @file
+ * @brief 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 <dev/isci/scil/sati_device.h>
+
+/**
+ * @enum _SATI_TRANSLATOR_SEQUENCE_TYPE
+ *
+ * @brief This enumeration defines the possible sequence types for the
+ * translator.
+ */
+typedef 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_ATA_INFORMATION,
+ SATI_SEQUENCE_INQUIRY_BLOCK_DEVICE,
+ SATI_SEQUENCE_INQUIRY_EXECUTE_DEVICE_DIAG,
+ 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_POWER_CONDITION,
+ 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_POWER_CONDITION,
+ 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_WRITE_AND_VERIFY,
+
+ SATI_SEQUENCE_START_STOP_UNIT,
+
+ SATI_SEQUENCE_REASSIGN_BLOCKS,
+
+ // SCSI Task Requests sequences
+
+ SATI_SEQUENCE_LUN_RESET,
+ SATI_SEQUENCE_ABORT_TASK_SET,
+
+ SATI_SEQUENCE_REQUEST_SENSE_SMART_RETURN_STATUS,
+ SATI_SEQUENCE_REQUEST_SENSE_CHECK_POWER_MODE,
+
+ SATI_SEQUENCE_WRITE_LONG,
+
+ SATI_SEQUENCE_UNMAP,
+
+ SATI_SEQUENCE_ATA_PASSTHROUGH_12,
+ SATI_SEQUENCE_ATA_PASSTHROUGH_16,
+
+ SATI_SEQUENCE_READ_BUFFER,
+ SATI_SEQUENCE_WRITE_BUFFER,
+ SATI_SEQUENCE_WRITE_BUFFER_MICROCODE
+
+} SATI_TRANSLATOR_SEQUENCE_TYPE;
+
+#define SATI_SEQUENCE_TYPE_READ_MIN SATI_SEQUENCE_READ_6
+#define SATI_SEQUENCE_TYPE_READ_MAX SATI_SEQUENCE_READ_16
+
+/**
+ * @name 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
+#define SATI_SEQUENCE_STATE_READ_ERROR 5
+/*@}*/
+
+/**
+ * @name 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
+ *
+ * @brief 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
+ *
+ * @brief This structure contains all of the current processing states
+ * for processing reassign block command's parameter fields.
+ */
+typedef 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;
+
+}SATI_REASSIGN_BLOCKS_PROCESSING_STATE_T;
+
+#define SATI_ATAPI_REQUEST_SENSE_CDB_LENGTH 12
+
+/**
+ * @struct SATI_ATAPI_DATA
+ *
+ * @brief The SATI_ATAPI_DATA structure is for sati atapi IO specific data.
+ */
+typedef struct SATI_ATAPI_DATA
+{
+ U8 request_sense_cdb[SATI_ATAPI_REQUEST_SENSE_CDB_LENGTH];
+} SATI_ATAPI_DATA_T;
+
+
+enum SATI_UNMAP_ATA_COMMAND_STATUS
+{
+ SATI_UNMAP_READY_TO_SEND,
+ SATI_UNMAP_COMMAND_FAIL,
+ SATI_UNMAP_COMMAND_SUCCESS,
+};
+
+/**
+ * @struct SATI_UNMAP_PROCESSING_STATE
+ *
+ * @brief This structure contains all of the current processing states
+ * for processing unmap command data translation.
+ */
+typedef struct SATI_UNMAP_PROCESSING_STATE
+{
+ U32 max_unmap_block_descriptors;
+ U32 current_unmap_block_descriptor_index;
+ U32 current_lba_count;
+ SATI_LBA current_lba;
+ SATI_LBA next_lba;
+ U32 max_lba_range_entries;
+ void * current_dsm_descriptor;
+ void * virtual_unmap_buffer;
+ U32 physical_unmap_buffer_low;
+ U32 physical_unmap_buffer_high;
+ void * unmap_buffer_sgl_pair;
+} SATI_UNMAP_PROCESSING_STATE_T;
+
+/**
+ * @struct SATI_TRANSLATOR_SEQUENCE
+ *
+ * @brief This structure contains all of the translation information
+ * associated with a particular request.
+ */
+typedef 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 indicates whether or not the translation requires
+ * response translation.
+ */
+ BOOL is_translate_response_required;
+
+ /**
+ * This field specifies the remote device context for which this
+ * translator sequence is destined.
+ */
+ SATI_DEVICE_T * 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;
+ SATI_REASSIGN_BLOCKS_PROCESSING_STATE_T reassign_blocks_process_state;
+ SATI_MODE_SELECT_PROCESSING_STATE_T process_state;
+ SATI_UNMAP_PROCESSING_STATE_T unmap_process_state;
+ SATI_ATAPI_DATA_T sati_atapi_data;
+ } command_specific_data;
+
+} SATI_TRANSLATOR_SEQUENCE_T;
+
+
+
+#endif // _SATI_TRANSLATOR_SEQUENCE_H_
+
diff --git a/sys/dev/isci/scil/sati_types.h b/sys/dev/isci/scil/sati_types.h
new file mode 100644
index 0000000..4851aeb
--- /dev/null
+++ b/sys/dev/isci/scil/sati_types.h
@@ -0,0 +1,152 @@
+/*-
+ * 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.
+ *
+ * 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.
+ *
+ * $FreeBSD$
+ */
+#ifndef _SATI_TYPES_H_
+#define _SATI_TYPES_H_
+
+/**
+ * @file
+ * @brief This file contains various type definitions to be utilized with
+ * SCSI to ATA Translation Implementation.
+ */
+
+#include <dev/isci/types.h>
+
+/**
+ * @enum _SATI_STATUS
+ *
+ * @brief This enumeration defines the possible return values from the
+ * SATI translation methods.
+ */
+typedef enum _SATI_STATUS
+{
+ /**
+ * This indicates that the translation was supported and occurred
+ * without error.
+ */
+ SATI_SUCCESS,
+
+ /**
+ * This indicates that the translation was supported and occurred
+ * without error.
+ * Additionally, this indicates the translation actually already
+ * translated the scatter gather list elements appropriately as
+ * well.
+ */
+ SATI_SUCCESS_SGL_TRANSLATED,
+
+ /**
+ * 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
+
+} SATI_STATUS;
+
+#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/sys/dev/isci/scil/sati_unmap.c b/sys/dev/isci/scil/sati_unmap.c
new file mode 100644
index 0000000..cc8327b
--- /dev/null
+++ b/sys/dev/isci/scil/sati_unmap.c
@@ -0,0 +1,609 @@
+/*-
+ * 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.
+ *
+ * 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 <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/**
+ * @file
+ * @brief This file contains the method implementations required to
+ * translate the SCSI unmap command.
+ */
+
+#if !defined(DISABLE_SATI_UNMAP)
+
+#include <dev/isci/scil/sati_unmap.h>
+#include <dev/isci/scil/sati_callbacks.h>
+#include <dev/isci/scil/sati_translator_sequence.h>
+#include <dev/isci/scil/sati_util.h>
+#include <dev/isci/scil/intel_ata.h>
+#include <dev/isci/scil/intel_scsi.h>
+#include <dev/isci/scil/intel_sat.h>
+
+//******************************************************************************
+//* P R I V A T E M E T H O D S
+//******************************************************************************
+
+/**
+ * @brief This method translates a given number of DSM
+ * requests into DSM blocks based on the devices logical block size
+ *
+ * @return Number of DSM blocks required for the DSM descriptor count
+ */
+U32 sati_unmap_calculate_dsm_blocks(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ U32 dsm_descriptor_count
+)
+{
+ U32 blocks = (dsm_descriptor_count * sizeof(TRIM_PAIR))/sequence->device->logical_block_size;
+ if ((dsm_descriptor_count * sizeof(TRIM_PAIR)) % sequence->device->logical_block_size)
+ {
+ blocks++;
+ }
+ return blocks;
+}
+
+/**
+ * @brief This method performs the SCSI Unmap command translation
+ * functionality.
+ * This includes:
+ * - setting the command register
+ * - setting the device head register
+ * - filling in fields in the SATI_TRANSLATOR_SEQUENCE object.
+ * For more information on the parameters passed to this method,
+ * please reference sati_translate_command().
+ *
+ * @return Indicate if the method was successfully completed.
+ * @retval SATI_SUCCESS This is returned in all other cases.
+ */
+SATI_STATUS sati_unmap_construct(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ void * ata_io,
+ U32 sector_count
+)
+{
+ U8 * h2d_register_fis = sati_cb_get_h2d_register_fis_address(ata_io);
+ U8 * d2h_register_fis = sati_cb_get_d2h_register_fis_address(ata_io);
+
+ sati_set_ata_command(h2d_register_fis, ATA_DATA_SET_MANAGEMENT);
+ sati_set_ata_features(h2d_register_fis, 0x01);
+ sati_set_ata_sector_count(h2d_register_fis, (U8)sector_count);
+ sati_set_ata_device_head(h2d_register_fis, ATA_DEV_HEAD_REG_LBA_MODE_ENABLE);
+
+ // Set the completion status since the core will not do that for
+ // the udma fast path.
+ sati_set_ata_status(d2h_register_fis, 0x00);
+
+ // Set up the direction and protocol for SCIC
+ sequence->data_direction = SATI_DATA_DIRECTION_OUT;
+ sequence->protocol = SAT_PROTOCOL_UDMA_DATA_OUT;
+ // The UNMAP translation will always require a callback
+ // on every response so it can free memory if an error
+ // occurs.
+ sequence->is_translate_response_required = TRUE;
+
+ ASSERT(sector_count < 0x100);
+
+ return SATI_SUCCESS;
+}
+
+/**
+ * @brief This method updates the unmap sequence state to the next
+ * unmap descriptor
+ *
+ * @return Indicate if the method was successfully completed.
+ * @retval SATI_SUCCESS This is returned in all other cases.
+ */
+SATI_STATUS sati_unmap_load_next_descriptor(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io
+)
+{
+ SATI_UNMAP_PROCESSING_STATE_T * unmap_process_state;
+ U32 index;
+ U8 unmap_block_descriptor[16];
+
+ unmap_process_state = &sequence->command_specific_data.unmap_process_state;
+
+ // Load the next descriptor
+ for(index = unmap_process_state->current_unmap_block_descriptor_index;
+ index < unmap_process_state->current_unmap_block_descriptor_index +
+ SATI_UNMAP_SIZEOF_SCSI_UNMAP_BLOCK_DESCRIPTOR;
+ index++)
+ {
+ sati_get_data_byte(sequence,
+ scsi_io,
+ index,
+ &unmap_block_descriptor[index-unmap_process_state->current_unmap_block_descriptor_index]);
+ }
+
+ // Update the internal state for the next translation pass
+ unmap_process_state->current_lba_count = (unmap_block_descriptor[8] << 24) |
+ (unmap_block_descriptor[9] << 16) |
+ (unmap_block_descriptor[10] << 8) |
+ (unmap_block_descriptor[11]);
+ unmap_process_state->current_lba = ((SATI_LBA)(unmap_block_descriptor[0]) << 56) |
+ ((SATI_LBA)(unmap_block_descriptor[1]) << 48) |
+ ((SATI_LBA)(unmap_block_descriptor[2]) << 40) |
+ ((SATI_LBA)(unmap_block_descriptor[3]) << 32) |
+ ((SATI_LBA)(unmap_block_descriptor[4]) << 24) |
+ ((SATI_LBA)(unmap_block_descriptor[5]) << 16) |
+ ((SATI_LBA)(unmap_block_descriptor[6]) << 8) |
+ ((SATI_LBA)(unmap_block_descriptor[7]));
+ unmap_process_state->next_lba = 0;
+
+ // Update the index for the next descriptor to translate
+ unmap_process_state->current_unmap_block_descriptor_index += SATI_UNMAP_SIZEOF_SCSI_UNMAP_BLOCK_DESCRIPTOR;
+
+ return SATI_SUCCESS;
+}
+
+/**
+ * @brief This method determines the max number of blocks of DSM data
+ * that can be satisfied by the device and the SW
+ *
+ * @return Number of blocks supported
+ * @retval Number of blocks supported
+ */
+U32 sati_unmap_get_max_buffer_size_in_blocks(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence
+)
+{
+ // Currently this SATI implementation only supports a single
+ // 4k block of memory for the DMA write operation for simplicity
+ // (no need to handle more than one SG element).
+ // Since most run time UNMAP requests use 1K or less buffer space,
+ // there is no performance degradation with only supporting a
+ // single physical page. For best results allocate the maximum
+ // amount of memory the device can handle up to the maximum of 4K.
+ return MIN(SATI_DSM_MAX_BUFFER_SIZE/sequence->device->logical_block_size,
+ sequence->device->max_lba_range_entry_blocks);
+}
+
+/**
+ * @brief This method will be called before starting the first unmap translation
+ *
+ * @return Indicate if the translation was successful.
+ * @retval SATI_SUCCESS This is returned if the command translation was
+ * successful and no further processing.
+ * @retval SATI_COMPLETE - The initial processing was completed successfully
+ * @retval SATI_FAILURE_CHECK_RESPONSE_DATA - Failed the initial processing
+ */
+SATI_STATUS sati_unmap_initial_processing(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ void * ata_io
+)
+{
+ SATI_UNMAP_PROCESSING_STATE_T * unmap_process_state;
+ U8 * cdb;
+ U16 unmap_length;
+ U32 descriptor_length;
+ U32 index;
+ U32 max_dsm_blocks;
+ U8 unmap_param_list[8];
+
+ unmap_process_state = &sequence->command_specific_data.unmap_process_state;
+
+ // Set up the sequence type for unmap translation
+ sequence->type = SATI_SEQUENCE_UNMAP;
+
+ // Make sure the device is TRIM capable
+ if ((sequence->device->capabilities & SATI_DEVICE_CAP_DSM_TRIM_SUPPORT)
+ != SATI_DEVICE_CAP_DSM_TRIM_SUPPORT)
+ {
+ // Can't send TRIM request to device that does not support it
+ sati_scsi_sense_data_construct(
+ sequence,
+ scsi_io,
+ SCSI_STATUS_CHECK_CONDITION,
+ SCSI_SENSE_ILLEGAL_REQUEST,
+ SCSI_ASC_INVALID_FIELD_IN_CDB,
+ SCSI_ASCQ_INVALID_FIELD_IN_CDB
+ );
+ return SATI_FAILURE_CHECK_RESPONSE_DATA;
+ }
+
+ // get the amount of data being sent from the cdb
+ cdb = sati_cb_get_cdb_address(scsi_io);
+ unmap_length = (sati_get_cdb_byte(cdb, 7) << 8) | sati_get_cdb_byte(cdb, 8);
+
+ // If nothing has been requested return success now.
+ if (unmap_length == 0)
+ {
+ // SAT: This is not an error
+ return SATI_SUCCESS;
+ }
+ if (unmap_length < SATI_UNMAP_SIZEOF_SCSI_UNMAP_PARAMETER_LIST)
+ {
+ // Not enough length specified in the CDB
+ sati_scsi_sense_data_construct(
+ sequence,
+ scsi_io,
+ SCSI_STATUS_CHECK_CONDITION,
+ SCSI_SENSE_ILLEGAL_REQUEST,
+ SCSI_ASC_INVALID_FIELD_IN_CDB,
+ SCSI_ASCQ_INVALID_FIELD_IN_CDB
+ );
+ return SATI_FAILURE_CHECK_RESPONSE_DATA;
+ }
+
+ sequence->allocation_length = unmap_length;
+
+ // Get the unmap parameter header
+ for(index = 0; index < SATI_UNMAP_SIZEOF_SCSI_UNMAP_PARAMETER_LIST; index++)
+ {
+ sati_get_data_byte(sequence, scsi_io, index, &unmap_param_list[index]);
+ }
+ descriptor_length = (unmap_param_list[2] << 8) | unmap_param_list[3];
+
+ // Check length again
+ if (descriptor_length == 0)
+ {
+ // SAT: This is not an error
+ return SATI_SUCCESS;
+ }
+
+ if ((U32)(unmap_length - SATI_UNMAP_SIZEOF_SCSI_UNMAP_PARAMETER_LIST) < descriptor_length)
+ {
+ // Not enough length specified in the CDB
+ sati_scsi_sense_data_construct(
+ sequence,
+ scsi_io,
+ SCSI_STATUS_CHECK_CONDITION,
+ SCSI_SENSE_ILLEGAL_REQUEST,
+ SCSI_ASC_INVALID_FIELD_IN_CDB,
+ SCSI_ASCQ_INVALID_FIELD_IN_CDB
+ );
+ return SATI_FAILURE_CHECK_RESPONSE_DATA;
+ }
+
+ // Save the maximum unmap block descriptors in this request
+ unmap_process_state->max_unmap_block_descriptors =
+ descriptor_length/SATI_UNMAP_SIZEOF_SCSI_UNMAP_BLOCK_DESCRIPTOR;
+
+ // Determine the maximum size of the write buffer that will be required
+ // for the translation in terms of number of blocks
+ max_dsm_blocks = sati_unmap_get_max_buffer_size_in_blocks(sequence);
+
+ // Save the maximum number of DSM descriptors we can send during the translation
+ unmap_process_state->max_lba_range_entries =
+ (max_dsm_blocks*sequence->device->logical_block_size)/sizeof(TRIM_PAIR);
+
+ // Get the write buffer for the translation
+ sati_cb_allocate_dma_buffer(
+ scsi_io,
+ max_dsm_blocks*sequence->device->logical_block_size,
+ &(unmap_process_state->virtual_unmap_buffer),
+ &(unmap_process_state->physical_unmap_buffer_low),
+ &(unmap_process_state->physical_unmap_buffer_high));
+
+ // Makes sure we have a buffer
+ if (unmap_process_state->virtual_unmap_buffer == NULL)
+ {
+ // Resource failure
+ sati_scsi_sense_data_construct(
+ sequence,
+ scsi_io,
+ SCSI_STATUS_CHECK_CONDITION,
+ SCSI_SENSE_ABORTED_COMMAND,
+ SCSI_ASC_NO_ADDITIONAL_SENSE,
+ SCSI_ASCQ_NO_ADDITIONAL_SENSE
+ );
+ return SATI_FAILURE_CHECK_RESPONSE_DATA;
+ }
+
+ // Get the first SGL entry. This code will only use one 4K page so will
+ // only utilize the first sge.
+ sati_cb_sgl_next_sge(scsi_io,
+ ata_io,
+ NULL,
+ &(unmap_process_state->unmap_buffer_sgl_pair));
+
+ // Load the first descriptor to start the translation loop
+ unmap_process_state->current_unmap_block_descriptor_index =
+ SATI_UNMAP_SIZEOF_SCSI_UNMAP_PARAMETER_LIST;
+ sati_unmap_load_next_descriptor(sequence,scsi_io);
+
+ // Next state will be incomplete since translation
+ // will require a callback and possibly more requests.
+ sequence->state = SATI_SEQUENCE_STATE_INCOMPLETE;
+
+ return SATI_COMPLETE;
+}
+
+/**
+ * @brief This method will process each unmap sequence.
+ *
+ * @return Indicate if the translation was successful.
+ * @retval SATI_SUCCESS
+ */
+SATI_STATUS sati_unmap_process(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ void * ata_io
+)
+{
+ SATI_UNMAP_PROCESSING_STATE_T * unmap_process_state;
+ SATI_LBA dsm_descriptor_lba_count;
+ U32 dsm_descriptor;
+ U32 dsm_bytes;
+ U32 dsm_remainder_bytes;
+ U32 dsm_blocks;
+ U32 max_dsm_blocks;
+
+ unmap_process_state = &sequence->command_specific_data.unmap_process_state;
+
+ // Set up the starting address of the buffer for this portion of the translation
+ unmap_process_state->current_dsm_descriptor = unmap_process_state->virtual_unmap_buffer;
+ dsm_descriptor = 0;
+
+ // Translate as much as we can
+ while ((dsm_descriptor < unmap_process_state->max_lba_range_entries) &&
+ (unmap_process_state->current_lba_count > 0)) {
+ // See if the LBA count will fit in to a single descriptor
+ if (unmap_process_state->current_lba_count > SATI_DSM_MAX_SECTOR_COUNT) {
+ // Can't fit all of the lbas for this descriptor in to
+ // one DSM request. Adjust the current LbaCount and total
+ // remaining for the next descriptor
+ dsm_descriptor_lba_count = SATI_DSM_MAX_SECTOR_COUNT;
+ unmap_process_state->current_lba_count -= SATI_DSM_MAX_SECTOR_COUNT;
+ unmap_process_state->next_lba =
+ unmap_process_state->current_lba + SATI_DSM_MAX_SECTOR_COUNT;
+ } else {
+ // It all fits in to one descriptor
+ dsm_descriptor_lba_count = unmap_process_state->current_lba_count;
+ unmap_process_state->current_lba_count = 0;
+ }
+
+ // Fill in the ATA DSM descriptor
+ ((PTRIM_PAIR)(unmap_process_state->current_dsm_descriptor))->sector_address =
+ unmap_process_state->current_lba;
+ ((PTRIM_PAIR)(unmap_process_state->current_dsm_descriptor))->sector_count =
+ dsm_descriptor_lba_count;
+
+ // See if we can move on to the next descriptor
+ if (unmap_process_state->current_lba_count == 0) {
+ // See if there is another descriptor
+ --unmap_process_state->max_unmap_block_descriptors;
+ if (unmap_process_state->max_unmap_block_descriptors > 0) {
+ // Move on to the next descriptor
+ sati_unmap_load_next_descriptor(sequence,scsi_io);
+ }
+ } else {
+ // Move to the next LBA in this descriptor
+ unmap_process_state->current_lba = unmap_process_state->next_lba;
+ }
+
+ // Make sure the LBA does not exceed 48 bits...
+ ASSERT(unmap_process_state->current_lba <= SATI_DSM_MAX_SECTOR_ADDRESS);
+
+ // Increment the number of descriptors used and point to the next entry
+ dsm_descriptor++;
+ unmap_process_state->current_dsm_descriptor =
+ (U8 *)(unmap_process_state->current_dsm_descriptor) + sizeof(TRIM_PAIR);
+ }
+
+ // Calculate number of blocks we have filled in
+ dsm_blocks = sati_unmap_calculate_dsm_blocks(sequence,dsm_descriptor);
+ dsm_bytes = dsm_blocks * sequence->device->logical_block_size;
+ max_dsm_blocks = sati_unmap_get_max_buffer_size_in_blocks(sequence);
+
+ // The current_dsm_descriptor points to the next location in the buffer
+ // Get the remaining bytes from the last translated descriptor
+ // to the end of the 4k buffer.
+ dsm_remainder_bytes = sequence->device->logical_block_size;
+ dsm_remainder_bytes -= (U32)((POINTER_UINT)unmap_process_state->current_dsm_descriptor &
+ (sequence->device->logical_block_size-1));
+
+ // If there was no remainder, the complete buffer was filled in.
+ if (dsm_remainder_bytes != sequence->device->logical_block_size)
+ {
+ // Add on the remaining unfilled blocks
+ dsm_remainder_bytes += (sequence->device->logical_block_size * (max_dsm_blocks - dsm_blocks));
+
+ // According to ATA-8, if the DSM buffer is not completely filled with
+ // valid DSM descriptor data, the remaining portion of the
+ // buffer must be filled in with zeros.
+ memset((U8 *)unmap_process_state->current_dsm_descriptor, 0, dsm_remainder_bytes);
+ }
+
+ // Tell scic to utilize this sgl pair for write DMA processing of
+ // the SCSI UNMAP translation with the total number of bytes for this transfer
+ sati_cb_sge_write(unmap_process_state->unmap_buffer_sgl_pair,
+ unmap_process_state->physical_unmap_buffer_low,
+ unmap_process_state->physical_unmap_buffer_high,
+ dsm_bytes);
+
+ // Construct the unmap ATA request
+ sati_unmap_construct(sequence,
+ scsi_io,
+ ata_io,
+ dsm_blocks);
+
+ // Determine sequence next state based on whether there is more translation
+ // to complete
+ if (unmap_process_state->current_lba_count == 0)
+ {
+ // used for completion routine to determine if there is more processing
+ sequence->state = SATI_SEQUENCE_STATE_FINAL;
+ }
+ // This requests has already translated the SGL, have SCIC skip SGL translataion
+ return SATI_SUCCESS_SGL_TRANSLATED;
+}
+
+//******************************************************************************
+//* P U B L I C M E T H O D S
+//******************************************************************************
+
+/**
+ * @brief This method will handle termination of the
+ * SCSI unmap translation and frees previously allocated
+ * dma buffer.
+ *
+ * @return None
+ */
+void sati_unmap_terminate(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ void * ata_io
+)
+{
+ SATI_UNMAP_PROCESSING_STATE_T * unmap_process_state;
+ unmap_process_state = &sequence->command_specific_data.unmap_process_state;
+
+ if (unmap_process_state->virtual_unmap_buffer != NULL)
+ {
+ sati_cb_free_dma_buffer(scsi_io, unmap_process_state->virtual_unmap_buffer);
+ unmap_process_state->virtual_unmap_buffer = NULL;
+ }
+}
+
+/**
+ * @brief This method will translate the SCSI Unmap command
+ * into corresponding ATA commands. Depending upon the capabilities
+ * supported by the target different ATA commands can be selected.
+ * Additionally, in some cases more than a single ATA command may
+ * be required.
+ *
+ * @return Indicate if the command translation succeeded.
+ * @retval SATI_SUCCESS This is returned if the command translation was
+ * successful.
+ * @retval SATI_COMPLETE This is returned if the command translation was
+ * successful and no ATA commands need to be set.
+ * @retval SATI_FAILURE_CHECK_RESPONSE_DATA This value is returned if
+ * sense data has been created as a result of something specified
+ * in the parameter data fields.
+ */
+SATI_STATUS sati_unmap_translate_command(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ void * ata_io
+)
+{
+ SATI_STATUS status = SATI_FAILURE_CHECK_RESPONSE_DATA;
+ SATI_UNMAP_PROCESSING_STATE_T * unmap_process_state;
+
+ unmap_process_state = &sequence->command_specific_data.unmap_process_state;
+
+ // Determine if this is the first step in the unmap sequence
+ if ( sequence->state == SATI_SEQUENCE_STATE_INITIAL )
+ {
+ status = sati_unmap_initial_processing(sequence,scsi_io,ata_io);
+ if (status != SATI_COMPLETE)
+ {
+ return status;
+ }
+ }
+ // Translate the next portion of the UNMAP request
+ return sati_unmap_process(sequence, scsi_io, ata_io);
+}
+
+/**
+ * @brief This method will translate the ATA command register FIS
+ * response into an appropriate SCSI response for Unmap.
+ * For more information on the parameters passed to this method,
+ * please reference sati_translate_response().
+ *
+ * @return Indicate if the response translation succeeded.
+ * @retval SATI_SUCCESS This is returned if the command translation was
+ * successful.
+ * @retval SATI_COMPLETE This is returned if the command translation was
+ * successful and no ATA commands need to be set.
+ * @retval SATI_FAILURE_CHECK_RESPONSE_DATA This value is returned if
+ * sense data has been created as a result of something specified
+ * in the parameter data fields.
+ */
+SATI_STATUS sati_unmap_translate_response(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ void * ata_io
+)
+{
+ U8 * register_fis = sati_cb_get_d2h_register_fis_address(ata_io);
+ SATI_UNMAP_PROCESSING_STATE_T * unmap_process_state;
+ SATI_STATUS sati_status = SATI_COMPLETE;
+
+ unmap_process_state = &sequence->command_specific_data.unmap_process_state;
+
+ if (sati_get_ata_status(register_fis) & ATA_STATUS_REG_ERROR_BIT)
+ {
+ sequence->state = SATI_SEQUENCE_STATE_FINAL;
+ sati_scsi_sense_data_construct(
+ sequence,
+ scsi_io,
+ SCSI_STATUS_CHECK_CONDITION,
+ SCSI_SENSE_ABORTED_COMMAND,
+ SCSI_ASC_NO_ADDITIONAL_SENSE,
+ SCSI_ASCQ_NO_ADDITIONAL_SENSE
+ );
+ // All done, terminate the translation
+ sati_unmap_terminate(sequence, scsi_io, ata_io);
+ }
+ else
+ {
+ if (sequence->state != SATI_SEQUENCE_STATE_INCOMPLETE)
+ {
+ // All done, terminate the translation
+ sati_unmap_terminate(sequence, scsi_io, ata_io);
+ }
+ else
+ {
+ // Still translating
+ sati_status = SATI_SEQUENCE_STATE_INCOMPLETE;
+ }
+ }
+ return sati_status;
+}
+
+#endif // !defined(DISABLE_SATI_UNMAP)
diff --git a/sys/dev/isci/scil/sati_unmap.h b/sys/dev/isci/scil/sati_unmap.h
new file mode 100644
index 0000000..1b5ffb2
--- /dev/null
+++ b/sys/dev/isci/scil/sati_unmap.h
@@ -0,0 +1,135 @@
+/*-
+ * 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.
+ *
+ * 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.
+ *
+ * $FreeBSD$
+ */
+#ifndef _SATI_UNMAP_H_
+#define _SATI_UNMAP_H_
+
+/**
+ * @file
+ * @brief This file contains the method implementations required to
+ * translate the SCSI reassign blocks command.
+ */
+
+#if !defined(DISABLE_SATI_UNMAP)
+
+#include <dev/isci/scil/sati_types.h>
+#include <dev/isci/scil/sati_translator_sequence.h>
+
+#define SATI_DSM_MAX_SECTOR_COUNT 0xFFFF
+#define SATI_DSM_MAX_SECTOR_ADDRESS 0xFFFFFFFFFFFF
+#define SATI_DSM_MAX_BUFFER_SIZE 4096
+
+#define SATI_UNMAP_SIZEOF_SCSI_UNMAP_BLOCK_DESCRIPTOR 16
+#define SATI_UNMAP_SIZEOF_SCSI_UNMAP_PARAMETER_LIST 8
+
+typedef struct _TRIM_PAIR
+{
+ U64 sector_address:48;
+ U64 sector_count:16;
+} TRIM_PAIR, *PTRIM_PAIR;
+
+U32 sati_unmap_calculate_dsm_blocks(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ U32 dsm_descriptor_count
+);
+
+SATI_STATUS sati_unmap_construct(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ void * ata_io,
+ U32 sector_count
+);
+
+SATI_STATUS sati_unmap_load_next_descriptor(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io
+);
+
+U32 sati_unmap_get_max_buffer_size_in_blocks(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence
+);
+
+SATI_STATUS sati_unmap_initial_processing(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ void * ata_io
+);
+
+SATI_STATUS sati_unmap_process(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ void * ata_io
+);
+
+SATI_STATUS sati_unmap_translate_command(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ void * ata_io
+);
+
+SATI_STATUS sati_unmap_translate_response(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ void * ata_io
+);
+
+void sati_unmap_terminate(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ void * ata_io
+);
+#else // !defined(DISABLE_SATI_UNMAP)
+#define sati_unmap_terminate(sequence,scsi_io,ata_io)
+#endif // !defined(DISABLE_SATI_UNMAP)
+
+#endif // _SATI_UNMAP_H_
diff --git a/sys/dev/isci/scil/sati_util.c b/sys/dev/isci/scil/sati_util.c
new file mode 100644
index 0000000..a161c58
--- /dev/null
+++ b/sys/dev/isci/scil/sati_util.c
@@ -0,0 +1,2005 @@
+/*-
+ * 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.
+ *
+ * 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 <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/**
+ * @file
+ * @brief This file contains all of the method implementations that
+ * provide generic support for SATI. Some methods can be utilized
+ * by a user to construct ATA/ATAPI commands, copy ATA device
+ * structure data, fill in sense data, etc.
+ */
+
+#include <dev/isci/scil/sati_util.h>
+#include <dev/isci/scil/sati_callbacks.h>
+#include <dev/isci/scil/intel_scsi.h>
+#include <dev/isci/scil/intel_ata.h>
+#include <dev/isci/scil/intel_sat.h>
+#include <dev/isci/scil/intel_sas.h>
+
+/**
+ * @brief This method will set the data direction, protocol, and transfer
+ * kength for an ATA non-data command.
+ *
+ * @pre It is expected that the user will use this method for setting these
+ * values in a non-data ATA command constuct.
+ *
+ * @param[out] ata_io This parameter specifies the ATA IO request structure
+ * for which to build the IDENTIFY DEVICE command.
+ * @param[in] sequence This parameter specifies the translator sequence
+ * for which the command is being constructed.
+ *
+ * @return none.
+ */
+void sati_ata_non_data_command(
+ void * ata_io,
+ SATI_TRANSLATOR_SEQUENCE_T * sequence
+)
+{
+ sequence->data_direction = SATI_DATA_DIRECTION_NONE;
+ sequence->protocol = SAT_PROTOCOL_NON_DATA;
+ sequence->ata_transfer_length = 0;
+}
+
+/**
+ * @brief This method will construct the ATA identify device command.
+ *
+ * @pre It is expected that the user has properly set the current contents
+ * of the register FIS to 0.
+ *
+ * @param[out] ata_io This parameter specifies the ATA IO request structure
+ * for which to build the IDENTIFY DEVICE command.
+ * @param[in] sequence This parameter specifies the translator sequence
+ * for which the command is being constructed.
+ *
+ * @return none.
+ */
+void sati_ata_identify_device_construct(
+ void * ata_io,
+ SATI_TRANSLATOR_SEQUENCE_T * sequence
+)
+{
+ U8 * register_fis = sati_cb_get_h2d_register_fis_address(ata_io);
+
+ sati_set_ata_command(register_fis, ATA_IDENTIFY_DEVICE);
+ sequence->data_direction = SATI_DATA_DIRECTION_IN;
+ sequence->protocol = SAT_PROTOCOL_PIO_DATA_IN;
+ sequence->ata_transfer_length = sizeof(ATA_IDENTIFY_DEVICE_DATA_T);
+}
+
+/**
+* @brief This method will construct the ATA Execute Device Diagnostic command.
+*
+* @param[out] ata_io This parameter specifies the ATA IO request structure
+* for which to build the IDENTIFY DEVICE command.
+* @param[in] sequence This parameter specifies the translator sequence
+* for which the command is being constructed.
+*
+* @return none.
+*/
+void sati_ata_execute_device_diagnostic_construct(
+ void * ata_io,
+ SATI_TRANSLATOR_SEQUENCE_T * sequence
+)
+{
+ U8 * register_fis = sati_cb_get_h2d_register_fis_address(ata_io);
+
+ sati_set_ata_command(register_fis, ATA_EXECUTE_DEVICE_DIAG);
+
+ sequence->data_direction = SATI_DATA_DIRECTION_IN;
+ sequence->protocol = SAT_PROTOCOL_DEVICE_DIAGNOSTIC;
+ sequence->ata_transfer_length = 16;
+}
+
+/**
+ * @brief This method will set data bytes in the user data area. If the
+ * caller requests it, the data written will be forced to ascii
+ * printable characters if it isn't already a printable character.
+ * A printable character is considered to be >= 0x20 and <= 0x70.
+ *
+ * @param[in] sequence This parameter specifies the translation sequence
+ * for which to copy and swap the data.
+ * @param[out] destination_scsi_io This parameter specifies the SCSI IO
+ * request containing the destination buffer into which to copy.
+ * @param[in] destination_offset This parameter specifies the offset into
+ * the data buffer where the information will be copied to.
+ * @param[in] source_value This parameter specifies the value retrieved
+ * from the source buffer that is to be copied into the user
+ * buffer area.
+ * @param[in] use_printable_chars This parameter indicates if the copy should
+ * ensure that the value copied is considered an ASCII printable
+ * character (e.g. A, B, " ", etc.). These characters reside
+ * in the 0x20 - 0x7E ASCII range.
+ *
+ * @return none
+ */
+static
+void sati_set_ascii_data_byte(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * destination_scsi_io,
+ U32 destination_offset,
+ U8 source_value,
+ BOOL use_printable_chars
+)
+{
+ // if the user requests that the copied data be ascii printable, then
+ // default to " " (i.e. 0x20) for all non-ascii printable characters.
+ if((use_printable_chars == TRUE)
+ && ((source_value < 0x20) || (source_value > 0x7E)))
+ {
+ source_value = 0x20;
+ }
+
+ sati_set_data_byte(
+ sequence, destination_scsi_io, destination_offset, source_value
+ );
+}
+
+/**
+ * @brief This method performs a copy operation using an offset into the
+ * source buffer, an offset into the destination buffer, and a length.
+ * It will perform the byte swap from the 16-bit identify field
+ * into the network byte order SCSI location.
+ *
+ * @param[in] sequence This parameter specifies the translation sequence
+ * for which to copy and swap the data.
+ * @param[out] destination_scsi_io This parameter specifies the SCSI IO
+ * request containing the destination buffer into which to copy.
+ * @param[in] destination_offset This parameter specifies the offset into
+ * the data buffer where the information will be copied to.
+ * @param[in] source_buffer This parameter specifies the source buffer from
+ * which the data will be copied.
+ * @param[in] source_offset This parameter specifies the offset into the
+ * source buffer where the copy shall begin.
+ * @param[in] length This parameter specifies the number of bytes to copy
+ * during this operation.
+ * @param[in] use_printable_chars This parameter indicates if the copy should
+ * ensure that the value copied is considered an ASCII printable
+ * character (e.g. A, B, " ", etc.). These characters reside
+ * in the 0x20 - 0x7E ASCII range.
+ *
+ * @return none
+ */
+void sati_ata_identify_device_copy_data(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * destination_scsi_io,
+ U32 destination_offset,
+ U8 * source_buffer,
+ U32 source_offset,
+ U32 length,
+ BOOL use_printable_chars
+)
+{
+ source_buffer += source_offset;
+ while (length > 0)
+ {
+ sati_set_ascii_data_byte(
+ sequence,
+ destination_scsi_io,
+ destination_offset,
+ *(source_buffer+1),
+ use_printable_chars
+ );
+
+ sati_set_ascii_data_byte(
+ sequence,
+ destination_scsi_io,
+ destination_offset+1,
+ *source_buffer,
+ use_printable_chars
+ );
+
+ destination_offset += 2;
+ source_buffer += 2;
+ length -= 2;
+ }
+}
+
+/**
+ * @brief This method performs a copy operation using a source buffer,
+ * an offset into the destination buffer, and a length.
+ *
+ * @param[in] sequence This parameter specifies the translation sequence
+ * for which to copy and swap the data.
+ * @param[out] destination_scsi_io This parameter specifies the SCSI IO
+ * request containing the destination buffer into which to copy.
+ * @param[in] destination_offset This parameter specifies the offset into
+ * the data buffer where the information will be copied to.
+ * @param[in] source_buffer This parameter specifies the source buffer from
+ * which the data will be copied.
+ * @param[in] length This parameter specifies the number of bytes to copy
+ * during this operation.
+ *
+ * @return none
+ */
+void sati_copy_data(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * destination_scsi_io,
+ U32 destination_offset,
+ U8 * source_buffer,
+ U32 length
+)
+{
+ while (length > 0)
+ {
+ sati_set_data_byte(
+ sequence, destination_scsi_io, destination_offset, *source_buffer
+ );
+
+ destination_offset++;
+ source_buffer++;
+ length--;
+ }
+}
+
+/**
+ * @brief This method extracts the Logical Block Address high and low 32-bit
+ * values and the sector count 32-bit value from the ATA identify
+ * device data.
+ *
+ * @param[in] identify This parameter specifies the ATA_IDENTIFY_DEVICE_DATA
+ * from which to extract the sector information.
+ * @param[out] lba_high This parameter specifies the upper 32 bits for the
+ * number of logical block addresses for the device. The upper
+ * 16-bits should always be 0, since 48-bits of LBA is the most
+ * supported by an ATA device.
+ * @param[out] lba_low This parameter specifies the lower 32 bits for the
+ * number of logical block addresses for the device.
+ * @param[out] sector_size This parameter specifies the 32-bits of sector
+ * size. If the ATA device doesn't support reporting it's
+ * sector size, then 512 bytes is utilized as the default value.
+ *
+ * @return none
+ */
+void sati_ata_identify_device_get_sector_info(
+ ATA_IDENTIFY_DEVICE_DATA_T * identify,
+ U32 * lba_high,
+ U32 * lba_low,
+ U32 * sector_size
+)
+{
+ // Calculate the values to be returned
+ // Calculation will be different if the SATA device supports
+ // 48-bit addressing. Bit 10 of Word 86 of ATA Identify
+ if (identify->command_set_enabled1
+ & ATA_IDENTIFY_COMMAND_SET_SUPPORTED1_48BIT_ENABLE)
+ {
+ // This drive supports 48-bit addressing
+
+ *lba_high = identify->max_48bit_lba[7] << 24;
+ *lba_high |= identify->max_48bit_lba[6] << 16;
+ *lba_high |= identify->max_48bit_lba[5] << 8;
+ *lba_high |= identify->max_48bit_lba[4];
+
+ *lba_low = identify->max_48bit_lba[3] << 24;
+ *lba_low |= identify->max_48bit_lba[2] << 16;
+ *lba_low |= identify->max_48bit_lba[1] << 8;
+ *lba_low |= identify->max_48bit_lba[0];
+ }
+ else
+ {
+ // This device doesn't support 48-bit addressing
+ // Pull out the largest LBA from words 60 and 61.
+ *lba_high = 0;
+ *lba_low = identify->total_num_sectors[3] << 24;
+ *lba_low |= identify->total_num_sectors[2] << 16;
+ *lba_low |= identify->total_num_sectors[1] << 8;
+ *lba_low |= identify->total_num_sectors[0];
+ }
+
+ // If the ATA device reports its sector size (bit 12 of Word 106),
+ // then use that instead.
+ if (identify->physical_logical_sector_info
+ & ATA_IDENTIFY_SECTOR_LARGER_THEN_512_ENABLE)
+ {
+ *sector_size = identify->words_per_logical_sector[3] << 24;
+ *sector_size |= identify->words_per_logical_sector[2] << 16;
+ *sector_size |= identify->words_per_logical_sector[1] << 8;
+ *sector_size |= identify->words_per_logical_sector[0];
+ }
+ else
+ {
+ // Default the sector size to 512 bytes
+ *sector_size = 512;
+ }
+}
+
+/**
+ * @brief This method will construct the ATA check power mode command.
+ *
+ * @pre It is expected that the user has properly set the current contents
+ * of the register FIS to 0.
+ *
+ * @param[out] ata_io This parameter specifies the ATA IO request structure
+ * for which to build the CHECK POWER MODE command.
+ * @param[in] sequence This parameter specifies the translator sequence
+ * for which the command is being constructed.
+ *
+ * @return none.
+ */
+void sati_ata_check_power_mode_construct(
+ void * ata_io,
+ SATI_TRANSLATOR_SEQUENCE_T * sequence
+)
+{
+ U8 * register_fis = sati_cb_get_h2d_register_fis_address(ata_io);
+
+ sati_set_ata_command(register_fis, ATA_CHECK_POWER_MODE);
+ sati_ata_non_data_command(ata_io, sequence);
+}
+
+/**
+ * @brief This method is utilized to set a specific byte in the sense
+ * data area. It will ensure that the supplied byte offset
+ * isn't larger then the length of the requested sense data.
+ *
+ * @param[in] scsi_io This parameter specifies the user SCSI IO request
+ * for which to set the sense data byte.
+ * @param[in] byte_offset This parameter specifies the byte offset into
+ * the sense data buffer where the data should be written.
+ * @param[in] value This parameter specifies the 8-bit value to be written
+ * into the sense data area.
+ *
+ * @return none
+ */
+void sati_set_sense_data_byte(
+ U8 * sense_data,
+ U32 max_sense_data_len,
+ U32 byte_offset,
+ U8 value
+)
+{
+ // Ensure that we don't attempt to write past the end of the sense
+ // data buffer.
+ if (byte_offset < max_sense_data_len)
+ sense_data[byte_offset] = value;
+}
+
+/**
+ * @brief This method will construct the common response IU in the user
+ * request's response IU location.
+ *
+ * @param[out] rsp_iu This parameter specifies the user request's
+ * response IU to be constructed.
+ * @param[in] scsi_status This parameter specifies the SCSI status
+ * value for the user's IO request.
+ * @param[in] sense_data_length This parameter specifies the sense data
+ * length for response IU.
+ * @param[in] data_present The parameter specifies the specific
+ * data present value for response IU.
+ *
+ * @return none
+ */
+void sati_scsi_common_response_iu_construct(
+ SCI_SSP_RESPONSE_IU_T * rsp_iu,
+ U8 scsi_status,
+ U8 sense_data_length,
+ U8 data_present
+)
+{
+ rsp_iu->sense_data_length[3] = sense_data_length;
+ rsp_iu->sense_data_length[2] = 0;
+ rsp_iu->sense_data_length[1] = 0;
+ rsp_iu->sense_data_length[0] = 0;
+ rsp_iu->status = scsi_status;
+ rsp_iu->data_present = data_present;
+}
+
+/**
+ * @brief This method will construct the buffer for sense data
+ * sense data buffer location. Additionally, it will set the user's
+ * SCSI status.
+ *
+ * @param[in,out] scsi_io This parameter specifies the user's IO request
+ * for which to construct the buffer for sense data.
+ * @param[in] scsi_status This parameter specifies the SCSI status
+ * value for the user's IO request.
+ * @param[out] sense_data This paramater
+ *
+ * @return none
+ */
+static
+void sati_scsi_get_sense_data_buffer(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ U8 scsi_status,
+ U8 ** sense_data,
+ U32 * sense_len)
+{
+#ifdef SATI_TRANSPORT_SUPPORTS_SAS
+ SCI_SSP_RESPONSE_IU_T * rsp_iu = (SCI_SSP_RESPONSE_IU_T*)
+ sati_cb_get_response_iu_address(scsi_io);
+
+ sati_scsi_common_response_iu_construct(
+ rsp_iu,
+ scsi_status,
+ sati_scsi_get_sense_data_length(sequence, scsi_io),
+ SCSI_RESPONSE_DATA_PRES_SENSE_DATA
+ );
+
+ *sense_data = (U8*) rsp_iu->data;
+ *sense_len = SSP_RESPONSE_IU_MAX_DATA * 4; // dwords to bytes
+#else
+ *sense_data = sati_cb_get_sense_data_address(scsi_io);
+ *sense_len = sati_cb_get_sense_data_length(scsi_io);
+ sati_cb_set_scsi_status(scsi_io, scsi_status);
+#endif // SATI_TRANSPORT_SUPPORTS_SAS
+}
+
+/**
+ * @brief This method extract response code based on on device settings.
+ *
+ * @return response code
+ */
+static
+U8 sati_scsi_get_sense_data_response_code(SATI_TRANSLATOR_SEQUENCE_T * sequence)
+{
+ if (sequence->device->descriptor_sense_enable)
+ {
+ return SCSI_DESCRIPTOR_CURRENT_RESPONSE_CODE;
+ }
+ else
+ {
+ return SCSI_FIXED_CURRENT_RESPONSE_CODE;
+ }
+}
+
+/**
+ * @brief This method will return length of descriptor sense data for executed command.
+ *
+ * @return sense data length
+ */
+static
+U8 sati_scsi_get_descriptor_sense_data_length(SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io)
+{
+ U8 * cdb = sati_cb_get_cdb_address(scsi_io);
+ //Initial value is descriptor header length
+ U8 length = 8;
+
+ switch (sati_get_cdb_byte(cdb, 0))
+ {
+#if !defined(DISABLE_SATI_WRITE_LONG)
+ case SCSI_WRITE_LONG_10:
+ case SCSI_WRITE_LONG_16:
+ length += SCSI_BLOCK_DESCRIPTOR_LENGTH +
+ SCSI_INFORMATION_DESCRIPTOR_LENGTH;
+ break;
+#endif // !defined(DISABLE_SATI_WRITE_LONG)
+#if !defined(DISABLE_SATI_REASSIGN_BLOCKS)
+ case SCSI_REASSIGN_BLOCKS:
+ length += SCSI_CMD_SPECIFIC_DESCRIPTOR_LENGTH +
+ SCSI_INFORMATION_DESCRIPTOR_LENGTH;
+ break;
+#endif // !defined(DISABLE_SATI_REASSIGN_BLOCKS)
+ case SCSI_READ_6:
+ case SCSI_READ_10:
+ case SCSI_READ_12:
+ case SCSI_READ_16:
+ case SCSI_WRITE_6:
+ case SCSI_WRITE_10:
+ case SCSI_WRITE_12:
+ case SCSI_WRITE_16:
+#if !defined(DISABLE_SATI_VERIFY)
+ case SCSI_VERIFY_10:
+ case SCSI_VERIFY_12:
+ case SCSI_VERIFY_16:
+#endif // !defined(DISABLE_SATI_VERIFY)
+#if !defined(DISABLE_SATI_WRITE_AND_VERIFY) \
+ && !defined(DISABLE_SATI_VERIFY) \
+ && !defined(DISABLE_SATI_WRITE)
+
+ case SCSI_WRITE_AND_VERIFY_10:
+ case SCSI_WRITE_AND_VERIFY_12:
+ case SCSI_WRITE_AND_VERIFY_16:
+#endif // !defined(DISABLE_SATI_WRITE_AND_VERIFY)
+ // && !defined(DISABLE_SATI_VERIFY)
+ // && !defined(DISABLE_SATI_WRITE)
+ length += SCSI_INFORMATION_DESCRIPTOR_LENGTH;
+ break;
+ }
+
+ return length;
+}
+
+/**
+ * @brief This method will return length of sense data.
+ *
+ * @return sense data length
+ */
+U8 sati_scsi_get_sense_data_length(SATI_TRANSLATOR_SEQUENCE_T * sequence, void * scsi_io)
+{
+ U8 response_code;
+
+ response_code = sati_scsi_get_sense_data_response_code(sequence);
+
+ switch (response_code)
+ {
+ case SCSI_FIXED_CURRENT_RESPONSE_CODE:
+ case SCSI_FIXED_DEFERRED_RESPONSE_CODE:
+ return SCSI_FIXED_SENSE_DATA_BASE_LENGTH;
+ break;
+ case SCSI_DESCRIPTOR_CURRENT_RESPONSE_CODE:
+ case SCSI_DESCRIPTOR_DEFERRED_RESPONSE_CODE:
+ return sati_scsi_get_descriptor_sense_data_length(sequence, scsi_io);
+ break;
+ }
+
+ return SCSI_FIXED_SENSE_DATA_BASE_LENGTH;
+}
+
+/**
+ * @brief This method will construct the sense data buffer in the user's
+ * sense data buffer location. Additionally, it will set the user's
+ * SCSI status.
+ *
+ * @param[in] sequence This parameter specifies the translation sequence
+ * for which to construct the sense data.
+ * @param[in,out] scsi_io This parameter specifies the user's IO request
+ * for which to construct the sense data.
+ * @param[in] scsi_status This parameter specifies the SCSI status
+ * value for the user's IO request.
+ * @param[in] sense_key This parameter specifies the sense key to
+ * be set for the user's IO request.
+ * @param[in] additional_sense_code This parameter specifies the
+ * additional sense code (ASC) key to be set for the user's
+ * IO request.
+ * @param[in] additional_sense_code_qualifier This parameter specifies
+ * the additional sense code qualifier (ASCQ) key to be set
+ * for the user's IO request.
+ *
+ * @return none
+ */
+void sati_scsi_sense_data_construct(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ U8 scsi_status,
+ U8 sense_key,
+ U8 additional_sense_code,
+ U8 additional_sense_code_qualifier
+)
+{
+ U8 response_code;
+
+ response_code = sati_scsi_get_sense_data_response_code(sequence);
+
+ switch (response_code)
+ {
+ case SCSI_FIXED_CURRENT_RESPONSE_CODE:
+ case SCSI_FIXED_DEFERRED_RESPONSE_CODE:
+ sati_scsi_fixed_sense_data_construct(sequence, scsi_io, scsi_status, response_code,
+ sense_key, additional_sense_code, additional_sense_code_qualifier);
+ break;
+ case SCSI_DESCRIPTOR_CURRENT_RESPONSE_CODE:
+ case SCSI_DESCRIPTOR_DEFERRED_RESPONSE_CODE:
+ sati_scsi_descriptor_sense_data_construct(sequence, scsi_io, scsi_status, response_code,
+ sense_key, additional_sense_code, additional_sense_code_qualifier);
+ break;
+ }
+
+ sequence->is_sense_response_set = TRUE;
+}
+
+/**
+ * @brief This method will construct the block descriptor in the user's descriptor
+ * sense data buffer location.
+ *
+ * @param[in] sense_data This parameter specifies the user SCSI IO request
+ * for which to set the sense data byte.
+ * @param[in] sense_len This parameter specifies length of the sense data
+ * to be returned by SATI.
+ * @param[out] descriptor_len This parameter returns the length of constructed
+ * descriptor.
+ *
+ * @return none
+ */
+static
+void sati_scsi_block_descriptor_construct(
+ U8 * sense_data,
+ U32 sense_len)
+{
+ U8 ili = 1;
+
+ sati_set_sense_data_byte(sense_data, sense_len, 0, SCSI_BLOCK_DESCRIPTOR_TYPE);
+ sati_set_sense_data_byte(sense_data, sense_len, 1, SCSI_BLOCK_DESCRIPTOR_ADDITIONAL_LENGTH);
+ sati_set_sense_data_byte(sense_data, sense_len, 2, 0);
+ sati_set_sense_data_byte(sense_data, sense_len, 3, (ili << 5));
+}
+
+/**
+ * @brief This method will construct the command-specific descriptor for
+ * the descriptor sense data buffer in the user's sense data buffer
+ * location.
+ *
+ * @param[in] sense_data This parameter specifies the user SCSI IO request
+ * for which to set the sense data byte.
+ * @param[in] sense_len This parameter specifies length of the sense data
+ * to be returned by SATI.
+ * @param[out] descriptor_len This parameter returns the length of constructed
+ * descriptor.
+ * @param[in] information_buff This parameter specifies the address for which
+ * to set the command-specific information buffer.
+ *
+ * @return none
+ */
+static
+void sati_scsi_command_specific_descriptor_construct(
+ U8 * sense_data,
+ U32 sense_len,
+ U8 * information_buff)
+{
+ U8 i;
+
+ sati_set_sense_data_byte(sense_data, sense_len, 0, SCSI_CMD_SPECIFIC_DESCRIPTOR_TYPE);
+ sati_set_sense_data_byte(sense_data, sense_len, 1, SCSI_CMD_SPECIFIC_DESCRIPTOR_ADDITIONAL_LENGTH);
+ sati_set_sense_data_byte(sense_data, sense_len, 2, 0);
+ sati_set_sense_data_byte(sense_data, sense_len, 3, 0);
+
+ // fill information buffer
+ // SBC 5.20.1 REASSIGN BLOCKS command overview
+ // If information about the first LBA not reassigned is not available
+ // COMMAND-SPECIFIC INFORMATION field shall be set to FFFF_FFFF_FFFF_FFFFh
+ for (i=0; i<8; i++)
+ sati_set_sense_data_byte(sense_data, sense_len, 4 + i, information_buff==NULL?0xFF:information_buff[i]);
+}
+
+/**
+ * @brief This method will construct the information descriptor for
+ * the descriptor sense data buffer in the user's sense data buffer
+ * location.
+ *
+ * @param[in] sense_data This parameter specifies the user SCSI IO request
+ * for which to set the sense data byte.
+ * @param[in] sense_len This parameter specifies length of the sense data
+ * to be returned by SATI.
+ * @param[out] descriptor_len This parameter returns the length of constructed
+ * descriptor.
+ * @param[in] information_buff This parameter specifies the address for which
+ * to set the information buffer.
+ *
+ * @return none
+ */
+static
+void sati_scsi_information_descriptor_construct(
+ U8 * sense_data,
+ U32 sense_len,
+ U8 * information_buff)
+{
+ U8 i;
+ U8 valid = 1;
+
+ sati_set_sense_data_byte(sense_data, sense_len, 0, SCSI_INFORMATION_DESCRIPTOR_TYPE);
+ sati_set_sense_data_byte(sense_data, sense_len, 1, SCSI_INFORMATION_DESCRIPTOR_ADDITIONAL_LENGTH);
+ sati_set_sense_data_byte(sense_data, sense_len, 2, (valid << 7));
+ sati_set_sense_data_byte(sense_data, sense_len, 3, 0);
+
+ // fill information buffer
+ for (i=0; i<8; i++)
+ sati_set_sense_data_byte(sense_data, sense_len, 4 + i, information_buff==NULL?0:information_buff[i]);
+}
+
+/**
+ * @brief This method will construct the descriptors in the user's descriptor
+ * sense data buffer location.
+ *
+ * @param[in,out] scsi_io This parameter specifies the user's IO request
+ * for which to construct the sense data.
+ * @param[in] sense_data This parameter specifies the user SCSI IO request
+ * for which to set the sense data byte.
+ * @param[in] sense_len This parameter specifies length of the sense data
+ * to be returned by SATI.
+ * @param[out] descriptor_len This parameter returns the length of constructed
+ * descriptor.
+ * @param[in] information_buff This parameter specifies the address for which
+ * to set the information buffer.
+ *
+ * @return none
+ */
+static
+void sati_scsi_common_descriptors_construct(
+ void * scsi_io,
+ U8 * sense_data,
+ U32 sense_len,
+ U8 * information_buff)
+{
+ U8 * cdb = sati_cb_get_cdb_address(scsi_io);
+ U8 offset = 0;
+
+ switch (sati_get_cdb_byte(cdb, 0))
+ {
+#if !defined(DISABLE_SATI_WRITE_LONG)
+ case SCSI_WRITE_LONG_10:
+ case SCSI_WRITE_LONG_16:
+ sati_scsi_block_descriptor_construct(
+ sense_data + offset,
+ sense_len - offset);
+
+ offset += SCSI_BLOCK_DESCRIPTOR_LENGTH;
+ sati_scsi_information_descriptor_construct(
+ sense_data + offset,
+ sense_len - offset,
+ information_buff);
+
+ offset += SCSI_INFORMATION_DESCRIPTOR_LENGTH;
+ break;
+#endif // !defined(DISABLE_SATI_WRITE_LONG)
+#if !defined(DISABLE_SATI_REASSIGN_BLOCKS)
+ case SCSI_REASSIGN_BLOCKS:
+ sati_scsi_command_specific_descriptor_construct(
+ sense_data + offset,
+ sense_len - offset,
+ NULL);
+
+ offset += SCSI_CMD_SPECIFIC_DESCRIPTOR_LENGTH;
+ sati_scsi_information_descriptor_construct(
+ sense_data + offset,
+ sense_len - offset,
+ information_buff);
+
+ offset += SCSI_INFORMATION_DESCRIPTOR_LENGTH;
+ break;
+#endif // !defined(DISABLE_SATI_REASSIGN_BLOCKS)
+ case SCSI_READ_6:
+ case SCSI_READ_10:
+ case SCSI_READ_12:
+ case SCSI_READ_16:
+ case SCSI_WRITE_6:
+ case SCSI_WRITE_10:
+ case SCSI_WRITE_12:
+ case SCSI_WRITE_16:
+#if !defined(DISABLE_SATI_VERIFY)
+ case SCSI_VERIFY_10:
+ case SCSI_VERIFY_12:
+ case SCSI_VERIFY_16:
+#endif // !defined(DISABLE_SATI_VERIFY)
+#if !defined(DISABLE_SATI_WRITE_AND_VERIFY) \
+ && !defined(DISABLE_SATI_VERIFY) \
+ && !defined(DISABLE_SATI_WRITE)
+
+ case SCSI_WRITE_AND_VERIFY_10:
+ case SCSI_WRITE_AND_VERIFY_12:
+ case SCSI_WRITE_AND_VERIFY_16:
+#endif // !defined(DISABLE_SATI_WRITE_AND_VERIFY)
+ // && !defined(DISABLE_SATI_VERIFY)
+ // && !defined(DISABLE_SATI_WRITE)
+ sati_scsi_information_descriptor_construct(
+ sense_data + offset,
+ sense_len - offset,
+ information_buff);
+
+ offset += SCSI_INFORMATION_DESCRIPTOR_LENGTH;
+ break;
+ }
+}
+
+/**
+ * @brief This method will construct the descriptor sense data buffer in
+ * the user's sense data buffer location. Additionally, it will set
+ * the user's SCSI status.
+ *
+ * @param[in] sequence This parameter specifies the translation sequence
+ * for which to construct the sense data.
+ * @param[in,out] scsi_io This parameter specifies the user's IO request
+ * for which to construct the sense data.
+ * @param[in] scsi_status This parameter specifies the SCSI status
+ * value for the user's IO request.
+ * @param[in] sense_key This parameter specifies the sense key to
+ * be set for the user's IO request.
+ * @param[in] additional_sense_code This parameter specifies the
+ * additional sense code (ASC) key to be set for the user's
+ * IO request.
+ * @param[in] additional_sense_code_qualifier This parameter specifies
+ * the additional sense code qualifier (ASCQ) key to be set
+ * for the user's IO request.
+ *
+ * @return none
+ */
+void sati_scsi_descriptor_sense_data_construct(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ U8 scsi_status,
+ U8 response_code,
+ U8 sense_key,
+ U8 additional_sense_code,
+ U8 additional_sense_code_qualifier
+)
+{
+ U8 * sense_data;
+ U32 sense_len;
+
+ sati_scsi_get_sense_data_buffer(sequence, scsi_io, scsi_status, &sense_data, &sense_len);
+
+ sati_set_sense_data_byte(
+ sense_data,
+ sense_len,
+ 0,
+ response_code
+ );
+
+ sati_set_sense_data_byte(sense_data, sense_len, 1, sense_key);
+ sati_set_sense_data_byte(sense_data, sense_len, 2, additional_sense_code);
+ sati_set_sense_data_byte(sense_data, sense_len, 3, additional_sense_code_qualifier);
+ sati_set_sense_data_byte(sense_data, sense_len, 4, 0);
+ sati_set_sense_data_byte(sense_data, sense_len, 5, 0);
+ sati_set_sense_data_byte(sense_data, sense_len, 6, 0);
+
+ sati_scsi_common_descriptors_construct(scsi_io, sense_data + 8, sense_len, NULL);
+
+ sati_set_sense_data_byte(sense_data, sense_len, 7, sati_scsi_get_descriptor_sense_data_length(sequence, scsi_io) - 8);
+}
+
+/**
+ * @brief This method will construct the fixed format sense data buffer
+ * in the user's sense data buffer location. Additionally, it will
+ * set the user's SCSI status.
+ *
+ * @param[in] sequence This parameter specifies the translation sequence
+ * for which to construct the sense data.
+ * @param[in,out] scsi_io This parameter specifies the user's IO request
+ * for which to construct the sense data.
+ * @param[in] scsi_status This parameter specifies the SCSI status
+ * value for the user's IO request.
+ * @param[in] sense_key This parameter specifies the sense key to
+ * be set for the user's IO request.
+ * @param[in] additional_sense_code This parameter specifies the
+ * additional sense code (ASC) key to be set for the user's
+ * IO request.
+ * @param[in] additional_sense_code_qualifier This parameter specifies
+ * the additional sense code qualifier (ASCQ) key to be set
+ * for the user's IO request.
+ *
+ * @return none
+ */
+void sati_scsi_fixed_sense_data_construct(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ U8 scsi_status,
+ U8 response_code,
+ U8 sense_key,
+ U8 additional_sense_code,
+ U8 additional_sense_code_qualifier
+)
+{
+ U8 * sense_data;
+ U32 sense_len;
+
+ sati_scsi_get_sense_data_buffer(sequence, scsi_io, scsi_status, &sense_data, &sense_len);
+
+ // Write out the sense data format per SPC-4.
+ // We utilize the fixed format sense data format.
+
+ sati_set_sense_data_byte(
+ sense_data,
+ sense_len,
+ 0,
+ response_code | SCSI_FIXED_SENSE_DATA_VALID_BIT
+ );
+
+ sati_set_sense_data_byte(sense_data, sense_len, 1, 0);
+ sati_set_sense_data_byte(sense_data, sense_len, 2, sense_key);
+ sati_set_sense_data_byte(sense_data, sense_len, 3, 0);
+ sati_set_sense_data_byte(sense_data, sense_len, 4, 0);
+ sati_set_sense_data_byte(sense_data, sense_len, 5, 0);
+ sati_set_sense_data_byte(sense_data, sense_len, 6, 0);
+ sati_set_sense_data_byte(sense_data, sense_len, 7, 0);
+ sati_set_sense_data_byte(sense_data, sense_len, 8, 0);
+ sati_set_sense_data_byte(sense_data, sense_len, 9, 0);
+ sati_set_sense_data_byte(sense_data, sense_len, 10, 0);
+ sati_set_sense_data_byte(sense_data, sense_len, 11, 0);
+ sati_set_sense_data_byte(sense_data, sense_len, 12, additional_sense_code);
+ sati_set_sense_data_byte(sense_data, sense_len, 13, additional_sense_code_qualifier);
+ sati_set_sense_data_byte(sense_data, sense_len, 14, 0);
+ sati_set_sense_data_byte(sense_data, sense_len, 15, 0);
+ sati_set_sense_data_byte(sense_data, sense_len, 16, 0);
+ sati_set_sense_data_byte(sense_data, sense_len, 17, 0);
+}
+
+/**
+* @brief This method will construct common sense data that will be identical in
+* both read error sense construct functions.
+* sati_scsi_read_ncq_error_sense_construct,
+* sati_scsi_read_error_sense_construct
+*
+ * @param[in] sense_data This parameter specifies the user SCSI IO request
+ * for which to set the sense data byte.
+* @param[in] sense_len This parameter specifies length of the sense data
+* to be returned by SATI.
+* @param[in] sense_key This parameter specifies the sense key to
+* be set for the user's IO request.
+* @param[in] additional_sense_code This parameter specifies the
+* additional sense code (ASC) key to be set for the user's
+* IO request.
+* @param[in] additional_sense_code_qualifier This parameter specifies
+* the additional sense code qualifier (ASCQ) key to be set
+* for the user's IO request.
+*
+* @return none
+*/
+static
+void sati_scsi_common_fixed_sense_construct(
+ U8 * sense_data,
+ U32 sense_len,
+ U8 sense_key,
+ U8 additional_sense_code,
+ U8 additional_sense_code_qualifier
+)
+{
+
+ sati_set_sense_data_byte(sense_data, sense_len, 1, 0);
+ sati_set_sense_data_byte(sense_data, sense_len, 2, sense_key);
+
+ //Bytes 3, 4, 5, 6 are set in read_error_sense_construct functions
+
+ sati_set_sense_data_byte(sense_data, sense_len, 7, 0);
+ sati_set_sense_data_byte(sense_data, sense_len, 8, 0);
+ sati_set_sense_data_byte(sense_data, sense_len, 9, 0);
+ sati_set_sense_data_byte(sense_data, sense_len, 10, 0);
+ sati_set_sense_data_byte(sense_data, sense_len, 11, 0);
+ sati_set_sense_data_byte(sense_data, sense_len, 12, additional_sense_code);
+ sati_set_sense_data_byte(sense_data, sense_len, 13, additional_sense_code_qualifier);
+ sati_set_sense_data_byte(sense_data, sense_len, 14, 0);
+ sati_set_sense_data_byte(sense_data, sense_len, 15, 0x80);
+ sati_set_sense_data_byte(sense_data, sense_len, 16, 0);
+ sati_set_sense_data_byte(sense_data, sense_len, 17, 0);
+}
+
+/**
+ * @brief This method will construct the descriptor sense data buffer in
+ * the user's sense data buffer location. Additionally, it will set
+ * the user's SCSI status.
+ *
+ * @param[in] sequence This parameter specifies the translation sequence
+ * for which to construct the sense data.
+ * @param[in,out] scsi_io This parameter specifies the user's IO request
+ * for which to construct the sense data.
+ * @param[in] scsi_status This parameter specifies the SCSI status
+ * value for the user's IO request.
+ * @param[in] sense_key This parameter specifies the sense key to
+ * be set for the user's IO request.
+ * @param[in] additional_sense_code This parameter specifies the
+ * additional sense code (ASC) key to be set for the user's
+ * IO request.
+ * @param[in] additional_sense_code_qualifier This parameter specifies
+ * the additional sense code qualifier (ASCQ) key to be set
+ * for the user's IO request.
+ *
+ * @return none
+ */
+static
+void sati_scsi_common_descriptor_sense_construct(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ U8 * sense_data,
+ U32 sense_len,
+ U8 sense_key,
+ U8 additional_sense_code,
+ U8 additional_sense_code_qualifier,
+ U8 * information_buff
+)
+{
+ sati_set_sense_data_byte(sense_data, sense_len, 1, sense_key);
+ sati_set_sense_data_byte(sense_data, sense_len, 2, additional_sense_code);
+ sati_set_sense_data_byte(sense_data, sense_len, 3, additional_sense_code_qualifier);
+ sati_set_sense_data_byte(sense_data, sense_len, 4, 0);
+ sati_set_sense_data_byte(sense_data, sense_len, 5, 0);
+ sati_set_sense_data_byte(sense_data, sense_len, 6, 0);
+
+ sati_scsi_common_descriptors_construct(scsi_io, sense_data + 8, sense_len, information_buff);
+
+ sati_set_sense_data_byte(sense_data, sense_len, 7, sati_scsi_get_descriptor_sense_data_length(sequence, scsi_io) - 8);
+}
+
+/**
+* @brief This method will construct the sense data buffer in the user's
+* descriptor sense data buffer location. Additionally, it will set
+* the user's SCSI status. This is only used for NCQ uncorrectable
+* read errors
+*
+* @param[in] sequence This parameter specifies the translation sequence
+* for which to construct the sense data.
+* @param[in,out] scsi_io This parameter specifies the user's IO request
+* for which to construct the sense data.
+* @param[in] ata_input_data This parameter specifies the user's ATA IO
+* response from a Read Log Ext command.
+* @param[in] scsi_status This parameter specifies the SCSI status
+* value for the user's IO request.
+* @param[in] sense_key This parameter specifies the sense key to
+* be set for the user's IO request.
+* @param[in] additional_sense_code This parameter specifies the
+* additional sense code (ASC) key to be set for the user's
+* IO request.
+* @param[in] additional_sense_code_qualifier This parameter specifies
+* the additional sense code qualifier (ASCQ) key to be set
+* for the user's IO request.
+*
+* @return none
+*/
+static
+void sati_scsi_read_ncq_error_descriptor_sense_construct(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ void * ata_input_data,
+ U8 scsi_status,
+ U8 response_code,
+ U8 sense_key,
+ U8 additional_sense_code,
+ U8 additional_sense_code_qualifier
+)
+{
+ U8 * sense_data;
+ U32 sense_len;
+
+ U8 information_buff[8] = {0};
+
+ ATA_NCQ_COMMAND_ERROR_LOG_T * ncq_log = (ATA_NCQ_COMMAND_ERROR_LOG_T *) ata_input_data;
+
+ sati_scsi_get_sense_data_buffer(sequence, scsi_io, scsi_status, &sense_data, &sense_len);
+
+ sati_set_sense_data_byte(
+ sense_data,
+ sense_len,
+ 0,
+ response_code
+ );
+
+ information_buff[2] = ncq_log->lba_47_40;
+ information_buff[3] = ncq_log->lba_39_32;
+ information_buff[4] = ncq_log->lba_31_24;
+ information_buff[5] = ncq_log->lba_23_16;
+ information_buff[6] = ncq_log->lba_15_8;
+ information_buff[7] = ncq_log->lba_7_0;
+
+ sati_scsi_common_descriptor_sense_construct(
+ sequence,
+ scsi_io,
+ sense_data,
+ sense_len,
+ sense_key,
+ additional_sense_code,
+ additional_sense_code_qualifier,
+ information_buff
+ );
+}
+
+/**
+* @brief This method will construct the sense data buffer in the user's
+* sense data buffer location. Additionally, it will set the user's
+* SCSI status. This is only used for NCQ uncorrectable read errors
+*
+* @param[in] sequence This parameter specifies the translation sequence
+* for which to construct the sense data.
+* @param[in,out] scsi_io This parameter specifies the user's IO request
+* for which to construct the sense data.
+* @param[in] ata_input_data This parameter specifies the user's ATA IO
+* response from a Read Log Ext command.
+* @param[in] scsi_status This parameter specifies the SCSI status
+* value for the user's IO request.
+* @param[in] sense_key This parameter specifies the sense key to
+* be set for the user's IO request.
+* @param[in] additional_sense_code This parameter specifies the
+* additional sense code (ASC) key to be set for the user's
+* IO request.
+* @param[in] additional_sense_code_qualifier This parameter specifies
+* the additional sense code qualifier (ASCQ) key to be set
+* for the user's IO request.
+*
+* @return none
+*/
+static
+void sati_scsi_read_ncq_error_fixed_sense_construct(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ void * ata_input_data,
+ U8 scsi_status,
+ U8 response_code,
+ U8 sense_key,
+ U8 additional_sense_code,
+ U8 additional_sense_code_qualifier
+)
+{
+ U8 * sense_data;
+ U32 sense_len;
+ U8 valid = TRUE;
+
+ ATA_NCQ_COMMAND_ERROR_LOG_T * ncq_log = (ATA_NCQ_COMMAND_ERROR_LOG_T *) ata_input_data;
+
+ sati_scsi_get_sense_data_buffer(sequence, scsi_io, scsi_status, &sense_data, &sense_len);
+
+ if(ncq_log->lba_39_32 > 0)
+ {
+ valid = FALSE;
+ }
+
+ sati_set_sense_data_byte(
+ sense_data,
+ sense_len,
+ 0,
+ (valid << 7) | response_code
+ );
+
+ sati_set_sense_data_byte(sense_data, sense_len, 3, ncq_log->lba_31_24);
+ sati_set_sense_data_byte(sense_data, sense_len, 4, ncq_log->lba_23_16);
+ sati_set_sense_data_byte(sense_data, sense_len, 5, ncq_log->lba_15_8);
+ sati_set_sense_data_byte(sense_data, sense_len, 6, ncq_log->lba_7_0);
+
+ sati_scsi_common_fixed_sense_construct(
+ sense_data,
+ sense_len,
+ sense_key,
+ additional_sense_code,
+ additional_sense_code_qualifier
+ );
+}
+
+void sati_scsi_read_ncq_error_sense_construct(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ void * ata_input_data,
+ U8 scsi_status,
+ U8 sense_key,
+ U8 additional_sense_code,
+ U8 additional_sense_code_qualifier
+)
+{
+ U8 response_code;
+
+ response_code = sati_scsi_get_sense_data_response_code(sequence);
+
+ switch (response_code)
+ {
+ case SCSI_FIXED_CURRENT_RESPONSE_CODE:
+ case SCSI_FIXED_DEFERRED_RESPONSE_CODE:
+ sati_scsi_read_ncq_error_fixed_sense_construct(sequence, scsi_io, ata_input_data, scsi_status,
+ response_code, sense_key, additional_sense_code, additional_sense_code_qualifier);
+ break;
+ case SCSI_DESCRIPTOR_CURRENT_RESPONSE_CODE:
+ case SCSI_DESCRIPTOR_DEFERRED_RESPONSE_CODE:
+ sati_scsi_read_ncq_error_descriptor_sense_construct(sequence, scsi_io, ata_input_data, scsi_status,
+ response_code, sense_key, additional_sense_code, additional_sense_code_qualifier);
+ break;
+ }
+
+ sequence->is_sense_response_set = TRUE;
+}
+
+/**
+* @brief This method will construct the sense data buffer in the user's
+* sense data buffer location. Additionally, it will set the user's
+* SCSI status. This is used for uncorrectable read errors.
+*
+* @param[in] sequence This parameter specifies the translation sequence
+* for which to construct the sense data.
+* @param[in,out] scsi_io This parameter specifies the user's IO request
+* for which to construct the sense data.
+* @param[in] ata_io This parameter is a pointer to the ATA IO data used
+* to get the ATA register fis.
+* @param[in] scsi_status This parameter specifies the SCSI status
+* value for the user's IO request.
+* @param[in] sense_key This parameter specifies the sense key to
+* be set for the user's IO request.
+* @param[in] additional_sense_code This parameter specifies the
+* additional sense code (ASC) key to be set for the user's
+* IO request.
+* @param[in] additional_sense_code_qualifier This parameter specifies
+* the additional sense code qualifier (ASCQ) key to be set
+* for the user's IO request.
+*
+* @return none
+*/
+static
+void sati_scsi_read_error_descriptor_sense_construct(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ void * ata_io,
+ U8 scsi_status,
+ U8 response_code,
+ U8 sense_key,
+ U8 additional_sense_code,
+ U8 additional_sense_code_qualifier
+)
+{
+ U8 * sense_data;
+ U32 sense_len;
+ U8 information_buff[8] = {0};
+
+ U8 * register_fis = sati_cb_get_d2h_register_fis_address(ata_io);
+
+ sati_scsi_get_sense_data_buffer(sequence, scsi_io, scsi_status, &sense_data, &sense_len);
+
+ information_buff[2] = sati_get_ata_lba_high_ext(register_fis);
+ information_buff[3] = sati_get_ata_lba_mid_ext(register_fis);
+ information_buff[4] = sati_get_ata_lba_low_ext(register_fis);
+ information_buff[5] = sati_get_ata_lba_high(register_fis);
+ information_buff[6] = sati_get_ata_lba_mid(register_fis);
+ information_buff[7] = sati_get_ata_lba_low(register_fis);
+
+ sati_set_sense_data_byte(
+ sense_data,
+ sense_len,
+ 0,
+ SCSI_DESCRIPTOR_CURRENT_RESPONSE_CODE
+ );
+
+ sati_scsi_common_descriptor_sense_construct(
+ sequence,
+ scsi_io,
+ sense_data,
+ sense_len,
+ sense_key,
+ additional_sense_code,
+ additional_sense_code_qualifier,
+ information_buff
+ );
+}
+
+/**
+* @brief This method will construct the sense data buffer in the user's
+* sense data buffer location. Additionally, it will set the user's
+* SCSI status. This is used for uncorrectable read errors.
+*
+* @param[in] sequence This parameter specifies the translation sequence
+* for which to construct the sense data.
+* @param[in,out] scsi_io This parameter specifies the user's IO request
+* for which to construct the sense data.
+* @param[in] ata_io This parameter is a pointer to the ATA IO data used
+* to get the ATA register fis.
+* @param[in] scsi_status This parameter specifies the SCSI status
+* value for the user's IO request.
+* @param[in] sense_key This parameter specifies the sense key to
+* be set for the user's IO request.
+* @param[in] additional_sense_code This parameter specifies the
+* additional sense code (ASC) key to be set for the user's
+* IO request.
+* @param[in] additional_sense_code_qualifier This parameter specifies
+* the additional sense code qualifier (ASCQ) key to be set
+* for the user's IO request.
+*
+* @return none
+*/
+static
+void sati_scsi_read_error_fixed_sense_construct(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ void * ata_io,
+ U8 scsi_status,
+ U8 response_code,
+ U8 sense_key,
+ U8 additional_sense_code,
+ U8 additional_sense_code_qualifier
+)
+{
+ U8 * sense_data;
+ U32 sense_len;
+ U8 valid = TRUE;
+
+ U8 * register_fis = sati_cb_get_d2h_register_fis_address(ata_io);
+
+ sati_scsi_get_sense_data_buffer(sequence, scsi_io, scsi_status, &sense_data, &sense_len);
+
+ if(sati_get_ata_lba_mid_ext(register_fis) > 0)
+ {
+ valid = FALSE;
+ }
+
+ sati_set_sense_data_byte(sense_data, sense_len, 3, sati_get_ata_lba_low_ext(register_fis));
+ sati_set_sense_data_byte(sense_data, sense_len, 4, sati_get_ata_lba_high(register_fis));
+ sati_set_sense_data_byte(sense_data, sense_len, 5, sati_get_ata_lba_mid(register_fis));
+ sati_set_sense_data_byte(sense_data, sense_len, 6, sati_get_ata_lba_low(register_fis));
+
+
+ sati_set_sense_data_byte(
+ sense_data,
+ sense_len,
+ 0,
+ (valid << 7) | SCSI_FIXED_CURRENT_RESPONSE_CODE
+ );
+
+ sati_scsi_common_fixed_sense_construct(
+ sense_data,
+ sense_len,
+ sense_key,
+ additional_sense_code,
+ additional_sense_code_qualifier
+ );
+}
+
+void sati_scsi_read_error_sense_construct(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ void * ata_input_data,
+ U8 scsi_status,
+ U8 sense_key,
+ U8 additional_sense_code,
+ U8 additional_sense_code_qualifier
+)
+{
+ U8 response_code;
+
+ response_code = sati_scsi_get_sense_data_response_code(sequence);
+
+ switch (response_code)
+ {
+ case SCSI_FIXED_CURRENT_RESPONSE_CODE:
+ case SCSI_FIXED_DEFERRED_RESPONSE_CODE:
+ sati_scsi_read_error_fixed_sense_construct(sequence, scsi_io, ata_input_data, scsi_status,
+ response_code, sense_key, additional_sense_code, additional_sense_code_qualifier);
+ break;
+ case SCSI_DESCRIPTOR_CURRENT_RESPONSE_CODE:
+ case SCSI_DESCRIPTOR_DEFERRED_RESPONSE_CODE:
+ sati_scsi_read_error_descriptor_sense_construct(sequence, scsi_io, ata_input_data, scsi_status,
+ response_code, sense_key, additional_sense_code, additional_sense_code_qualifier);
+ break;
+ }
+
+ sequence->is_sense_response_set = TRUE;
+}
+
+/*
+ * @brief This method builds the scsi response data for a sata task management
+ * request.
+ *
+ * @param[in] sequence This parameter specifies the translation sequence
+ * for which to construct the sense data.
+ * @param[in,out] scsi_io This parameter specifies the user's IO request
+ * for which to construct the sense data.
+ * @param[in] response_data The response status for the task management
+ * request.
+ */
+void sati_scsi_response_data_construct(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ U8 response_data
+)
+{
+#ifdef SATI_TRANSPORT_SUPPORTS_SAS
+ SCI_SSP_RESPONSE_IU_T * rsp_iu = (SCI_SSP_RESPONSE_IU_T*)
+ sati_cb_get_response_iu_address(scsi_io);
+ rsp_iu->data_present = 0x01;
+ rsp_iu->response_data_length[3] = sizeof(U32);
+ rsp_iu->status = 0;
+ ((U8 *)rsp_iu->data)[3] = response_data;
+#else
+#endif // SATI_TRANSPORT_SUPPORTS_SAS
+}
+
+/**
+ * @brief This method checks to make sure that the translation isn't
+ * exceeding the allocation length specified in the CDB prior
+ * to retrieving the payload data byte from the user's buffer.
+ *
+ * @param[in,out] scsi_io This parameter specifies the user's IO request
+ * for which to set the user payload data byte.
+ * @param[in] byte_offset This parameter specifies the offset into
+ * the user's payload buffer at which to write the supplied
+ * value.
+ * @param[in] value This parameter specifies the memory location into
+ * which to read the value from the user's payload buffer.
+ *
+ * @return none
+ */
+void sati_get_data_byte(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ U32 byte_offset,
+ U8 * value
+)
+{
+ if (byte_offset < sequence->allocation_length)
+ sati_cb_get_data_byte(scsi_io, byte_offset, value);
+}
+
+/**
+ * @brief This method checks to make sure that the translation isn't
+ * exceeding the allocation length specified in the CDB while
+ * translating payload data into the user's buffer.
+ *
+ * @param[in] sequence This parameter specifies the translation sequence
+ * for which to set the user payload data byte.
+ * @param[in,out] scsi_io This parameter specifies the user's IO request
+ * for which to set the user payload data byte.
+ * @param[in] byte_offset This parameter specifies the offset into
+ * the user's payload buffer at which to write the supplied
+ * value.
+ * @param[in] value This parameter specifies the new value to be
+ * written out into the user's payload buffer.
+ *
+ * @return none
+ */
+void sati_set_data_byte(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ U32 byte_offset,
+ U8 value
+)
+{
+ if (byte_offset < sequence->allocation_length)
+ {
+ sequence->number_data_bytes_set++;
+ sati_cb_set_data_byte(scsi_io, byte_offset, value);
+ }
+}
+
+/**
+ * @brief This method checks to make sure that the translation isn't
+ * exceeding the allocation length specified in the CDB while
+ * translating payload data into the user's buffer.
+ *
+ * @param[in] sequence This parameter specifies the translation sequence
+ * for which to set the user payload data dword.
+ * @param[in,out] scsi_io This parameter specifies the user's IO request
+ * for which to set the user payload data dword.
+ * @param[in] byte_offset This parameter specifies the offset into
+ * the user's payload buffer at which to write the supplied
+ * value.
+ * @param[in] value This parameter specifies the new value to be
+ * written out into the user's payload buffer.
+ *
+ * @return none
+ */
+void sati_set_data_dword(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ U32 byte_offset,
+ U32 value
+)
+{
+ /// @todo Check to ensure that the bytes appear correctly (SAS Address).
+
+ sati_set_data_byte(sequence, scsi_io, byte_offset, (U8)value & 0xFF);
+ byte_offset++;
+ sati_set_data_byte(sequence, scsi_io, byte_offset, (U8)(value >> 8) & 0xFF);
+ byte_offset++;
+ sati_set_data_byte(sequence, scsi_io, byte_offset, (U8)(value >> 16) & 0xFF);
+ byte_offset++;
+ sati_set_data_byte(sequence, scsi_io, byte_offset, (U8)(value >> 24) & 0xFF);
+}
+
+/**
+ * @brief This method will construct the ATA flush cache command.
+ *
+ * @pre It is expected that the user has properly set the current contents
+ * of the register FIS to 0.
+ *
+ * @param[out] ata_io This parameter specifies the ATA IO request structure
+ * for which to build the FLUSH CACHE command.
+ * @param[in] sequence This parameter specifies the translator sequence
+ * for which the command is being constructed.
+ *
+ * @return none.
+ */
+void sati_ata_flush_cache_construct(
+ void * ata_io,
+ SATI_TRANSLATOR_SEQUENCE_T * sequence
+)
+{
+ U8 * register_fis = sati_cb_get_h2d_register_fis_address(ata_io);
+
+ sati_set_ata_command(register_fis, ATA_FLUSH_CACHE);
+ sati_ata_non_data_command(ata_io, sequence);
+}
+
+/**
+ * @brief This method will construct the ATA standby immediate command.
+ *
+ * @pre It is expected that the user has properly set the current contents
+ * of the register FIS to 0.
+ *
+ * @param[out] ata_io This parameter specifies the ATA IO request structure
+ * for which to build the STANDBY IMMEDIATE command.
+ * @param[in] sequence This parameter specifies the translator sequence
+ * for which the command is being constructed.
+ *
+ * @param[in] count This parameter specifies the time period programmed
+ * into the Standby Timer. See ATA8 spec for more details
+ * @return none.
+ */
+void sati_ata_standby_construct(
+ void * ata_io,
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ U16 count
+)
+{
+ U8 * register_fis = sati_cb_get_h2d_register_fis_address(ata_io);
+
+ sati_set_ata_command(register_fis, ATA_STANDBY);
+ sati_set_ata_sector_count(register_fis, count);
+
+ sequence->device->ata_standby_timer = (U8) count;
+
+ sati_ata_non_data_command(ata_io, sequence);
+}
+
+/**
+ * @brief This method will construct the ATA standby immediate command.
+ *
+ * @pre It is expected that the user has properly set the current contents
+ * of the register FIS to 0.
+ *
+ * @param[out] ata_io This parameter specifies the ATA IO request structure
+ * for which to build the STANDBY IMMEDIATE command.
+ * @param[in] sequence This parameter specifies the translator sequence
+ * for which the command is being constructed.
+ *
+ * @return none.
+ */
+void sati_ata_standby_immediate_construct(
+ void * ata_io,
+ SATI_TRANSLATOR_SEQUENCE_T * sequence
+)
+{
+ U8 * register_fis = sati_cb_get_h2d_register_fis_address(ata_io);
+
+ sati_set_ata_command(register_fis, ATA_STANDBY_IMMED);
+ sati_ata_non_data_command(ata_io, sequence);
+}
+
+/**
+ * @brief This method will construct the ATA idle immediate command.
+ *
+ * @pre It is expected that the user has properly set the current contents
+ * of the register FIS to 0.
+ *
+ * @param[out] ata_io This parameter specifies the ATA IO request structure
+ * for which to build the IDLE IMMEDIATE command.
+ * @param[in] sequence This parameter specifies the translator sequence
+ * for which the command is being constructed.
+ *
+ * @return none.
+ */
+void sati_ata_idle_immediate_construct(
+ void * ata_io,
+ SATI_TRANSLATOR_SEQUENCE_T * sequence
+)
+{
+ U8 * register_fis = sati_cb_get_h2d_register_fis_address(ata_io);
+
+ sati_set_ata_command(register_fis, ATA_IDLE_IMMED);
+ sati_set_ata_features(register_fis, 0x00);
+ sati_set_ata_sector_count(register_fis, 0x00);
+ sati_set_ata_lba_high(register_fis, 0x00);
+ sati_set_ata_lba_mid(register_fis, 0x00);
+ sati_set_ata_lba_low(register_fis, 0x00);
+ sati_ata_non_data_command(ata_io, sequence);
+}
+
+/**
+ * @brief This method will construct the ATA idle immediate command
+ for Unload Features.
+ *
+ * @pre It is expected that the user has properly set the current contents
+ * of the register FIS to 0.
+ *
+ * @param[out] ata_io This parameter specifies the ATA IO request structure
+ * for which to build the IDLE IMMEDIATE command.
+ * @param[in] sequence This parameter specifies the translator sequence
+ * for which the command is being constructed.
+ *
+ * @return none.
+ */
+void sati_ata_idle_immediate_unload_construct(
+ void * ata_io,
+ SATI_TRANSLATOR_SEQUENCE_T * sequence
+)
+{
+ U8 * register_fis = sati_cb_get_h2d_register_fis_address(ata_io);
+
+ sati_set_ata_command(register_fis, ATA_IDLE_IMMED);
+ sati_set_ata_features(register_fis, 0x44);
+ sati_set_ata_sector_count(register_fis, 0x00);
+ sati_set_ata_lba_high(register_fis, 0x55);
+ sati_set_ata_lba_mid(register_fis, 0x4E);
+ sati_set_ata_lba_low(register_fis, 0x4C);
+ sati_ata_non_data_command(ata_io, sequence);
+}
+
+/**
+ * @brief This method will construct the ATA IDLE command.\
+ *
+ * @pre It is expected that the user has properly set the current contents
+ * of the register FIS to 0.
+ *
+ * @param[out] ata_io This parameter specifies the ATA IO request structure
+ * for which to build the ATA IDLE command.
+ * @param[in] sequence This parameter specifies the translator sequence
+ * for which the command is being constructed.
+ *
+ * @return none.
+ */
+void sati_ata_idle_construct(
+ void * ata_io,
+ SATI_TRANSLATOR_SEQUENCE_T * sequence
+)
+{
+ U8 * register_fis = sati_cb_get_h2d_register_fis_address(ata_io);
+
+ sati_set_ata_command(register_fis, ATA_IDLE);
+ sati_set_ata_features(register_fis, 0x00);
+ sati_set_ata_sector_count(register_fis, 0x00);
+
+ sequence->device->ata_standby_timer = 0x00;
+
+ sati_set_ata_lba_high(register_fis, 0x00);
+ sati_set_ata_lba_mid(register_fis, 0x00);
+ sati_set_ata_lba_low(register_fis, 0x00);
+ sati_ata_non_data_command(ata_io, sequence);
+}
+
+/**
+ * @brief This method will construct the ATA MEDIA EJECT command.
+ *
+ * @pre It is expected that the user has properly set the current contents
+ * of the register FIS to 0.
+ *
+ * @param[out] ata_io This parameter specifies the ATA IO request structure
+ * for which to build the MEDIA EJCT command.
+ * @param[in] sequence This parameter specifies the translator sequence
+ * for which the command is being constructed.
+ *
+ * @return none.
+ */
+void sati_ata_media_eject_construct(
+ void * ata_io,
+ SATI_TRANSLATOR_SEQUENCE_T * sequence
+)
+{
+ U8 * register_fis = sati_cb_get_h2d_register_fis_address(ata_io);
+
+ sati_set_ata_command(register_fis, ATA_MEDIA_EJECT);
+ sati_ata_non_data_command(ata_io, sequence);
+}
+
+
+/**
+ * @brief This method will construct the ATA read verify sector(s) command.
+ *
+ * @pre It is expected that the user has properly set the current contents
+ * of the register FIS to 0.
+ *
+ * @param[out] ata_io This parameter specifies the ATA IO request structure
+ * for which to build the ATA READ VERIFY SECTOR(S) command.
+ * @param[in] sequence This parameter specifies the translator sequence
+ * for which the command is being constructed.
+ *
+ * @return none.
+ */
+void sati_ata_read_verify_sectors_construct(
+ void * ata_io,
+ SATI_TRANSLATOR_SEQUENCE_T * sequence
+)
+{
+ U8 * register_fis = sati_cb_get_h2d_register_fis_address(ata_io);
+
+ sati_set_ata_command(register_fis, ATA_READ_VERIFY_SECTORS);
+
+ //According to SAT-2 (v7) 9.11.3
+ sati_set_ata_sector_count(register_fis, 1);
+
+ //According to SAT-2 (v7) 9.11.3, set LBA to a value between zero and the
+ //maximum LBA supported by the ATA device in its current configuration.
+ //From the unit test, it seems we have to set LBA to a non-zero value.
+ sati_set_ata_lba_low(register_fis, 1);
+
+ sati_ata_non_data_command(ata_io, sequence);
+}
+
+/**
+ * @brief This method will construct a ATA SMART Return Status command so the
+ * status of the ATA device can be returned. The status of the SMART
+ * threshold will be returned by this command.
+ *
+ * @return N/A
+ *
+ */
+void sati_ata_smart_return_status_construct(
+ void * ata_io,
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ U8 feature_value
+)
+{
+ U8 * register_fis = sati_cb_get_h2d_register_fis_address(ata_io);
+
+ sati_set_ata_command(register_fis, ATA_SMART);
+
+ sati_set_ata_features(register_fis, feature_value);
+
+ sati_set_ata_lba_high(register_fis, 0xC2);
+ sati_set_ata_lba_mid(register_fis, 0x4F);
+
+ sati_ata_non_data_command(ata_io, sequence);
+}
+
+/**
+ * @brief This method will construct a ATA SMART Return Status command so the
+ * status of the ATA device can be returned. The status of the SMART
+ * threshold will be returned by this command.
+ *
+ * @return N/A
+ *
+ */
+void sati_ata_smart_read_log_construct(
+ void * ata_io,
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ U8 log_address,
+ U32 transfer_length
+)
+{
+ U8 * register_fis = sati_cb_get_h2d_register_fis_address(ata_io);
+
+ sati_set_ata_command(register_fis, ATA_SMART);
+ sati_set_ata_features(register_fis, ATA_SMART_SUB_CMD_READ_LOG);
+
+ sati_set_ata_lba_high(register_fis, 0xC2);
+ sati_set_ata_lba_mid(register_fis, 0x4F);
+ sati_set_ata_lba_low(register_fis, log_address);
+
+ sequence->data_direction = SATI_DATA_DIRECTION_IN;
+ sequence->protocol = SAT_PROTOCOL_PIO_DATA_IN;
+ sequence->ata_transfer_length = transfer_length;
+}
+
+/**
+ * @brief This method will construct a Write Uncorrectable ATA command that
+ * will write one sector with a psuedo or flagged error. The type of
+ * error is specified by the feature value.
+ *
+ * @return N/A
+ *
+ */
+void sati_ata_write_uncorrectable_construct(
+ void * ata_io,
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ U8 feature_value
+)
+{
+ U8 * register_fis = sati_cb_get_h2d_register_fis_address(ata_io);
+
+ sati_set_ata_command(register_fis, ATA_WRITE_UNCORRECTABLE);
+ sati_set_ata_features(register_fis, feature_value);
+ sati_set_ata_sector_count(register_fis, 0x0001);
+ sati_ata_non_data_command(ata_io, sequence);
+}
+
+/**
+ * @brief This method will construct a Mode Select ATA SET FEATURES command
+ * For example, Enable/Disable Write Cache, Enable/Disable Read Ahead
+ *
+ * @return N/A
+ *
+ */
+void sati_ata_set_features_construct(
+ void * ata_io,
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ U8 feature
+)
+{
+ U8 * register_fis = sati_cb_get_h2d_register_fis_address(ata_io);
+
+ sati_set_ata_command(register_fis, ATA_SET_FEATURES);
+ sati_set_ata_features(register_fis, feature);
+ sati_ata_non_data_command(ata_io, sequence);
+}
+
+
+
+/**
+ * @brief This method will construct a Read Log ext ATA command that
+ * will request a log page based on the log_address.
+ *
+ * @param[in] log_address This parameter specifies the log page
+ * to be returned from Read Log Ext.
+ *
+ * @param[in] transfer_length This parameter specifies the size of the
+ * log page response returned by Read Log Ext.
+ *
+ * @return N/A
+ *
+ */
+void sati_ata_read_log_ext_construct(
+ void * ata_io,
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ U8 log_address,
+ U32 transfer_length
+)
+{
+ U8 * register_fis = sati_cb_get_h2d_register_fis_address(ata_io);
+
+ sati_set_ata_command(register_fis, ATA_READ_LOG_EXT);
+
+ sati_set_ata_lba_low(register_fis, log_address);
+ sati_set_ata_lba_mid(register_fis, 0x00);
+ sati_set_ata_lba_mid_exp(register_fis, 0x00);
+
+ sati_set_ata_sector_count(register_fis, 0x01);
+
+ sequence->data_direction = SATI_DATA_DIRECTION_IN;
+ sequence->protocol = SAT_PROTOCOL_PIO_DATA_IN;
+ sequence->ata_transfer_length = transfer_length;
+
+}
+
+/**
+* @brief This method will check if the ATA device is in the stopped power
+* state. This is used for all medium access commands for SAT
+* compliance. See SAT2r07 section 9.11.1
+*
+* @param[in] sequence - SATI sequence data with the device state.
+*
+* @return TRUE If device is stopped
+*
+*/
+BOOL sati_device_state_stopped(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io
+)
+{
+ if(sequence->device->state == SATI_DEVICE_STATE_STOPPED)
+ {
+ sati_scsi_sense_data_construct(
+ sequence,
+ scsi_io,
+ SCSI_STATUS_CHECK_CONDITION,
+ SCSI_SENSE_NOT_READY ,
+ SCSI_ASC_INITIALIZING_COMMAND_REQUIRED,
+ SCSI_ASCQ_INITIALIZING_COMMAND_REQUIRED
+ );
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/**
+* @brief This method will construct a ATA Read Buffer command that
+* will request PIO in data containing the target device's buffer.
+*
+* @param[out] ata_io This parameter specifies the ATA IO request structure
+* for which to build the ATA READ VERIFY SECTOR(S) command.
+* @param[in] sequence This parameter specifies the translator sequence
+* for which the command is being constructed.
+* @return N/A
+*
+*/
+void sati_ata_read_buffer_construct(
+ void * ata_io,
+ SATI_TRANSLATOR_SEQUENCE_T * sequence
+)
+{
+ U8 * register_fis = sati_cb_get_h2d_register_fis_address(ata_io);
+
+ sati_set_ata_command(register_fis, ATA_READ_BUFFER);
+ sequence->data_direction = SATI_DATA_DIRECTION_IN;
+ sequence->protocol = SAT_PROTOCOL_PIO_DATA_IN;
+ sequence->ata_transfer_length = 512;
+}
+
+
+/**
+* @brief This method will construct a ATA Write Buffer command that
+* will send PIO out data to the target device's buffer.
+*
+* @param[out] ata_io This parameter specifies the ATA IO request structure
+* for which to build the ATA READ VERIFY SECTOR(S) command.
+* @param[in] sequence This parameter specifies the translator sequence
+* for which the command is being constructed.
+* @return N/A
+*
+*/
+void sati_ata_write_buffer_construct(
+ void * ata_io,
+ SATI_TRANSLATOR_SEQUENCE_T * sequence
+)
+{
+ U8 * register_fis = sati_cb_get_h2d_register_fis_address(ata_io);
+
+ sati_set_ata_command(register_fis, ATA_WRITE_BUFFER);
+
+ sequence->data_direction = SATI_DATA_DIRECTION_OUT;
+ sequence->protocol = SAT_PROTOCOL_PIO_DATA_OUT;
+ sequence->ata_transfer_length = 512;
+}
+
+
+/**
+* @brief This method will construct a ATA Download Microcode command that
+* will send PIO out data containing new firmware for the target drive.
+*
+* @param[out] ata_io This parameter specifies the ATA IO request structure
+* for which to build the ATA READ VERIFY SECTOR(S) command.
+* @param[in] sequence This parameter specifies the translator sequence
+* for which the command is being constructed.
+* @param[in] mode This parameter specifies the download microcode sub-command
+* code.
+* @param[in] allocation_length This parameter specifies the number of bytes
+* being sent to the target device.
+* @param[in] buffer_offset This parameter specifies the buffer offset for the
+* data sent to the target device.
+*
+* @return N/A
+*
+*/
+void sati_ata_download_microcode_construct(
+ void * ata_io,
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ U8 mode,
+ U32 allocation_length,
+ U32 buffer_offset
+)
+{
+ U8 * register_fis = sati_cb_get_h2d_register_fis_address(ata_io);
+
+ sati_set_ata_command(register_fis, ATA_DOWNLOAD_MICROCODE);
+ sati_set_ata_features(register_fis, mode);
+
+ if(mode == ATA_MICROCODE_DOWNLOAD_SAVE)
+ {
+ sati_set_ata_sector_count(register_fis, (U8) (allocation_length >> 9));
+ sati_set_ata_lba_low(register_fis, (U8) (allocation_length >> 17));
+ }
+ else //mode == 0x03
+ {
+ sati_set_ata_sector_count(register_fis, (U8) (allocation_length >> 9));
+ sati_set_ata_lba_low(register_fis, (U8) (allocation_length >> 17));
+ sati_set_ata_lba_high(register_fis, (U8) (buffer_offset >> 9));
+ }
+
+ if((allocation_length == 0) && (buffer_offset == 0))
+ {
+ sati_ata_non_data_command(ata_io, sequence);
+ }
+ else
+ {
+ sequence->data_direction = SATI_DATA_DIRECTION_OUT;
+ sequence->protocol = SAT_PROTOCOL_PIO_DATA_OUT;
+ sequence->ata_transfer_length = allocation_length;
+ }
+}
diff --git a/sys/dev/isci/scil/sati_util.h b/sys/dev/isci/scil/sati_util.h
new file mode 100644
index 0000000..0f141df
--- /dev/null
+++ b/sys/dev/isci/scil/sati_util.h
@@ -0,0 +1,393 @@
+/*-
+ * 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.
+ *
+ * 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.
+ *
+ * $FreeBSD$
+ */
+#ifndef _SATI_UTIL_H_
+#define _SATI_UTIL_H_
+
+/**
+ * @file
+ * @brief This file contains all of the interface methods, macros, structures
+ * that provide general support for SATI. Some methods can be utilized
+ * by a user to construct ATA/ATAPI commands, copy ATA device
+ * structure data, fill in sense data, etc.
+ */
+
+#include <dev/isci/scil/sati_types.h>
+#include <dev/isci/scil/sati_translator_sequence.h>
+
+#include <dev/isci/scil/intel_sata.h>
+#include <dev/isci/scil/intel_sas.h>
+
+/**
+ * This macro allows the translator to be able to handle environments where
+ * the contents of the CDB are of a different endian nature of byte swapped
+ * in some fashion.
+ */
+#define sati_get_cdb_byte(the_cdb, index) (the_cdb)[(index)]
+
+#define sati_get_ata_status(the_reg_fis) ((SATA_FIS_REG_D2H_T*)(the_reg_fis))->status
+#define sati_get_ata_error(the_reg_fis) ((SATA_FIS_REG_D2H_T*)(the_reg_fis))->error
+
+#define sati_get_ata_command(the_reg_fis) \
+ ((SATA_FIS_REG_H2D_T*)(the_reg_fis))->command
+
+#define sati_get_ata_sector_count(the_reg_fis) \
+ ((SATA_FIS_REG_D2H_T*)(the_reg_fis))->sector_count
+#define sati_get_ata_sector_count_exp(the_reg_fis) \
+ ((SATA_FIS_REG_D2H_T*)(the_reg_fis))->sector_count_exp
+#define sati_get_ata_lba_low(the_reg_fis) \
+ ((SATA_FIS_REG_D2H_T*)(the_reg_fis))->lba_low
+#define sati_get_ata_lba_mid(the_reg_fis) \
+ ((SATA_FIS_REG_D2H_T*)(the_reg_fis))->lba_mid
+#define sati_get_ata_lba_high(the_reg_fis) \
+ ((SATA_FIS_REG_D2H_T*)(the_reg_fis))->lba_high
+#define sati_get_ata_sector_count_ext(the_reg_fis) \
+ ((SATA_FIS_REG_D2H_T*)(the_reg_fis))->sector_count_exp
+#define sati_get_ata_lba_low_ext(the_reg_fis) \
+ ((SATA_FIS_REG_D2H_T*)(the_reg_fis))->lba_low_exp
+#define sati_get_ata_lba_mid_ext(the_reg_fis) \
+ ((SATA_FIS_REG_D2H_T*)(the_reg_fis))->lba_mid_exp
+#define sati_get_ata_lba_high_ext(the_reg_fis) \
+ ((SATA_FIS_REG_D2H_T*)(the_reg_fis))->lba_high_exp
+#define sati_get_ata_device(the_reg_fis) \
+ ((SATA_FIS_REG_D2H_T*)(the_reg_fis))->device
+
+#define sati_set_ata_status(the_reg_fis, value) \
+ ((SATA_FIS_REG_D2H_T*)(the_reg_fis))->status = (value)
+#define sati_set_sata_fis_type(the_reg_fis, value) \
+ ((SATA_FIS_REG_H2D_T*)(the_reg_fis))->fis_type = (value)
+#define sati_set_sata_command_flag(the_reg_fis) \
+ ((SATA_FIS_REG_H2D_T*)(the_reg_fis))->command_flag = 1
+#define sati_clear_sata_command_flag(the_reg_fis) \
+ ((SATA_FIS_REG_H2D_T*)(the_reg_fis))->command_flag = 0
+
+#define sati_set_ata_command(the_reg_fis, value) \
+ ((SATA_FIS_REG_H2D_T*)(the_reg_fis))->command = (value)
+#define sati_set_ata_features(the_reg_fis, value) \
+ ((SATA_FIS_REG_H2D_T*)(the_reg_fis))->features = (value)
+#define sati_set_ata_features_exp(the_reg_fis, value) \
+ ((SATA_FIS_REG_H2D_T*)(the_reg_fis))->features_exp = (value)
+#define sati_set_ata_control(the_reg_fis, value) \
+ ((SATA_FIS_REG_H2D_T*)(the_reg_fis))->control = (value)
+#define sati_set_ata_sector_count(the_reg_fis, value) \
+ ((SATA_FIS_REG_H2D_T*)(the_reg_fis))->sector_count = (value)
+#define sati_set_ata_sector_count_exp(the_reg_fis, value) \
+ ((SATA_FIS_REG_H2D_T*)(the_reg_fis))->sector_count_exp = (value)
+#define sati_set_ata_lba_low(the_reg_fis, value) \
+ ((SATA_FIS_REG_H2D_T*)(the_reg_fis))->lba_low = (value)
+#define sati_set_ata_lba_mid(the_reg_fis, value) \
+ ((SATA_FIS_REG_H2D_T*)(the_reg_fis))->lba_mid = (value)
+#define sati_set_ata_lba_high(the_reg_fis, value) \
+ ((SATA_FIS_REG_H2D_T*)(the_reg_fis))->lba_high = (value)
+#define sati_set_ata_lba_low_exp(the_reg_fis, value) \
+ ((SATA_FIS_REG_H2D_T*)(the_reg_fis))->lba_low_exp = (value)
+#define sati_set_ata_lba_mid_exp(the_reg_fis, value) \
+ ((SATA_FIS_REG_H2D_T*)(the_reg_fis))->lba_mid_exp = (value)
+#define sati_set_ata_lba_high_exp(the_reg_fis, value) \
+ ((SATA_FIS_REG_H2D_T*)(the_reg_fis))->lba_high_exp = (value)
+#define sati_set_ata_device_head(the_reg_fis, value) \
+ ((SATA_FIS_REG_H2D_T*)(the_reg_fis))->device = (value)
+
+#define ATA_MID_REGISTER_THRESHOLD_EXCEEDED 0xF4
+#define ATA_HIGH_REGISTER_THRESHOLD_EXCEEDED 0x2C
+
+#define ATA_MICROCODE_OFFSET_DOWNLOAD 0x03
+#define ATA_MICROCODE_DOWNLOAD_SAVE 0x07
+
+#ifndef MIN
+#define MIN(x,y) ((x) < (y) ? (x) : (y))
+#endif
+
+#ifndef MAX
+#define MAX(x,y) ((x) > (y) ? (x) : (y))
+#endif
+
+
+void sati_ata_non_data_command(
+ void * ata_io,
+ SATI_TRANSLATOR_SEQUENCE_T * sequence
+);
+
+void sati_ata_identify_device_construct(
+ void * ata_io,
+ SATI_TRANSLATOR_SEQUENCE_T * sequence
+);
+
+void sati_ata_execute_device_diagnostic_construct(
+ void * ata_io,
+ SATI_TRANSLATOR_SEQUENCE_T * sequence
+);
+
+void sati_ata_identify_device_copy_data(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * destination_scsi_io,
+ U32 destination_offset,
+ U8 * source_buffer,
+ U32 source_offset,
+ U32 length,
+ BOOL use_printable_chars
+);
+
+void sati_copy_data(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * destination_scsi_io,
+ U32 destination_offset,
+ U8 * source_buffer,
+ U32 length
+);
+
+void sati_ata_identify_device_get_sector_info(
+ ATA_IDENTIFY_DEVICE_DATA_T * identify,
+ U32 * lba_high,
+ U32 * lba_low,
+ U32 * sector_size
+);
+
+void sati_ata_check_power_mode_construct(
+ void * ata_io,
+ SATI_TRANSLATOR_SEQUENCE_T * sequence
+);
+
+U8 sati_scsi_get_sense_data_length(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io
+);
+
+void sati_scsi_common_response_iu_construct(
+ SCI_SSP_RESPONSE_IU_T * rsp_iu,
+ U8 scsi_status,
+ U8 sense_data_length,
+ U8 data_present
+);
+
+void sati_scsi_sense_data_construct(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ U8 status,
+ U8 sense_key,
+ U8 additional_sense_code,
+ U8 additional_sense_code_qualifier
+);
+
+void sati_scsi_fixed_sense_data_construct(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ U8 response_code,
+ U8 scsi_status,
+ U8 sense_key,
+ U8 additional_sense_code,
+ U8 additional_sense_code_qualifier
+);
+
+void sati_scsi_descriptor_sense_data_construct(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ U8 response_code,
+ U8 scsi_status,
+ U8 sense_key,
+ U8 additional_sense_code,
+ U8 additional_sense_code_qualifier
+);
+
+void sati_scsi_read_ncq_error_sense_construct(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ void * ata_input_data,
+ U8 scsi_status,
+ U8 sense_key,
+ U8 additional_sense_code,
+ U8 additional_sense_code_qualifier
+);
+
+void sati_scsi_read_error_sense_construct(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ void * ata_io,
+ U8 status,
+ U8 sense_key,
+ U8 additional_sense_code,
+ U8 additional_sense_code_qualifier
+);
+
+void sati_scsi_response_data_construct(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ U8 response_data
+);
+
+void sati_get_data_byte(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ U32 byte_offset,
+ U8 * value
+);
+
+void sati_set_data_byte(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ U32 byte_offset,
+ U8 value
+);
+
+void sati_set_data_dword(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ U32 byte_offset,
+ U32 value
+);
+
+void sati_set_sense_data_byte(
+ U8 * sense_data,
+ U32 max_sense_data_len,
+ U32 byte_offset,
+ U8 value
+);
+
+void sati_ata_flush_cache_construct(
+ void * ata_io,
+ SATI_TRANSLATOR_SEQUENCE_T * sequence
+);
+
+void sati_ata_standby_construct(
+ void * ata_io,
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ U16 count
+);
+
+void sati_ata_standby_immediate_construct(
+ void * ata_io,
+ SATI_TRANSLATOR_SEQUENCE_T * sequence
+);
+
+void sati_ata_idle_immediate_construct(
+ void * ata_io,
+ SATI_TRANSLATOR_SEQUENCE_T * sequence
+);
+
+void sati_ata_idle_immediate_unload_construct(
+ void * ata_io,
+ SATI_TRANSLATOR_SEQUENCE_T * sequence
+);
+
+void sati_ata_idle_construct(
+ void * ata_io,
+ SATI_TRANSLATOR_SEQUENCE_T * sequence
+);
+
+void sati_ata_media_eject_construct(
+ void * ata_io,
+ SATI_TRANSLATOR_SEQUENCE_T * sequence
+);
+
+void sati_ata_read_verify_sectors_construct(
+ void * ata_io,
+ SATI_TRANSLATOR_SEQUENCE_T * sequence
+);
+
+void sati_ata_smart_return_status_construct(
+ void * ata_io,
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ U8 feature_value
+);
+
+void sati_ata_smart_read_log_construct(
+ void * ata_io,
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ U8 log_address,
+ U32 transfer_length
+);
+
+void sati_ata_write_uncorrectable_construct(
+ void * ata_io,
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ U8 feature_value
+);
+
+void sati_ata_set_features_construct(
+ void * ata_io,
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ U8 feature
+);
+
+void sati_ata_read_log_ext_construct(
+ void * ata_io,
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ U8 log_address,
+ U32 transfer_length
+);
+
+BOOL sati_device_state_stopped(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io
+);
+
+void sati_ata_read_buffer_construct(
+ void * ata_io,
+ SATI_TRANSLATOR_SEQUENCE_T * sequence
+);
+
+void sati_ata_write_buffer_construct(
+ void * ata_io,
+ SATI_TRANSLATOR_SEQUENCE_T * sequence
+);
+
+void sati_ata_download_microcode_construct(
+ void * ata_io,
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ U8 mode,
+ U32 block_count,
+ U32 buffer_offset
+);
+
+#endif // _SATI_UTIL_H_
+
diff --git a/sys/dev/isci/scil/sati_verify.c b/sys/dev/isci/scil/sati_verify.c
new file mode 100644
index 0000000..350499d
--- /dev/null
+++ b/sys/dev/isci/scil/sati_verify.c
@@ -0,0 +1,273 @@
+/*-
+ * 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.
+ *
+ * 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 <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/**
+ * @file
+ * @brief This file contains the method implementations for translating
+ * the SCSI VERIFY (10, 12, 16-byte) commands.
+ */
+
+#if !defined(DISABLE_SATI_VERIFY)
+
+#include <dev/isci/scil/sati_verify.h>
+#include <dev/isci/scil/sati_callbacks.h>
+#include <dev/isci/scil/sati_util.h>
+#include <dev/isci/scil/sati_move.h>
+
+#include <dev/isci/scil/intel_ata.h>
+#include <dev/isci/scil/intel_scsi.h>
+#include <dev/isci/scil/intel_sat.h>
+
+//******************************************************************************
+//* P R I V A T E M E T H O D S
+//******************************************************************************
+
+/**
+ * @brief This method performs the SCSI VERIFY command translation
+ * functionality common to all VERIFY command sizes.
+ * This includes:
+ * - setting the command register
+ * - setting the device head register
+ * - filling in fields in the SATI_TRANSLATOR_SEQUENCE object.
+ * For more information on the parameters passed to this method,
+ * please reference sati_translate_command().
+ *
+ * @return Indicate if the method was successfully completed.
+ * @retval SATI_SUCCESS This is returned in all other cases.
+ */
+static
+SATI_STATUS sati_verify_translate_command(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ void * ata_io
+)
+{
+ U8 * cdb = sati_cb_get_cdb_address(scsi_io);
+ U8 * register_fis = sati_cb_get_h2d_register_fis_address(ata_io);
+
+ /**
+ * The translator doesn't support performing the byte check operation.
+ * As a result, error the request if the BYTCHK bit is set.
+ */
+ if ((sati_get_cdb_byte(cdb, 1) & SCSI_VERIFY_BYTCHK_ENABLED))
+ {
+ sati_scsi_sense_data_construct(
+ sequence,
+ scsi_io,
+ SCSI_STATUS_CHECK_CONDITION,
+ SCSI_SENSE_ILLEGAL_REQUEST,
+ SCSI_ASC_INVALID_FIELD_IN_CDB,
+ SCSI_ASCQ_INVALID_FIELD_IN_CDB
+ );
+ return SATI_FAILURE_CHECK_RESPONSE_DATA;
+ }
+
+ sequence->protocol = SAT_PROTOCOL_NON_DATA;
+ sequence->data_direction = SATI_DATA_DIRECTION_NONE;
+
+ sati_set_ata_device_head(register_fis, ATA_DEV_HEAD_REG_LBA_MODE_ENABLE);
+
+ // Ensure the device supports the 48 bit feature set.
+ if (sequence->device->capabilities & SATI_DEVICE_CAP_48BIT_ENABLE)
+ sati_set_ata_command(register_fis, ATA_READ_VERIFY_SECTORS_EXT);
+ else
+ sati_set_ata_command(register_fis, ATA_READ_VERIFY_SECTORS);
+
+ return SATI_SUCCESS;
+}
+
+//******************************************************************************
+//* P U B L I C M E T H O D S
+//******************************************************************************
+
+/**
+ * @brief This method performs all of the translation required for a
+ * SCSI VERIFY 10 byte CDB.
+ * This includes:
+ * - logical block address translation
+ * - transfer length (sector count) translation
+ * - translation items common to all VERIFY CDB sizes.
+ * For more information on the parameters passed to this method,
+ * please reference sati_translate_command().
+ *
+ * @return Indicate if the command translation was successful.
+ * For more information on return values please reference
+ * sati_move_set_sector_count(), sati_verify_translate_command()
+ */
+SATI_STATUS sati_verify_10_translate_command(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ void * ata_io
+)
+{
+ SATI_STATUS status;
+ U8 * cdb = sati_cb_get_cdb_address(scsi_io);
+ U32 sector_count = (sati_get_cdb_byte(cdb, 7) << 8) |
+ (sati_get_cdb_byte(cdb, 8));
+
+ if(sati_device_state_stopped(sequence, scsi_io))
+ {
+ return SATI_FAILURE_CHECK_RESPONSE_DATA;
+ }
+ else
+ {
+ sequence->type = SATI_SEQUENCE_VERIFY_10;
+
+ // Fill in the Logical Block Address fields and sector count registers.
+ sati_move_translate_32_bit_lba(sequence, scsi_io, ata_io);
+ status = sati_move_set_sector_count(sequence,scsi_io,ata_io,sector_count,0);
+ if (status != SATI_SUCCESS)
+ return status;
+
+ return sati_verify_translate_command(sequence, scsi_io, ata_io);
+ }
+}
+
+/**
+ * @brief This method performs all of the translation required for a
+ * SCSI VERIFY 12 byte CDB.
+ * This includes:
+ * - logical block address translation
+ * - transfer length (sector count) translation
+ * - translation items common to all VERIFY CDB sizes.
+ * For more information on the parameters passed to this method,
+ * please reference sati_translate_command().
+ *
+ * @return Indicate if the command translation was successful.
+ * For more information on return values please reference
+ * sati_move_set_sector_count(), sati_verify_translate_command()
+ */
+SATI_STATUS sati_verify_12_translate_command(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ void * ata_io
+)
+{
+ SATI_STATUS status;
+ U8 * cdb = sati_cb_get_cdb_address(scsi_io);
+ U32 sector_count = (sati_get_cdb_byte(cdb, 6) << 24) |
+ (sati_get_cdb_byte(cdb, 7) << 16) |
+ (sati_get_cdb_byte(cdb, 8) << 8) |
+ (sati_get_cdb_byte(cdb, 9));
+
+ if(sati_device_state_stopped(sequence, scsi_io))
+ {
+ return SATI_FAILURE_CHECK_RESPONSE_DATA;
+ }
+ else
+ {
+ sequence->type = SATI_SEQUENCE_VERIFY_12;
+
+ // Fill in the Logical Block Address fields and sector count registers.
+ sati_move_translate_32_bit_lba(sequence, scsi_io, ata_io);
+ status = sati_move_set_sector_count(sequence,scsi_io,ata_io,sector_count,0);
+ if (status != SATI_SUCCESS)
+ return status;
+
+ return sati_verify_translate_command(sequence, scsi_io, ata_io);
+ }
+}
+
+/**
+ * @brief This method performs all of the translation required for a
+ * SCSI VERIFY 16 byte CDB.
+ * This includes:
+ * - logical block address translation
+ * - transfer length (sector count) translation
+ * - translation items common to all VERIFY CDB sizes.
+ * For more information on the parameters passed to this method,
+ * please reference sati_translate_command().
+ *
+ * @return Indicate if the command translation was successful.
+ * For more information on return values please reference
+ * sati_move_set_sector_count(), sati_verify_translate_command()
+ */
+SATI_STATUS sati_verify_16_translate_command(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ void * ata_io
+)
+{
+ SATI_STATUS status;
+ U8 * cdb = sati_cb_get_cdb_address(scsi_io);
+ U32 sector_count = (sati_get_cdb_byte(cdb, 10) << 24) |
+ (sati_get_cdb_byte(cdb, 11) << 16) |
+ (sati_get_cdb_byte(cdb, 12) << 8) |
+ (sati_get_cdb_byte(cdb, 13));
+
+ if(sati_device_state_stopped(sequence, scsi_io))
+ {
+ return SATI_FAILURE_CHECK_RESPONSE_DATA;
+ }
+ else
+ {
+ sequence->type = SATI_SEQUENCE_VERIFY_16;
+
+ // Fill in the Logical Block Address field.
+ status = sati_move_translate_64_bit_lba(sequence, scsi_io, ata_io);
+ if (status != SATI_SUCCESS)
+ return status;
+
+ // Fill in the Sector Count fields.
+ status = sati_move_set_sector_count(sequence,scsi_io,ata_io,sector_count,0);
+ if (status != SATI_SUCCESS)
+ return status;
+
+ return sati_verify_translate_command(sequence, scsi_io, ata_io);
+ }
+}
+
+#endif // !defined(DISABLE_SATI_VERIFY)
+
diff --git a/sys/dev/isci/scil/sati_verify.h b/sys/dev/isci/scil/sati_verify.h
new file mode 100644
index 0000000..7c762f6
--- /dev/null
+++ b/sys/dev/isci/scil/sati_verify.h
@@ -0,0 +1,83 @@
+/*-
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 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.
+ *
+ * $FreeBSD$
+ */
+#ifndef _SATI_VERIFY_H_
+#define _SATI_VERIFY_H_
+
+/**
+ * @file
+ * @brief This file contains the method prototypes and constructs
+ * for translating the SCSI VERIFY (10, 12, 16-byte) commands.
+ */
+
+#include <dev/isci/scil/sati_translator_sequence.h>
+
+SATI_STATUS sati_verify_10_translate_command(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ void * ata_io
+);
+
+SATI_STATUS sati_verify_12_translate_command(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ void * ata_io
+);
+
+SATI_STATUS sati_verify_16_translate_command(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ void * ata_io
+);
+
+#endif // _SATI_VERIFY_H_
diff --git a/sys/dev/isci/scil/sati_write.c b/sys/dev/isci/scil/sati_write.c
new file mode 100644
index 0000000..931a1a5
--- /dev/null
+++ b/sys/dev/isci/scil/sati_write.c
@@ -0,0 +1,321 @@
+/*-
+ * 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.
+ *
+ * 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 <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/**
+ * @file
+ * @brief This file contains the method implementations required to
+ * translate the SCSI write (6, 10, 12, or 16-byte) commands.
+ */
+
+#include <dev/isci/scil/sati_move.h>
+#include <dev/isci/scil/sati_write.h>
+#include <dev/isci/scil/sati_callbacks.h>
+#include <dev/isci/scil/sati_util.h>
+
+#include <dev/isci/scil/intel_ata.h>
+#include <dev/isci/scil/intel_scsi.h>
+
+//******************************************************************************
+//* P R I V A T E M E T H O D S
+//******************************************************************************
+
+/**
+ * @brief This method performs the common translation functionality for
+ * all SCSI write operations that are 10 bytes in size or larger.
+ * Translated/Written items include:
+ * - Force Unit Access (FUA)
+ * - Sector Count/Transfer Length
+ * - Command register
+ *
+ * @param[in] sector_count This parameter specifies the number of sectors
+ * to be transferred by this request.
+ * @param[in] device_head This parameter points to device head register
+ * that is to be written into the ATA task file (register FIS).
+ *
+ * @return Indicate if the command translation succeeded.
+ * @see sati_move_set_sector_count() for additional return values.
+ */
+static
+SATI_STATUS sati_write_large_translate_command(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ void * ata_io,
+ U32 sector_count,
+ U8 * device_head
+)
+{
+ sequence->data_direction = SATI_DATA_DIRECTION_OUT;
+
+ return sati_move_large_translate_command(
+ sequence,
+ scsi_io,
+ ata_io,
+ sector_count,
+ device_head
+ );
+}
+
+/**
+ * @brief This method performs the common translation functionality for
+ * all SCSI write operations containing a 32-bit logical block
+ * address.
+ * Translated/Written items include:
+ * - Logical Block Address (LBA)
+ * - Force Unit Access (FUA)
+ * - Sector Count/Transfer Length
+ * - Command register
+ * For more information on the parameters passed to this method,
+ * please reference sati_translate_command().
+ *
+ * @param[in] sector_count This parameter specifies the number of sectors
+ * to be transferred by this request.
+ * @param[in] control_byte_offset This parameter specifies the byte offset
+ * into the command descriptor block at which the control byte
+ * is located.
+ *
+ * @return Indicate if the command translation succeeded.
+ * @see sati_move_32_bit_lba_translate_command(), sati_move_set_sector_count()
+ * for additional return values.
+ */
+static
+SATI_STATUS sati_write_32_bit_lba_translate_command(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ void * ata_io,
+ U32 sector_count,
+ U8 control_byte_offset
+)
+{
+ U8 device_head = 0;
+ SATI_STATUS status;
+
+ status = sati_write_large_translate_command(
+ sequence, scsi_io, ata_io, sector_count, &device_head
+ );
+
+ if (status == SATI_SUCCESS)
+ {
+ status = sati_move_32_bit_lba_translate_command(
+ sequence, scsi_io, ata_io, device_head
+ );
+ }
+
+ return status;
+}
+
+//******************************************************************************
+//* P U B L I C M E T H O D S
+//******************************************************************************
+
+/**
+ * @brief This method will translate the SCSI write command into a
+ * corresponding ATA write 6 command. Depending upon the capabilities
+ * supported by the target different ATA commands can be selected.
+ * For more information on the parameters passed to this method,
+ * please reference sati_translate_command().
+ *
+ * @return Indicate if the command translation succeeded.
+ * @retval SCI_SUCCESS This is returned if the command translation was
+ * successful.
+ * @retval SATI_FAILURE_CHECK_RESPONSE_DATA This value is returned if
+ * sense data has been created as a result of something specified
+ * in the CDB.
+ */
+SATI_STATUS sati_write_6_translate_command(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ void * ata_io
+)
+{
+ if(sati_device_state_stopped(sequence, scsi_io))
+ {
+ return SATI_FAILURE_CHECK_RESPONSE_DATA;
+ }
+ else
+ {
+ sequence->data_direction = SATI_DATA_DIRECTION_OUT;
+ sequence->type = SATI_SEQUENCE_WRITE_6;
+
+ return sati_move_small_translate_command(sequence, scsi_io, ata_io);
+ }
+}
+
+/**
+ * @brief This method will translate the SCSI write 10 command into a
+ * corresponding ATA write command. Depending upon the capabilities
+ * supported by the target different ATA commands can be selected.
+ * It ensures that all translation required for this command is
+ * performed successfully.
+ * For more information on the parameters passed to this method,
+ * please reference sati_translate_command().
+ *
+ * @return Indicate if the command translation succeeded.
+ * @see sati_write_32_bit_lba_translate_command() for return values.
+ */
+SATI_STATUS sati_write_10_translate_command(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ void * ata_io
+)
+{
+ U8 * cdb = sati_cb_get_cdb_address(scsi_io);
+ U32 sector_count = (sati_get_cdb_byte(cdb, 7) << 8) |
+ (sati_get_cdb_byte(cdb, 8));
+
+ if(sati_device_state_stopped(sequence, scsi_io))
+ {
+ return SATI_FAILURE_CHECK_RESPONSE_DATA;
+ }
+ else
+ {
+ sequence->type = SATI_SEQUENCE_WRITE_10;
+
+ return sati_write_32_bit_lba_translate_command(
+ sequence, scsi_io, ata_io, sector_count, 9
+ );
+ }
+}
+
+/**
+ * @brief This method will translate the SCSI write 12 command into a
+ * corresponding ATA write command. Depending upon the capabilities
+ * supported by the target different ATA commands can be selected.
+ * It ensures that all translation required for this command is
+ * performed successfully.
+ * For more information on the parameters passed to this method,
+ * please reference sati_translate_command().
+ *
+ * @return Indicate if the command translation succeeded.
+ * @see sati_write_32_bit_lba_translate_command() for return values.
+ */
+SATI_STATUS sati_write_12_translate_command(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ void * ata_io
+)
+{
+ U8 * cdb = sati_cb_get_cdb_address(scsi_io);
+ U32 sector_count = (sati_get_cdb_byte(cdb, 6) << 24) |
+ (sati_get_cdb_byte(cdb, 7) << 16) |
+ (sati_get_cdb_byte(cdb, 8) << 8) |
+ (sati_get_cdb_byte(cdb, 9));
+
+ if(sati_device_state_stopped(sequence, scsi_io))
+ {
+ return SATI_FAILURE_CHECK_RESPONSE_DATA;
+ }
+ else
+ {
+ sequence->type = SATI_SEQUENCE_WRITE_12;
+
+ return sati_write_32_bit_lba_translate_command(
+ sequence, scsi_io, ata_io, sector_count, 11
+ );
+ }
+}
+
+/**
+ * @brief This method will translate the SCSI write 16 command into a
+ * corresponding ATA write command. Depending upon the capabilities
+ * supported by the target different ATA commands can be selected.
+ * It ensures that all translation required for this command is
+ * performed successfully.
+ * For more information on the parameters passed to this method,
+ * please reference sati_translate_command().
+ *
+ * @return Indicate if the command translation succeeded.
+ * @see sati_write_large_translate_command(), sati_move_translate_64_bit_lba()
+ * for additional return values.
+ */
+SATI_STATUS sati_write_16_translate_command(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ void * ata_io
+)
+{
+ SATI_STATUS status;
+ U8 device_head = 0;
+ U8 * cdb = sati_cb_get_cdb_address(scsi_io);
+ U32 sector_count = (sati_get_cdb_byte(cdb, 10) << 24) |
+ (sati_get_cdb_byte(cdb, 11) << 16) |
+ (sati_get_cdb_byte(cdb, 12) << 8) |
+ (sati_get_cdb_byte(cdb, 13));
+
+ if(sati_device_state_stopped(sequence, scsi_io))
+ {
+ return SATI_FAILURE_CHECK_RESPONSE_DATA;
+ }
+ else
+ {
+ sequence->type = SATI_SEQUENCE_WRITE_16;
+
+ // Translate the sector count, write command register, and check various
+ // other parts of the CDB.
+ status = sati_write_large_translate_command(
+ sequence, scsi_io, ata_io, sector_count, &device_head
+ );
+
+ // Attempt to translate the 64-bit LBA field from the SCSI request
+ // into the 48-bits of LBA in the ATA register FIS.
+ if (status == SATI_SUCCESS)
+ {
+ sati_move_translate_command(sequence, scsi_io, ata_io, device_head);
+ status = sati_move_translate_64_bit_lba(sequence, scsi_io, ata_io);
+ }
+
+ return status;
+ }
+}
+
diff --git a/sys/dev/isci/scil/sati_write.h b/sys/dev/isci/scil/sati_write.h
new file mode 100644
index 0000000..9d7be32
--- /dev/null
+++ b/sys/dev/isci/scil/sati_write.h
@@ -0,0 +1,91 @@
+/*-
+ * 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.
+ *
+ * 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.
+ *
+ * $FreeBSD$
+ */
+#ifndef _SATI_WRITE_H_
+#define _SATI_WRITE_H_
+
+/**
+ * @file
+ * @brief This file contains the method declarations and type definitions
+ * required to translate the SCSI write (6, 10, 12, or 16-byte)
+ * commands.
+ */
+
+#include <dev/isci/scil/sati_types.h>
+#include <dev/isci/scil/sati_translator_sequence.h>
+
+SATI_STATUS sati_write_6_translate_command(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ void * ata_io
+);
+
+SATI_STATUS sati_write_10_translate_command(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ void * ata_io
+);
+
+SATI_STATUS sati_write_12_translate_command(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ void * ata_io
+);
+
+SATI_STATUS sati_write_16_translate_command(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ void * ata_io
+);
+
+#endif // _SATI_WRITE_H_
diff --git a/sys/dev/isci/scil/sati_write_and_verify.c b/sys/dev/isci/scil/sati_write_and_verify.c
new file mode 100644
index 0000000..bca6ca4
--- /dev/null
+++ b/sys/dev/isci/scil/sati_write_and_verify.c
@@ -0,0 +1,243 @@
+/*-
+ * 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.
+*
+* 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 <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/**
+* @file
+* @brief This file contains the method implementations to translate
+* SCSI Write and Verify command based of the SAT spec.
+*/
+
+#if !defined(DISABLE_SATI_WRITE_AND_VERIFY)
+
+#include <dev/isci/scil/sati_write_and_verify.h>
+#include <dev/isci/scil/sati_write.h>
+#include <dev/isci/scil/sati_verify.h>
+#include <dev/isci/scil/sati_callbacks.h>
+#include <dev/isci/scil/sati_util.h>
+
+#include <dev/isci/scil/intel_ata.h>
+#include <dev/isci/scil/intel_scsi.h>
+
+/**
+* @brief This function translates a SCSI Write and Verify 10 command
+* into both ATA write and ATA read verify commands. This
+* happens by passing the SCSI IO, ATA IO, and Sequence pointers
+* to both the sati_write_10_translate_command and the
+* sati_verify_10_translate_command.
+*
+* @return Indicate if the command translation succeeded.
+* @retval SCI_SUCCESS This is returned if the command translation was
+* successful.
+* @retval SATI_FAILURE_CHECK_RESPONSE_DATA is returned if there was
+* a problem with the translation of write long.
+* @retval SATI_FAILURE is returned if there the sequence is out of
+* state for a sati_write_and_verify_10 translation.
+*
+*/
+SATI_STATUS sati_write_and_verify_10_translate_command(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ void * ata_io
+)
+{
+ SATI_STATUS status;
+
+ if(sequence->state == SATI_SEQUENCE_STATE_INITIAL)
+ {
+ status = sati_write_10_translate_command(sequence, scsi_io, ata_io);
+ sequence->state = SATI_SEQUENCE_STATE_INCOMPLETE;
+ sequence->is_translate_response_required = TRUE;
+ }
+ else if(sequence->state == SATI_SEQUENCE_STATE_INCOMPLETE)
+ {
+ status = sati_verify_10_translate_command(sequence, scsi_io, ata_io);
+ sequence->state = SATI_SEQUENCE_STATE_AWAIT_RESPONSE;
+ }
+ else
+ {
+ //SATI sequence is in the wrong state
+ return SATI_FAILURE;
+ }
+
+ sequence->type = SATI_SEQUENCE_WRITE_AND_VERIFY;
+ return status;
+}
+
+/**
+* @brief This function translates a SCSI Write and Verify 12 command
+* into both ATA write and ATA read verify commands. This
+* happens by passing the SCSI IO, ATA IO, and Sequence pointers
+* to both the sati_write_12_translate_command and the
+* sati_verify_12_translate_command.
+*
+* @return Indicate if the command translation succeeded.
+* @retval SCI_SUCCESS This is returned if the command translation was
+* successful.
+* @retval SATI_FAILURE_CHECK_RESPONSE_DATA is returned if there was
+* a problem with the translation of write long.
+* @retval SATI_FAILURE is returned if there the sequence is out of
+* state for a sati_write_and_verify_12 translation.
+*
+*/
+SATI_STATUS sati_write_and_verify_12_translate_command(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ void * ata_io
+)
+{
+ SATI_STATUS status;
+
+ if(sequence->state == SATI_SEQUENCE_STATE_INITIAL)
+ {
+ status = sati_write_12_translate_command(sequence, scsi_io, ata_io);
+ sequence->state = SATI_SEQUENCE_STATE_INCOMPLETE;
+ sequence->is_translate_response_required = TRUE;
+ }
+ else if(sequence->state == SATI_SEQUENCE_STATE_INCOMPLETE)
+ {
+ status = sati_verify_12_translate_command(sequence, scsi_io, ata_io);
+ sequence->state = SATI_SEQUENCE_STATE_AWAIT_RESPONSE;
+ }
+ else
+ {
+ //SATI sequence is in the wrong state
+ return SATI_FAILURE;
+ }
+
+ sequence->type = SATI_SEQUENCE_WRITE_AND_VERIFY;
+ return status;
+}
+
+/**
+* @brief This function translates a SCSI Write and Verify 16 command
+* into both ATA write and ATA read verify commands. This
+* happens by passing the SCSI IO, ATA IO, and Sequence pointers
+* to both the sati_write_16_translate_command and the
+* sati_verify_16_translate_command.
+*
+* @return Indicate if the command translation succeeded.
+* @retval SCI_SUCCESS This is returned if the command translation was
+* successful.
+* @retval SATI_FAILURE_CHECK_RESPONSE_DATA is returned if there was
+* a problem with the translation of write long.
+* @retval SATI_FAILURE is returned if there the sequence is out of
+* state for a sati_write_and_verify_16 translation.
+*
+*/
+SATI_STATUS sati_write_and_verify_16_translate_command(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ void * ata_io
+)
+{
+ SATI_STATUS status;
+
+ if(sequence->state == SATI_SEQUENCE_STATE_INITIAL)
+ {
+ status = sati_write_16_translate_command(sequence, scsi_io, ata_io);
+ sequence->state = SATI_SEQUENCE_STATE_INCOMPLETE;
+ sequence->is_translate_response_required = TRUE;
+ }
+ else if(sequence->state == SATI_SEQUENCE_STATE_INCOMPLETE)
+ {
+ status = sati_verify_16_translate_command(sequence, scsi_io, ata_io);
+ sequence->state = SATI_SEQUENCE_STATE_AWAIT_RESPONSE;
+ }
+ else
+ {
+ //SATI sequence is in the wrong state
+ return SATI_FAILURE;
+ }
+
+ sequence->type = SATI_SEQUENCE_WRITE_AND_VERIFY;
+ return status;
+}
+
+/**
+* @brief This function is the response to a sati_write_and_verify
+ translation. Since no response translation is required
+ this function will only check the sequence state and return
+ status.
+*
+* @return Indicate if the command response translation succeeded.
+* @retval SCI_COMPLETE This is returned if the command translation
+ is successful and requires no more work.
+* @retval SATI_SEQUENCE_INCOMPLETE This is returned if the command
+ translation has finished sending the ATA Write command but
+ still needs to complete the Verify portion.
+* @retval SATI_FAILURE is returned if there the sequence is out of
+* state for a sati_write_and_verify translation.
+*
+*/
+SATI_STATUS sati_write_and_verify_translate_response(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ void * ata_io
+)
+{
+ if(sequence->state == SATI_SEQUENCE_STATE_INCOMPLETE)
+ {
+ return SATI_SEQUENCE_INCOMPLETE;
+ }
+ else if(sequence->state == SATI_SEQUENCE_STATE_AWAIT_RESPONSE)
+ {
+ sequence->state = SATI_SEQUENCE_STATE_FINAL;
+ return SATI_COMPLETE;
+ }
+
+ return SATI_FAILURE;
+}
+
+#endif //!defined(DISABLE_SATI_WRITE_AND_VERIFY)
diff --git a/sys/dev/isci/scil/sati_write_and_verify.h b/sys/dev/isci/scil/sati_write_and_verify.h
new file mode 100644
index 0000000..bbe8806
--- /dev/null
+++ b/sys/dev/isci/scil/sati_write_and_verify.h
@@ -0,0 +1,90 @@
+/*-
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+*
+* GPL LICENSE SUMMARY
+*
+* Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+*
+* This program is free software; you can redistribute it and/or modify
+* it under the terms of version 2 of the GNU General Public License as
+* published by the Free Software Foundation.
+*
+* This program is distributed in the hope that it will be useful, but
+* WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+* General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software
+* Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+* The full GNU General Public License is included in this distribution
+* in the file called LICENSE.GPL.
+*
+* BSD LICENSE
+*
+* Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+* All rights reserved.
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions
+* are met:
+*
+* * Redistributions of source code must retain the above copyright
+* notice, this list of conditions and the following disclaimer.
+* * Redistributions in binary form must reproduce the above copyright
+* notice, this list of conditions and the following disclaimer in
+* the documentation and/or other materials provided with the
+* distribution.
+*
+* 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.
+ *
+ * $FreeBSD$
+ */
+/**
+* @file
+* @brief This file contains the method definitions to translate
+* SCSI Write and Verify command based of the SAT spec.
+*/
+
+#ifndef _SATI_WRITE_AND_VERIFY_H_
+#define _SATI_WRITE_AND_VERIFY_H_
+
+#include <dev/isci/scil/sati_types.h>
+#include <dev/isci/scil/sati_translator_sequence.h>
+
+SATI_STATUS sati_write_and_verify_10_translate_command(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ void * ata_io
+);
+
+SATI_STATUS sati_write_and_verify_12_translate_command(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ void * ata_io
+);
+
+SATI_STATUS sati_write_and_verify_16_translate_command(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ void * ata_io
+);
+
+SATI_STATUS sati_write_and_verify_translate_response(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ void * ata_io
+);
+
+#endif //#ifndef _SATI_WRITE_AND_VERIFY_H_
diff --git a/sys/dev/isci/scil/sati_write_buffer.c b/sys/dev/isci/scil/sati_write_buffer.c
new file mode 100644
index 0000000..97bdb74
--- /dev/null
+++ b/sys/dev/isci/scil/sati_write_buffer.c
@@ -0,0 +1,254 @@
+/*-
+ * 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.
+*
+* 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 <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/**
+* @file
+* @brief This file contains the method implementations to translate
+* SCSI Write Buffer command based of the SAT2v07 spec.
+*/
+
+#include <dev/isci/scil/sati_write_buffer.h>
+#include <dev/isci/scil/sati_callbacks.h>
+#include <dev/isci/scil/sati_util.h>
+
+#define WRITE_BUFFER_WRITE_DATA 0x02
+#define WRITE_BUFFER_DOWNLOAD_SAVE 0x05
+#define WRITE_BUFFER_OFFSET_DOWNLOAD_SAVE 0x07
+#define BLOCK_SIZE 512
+
+/**
+* @brief This method will translate the SCSI Write Buffer command
+* into a corresponding ATA Write Buffer and Download Microcode commands.
+* For more information on the parameters passed to this method,
+* please reference sati_translate_command().
+*
+* @return Indicates if the command translation succeeded.
+* @retval SATI_SUCCESS indicates that the translation was supported and occurred
+* without error.
+* @retval SATI_FAILURE_CHECK_RESPONSE_DATA This value is returned if
+* there is a translation failure.
+*/
+SATI_STATUS sati_write_buffer_translate_command(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ void * ata_io
+)
+{
+ U8 * cdb = sati_cb_get_cdb_address(scsi_io);
+ SATI_STATUS status = SATI_FAILURE;
+ U32 allocation_length;
+ U32 buffer_offset;
+
+ allocation_length = ((sati_get_cdb_byte(cdb, 6) << 16) |
+ (sati_get_cdb_byte(cdb, 7) << 8) |
+ (sati_get_cdb_byte(cdb, 8)));
+
+ buffer_offset = ((sati_get_cdb_byte(cdb, 3) << 16) |
+ (sati_get_cdb_byte(cdb, 4) << 8) |
+ (sati_get_cdb_byte(cdb, 5)));
+
+ sequence->allocation_length = allocation_length;
+
+ switch(sati_get_cdb_byte(cdb, 1))
+ {
+ case WRITE_BUFFER_WRITE_DATA:
+ if((allocation_length == BLOCK_SIZE) && (buffer_offset == 0) &&
+ (sati_get_cdb_byte(cdb, 2) == 0))
+ {
+ sati_ata_write_buffer_construct(ata_io, sequence);
+ sequence->type = SATI_SEQUENCE_WRITE_BUFFER;
+ sequence->state = SATI_SEQUENCE_STATE_AWAIT_RESPONSE;
+ status = SATI_SUCCESS;
+ }
+ else
+ {
+ sati_scsi_sense_data_construct(
+ sequence,
+ scsi_io,
+ SCSI_STATUS_CHECK_CONDITION,
+ SCSI_SENSE_ILLEGAL_REQUEST,
+ SCSI_ASC_INVALID_FIELD_IN_CDB,
+ SCSI_ASCQ_INVALID_FIELD_IN_CDB
+ );
+
+ sequence->state = SATI_SEQUENCE_STATE_FINAL;
+ status = SATI_FAILURE_CHECK_RESPONSE_DATA;
+ }
+ break;
+
+ case WRITE_BUFFER_DOWNLOAD_SAVE:
+
+ sati_ata_download_microcode_construct(
+ ata_io,
+ sequence,
+ ATA_MICROCODE_DOWNLOAD_SAVE,
+ allocation_length,
+ buffer_offset
+ );
+
+ sequence->type = SATI_SEQUENCE_WRITE_BUFFER_MICROCODE;
+ sequence->state = SATI_SEQUENCE_STATE_AWAIT_RESPONSE;
+ status = SATI_SUCCESS;
+ break;
+
+ case WRITE_BUFFER_OFFSET_DOWNLOAD_SAVE:
+ if(((allocation_length & 0x000001FF) == 0) && //Bits 08:00 need to be zero per SAT2v7
+ ((buffer_offset & 0x000001FF) == 0) &&
+ (allocation_length <= sequence->device->max_blocks_per_microcode_command) &&
+ (allocation_length >= sequence->device->min_blocks_per_microcode_command))
+ {
+ sati_ata_download_microcode_construct(
+ ata_io,
+ sequence,
+ ATA_MICROCODE_OFFSET_DOWNLOAD,
+ allocation_length,
+ buffer_offset
+ );
+
+ sequence->type = SATI_SEQUENCE_WRITE_BUFFER_MICROCODE;
+ sequence->state = SATI_SEQUENCE_STATE_AWAIT_RESPONSE;
+ status = SATI_SUCCESS;
+ }
+ else
+ {
+ sati_scsi_sense_data_construct(
+ sequence,
+ scsi_io,
+ SCSI_STATUS_CHECK_CONDITION,
+ SCSI_SENSE_ILLEGAL_REQUEST,
+ SCSI_ASC_INVALID_FIELD_IN_CDB,
+ SCSI_ASCQ_INVALID_FIELD_IN_CDB
+ );
+
+ sequence->state = SATI_SEQUENCE_STATE_FINAL;
+ status = SATI_FAILURE_CHECK_RESPONSE_DATA;
+ }
+ break;
+
+ default: //unsupported Write Buffer Mode
+ sati_scsi_sense_data_construct(
+ sequence,
+ scsi_io,
+ SCSI_STATUS_CHECK_CONDITION,
+ SCSI_SENSE_ILLEGAL_REQUEST,
+ SCSI_ASC_INVALID_FIELD_IN_CDB,
+ SCSI_ASCQ_INVALID_FIELD_IN_CDB
+ );
+
+ sequence->state = SATI_SEQUENCE_STATE_FINAL;
+ status = SATI_FAILURE_CHECK_RESPONSE_DATA;
+ break;
+ }
+ return status;
+}
+
+/**
+* @brief This method will complete the Write Buffer Translation by checking
+* for ATA errors and then creating a unit attention condition for
+* changed microcode.
+*
+* @return Indicates if the command translation succeeded.
+* @retval SATI_FAILURE_CHECK_RESPONSE_DATA This value is returned if
+* there is a translation failure.
+* @retval SATI_COMPLETE indicates that the translation was supported, occurred without
+* error, and no additional translation is necessary.
+*/
+SATI_STATUS sati_write_buffer_translate_response(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ void * ata_io
+)
+{
+ U8 * register_fis = sati_cb_get_d2h_register_fis_address(ata_io);
+ U8 ata_status = (U8) sati_get_ata_status(register_fis);
+ SATI_STATUS status = SATI_FAILURE;
+
+ if (ata_status & ATA_STATUS_REG_ERROR_BIT)
+ {
+ sati_scsi_sense_data_construct(
+ sequence,
+ scsi_io,
+ SCSI_STATUS_CHECK_CONDITION,
+ SCSI_SENSE_ABORTED_COMMAND,
+ SCSI_ASC_NO_ADDITIONAL_SENSE,
+ SCSI_ASCQ_NO_ADDITIONAL_SENSE
+ );
+ status = SATI_FAILURE_CHECK_RESPONSE_DATA;
+ }
+ else
+ {
+ switch(sequence->type)
+ {
+ case SATI_SEQUENCE_WRITE_BUFFER_MICROCODE:
+ sati_scsi_sense_data_construct(
+ sequence,
+ scsi_io,
+ SCSI_STATUS_GOOD,
+ SCSI_SENSE_UNIT_ATTENTION,
+ SCSI_ASC_MICROCODE_HAS_CHANGED,
+ SCSI_ASCQ_MICROCODE_HAS_CHANGED
+ );
+ status = SATI_COMPLETE;
+ break;
+
+ default:
+ status = SATI_COMPLETE;
+ break;
+ }
+ }
+
+ sequence->state = SATI_SEQUENCE_STATE_FINAL;
+ return status;
+}
diff --git a/sys/dev/isci/scil/sati_write_buffer.h b/sys/dev/isci/scil/sati_write_buffer.h
new file mode 100644
index 0000000..c027e1c
--- /dev/null
+++ b/sys/dev/isci/scil/sati_write_buffer.h
@@ -0,0 +1,78 @@
+/*-
+ * 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.
+*
+* 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.
+ *
+ * $FreeBSD$
+ */
+/**
+* @file
+* @brief This file contains the method definitions to translate
+* SCSI Write Buffer command based of the SAT2v07 spec.
+*/
+
+#ifndef _SATI_WRITE_BUFFER_H_
+#define _SATI_WRITE_BUFFER_H_
+
+#include <dev/isci/scil/sati_types.h>
+#include <dev/isci/scil/sati_translator_sequence.h>
+
+SATI_STATUS sati_write_buffer_translate_command(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ void * ata_io
+);
+
+SATI_STATUS sati_write_buffer_translate_response(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ void * ata_io
+);
+
+#endif // _SATI_WRITE_BUFFER_H_
diff --git a/sys/dev/isci/scil/sati_write_long.c b/sys/dev/isci/scil/sati_write_long.c
new file mode 100644
index 0000000..7847cc1
--- /dev/null
+++ b/sys/dev/isci/scil/sati_write_long.c
@@ -0,0 +1,259 @@
+/*-
+ * 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.
+ *
+ * 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 <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/**
+ * @file
+ * @brief This file contains the implementation to translate
+ * SCSI Write Long 10 and 16 commands based on the SAT spec.
+ */
+
+#if !defined(DISABLE_SATI_WRITE_LONG)
+
+#include <dev/isci/scil/sati_write_long.h>
+#include <dev/isci/scil/sati_device.h>
+#include <dev/isci/scil/sati_util.h>
+#include <dev/isci/scil/intel_scsi.h>
+#include <dev/isci/scil/intel_ata.h>
+#include <dev/isci/scil/intel_sat.h>
+#include <dev/isci/scil/sati_callbacks.h>
+#include <dev/isci/scil/sati_move.h>
+
+#define LOGICAL_PER_PHYSICAL_SECTOR 0xF
+
+#define WR_UNCOR_BIT 0x02
+#define WR_UNCOR_PBLOCK_BIT 0x03
+#define COR_DIS_WR_UNCORR_BIT 0x06
+
+
+/**
+ * @brief This method will translate the write long 10 & 16 SCSI commands into
+ * ATA write uncorrectable commands. For more information on the
+ * parameters passed to this method, please reference
+ * sati_translate_command().
+ *
+ * @return Indicate if the command translation succeeded.
+ * @retval SCI_SUCCESS This is returned if the command translation was
+ * successful.
+ * @retval SATI_FAILURE_CHECK_RESPONSE_DATA is returned if there was
+ * a problem with the translation of write long.
+ *
+ */
+SATI_STATUS sati_write_long_translate_command(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ void * ata_io
+)
+{
+ U8 * cdb = sati_cb_get_cdb_address(scsi_io);
+ SATI_STATUS status = SATI_FAILURE;
+ U16 byte_transfer_length;
+ U8 device_head = 0;
+
+ if((sequence->device->capabilities &
+ SATI_DEVICE_CAP_WRITE_UNCORRECTABLE_ENABLE) == 0)
+ {
+ sati_scsi_sense_data_construct(
+ sequence,
+ scsi_io,
+ SCSI_STATUS_CHECK_CONDITION,
+ SCSI_SENSE_ILLEGAL_REQUEST,
+ SCSI_ASC_INVALID_COMMAND_OPERATION_CODE,
+ SCSI_ASCQ_INVALID_COMMAND_OPERATION_CODE
+ );
+ return SATI_FAILURE_CHECK_RESPONSE_DATA;
+ }
+
+ //Write Long 10
+ if(sati_get_cdb_byte(cdb, 0) == SCSI_WRITE_LONG_10)
+ {
+ byte_transfer_length = (sati_get_cdb_byte(cdb, 7) << 8) |
+ (sati_get_cdb_byte(cdb, 8));
+
+ sati_move_translate_32_bit_lba(sequence, scsi_io, ata_io);
+ }
+ else //Write Long 16
+ {
+ byte_transfer_length = (sati_get_cdb_byte(cdb, 12) << 8) |
+ (sati_get_cdb_byte(cdb, 13));
+
+ status = sati_move_translate_64_bit_lba(sequence, scsi_io, ata_io);
+
+ if( status == SATI_FAILURE_CHECK_RESPONSE_DATA)
+ {
+ return status;
+ }
+ }
+
+
+ sati_move_translate_command(sequence, scsi_io, ata_io, device_head);
+
+ if( byte_transfer_length != 0 )
+ {
+ sati_scsi_sense_data_construct(
+ sequence,
+ scsi_io,
+ SCSI_STATUS_CHECK_CONDITION,
+ SCSI_SENSE_ILLEGAL_REQUEST,
+ SCSI_ASC_INVALID_FIELD_IN_CDB,
+ SCSI_ASCQ_INVALID_FIELD_IN_CDB
+ );
+ return SATI_FAILURE_CHECK_RESPONSE_DATA;
+ }
+
+ switch(SATI_WRITE_LONG_GET_COR_WR_PB_BITS(cdb))
+ {
+ case WR_UNCOR_BIT :
+
+ if( (sequence->device->capabilities &
+ SATI_DEVICE_CAP_MULTIPLE_SECTORS_PER_PHYSCIAL_SECTOR) != 0 )
+ {
+ sati_scsi_sense_data_construct(
+ sequence,
+ scsi_io,
+ SCSI_STATUS_CHECK_CONDITION,
+ SCSI_SENSE_ILLEGAL_REQUEST,
+ SCSI_ASC_INVALID_FIELD_IN_CDB,
+ SCSI_ASCQ_INVALID_FIELD_IN_CDB
+ );
+ return SATI_FAILURE_CHECK_RESPONSE_DATA;
+ }
+ else
+ {
+ sati_ata_write_uncorrectable_construct(
+ ata_io,
+ sequence,
+ ATA_WRITE_UNCORRECTABLE_PSUEDO
+ );
+ sequence->type = SATI_SEQUENCE_WRITE_LONG;
+ status = SATI_SUCCESS;
+ }
+ break;
+
+ case WR_UNCOR_PBLOCK_BIT :
+
+ sati_ata_write_uncorrectable_construct(
+ ata_io,
+ sequence,
+ ATA_WRITE_UNCORRECTABLE_PSUEDO
+ );
+ sequence->type = SATI_SEQUENCE_WRITE_LONG;
+ status = SATI_SUCCESS;
+ break;
+
+ case COR_DIS_WR_UNCORR_BIT :
+
+ sati_ata_write_uncorrectable_construct(
+ ata_io,
+ sequence,
+ ATA_WRITE_UNCORRECTABLE_FLAGGED
+ );
+ sequence->type = SATI_SEQUENCE_WRITE_LONG;
+ status = SATI_SUCCESS;
+ break;
+
+ default :
+
+ sati_scsi_sense_data_construct(
+ sequence,
+ scsi_io,
+ SCSI_STATUS_CHECK_CONDITION,
+ SCSI_SENSE_ILLEGAL_REQUEST,
+ SCSI_ASC_INVALID_FIELD_IN_CDB,
+ SCSI_ASCQ_INVALID_FIELD_IN_CDB
+ );
+ return SATI_FAILURE_CHECK_RESPONSE_DATA;
+ break;
+ }
+ return status;
+}
+
+/**
+ * @brief This method will translate the response to the SATI Write Long
+ * translation. This response is only error checking the
+ * ATA Write Uncorrectable command.
+ *
+ * @return SATI_STATUS Indicates if the response translation succeeded.
+ * @retval SCI_COMPLETE This is returned if the command translation was
+ * successful.
+ * @retval SATI_FAILURE_CHECK_RESPONSE_DATA is returned if there was
+ * a problem with the translation of write long.
+ */
+SATI_STATUS sati_write_long_translate_response(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ void * ata_io
+)
+{
+ U8 * register_fis = sati_cb_get_d2h_register_fis_address(ata_io);
+
+ if (sati_get_ata_status(register_fis) & ATA_STATUS_REG_ERROR_BIT)
+ {
+ sati_scsi_sense_data_construct(
+ sequence,
+ scsi_io,
+ SCSI_STATUS_CHECK_CONDITION,
+ SCSI_SENSE_ABORTED_COMMAND,
+ SCSI_ASC_COMMAND_SEQUENCE_ERROR,
+ SCSI_ASCQ_NO_ADDITIONAL_SENSE
+ );
+ return SATI_FAILURE_CHECK_RESPONSE_DATA;
+ }
+ else
+ {
+ return SATI_COMPLETE;
+ }
+}
+
+#endif // !defined(DISABLE_SATI_WRITE_LONG)
diff --git a/sys/dev/isci/scil/sati_write_long.h b/sys/dev/isci/scil/sati_write_long.h
new file mode 100644
index 0000000..1084f85
--- /dev/null
+++ b/sys/dev/isci/scil/sati_write_long.h
@@ -0,0 +1,83 @@
+/*-
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 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.
+ *
+ * $FreeBSD$
+ */
+/**
+ * @file
+ * @brief This file contains the method definitions to translate
+ * SCSI Write Long command based of the SAT spec.
+ */
+
+#ifndef _SATI_WRITE_LONG_H_
+#define _SATI_WRITE_LONG_H_
+
+#include <dev/isci/scil/sati_types.h>
+#include <dev/isci/scil/sati_translator_sequence.h>
+
+#define SATI_WRITE_LONG_GET_COR_WR_PB_BITS(cdb) \
+ (( sati_get_cdb_byte(cdb, 1) & 0xE0) \
+ >> 5)
+
+
+SATI_STATUS sati_write_long_translate_command(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ void * ata_io
+);
+
+SATI_STATUS sati_write_long_translate_response(
+ SATI_TRANSLATOR_SEQUENCE_T * sequence,
+ void * scsi_io,
+ void * ata_io
+);
+
+#endif // _SATI_WRITE_LONG_H_
diff --git a/sys/dev/isci/scil/sci_abstract_list.c b/sys/dev/isci/scil/sci_abstract_list.c
new file mode 100644
index 0000000..641eb4a
--- /dev/null
+++ b/sys/dev/isci/scil/sci_abstract_list.c
@@ -0,0 +1,599 @@
+/*-
+ * 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.
+ *
+ * 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 <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/**
+ * @file
+ *
+ * @brief This file contains the implementation of an abstract list class.
+ * This class will allow for the same item to occur multiple times in
+ * the list. It will provide an interface that is similar to the
+ * C++ standard template list interface.
+ */
+
+//******************************************************************************
+//*
+//* I N C L U D E S
+//*
+//******************************************************************************
+
+#include <dev/isci/scil/sci_abstract_list.h>
+
+
+//******************************************************************************
+//*
+//* P R I V A T E M E M B E R S
+//*
+//******************************************************************************
+
+//******************************************************************************
+//*
+//* P R O T E C T E D M E T H O D S
+//*
+//******************************************************************************
+
+/**
+ * @brief Initialize the abstract list
+ *
+ * @pre The supplied free pool should be constructed prior to utilization
+ * of this abstract list. It isn't mandatory for the free pool to be
+ * constructed before invoking this method, but suggested.
+ *
+ * @param[in] list This parameter specifies the abstract list to be
+ * constructed.
+ * @param[in] free_pool This parameter specifies the free pool to be
+ * utilized as the repository of free elements for list usage.
+ *
+ * @return none
+ */
+void sci_abstract_list_construct(
+ SCI_ABSTRACT_LIST_T * list,
+ SCI_ABSTRACT_ELEMENT_POOL_T * free_pool
+)
+{
+ memset(list, 0, sizeof(SCI_ABSTRACT_LIST_T));
+ list->free_pool = free_pool;
+}
+
+/**
+ * Initialize the abstract list with its free pool
+ *
+ * @param[in] pool
+ * the free pool from which the elements will be extracted
+ * @param[in] list_elements
+ * the array of list elements to be added to the free list
+ * @param[in] element_count
+ * the count of the elements to be added to the free list these should be
+ * the same as the array size of list elements
+ *
+ * @return none
+ */
+void sci_abstract_element_pool_construct(
+ SCI_ABSTRACT_ELEMENT_POOL_T * pool,
+ SCI_ABSTRACT_ELEMENT_T * list_elements,
+ int element_count
+)
+{
+ int index;
+
+ memset(pool, 0, sizeof(SCI_ABSTRACT_ELEMENT_POOL_T));
+ memset(list_elements, 0, sizeof(SCI_ABSTRACT_ELEMENT_T) * element_count);
+
+ pool->elements = list_elements;
+ pool->max_elements = element_count;
+
+ // Loop through all of the elements in the array and push them onto the
+ // pool's free list.
+ for (index = element_count - 1; index >= 0; index--)
+ {
+ private_pool_free(pool, &(list_elements[index]));
+ }
+}
+
+
+#ifdef USE_ABSTRACT_LIST_FUNCTIONS
+
+//******************************************************************************
+//*
+//* P U B L I C M E T H O D S
+//*
+//******************************************************************************
+
+/**
+ * Simply return the front element pointer of the list. This returns an element
+ * element as opposed to what the element is pointing to.
+ */
+SCI_ABSTRACT_ELEMENT_T * sci_abstract_list_get_front(
+ SCI_ABSTRACT_LIST_T * list_p
+)
+{
+ return (list_p)->elements.front_p;
+}
+
+/**
+ * This method simply returns the object pointed to by the head (front) of
+ * the list.
+ */
+void * sci_abstract_list_front(
+ SCI_ABSTRACT_LIST_T * list_p
+)
+{
+ return
+ ( ( (list_p)->elements.front_p ) ? ((list_p)->elements.front_p->object_p) : NULL );
+}
+
+/**
+ * This method simply returns the object pointed to by the tail (back) of
+ * the list.
+ */
+void * sci_abstract_list_back(
+ SCI_ABSTRACT_LIST_T * list_p
+)
+{
+ return
+ ( ( (list_p)->elements.back_p ) ? ((list_p)->elements.back_p->object_p) : NULL );
+}
+
+/**
+ * This method will return FALSE if the list is not empty.
+ */
+BOOL sci_abstract_list_is_empty(
+ SCI_ABSTRACT_LIST_T * list_p
+)
+{
+ return ( (list_p)->elements.front_p == NULL );
+}
+
+
+/**
+ * This method will return the number of elements queued in the list.
+ */
+U32 sci_abstract_list_size(
+ SCI_ABSTRACT_LIST_T * list_p
+)
+{
+ return ( (list_p)->elements.size );
+}
+
+
+/**
+ * This method simply returns the next list element in the list.
+ */
+SCI_ABSTRACT_ELEMENT_T * sci_abstract_list_get_next(
+ SCI_ABSTRACT_ELEMENT_T * alElement_p
+)
+{
+ return ( (alElement_p)->next_p );
+}
+
+
+#if defined(SCI_LOGGING)
+/**
+ * This method simply prints the contents of the list.
+ */
+void sci_abstract_list_print(
+ SCI_ABSTRACT_LIST_T * list_p
+)
+{
+ SCI_ABSTRACT_ELEMENT_T * alElement_p = list_p->elements.front_p;
+
+ while (alElement_p != NULL)
+ {
+#ifdef UNIT_TEST_DEBUG
+ /* Check to see if we found the object for which we are searching. */
+ printf("ITEM next_p 0x%x prev_p 0x%x obj_p 0x%x, 0x%x\n",
+ alElement_p->next_p,
+ alElement_p->previous_p,
+ (U32*) (alElement_p->object_p));
+#endif
+ alElement_p = alElement_p->next_p;
+ }
+}
+#endif // defined(SCI_LOGGING)
+
+
+/**
+ * This method will simply search the supplied list for the desired object.
+ * It will return a pointer to the object, if it is found. Otherwise
+ * it will return NULL.
+ */
+void * sci_abstract_list_find(
+ SCI_ABSTRACT_LIST_T * list_p,
+ void * obj_p
+)
+{
+ return
+ sci_abstract_list_get_object(private_find(&(list_p)->elements, (obj_p)));
+}
+
+
+/**
+ * This method will simply remove the element at the back (tail) of the list.
+ * It will return a pointer to the object that was removed or NULL if not
+ * found.
+ */
+void * sci_abstract_list_popback(
+ SCI_ABSTRACT_LIST_T * list_p
+)
+{
+ SCI_ABSTRACT_ELEMENT_LIST_T * elem_list = &(list_p)->elements;
+ SCI_ABSTRACT_ELEMENT_T * alElement_p = elem_list->back_p;
+ void * obj_p = NULL;
+
+ if (alElement_p != NULL)
+ {
+ obj_p = alElement_p->object_p;
+ if (elem_list->back_p == elem_list->front_p)
+ {
+ elem_list->back_p = elem_list->front_p = NULL;
+ }
+ else
+ {
+ elem_list->back_p = elem_list->back_p->previous_p;
+ elem_list->back_p->next_p = NULL;
+ }
+
+ elem_list->size--;
+ private_pool_free((list_p)->free_pool, alElement_p);
+ }
+
+ return obj_p;
+}
+
+/**
+ * This method simply removes the list element at the head of the list
+ * and returns the pointer to the object that was removed.
+ */
+void * sci_abstract_list_popfront(
+ SCI_ABSTRACT_LIST_T * list_p
+)
+{
+ SCI_ABSTRACT_ELEMENT_T * alElement_p =
+ private_pop_front(&(list_p)->elements);
+ void * obj_p = NULL;
+
+ if (alElement_p != NULL)
+ {
+ obj_p = alElement_p->object_p;
+ private_pool_free((list_p)->free_pool, alElement_p);
+ }
+
+ return obj_p;
+}
+
+
+
+/**
+ * This method will erase (remove) all instances of the supplied object from
+ * anywhere in the list.
+ */
+void sci_abstract_list_erase(
+ SCI_ABSTRACT_LIST_T * list_p,
+ void * obj_p
+)
+{
+ SCI_ABSTRACT_ELEMENT_LIST_T * elem_list = &(list_p)->elements;
+ SCI_ABSTRACT_ELEMENT_T * alElement_p;
+
+ while ((alElement_p = private_find(elem_list, (obj_p))) != NULL)
+ {
+ if (alElement_p == elem_list->front_p)
+ {
+ sci_abstract_list_popfront(list_p);
+ }
+ else if (alElement_p == elem_list->back_p)
+ {
+ sci_abstract_list_popback(list_p);
+ }
+ else
+ {
+ alElement_p->previous_p->next_p = alElement_p->next_p;
+ alElement_p->next_p->previous_p = alElement_p->previous_p;
+ elem_list->size--;
+ private_pool_free((list_p)->free_pool, alElement_p);
+ }
+ }
+ return;
+}
+
+/**
+ * This method simply adds a LIST_ELEMENT for the supplied object to the back
+ * (tail) of the supplied list.
+ */
+void sci_abstract_list_pushback(
+ SCI_ABSTRACT_LIST_T * list_p,
+ void * obj_p
+)
+{
+ SCI_ABSTRACT_ELEMENT_LIST_T * elem_list = &(list_p)->elements;
+ SCI_ABSTRACT_ELEMENT_T * alElement_p
+ = private_pool_allocate((list_p)->free_pool);
+// assert(alElement_p != NULL);
+
+ alElement_p->object_p = (obj_p);
+
+ if (elem_list->front_p == NULL)
+ {
+ elem_list->front_p = elem_list->back_p = alElement_p;
+ }
+ else
+ {
+ elem_list->back_p->next_p = alElement_p;
+ alElement_p->previous_p = elem_list->back_p;
+ elem_list->back_p = alElement_p;
+ }
+
+ elem_list->size++;
+}
+
+
+
+/**
+ * This method simply adds a LIST_ELEMENT for the supplied object to the front
+ * (head) of the supplied list.
+ */
+void sci_abstract_list_pushfront(
+ SCI_ABSTRACT_LIST_T * list_p,
+ void * obj_p
+)
+{
+ SCI_ABSTRACT_ELEMENT_T * alElement_p =
+ private_pool_allocate((list_p)->free_pool);
+ alElement_p->object_p = (obj_p);
+ private_push_front(&(list_p)->elements, alElement_p);
+}
+
+
+/**
+ * This method will add the objToAdd_p object to the list before the obj_p.
+ *
+ */
+void sci_abstract_list_insert(
+ SCI_ABSTRACT_LIST_T * list_p,
+ void * obj_p,
+ void * objToAdd_p
+)
+{
+ SCI_ABSTRACT_ELEMENT_LIST_T * elem_list = &(list_p)->elements;
+
+ SCI_ABSTRACT_ELEMENT_T * obj_element = private_find(elem_list, obj_p);
+
+ SCI_ABSTRACT_ELEMENT_T * objToAdd_element =
+ private_pool_allocate((list_p)->free_pool);
+
+ objToAdd_element->object_p = objToAdd_p;
+
+ ASSERT(obj_element != NULL);
+ ASSERT(objToAdd_element != NULL);
+
+ if (obj_element == elem_list->front_p)
+ {
+ objToAdd_element->object_p = (objToAdd_p);
+ private_push_front(&(list_p)->elements, objToAdd_element);
+ }
+ else
+ {
+ obj_element->previous_p->next_p = objToAdd_element;
+ objToAdd_element->previous_p = obj_element->previous_p;
+
+ obj_element->previous_p = objToAdd_element;
+ objToAdd_element->next_p = obj_element;
+
+ elem_list->size++;
+ }
+}
+
+/**
+ * This method simply frees all the items from the list.
+ */
+void sci_abstract_list_clear(
+ SCI_ABSTRACT_LIST_T * list_p
+)
+{
+ while ((list_p)->elements.size > 0)
+ sci_abstract_list_popfront((list_p));
+}
+
+/**
+ * This method simply returns the object being pointed to by the list element
+ * (The item being listed).
+ */
+void * sci_abstract_list_get_object(
+ SCI_ABSTRACT_ELEMENT_T * alElement_p
+)
+{
+ void * obj_p = NULL;
+ if ((alElement_p) != NULL)
+ obj_p = (alElement_p)->object_p;
+
+ return obj_p;
+}
+
+
+/**
+ * This method is simply a wrapper to provide the number of elements in
+ * the free list.
+ */
+U32 sci_abstract_list_freeList_size(
+ SCI_ABSTRACT_LIST_T * freeList
+)
+{
+ return (sci_abstract_list_size(freeList));
+}
+
+//******************************************************************************
+//*
+//* P R I V A T E M E T H O D S
+//*
+//******************************************************************************
+
+/**
+ * This method simply performs the common portion of pushing a list element
+ * onto a list.
+ *
+ * WARNING: This is a private helper method that should not be called directly
+ * by any users.
+ */
+void private_push_front(
+ SCI_ABSTRACT_ELEMENT_LIST_T * privateList_p,
+ SCI_ABSTRACT_ELEMENT_T * alElement_p
+)
+{
+ if ((privateList_p)->front_p == NULL)
+ {
+ (privateList_p)->front_p = (privateList_p)->back_p = (alElement_p);
+ (alElement_p)->next_p = (alElement_p)->previous_p = NULL;
+ }
+ else
+ {
+ (alElement_p)->next_p = (privateList_p)->front_p;
+ (alElement_p)->previous_p = NULL;
+ (privateList_p)->front_p->previous_p = (alElement_p);
+ (privateList_p)->front_p = (alElement_p);
+ }
+
+ (privateList_p)->size++;
+}
+
+/**
+ * This method simply performs the common portion of popping a list element
+ * from a list.
+ *
+ * WARNING: This is a private helper method that should not be called directly
+ * by any users.
+ */
+SCI_ABSTRACT_ELEMENT_T * private_pop_front(
+ SCI_ABSTRACT_ELEMENT_LIST_T * privateList_p
+)
+{
+ SCI_ABSTRACT_ELEMENT_T * alElement_p = (privateList_p)->front_p;
+
+ if (alElement_p != NULL)
+ {
+ if ((privateList_p)->front_p == (privateList_p)->back_p)
+ {
+ (privateList_p)->front_p = (privateList_p)->back_p = NULL;
+ }
+ else
+ {
+ (privateList_p)->front_p = (privateList_p)->front_p->next_p;
+ (privateList_p)->front_p->previous_p = NULL;
+ }
+
+ (privateList_p)->size--;
+ }
+
+ return alElement_p;
+}
+
+/**
+ * This method will simply search the supplied list for the desired object.
+ * It will return a pointer to the abstract_list_element if found, otherwise
+ * it will return NULL.
+ */
+SCI_ABSTRACT_ELEMENT_T * private_find(
+ SCI_ABSTRACT_ELEMENT_LIST_T * list_p,
+ void * obj_p
+)
+{
+ SCI_ABSTRACT_ELEMENT_T * alElement_p = (list_p)->front_p;
+
+ while (alElement_p != NULL)
+ {
+ /* Check to see if we found the object for which we are searching. */
+ if (alElement_p->object_p == (void*) (obj_p))
+ {
+ break;
+ }
+
+ alElement_p = alElement_p->next_p;
+ }
+
+ return alElement_p;
+}
+
+/**
+ * This private method will free the supplied list element back to the pool
+ * of free list elements.
+ */
+void private_pool_free(
+ SCI_ABSTRACT_ELEMENT_POOL_T * free_pool,
+ SCI_ABSTRACT_ELEMENT_T * alElement_p
+)
+{
+ /* Push the list element back to the head to get better locality of */
+ /* reference with the cache. */
+ private_push_front(&(free_pool)->free_list, (alElement_p));
+}
+
+/**
+ * This private method will allocate a list element from the pool of free
+ * list elements.
+ */
+SCI_ABSTRACT_ELEMENT_T * private_pool_allocate(
+ SCI_ABSTRACT_ELEMENT_POOL_T * free_pool
+)
+{
+ SCI_ABSTRACT_ELEMENT_T * alElement_p;
+
+ alElement_p = private_pop_front(&(free_pool)->free_list);
+
+ alElement_p->next_p = NULL;
+ alElement_p->previous_p = NULL;
+ alElement_p->object_p = NULL;
+
+ return alElement_p;
+}
+
+#endif // USE_ABSTRACT_LIST_FUNCTIONS
diff --git a/sys/dev/isci/scil/sci_abstract_list.h b/sys/dev/isci/scil/sci_abstract_list.h
new file mode 100644
index 0000000..7ae53ea
--- /dev/null
+++ b/sys/dev/isci/scil/sci_abstract_list.h
@@ -0,0 +1,871 @@
+/*-
+ * 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.
+ *
+ * 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.
+ *
+ * $FreeBSD$
+ */
+/**
+ * @file
+ *
+ * @brief This file contains the interface to the abstract list class.
+ * This class will allow for the same item to occur multiple times in
+ * a list or multiple lists. It will provide an interface that is
+ * similar to the C++ standard template list interface.
+ * Methods Provided:
+ * - sci_abstract_list_front()
+ * - sci_abstract_list_back()
+ * - sci_abstract_list_is_empty()
+ * - sci_abstract_list_size()
+ * - sci_abstract_list_print()
+ * - sci_abstract_list_find()
+ * - sci_abstract_list_popback()
+ * - sci_abstract_list_popfront()
+ * - sci_abstract_list_erase()
+ * - sci_abstract_list_pushback()
+ * - sci_abstract_list_pushfront()
+ * - sci_abstract_list_get_object()
+ * - sci_abstract_list_get_next()
+ * - sci_abstract_list_insert() UNIMPLEMENTED
+ * - sci_abstract_list_clear()
+ */
+
+#ifndef _SCI_ABSTRACT_LIST_H_
+#define _SCI_ABSTRACT_LIST_H_
+
+//******************************************************************************
+//*
+//* I N C L U D E S
+//*
+//******************************************************************************
+
+#include <dev/isci/scil/sci_types.h>
+
+//******************************************************************************
+//*
+//* C O N S T A N T S
+//*
+//******************************************************************************
+
+//******************************************************************************
+//*
+//* T Y P E S
+//*
+//******************************************************************************
+
+/**
+ * @struct SCI_ABSTRACT_ELEMENT
+ *
+ * @brief This object represents an element of a abstract list.
+ * NOTE: This structure does not evenly align on a cache line
+ * boundary. If SSP specific code ends up using this list,
+ * then it may be a good idea to force the alignment. Now
+ * it is more important to save the space.
+ */
+typedef struct SCI_ABSTRACT_ELEMENT
+{
+ /**
+ * This field points to the next item in the abstract_list.
+ */
+ struct SCI_ABSTRACT_ELEMENT * next_p;
+
+ /**
+ * This field points to the previous item in the abstract_list.
+ */
+ struct SCI_ABSTRACT_ELEMENT * previous_p;
+
+ /**
+ * This field points to the object the list is managing (i.e. the thing
+ * being listed).
+ */
+ void * object_p;
+
+} SCI_ABSTRACT_ELEMENT_T;
+
+/**
+ * @struct SCI_ABSTRACT_ELEMENT_LIST
+ *
+ * @brief This object represents an element list object. It can have
+ * elements added and removed from it.
+ */
+typedef struct SCI_ABSTRACT_ELEMENT_LIST
+{
+ /**
+ * Pointer to the front (head) of the list.
+ */
+ SCI_ABSTRACT_ELEMENT_T * front_p;
+
+ /**
+ * Pointer to the back (tail) of the list.
+ */
+ SCI_ABSTRACT_ELEMENT_T * back_p;
+
+ /**
+ * This field depicts the number of elements in this list.
+ * NOTE: It is possible to remove this field and replace it with a
+ * linear walking of the list to determine the size, but since
+ * there aren't many lists in the system we don't utilize much
+ * space.
+ */
+ U32 size;
+
+} SCI_ABSTRACT_ELEMENT_LIST_T;
+
+/**
+ * @struct SCI_ABSTRACT_ELEMENT_POOL
+ *
+ * @brief This structure provides the pool of free abstract elements to be
+ * utilized by an SCI_ABSTRACT_LIST.
+ */
+typedef struct SCI_ABSTRACT_ELEMENT_POOL
+{
+ /**
+ * Pointer to an array of elements to be managed by this pool. This
+ * array acts as the memory store for the elements in the free pool or
+ * allocated out of the pool into an SCI_ABSTRACT_LIST.
+ */
+ SCI_ABSTRACT_ELEMENT_T * elements;
+
+ /**
+ * This field contains the maximum number of free elements for the pool.
+ * It is set at creation of the pool and should not be changed afterward.
+ */
+ U32 max_elements;
+
+ /**
+ * Pointer to the list of free elements that can be allocated from
+ * the pool.
+ */
+ struct SCI_ABSTRACT_ELEMENT_LIST free_list;
+
+} SCI_ABSTRACT_ELEMENT_POOL_T;
+
+/**
+ * @struct SCI_ABSTRACT_LIST
+ *
+ * @brief This object provides the ability to queue any type of object or
+ * even the same object multiple times. The object must be provided
+ * an element pool from which to draw free elements.
+ */
+typedef struct SCI_ABSTRACT_LIST
+{
+ /**
+ * This represents the elements currently managed by the list.
+ */
+ SCI_ABSTRACT_ELEMENT_LIST_T elements;
+
+ /**
+ * This field contains elements that are currently available for
+ * allocation into the list of elements;
+ */
+ SCI_ABSTRACT_ELEMENT_POOL_T * free_pool;
+
+} SCI_ABSTRACT_LIST_T;
+
+//******************************************************************************
+//*
+//* P R O T E C T E D M E T H O D S
+//*
+//******************************************************************************
+
+void sci_abstract_element_pool_construct(
+ SCI_ABSTRACT_ELEMENT_POOL_T * pool,
+ SCI_ABSTRACT_ELEMENT_T * list_elements,
+ int element_count
+);
+
+void sci_abstract_list_construct(
+ SCI_ABSTRACT_LIST_T * list,
+ SCI_ABSTRACT_ELEMENT_POOL_T * free_pool
+);
+
+
+
+#ifdef USE_ABSTRACT_LIST_FUNCTIONS
+//******************************************************************************
+//*
+//* P U B L I C M E T H O D S
+//*
+//******************************************************************************
+
+/**
+ * Simply return the front element pointer of the list. This returns an element
+ * element as opposed to what the element is pointing to.
+ */
+SCI_ABSTRACT_ELEMENT_T * sci_abstract_list_get_front(
+ SCI_ABSTRACT_LIST_T * list_p
+);
+
+
+/**
+ * This method simply returns the object pointed to by the head (front) of
+ * the list.
+ */
+void * sci_abstract_list_front(
+ SCI_ABSTRACT_LIST_T * list_p
+);
+
+
+/**
+ * This method simply returns the object pointed to by the tail (back) of
+ * the list.
+ */
+void * sci_abstract_list_back(
+ SCI_ABSTRACT_LIST_T * list_p
+);
+
+
+/**
+ * This method will return FALSE if the list is not empty.
+ */
+BOOL sci_abstract_list_is_empty(
+ SCI_ABSTRACT_LIST_T * list_p
+);
+
+
+/**
+ * This method will return the number of elements queued in the list.
+ */
+U32 sci_abstract_list_size(
+ SCI_ABSTRACT_LIST_T * list_p
+);
+
+
+/**
+ * This method simply returns the next list element in the list.
+ */
+SCI_ABSTRACT_ELEMENT_T * sci_abstract_list_get_next(
+ SCI_ABSTRACT_ELEMENT_T * alElement_p
+);
+
+
+/**
+ * This method simply prints the contents of the list.
+ */
+void sci_abstract_list_print(
+ SCI_ABSTRACT_LIST_T * list_p
+);
+
+
+/**
+ * This method will simply search the supplied list for the desired object.
+ * It will return a pointer to the object, if it is found. Otherwise
+ * it will return NULL.
+ */
+void * sci_abstract_list_find(
+ SCI_ABSTRACT_LIST_T * list_p,
+ void * obj_p
+);
+
+
+/**
+ * This method will simply remove the element at the back (tail) of the list.
+ * It will return a pointer to the object that was removed or NULL if not
+ * found.
+ */
+void * sci_abstract_list_popback(
+ SCI_ABSTRACT_LIST_T * list_p
+);
+
+
+/**
+ * This method simply removes the list element at the head of the list
+ * and returns the pointer to the object that was removed.
+ */
+void * sci_abstract_list_popfront(
+ SCI_ABSTRACT_LIST_T * list_p
+);
+
+
+
+/**
+ * This method will erase (remove) all instances of the supplied object from
+ * anywhere in the list.
+ */
+void sci_abstract_list_erase(
+ SCI_ABSTRACT_LIST_T * list_p,
+ void * obj_p
+);
+
+
+/**
+ * This method simply adds a LIST_ELEMENT for the supplied object to the back
+ * (tail) of the supplied list.
+ */
+void sci_abstract_list_pushback(
+ SCI_ABSTRACT_LIST_T * list_p,
+ void * obj_p
+);
+
+
+
+/**
+ * This method simply adds a LIST_ELEMENT for the supplied object to the front
+ * (head) of the supplied list.
+ */
+void sci_abstract_list_pushfront(
+ SCI_ABSTRACT_LIST_T * list_p,
+ void * obj_p
+);
+
+
+/**
+ * This method will add the objToAdd_p object to the list before the obj_p.
+ * NOTE: UNIMPLEMENTED
+ */
+void sci_abstract_list_insert(
+ SCI_ABSTRACT_LIST_T * list_p,
+ void * obj_p,
+ void * objToAdd_p
+);
+
+
+/**
+ * This method simply frees all the items from the list.
+ */
+void sci_abstract_list_clear(
+ SCI_ABSTRACT_LIST_T * list_p
+);
+
+
+/**
+ * This method simply returns the object being pointed to by the list element
+ * (The item being listed).
+ */
+void * sci_abstract_list_get_object(
+ SCI_ABSTRACT_ELEMENT_T * alElement_p
+);
+
+
+/**
+ * This method is simply a wrapper to provide the number of elements in
+ * the free list.
+ */
+U32 sci_abstract_list_freeList_size(
+ SCI_ABSTRACT_LIST_T * freeList
+);
+
+
+//******************************************************************************
+//*
+//* P R I V A T E M E T H O D S
+//*
+//******************************************************************************
+
+/**
+ * This method simply performs the common portion of pushing a list element
+ * onto a list.
+ *
+ * WARNING: This is a private helper method that should not be called directly
+ * by any users.
+ */
+void private_push_front(
+ SCI_ABSTRACT_ELEMENT_LIST_T * privateList_p,
+ SCI_ABSTRACT_ELEMENT_T * alElement_p
+);
+
+
+/**
+ * This method simply performs the common portion of popping a list element
+ * from a list.
+ *
+ * WARNING: This is a private helper method that should not be called directly
+ * by any users.
+ */
+SCI_ABSTRACT_ELEMENT_T * private_pop_front(
+ SCI_ABSTRACT_ELEMENT_LIST_T * privateList_p
+);
+
+
+/**
+ * This method will simply search the supplied list for the desired object.
+ * It will return a pointer to the abstract_list_element if found, otherwise
+ * it will return NULL.
+ */
+SCI_ABSTRACT_ELEMENT_T * private_find(
+ SCI_ABSTRACT_ELEMENT_LIST_T * list_p,
+ void * obj_p
+);
+
+
+/**
+ * This private method will free the supplied list element back to the pool
+ * of free list elements.
+ */
+void private_pool_free(
+ SCI_ABSTRACT_ELEMENT_POOL_T * free_pool,
+ SCI_ABSTRACT_ELEMENT_T * alElement_p
+);
+
+
+/**
+ * This private method will allocate a list element from the pool of free
+ * list elements.
+ */
+SCI_ABSTRACT_ELEMENT_T * private_pool_allocate(
+ SCI_ABSTRACT_ELEMENT_POOL_T * free_pool
+);
+
+
+#else
+
+//******************************************************************************
+//*
+//* P U B L I C M E T H O D S
+//*
+//******************************************************************************
+
+/**
+ * Simply return the front element pointer of the list. This returns an element
+ * element as opposed to what the element is pointing to.
+ */
+#define sci_abstract_list_get_front( \
+ list_p \
+) \
+((list_p)->elements.front_p)
+
+/**
+ * This method simply returns the object pointed to by the head (front) of
+ * the list.
+ */
+#define sci_abstract_list_front( \
+ list_p \
+) \
+( ( (list_p)->elements.front_p ) ? ((list_p)->elements.front_p->object_p) : NULL )
+
+/**
+ * This method simply returns the object pointed to by the tail (back) of
+ * the list.
+ */
+#define sci_abstract_list_back( \
+ list_p \
+) \
+( ( (list_p)->elements.back_p ) ? ((list_p)->elements.back_p->object_p) : NULL )
+
+/**
+ * This method will return FALSE if the list is not empty.
+ */
+#define sci_abstract_list_is_empty( \
+ list_p \
+) \
+( (list_p)->elements.front_p == NULL )
+
+/**
+ * This method will return the number of elements queued in the list.
+ */
+#define sci_abstract_list_size( \
+ list_p \
+) \
+( (list_p)->elements.size )
+
+/**
+ * This method simply returns the next list element in the list.
+ */
+#define sci_abstract_list_get_next( \
+ alElement_p \
+) \
+( (alElement_p)->next_p )
+
+/**
+ * This method simply prints the contents of the list.
+ */
+#define sci_abstract_list_print( \
+ list_p \
+) \
+{ \
+ SCI_ABSTRACT_ELEMENT_T * alElement_p = list_p->elements.front_p; \
+ \
+ while (alElement_p != NULL) \
+ { \
+ /* Check to see if we found the object for which we are searching. */ \
+ printf("ITEM next_p 0x%x prev_p 0x%x obj_p 0x%x, 0x%x\n", \
+ alElement_p->next_p, \
+ alElement_p->previous_p, \
+ (U32*) (alElement_p->object_p)); \
+ \
+ alElement_p = alElement_p->next_p; \
+ } \
+}
+
+/**
+ * This method will simply search the supplied list for the desired object.
+ * It will return a pointer to the object, if it is found. Otherwise
+ * it will return NULL.
+ */
+#define sci_abstract_list_find( \
+ list_p, \
+ obj_p \
+) \
+({ \
+ sci_abstract_list_get_object(private_find(&(list_p)->elements, (obj_p))); \
+})
+
+/**
+ * This method will simply remove the element at the back (tail) of the list.
+ * It will return a pointer to the object that was removed or NULL if not
+ * found.
+ */
+#define sci_abstract_list_popback( \
+ list_p \
+) \
+({ \
+ SCI_ABSTRACT_ELEMENT_LIST_T * elem_list = &(list_p)->elements; \
+ SCI_ABSTRACT_ELEMENT_T * alElement_p = elem_list->back_p; \
+ void * obj_p = NULL; \
+ \
+ if (alElement_p != NULL) \
+ { \
+ obj_p = alElement_p->object_p; \
+ if (elem_list->back_p == elem_list->front_p) \
+ { \
+ elem_list->back_p = elem_list->front_p = NULL; \
+ } \
+ else \
+ { \
+ elem_list->back_p = elem_list->back_p->previous_p; \
+ elem_list->back_p->next_p = NULL; \
+ } \
+ \
+ elem_list->size--; \
+ private_pool_free((list_p)->free_pool, alElement_p); \
+ } \
+ \
+ obj_p; \
+})
+
+/**
+ * This method simply removes the list element at the head of the list
+ * and returns the pointer to the object that was removed.
+ */
+#define sci_abstract_list_popfront( \
+ list_p \
+) \
+({ \
+ SCI_ABSTRACT_ELEMENT_T * alElement_p = \
+ private_pop_front(&(list_p)->elements); \
+ void * obj_p = NULL; \
+ \
+ if (alElement_p != NULL) \
+ { \
+ obj_p = alElement_p->object_p; \
+ private_pool_free((list_p)->free_pool, alElement_p); \
+ } \
+ \
+ obj_p; \
+})
+
+/**
+ * This method will erase (remove) all instances of the supplied object from
+ * anywhere in the list.
+ */
+#define sci_abstract_list_erase( \
+ list_p, \
+ obj_p \
+) \
+{ \
+ SCI_ABSTRACT_ELEMENT_LIST_T * elem_list = &(list_p)->elements; \
+ SCI_ABSTRACT_ELEMENT_T * alElement_p; \
+ \
+ while ((alElement_p = private_find(elem_list, (obj_p))) != NULL) \
+ { \
+ if (alElement_p == elem_list->front_p) \
+ { \
+ sci_abstract_list_popfront(list_p); \
+ } \
+ else if (alElement_p == elem_list->back_p) \
+ { \
+ sci_abstract_list_popback(list_p); \
+ } \
+ else \
+ { \
+ alElement_p->previous_p->next_p = alElement_p->next_p; \
+ alElement_p->next_p->previous_p = alElement_p->previous_p; \
+ elem_list->size--; \
+ private_pool_free((list_p)->free_pool, alElement_p); \
+ } \
+ } \
+}
+
+/**
+ * This method simply adds a LIST_ELEMENT for the supplied object to the back
+ * (tail) of the supplied list.
+ */
+#define sci_abstract_list_pushback( \
+ list_p, \
+ obj_p \
+) \
+{ \
+ SCI_ABSTRACT_ELEMENT_LIST_T * elem_list = &(list_p)->elements; \
+ SCI_ABSTRACT_ELEMENT_T * alElement_p \
+ = private_pool_allocate((list_p)->free_pool); \
+ assert(alElement_p != NULL); \
+ \
+ alElement_p->object_p = (obj_p); \
+ \
+ if (elem_list->front_p == NULL) \
+ { \
+ elem_list->front_p = elem_list->back_p = alElement_p; \
+ } \
+ else \
+ { \
+ elem_list->back_p->next_p = alElement_p; \
+ alElement_p->previous_p = elem_list->back_p; \
+ elem_list->back_p = alElement_p; \
+ } \
+ \
+ elem_list->size++; \
+}
+
+/**
+ * This method simply adds a LIST_ELEMENT for the supplied object to the front
+ * (head) of the supplied list.
+ */
+#define sci_abstract_list_pushfront( \
+ list_p, \
+ obj_p \
+) \
+{ \
+ SCI_ABSTRACT_ELEMENT_T * alElement_p = \
+ private_pool_allocate((list_p)->free_pool); \
+ alElement_p->object_p = (obj_p); \
+ private_push_front(&(list_p)->elements, alElement_p); \
+}
+
+/**
+ * This method will add the objToAdd_p object to the list before the obj_p.
+ * NOTE: UNIMPLEMENTED
+ */
+#define sci_abstract_list_insert( \
+ list_p, \
+ obj_p, \
+ objToAdd_p \
+) \
+{ \
+ SCI_ABSTRACT_ELEMENT_LIST_T * elem_list = &(list_p)->elements; \
+ \
+ SCI_ABSTRACT_ELEMENT_T * obj_element = private_find(elem_list, obj_p); \
+ \
+ SCI_ABSTRACT_ELEMENT_T * objToAdd_element = \
+ private_pool_allocate((list_p)->free_pool); \
+ \
+ objToAdd_element->object_p = objToAdd_p; \
+ \
+ ASSERT(obj_element != NULL); \
+ ASSERT(objToAdd_element != NULL); \
+ \
+ if (obj_element == elem_list->front_p) \
+ { \
+ objToAdd_element->object_p = (objToAdd_p); \
+ private_push_front(&(list_p)->elements, objToAdd_element); \
+ } \
+ else \
+ { \
+ obj_element->previous_p->next_p = objToAdd_element; \
+ objToAdd_element->previous_p = obj_element->previous_p; \
+ \
+ obj_element->previous_p = objToAdd_element; \
+ objToAdd_element->next_p = obj_element; \
+ \
+ elem_list->size++; \
+ } \
+}
+
+/**
+ * This method simply frees all the items from the list.
+ */
+#define sci_abstract_list_clear( \
+ list_p \
+) \
+{ \
+ while ((list_p)->elements.size > 0) \
+ sci_abstract_list_popfront((list_p)); \
+}
+
+/**
+ * This method simply returns the object being pointed to by the list element
+ * (The item being listed).
+ */
+#define sci_abstract_list_get_object( \
+ alElement_p \
+) \
+({ \
+ void * obj_p = NULL; \
+ if ((alElement_p) != NULL) \
+ obj_p = (alElement_p)->object_p; \
+ \
+ obj_p; \
+})
+
+/**
+ * This method is simply a wrapper to provide the number of elements in
+ * the free list.
+ */
+#define sci_abstract_list_freeList_size(freeList) (sci_abstract_list_size(freeList))
+
+//******************************************************************************
+//*
+//* P R I V A T E M E T H O D S
+//*
+//******************************************************************************
+
+/**
+ * This method simply performs the common portion of pushing a list element
+ * onto a list.
+ *
+ * WARNING: This is a private helper method that should not be called directly
+ * by any users.
+ */
+#define private_push_front( \
+ privateList_p, \
+ alElement_p \
+) \
+{ \
+ if ((privateList_p)->front_p == NULL) \
+ { \
+ (privateList_p)->front_p = (privateList_p)->back_p = (alElement_p); \
+ (alElement_p)->next_p = (alElement_p)->previous_p = NULL; \
+ } \
+ else \
+ { \
+ (alElement_p)->next_p = (privateList_p)->front_p; \
+ (alElement_p)->previous_p = NULL; \
+ (privateList_p)->front_p->previous_p = (alElement_p); \
+ (privateList_p)->front_p = (alElement_p); \
+ } \
+ \
+ (privateList_p)->size++; \
+}
+
+/**
+ * This method simply performs the common portion of popping a list element
+ * from a list.
+ *
+ * WARNING: This is a private helper method that should not be called directly
+ * by any users.
+ */
+#define private_pop_front( \
+ privateList_p \
+) \
+({ \
+ SCI_ABSTRACT_ELEMENT_T * alElement_p = (privateList_p)->front_p; \
+ \
+ if (alElement_p != NULL) \
+ { \
+ if ((privateList_p)->front_p == (privateList_p)->back_p) \
+ { \
+ (privateList_p)->front_p = (privateList_p)->back_p = NULL; \
+ } \
+ else \
+ { \
+ (privateList_p)->front_p = (privateList_p)->front_p->next_p; \
+ (privateList_p)->front_p->previous_p = NULL; \
+ } \
+ \
+ (privateList_p)->size--; \
+ } \
+ \
+ alElement_p; \
+})
+
+/**
+ * This method will simply search the supplied list for the desired object.
+ * It will return a pointer to the abstract_list_element if found, otherwise
+ * it will return NULL.
+ */
+#define private_find( \
+ list_p, \
+ obj_p \
+) \
+({ \
+ SCI_ABSTRACT_ELEMENT_T * alElement_p = (list_p)->front_p; \
+ \
+ while (alElement_p != NULL) \
+ { \
+ /* Check to see if we found the object for which we are searching. */ \
+ if (alElement_p->object_p == (void*) (obj_p)) \
+ { \
+ break; \
+ } \
+ \
+ alElement_p = alElement_p->next_p; \
+ } \
+ \
+ alElement_p; \
+})
+
+/**
+ * This private method will free the supplied list element back to the pool
+ * of free list elements.
+ */
+#define private_pool_free( \
+ free_pool, \
+ alElement_p \
+) \
+{ \
+ /* Push the list element back to the head to get better locality of */ \
+ /* reference with the cache. */ \
+ private_push_front(&(free_pool)->free_list, (alElement_p)); \
+}
+
+/**
+ * This private method will allocate a list element from the pool of free
+ * list elements.
+ */
+#define private_pool_allocate(free_pool) \
+({ \
+ SCI_ABSTRACT_ELEMENT_T * alElement_p; \
+ \
+ alElement_p = private_pop_front(&(free_pool)->free_list); \
+ \
+ memset(alElement_p, 0, sizeof(SCI_ABSTRACT_ELEMENT_T)); \
+ alElement_p; \
+})
+
+#endif
+#endif // _ABSTRACT_LIST_H_
diff --git a/sys/dev/isci/scil/sci_base_controller.c b/sys/dev/isci/scil/sci_base_controller.c
new file mode 100644
index 0000000..5253304
--- /dev/null
+++ b/sys/dev/isci/scil/sci_base_controller.c
@@ -0,0 +1,105 @@
+/*-
+ * 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.
+ *
+ * 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 <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/**
+ * @file
+ *
+ * @brief This file contains the base controller method implementations and
+ * any constants or structures private to the base controller object
+ * or common to all controller derived objects.
+ */
+
+#include <dev/isci/scil/sci_base_controller.h>
+#include <dev/isci/scil/sci_controller.h>
+
+//******************************************************************************
+//* P U B L I C M E T H O D S
+//******************************************************************************
+
+SCI_MEMORY_DESCRIPTOR_LIST_HANDLE_T sci_controller_get_memory_descriptor_list_handle(
+ SCI_CONTROLLER_HANDLE_T controller
+)
+{
+ SCI_BASE_CONTROLLER_T * this_controller = (SCI_BASE_CONTROLLER_T*)controller;
+ return (SCI_MEMORY_DESCRIPTOR_LIST_HANDLE_T) &this_controller->mdl;
+}
+
+//******************************************************************************
+//* P R O T E C T E D M E T H O D S
+//******************************************************************************
+
+void sci_base_controller_construct(
+ SCI_BASE_CONTROLLER_T * this_controller,
+ SCI_BASE_LOGGER_T * logger,
+ SCI_BASE_STATE_T * state_table,
+ SCI_PHYSICAL_MEMORY_DESCRIPTOR_T * mdes,
+ U32 mde_count,
+ SCI_MEMORY_DESCRIPTOR_LIST_HANDLE_T next_mdl
+)
+{
+ sci_base_object_construct((SCI_BASE_OBJECT_T *)this_controller, logger);
+
+ sci_base_state_machine_construct(
+ &this_controller->state_machine,
+ &this_controller->parent,
+ state_table,
+ SCI_BASE_CONTROLLER_STATE_INITIAL
+ );
+
+ sci_base_mdl_construct(&this_controller->mdl, mdes, mde_count, next_mdl);
+
+ sci_base_state_machine_start(&this_controller->state_machine);
+}
+
diff --git a/sys/dev/isci/scil/sci_base_controller.h b/sys/dev/isci/scil/sci_base_controller.h
new file mode 100644
index 0000000..5436840
--- /dev/null
+++ b/sys/dev/isci/scil/sci_base_controller.h
@@ -0,0 +1,347 @@
+/*-
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 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.
+ *
+ * $FreeBSD$
+ */
+#ifndef _SCI_BASE_CONTROLLER_H_
+#define _SCI_BASE_CONTROLLER_H_
+
+/**
+ * @file
+ *
+ * @brief This file contains all of the structures, constants, and methods
+ * common to all controller object definitions.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif // __cplusplus
+
+#include <dev/isci/scil/intel_sas.h>
+#include <dev/isci/scil/sci_controller_constants.h>
+
+#include <dev/isci/scil/sci_base_object.h>
+#include <dev/isci/scil/sci_base_state.h>
+#include <dev/isci/scil/sci_base_logger.h>
+#include <dev/isci/scil/sci_base_memory_descriptor_list.h>
+#include <dev/isci/scil/sci_base_state_machine.h>
+#include <dev/isci/scil/sci_base_state_machine_logger.h>
+
+/**
+ * @enum SCI_BASE_CONTROLLER_STATES
+ *
+ * @brief This enumeration depicts all the states for the common controller
+ * state machine.
+ */
+typedef 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
+
+} SCI_BASE_CONTROLLER_STATES;
+
+/**
+ * @struct SCI_BASE_CONTROLLER
+ *
+ * @brief The base controller object abstracts the fields common to all
+ * SCI controller objects.
+ */
+typedef struct SCI_BASE_CONTROLLER
+{
+ /**
+ * The field specifies that the parent object for the base controller
+ * is the base object itself.
+ */
+ SCI_BASE_OBJECT_T parent;
+
+ /**
+ * This field points to the memory descriptor list associated with this
+ * controller. The MDL indicates the memory requirements necessary for
+ * this controller object.
+ */
+ SCI_BASE_MEMORY_DESCRIPTOR_LIST_T mdl;
+
+ /**
+ * This field records the fact that the controller has encountered a fatal memory
+ * error and controller must stay in failed state.
+ */
+ U8 error;
+
+ /**
+ * This field contains the information for the base controller state
+ * machine.
+ */
+ SCI_BASE_STATE_MACHINE_T state_machine;
+
+ #ifdef SCI_LOGGING
+ SCI_BASE_STATE_MACHINE_LOGGER_T state_machine_logger;
+ #endif // SCI_LOGGING
+
+} SCI_BASE_CONTROLLER_T;
+
+// Forward declarations
+struct SCI_BASE_REMOTE_DEVICE;
+struct SCI_BASE_REQUEST;
+
+typedef SCI_STATUS (*SCI_BASE_CONTROLLER_HANDLER_T)(
+ SCI_BASE_CONTROLLER_T *
+);
+
+typedef SCI_STATUS (*SCI_BASE_CONTROLLER_TIMED_HANDLER_T)(
+ SCI_BASE_CONTROLLER_T *,
+ U32
+);
+
+typedef SCI_STATUS (*SCI_BASE_CONTROLLER_REQUEST_HANDLER_T)(
+ SCI_BASE_CONTROLLER_T *,
+ struct SCI_BASE_REMOTE_DEVICE *,
+ struct SCI_BASE_REQUEST *
+);
+
+typedef SCI_STATUS (*SCI_BASE_CONTROLLER_START_REQUEST_HANDLER_T)(
+ SCI_BASE_CONTROLLER_T *,
+ struct SCI_BASE_REMOTE_DEVICE *,
+ struct SCI_BASE_REQUEST *,
+ U16
+);
+
+
+/**
+ * @struct SCI_BASE_CONTROLLER_STATE_HANDLER
+ *
+ * @brief 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.
+ */
+typedef 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_handler;
+
+ /**
+ * The stop_handler specifies the method invoked when a user attempts to
+ * stop a controller.
+ */
+ SCI_BASE_CONTROLLER_TIMED_HANDLER_T stop_handler;
+
+ /**
+ * The reset_handler specifies the method invoked when a user attempts to
+ * reset a controller.
+ */
+ SCI_BASE_CONTROLLER_HANDLER_T reset_handler;
+
+ /**
+ * The initialize_handler specifies the method invoked when a user
+ * attempts to initialize a controller.
+ */
+ SCI_BASE_CONTROLLER_HANDLER_T initialize_handler;
+
+ /**
+ * 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_handler;
+
+ /**
+ * The start_internal_request_handler specifies the method invoked when a user
+ * attempts to start an internal request for a controller.
+ */
+ SCI_BASE_CONTROLLER_START_REQUEST_HANDLER_T start_high_priority_io_handler;
+
+ /**
+ * 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_handler;
+
+ /**
+ * The complete_high_priority_io_handler specifies the method invoked when a user
+ * attempts to complete a high priority IO request for a controller.
+ */
+ SCI_BASE_CONTROLLER_REQUEST_HANDLER_T complete_high_priority_io_handler;
+
+ /**
+ * 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_handler;
+
+ /**
+ * 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_handler;
+
+ /**
+ * 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_handler;
+
+} SCI_BASE_CONTROLLER_STATE_HANDLER_T;
+
+/**
+ * @brief Construct the base controller
+ *
+ * @param[in] this_controller This parameter specifies the base controller
+ * to be constructed.
+ * @param[in] logger This parameter specifies the logger associated with
+ * this base controller object.
+ * @param[in] state_table This parameter specifies the table of state
+ * definitions to be utilized for the controller state machine.
+ * @param[in] mde_array This parameter specifies the array of memory
+ * descriptor entries to be managed by this list.
+ * @param[in] mde_array_length This parameter specifies the size of the
+ * array of entries.
+ * @param[in] next_mdl This parameter specifies a subsequent MDL object
+ * to be managed by this MDL object.
+ * @param[in] oem_parameters This parameter specifies the original
+ * equipment manufacturer parameters to be utilized by this
+ * controller object.
+ *
+ * @return none
+ */
+void sci_base_controller_construct(
+ SCI_BASE_CONTROLLER_T * this_controller,
+ SCI_BASE_LOGGER_T * logger,
+ SCI_BASE_STATE_T * state_table,
+ SCI_PHYSICAL_MEMORY_DESCRIPTOR_T * mdes,
+ U32 mde_count,
+ SCI_MEMORY_DESCRIPTOR_LIST_HANDLE_T next_mdl
+);
+
+#ifdef __cplusplus
+}
+#endif // __cplusplus
+
+#endif // _SCI_BASE_CONTROLLER_H_
diff --git a/sys/dev/isci/scil/sci_base_domain.c b/sys/dev/isci/scil/sci_base_domain.c
new file mode 100644
index 0000000..87b112c
--- /dev/null
+++ b/sys/dev/isci/scil/sci_base_domain.c
@@ -0,0 +1,89 @@
+/*-
+ * 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.
+ *
+ * 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 <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/**
+ * @file
+ *
+ * @brief This file contains the base domain method implementations and
+ * any constants or structures private to the base domain object.
+ */
+
+#include <dev/isci/scil/sci_base_domain.h>
+#include <dev/isci/scil/sci_base_state_machine.h>
+
+//******************************************************************************
+//* P R O T E C T E D M E T H O D S
+//******************************************************************************
+
+void sci_base_domain_construct(
+ SCI_BASE_DOMAIN_T * this_domain,
+ SCI_BASE_LOGGER_T * logger,
+ SCI_BASE_STATE_T * state_table
+)
+{
+ sci_base_object_construct(&this_domain->parent, logger);
+
+ sci_base_state_machine_construct(
+ &this_domain->state_machine,
+ &this_domain->parent,
+ state_table,
+ SCI_BASE_DOMAIN_STATE_INITIAL
+ );
+
+ sci_base_state_machine_start(
+ &this_domain->state_machine
+ );
+}
+
diff --git a/sys/dev/isci/scil/sci_base_domain.h b/sys/dev/isci/scil/sci_base_domain.h
new file mode 100644
index 0000000..efe0f2b
--- /dev/null
+++ b/sys/dev/isci/scil/sci_base_domain.h
@@ -0,0 +1,309 @@
+/*-
+ * 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.
+ *
+ * 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.
+ *
+ * $FreeBSD$
+ */
+#ifndef _SCI_BASE_DOMAIN_H_
+#define _SCI_BASE_DOMAIN_H_
+
+/**
+ * @file
+ *
+ * @brief This file contains all of the structures, constants, and methods
+ * common to all domain object definitions.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif // __cplusplus
+
+#include <dev/isci/scil/sci_base_object.h>
+#include <dev/isci/scil/sci_base_logger.h>
+#include <dev/isci/scil/sci_base_state_machine.h>
+#include <dev/isci/scil/sci_base_state_machine_logger.h>
+
+/**
+ * @enum SCI_BASE_DOMAIN_STATES
+ *
+ * @brief This enumeration depicts the standard states common to all domain
+ * state machine implementations.
+ */
+typedef enum _SCI_BASE_DOMAIN_STATES
+{
+ /**
+ * Simply the initial state for the base domain state machine.
+ */
+ SCI_BASE_DOMAIN_STATE_INITIAL,
+
+ /**
+ * This state indicates that the domain 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 DISCOVERING state.
+ */
+ SCI_BASE_DOMAIN_STATE_STARTING,
+
+ /**
+ * This state indicates the the domain is now ready. Thus, the user
+ * is able to perform IO operations to remote devices in this domain.
+ * This state is entered from the STOPPED state.
+ * This state is entered from the STOPPING state.
+ * This state is entered from the DISCOVERING state.
+ */
+ SCI_BASE_DOMAIN_STATE_READY,
+
+ /**
+ * This state indicates that the domain is in the process of stopping.
+ * In this state no new IO operations are permitted, but existing IO
+ * operations in the domain are allowed to complete.
+ * This state is entered from the READY state.
+ * This state is entered from the DISCOVERING state.
+ */
+ SCI_BASE_DOMAIN_STATE_STOPPING,
+
+ /**
+ * This state indicates that the domain 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_DOMAIN_STATE_STOPPED,
+
+ /**
+ * This state indicates that the domain is actively attempting to
+ * discover what remote devices are contained in it. In this state no
+ * new user IO requests are permitted.
+ * This state is entered from the READY state.
+ */
+ SCI_BASE_DOMAIN_STATE_DISCOVERING,
+
+ SCI_BASE_DOMAIN_MAX_STATES
+
+} SCI_BASE_DOMAIN_STATES;
+
+/**
+ * @struct SCI_BASE_DOMAIN
+ *
+ * @brief This structure defines all of the fields common to DOMAIN objects.
+ */
+typedef struct SCI_BASE_DOMAIN
+{
+ /**
+ * This field depicts the parent object (SCI_BASE_OBJECT) for the domain.
+ */
+ SCI_BASE_OBJECT_T parent;
+
+ /**
+ * This field contains the information for the base domain state machine.
+ */
+ SCI_BASE_STATE_MACHINE_T state_machine;
+
+ #ifdef SCI_LOGGING
+ SCI_BASE_STATE_MACHINE_LOGGER_T state_machine_logger;
+ #endif // SCI_LOGGING
+
+} SCI_BASE_DOMAIN_T;
+
+struct SCI_BASE_CONTROLLER;
+struct SCI_BASE_REMOTE_DEVICE;
+struct SCI_BASE_REQUEST;
+struct SCI_BASE_REQUEST;
+
+typedef SCI_STATUS (*SCI_BASE_DOMAIN_TIMED_HANDLER_T)(
+ SCI_BASE_DOMAIN_T *,
+ U32,
+ U32
+);
+
+typedef SCI_STATUS (*SCI_BASE_DOMAIN_HANDLER_T)(
+ SCI_BASE_DOMAIN_T *
+);
+
+typedef SCI_STATUS (*SCI_BASE_DOMAIN_PORT_NOT_READY_HANDLER_T)(
+ SCI_BASE_DOMAIN_T *,
+ U32
+);
+
+typedef SCI_STATUS (*SCI_BASE_DOMAIN_DEVICE_HANDLER_T)(
+ SCI_BASE_DOMAIN_T *,
+ struct SCI_BASE_REMOTE_DEVICE *
+);
+
+typedef SCI_STATUS (*SCI_BASE_DOMAIN_REQUEST_HANDLER_T)(
+ SCI_BASE_DOMAIN_T *,
+ struct SCI_BASE_REMOTE_DEVICE *,
+ struct SCI_BASE_REQUEST *
+);
+
+typedef SCI_STATUS (*SCI_BASE_DOMAIN_HIGH_PRIORITY_REQUEST_COMPLETE_HANDLER_T)(
+ SCI_BASE_DOMAIN_T *,
+ struct SCI_BASE_REMOTE_DEVICE *,
+ struct SCI_BASE_REQUEST *,
+ void *,
+ SCI_IO_STATUS
+);
+
+
+/**
+ * @struct SCI_BASE_DOMAIN_STATE_HANDLER
+ *
+ * @brief This structure contains all of the state handler methods common to
+ * base domain state machines. Handler methods provide the ability
+ * to change the behavior for user requests or transitions depending
+ * on the state the machine is in.
+ */
+typedef struct SCI_BASE_DOMAIN_STATE_HANDLER
+{
+ /**
+ * The discover_handler specifies the method invoked when a user attempts
+ * to discover a domain.
+ */
+ SCI_BASE_DOMAIN_TIMED_HANDLER_T discover_handler;
+
+ /**
+ * The port_ready_handler specifies the method invoked an SCI Core
+ * informs the domain object that it's associated port is now ready
+ * for IO operation.
+ */
+ SCI_BASE_DOMAIN_HANDLER_T port_ready_handler;
+
+ /**
+ * The port_not_ready_handler specifies the method invoked an SCI Core
+ * informs the domain object that it's associated port is no longer ready
+ * for IO operation.
+ */
+ SCI_BASE_DOMAIN_PORT_NOT_READY_HANDLER_T port_not_ready_handler;
+
+ /**
+ * The device_start_complete_handler specifies the method invoked when a
+ * remote device start operation in the domain completes.
+ */
+ SCI_BASE_DOMAIN_DEVICE_HANDLER_T device_start_complete_handler;
+
+ /**
+ * The device_stop_complete_handler specifies the method invoked when a
+ * remote device stop operation in the domain completes.
+ */
+ SCI_BASE_DOMAIN_DEVICE_HANDLER_T device_stop_complete_handler;
+
+ /**
+ * The device_destruct_handler specifies the method invoked when sci user
+ * destruct a remote device of this domain.
+ */
+ SCI_BASE_DOMAIN_DEVICE_HANDLER_T device_destruct_handler;
+
+ /**
+ * The start_io_handler specifies the method invoked when a user
+ * attempts to start an IO request for a domain.
+ */
+ SCI_BASE_DOMAIN_REQUEST_HANDLER_T start_io_handler;
+
+ /**
+ * The start_high_priority_io_handler specifies the method invoked when a user
+ * attempts to start an high priority request for a domain.
+ */
+ SCI_BASE_DOMAIN_REQUEST_HANDLER_T start_high_priority_io_handler;
+
+ /**
+ * The complete_io_handler specifies the method invoked when a user
+ * attempts to complete an IO request for a domain.
+ */
+ SCI_BASE_DOMAIN_REQUEST_HANDLER_T complete_io_handler;
+
+ /**
+ * The complete_high_priority_io_handler specifies the method invoked when a
+ * user attempts to complete an high priority IO request for a domain.
+ */
+ SCI_BASE_DOMAIN_HIGH_PRIORITY_REQUEST_COMPLETE_HANDLER_T complete_high_priority_io_handler;
+
+ /**
+ * The continue_io_handler specifies the method invoked when a user
+ * attempts to continue an IO request for a domain.
+ */
+ SCI_BASE_DOMAIN_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 domain.
+ */
+ SCI_BASE_DOMAIN_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 domain.
+ */
+ SCI_BASE_DOMAIN_REQUEST_HANDLER_T complete_task_handler;
+
+} SCI_BASE_DOMAIN_STATE_HANDLER_T;
+
+/**
+ * @brief Construct the base domain
+ *
+ * @param[in] this_domain This parameter specifies the base domain to be
+ * constructed.
+ * @param[in] logger This parameter specifies the logger associated with
+ * this base domain object.
+ * @param[in] state_table This parameter specifies the table of state
+ * definitions to be utilized for the domain state machine.
+ *
+ * @return none
+ */
+void sci_base_domain_construct(
+ SCI_BASE_DOMAIN_T * this_domain,
+ SCI_BASE_LOGGER_T * logger,
+ SCI_BASE_STATE_T * state_table
+);
+
+#ifdef __cplusplus
+}
+#endif // __cplusplus
+
+#endif // _SCI_BASE_DOMAIN_H_
diff --git a/sys/dev/isci/scil/sci_base_iterator.c b/sys/dev/isci/scil/sci_base_iterator.c
new file mode 100644
index 0000000..6855f40
--- /dev/null
+++ b/sys/dev/isci/scil/sci_base_iterator.c
@@ -0,0 +1,182 @@
+/*-
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 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 <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/**
+ * @file
+ *
+ * @brief This file contains the implementation of an iterator class.
+ * This class will allow for iterating across the elements of a
+ * container.
+ */
+
+#if !defined(DISABLE_SCI_ITERATORS)
+
+//******************************************************************************
+//*
+//* I N C L U D E S
+//*
+//******************************************************************************
+
+#include <dev/isci/scil/sci_base_iterator.h>
+
+//******************************************************************************
+//*
+//* P R I V A T E M E M B E R S
+//*
+//******************************************************************************
+
+//******************************************************************************
+//*
+//* P R O T E C T E D M E T H O D S
+//*
+//******************************************************************************
+
+/**
+ * @brief Return the size of an iterator object.
+ *
+ * @return U32 : size of iterator object in bytes.
+ *
+ */
+U32 sci_iterator_get_object_size(
+ void
+)
+{
+ return sizeof(SCI_BASE_ITERATOR_T);
+}
+
+/**
+ * @brief Initialize the interator.
+ *
+ * @param[in] iterator This parameter specifies the iterator to be
+ * constructed.
+ * @param[in] list This parameter specifies the abstract list that will be
+ * iterated on by this iterator. The iterator will by initialized
+ * to point to the first element in this abstract list.
+ *
+ * @return none
+ */
+void sci_base_iterator_construct(
+ SCI_ITERATOR_HANDLE_T iterator_handle,
+ SCI_ABSTRACT_LIST_T * list
+)
+{
+ SCI_BASE_ITERATOR_T * iterator = (SCI_BASE_ITERATOR_T *) iterator_handle;
+
+ memset(iterator, 0, sizeof(SCI_BASE_ITERATOR_T));
+ iterator->list = list;
+ sci_iterator_first(iterator);
+}
+
+/**
+ * @brief Get the object currently pointed to by this iterator.
+ *
+ * @param[in] iterator_handle Handle to an iterator.
+ *
+ * @return void * : Object pointed to by this iterator.
+ * @retval NULL If iterator is not currently pointing to a valid element.
+ */
+void * sci_iterator_get_current(
+ SCI_ITERATOR_HANDLE_T iterator_handle
+)
+{
+ SCI_BASE_ITERATOR_T * iterator = (SCI_BASE_ITERATOR_T *)iterator_handle;
+
+ void *current_object = NULL;
+
+ if (iterator->current != NULL)
+ {
+ current_object = sci_abstract_list_get_object(iterator->current);
+ }
+
+ return current_object;
+}
+
+/**
+ * @brief Modify the iterator to point to the first element in the list.
+ *
+ * @param[in] iterator
+ *
+ * @return none
+ */
+void sci_iterator_first(
+ SCI_ITERATOR_HANDLE_T iterator_handle
+)
+{
+ SCI_BASE_ITERATOR_T * iterator = (SCI_BASE_ITERATOR_T *)iterator_handle;
+
+ iterator->current = sci_abstract_list_get_front(iterator->list);
+}
+
+/**
+ * @brief Modify the iterator to point to the next element in the list.
+ *
+ * @param[in] iterator
+ *
+ * @return none
+ */
+void sci_iterator_next(
+ SCI_ITERATOR_HANDLE_T iterator_handle
+)
+{
+ SCI_BASE_ITERATOR_T * iterator = (SCI_BASE_ITERATOR_T *)iterator_handle;
+
+ if (iterator->current != NULL)
+ {
+ iterator->current = sci_abstract_list_get_next(iterator->current);
+ }
+}
+
+#endif // !defined(DISABLE_SCI_ITERATORS)
+
diff --git a/sys/dev/isci/scil/sci_base_iterator.h b/sys/dev/isci/scil/sci_base_iterator.h
new file mode 100644
index 0000000..36a23f2
--- /dev/null
+++ b/sys/dev/isci/scil/sci_base_iterator.h
@@ -0,0 +1,134 @@
+/*-
+ * 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.
+ *
+ * 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.
+ *
+ * $FreeBSD$
+ */
+/**
+ * @file
+ *
+ * @brief This file contains the protected interface to the iterator class.
+ * Methods Provided:
+ * - sci_base_iterator_construct()
+ */
+
+#ifndef _SCI_BASE_ITERATOR_H_
+#define _SCI_BASE_ITERATOR_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif // __cplusplus
+
+//******************************************************************************
+//*
+//* I N C L U D E S
+//*
+//******************************************************************************
+
+#include <dev/isci/scil/sci_iterator.h>
+#include <dev/isci/scil/sci_abstract_list.h>
+
+//******************************************************************************
+//*
+//* C O N S T A N T S
+//*
+//******************************************************************************
+
+//******************************************************************************
+//*
+//* T Y P E S
+//*
+//******************************************************************************
+
+/**
+ * @struct SCI_BASE_ITERATOR
+ *
+ * @brief This object represents an iterator of an abstract list.
+ *
+ */
+typedef struct SCI_BASE_ITERATOR
+{
+ /**
+ * This field points to the list iterated by this iterator.
+ */
+ SCI_ABSTRACT_LIST_T * list;
+
+ /**
+ * This field points to the list element currently referenced by this
+ * iterator.
+ */
+ SCI_ABSTRACT_ELEMENT_T * current;
+
+} SCI_BASE_ITERATOR_T;
+
+//******************************************************************************
+//*
+//* P U B L I C M E T H O D S
+//*
+//******************************************************************************
+
+#if !defined(DISABLE_SCI_ITERATORS)
+
+void sci_base_iterator_construct(
+ SCI_ITERATOR_HANDLE_T iterator,
+ SCI_ABSTRACT_LIST_T * list
+);
+
+#else // !defined(DISABLE_SCI_ITERATORS)
+
+#define sci_base_iterator_construct(the_iterator, the_list)
+
+#endif // !defined(DISABLE_SCI_ITERATORS)
+
+#ifdef __cplusplus
+}
+#endif // __cplusplus
+
+#endif // _BASE_ITERATOR_H_
diff --git a/sys/dev/isci/scil/sci_base_library.c b/sys/dev/isci/scil/sci_base_library.c
new file mode 100644
index 0000000..a3b85e6
--- /dev/null
+++ b/sys/dev/isci/scil/sci_base_library.c
@@ -0,0 +1,103 @@
+/*-
+ * 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.
+ *
+ * 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 <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/**
+ * @file
+ *
+ * @brief This file contains all of the method imlementations for the
+ * SCI_BASE_LIBRARY object.
+ */
+
+#include <dev/isci/scil/sci_base_library.h>
+
+//******************************************************************************
+//* P U B L I C M E T H O D S
+//******************************************************************************
+
+U32 sci_library_get_major_version(
+ void
+)
+{
+ // Return the 32-bit value representing the major version for this SCI
+ // binary.
+ return __SCI_LIBRARY_MAJOR_VERSION__;
+}
+
+// ---------------------------------------------------------------------------
+
+U32 sci_library_get_minor_version(
+ void
+)
+{
+ // Return the 32-bit value representing the minor version for this SCI
+ // binary.
+ return __SCI_LIBRARY_MINOR_VERSION__;
+}
+
+// ---------------------------------------------------------------------------
+
+U32 sci_library_get_build_version(
+ void
+)
+{
+ // Return the 32-bit value representing the build version for this SCI
+ // binary.
+ return __SCI_LIBRARY_BUILD_VERSION__;
+}
+
+//******************************************************************************
+//* P R O T E C T E D M E T H O D S
+//******************************************************************************
+
diff --git a/sys/dev/isci/scil/sci_base_library.h b/sys/dev/isci/scil/sci_base_library.h
new file mode 100644
index 0000000..63d2cb4
--- /dev/null
+++ b/sys/dev/isci/scil/sci_base_library.h
@@ -0,0 +1,197 @@
+/*-
+ * 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.
+ *
+ * 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.
+ *
+ * $FreeBSD$
+ */
+#ifndef _SCI_BASE_LIBRARY_H_
+#define _SCI_BASE_LIBRARY_H_
+
+/**
+ * @file
+ *
+ * @brief This file contains the protected interface structures, constants
+ * and interface methods for the SCI_BASE_LIBRARY object.
+ *
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif // __cplusplus
+
+#include <dev/isci/scil/sci_library.h>
+#include <dev/isci/scil/sci_pool.h>
+#include <dev/isci/scil/sci_base_object.h>
+#include <dev/isci/scil/sci_base_logger.h>
+#include <dev/isci/scil/sci_controller_constants.h>
+
+/**
+ * @struct SCI_BASE_LIBRARY
+ *
+ * @brief This structure contains all of the objects common to all library
+ * sub-objects.
+ */
+typedef struct SCI_BASE_LIBRARY
+{
+ /**
+ * This class derives directly from the base object class. As a result,
+ * the field is named "parent" and is the first field contained in the
+ * structure.
+ */
+ SCI_BASE_OBJECT_T parent;
+
+ /**
+ * This field provides the logger object to be utilized by all objects
+ * contained inside of a library.
+ */
+ SCI_BASE_LOGGER_T logger;
+
+ // Create a pool structure to manage free controller indices.
+ SCI_POOL_CREATE(controller_id_pool, U16, SCI_MAX_CONTROLLERS);
+
+} SCI_BASE_LIBRARY_T;
+
+
+/**
+ * @brief This method will construct the base library object.
+ *
+ * @param[in] this_library This parameter specifies the library object
+ * to be constructed.
+ * @param[in] max_controllers This parameter specifies the maximum number
+ * of controllers to be supported by this library.
+ *
+ * @return none
+ */
+void sci_base_library_construct(
+ SCI_BASE_LIBRARY_T * this_library,
+ U32 max_controllers
+);
+
+/**
+ * This macro provides common code for allocating a controller from a library.
+ * It will ensure that we successfully allocate an available controller index
+ * and return SCI_FAILURE_INSUFFICIENT_RESOURCES if unsuccessful.
+ */
+#define SCI_BASE_LIBRARY_ALLOCATE_CONTROLLER( \
+ library, \
+ controller_ptr, \
+ rc \
+) \
+{ \
+ U16 index; \
+ *rc = SCI_SUCCESS; \
+ if (! sci_pool_empty((library)->parent.controller_id_pool)) \
+ { \
+ sci_pool_get((library)->parent.controller_id_pool, index); \
+ *controller_ptr = (SCI_CONTROLLER_HANDLE_T) \
+ & (library)->controllers[index]; \
+ } \
+ else \
+ *rc = SCI_FAILURE_INSUFFICIENT_RESOURCES; \
+}
+
+/**
+ * This macro provides common code for freeing a controller to a library.
+ * It calculates the index to the controller instance in the array by
+ * determining the offset.
+ */
+#define SCI_BASE_LIBRARY_FREE_CONTROLLER( \
+ library, \
+ controller, \
+ CONTROLLER_TYPE, \
+ rc \
+) \
+{ \
+ U16 index = (U16) \
+ ((((char *)(controller)) - ((char *)(library)->controllers))\
+ / sizeof(CONTROLLER_TYPE)); \
+ *rc = SCI_SUCCESS; \
+ if ( (index < SCI_MAX_CONTROLLERS) \
+ && (! sci_pool_full((library)->parent.controller_id_pool)) ) \
+ { \
+ sci_pool_put((library)->parent.controller_id_pool, index); \
+ } \
+ else \
+ *rc = SCI_FAILURE_CONTROLLER_NOT_FOUND; \
+}
+
+
+
+/**
+ * This macro provides common code for constructing library. It
+ * It initialize and fill the library's controller_id_pool.
+ */
+#define SCI_BASE_LIBRARY_CONSTRUCT( \
+ library, \
+ base_library, \
+ max_controllers, \
+ CONTROLLER_TYPE, \
+ status \
+) \
+{ \
+ U32 controller_index; \
+ sci_base_object_construct(&(base_library)->parent, &(base_library)->logger); \
+ sci_pool_initialize((base_library)->controller_id_pool); \
+ for (controller_index = 0; controller_index < max_controller_count; controller_index++) \
+ { \
+ SCI_BASE_LIBRARY_FREE_CONTROLLER( \
+ library, \
+ &library->controllers[controller_index], \
+ CONTROLLER_TYPE, \
+ &status \
+ ); \
+ } \
+}
+
+#ifdef __cplusplus
+}
+#endif // __cplusplus
+
+#endif // _SCI_BASE_LIBRARY_H_
diff --git a/sys/dev/isci/scil/sci_base_logger.c b/sys/dev/isci/scil/sci_base_logger.c
new file mode 100644
index 0000000..7f0e425
--- /dev/null
+++ b/sys/dev/isci/scil/sci_base_logger.c
@@ -0,0 +1,291 @@
+/*-
+ * 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.
+ *
+ * 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 <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/**
+ * @file
+ *
+ * @brief This file contains the implementation for the base logger object.
+ * It provides the functionality necessary to enabling, disabling,
+ * constructing, etc. logger objects.
+ */
+
+
+#include <dev/isci/scil/sci_base_logger.h>
+
+
+#ifdef SCI_LOGGING
+
+//******************************************************************************
+//* P R I V A T E M E T H O D S
+//******************************************************************************
+
+#define SCI_LOGGER_GET_OBJECT_MASK(logger, verbosity_level) \
+ (((SCI_BASE_LOGGER_T *)(logger))->object_mask[(verbosity_level)])
+
+/**
+ * @brief This method is private to this object. It attempts to enable the
+ * supplied log objects for the supplied verbosity levels.
+ *
+ * @param[in] logger This parameter specifies the logger object for which
+ * to attempt to enable log object and verbosity levels.
+ * @param[in] log_object_mask This parameter specifies the log objects to
+ * attempt to enable.
+ * @param[in] verbosity_mask This parameter specifies the verbosity levels
+ * that are allowed to be enabled.
+ * @param[in] verbosity This parameter specifies the specific verbosity level
+ * to attempt to enable.
+ *
+ * @return none
+ */
+static
+void sci_base_logger_enable_log_object(
+ SCI_LOGGER_HANDLE_T logger,
+ U32 log_object_mask,
+ U8 verbosity_mask,
+ U8 verbosity
+)
+{
+ // Enable the log objects for the error verbosity if errs are enabled.
+ if ( (1<<verbosity) & verbosity_mask)
+ {
+ SCI_LOGGER_GET_OBJECT_MASK(logger, verbosity) |= log_object_mask;
+ (((SCI_BASE_LOGGER_T *)(logger))->verbosity_mask |= (1<<verbosity) );
+ }
+}
+
+/**
+ * @brief This method is private to this object. It attempts to disable the
+ * supplied log objects for the supplied verbosity levels.
+ *
+ * @param[in] logger This parameter specifies the logger object for which
+ * to attempt to disable log object and verbosity levels.
+ * @param[in] log_object_mask This parameter specifies the log objects to
+ * attempt to disable.
+ * @param[in] verbosity_mask This parameter specifies the verbosity levels
+ * that are allowed to be disabled.
+ * @param[in] verbosity This parameter specifies the specific verbosity level
+ * to attempt to disable.
+ *
+ * @return none
+ */
+static
+void sci_base_logger_disable_log_object(
+ SCI_LOGGER_HANDLE_T logger,
+ U32 log_object_mask,
+ U8 verbosity_mask,
+ U8 verbosity
+)
+{
+ if ( (1<<verbosity) & verbosity_mask)
+ {
+ SCI_LOGGER_GET_OBJECT_MASK(logger, verbosity) &= ~log_object_mask;
+
+ // If all of the objects in the object mask are disabled for this
+ // verbosity, then disable the verbosity as well.
+ if (SCI_LOGGER_GET_OBJECT_MASK(logger, verbosity) == 0)
+ (((SCI_BASE_LOGGER_T *)(logger))->verbosity_mask &= ~(1<<verbosity) );
+ }
+}
+
+//******************************************************************************
+//* P U B L I C M E T H O D S
+//******************************************************************************
+
+U8 sci_logger_get_verbosity_mask(
+ SCI_LOGGER_HANDLE_T logger,
+ U32 log_object
+)
+{
+ U8 verbosity_mask = 0;
+ SCI_BASE_LOGGER_T * base_logger = (SCI_BASE_LOGGER_T *)logger;
+
+ if ( base_logger->object_mask[SCI_LOG_VERBOSITY_ERROR] & log_object )
+ verbosity_mask |= 1<<SCI_LOG_VERBOSITY_ERROR;
+
+ if ( base_logger->object_mask[SCI_LOG_VERBOSITY_WARNING] & log_object )
+ verbosity_mask |= 1<<SCI_LOG_VERBOSITY_WARNING;
+
+ if ( base_logger->object_mask[SCI_LOG_VERBOSITY_INFO] & log_object )
+ verbosity_mask |= 1<<SCI_LOG_VERBOSITY_INFO;
+
+ if ( base_logger->object_mask[SCI_LOG_VERBOSITY_TRACE] & log_object )
+ verbosity_mask |= 1<<SCI_LOG_VERBOSITY_TRACE;
+
+ if ( base_logger->object_mask[SCI_LOG_VERBOSITY_STATES] & log_object )
+ verbosity_mask |= 1<<SCI_LOG_VERBOSITY_TRACE;
+
+ return verbosity_mask;
+}
+
+// ---------------------------------------------------------------------------
+
+U32 sci_logger_get_object_mask(
+ SCI_LOGGER_HANDLE_T logger,
+ U8 verbosity
+)
+{
+ // Ensure that a supported verbosity level was supplied.
+ if ( (SCI_LOG_VERBOSITY_ERROR == verbosity)
+ || (SCI_LOG_VERBOSITY_WARNING == verbosity)
+ || (SCI_LOG_VERBOSITY_INFO == verbosity)
+ || (SCI_LOG_VERBOSITY_TRACE == verbosity)
+ || (SCI_LOG_VERBOSITY_STATES == verbosity) )
+ {
+ return SCI_LOGGER_GET_OBJECT_MASK(logger, verbosity);
+ }
+
+ // An unsupported verbosity level was supplied. Simply return an empty
+ // log object mask.
+ return 0;
+}
+
+// ---------------------------------------------------------------------------
+
+void sci_logger_enable(
+ SCI_LOGGER_HANDLE_T logger,
+ U32 log_object_mask,
+ U8 verbosity_mask
+)
+{
+ sci_base_logger_enable_log_object(
+ logger, log_object_mask, verbosity_mask, SCI_LOG_VERBOSITY_ERROR
+ );
+
+ sci_base_logger_enable_log_object(
+ logger, log_object_mask, verbosity_mask, SCI_LOG_VERBOSITY_WARNING
+ );
+
+ sci_base_logger_enable_log_object(
+ logger, log_object_mask, verbosity_mask, SCI_LOG_VERBOSITY_INFO
+ );
+
+ sci_base_logger_enable_log_object(
+ logger, log_object_mask, verbosity_mask, SCI_LOG_VERBOSITY_TRACE
+ );
+
+ sci_base_logger_enable_log_object(
+ logger, log_object_mask, verbosity_mask, SCI_LOG_VERBOSITY_STATES
+ );
+}
+
+// ---------------------------------------------------------------------------
+
+void sci_logger_disable(
+ SCI_LOGGER_HANDLE_T logger,
+ U32 log_object_mask,
+ U8 verbosity_mask
+)
+{
+ sci_base_logger_disable_log_object(
+ logger, log_object_mask, verbosity_mask, SCI_LOG_VERBOSITY_ERROR
+ );
+
+ sci_base_logger_disable_log_object(
+ logger, log_object_mask, verbosity_mask, SCI_LOG_VERBOSITY_WARNING
+ );
+
+ sci_base_logger_disable_log_object(
+ logger, log_object_mask, verbosity_mask, SCI_LOG_VERBOSITY_INFO
+ );
+
+ sci_base_logger_disable_log_object(
+ logger, log_object_mask, verbosity_mask, SCI_LOG_VERBOSITY_TRACE
+ );
+
+ sci_base_logger_disable_log_object(
+ logger, log_object_mask, verbosity_mask, SCI_LOG_VERBOSITY_STATES
+ );
+}
+
+// ---------------------------------------------------------------------------
+
+BOOL sci_logger_is_enabled(
+ SCI_LOGGER_HANDLE_T logger,
+ U32 log_object_mask,
+ U8 verbosity_level
+)
+{
+ SCI_BASE_LOGGER_T * base_logger = (SCI_BASE_LOGGER_T*) logger;
+
+ if ( (base_logger->verbosity_mask & (1<<verbosity_level))
+ && (base_logger->object_mask[verbosity_level] & log_object_mask) )
+ return TRUE;
+
+ return FALSE;
+}
+
+//******************************************************************************
+//* P R O T E C T E D M E T H O D S
+//******************************************************************************
+
+void sci_base_logger_construct(
+ SCI_BASE_LOGGER_T *this_logger
+)
+{
+ int index;
+
+ sci_base_object_construct(
+ &this_logger->parent, this_logger
+ );
+
+ this_logger->verbosity_mask = 0;
+
+ for (index = 0; index < SCI_BASE_LOGGER_MAX_VERBOSITY_LEVELS; index++)
+ {
+ this_logger->object_mask[index] = 0;
+ }
+}
+
+#endif // SCI_LOGGING
diff --git a/sys/dev/isci/scil/sci_base_logger.h b/sys/dev/isci/scil/sci_base_logger.h
new file mode 100644
index 0000000..e3c5a40
--- /dev/null
+++ b/sys/dev/isci/scil/sci_base_logger.h
@@ -0,0 +1,131 @@
+/*-
+ * 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.
+ *
+ * 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.
+ *
+ * $FreeBSD$
+ */
+#ifndef _SCI_BASE_LOGGER_H_
+#define _SCI_BASE_LOGGER_H_
+
+/**
+ * @file
+ *
+ * @brief This file contains all of the constants, structures, and methods
+ * common to all base logger objects.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif // __cplusplus
+
+#include <dev/isci/scil/sci_logger.h>
+#include <dev/isci/scil/sci_base_object.h>
+
+
+#define SCI_BASE_LOGGER_MAX_VERBOSITY_LEVELS 5
+
+/**
+ * @struct SCI_BASE_LOGGER
+ *
+ * @brief This structure contains the set of log objects and verbosities that
+ * are enabled for logging. It's parent is the SCI_BASE_OBJECT_T.
+ */
+typedef struct SCI_BASE_LOGGER
+{
+#if defined(SCI_LOGGING)
+ /**
+ * The field specifies that the parent object for the base logger
+ * is the base object itself.
+ */
+ SCI_BASE_OBJECT_T parent;
+
+ /**
+ * This filed specifies an array of objects mask. There is one object
+ * mask for each verbosity level (e.g. ERROR, WARNING, etc.). This
+ * allows for more flexible logging.
+ */
+ U32 object_mask[SCI_BASE_LOGGER_MAX_VERBOSITY_LEVELS];
+
+ /**
+ * This filed specifies which verbosity levels are currently enabled
+ * for logging
+ */
+ U32 verbosity_mask;
+#else // defined(SCI_LOGGING)
+ U8 dummy;
+#endif // defined(SCI_LOGGING)
+
+} SCI_BASE_LOGGER_T;
+
+#if defined(SCI_LOGGING)
+
+/**
+ * @brief This method simply performs initialization of the base logger object.
+ *
+ * @param[in] this_logger This parameter specifies the logger that we are
+ * going to construct
+ *
+ * @return none
+ */
+void sci_base_logger_construct(
+ SCI_BASE_LOGGER_T *this_logger
+);
+
+#else // SCI_LOGGING
+
+#define sci_base_logger_construct
+
+#endif
+
+#ifdef __cplusplus
+}
+#endif // __cplusplus
+
+#endif // _SCI_BASE_LOGGER_H_
diff --git a/sys/dev/isci/scil/sci_base_memory_descriptor_list.c b/sys/dev/isci/scil/sci_base_memory_descriptor_list.c
new file mode 100644
index 0000000..d470b8f
--- /dev/null
+++ b/sys/dev/isci/scil/sci_base_memory_descriptor_list.c
@@ -0,0 +1,168 @@
+/*-
+ * 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.
+ *
+ * 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 <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/**
+ * @file
+ *
+ * @brief This file contains the base implementation for the memory
+ * descriptor list. This is currently comprised of MDL iterator
+ * methods.
+ */
+
+#include <dev/isci/scil/sci_base_memory_descriptor_list.h>
+
+//******************************************************************************
+//* P U B L I C M E T H O D S
+//******************************************************************************
+
+void sci_mdl_first_entry(
+ SCI_MEMORY_DESCRIPTOR_LIST_HANDLE_T mdl
+)
+{
+ SCI_BASE_MEMORY_DESCRIPTOR_LIST_T * base_mdl = (SCI_BASE_MEMORY_DESCRIPTOR_LIST_T*) 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(
+ SCI_MEMORY_DESCRIPTOR_LIST_HANDLE_T mdl
+)
+{
+ SCI_BASE_MEMORY_DESCRIPTOR_LIST_T * base_mdl = (SCI_BASE_MEMORY_DESCRIPTOR_LIST_T*) 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);
+ }
+}
+
+// ---------------------------------------------------------------------------
+
+SCI_PHYSICAL_MEMORY_DESCRIPTOR_T * sci_mdl_get_current_entry(
+ SCI_MEMORY_DESCRIPTOR_LIST_HANDLE_T mdl
+)
+{
+ SCI_BASE_MEMORY_DESCRIPTOR_LIST_T * base_mdl = (SCI_BASE_MEMORY_DESCRIPTOR_LIST_T*) 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(
+ SCI_BASE_MEMORY_DESCRIPTOR_LIST_T * mdl,
+ SCI_PHYSICAL_MEMORY_DESCRIPTOR_T * mde_array,
+ U32 mde_array_length,
+ SCI_MEMORY_DESCRIPTOR_LIST_HANDLE_T 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(
+ SCI_PHYSICAL_MEMORY_DESCRIPTOR_T * mde,
+ U32 alignment,
+ U32 size,
+ U16 attributes
+)
+{
+ // Only need the lower 32 bits to ensure alignment is met.
+ U32 physical_address = sci_cb_physical_address_lower(mde->physical_address);
+
+ if (
+ ((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/sys/dev/isci/scil/sci_base_memory_descriptor_list.h b/sys/dev/isci/scil/sci_base_memory_descriptor_list.h
new file mode 100644
index 0000000..b4bb43a
--- /dev/null
+++ b/sys/dev/isci/scil/sci_base_memory_descriptor_list.h
@@ -0,0 +1,168 @@
+/*-
+ * 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.
+ *
+ * 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.
+ *
+ * $FreeBSD$
+ */
+#ifndef _SCI_BASE_MEMORY_DESCRIPTOR_LIST_H_
+#define _SCI_BASE_MEMORY_DESCRIPTOR_LIST_H_
+
+/**
+ * @file
+ *
+ * @brief This file contains the protected interface structures, constants
+ * and interface methods for the SCI_BASE_MEMORY_DESCRIPTOR_LIST
+ * object.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif // __cplusplus
+
+#include <dev/isci/scil/sci_types.h>
+#include <dev/isci/scil/sci_memory_descriptor_list.h>
+
+
+/**
+ * @struct SCI_BASE_MEMORY_DESCRIPTOR_LIST
+ *
+ * @brief This structure contains all of the fields necessary to implement
+ * a simple stack for managing the list of available controller indices.
+ */
+typedef 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.
+ */
+ SCI_PHYSICAL_MEMORY_DESCRIPTOR_T * 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.
+ */
+ SCI_MEMORY_DESCRIPTOR_LIST_HANDLE_T next_mdl;
+
+} SCI_BASE_MEMORY_DESCRIPTOR_LIST_T;
+
+/**
+ * @brief This method is invoked to construct an memory descriptor list.
+ * It initializes the fields of the MDL.
+ *
+ * @param[in] mdl This parameter specifies the memory descriptor list
+ * to be constructed.
+ * @param[in] mde_array This parameter specifies the array of memory
+ * descriptor entries to be managed by this list.
+ * @param[in] mde_array_length This parameter specifies the size of the
+ * array of entries.
+ * @param[in] next_mdl This parameter specifies a subsequent MDL object
+ * to be managed by this MDL object.
+ *
+ * @return none.
+ */
+void sci_base_mdl_construct(
+ SCI_BASE_MEMORY_DESCRIPTOR_LIST_T * mdl,
+ SCI_PHYSICAL_MEMORY_DESCRIPTOR_T * mde_array,
+ U32 mde_array_length,
+ SCI_MEMORY_DESCRIPTOR_LIST_HANDLE_T next_mdl
+);
+
+/**
+ * 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); \
+}
+
+/**
+ * @brief This method validates that the memory descriptor is correctly
+ * filled out by the SCI User
+ *
+ * @param[in] mde This parameter is the mde entry to validate
+ * @param[in] alignment This parameter specifies the expected alignment of
+ * the memory for the mde.
+ * @param[in] size This parameter specifies the memory size expected for
+ * the mde its value should not have been changed by the SCI
+ * User.
+ * @param[in] attributes This parameter specifies the attributes for the
+ * memory descriptor provided.
+ *
+ * @return BOOL This method returns an indication as to whether the
+ * supplied MDE is valid or not.
+ * @retval TRUE The MDE is valid.
+ * @retval FALSE The MDE is not valid.
+ */
+BOOL sci_base_mde_is_valid(
+ SCI_PHYSICAL_MEMORY_DESCRIPTOR_T *mde,
+ U32 alignment,
+ U32 size,
+ U16 attributes
+);
+
+#ifdef __cplusplus
+}
+#endif // __cplusplus
+
+#endif // _SCI_BASE_MEMORY_DESCRIPTOR_LIST_H_
diff --git a/sys/dev/isci/scil/sci_base_memory_descriptor_list_decorator.c b/sys/dev/isci/scil/sci_base_memory_descriptor_list_decorator.c
new file mode 100644
index 0000000..0c691f0
--- /dev/null
+++ b/sys/dev/isci/scil/sci_base_memory_descriptor_list_decorator.c
@@ -0,0 +1,149 @@
+/*-
+ * 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.
+ *
+ * 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 <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/**
+ * @file
+ *
+ * @brief This file contains the base implementation for the memory
+ * descriptor list decorator. The decorator adds additional
+ * functionality that may be used by SCI users to help
+ * offload MDE processing.
+ */
+
+#include <dev/isci/scil/sci_memory_descriptor_list_decorator.h>
+
+U32 sci_mdl_decorator_get_memory_size(
+ SCI_MEMORY_DESCRIPTOR_LIST_HANDLE_T mdl,
+ U32 attributes
+)
+{
+ U32 size = 0;
+ SCI_PHYSICAL_MEMORY_DESCRIPTOR_T * mde;
+
+ sci_mdl_first_entry(mdl);
+ mde = sci_mdl_get_current_entry(mdl);
+ while (mde != NULL)
+ {
+ if ( (mde->constant_memory_attributes == attributes)
+ || (attributes == 0) )
+ size += (mde->constant_memory_size + mde->constant_memory_alignment);
+
+ sci_mdl_next_entry(mdl);
+ mde = sci_mdl_get_current_entry(mdl);
+ }
+
+ return size;
+}
+
+// ---------------------------------------------------------------------------
+
+void sci_mdl_decorator_assign_memory(
+ SCI_MEMORY_DESCRIPTOR_LIST_HANDLE_T mdl,
+ U32 attributes,
+ POINTER_UINT virtual_address,
+ SCI_PHYSICAL_ADDRESS sci_physical_address
+)
+{
+ SCI_PHYSICAL_MEMORY_DESCRIPTOR_T * mde;
+ U64 physical_address;
+
+ physical_address
+ = ((U64) sci_cb_physical_address_lower(sci_physical_address))
+ | (((U64) sci_cb_physical_address_upper(sci_physical_address)) << 32);
+
+ sci_mdl_first_entry(mdl);
+ mde = sci_mdl_get_current_entry(mdl);
+ while (mde != NULL)
+ {
+ // As long as the memory attribute for this MDE is equivalent to
+ // those supplied by the caller, then fill out the appropriate
+ // MDE fields.
+ if ( (mde->constant_memory_attributes == attributes)
+ || (attributes == 0) )
+ {
+ // Ensure the virtual address alignment rules are met.
+ if ((virtual_address % mde->constant_memory_alignment) != 0)
+ {
+ virtual_address
+ += (mde->constant_memory_alignment -
+ (virtual_address % mde->constant_memory_alignment));
+ }
+
+ // Ensure the physical address alignment rules are met.
+ if ((physical_address % mde->constant_memory_alignment) != 0)
+ {
+ physical_address
+ += (mde->constant_memory_alignment -
+ (physical_address % mde->constant_memory_alignment));
+ }
+
+ // Update the MDE with properly aligned address values.
+ mde->virtual_address = (void *)virtual_address;
+ sci_cb_make_physical_address(
+ mde->physical_address,
+ (U32) (physical_address >> 32),
+ (U32) (physical_address & 0xFFFFFFFF)
+ );
+
+ virtual_address += mde->constant_memory_size;
+ physical_address += mde->constant_memory_size;
+ }
+
+ // Move on to the next MDE
+ sci_mdl_next_entry(mdl);
+ mde = sci_mdl_get_current_entry (mdl);
+ }
+}
+
diff --git a/sys/dev/isci/scil/sci_base_object.c b/sys/dev/isci/scil/sci_base_object.c
new file mode 100644
index 0000000..94af19f
--- /dev/null
+++ b/sys/dev/isci/scil/sci_base_object.c
@@ -0,0 +1,118 @@
+/*-
+ * 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.
+ *
+ * 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 <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/**
+ * @file
+ *
+ * @brief This file contains all of the method implementations for the
+ * SCI_BASE_OBJECT object.
+ */
+
+#include <dev/isci/scil/sci_status.h>
+#include <dev/isci/scil/sci_types.h>
+#include <dev/isci/scil/sci_base_object.h>
+
+//******************************************************************************
+//* P U B L I C M E T H O D S
+//******************************************************************************
+
+#if defined(SCI_OBJECT_USE_ASSOCIATION_FUNCTIONS)
+void * sci_object_get_association(
+ SCI_OBJECT_HANDLE_T object
+)
+{
+ return ((SCI_BASE_OBJECT_T *) object)->associated_object;
+}
+#endif
+
+// ---------------------------------------------------------------------------
+
+#if defined(SCI_OBJECT_USE_ASSOCIATION_FUNCTIONS)
+SCI_STATUS sci_object_set_association(
+ SCI_OBJECT_HANDLE_T object,
+ void * associated_object
+)
+{
+ ((SCI_BASE_OBJECT_T *)object)->associated_object = associated_object;
+ return SCI_SUCCESS;
+}
+#endif
+
+// ---------------------------------------------------------------------------
+
+void sci_base_object_construct(
+ SCI_BASE_OBJECT_T * base_object,
+ struct SCI_BASE_LOGGER * logger
+)
+{
+#if defined(SCI_LOGGING)
+ base_object->logger = logger;
+#endif // defined(SCI_LOGGING)
+ base_object->associated_object = NULL;
+}
+
+// ---------------------------------------------------------------------------
+
+SCI_LOGGER_HANDLE_T sci_object_get_logger(
+ SCI_OBJECT_HANDLE_T object
+)
+{
+#if defined(SCI_LOGGING)
+ return sci_base_object_get_logger(object);
+#else // defined(SCI_LOGGING)
+ return NULL;
+#endif // defined(SCI_LOGGING)
+}
+
diff --git a/sys/dev/isci/scil/sci_base_object.h b/sys/dev/isci/scil/sci_base_object.h
new file mode 100644
index 0000000..58f0430
--- /dev/null
+++ b/sys/dev/isci/scil/sci_base_object.h
@@ -0,0 +1,142 @@
+/*-
+ * 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.
+ *
+ * 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.
+ *
+ * $FreeBSD$
+ */
+#ifndef _SCI_BASE_OBJECT_H_
+#define _SCI_BASE_OBJECT_H_
+
+/**
+ * @file
+ *
+ * @brief 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.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif // __cplusplus
+
+#include <dev/isci/scil/sci_object.h>
+
+// Forward declare the logger object
+struct SCI_BASE_LOGGER;
+
+/**
+ * @struct SCI_BASE_OBJECT
+ *
+ * @brief The SCI_BASE_OBJECT object represents the data and functionality
+ * that is common to all SCI objects. It is the base class.
+ */
+typedef struct SCI_BASE_OBJECT
+{
+ /**
+ * This field represents an association created by the user for this
+ * object. The association can be whatever the user wishes. Think of
+ * it as a cookie.
+ */
+ void * associated_object;
+
+ /**
+ * This field simply contains a handle to the logger object to be
+ * utilized when utilizing the logger interface.
+ */
+ struct SCI_BASE_LOGGER * logger;
+
+} SCI_BASE_OBJECT_T;
+
+
+/**
+ * @brief This method constructs the sci base object.
+ *
+ * @param[in] base_object This parameter specifies the SCI base
+ * object which we whish to construct.
+ * @param[in] logger This parameter specifies the logger object to be
+ * saved and utilized for this base object.
+ *
+ * @return none
+ */
+void sci_base_object_construct(
+ SCI_BASE_OBJECT_T * base_object,
+ struct SCI_BASE_LOGGER * logger
+);
+
+#if defined(SCI_LOGGING)
+/**
+ * @brief This method returns the logger to which a previous
+ * association was created.
+ *
+ * @param[in] base_object This parameter specifies the SCI base object for
+ * which to retrieve the logger.
+ *
+ * @return This method returns a pointer to the logger that was
+ * previously associated to the supplied base_object
+ * parameter.
+ * @retval NULL This value is returned when there is no logger
+ * association for the supplied base_object instance.
+ */
+#define sci_base_object_get_logger(this_object) \
+ (((SCI_BASE_OBJECT_T *)(this_object))->logger)
+
+#else // defined(SCI_LOGGING)
+
+#define sci_base_object_get_logger(this_object) NULL
+
+#endif // defined(SCI_LOGGING)
+
+#ifdef __cplusplus
+}
+#endif // __cplusplus
+
+
+#endif // _SCI_BASE_OBJECT_H_
+
diff --git a/sys/dev/isci/scil/sci_base_observer.c b/sys/dev/isci/scil/sci_base_observer.c
new file mode 100644
index 0000000..60403a5
--- /dev/null
+++ b/sys/dev/isci/scil/sci_base_observer.c
@@ -0,0 +1,107 @@
+/*-
+ * 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.
+ *
+ * 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 <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/**
+ * @file
+ *
+ * @brief This file implements the functionality common to all observer
+ * objects.
+ */
+
+#include <dev/isci/scil/sci_types.h>
+#include <dev/isci/scil/sci_base_subject.h>
+#include <dev/isci/scil/sci_base_observer.h>
+
+#if defined(SCI_LOGGING)
+
+//******************************************************************************
+//* P U B L I C M E T H O D S
+//******************************************************************************
+
+void sci_base_observer_construct(
+ struct SCI_BASE_OBSERVER *this_observer,
+ SCI_BASE_OBSERVER_UPDATE_T update
+)
+{
+ this_observer->next = NULL;
+ this_observer->update = update;
+}
+
+// ---------------------------------------------------------------------------
+
+void sci_base_observer_initialize(
+ SCI_BASE_OBSERVER_T * the_observer,
+ SCI_BASE_OBSERVER_UPDATE_T update,
+ SCI_BASE_SUBJECT_T * the_subject
+)
+{
+ sci_base_observer_construct(the_observer, update);
+ sci_base_subject_attach_observer(the_subject, the_observer);
+}
+
+// ---------------------------------------------------------------------------
+
+void sci_base_observer_update(
+ SCI_BASE_OBSERVER_T *this_observer,
+ SCI_BASE_SUBJECT_T *the_subject
+)
+{
+ if (this_observer->update != NULL)
+ {
+ this_observer->update(this_observer, the_subject);
+ }
+}
+
+#endif // defined(SCI_LOGGING)
diff --git a/sys/dev/isci/scil/sci_base_observer.h b/sys/dev/isci/scil/sci_base_observer.h
new file mode 100644
index 0000000..991d66a
--- /dev/null
+++ b/sys/dev/isci/scil/sci_base_observer.h
@@ -0,0 +1,167 @@
+/*-
+ * 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.
+ *
+ * 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.
+ *
+ * $FreeBSD$
+ */
+#ifndef _SCI_BASE_OBSERVER_H_
+#define _SCI_BASE_OBSERVER_H_
+
+/**
+ * @file
+ *
+ * @brief This file contains all of the structures, constants, and methods
+ * common to all base observer object definitions.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif // __cplusplus
+
+#if defined(SCI_LOGGING)
+
+struct SCI_BASE_OBSERVER;
+struct SCI_BASE_SUBJECT;
+
+/**
+ * @typedef SCI_BASE_OBSERVER_UPDATE_T
+ *
+ * @brief This type definition defines the format for the update method
+ * that is invoked for all observers participating in the observer
+ * design pattern.
+ */
+typedef void (*SCI_BASE_OBSERVER_UPDATE_T)(
+ struct SCI_BASE_OBSERVER *this_observer,
+ struct SCI_BASE_SUBJECT *the_subject
+);
+
+/**
+ * @struct SCI_BASE_OBSERVER
+ *
+ * @brief This structure defines the fields necessary for an object that
+ * intends to participate as an observer.
+ */
+typedef struct SCI_BASE_OBSERVER
+{
+ /**
+ * This filed points to the next observer if there is one
+ */
+ struct SCI_BASE_OBSERVER *next;
+
+ /**
+ * This field defines the function pointer that is invoked in order to
+ * notify the observer of a change in the subject (i.e. observed object).
+ */
+ SCI_BASE_OBSERVER_UPDATE_T update;
+
+} SCI_BASE_OBSERVER_T;
+
+/**
+ * @brief This method is the basic constructor for the observer
+ *
+ * @param[in] this_observer This parameter specifies the observer to
+ * be constructed.
+ * @param[in] update This parameter specifies the update method to be
+ * invoked for this observer.
+ *
+ * @return none
+ */
+void sci_base_observer_construct(
+ struct SCI_BASE_OBSERVER *this_observer,
+ SCI_BASE_OBSERVER_UPDATE_T update
+);
+
+/**
+ * @brief This method performs the actions of construction and attaches to the
+ * subject.
+ *
+ * @pre The the_subject to be observed must be constructed before this call.
+ *
+ * @param[in] this_observer This parameter specifies the observer to construct
+ * an attach to the subject.
+ * @param[in] update This parameter is the update function that is passed to
+ * the constructor.
+ * @param[in] the_subject This parameter specifies the subject to observe.
+ */
+void sci_base_observer_initialize(
+ struct SCI_BASE_OBSERVER *this_observer,
+ SCI_BASE_OBSERVER_UPDATE_T update,
+ struct SCI_BASE_SUBJECT *the_subject
+);
+
+/**
+ * @brief This method will call the observers update function
+ *
+ * @param[in] this_observer This parameter specifies the observer to be
+ * notified.
+ * @param[in] the_subject This parameter indicates the subject for which
+ * the update call is occurring.
+ *
+ * @return none
+ */
+void sci_base_observer_update(
+ struct SCI_BASE_OBSERVER *this_observer,
+ struct SCI_BASE_SUBJECT *the_subject
+);
+
+#else // defined(SCI_LOGGING)
+
+typedef U8 SCI_BASE_OBSERVER_T;
+#define sci_base_observer_construct
+#define sci_base_observer_initialize
+#define sci_base_observer_update
+
+#endif // defined(SCI_LOGGING)
+
+#ifdef __cplusplus
+}
+#endif // __cplusplus
+
+#endif // _SCI_BASE_OBSERVER_H_
diff --git a/sys/dev/isci/scil/sci_base_phy.c b/sys/dev/isci/scil/sci_base_phy.c
new file mode 100644
index 0000000..8cffc13
--- /dev/null
+++ b/sys/dev/isci/scil/sci_base_phy.c
@@ -0,0 +1,89 @@
+/*-
+ * 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.
+ *
+ * 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 <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/**
+ * @file
+ *
+ * @brief This file contains the base phy method implementations and
+ * any constants or structures private to the base phy object.
+ */
+
+#include <dev/isci/scil/sci_base_phy.h>
+#include <dev/isci/scil/sci_base_state_machine.h>
+
+//******************************************************************************
+//* P R O T E C T E D M E T H O D S
+//******************************************************************************
+
+void sci_base_phy_construct(
+ SCI_BASE_PHY_T *this_phy,
+ SCI_BASE_LOGGER_T *logger,
+ SCI_BASE_STATE_T *state_table
+)
+{
+ sci_base_object_construct(&this_phy->parent, logger);
+
+ sci_base_state_machine_construct(
+ &this_phy->state_machine,
+ &this_phy->parent,
+ state_table,
+ SCI_BASE_PHY_STATE_INITIAL
+ );
+
+ sci_base_state_machine_start(
+ &this_phy->state_machine
+ );
+}
+
diff --git a/sys/dev/isci/scil/sci_base_phy.h b/sys/dev/isci/scil/sci_base_phy.h
new file mode 100644
index 0000000..09e5786
--- /dev/null
+++ b/sys/dev/isci/scil/sci_base_phy.h
@@ -0,0 +1,213 @@
+/*-
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 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.
+ *
+ * $FreeBSD$
+ */
+#ifndef _SCI_BASE_PHY_H_
+#define _SCI_BASE_PHY_H_
+
+/**
+ * @file
+ *
+ * @brief This file contains all of the structures, constants, and methods
+ * common to all phy object definitions.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif // __cplusplus
+
+#include <dev/isci/scil/sci_base_logger.h>
+#include <dev/isci/scil/sci_base_state_machine.h>
+#include <dev/isci/scil/sci_base_state_machine_logger.h>
+
+/**
+ * @enum SCI_BASE_PHY_STATES
+ *
+ * @brief This enumeration depicts the standard states common to all phy
+ * state machine implementations.
+ */
+typedef 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
+
+} SCI_BASE_PHY_STATES;
+
+/**
+ * @struct SCI_BASE_PHY
+ *
+ * @brief This structure defines all of the fields common to PHY objects.
+ */
+typedef struct SCI_BASE_PHY
+{
+ /**
+ * This field depicts the parent object (SCI_BASE_OBJECT) for the phy.
+ */
+ SCI_BASE_OBJECT_T parent;
+
+ /**
+ * This field contains the information for the base phy state machine.
+ */
+ SCI_BASE_STATE_MACHINE_T state_machine;
+
+ #ifdef SCI_LOGGING
+ SCI_BASE_STATE_MACHINE_LOGGER_T state_machine_logger;
+ #endif // SCI_LOGGING
+
+} SCI_BASE_PHY_T;
+
+typedef SCI_STATUS (*SCI_BASE_PHY_HANDLER_T)(
+ SCI_BASE_PHY_T *
+);
+
+/**
+ * @struct SCI_BASE_PHY_STATE_HANDLER
+ *
+ * @brief 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.
+ */
+typedef 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_STATE_HANDLER_T;
+
+/**
+ * @brief Construct the base phy
+ *
+ * @param[in] this_phy This parameter specifies the base phy to be
+ * constructed.
+ * @param[in] logger This parameter specifies the logger associated with
+ * this base phy object.
+ * @param[in] state_table This parameter specifies the table of state
+ * definitions to be utilized for the phy state machine.
+ *
+ * @return none
+ */
+void sci_base_phy_construct(
+ SCI_BASE_PHY_T * this_phy,
+ SCI_BASE_LOGGER_T * logger,
+ SCI_BASE_STATE_T * state_table
+);
+
+#ifdef __cplusplus
+}
+#endif // __cplusplus
+
+#endif // _SCI_BASE_PHY_H_
diff --git a/sys/dev/isci/scil/sci_base_port.c b/sys/dev/isci/scil/sci_base_port.c
new file mode 100644
index 0000000..d482aa9
--- /dev/null
+++ b/sys/dev/isci/scil/sci_base_port.c
@@ -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.
+ *
+ * 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 <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/**
+ * @file
+ *
+ * @brief This file contains the base port method implementations and
+ * any constants or structures private to the base port object.
+ */
+
+#include <dev/isci/scil/sci_base_port.h>
+
+//******************************************************************************
+//* P R O T E C T E D M E T H O D S
+//******************************************************************************
+
+void sci_base_port_construct(
+ SCI_BASE_PORT_T *this_port,
+ SCI_BASE_LOGGER_T *logger,
+ SCI_BASE_STATE_T *state_table
+)
+{
+ sci_base_object_construct(&this_port->parent, logger);
+
+ sci_base_state_machine_construct(
+ &this_port->state_machine,
+ &this_port->parent,
+ state_table,
+ SCI_BASE_PORT_STATE_STOPPED
+ );
+
+ sci_base_state_machine_start(
+ &this_port->state_machine
+ );
+}
+
diff --git a/sys/dev/isci/scil/sci_base_port.h b/sys/dev/isci/scil/sci_base_port.h
new file mode 100644
index 0000000..733677d
--- /dev/null
+++ b/sys/dev/isci/scil/sci_base_port.h
@@ -0,0 +1,233 @@
+/*-
+ * 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.
+ *
+ * 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.
+ *
+ * $FreeBSD$
+ */
+#ifndef _SCI_BASE_PORT_H_
+#define _SCI_BASE_PORT_H_
+
+/**
+ * @file
+ *
+ * @brief This file contains all of the structures, constants, and methods
+ * common to all port object definitions.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif // __cplusplus
+
+#include <dev/isci/scil/sci_base_object.h>
+#include <dev/isci/scil/sci_base_logger.h>
+#include <dev/isci/scil/sci_base_state_machine.h>
+#include <dev/isci/scil/sci_base_state_machine_logger.h>
+
+/**
+ * @enum SCI_BASE_PORT_STATES
+ *
+ * @brief This enumeration depicts all the states for the common port
+ * state machine.
+ */
+typedef 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
+
+} SCI_BASE_PORT_STATES;
+
+/**
+ * @struct SCI_BASE_PORT
+ *
+ * @brief The base port object abstracts the fields common to all SCI
+ * port objects.
+ */
+typedef struct SCI_BASE_PORT
+{
+ /**
+ * The field specifies that the parent object for the base controller
+ * is the base object itself.
+ */
+ SCI_BASE_OBJECT_T parent;
+
+ /**
+ * This field contains the information for the base port state machine.
+ */
+ SCI_BASE_STATE_MACHINE_T state_machine;
+
+ #ifdef SCI_LOGGING
+ SCI_BASE_STATE_MACHINE_LOGGER_T state_machine_logger;
+ #endif // SCI_LOGGING
+
+} SCI_BASE_PORT_T;
+
+struct SCI_BASE_PHY;
+
+typedef SCI_STATUS (*SCI_BASE_PORT_HANDLER_T)(
+ SCI_BASE_PORT_T *
+);
+
+typedef SCI_STATUS (*SCI_BASE_PORT_PHY_HANDLER_T)(
+ SCI_BASE_PORT_T *,
+ struct SCI_BASE_PHY *
+);
+
+typedef SCI_STATUS (*SCI_BASE_PORT_RESET_HANDLER_T)(
+ SCI_BASE_PORT_T *,
+ U32 timeout
+);
+
+/**
+ * @struct SCI_BASE_PORT_STATE_HANDLER
+ *
+ * @brief 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.
+ */
+typedef 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_STATE_HANDLER_T;
+
+/**
+ * @brief Construct the base port object
+ *
+ * @param[in] this_port This parameter specifies the base port to be
+ * constructed.
+ * @param[in] logger This parameter specifies the logger to be associated
+ * with this base port object.
+ * @param[in] state_table This parameter specifies the table of state
+ * definitions to be utilized for the domain state machine.
+ *
+ * @return none
+ */
+void sci_base_port_construct(
+ SCI_BASE_PORT_T * this_port,
+ SCI_BASE_LOGGER_T * logger,
+ SCI_BASE_STATE_T * state_table
+);
+
+#ifdef __cplusplus
+}
+#endif // __cplusplus
+
+#endif // _SCI_BASE_PORT_H_
diff --git a/sys/dev/isci/scil/sci_base_remote_device.c b/sys/dev/isci/scil/sci_base_remote_device.c
new file mode 100644
index 0000000..e227166
--- /dev/null
+++ b/sys/dev/isci/scil/sci_base_remote_device.c
@@ -0,0 +1,80 @@
+/*-
+ * 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.
+ *
+ * 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 <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <dev/isci/scil/sci_base_remote_device.h>
+
+void sci_base_remote_device_construct(
+ SCI_BASE_REMOTE_DEVICE_T *this_device,
+ SCI_BASE_LOGGER_T *logger,
+ SCI_BASE_STATE_T *state_table
+)
+{
+ sci_base_object_construct(
+ &this_device->parent,
+ logger
+ );
+
+ sci_base_state_machine_construct(
+ &this_device->state_machine,
+ &this_device->parent,
+ state_table,
+ SCI_BASE_REMOTE_DEVICE_STATE_INITIAL
+ );
+
+ sci_base_state_machine_start(
+ &this_device->state_machine
+ );
+}
+
diff --git a/sys/dev/isci/scil/sci_base_remote_device.h b/sys/dev/isci/scil/sci_base_remote_device.h
new file mode 100644
index 0000000..95870f3
--- /dev/null
+++ b/sys/dev/isci/scil/sci_base_remote_device.h
@@ -0,0 +1,298 @@
+/*-
+ * 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.
+ *
+ * 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.
+ *
+ * $FreeBSD$
+ */
+#ifndef _SCI_BASE_REMOTE_DEVICE_H_
+#define _SCI_BASE_REMOTE_DEVICE_H_
+
+/**
+ * @file
+ *
+ * @brief This file contains all of the structures, constants, and methods
+ * common to all remote device object definitions.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif // __cplusplus
+
+#include <dev/isci/scil/sci_base_state_machine.h>
+#include <dev/isci/scil/sci_base_logger.h>
+#include <dev/isci/scil/sci_base_state_machine_logger.h>
+
+struct SCI_BASE_REQUEST;
+
+/**
+ * @enum SCI_BASE_REMOTE_DEVICE_STATES
+ *
+ * @brief This enumeration depicts all the states for the common remote device
+ * state machine.
+ */
+typedef 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,
+
+#if !defined(DISABLE_WIDE_PORTED_TARGETS)
+ /**
+ * This state indicates the device is in the middle of updating
+ * its port width. All the IOs sent to this device will be Quiesced.
+ */
+ SCI_BASE_REMOTE_DEVICE_STATE_UPDATING_PORT_WIDTH,
+#endif
+
+ /**
+ * Simply the final state for the base remote device state machine.
+ */
+ SCI_BASE_REMOTE_DEVICE_STATE_FINAL,
+
+ SCI_BASE_REMOTE_DEVICE_MAX_STATES
+
+} SCI_BASE_REMOTE_DEVICE_STATES;
+
+/**
+ * @struct SCI_BASE_REMOTE_DEVICE
+ *
+ * @brief The base remote device object abstracts the fields common to all
+ * SCI remote device objects.
+ */
+typedef struct SCI_BASE_REMOTE_DEVICE
+{
+ /**
+ * The field specifies that the parent object for the base remote
+ * device is the base object itself.
+ */
+ SCI_BASE_OBJECT_T parent;
+
+ /**
+ * This field contains the information for the base remote device state
+ * machine.
+ */
+ SCI_BASE_STATE_MACHINE_T state_machine;
+
+ #ifdef SCI_LOGGING
+ /**
+ * This field contains the state machine observer for the state machine.
+ */
+ SCI_BASE_STATE_MACHINE_LOGGER_T state_machine_logger;
+ #endif // SCI_LOGGING
+
+} SCI_BASE_REMOTE_DEVICE_T;
+
+
+typedef SCI_STATUS (*SCI_BASE_REMOTE_DEVICE_HANDLER_T)(
+ SCI_BASE_REMOTE_DEVICE_T *
+);
+
+typedef SCI_STATUS (*SCI_BASE_REMOTE_DEVICE_REQUEST_HANDLER_T)(
+ SCI_BASE_REMOTE_DEVICE_T *,
+ struct SCI_BASE_REQUEST *
+);
+
+typedef SCI_STATUS (*SCI_BASE_REMOTE_DEVICE_HIGH_PRIORITY_REQUEST_COMPLETE_HANDLER_T)(
+ SCI_BASE_REMOTE_DEVICE_T *,
+ struct SCI_BASE_REQUEST *,
+ void *,
+ SCI_IO_STATUS
+);
+
+/**
+ * @struct SCI_BASE_CONTROLLER_STATE_HANDLER
+ *
+ * @brief 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.
+ */
+typedef 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_STATE_HANDLER_T;
+
+/**
+ * @brief Construct the base remote device
+ *
+ * @param[in] this_remote_device This parameter specifies the base remote
+ * device to be constructed.
+ * @param[in] logger This parameter specifies the logger associated with
+ * this base remote device object.
+ * @param[in] state_table This parameter specifies the table of state
+ * definitions to be utilized for the remote device state machine.
+ *
+ * @return none
+ */
+void sci_base_remote_device_construct(
+ SCI_BASE_REMOTE_DEVICE_T * this_device,
+ SCI_BASE_LOGGER_T * logger,
+ SCI_BASE_STATE_T * state_table
+);
+
+#ifdef __cplusplus
+}
+#endif // __cplusplus
+
+#endif // _SCI_BASE_REMOTE_DEVICE_H_
diff --git a/sys/dev/isci/scil/sci_base_request.c b/sys/dev/isci/scil/sci_base_request.c
new file mode 100644
index 0000000..ecb75c4
--- /dev/null
+++ b/sys/dev/isci/scil/sci_base_request.c
@@ -0,0 +1,79 @@
+/*-
+ * 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.
+ *
+ * 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 <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <dev/isci/scil/sci_base_request.h>
+
+void sci_base_request_construct(
+ SCI_BASE_REQUEST_T *this_request,
+ SCI_BASE_LOGGER_T *my_logger,
+ SCI_BASE_STATE_T *my_state_table
+)
+{
+ sci_base_object_construct(
+ &this_request->parent,
+ my_logger
+ );
+
+ sci_base_state_machine_construct(
+ &this_request->state_machine,
+ &this_request->parent,
+ my_state_table,
+ SCI_BASE_REQUEST_STATE_INITIAL
+ );
+
+ sci_base_state_machine_start(
+ &this_request->state_machine
+ );
+}
diff --git a/sys/dev/isci/scil/sci_base_request.h b/sys/dev/isci/scil/sci_base_request.h
new file mode 100644
index 0000000..231c0bf
--- /dev/null
+++ b/sys/dev/isci/scil/sci_base_request.h
@@ -0,0 +1,209 @@
+/*-
+ * 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.
+ *
+ * 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.
+ *
+ * $FreeBSD$
+ */
+#ifndef _SCI_BASE_REQUST_H_
+#define _SCI_BASE_REQUST_H_
+
+/**
+ * @file
+ *
+ * @brief This file contains all of the constants, types, and method
+ * declarations for the SCI base IO and task request objects.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif // __cplusplus
+
+#include <dev/isci/scil/sci_base_logger.h>
+#include <dev/isci/scil/sci_base_state_machine.h>
+#include <dev/isci/scil/sci_base_state_machine_logger.h>
+
+/**
+ * @enum SCI_BASE_REQUEST_STATES
+ *
+ * @brief This enumeration depicts all the states for the common request
+ * state machine.
+ */
+typedef 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,
+
+ SCI_BASE_REQUEST_MAX_STATES
+
+} SCI_BASE_REQUEST_STATES;
+
+/**
+ * @struct SCI_BASE_REQUEST
+ *
+ * @brief The base request object abstracts the fields common to all SCI IO
+ * and task request objects.
+ */
+typedef struct SCI_BASE_REQUEST
+{
+ /**
+ * The field specifies that the parent object for the base request is the
+ * base object itself.
+ */
+ SCI_BASE_OBJECT_T parent;
+
+ /**
+ * This field contains the information for the base request state machine.
+ */
+ SCI_BASE_STATE_MACHINE_T state_machine;
+
+ #ifdef SCI_LOGGING
+ SCI_BASE_STATE_MACHINE_LOGGER_T state_machine_logger;
+ #endif // SCI_LOGGING
+
+} SCI_BASE_REQUEST_T;
+
+typedef SCI_STATUS (*SCI_BASE_REQUEST_HANDLER_T)(
+ SCI_BASE_REQUEST_T * this_request
+);
+
+/**
+ * @struct SCI_BASE_REQUEST_STATE_HANDLER
+ *
+ * @brief 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.
+ *
+ */
+typedef 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_STATE_HANDLER_T;
+
+/**
+ * @brief Construct the base request.
+ *
+ * @param[in] this_request This parameter specifies the base request
+ * to be constructed.
+ * @param[in] logger This parameter specifies the logger associated with
+ * this base request object.
+ * @param[in] state_table This parameter specifies the table of state
+ * definitions to be utilized for the request state machine.
+ *
+ * @return none
+ */
+void sci_base_request_construct(
+ SCI_BASE_REQUEST_T * this_request,
+ SCI_BASE_LOGGER_T * logger,
+ SCI_BASE_STATE_T * state_table
+);
+
+#ifdef __cplusplus
+}
+#endif // __cplusplus
+
+#endif // _SCI_BASE_REQUST_H_
diff --git a/sys/dev/isci/scil/sci_base_state.h b/sys/dev/isci/scil/sci_base_state.h
new file mode 100644
index 0000000..68cce84
--- /dev/null
+++ b/sys/dev/isci/scil/sci_base_state.h
@@ -0,0 +1,110 @@
+/*-
+ * 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.
+ *
+ * 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.
+ *
+ * $FreeBSD$
+ */
+#ifndef _SCI_BASE_STATE_H_
+#define _SCI_BASE_STATE_H_
+
+/**
+ * @file
+ *
+ * @brief This file contains all of the structures, constants, and methods
+ * common to all base object definitions.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif // __cplusplus
+
+#include <dev/isci/scil/sci_base_object.h>
+
+typedef void (*SCI_BASE_STATE_HANDLER_T)(
+ void
+);
+
+typedef void (*SCI_STATE_TRANSITION_T)(
+ SCI_BASE_OBJECT_T *base_object
+);
+
+/**
+ * @struct SCI_BASE_STATE
+ *
+ * @brief The base state object abstracts the fields common to all state
+ * objects defined in SCI.
+ */
+typedef struct SCI_BASE_STATE
+{
+ /**
+ * This field indicates the defined value for this state. After
+ * initialization this field should not change.
+ */
+ U32 value;
+
+ /**
+ * 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;
+
+} SCI_BASE_STATE_T;
+
+#ifdef __cplusplus
+}
+#endif // __cplusplus
+
+#endif // _SCI_BASE_STATE_H_
diff --git a/sys/dev/isci/scil/sci_base_state_machine.c b/sys/dev/isci/scil/sci_base_state_machine.c
new file mode 100644
index 0000000..0e95c64
--- /dev/null
+++ b/sys/dev/isci/scil/sci_base_state_machine.c
@@ -0,0 +1,212 @@
+/*-
+ * 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.
+ *
+ * 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 <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/**
+ * @file
+ *
+ * @brief This file contains all of the functionality common to all state
+ * machine object implementations.
+ */
+
+#include <dev/isci/scil/sci_base_state_machine.h>
+
+#define SCI_STATE_MACHINE_EXIT_STATE(state_machine) \
+ if ( \
+ ((state_machine)->state_table[(state_machine)->current_state_id].\
+ exit_state != NULL) \
+ ) \
+ { \
+ ((state_machine)->state_table[(state_machine)->current_state_id].\
+ exit_state((state_machine)->state_machine_owner)); \
+ }
+
+#define SCI_STATE_MACHINE_ENTER_STATE(state_machine) \
+ ((state_machine)->state_table[(state_machine)->current_state_id].\
+ enter_state((state_machine)->state_machine_owner))
+
+#define SCI_STATE_MACHINE_SET_STATE(state_machine, id) \
+ ((state_machine)->current_state_id = (id))
+
+//******************************************************************************
+//* P R O T E C T E D M E T H O D S
+//******************************************************************************
+
+/**
+ * @brief 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.
+ *
+ * @param[in] this_state_machine This parameter provides the state machine
+ * object to be constructed.
+ * @param[in] state_machine_owner This parameter indicates the object that
+ * is owns the state machine being constructed.
+ * @param[in] state_table This parameter specifies the table of state objects
+ * that is managed by this state machine.
+ * @param[in] initial_state This parameter specifies the value of the initial
+ * state for this state machine.
+ *
+ * @return none
+ */
+void sci_base_state_machine_construct(
+ SCI_BASE_STATE_MACHINE_T * this_state_machine,
+ SCI_BASE_OBJECT_T * my_state_machine_owner,
+ SCI_BASE_STATE_T * state_table,
+ U32 initial_state
+)
+{
+#if defined(SCI_LOGGING)
+ sci_base_subject_construct(&this_state_machine->parent);
+#endif // defined(SCI_LOGGING)
+
+ this_state_machine->state_machine_owner = my_state_machine_owner;
+ this_state_machine->initial_state_id = initial_state;
+ this_state_machine->previous_state_id = initial_state;
+ this_state_machine->current_state_id = initial_state;
+ this_state_machine->state_table = state_table;
+}
+
+/**
+ * @brief This method will cause the state machine to enter the
+ * initial state.
+ *
+ * @see sci_base_state_machine_construct() for how to set the initial state
+ *
+ * @param[in] this_state_machine This parameter specifies the state machine
+ * that is to be started.
+ *
+ * @return none
+ */
+void sci_base_state_machine_start(
+ SCI_BASE_STATE_MACHINE_T *this_state_machine
+)
+{
+ SCI_STATE_MACHINE_SET_STATE(
+ this_state_machine, this_state_machine->initial_state_id
+ );
+
+#if defined(SCI_BASE_ENABLE_SUBJECT_NOTIFICATION)
+ sci_base_subject_notify(&this_state_machine->parent);
+#endif
+
+ SCI_STATE_MACHINE_ENTER_STATE(this_state_machine);
+}
+
+/**
+ * @brief This method will cause the state machine to exit it's current
+ * state only.
+ *
+ * @param[in] this_state_machine This parameter specifies the state machine
+ * that is to be stopped.
+ *
+ * @return none
+ */
+void sci_base_state_machine_stop(
+ SCI_BASE_STATE_MACHINE_T *this_state_machine
+)
+{
+ SCI_STATE_MACHINE_EXIT_STATE(this_state_machine);
+
+#if defined(SCI_BASE_ENABLE_SUBJECT_NOTIFICATION)
+ sci_base_subject_notify(&this_state_machine->parent);
+#endif
+}
+
+/**
+ * @brief This method performs an update to the current state of
+ * the state machine.
+ *
+ * @param[in] this_state_machine This parameter specifies the state machine
+ * for which the caller wishes to perform a state change.
+ * @param[in] next_state This parameter specifies the new state for the
+ * state machine.
+ *
+ * @return none
+ */
+void sci_base_state_machine_change_state(
+ SCI_BASE_STATE_MACHINE_T *this_state_machine,
+ U32 next_state
+)
+{
+ SCI_STATE_MACHINE_EXIT_STATE(this_state_machine);
+
+ this_state_machine->previous_state_id = this_state_machine->current_state_id;
+ SCI_STATE_MACHINE_SET_STATE(this_state_machine, next_state);
+
+#if defined(SCI_BASE_ENABLE_SUBJECT_NOTIFICATION)
+ // Notify of the state change prior to entering the state.
+ sci_base_subject_notify(&this_state_machine->parent);
+#endif
+
+ SCI_STATE_MACHINE_ENTER_STATE(this_state_machine);
+}
+
+/**
+ * @brief This method simply returns the current state of the
+ * state machine to the caller.
+ *
+ * @param[in] this_state_machine This parameter specifies the state
+ * machine for which to retrieve the current state.
+ *
+ * @return This method returns a U32 value indicating the current state for
+ * the supplied state machine.
+ */
+U32 sci_base_state_machine_get_state(
+ SCI_BASE_STATE_MACHINE_T *this_state_machine
+)
+{
+ return this_state_machine->current_state_id;
+}
+
diff --git a/sys/dev/isci/scil/sci_base_state_machine.h b/sys/dev/isci/scil/sci_base_state_machine.h
new file mode 100644
index 0000000..9a5f749
--- /dev/null
+++ b/sys/dev/isci/scil/sci_base_state_machine.h
@@ -0,0 +1,157 @@
+/*-
+ * 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.
+ *
+ * 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.
+ *
+ * $FreeBSD$
+ */
+#ifndef _SCI_BASE_STATE_MACHINE_H_
+#define _SCI_BASE_STATE_MACHINE_H_
+
+/**
+ * @file
+ *
+ * @brief This file contains all structures, constants, or method declarations
+ * common to all state machines defined in SCI.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif // __cplusplus
+
+#include <dev/isci/scil/sci_base_subject.h>
+#include <dev/isci/scil/sci_base_state.h>
+
+
+/**
+ * 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
+ *
+ * @brief This structure defines the fields common to all state machines.
+ */
+typedef struct SCI_BASE_STATE_MACHINE
+{
+#if defined(SCI_LOGGING)
+ /**
+ * The state machine object participates in the observer design pattern.
+ * Thus, the SCI_BASE_SUBJECT is the parent object, which allows a
+ * state machine to be easily monitored by a user.
+ */
+ SCI_BASE_SUBJECT_T parent;
+#endif // defined(SCI_LOGGING)
+
+ /**
+ * This field points to the start of the state machine's state table.
+ */
+ SCI_BASE_STATE_T * 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.
+ */
+ SCI_BASE_OBJECT_T * 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;
+
+} SCI_BASE_STATE_MACHINE_T;
+
+//******************************************************************************
+//* P R O T E C T E D M E T H O D S
+//******************************************************************************
+
+void sci_base_state_machine_construct(
+ SCI_BASE_STATE_MACHINE_T *this_state_machine,
+ SCI_BASE_OBJECT_T *state_machine_owner,
+ SCI_BASE_STATE_T *state_table,
+ U32 initial_state
+);
+
+void sci_base_state_machine_start(
+ SCI_BASE_STATE_MACHINE_T *this_state_machine
+);
+
+void sci_base_state_machine_stop(
+ SCI_BASE_STATE_MACHINE_T *this_state_machine
+);
+
+void sci_base_state_machine_change_state(
+ SCI_BASE_STATE_MACHINE_T *this_state_machine,
+ U32 next_state
+);
+
+U32 sci_base_state_machine_get_state(
+ SCI_BASE_STATE_MACHINE_T *this_state_machine
+);
+
+#ifdef __cplusplus
+}
+#endif // __cplusplus
+
+#endif // _SCI_BASE_STATE_MACHINE_H_
diff --git a/sys/dev/isci/scil/sci_base_state_machine_logger.c b/sys/dev/isci/scil/sci_base_state_machine_logger.c
new file mode 100644
index 0000000..0adec26
--- /dev/null
+++ b/sys/dev/isci/scil/sci_base_state_machine_logger.c
@@ -0,0 +1,217 @@
+/*-
+ * 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.
+ *
+ * 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 <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/**
+ * @file
+ *
+ * @brief This file provides the public and protected implementations for the
+ * state machine logger. The state machine logger will provide debug
+ * log information on a state machine for each state transition.
+ */
+
+#include <dev/isci/scil/sci_base_state_machine_logger.h>
+
+#if defined(SCI_LOGGING)
+
+//******************************************************************************
+//* P R O T E C T E D M E T H O D S
+//******************************************************************************
+
+/**
+ * This is the function that is called when the state machine wants to notify
+ * this observer that there has been a state change.
+ *
+ * @param[in] observer The state machine logger that is observing the state
+ * machine.
+ * @param[in] subject The state machine that is being observed.
+ */
+static
+void sci_base_state_machine_logger_update(
+ SCI_BASE_OBSERVER_T *observer,
+ SCI_BASE_SUBJECT_T *subject
+)
+{
+ SCI_BASE_STATE_MACHINE_LOGGER_T *this_observer;
+ this_observer = (SCI_BASE_STATE_MACHINE_LOGGER_T *)observer;
+
+ this_observer->log_function(
+ sci_base_object_get_logger(this_observer->log_object),
+ this_observer->log_mask,
+ "%s 0x%08x %s has transitioned from %d to %d\n",
+ this_observer->log_object_name,
+ this_observer->log_object,
+ this_observer->log_state_machine_name,
+ this_observer->parent.subject_state,
+ sci_base_state_machine_get_state((SCI_BASE_STATE_MACHINE_T *)subject)
+ );
+
+ sci_base_state_machine_observer_default_update(
+ &this_observer->parent.parent, subject
+ );
+}
+
+//******************************************************************************
+//* P U B L I C M E T H O D S
+//******************************************************************************
+
+/**
+ * This function will construct the state machine logger and attach it to the
+ * state machine that is to be observed.
+ *
+ * @param[in] this_observer This is the state machine logger object that is
+ * going to observe the subject state machine.
+ * @param[in] the_object This is the object that contains the state machine
+ * being observed it is used to report the address of the object for
+ * which a state transition has occurred.
+ * @param[in] the_log_function This is the logging function to be used when a
+ * state machine transition occurs. Since this is a base object type it
+ * does not actually know if the logging function is for the core or
+ * framework.
+ * @param[in] the_object_name This is the name of the object that contains the
+ * state machine being observed.
+ * @param[in] the_state_machine_name This is the name that will be displayed
+ * in the log string for the state machine being observed.
+ * @param[in] the_object_mask This is the log object mask used when calling
+ * the logging function.
+ *
+ * @return Nothing
+ */
+void sci_base_state_machine_logger_construct(
+ SCI_BASE_STATE_MACHINE_LOGGER_T * this_observer,
+ SCI_BASE_OBJECT_T * the_object,
+ SCI_BASE_STATE_MACHINE_LOGGER_LOG_HANDLER_T the_log_function,
+ char * log_object_name,
+ char * log_state_machine_name,
+ U32 log_object_mask
+)
+{
+ sci_base_state_machine_observer_construct(&this_observer->parent);
+
+ this_observer->log_object = the_object;
+ this_observer->log_function = the_log_function;
+ this_observer->log_object_name = log_object_name;
+ this_observer->log_state_machine_name = log_state_machine_name;
+ this_observer->log_mask = log_object_mask;
+
+ this_observer->parent.parent.update = sci_base_state_machine_logger_update;
+}
+
+/**
+ * This is a helper function that will construct the state machine logger and
+ * attach it to the state machine that is to be observed.
+ *
+ * @param[in] this_observer This is the state machine logger object that is
+ * going to observe the subject state machine.
+ * @param[in] the_state_machine This is the state machine that is under
+ * observation.
+ * @param[in] the_object This is the object that contains the state machine
+ * being observed it is used to report the address of the object for
+ * which a state transition has occurred.
+ * @param[in] the_log_function This is the logging function to be used when a
+ * state machine transition occurs. Since this is a base object type it
+ * does not actually know if the logging function is for the core or
+ * framework.
+ * @param[in] the_object_name This is the name of the object that contains the
+ * state machine being observed.
+ * @param[in] the_state_machine_name This is the name that will be displayed
+ * in the log string for the state machine being observed.
+ * @param[in] the_object_mask This is the log object mask used when calling
+ * the logging function.
+ *
+ * @return Nothing
+ */
+void sci_base_state_machine_logger_initialize(
+ SCI_BASE_STATE_MACHINE_LOGGER_T * this_observer,
+ SCI_BASE_STATE_MACHINE_T * the_state_machine,
+ SCI_BASE_OBJECT_T * the_object,
+ SCI_BASE_STATE_MACHINE_LOGGER_LOG_HANDLER_T the_log_function,
+ char * log_object_name,
+ char * log_state_machine_name,
+ U32 log_object_mask
+)
+{
+ sci_base_state_machine_logger_construct(
+ this_observer, the_object,
+ the_log_function, log_object_name, log_state_machine_name, log_object_mask
+ );
+
+ sci_base_subject_attach_observer(
+ &the_state_machine->parent, &this_observer->parent.parent
+ );
+}
+
+/**
+ * This is a helper function that will detach this observer from the state
+ * machine that is being observerd.
+ *
+ * @param[in] this_observer This is the observer to detach from the state
+ * machine.
+ * @parame[in] the_state_machine This is the state machine that is no longer
+ * going to be observed.
+ *
+ * @return Nothing
+ */
+void sci_base_state_machine_logger_deinitialize(
+ SCI_BASE_STATE_MACHINE_LOGGER_T * this_observer,
+ SCI_BASE_STATE_MACHINE_T * the_state_machine
+)
+{
+ sci_base_subject_detach_observer(
+ &the_state_machine->parent, &this_observer->parent.parent
+ );
+}
+
+#endif // defined(SCI_LOGGING)
+
diff --git a/sys/dev/isci/scil/sci_base_state_machine_logger.h b/sys/dev/isci/scil/sci_base_state_machine_logger.h
new file mode 100644
index 0000000..42f2121
--- /dev/null
+++ b/sys/dev/isci/scil/sci_base_state_machine_logger.h
@@ -0,0 +1,137 @@
+/*-
+ * 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.
+ *
+ * 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.
+ *
+ * $FreeBSD$
+ */
+#ifndef _SCI_BASE_STATE_MACHINE_LOGGER_H_
+#define _SCI_BASE_STATE_MACHINE_LOGGER_H_
+
+/**
+ * @file
+ *
+ * @brief This file provides the structures and function prototypes for the
+ * state machine logger. The functions provided are only implemented
+ * if the SCI_LOGGING flag is enabled.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif // __cplusplus
+
+#include <dev/isci/scil/sci_types.h>
+#include <dev/isci/scil/sci_base_object.h>
+#include <dev/isci/scil/sci_base_state_machine.h>
+#include <dev/isci/scil/sci_base_state_machine_observer.h>
+
+/**
+ * This type is defined so we can pass either a core or framework logging
+ * function to the state machine logger since both have the same prototypes
+ * and this base state machine logger does not actually know which component
+ * will be doing the logging.
+ */
+typedef void (*SCI_BASE_STATE_MACHINE_LOGGER_LOG_HANDLER_T)(
+ SCI_LOGGER_HANDLE_T, U32, char *, ...
+);
+
+#if defined(SCI_LOGGING)
+
+typedef struct SCI_BASE_STATE_MACHINE_LOGGER
+{
+ SCI_BASE_STATE_MACHINE_OBSERVER_T parent;
+
+ SCI_BASE_OBJECT_T * log_object;
+ SCI_BASE_STATE_MACHINE_LOGGER_LOG_HANDLER_T log_function;
+ char * log_object_name;
+ char * log_state_machine_name;
+ U32 log_mask;
+
+} SCI_BASE_STATE_MACHINE_LOGGER_T;
+
+
+void sci_base_state_machine_logger_construct(
+ SCI_BASE_STATE_MACHINE_LOGGER_T * this_observer,
+ SCI_BASE_OBJECT_T * the_object,
+ SCI_BASE_STATE_MACHINE_LOGGER_LOG_HANDLER_T the_log_function,
+ char * log_object_name,
+ char * log_state_machine_name,
+ U32 log_object_mask
+);
+
+void sci_base_state_machine_logger_initialize(
+ SCI_BASE_STATE_MACHINE_LOGGER_T * this_observer,
+ SCI_BASE_STATE_MACHINE_T * the_state_machine,
+ SCI_BASE_OBJECT_T * the_object,
+ SCI_BASE_STATE_MACHINE_LOGGER_LOG_HANDLER_T the_log_function,
+ char * log_object_name,
+ char * log_state_machine_name,
+ U32 log_object_mask
+);
+
+void sci_base_state_machine_logger_deinitialize(
+ SCI_BASE_STATE_MACHINE_LOGGER_T * this_observer,
+ SCI_BASE_STATE_MACHINE_T * the_state_machine
+);
+
+#else // SCI_LOGGING
+
+typedef U8 SCI_BASE_STATE_MACHINE_LOGGER_T;
+
+#define sci_base_state_machine_logger_construct(this_observer,the_object,the_log_function,log_object_name,log_state_machine_name,log_object_mask)
+#define sci_base_state_machine_logger_initialize(this_observer,the_state_machine,the_object,the_log_function,log_object_name,log_state_machine_name,log_object_mask)
+#define sci_base_state_machine_logger_deinitialize(this_observer, the_state_machine)
+
+#endif // SCI_LOGGING
+
+#ifdef __cplusplus
+}
+#endif // __cplusplus
+
+#endif // _SCI_BASE_STATE_MACHINE_LOGGER_H_
diff --git a/sys/dev/isci/scil/sci_base_state_machine_observer.c b/sys/dev/isci/scil/sci_base_state_machine_observer.c
new file mode 100644
index 0000000..5a0ef54
--- /dev/null
+++ b/sys/dev/isci/scil/sci_base_state_machine_observer.c
@@ -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.
+ *
+ * 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 <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/**
+ * @file
+ *
+ * @brief This file provides the implementation for the observer role
+ * for a state machine. A state machine observer is notified when
+ * the state machine changes states.
+ */
+
+#include <dev/isci/scil/sci_base_state_machine.h>
+#include <dev/isci/scil/sci_base_state_machine_observer.h>
+
+#if defined(SCI_LOGGING)
+
+#define SCI_BASE_INVALID_SUBJECT_STATE 0xFFFF
+
+//******************************************************************************
+//* P R O T E C T E D M E T H O D S
+//******************************************************************************
+
+void sci_base_state_machine_observer_default_update(
+ SCI_BASE_OBSERVER_T *this_observer,
+ SCI_BASE_SUBJECT_T *the_subject
+)
+{
+ SCI_BASE_STATE_MACHINE_OBSERVER_T *state_machine_observer;
+
+ state_machine_observer = (SCI_BASE_STATE_MACHINE_OBSERVER_T *)this_observer;
+
+ state_machine_observer->subject_state =
+ sci_base_state_machine_get_state((SCI_BASE_STATE_MACHINE_T *)the_subject);
+}
+
+// ---------------------------------------------------------------------------
+
+void sci_base_state_machine_observer_construct(
+ SCI_BASE_STATE_MACHINE_OBSERVER_T *this_observer
+)
+{
+ this_observer->parent.update = sci_base_state_machine_observer_default_update;
+
+ this_observer->subject_state = SCI_BASE_INVALID_SUBJECT_STATE;
+}
+
+#endif // defined(SCI_LOGGING)
diff --git a/sys/dev/isci/scil/sci_base_state_machine_observer.h b/sys/dev/isci/scil/sci_base_state_machine_observer.h
new file mode 100644
index 0000000..adbeabd
--- /dev/null
+++ b/sys/dev/isci/scil/sci_base_state_machine_observer.h
@@ -0,0 +1,138 @@
+/*-
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 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.
+ *
+ * $FreeBSD$
+ */
+#ifndef _SCI_BASE_STATE_MACHINE_OBSERVER_H_
+#define _SCI_BASE_STATE_MACHINE_OBSERVER_H_
+
+/**
+ * @file
+ *
+ * @brief This file contains all of the structures, constants, and methods
+ * common to all state machine observer object definitions.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif // __cplusplus
+
+#include <dev/isci/scil/sci_base_observer.h>
+#include <dev/isci/scil/sci_base_subject.h>
+
+#if defined(SCI_LOGGING)
+
+/**
+ * @struct SCI_BASE_STATE_MACHINE_OBSERVER
+ *
+ * @brief The base state machine observer structure defines the fields
+ * necessary for a user that wishes to observe the behavior (i.e.
+ * state changes) of a state machine.
+ */
+typedef struct SCI_BASE_STATE_MACHINE_OBSERVER
+{
+ /**
+ * The field specifies that the parent object for the base state
+ * machine observer is the base observer itself.
+ */
+ SCI_BASE_OBSERVER_T parent;
+
+ /**
+ * This field contains the state recorded during the last state machine
+ * update.
+ */
+ U32 subject_state;
+
+} SCI_BASE_STATE_MACHINE_OBSERVER_T;
+
+/**
+ * @brief This method provides default behavior for a state machine observer.
+ * This method records the state of the subject (i.e. the state
+ * machine) and returns.
+ *
+ * @param[in] this_observer This parameter specifes the state machine
+ * observer in which to record the state change from the subject.
+ * @param[in] the_subject This parameter evaluates to the state machine
+ * object under observation.
+ *
+ * @return none
+ */
+void sci_base_state_machine_observer_default_update(
+ SCI_BASE_OBSERVER_T *this_observer,
+ SCI_BASE_SUBJECT_T *the_subject
+);
+
+/**
+ * @brief This method constructs the supplied state machine observer.
+ *
+ * @param[in] this_observer This parameter specifes the state machine
+ * observer to be constructed.
+ *
+ * @return none
+ */
+void sci_base_state_machine_observer_construct(
+ SCI_BASE_STATE_MACHINE_OBSERVER_T *this_observer
+);
+
+#else // defined(SCI_LOGGING)
+
+typedef U8 SCI_BASE_STATE_MACHINE_OBSERVER_T;
+
+#define sci_base_state_machine_observer_default_update
+#define sci_base_state_machine_observer_construct
+
+#endif // defined(SCI_LOGGING)
+
+#ifdef __cplusplus
+}
+#endif // __cplusplus
+
+#endif // _SCI_BASE_STATE_MACHINE_OBSERVER_H_
diff --git a/sys/dev/isci/scil/sci_base_subject.c b/sys/dev/isci/scil/sci_base_subject.c
new file mode 100644
index 0000000..894136d
--- /dev/null
+++ b/sys/dev/isci/scil/sci_base_subject.c
@@ -0,0 +1,149 @@
+/*-
+ * 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.
+ *
+ * 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 <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/**
+ * @file
+ *
+ * @brief This file contains the base subject method implementations and
+ * any constants or structures private to the base subject object.
+ * A subject is a participant in the observer design pattern. A
+ * subject represents the object being observed.
+ */
+
+#include <dev/isci/scil/sci_types.h>
+#include <dev/isci/scil/sci_base_subject.h>
+#include <dev/isci/scil/sci_base_observer.h>
+
+#if defined(SCI_LOGGING)
+
+//******************************************************************************
+//* P R O T E C T E D M E T H O D S
+//******************************************************************************
+
+void sci_base_subject_construct(
+ SCI_BASE_SUBJECT_T *this_subject
+)
+{
+ this_subject->observer_list = NULL;
+}
+
+// ---------------------------------------------------------------------------
+
+void sci_base_subject_notify(
+ SCI_BASE_SUBJECT_T *this_subject
+)
+{
+ SCI_BASE_OBSERVER_T *this_observer = this_subject->observer_list;
+
+ while (this_observer != NULL)
+ {
+ sci_base_observer_update(this_observer, this_subject);
+
+ this_observer = this_observer->next;
+ }
+}
+
+// ---------------------------------------------------------------------------
+
+void sci_base_subject_attach_observer(
+ SCI_BASE_SUBJECT_T *this_subject,
+ SCI_BASE_OBSERVER_T *observer
+)
+{
+ observer->next = this_subject->observer_list;
+
+ this_subject->observer_list = observer;
+}
+
+// ---------------------------------------------------------------------------
+
+void sci_base_subject_detach_observer(
+ SCI_BASE_SUBJECT_T *this_subject,
+ SCI_BASE_OBSERVER_T *observer
+)
+{
+ SCI_BASE_OBSERVER_T *current_observer = this_subject->observer_list;
+ SCI_BASE_OBSERVER_T *previous_observer = NULL;
+
+ // Search list for the item to remove
+ while (
+ current_observer != NULL
+ && current_observer != observer
+ )
+ {
+ previous_observer = current_observer;
+ current_observer = current_observer->next;
+ }
+
+ // Was this observer in the list?
+ if (current_observer == observer)
+ {
+ if (previous_observer != NULL)
+ {
+ // Remove from middle or end of list
+ previous_observer->next = observer->next;
+ }
+ else
+ {
+ // Remove from the front of the list
+ this_subject->observer_list = observer->next;
+ }
+
+ // protect the list so people dont follow bad pointers
+ observer->next = NULL;
+ }
+}
+
+#endif // defined(SCI_LOGGING)
diff --git a/sys/dev/isci/scil/sci_base_subject.h b/sys/dev/isci/scil/sci_base_subject.h
new file mode 100644
index 0000000..0499d1b
--- /dev/null
+++ b/sys/dev/isci/scil/sci_base_subject.h
@@ -0,0 +1,157 @@
+/*-
+ * 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.
+ *
+ * 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.
+ *
+ * $FreeBSD$
+ */
+#ifndef _SCI_BASE_SUBJECT_H_
+#define _SCI_BASE_SUBJECT_H_
+
+/**
+ * @file
+ *
+ * @brief This file contains all of the structures, constants, and methods
+ * common to all subjects object definitions. A subject is a
+ * participant in the observer pattern. A subject represents the
+ * object being observed.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif // __cplusplus
+
+#include <dev/isci/scil/sci_types.h>
+
+#if defined(SCI_LOGGING)
+
+struct SCI_BASE_OBSERVER;
+
+/**
+ * @struct SCI_BASE_SUBJECT
+ *
+ * @brief This structure defines the fields common to all subjects that
+ * participate in the observer design pattern
+ */
+typedef struct SCI_BASE_SUBJECT
+{
+ struct SCI_BASE_OBSERVER *observer_list;
+
+} SCI_BASE_SUBJECT_T;
+
+
+/**
+ * @brief This method acts as the basic constructor for the subject.
+ *
+ * @param[in] this_subject This fields specifies the subject being
+ * constructed.
+ *
+ * @return none
+ */
+void sci_base_subject_construct(
+ SCI_BASE_SUBJECT_T *this_subject
+);
+
+/**
+ * @brief This method will call the update method for all
+ * observers attached to this subject.
+ *
+ * @param[in] this_subject This parameter specifies the subject for
+ * which to notify participating observers.
+ *
+ * @return none
+ */
+void sci_base_subject_notify(
+ SCI_BASE_SUBJECT_T *this_subject
+);
+
+/**
+ * @brief This method will add an observer to the subject.
+ *
+ * @param[in] this_subject This parameter specifies the subject for which
+ * an observer is being added.
+ * @param[in] observer This parameter specifies the observer that wishes
+ * it listen for notifications for the supplied subject.
+ *
+ * @return none
+ */
+void sci_base_subject_attach_observer(
+ SCI_BASE_SUBJECT_T *this_subject,
+ struct SCI_BASE_OBSERVER *observer
+);
+
+/**
+ * @brief This method will remove the observer from the subject.
+ *
+ * @param[in] this_subject
+ * @param[in] my_observer
+ *
+ * @return none
+ */
+void sci_base_subject_detach_observer(
+ SCI_BASE_SUBJECT_T *this_subject,
+ struct SCI_BASE_OBSERVER *my_observer
+);
+
+#else // defined(SCI_LOGGING)
+
+typedef U8 SCI_BASE_SUBJECT_T;
+
+#define sci_base_subject_construct
+#define sci_base_subject_notify
+#define sci_base_subject_attach_observer
+#define sci_base_subject_detach_observer
+
+#endif // defined(SCI_LOGGING)
+
+#ifdef __cplusplus
+}
+#endif // __cplusplus
+
+#endif // _SCI_BASE_SUBJECT_H_
diff --git a/sys/dev/isci/scil/sci_controller.h b/sys/dev/isci/scil/sci_controller.h
new file mode 100644
index 0000000..ca004f0
--- /dev/null
+++ b/sys/dev/isci/scil/sci_controller.h
@@ -0,0 +1,113 @@
+/*-
+ * 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.
+ *
+ * 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.
+ *
+ * $FreeBSD$
+ */
+#ifndef _SCI_CONTROLLER_H_
+#define _SCI_CONTROLLER_H_
+
+/**
+ * @file
+ *
+ * @brief This file contains all of the interface methods that can be called
+ * by an SCI user on all SCI controller objects.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif // __cplusplus
+
+#include <dev/isci/scil/sci_types.h>
+
+
+#define SCI_CONTROLLER_INVALID_IO_TAG 0xFFFF
+
+typedef enum _SCI_CONTROLLER_ERROR {
+ SCI_CONTROLLER_FATAL_ERROR = 1,
+ SCI_CONTROLLER_REMOTE_DEVICE_ERROR,
+ SCI_CONTROLLER_FATAL_MEMORY_ERROR
+} SCI_CONTROLLER_ERROR;
+
+/**
+ * @brief 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.
+ *
+ * @warning 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.
+ *
+ * @pre 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.
+ *
+ * @param[in] controller This parameter specifies the controller for which
+ * to retrieve the DMA safe memory descriptor list.
+ *
+ * @return A pointer to a physical memory descriptor array.
+ */
+SCI_MEMORY_DESCRIPTOR_LIST_HANDLE_T
+sci_controller_get_memory_descriptor_list_handle(
+ SCI_CONTROLLER_HANDLE_T controller
+);
+
+#ifdef __cplusplus
+}
+#endif // __cplusplus
+
+#endif // _SCI_CONTROLLER_H_
+
diff --git a/sys/dev/isci/scil/sci_controller_constants.h b/sys/dev/isci/scil/sci_controller_constants.h
new file mode 100644
index 0000000..36740f7
--- /dev/null
+++ b/sys/dev/isci/scil/sci_controller_constants.h
@@ -0,0 +1,217 @@
+/*-
+ * 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.
+ *
+ * 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.
+ *
+ * $FreeBSD$
+ */
+#ifndef _SCI_CONTROLLER_CONSTANTS_H_
+#define _SCI_CONTROLLER_CONSTANTS_H_
+
+/**
+ * @file
+ *
+ * @brief 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 __cplusplus
+extern "C" {
+#endif // __cplusplus
+
+#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_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 PCI devices that can be supported
+ * by the driver.
+ */
+#define SCI_MAX_PCI_DEVICES (2)
+
+/**
+ * This constant defines the maximum number of controllers that can
+ * occur in a single silicon package.
+ */
+#define SCI_MAX_CONTROLLERS_PER_PCI_DEVICE (2)
+
+/**
+ * This constant defines the maximum number of controllers that can
+ * be supported by a library object. The user specified maximum controller
+ * count must be less than or equal to this number. This is a driver
+ * specific constant that is not tied to silicon capabilities.
+ */
+#if !defined(SCI_MAX_CONTROLLERS)
+#define SCI_MAX_CONTROLLERS (2)
+#endif
+
+#ifndef SCI_MAX_MSIX_MESSAGES_PER_CONTROLLER
+/**
+ * This constant defines the maximum number of MSI-X interrupt vectors/messages
+ * supported for an SCU hardware controller instance.
+ */
+#define SCI_MAX_MSIX_MESSAGES_PER_CONTROLLER (2)
+#endif
+
+/**
+ * This constant defines the maximum number of MSI-X interrupt vectors/messages
+ * supported for an SCU device.
+ */
+#define SCI_MAX_MSIX_MESSAGES \
+ (SCI_MAX_MSIX_MESSAGES_PER_CONTROLLER * SCI_MAX_CONTROLLERS)
+
+/**
+ * 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
+
+#ifdef __cplusplus
+}
+#endif // __cplusplus
+
+#endif // _SCI_CONTROLLER_CONSTANTS_H_
+
diff --git a/sys/dev/isci/scil/sci_fast_list.h b/sys/dev/isci/scil/sci_fast_list.h
new file mode 100644
index 0000000..a7f166d
--- /dev/null
+++ b/sys/dev/isci/scil/sci_fast_list.h
@@ -0,0 +1,339 @@
+/*-
+ * 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.
+ *
+ * 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.
+ *
+ * $FreeBSD$
+ */
+#ifndef _SCI_FAST_LIST_HEADER_
+#define _SCI_FAST_LIST_HEADER_
+
+/**
+ * @file
+ *
+ * @brief Header file that contains basic Linked List manipulation macros.
+ * These macros implement a double linked list (SCI_FAST_LIST_T) that is
+ * circular in nature. This means that the next and prev pointers for
+ * an empty queue head always the address of the queue head
+ * SCI_FAST_LIST_T. Likewise an element that has been removed from
+ * a queue will have its next and prev pointer set to the address of
+ * the SCI_FAST_LIST_T found in the structure just removed from the
+ * queue. Pointers in this implementation never == NULL.
+ *
+ * Definitions:
+ * - anchor : This is ths list container and has a
+ * pointer to both the head and tail of the
+ * list elements
+ * - element: This is the list element not the actual
+ * object but the list element which has a
+ * pointer to the object.
+ */
+
+//******************************************************************************
+//*
+//* P U B L I C M E T H O D S
+//*
+//******************************************************************************
+
+/**
+ * Initialize the double linked list anchor. The other macros require the list
+ * anchor to be set up using this macro.
+ */
+#define sci_fast_list_init(anchor) \
+{ \
+ (anchor)->list_head = NULL; \
+ (anchor)->list_tail = NULL; \
+ (anchor)->element_count = 0; \
+}
+
+/**
+ * Initialize the sci_fast_list_element to point to its owning object
+ */
+#define sci_fast_list_element_init(list_object, element) \
+{ \
+ (element)->object = (list_object); \
+ (element)->next = (element)->prev = NULL; \
+ (element)->owning_list = NULL; \
+}
+
+/**
+ * See if there is anything on the list by checking the list anchor.
+ */
+#define sci_fast_list_is_empty(anchor) ((anchor)->list_head == NULL)
+
+/**
+ * Return a pointer to the element at the head of the sci_fast_list. The
+ * item is NOT removed from the list.
+ *
+ * NOTE: This macro will always return a value, even if the list is empty.
+ * You must insure the list is not empty or use Dlist_safeGetHead.
+ *
+ * element - A pointer into which to save the address of the structure
+ * containing the SCI_FAST_LIST at the list head.
+ */
+#define sci_fast_list_get_head(anchor) \
+ ((anchor)->list_head == NULL ? NULL: (anchor)->list_head->object)
+
+/**
+ * Return a pointer to the element at the tail of the sci_fast_list. The item
+ * is NOT removed from the list.
+ *
+ * NOTE: This macro will always return a value, even if the list is empty.
+ * You must insure the list is not empty or use Dlist_safeGetHead.
+ *
+ * element - A pointer into which to save the address of the structure
+ * containing the SCI_FAST_LIST at the list head.
+ */
+#define sci_fast_list_get_tail(anchor) \
+ ((anchor)->list_tail == NULL ? NULL: (anchor)->list_head->object)
+
+/**
+ * This method will get the next dListField in the SCI_FAST_LIST. This method
+ * returns a pointer to a SCI_FAST_LIST object.
+ */
+#define sci_fast_list_get_next(element) ((element)->next)
+
+/**
+ * This method will get the prev dListField in the SCI_FAST_LIST. This method
+ * returns a pointer to a SCI_FAST_LIST object.
+ */
+#define sci_fast_list_get_prev(element) ((element)->prev)
+
+
+/**
+ * This method returns the object that is represented by this
+ * sci_fast_list_element
+ */
+#define sci_fast_list_get_object(element) ((element)->object)
+
+/**
+ * This method will determine if the supplied dListField is on a SCI_FAST_LIST.
+ * If the element has only one dListField but can be on more than one list,
+ * this will only tell you that it is on one of them. If the element has
+ * multiple dListFields and can exist on multiple lists at the same time, this
+ * macro can tell you exactly which list it is on.
+ */
+#define sci_fast_list_is_on_a_list(element) ((element)->owning_list != NULL)
+
+/**
+ * This method will determine if the supplied dListFieldName is on the given
+ * specified list? If the element can be on more than one list, this
+ * allows you to determine exactly which list it is on. Performs a linear
+ * search through the list.
+ * result - BOOL_T that will contain the result of the search.
+ * TRUE - item is on the list described by head.
+ * FALSE - item is not on the list.
+ */
+#define sci_fast_list_is_on_this_list(anchor, element) \
+ ((element)->owning_list == (anchor))
+
+//******************************************************************************
+//*
+//* T Y P E S
+//*
+//******************************************************************************
+
+/**
+ * @struct SCI_FAST_LIST
+ *
+ * @brief the list owner or list anchor for a set of SCI_FAST_LIST
+ * elements.
+ */
+typedef struct SCI_FAST_LIST
+{
+ struct SCI_FAST_LIST_ELEMENT *list_head;
+ struct SCI_FAST_LIST_ELEMENT *list_tail;
+ int element_count;
+} SCI_FAST_LIST_T;
+
+/**
+ * @struct SCI_FAST_LIST_ELEMENT
+ *
+ * @brief This structure defines what a doubly linked list element contains.
+ */
+typedef struct SCI_FAST_LIST_ELEMENT
+{
+ struct SCI_FAST_LIST_ELEMENT *next;
+ struct SCI_FAST_LIST_ELEMENT *prev;
+ struct SCI_FAST_LIST *owning_list;
+ void *object;
+} SCI_FAST_LIST_ELEMENT_T;
+
+
+/**
+ * Insert an element to be the new head of the list hanging off of the list
+ * anchor. An empty list has the list anchor pointing to itself.
+ * dListAnchor - The name of the SCI_FAST_LIST_T element that is the anchor
+ * of the queue.
+ * dListFieldBeingInserted - The SCI_FAST_LIST_T field in the data structure
+ * being queued. This SCI_FAST_LIST will become
+ * the new list head.
+ */
+INLINE
+static void sci_fast_list_insert_head(
+ SCI_FAST_LIST_T *anchor,
+ SCI_FAST_LIST_ELEMENT_T *element
+)
+{
+ element->owning_list = anchor;
+ element->prev = NULL;
+ if ( anchor->list_head == NULL )
+ anchor->list_tail = element;
+ else
+ anchor->list_head->prev = element;
+ element->next = anchor->list_head;
+ anchor->list_head = element;
+ anchor->element_count++;
+}
+
+/**
+ * Insert an element at the tail of the list. Since the list is circular we
+ * can add the element at the tail through use the list anchors previous
+ * pointer.
+ * dListAnchor - The name of the SCI_FAST_LIST_T element that is the anchor
+ * of the queue.
+ * dListFieldBeingInserted - The SCI_FAST_LIST_T field in the data structure
+ * being queued. This SCI_FAST_LIST will become
+ * the new list head.
+ */
+INLINE
+static void sci_fast_list_insert_tail(
+ SCI_FAST_LIST_T *anchor,
+ SCI_FAST_LIST_ELEMENT_T *element
+)
+{
+ element->owning_list = anchor;
+ element->next = NULL;
+ if ( anchor->list_tail == NULL ) {
+ anchor->list_head = element;
+ } else {
+ anchor->list_tail->next = element;
+ }
+ element->prev = anchor->list_tail;
+ anchor->list_tail = element;
+ anchor->element_count++;
+}
+
+/**
+ * This method will remove a dListFieldName from the head of the list.
+ *
+ * NOTE: This macro will always return a value, even if the list is empty.
+ * You must insure the list is not empty or use Dlist_safeRemoveHead.
+ *
+ * element - A pointer into which to save the address of the structure
+ * containing the SCI_FAST_LIST at the list head.
+ */
+INLINE
+static void *sci_fast_list_remove_head(
+ SCI_FAST_LIST_T *anchor
+)
+{
+ void *object = NULL;
+ SCI_FAST_LIST_ELEMENT_T *element;
+ if ( anchor->list_head != NULL )
+ {
+ element = anchor->list_head;
+ object = anchor->list_head->object;
+ anchor->list_head = anchor->list_head->next;
+ if ( anchor->list_head == NULL )
+ {
+ anchor->list_tail = NULL;
+ }
+ anchor->element_count--;
+ element->next = element->prev = NULL;
+ element->owning_list = NULL;
+ }
+ return object;
+}
+
+INLINE
+static void *sci_fast_list_remove_tail(
+ SCI_FAST_LIST_T *anchor
+)
+{
+ void *object = NULL;
+ SCI_FAST_LIST_ELEMENT_T *element;
+ if ( anchor->list_tail != NULL )
+ {
+ element = anchor->list_tail;
+ object = element->object;
+ anchor->list_tail = element->prev;
+ if ( anchor->list_tail == NULL )
+ anchor->list_head = NULL;
+ anchor->element_count--;
+ element->next = element->prev = NULL;
+ element->owning_list = NULL;
+ }
+ return object;
+}
+
+/**
+ * Remove an element from anywhere in the list referenced by name.
+ */
+INLINE
+static void sci_fast_list_remove_element(
+ SCI_FAST_LIST_ELEMENT_T *element
+)
+{
+ if ( element->next == NULL )
+ element->owning_list->list_tail = element->prev;
+ else
+ element->next->prev = element->prev;
+
+ if ( element->prev == NULL )
+ element->owning_list->list_head = element->next;
+ else
+ element->prev->next = element->next;
+
+ element->owning_list->element_count--;
+ element->next = element->prev = NULL;
+ element->owning_list = NULL;
+}
+
+#endif // _SCI_FAST_LIST_HEADER_
diff --git a/sys/dev/isci/scil/sci_iterator.h b/sys/dev/isci/scil/sci_iterator.h
new file mode 100644
index 0000000..fd5cab2
--- /dev/null
+++ b/sys/dev/isci/scil/sci_iterator.h
@@ -0,0 +1,129 @@
+/*-
+ * 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.
+ *
+ * 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.
+ *
+ * $FreeBSD$
+ */
+/**
+ * @file
+ *
+ * @brief This file contains the interface to the iterator class.
+ * Methods Provided:
+ * - sci_iterator_get_object_size()
+ * - sci_iterator_get_current()
+ * - sci_iterator_first()
+ * - sci_iterator_next()
+ */
+
+#ifndef _SCI_ITERATOR_H_
+#define _SCI_ITERATOR_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif // __cplusplus
+
+#if !defined(DISABLE_SCI_ITERATORS)
+
+//******************************************************************************
+//*
+//* I N C L U D E S
+//*
+//******************************************************************************
+
+#include <dev/isci/scil/sci_types.h>
+
+//******************************************************************************
+//*
+//* C O N S T A N T S
+//*
+//******************************************************************************
+
+//******************************************************************************
+//*
+//* T Y P E S
+//*
+//******************************************************************************
+
+//******************************************************************************
+//*
+//* P U B L I C M E T H O D S
+//*
+//******************************************************************************
+
+U32 sci_iterator_get_object_size(
+ void
+);
+
+void * sci_iterator_get_current(
+ SCI_ITERATOR_HANDLE_T iterator_handle
+);
+
+void sci_iterator_first(
+ SCI_ITERATOR_HANDLE_T iterator_handle
+);
+
+void sci_iterator_next(
+ SCI_ITERATOR_HANDLE_T iterator_handle
+);
+
+#else // !defined(DISABLE_SCI_ITERATORS)
+
+#define sci_iterator_get_object_size() 0
+#define sci_iterator_get_current(the_iterator) NULL
+#define sci_iterator_first(the_iterator)
+#define sci_iterator_next(the_iterator)
+
+#endif // !defined(DISABLE_SCI_ITERATORS)
+
+#ifdef __cplusplus
+}
+#endif // __cplusplus
+
+#endif // _ITERATOR_H_
diff --git a/sys/dev/isci/scil/sci_library.h b/sys/dev/isci/scil/sci_library.h
new file mode 100644
index 0000000..6dea219
--- /dev/null
+++ b/sys/dev/isci/scil/sci_library.h
@@ -0,0 +1,111 @@
+/*-
+ * 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.
+ *
+ * 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.
+ *
+ * $FreeBSD$
+ */
+#ifndef _SCI_LIBRARY_H_
+#define _SCI_LIBRARY_H_
+
+/**
+ * @file
+ *
+ * @brief This file contains all of the interface methods that can be called
+ * by an SCI user on a library object. The library is the container
+ * of all other objects being managed (i.e. controllers, target devices,
+ * sas ports, etc.).
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif // __cplusplus
+
+#include <dev/isci/scil/sci_types.h>
+
+
+/**
+ * @brief This method will return the major revision level for the entire
+ * SCI library.
+ * @note Format: Major.Minor.Build.
+ *
+ * @return Return an integer value indicating the major revision level.
+ */
+U32 sci_library_get_major_version(
+ void
+);
+
+/**
+ * @brief This method will return the minor revision level for the entire
+ * SCI library.
+ * @note Format: Major.Minor.Build.
+ *
+ * @return Return an integer value indicating the minor revision level.
+ */
+U32 sci_library_get_minor_version(
+ void
+);
+
+/**
+ * @brief This method will return the build revision level for the entire
+ * SCI library.
+ * @note Format: Major.Minor.Build.
+ *
+ * @return Return an integer value indicating the build revision level.
+ */
+U32 sci_library_get_build_version(
+ void
+);
+
+#ifdef __cplusplus
+}
+#endif // __cplusplus
+
+#endif // _SCI_LIBRARY_H_
+
diff --git a/sys/dev/isci/scil/sci_logger.h b/sys/dev/isci/scil/sci_logger.h
new file mode 100644
index 0000000..e980812
--- /dev/null
+++ b/sys/dev/isci/scil/sci_logger.h
@@ -0,0 +1,250 @@
+/*-
+ * 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.
+ *
+ * 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.
+ *
+ * $FreeBSD$
+ */
+#ifndef _SCI_LOGGER_H_
+#define _SCI_LOGGER_H_
+
+/**
+ * @file
+ *
+ * @brief This file contains all of the interface methods that can be called
+ * by an SCI user on the logger object. These methods should be
+ * utilized to control the amount of information being logged by the
+ * SCI implementation.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif // __cplusplus
+
+#include <dev/isci/scil/sci_types.h>
+
+
+/* The following is a list of verbosity levels that can be used to enable */
+/* logging for specific log objects. */
+
+/** Enable/disable error level logging for the associated logger object(s). */
+#define SCI_LOG_VERBOSITY_ERROR 0x00
+
+/** Enable/disable warning level logging for the associated logger object(s). */
+#define SCI_LOG_VERBOSITY_WARNING 0x01
+
+/**
+ * Enable/disable informative level logging for the associated logger object(s).
+ */
+#define SCI_LOG_VERBOSITY_INFO 0x02
+
+/**
+ * This constant is used to enable function trace (enter/exit) level
+ * logging for the associated log object(s).
+ */
+#define SCI_LOG_VERBOSITY_TRACE 0x03
+
+/**
+ * This constant is used to enable state tracing information it will emit a
+ * log message each time a state is entered for the associated log object(s).
+ */
+#define SCI_LOG_VERBOSITY_STATES 0x04
+
+#ifdef SCI_LOGGING
+
+/**
+ * @brief This method will return the verbosity levels enabled for the object
+ * listed in the log_object parameter.
+ * @note Logging must be enabled at compile time in the driver, otherwise
+ * calling this method has no affect.
+ *
+ * @param[in] logger This parameter specifies the logger for which to
+ * disable the supplied objects/verbosities. For example,
+ * the framework and core components have different loggers.
+ * @param[in] log_object This parameter specifies the log object for which
+ * to retrieve the associated verbosity levels.
+ * @note This parameter is not a mask, but rather a discrete
+ * value.
+ *
+ * @return This method will return the verbosity levels enabled for the
+ * supplied log object.
+ * @retval SCI_LOGGER_VERBOSITY_ERROR This value indicates that the error
+ * verbosity level was set for the supplied log_object.
+ * @retval SCI_LOGGER_VERBOSITY_WARNING This value indicates that the warning
+ * verbosity level was set for the supplied log_object.
+ * @retval SCI_LOGGER_VERBOSITY_INFO This value indicates that the
+ * informational verbosity level was set for the supplied log_object.
+ * @retval SCI_LOGGER_VERBOSITY_TRACE This value indicates that the trace
+ * verbosity level was set for the supplied log_object.
+ * @retval SCI_LOGGER_VERBOSITY_STATES This value indicates that the states
+ * transition verbosity level was set for the supplied log_object
+ */
+U8 sci_logger_get_verbosity_mask(
+ SCI_LOGGER_HANDLE_T logger,
+ U32 log_object
+);
+
+/**
+ * @brief This method simply returns the log object mask. This mask
+ * is essentially a list of log objects for which the specified
+ * level (verbosity) is enabled.
+ * @note Logging must be enabled at compile time in the driver, otherwise
+ * calling this method has no affect.
+ * @note Reserved bits in both the supplied masks shall be ignored.
+ *
+ * @param[in] logger This parameter specifies the logger for which to
+ * disable the supplied objects/verbosities. For example,
+ * the framework and core components have different loggers.
+ * @param[in] verbosity This parameter specifies the verbosity for which
+ * to retrieve the set of enabled log objects. Valid values for
+ * this parameter are:
+ * -# SCI_LOGGER_VERBOSITY_ERROR
+ * -# SCI_LOGGER_VERBOSITY_WARNING
+ * -# SCI_LOGGER_VERBOSITY_INFO
+ * -# SCI_LOGGER_VERBOSITY_TRACE
+ * -# SCI_LOGGER_VERBOSITY_STATES
+ * @note This parameter is not a mask, but rather a discrete
+ * value.
+ *
+ * @return This method will return the log object mask indicating each of
+ * the log objects for which logging is enabled at the supplied level.
+ */
+U32 sci_logger_get_object_mask(
+ SCI_LOGGER_HANDLE_T logger,
+ U8 verbosity
+);
+
+/**
+ * @brief This method will enable each of the supplied log objects in
+ * log_object_mask for each of the supplied verbosities in
+ * verbosity_mask. To enable all logging, simply set all bits in
+ * both the log_object_mask and verbosity_mask.
+ * @note Logging must be enabled at compile time in the driver, otherwise
+ * calling this method has no affect.
+ * @note Reserved bits in both the supplied masks shall be ignored.
+ *
+ * @param[in] logger This parameter specifies the logger for which to
+ * disable the supplied objects/verbosities. For example,
+ * the framework and core components have different loggers.
+ * @param[in] log_object_mask This parameter specifies the log objects for
+ * which to enable logging.
+ * @param[in] verbosity_mask This parameter specifies the verbosity levels
+ * at which to enable each log_object.
+ *
+ * @return none
+ */
+void sci_logger_enable(
+ SCI_LOGGER_HANDLE_T logger,
+ U32 log_object_mask,
+ U8 verbosity_mask
+);
+
+/**
+ * @brief This method will disable each of the supplied log objects in
+ * log_object_mask for each of the supplied verbosities in
+ * verbosity_mask. To disable all logging, simply set all bits in
+ * both the log_object_mask and verbosity_mask.
+ * @note Logging must be enabled at compile time in the driver, otherwise
+ * calling this method has no affect.
+ * @note Reserved bits in both the supplied masks shall be ignored.
+ *
+ * @param[in] logger This parameter specifies the logger for which to
+ * disable the supplied objects/verbosities. For example,
+ * the framework and core components have different loggers.
+ * @param[in] log_object_mask This parameter specifies the log objects for
+ * which to disable logging.
+ * @param[in] verbosity_mask This parameter specifies the verbosity levels
+ * at which to disable each log_object.
+ *
+ * @return none
+ */
+void sci_logger_disable(
+ SCI_LOGGER_HANDLE_T logger,
+ U32 log_object_mask,
+ U8 verbosity_mask
+);
+
+
+/**
+ * @brief this macro checks whether it is ok to log.
+ *
+ * @param[in] logger This parameter specifies the logger for
+ * which to disable the supplied
+ * objects/verbosities. For example, the framework
+ * and core components have different loggers.
+ * @param[in] log_object_mask This parameter specifies the log objects for
+ * which to disable logging.
+ * @param[in] verbosity_mask This parameter specifies the verbosity levels
+ * at which to disable each log_object.
+ *
+ * @return TRUE or FALSE
+ */
+BOOL sci_logger_is_enabled(
+ SCI_LOGGER_HANDLE_T logger,
+ U32 log_object_mask,
+ U8 verbosity_mask
+);
+
+
+#else // SCI_LOGGING
+
+#define sci_logger_get_verbosity_mask(logger, log_object)
+#define sci_logger_get_object_mask(logger, verbosity)
+#define sci_logger_enable(logger, log_object_mask, verbosity_mask)
+#define sci_logger_disable(logger, log_object_mask, verbosity_mask)
+#define sci_logger_is_enabled(logger, log_object_mask, verbosity_level)
+
+#endif // SCI_LOGGING
+
+#ifdef __cplusplus
+}
+#endif // __cplusplus
+
+#endif // _SCI_LOGGER_H_
+
diff --git a/sys/dev/isci/scil/sci_memory_descriptor_list.h b/sys/dev/isci/scil/sci_memory_descriptor_list.h
new file mode 100644
index 0000000..3912ceb
--- /dev/null
+++ b/sys/dev/isci/scil/sci_memory_descriptor_list.h
@@ -0,0 +1,181 @@
+/*-
+ * 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.
+ *
+ * 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.
+ *
+ * $FreeBSD$
+ */
+#ifndef _SCI_MEMORY_DESCRIPTOR_LIST_H_
+#define _SCI_MEMORY_DESCRIPTOR_LIST_H_
+
+/**
+ * @file
+ *
+ * @brief This file contains all of the basic data types utilized by an
+ * SCI user or implementor.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif // __cplusplus
+
+#include <dev/isci/scil/sci_types.h>
+
+/**
+ * @name 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
+ * @brief This structure defines a description of a memory location for
+ * the SCI implementation.
+ */
+typedef 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()
+ */
+ SCI_PHYSICAL_ADDRESS 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_PHYSICAL_MEMORY_DESCRIPTOR_T;
+
+/**
+ * @brief This method simply rewinds the MDL iterator back to the first memory
+ * descriptor entry in the list.
+ *
+ * @param[in] mdl This parameter specifies the memory descriptor list that
+ * is to be rewound.
+ *
+ * @return none
+ */
+void sci_mdl_first_entry(
+ SCI_MEMORY_DESCRIPTOR_LIST_HANDLE_T mdl
+);
+
+/**
+ * @brief This method simply updates the "current" pointer to the next
+ * sequential memory descriptor.
+ *
+ * @param[in] mdl This parameter specifies the memory descriptor list for
+ * which to return the next memory descriptor entry in the list.
+ *
+ * @return none.
+ */
+void sci_mdl_next_entry(
+ SCI_MEMORY_DESCRIPTOR_LIST_HANDLE_T mdl
+);
+
+/**
+ * @brief This method simply returns the current memory descriptor entry.
+ *
+ * @param[in] mdl This parameter specifies the memory descriptor list for
+ * which to return the current memory descriptor entry.
+ *
+ * @return This method returns a pointer to the current physical memory
+ * descriptor in the MDL.
+ * @retval NULL This value is returned if there are no descriptors in the
+ * list.
+ */
+SCI_PHYSICAL_MEMORY_DESCRIPTOR_T * sci_mdl_get_current_entry(
+ SCI_MEMORY_DESCRIPTOR_LIST_HANDLE_T mdl
+);
+
+#ifdef __cplusplus
+}
+#endif // __cplusplus
+
+#endif // _SCI_MEMORY_DESCRIPTOR_LIST_H_
+
diff --git a/sys/dev/isci/scil/sci_memory_descriptor_list_decorator.h b/sys/dev/isci/scil/sci_memory_descriptor_list_decorator.h
new file mode 100644
index 0000000..42f4db1
--- /dev/null
+++ b/sys/dev/isci/scil/sci_memory_descriptor_list_decorator.h
@@ -0,0 +1,129 @@
+/*-
+ * 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.
+ *
+ * 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.
+ *
+ * $FreeBSD$
+ */
+#ifndef _SCI_MEMORY_DESCRIPTOR_LIST_DECORATOR_H_
+#define _SCI_MEMORY_DESCRIPTOR_LIST_DECORATOR_H_
+
+/**
+ * @file
+ *
+ * @brief This file contains methods utilized to provide additional
+ * functionality above normal MDL processing.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif // __cplusplus
+
+#include <dev/isci/scil/sci_memory_descriptor_list.h>
+
+/**
+ * @brief This method will determine the amount of memory needed for
+ * memory descriptors with exact matching memory attributes.
+ * If the supplied attributes value is 0, then all MDEs are
+ * included in the calculation.
+ *
+ * @param[in] mdl This parameter specifies the MDL to search through
+ * for MDEs with matching memory attributes.
+ * @param[in] attributes This parameter specifies the attributes to
+ * match. If this parameter is set to 0, then each MDE
+ * is included in the calculation.
+ *
+ * @return This method returns the number of bytes, including offsets
+ * to achieve proper alignment, for memory descriptors that
+ * exactly match the supplied memory attributes.
+ */
+U32 sci_mdl_decorator_get_memory_size(
+ SCI_MEMORY_DESCRIPTOR_LIST_HANDLE_T mdl,
+ U32 attributes
+);
+
+/**
+ * @brief This method will assign the supplied memory address values
+ * to all of the MDEs in the memory descriptor list with
+ * exact matching attributes as those supplied by parameter.
+ * If the supplied attributes value is 0, then all MDEs will
+ * have their values assigned.
+ *
+ * @warning It is suggested the user invoke the
+ * sci_mdl_decorator_get_memory_size() method prior to invoking
+ * this method. This ensures that the user supplies pointers
+ * that refer to memory locations with sufficient space.
+ *
+ * @param[in,out] mdl This parameter specifies the MDL to iterate through
+ * for MDEs with matching memory attributes.
+ * @param[in] attributes This parameter specifies the attributes to
+ * match. If this parameter is set to 0, then each
+ * memory descriptor will be filled out.
+ * @param[in] virtual_address This parameter specifies the starting
+ * virtual address to be used when filling out the MDE
+ * virtual address field.
+ * @param[in] sci_physical_address This parameter specifies the starting
+ * physical address to be used when filling out the MDE
+ * physical address field.
+ *
+ * @return none
+ */
+void sci_mdl_decorator_assign_memory(
+ SCI_MEMORY_DESCRIPTOR_LIST_HANDLE_T mdl,
+ U32 attributes,
+ POINTER_UINT virtual_address,
+ SCI_PHYSICAL_ADDRESS sci_physical_address
+);
+
+#ifdef __cplusplus
+}
+#endif // __cplusplus
+
+#endif // _SCI_MEMORY_DESCRIPTOR_LIST_DECORATOR_H_
+
diff --git a/sys/dev/isci/scil/sci_object.h b/sys/dev/isci/scil/sci_object.h
new file mode 100644
index 0000000..e88e44b
--- /dev/null
+++ b/sys/dev/isci/scil/sci_object.h
@@ -0,0 +1,139 @@
+/*-
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 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.
+ *
+ * $FreeBSD$
+ */
+#ifndef _SCI_OBJECT_H_
+#define _SCI_OBJECT_H_
+
+/**
+ * @file
+ *
+ * @brief 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.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif // __cplusplus
+
+#include <dev/isci/scil/sci_types.h>
+#include <dev/isci/scil/sci_status.h>
+
+/**
+ * @brief This method returns the object to which a previous association was
+ * created. This association represents a link between an SCI object
+ * and another SCI object or potentially a user object. The
+ * association essentially acts as a cookie for the user of an object.
+ * The user of an SCI object is now able to retrieve a handle to their
+ * own object that is managing, or related in someway, to said SCI
+ * object.
+ *
+ * @param[in] base_object This parameter specifies the SCI object for
+ * which to retrieve the association reference.
+ *
+ * @return This method returns a pointer to the object that was previously
+ * associated to the supplied base_object parameter.
+ * @retval SCI_INVALID_HANDLE This value is returned when there is no known
+ * association for the supplied base_object instance.
+ */
+#if defined(SCI_OBJECT_USE_ASSOCIATION_FUNCTIONS)
+void * sci_object_get_association(
+ SCI_OBJECT_HANDLE_T base_object
+);
+#else
+#define sci_object_get_association(object) (*((void **)object))
+#endif
+
+/**
+ * @brief This method will associate to SCI objects.
+ *
+ * @see For more information about associations please reference the
+ * sci_object_get_association() method.
+ *
+ * @param[in] base_object This parameter specifies the SCI object for
+ * which to set the association reference.
+ * @param[in] associated_object This parameter specifies a pointer to the
+ * object being associated.
+ *
+ * @return This method will return an indication as to whether the
+ * association was set successfully.
+ * @retval SCI_SUCCESS This value is currently always returned.
+ */
+#if defined(SCI_OBJECT_USE_ASSOCIATION_FUNCTIONS)
+SCI_STATUS sci_object_set_association(
+ SCI_OBJECT_HANDLE_T base_object,
+ void * associated_object
+);
+#else
+#define sci_object_set_association(base_object, associated_object) \
+ ((*((void **)base_object)) = (associated_object))
+#endif
+
+/**
+ * @brief This method will get the logger for an object.
+ *
+ * @param[in] object This parameter specifies SCI object for
+ * which to retrieve its logger.
+ *
+ * @return This method returns a SCI_LOGGER_HANDLE to SCI user.
+ */
+SCI_LOGGER_HANDLE_T sci_object_get_logger(
+ SCI_OBJECT_HANDLE_T object
+);
+
+#ifdef __cplusplus
+}
+#endif // __cplusplus
+
+#endif // _SCI_OBJECT_H_
+
diff --git a/sys/dev/isci/scil/sci_overview.h b/sys/dev/isci/scil/sci_overview.h
new file mode 100644
index 0000000..fadea72
--- /dev/null
+++ b/sys/dev/isci/scil/sci_overview.h
@@ -0,0 +1,251 @@
+/*-
+ * 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.
+ *
+ * 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.
+ *
+ * $FreeBSD$
+ */
+#ifndef _SCI_OVERVIEW_H_
+#define _SCI_OVERVIEW_H_
+
+/**
+@mainpage The Intel Storage Controller Interface (SCI)
+
+SCI provides a common interface across intel storage controller hardware.
+This includes abstracting differences between Physical PCI functions and
+Virtual PCI functions. The SCI is comprised of four primary components:
+-# SCI Base classes
+-# SCI Core
+-# SCI Framework
+
+It is important to recognize that no component, object, or functionality in
+SCI directly allocates memory from the operating system. It is expected that
+the SCI User (OS specific driver code) allocates and frees all memory from
+and to the operating system itself.
+
+The C language is utilized to implement SCI. Although C is not an object
+oriented language the SCI driver components, methods, and structures are
+modeled and organized following object oriented principles.
+
+The Unified Modeling Language is utilized to present graphical depictions
+of the SCI classes and their relationships.
+
+The following figure denotes the meanings of the colors utilized in UML
+diagrams throughout this document.
+@image latex object_color_key.eps "Object Color Legend" width=8cm
+
+The following figure denotes the meanings for input and output arrows that
+are utilized to define parameters for methods defined in this specification.
+@image latex arrow_image.eps "Method Parameter Symbol Definition"
+
+@page abbreviations_section Abbreviations
+
+- ATA: Advanced Technology Attachment
+- IAF: Identify Address Frame
+- SAS: Serial Attached SCSI
+- SAT: SCSI to ATA Translation
+- SATA: Serial ATA
+- SCI: Storage Controller Interface
+- SCIC: SCI Core
+- SCIF: SCI Framework
+- SCU: Storage Controller Unit
+- SDS: SCU Driver Standard (i.e. non-virtualization)
+- SDV: SCU Driver Virtualized
+- SDVP: SDV Physical (PCI function)
+- SDVV: SDV Virtual (PCI function)
+- SGE: Scatter-Gather Element
+- SGL: Scatter-Gather List
+- SGPIO: Serial General Purpose Input/Output
+- SSC: Spread Spectrum Clocking
+
+@page definitions_section Definitions
+
+- <b>construct</b> - The term "construct" is utilized throughout the
+ interface to indicate when an object is being created. Typically construct
+ methods perform pure memory initialization. No "construct" method ever
+ performs memory allocation. It is incumbent upon the SCI user to provide
+ the necessary memory.
+- <b>initialize</b> - The term "initialize" is utilized throughout the
+ interface to indicate when an object is performing actions on other objects
+ or on physical resources in an attempt to allow these resources to become
+ operational.
+- <b>protected</b> - The term "protected" is utilized to denote a method
+ defined in this standard that MUST NOT be invoked directly by operating
+ system specific driver code.
+- <b>SCI Component</b> - An SCI component is one of: SCI base classes, Core,
+ or Framework.
+- <b>SCI User</b> - The user callbacks for each SCI Component represent the
+ dependencies that the SCI component implementation has upon the operating
+ system/environment specific portion of the driver. It is essentially a
+ set of functions or macro definitions that are specific to a particular
+ operating system.
+- <b>THIN</b> - A term utilized to describe an SCI Component implementation
+ that is built to conserve memory.
+
+@page inheritance SCI Inheritance Hierarchy
+
+This section describes the inheritance (i.e. "is-a") relationships between
+the various objects in SCI. Due to various operating environment requirements
+the programming language employed for the SCI driver is C. As a result, one
+might be curious how inheritance shall be applied in such an environment.
+The SCI driver source shall maintain generalization relationships by ensuring
+that child object structures shall contain an instance of their parent's
+structure as the very first member of their structure. As a result, parent
+object methods can be invoked with a child structure parameter. This works
+since casting of the child structure to the parent structure inside the parent
+method will yield correct access to the parent structure fields.
+
+Consider the following example:
+<pre>
+typedef struct SCI_OBJECT
+{
+ U32 object_type;
+};
+
+typedef struct SCI_CONTROLLER
+{
+ U32 state;
+
+} SCI_CONTROLLER_T;
+
+typedef struct SCIC_CONTROLLER
+{
+ SCI_CONTROLLER_T parent;
+ U32 type;
+
+} SCIC_CONTROLLER_T;
+</pre>
+
+With the above structure orientation, a user would be allowed to perform
+method invocations in a manner similar to the following:
+<pre>
+SCIC_CONTROLLER_T scic_controller;
+scic_controller_initialize((SCIC_CONTROLLER_T*) &scic_controller);
+
+// OR
+
+sci_object_get_association(&scic_controller);
+</pre>
+@note The actual interface will not require type casting.
+
+The following diagram graphically depicts the inheritance relationships
+between the various objects defined in the Storage Controller Interface.
+@image latex inheritance.eps "SCI Inheritance Hierarchy" width=16cm
+
+@page sci_classes SCI Classes
+
+This section depicts the common classes and utility functions across the
+entire set of SCI Components. Descriptions about each of the specific
+objects will be found in the header file definition in the File Documentation
+section.
+
+The following is a list of features that can be found in the SCI base classes:
+-# Logging utility methods, constants, and type definitions
+-# Memory Descriptor object methods common to the core and framework.
+-# Controller object methods common to SCI derived controller objects.
+-# Library object methods common to SCI derived library objects.
+-# Storage standard (e.g. SAS, SATA) defined constants, structures, etc.
+-# Standard types utilized by SCI sub-components.
+-# The ability to associate/link SCI objects together or to user objects.
+
+SCI class methods can be overridden by sub-classes in the SCI Core,
+SCI Framework, etc. SCI class methods that MUST NOT be invoked directly
+by operating system specific driver code shall be adorned with a
+<code>[protected]</code> keyword. These <code>[protected]</code> API are still
+defined as part of the specification in order to demonstrate commonality across
+components as well as provide a common description of related methods. If
+these methods are invoked directly by operating system specific code, the
+operation of the driver as a whole is not specified or supported.
+
+The following UML diagram graphically depicts the SCI base classes and their
+relationships to one another.
+@image latex sci_base_classes.eps "SCI Classes" width=4cm
+
+@page associations_section Associations
+The sci_object class provides functionality common to all SCI objects.
+An important feature provided by this base class is the means by which to
+associate one object to another. An SCI object can be made to have an
+association to another SCI object. Additionally, an SCI object can be
+made to have an association to a non-SCI based object. For example, an SCI
+Framework library can have it's association set to an operating system
+specific adapter/device driver structre.
+
+Simply put, the association that an object has is a handle (i.e. a void pointer)
+to a user structure. This enables the user of the SCI object to
+easily determine it's own associated structure. This association is useful
+because the user is now enabled to easily determine their pertinent information
+inside of their SCI user callback methods.
+
+Setting an association within an SCI object is generally optional. The
+primary case in which an association is not optional is in the case of IO
+request objects. These associations are necessary in order to fill
+to fill in appropriate information for an IO request (i.e. CDB address, size,
+SGL information, etc.) in an efficient manner.
+
+In the case of other objects, the user is free to not create associations.
+When the user chooses not to create an association, the user is responsible for
+being able to determine their data structures based on the SCI object handles.
+Additionally, the user may be forced to invoke additional functionality in
+situations where the SCI Framework is employed. If the user does not
+establish proper associations between objects (i.e. SCIC Library to SCIF Library), then the framework is unable to automate interactions. Users should
+strongly consider establishing associations between SCI Framework objects and
+OS Driver related structures.
+
+Example Associations:
+- The user might set the scif_controller association to their adapter or
+controller object.
+- The user might set the scif_domain association to their SCSI bus object.
+
+If SCIF is being utilized, then the framework will set the associations
+in the core. In this situation, the user should only set the associations
+in the framework objects, unless otherwise directed.
+*/
+
+#endif // _SCI_OVERVIEW_H_
+
diff --git a/sys/dev/isci/scil/sci_pool.h b/sys/dev/isci/scil/sci_pool.h
new file mode 100644
index 0000000..2a4d45e
--- /dev/null
+++ b/sys/dev/isci/scil/sci_pool.h
@@ -0,0 +1,188 @@
+/*-
+ * 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.
+ *
+ * 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.
+ *
+ * $FreeBSD$
+ */
+/**
+ * @file
+ *
+ * @brief 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_
+
+#include <dev/isci/types.h>
+
+/**
+ * Private operation for the pool
+ */
+#define SCI_POOL_INCREMENT(this_pool, index) \
+ (((index) + 1) == (this_pool).size ? 0 : (index) + 1)
+
+/**
+ * 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
+
+
+/**
+ * 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)
+
+/**
+ * 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)
+
+/**
+ * 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)
+
+/**
+ * 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) \
+ ) \
+ ) \
+ )
+
+/**
+ * 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; \
+}
+
+/**
+ * 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); \
+}
+
+/**
+ * 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); \
+}
+
+/**
+ * This macro will search the pool and remove any elements in the pool
+ * matching the supplied value.
+ * @note 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/sys/dev/isci/scil/sci_simple_list.h b/sys/dev/isci/scil/sci_simple_list.h
new file mode 100644
index 0000000..98d29e1
--- /dev/null
+++ b/sys/dev/isci/scil/sci_simple_list.h
@@ -0,0 +1,350 @@
+/*-
+ * 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.
+ *
+ * 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.
+ *
+ * $FreeBSD$
+ */
+#ifndef _SCI_SIMPLE_LIST_HEADER_
+#define _SCI_SIMPLE_LIST_HEADER_
+
+/**
+ * @file
+ *
+ * @brief This header file contains simple linked list manipulation macros.
+ * These macros differ from the SCI_FAST_LIST in that deletion of
+ * an element from the list is O(n).
+ * The reason for using this implementation over the SCI_FAST_LIST
+ * is
+ * 1) space savings as there is only a single link element instead
+ * of the 2 link elements used in the SCI_FAST_LIST and
+ * 2) it is possible to detach the entire list from its anchor
+ * element for processing.
+ *
+ * @note Do not use the SCI_SIMPLE_LIST if you need to remove elements from
+ * random locations within the list use instead the SCI_FAST_LIST.
+ */
+
+
+//******************************************************************************
+//*
+//* P U B L I C M E T H O D S
+//*
+//******************************************************************************
+
+/**
+ * Initialize the singely linked list anchor. The other macros require the
+ * list anchor to be properly initialized.
+ */
+#define sci_simple_list_init(anchor) \
+{ \
+ (anchor)->list_head = NULL; \
+ (anchor)->list_tail = NULL; \
+ (anchor)->list_count = 0; \
+}
+
+/**
+ * Initialze the singely linked list element. The other macros require the
+ * list element to be properly initialized.
+ */
+#define sci_simple_list_element_init(list_object, element) \
+{ \
+ (element)->next = NULL; \
+ (element)->object = (list_object); \
+}
+
+/**
+ * See if there are any list elements on this list.
+ */
+#define sci_simple_list_is_empty(anchor) ((anchor)->list_head == NULL)
+
+/**
+ * Return a pointer to the list element at the head of the list. The list
+ * element is not removed from the list.
+ */
+#define sci_simple_list_get_head(anchor) ((anchor)->list_head)
+
+/**
+ * Retuen a pointer to the lsit element at the tail of the list. The list
+ * element is not removed from the list.
+ */
+#define sci_simple_list_get_tail(anchor) ((anchor)->list_tail)
+
+/**
+ * Return the count of the number of elements in this list.
+ */
+#define sci_simple_list_get_count(anchor) ((anchor)->list_count)
+
+/**
+ * Return a pointer to the list element following this list element.
+ * If this is the last element in the list then NULL is returned.
+ */
+#define sci_simple_list_get_next(element) ((element)->next)
+
+/**
+ * Return the object represented by the list element.
+ */
+#define sci_simple_list_get_object(element) ((element)->object)
+
+
+//******************************************************************************
+//*
+//* T Y P E S
+//*
+//******************************************************************************
+
+/**
+ * @struct
+ *
+ * @brief This structure defines the list owner for singely linked list.
+ */
+typedef struct SCI_SIMPLE_LIST
+{
+ struct SCI_SIMPLE_LIST_ELEMENT *list_head;
+ struct SCI_SIMPLE_LIST_ELEMENT *list_tail;
+ U32 list_count;
+} SCI_SIMPLE_LIST_T;
+
+/**
+ * @struct SCI_SIMPLE_LIST_ELEMENT
+ *
+ * @brief This structure defines what a singely linked list element contains.
+ */
+typedef struct SCI_SIMPLE_LIST_ELEMENT
+{
+ struct SCI_SIMPLE_LIST_ELEMENT *next;
+ void *object;
+} SCI_SIMPLE_LIST_ELEMENT_T;
+
+/**
+ * This method will insert the list element to the head of the list contained
+ * by the anchor.
+ *
+ * @note Pushing new elements onto a list is more efficient than inserting
+ * them to the tail of the list though both are O(1) operations.
+ */
+INLINE
+static void sci_simple_list_insert_head(
+ SCI_SIMPLE_LIST_T * anchor,
+ SCI_SIMPLE_LIST_ELEMENT_T *element
+)
+{
+ if (anchor->list_tail == NULL)
+ {
+ anchor->list_tail = element;
+ }
+
+ element->next = anchor->list_head;
+ anchor->list_head = element;
+ anchor->list_count++;
+}
+
+/**
+ * This methos will insert the list element to the tail of the list contained
+ * by the anchor.
+ *
+ * @param[in, out] anchor this is the list into which the element is to be
+ * inserted
+ * @param[in] element this is the element which to insert into the list.
+ *
+ * @note Pushing new elements onto a list is more efficient than inserting
+ * them to the tail of the list though both are O(1) operations.
+ */
+INLINE
+static void sci_simple_list_insert_tail(
+ SCI_SIMPLE_LIST_T * anchor,
+ SCI_SIMPLE_LIST_ELEMENT_T *element
+)
+{
+ if (anchor->list_tail == NULL)
+ {
+ anchor->list_head = element;
+ }
+ else
+ {
+ anchor->list_tail->next = element;
+ }
+
+ anchor->list_tail = element;
+ anchor->list_count++;
+}
+
+/**
+ * This method will remove the list element from the anchor and return the
+ * object pointed to by that list element.
+ *
+ * @param[in, out] anchor this is the list into which the element is to be
+ * inserted
+ *
+ * @return the list element at the head of the list.
+ */
+INLINE
+static void * sci_simple_list_remove_head(
+ SCI_SIMPLE_LIST_T * anchor
+)
+{
+ void * object = NULL;
+
+ if (anchor->list_head != NULL)
+ {
+ object = anchor->list_head->object;
+
+ anchor->list_head = anchor->list_head->next;
+
+ if (anchor->list_head == NULL)
+ {
+ anchor->list_tail = NULL;
+ }
+
+ anchor->list_count--;
+ }
+
+ return object;
+}
+
+/**
+ * Move all the list elements from source anchor to the dest anchor.
+ * The source anchor will have all of its elements removed making it
+ * an empty list and the dest anchor will contain all of the source
+ * and dest list elements.
+ *
+ * @param[in, out] dest_anchor this is the list into which all elements from
+ * the source list are to be moved.
+ * @param[in, out] source_anchor this is the list which is to be moved to the
+ * destination list. This list will be empty on return.
+ *
+ * @return the list element at the head of the list.
+ * @note If the destination has list elements use the insert at head
+ * or tail routines instead.
+ */
+INLINE
+static void sci_simple_list_move_list(
+ SCI_SIMPLE_LIST_T * dest_anchor,
+ SCI_SIMPLE_LIST_T * source_anchor
+)
+{
+ *dest_anchor = *source_anchor;
+
+ sci_simple_list_init(source_anchor);
+}
+
+/**
+ * This method will insert the list elements from the source anchor to the
+ * destination list before all previous elements on the destination list.
+ *
+ * @param[in, out] dest_anchor this is the list into which all elements from
+ * the source list are to be moved. The destination list will
+ * now contain both sets of list elements.
+ * @param[in, out] source_anchor this is the list which is to be moved to the
+ * destination list. This list will be empty on return.
+ */
+INLINE
+static void sci_simple_list_insert_list_at_head(
+ SCI_SIMPLE_LIST_T * dest_anchor,
+ SCI_SIMPLE_LIST_T * source_anchor
+)
+{
+ if (!sci_simple_list_is_empty(source_anchor))
+ {
+ if (sci_simple_list_is_empty(dest_anchor))
+ {
+ // Destination is empty just copy the source on over
+ *dest_anchor = *source_anchor;
+ }
+ else
+ {
+ source_anchor->list_tail->next = dest_anchor->list_head;
+ dest_anchor->list_head = source_anchor->list_head;
+ dest_anchor->list_count += source_anchor->list_count;
+ }
+
+ // Wipe the source list to make sure the list elements can not be accessed
+ // from two seperate lists at the same time.
+ sci_simple_list_init(source_anchor);
+ }
+}
+
+/**
+ * This method will insert the list elements from the source anchor to the
+ * destination anchor after all list elements on the destination anchor.
+ *
+ * @param[in, out] dest_anchor this is the list into which all elements from
+ * the source list are to be moved. The destination list will
+ * contain both the source and destination list elements.
+ * @param[in, out] source_anchor this is the list which is to be moved to the
+ * destination list. This list will be empty on return.
+ */
+INLINE
+static void sci_simple_list_insert_list_at_tail(
+ SCI_SIMPLE_LIST_T * dest_anchor,
+ SCI_SIMPLE_LIST_T * source_anchor
+)
+{
+ if (!sci_simple_list_is_empty(source_anchor))
+ {
+ if (sci_simple_list_is_empty(dest_anchor))
+ {
+ // Destination is empty just copy the source on over
+ *dest_anchor = *source_anchor;
+ }
+ else
+ {
+ // If the source list is empty the desination list is the result.
+ dest_anchor->list_tail->next = source_anchor->list_head;
+ dest_anchor->list_tail = source_anchor->list_tail;
+ dest_anchor->list_count += source_anchor->list_count;
+ }
+
+ // Wipe the source list to make sure the list elements can not be accessed
+ // from two seperate lists at the same time.
+ sci_simple_list_init(source_anchor);
+ }
+}
+
+#endif // _SCI_SIMPLE_LIST_HEADER_
diff --git a/sys/dev/isci/scil/sci_status.h b/sys/dev/isci/scil/sci_status.h
new file mode 100644
index 0000000..1b40860
--- /dev/null
+++ b/sys/dev/isci/scil/sci_status.h
@@ -0,0 +1,418 @@
+/*-
+ * 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.
+ *
+ * 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.
+ *
+ * $FreeBSD$
+ */
+#ifndef _SCI_STATUS_H_
+#define _SCI_STATUS_H_
+
+/**
+ * @file
+ *
+ * @brief This file contains all of the return status codes utilized across
+ * the various sub-components in SCI.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif // __cplusplus
+
+/**
+ * @enum _SCI_STATUS
+ * @brief This is the general return status enumeration for non-IO, non-task
+ * management related SCI interface methods.
+ */
+typedef 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_request_get_controller_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
+
+} SCI_STATUS;
+
+/**
+ * @enum _SCI_IO_STATUS
+ * @brief This enumeration depicts all of the possible IO completion
+ * status values. Each value in this enumeration maps directly to
+ * a value in the SCI_STATUS enumeration. Please refer to that
+ * enumeration for detailed comments concerning what the status
+ * represents.
+ * @todo Add the API to retrieve the SCU status from the core.
+ * @todo Check to see that the following status are properly handled:
+ * - SCI_IO_FAILURE_UNSUPPORTED_PROTOCOL
+ * - SCI_IO_FAILURE_INVALID_IO_TAG
+ */
+typedef 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
+} SCI_IO_STATUS;
+
+/**
+ * @enum _SCI_TASK_STATUS
+ * @brief This enumeration depicts all of the possible task completion
+ * status values. Each value in this enumeration maps directly to
+ * a value in the SCI_STATUS enumeration. Please refer to that
+ * enumeration for detailed comments concerning what the status
+ * represents.
+ * @todo Check to see that the following status are properly handled:
+ */
+typedef 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
+
+} SCI_TASK_STATUS;
+
+#ifdef __cplusplus
+}
+#endif // __cplusplus
+
+#endif // _SCI_STATUS_H_
+
diff --git a/sys/dev/isci/scil/sci_types.h b/sys/dev/isci/scil/sci_types.h
new file mode 100644
index 0000000..b48ee7b
--- /dev/null
+++ b/sys/dev/isci/scil/sci_types.h
@@ -0,0 +1,280 @@
+/*-
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 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.
+ *
+ * $FreeBSD$
+ */
+#ifndef _SCI_TYPES_H_
+#define _SCI_TYPES_H_
+
+/**
+ * @file
+ *
+ * @brief This file contains all of the basic data types utilized by an
+ * SCI user or implementor.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif // __cplusplus
+
+#include <dev/isci/types.h>
+
+#ifndef sci_cb_physical_address_upper
+#error "sci_cb_physical_address_upper needs to be defined in appropriate environment.h"
+#endif
+
+#ifndef sci_cb_physical_address_lower
+#error "sci_cb_physical_address_lower needs to be defined in appropriate environment.h"
+#endif
+
+#ifndef sci_cb_make_physical_address
+#error "sci_cb_make_physical_address needs to be defined in appropriate environment.h"
+#endif
+
+#ifndef ASSERT
+#error "ASSERT needs to be defined in appropriate environment.h or system"
+#endif
+
+
+/**
+ * This constant defines the value utilized by SCI Components to indicate
+ * an invalid handle.
+ */
+#define SCI_INVALID_HANDLE 0x0
+
+/**
+ * @typedef SCI_OBJECT_HANDLE_T
+ * @brief This typedef just provides an opaque handle for all SCI
+ * objects.
+ */
+typedef void* SCI_OBJECT_HANDLE_T;
+
+/**
+ * @typedef SCI_LOGGER_HANDLE_T
+ * @brief This typedef just provides an opaque handle for all SCI
+ * Logger objects.
+ */
+typedef void* SCI_LOGGER_HANDLE_T;
+
+/**
+ * @typedef SCI_IO_REQUEST_HANDLE_T
+ * @brief The SCI_IO_REQUEST_HANDLE_T will be utilized by SCI users as an
+ * opaque handle for the various SCI IO Request objects.
+ */
+typedef void * SCI_IO_REQUEST_HANDLE_T;
+
+/**
+ * @typedef SCI_TASK_REQUEST_HANDLE_T
+ * @brief The SCI_TASK_REQUEST_HANDLE_T will be utilized by SCI users as an
+ * opaque handle for the various SCI Task Management Request objects.
+ */
+typedef void * SCI_TASK_REQUEST_HANDLE_T;
+
+/**
+ * @typedef SCI_PHY_HANDLE_T
+ * @brief This typedef just provides an opaque handle for all SCI
+ * Phy objects.
+ */
+typedef void * SCI_PHY_HANDLE_T;
+
+/**
+ * @typedef SCI_REMOTE_DEVICE_HANDLE_T
+ * @brief The SCI_REMOTE_DEVICE_HANDLE_T will be utilized by SCI users as
+ * an opaque handle for the SCI remote device object.
+ */
+typedef void * SCI_REMOTE_DEVICE_HANDLE_T;
+
+/**
+ * @typedef SCI_DOMAIN_HANDLE_T
+ * @brief This typedef just provides an opaque handle for all SCI
+ * Domain objects.
+ */
+typedef void* SCI_DOMAIN_HANDLE_T;
+
+/**
+ * @typedef SCI_PORT_HANDLE_T
+ * @brief This typedef just provides an opaque handle for all SCI
+ * SAS or SATA Port objects.
+ */
+typedef void * SCI_PORT_HANDLE_T;
+
+/**
+ * @typedef SCI_MEMORY_DESCRIPTOR_LIST_HANDLE_T
+ * @brief The SCI_MEMORY_DESCRIPTOR_LIST_HANDLE_T will be utilized by SCI
+ * users as an opaque handle for the SCI MEMORY DESCRIPTOR LIST object.
+ */
+typedef void * SCI_MEMORY_DESCRIPTOR_LIST_HANDLE_T;
+
+/**
+ * @typedef SCI_LOCK_HANDLE_T
+ * @brief The SCI_LOCK_HANDLE_T will be utilized by SCI users as an
+ * opaque handle for the SCI LOCK object. A lock denotes a
+ * critical code section of some form.
+ */
+typedef void * SCI_LOCK_HANDLE_T;
+
+/**
+ * @typedef SCI_CONTROLLER_HANDLE_T
+ * @brief The SCI_CONTROLLER_HANDLE_T will be utilized by SCI users as an
+ * opaque handle for all SCI Controller objects.
+ */
+typedef void * SCI_CONTROLLER_HANDLE_T;
+
+/**
+ * @typedef SCI_LIBRARY_HANDLE_T
+ * @brief The SCI_LIBRARY_HANDLE_T will be utilized by SCI users as an
+ * opaque handle for the SCI Library object.
+ */
+typedef void * SCI_LIBRARY_HANDLE_T;
+
+/**
+ * @typedef SCI_ITERATOR_HANDLE_T
+ * @brief The SCI_ITERATOR_T will be utilized by SCI users as an
+ * opaque handle for the SCI Iterator object.
+ */
+typedef void * SCI_ITERATOR_HANDLE_T;
+
+/**
+ * @typedef SCI_TIMER_CALLBACK_T
+ * @brief This callback defines the format of all other timer callback
+ * methods that are to be implemented by an SCI user, including
+ * the method that will be invoked as a result of timer expiration.
+ *
+ * Parameters:
+ * - The void* value passed into the callback represents the cookie
+ * supplied by the SCI component when the timer was created.
+ *
+ * Return:
+ * - None
+ */
+typedef void (*SCI_TIMER_CALLBACK_T)(void*);
+
+/**
+ * @brief This enumeration is provided so the SCI User can communicate the
+ * data direction for an IO request.
+ */
+typedef enum
+{
+ /**
+ * The data direction for the request is in (a read operation)
+ * This is also the value to use for an io request that has no specific
+ * data direction.
+ */
+ SCI_IO_REQUEST_DATA_IN = 0,
+
+ /**
+ * The data direction for the request is out (a write operation)
+ */
+ SCI_IO_REQUEST_DATA_OUT,
+
+ /**
+ * There is no data transfer for the associated request.
+ */
+ SCI_IO_REQUEST_NO_DATA
+
+} SCI_IO_REQUEST_DATA_DIRECTION;
+
+/**
+ * @enum SCI_LOCK_LEVEL
+ * @brief This enumeration defines the various lock levels utilized by
+ * the SCI component. These lock levels help inform users, of the
+ * library, about what APIs must be protected from other APIs.
+ * The higher the lock level the more restricted the access. For
+ * example, APIs specifying lock level 5 are allowed to be executed
+ * while an API of lock level 4 is on-going, but the converse is
+ * not true.
+ */
+typedef enum
+{
+ /**
+ * This value indicates there is no lock level required. This is
+ * primarily utilized for situations in which there is a true critical
+ * code section that merely needs to protect against access to a
+ * region of memory.
+ */
+ SCI_LOCK_LEVEL_NONE,
+
+ SCI_LOCK_LEVEL_1,
+ SCI_LOCK_LEVEL_2,
+ SCI_LOCK_LEVEL_3,
+ SCI_LOCK_LEVEL_4,
+ SCI_LOCK_LEVEL_5
+
+} SCI_LOCK_LEVEL;
+
+/**
+ * @enum _SCI_CONTROLLER_MODE
+ * @brief This enumeration is utilized to indicate the operating mode
+ * in which the SCI component should function.
+ */
+typedef enum _SCI_CONTROLLER_MODE
+{
+ /**
+ * This enumerant specifies that the SCI component be optimized to
+ * perform as fast as possible without concern for the amount of
+ * memory being utilized.
+ */
+ SCI_MODE_SPEED,
+
+ /**
+ * This enumerant specifies that the SCI component be optimized to
+ * save memory space without concern for performance of the system.
+ */
+ SCI_MODE_SIZE
+
+} SCI_CONTROLLER_MODE;
+
+#ifdef __cplusplus
+}
+#endif // __cplusplus
+
+#endif // _SCI_TYPES_H_
+
diff --git a/sys/dev/isci/scil/sci_util.c b/sys/dev/isci/scil/sci_util.c
new file mode 100644
index 0000000..693bc8b
--- /dev/null
+++ b/sys/dev/isci/scil/sci_util.c
@@ -0,0 +1,72 @@
+/*-
+ * 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.
+ *
+ * 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 <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <dev/isci/scil/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/sys/dev/isci/scil/sci_util.h b/sys/dev/isci/scil/sci_util.h
new file mode 100644
index 0000000..25a19ae
--- /dev/null
+++ b/sys/dev/isci/scil/sci_util.h
@@ -0,0 +1,164 @@
+/*-
+ * 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.
+ *
+ * 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.
+ *
+ * $FreeBSD$
+ */
+#ifndef _SCI_UTIL_H_
+#define _SCI_UTIL_H_
+
+#include <dev/isci/scil/sci_types.h>
+
+#ifndef ARRAY_SIZE
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
+#endif
+
+#ifndef MIN
+#define MIN(x,y) ((x) < (y) ? (x) : (y))
+#endif
+
+#ifndef MAX
+#define MAX(x,y) ((x) > (y) ? (x) : (y))
+#endif
+
+/**
+ * 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) ((POINTER_UINT)&(((type *)0)->field))
+
+//This macro counts how many bits being set in a mask.
+#define SCI_GET_BITS_SET_COUNT(mask, set_bit_count) \
+{ \
+ U8 index; \
+ set_bit_count = 0; \
+ for (index = 0; index < sizeof(mask)*8; index++) \
+ { \
+ if( mask & (1<<index) ) \
+ set_bit_count++; \
+ } \
+}
+
+/**
+ * This macro simply performs addition on an SCI_PHYSICAL_ADDRESS
+ * 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 = sci_cb_physical_address_lower((physical_address)); \
+ U32 upper = sci_cb_physical_address_upper((physical_address)); \
+ \
+ if (lower + (value) < lower) \
+ upper += 1; \
+ \
+ lower += (value); \
+ sci_cb_make_physical_address(physical_address, upper, lower); \
+}
+
+/**
+ * This macro simply performs subtraction on an SCI_PHYSICAL_ADDRESS
+ * 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 = sci_cb_physical_address_lower((physical_address)); \
+ U32 upper = sci_cb_physical_address_upper((physical_address)); \
+ \
+ if (lower - (value) > lower) \
+ upper -= 1; \
+ \
+ lower -= (value); \
+ sci_cb_make_physical_address(physical_address, upper, lower); \
+}
+
+/**
+ * @brief Copy the data from source to destination and swap the
+ * bytes during the copy.
+ *
+ * @param[in] destination This parameter specifies the destination address
+ * to which the data is to be copied.
+ * @param[in] source This parameter specifies the source address from
+ * which data is to be copied.
+ * @param[in] word_count This parameter specifies the number of 32-bit words
+ * to copy and byte swap.
+ *
+ * @return none
+ */
+void scic_word_copy_with_swap(
+ U32 *destination,
+ U32 *source,
+ U32 word_count
+);
+
+
+#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)
+
+#endif // _SCI_UTIL_H_
diff --git a/sys/dev/isci/scil/scic_config_parameters.h b/sys/dev/isci/scil/scic_config_parameters.h
new file mode 100644
index 0000000..1c6c86c
--- /dev/null
+++ b/sys/dev/isci/scil/scic_config_parameters.h
@@ -0,0 +1,346 @@
+/*-
+ * 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.
+ *
+ * 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.
+ *
+ * $FreeBSD$
+ */
+#ifndef _SCIC_SDS_USER_PARAMETERS_H_
+#define _SCIC_SDS_USER_PARAMETERS_H_
+
+/**
+ * @file
+ *
+ * @brief This file contains all of the structure definitions and interface
+ * methods that can be called by a SCIC user on the SCU Driver
+ * Standard (SCIC_SDS_USER_PARAMETERS_T) user parameter block.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif // __cplusplus
+
+#include <dev/isci/scil/sci_types.h>
+#include <dev/isci/scil/sci_status.h>
+#include <dev/isci/scil/intel_sas.h>
+#include <dev/isci/scil/sci_controller_constants.h>
+#include <dev/isci/scil/scu_bios_definitions.h>
+
+/**
+ * @name 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
+ *
+ * @brief This structure delineates the various user parameters that can be
+ * changed by the core user.
+ */
+typedef 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 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;
+
+} SCIC_SDS_USER_PARAMETERS_T;
+
+/**
+ * @union SCIC_USER_PARAMETERS
+ * @brief This structure/union specifies the various different user
+ * parameter sets available. Each type is specific to a hardware
+ * controller version.
+ */
+typedef union SCIC_USER_PARAMETERS
+{
+ /**
+ * This field specifies the user parameters specific to the
+ * Storage Controller Unit (SCU) Driver Standard (SDS) version
+ * 1.
+ */
+ SCIC_SDS_USER_PARAMETERS_T sds1;
+
+} SCIC_USER_PARAMETERS_T;
+
+
+/**
+ * @name 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
+/*@}*/
+
+#define MAX_CONCURRENT_DEVICE_SPIN_UP_COUNT 4
+
+typedef SCI_BIOS_OEM_PARAM_ELEMENT_v_1_3_T SCIC_SDS_OEM_PARAMETERS_T;
+
+/**
+ * @union SCIC_OEM_PARAMETERS
+ *
+ * @brief This structure/union specifies the various different OEM
+ * parameter sets available. Each type is specific to a hardware
+ * controller version.
+ */
+typedef union SCIC_OEM_PARAMETERS
+{
+ /**
+ * This field specifies the OEM parameters specific to the
+ * Storage Controller Unit (SCU) Driver Standard (SDS) version
+ * 1.
+ */
+ SCIC_SDS_OEM_PARAMETERS_T sds1;
+
+} SCIC_OEM_PARAMETERS_T;
+
+/**
+ * @union OEM_SSC_DATA
+ *
+ * @brief This typedef provides a means to convert from the original
+ * 1.0 version of the OEM PARAMETER do_enable_ssc to the more
+ * comprehensive 1.1 version of enabling SSC parameters.
+ * For the definition of the field members see scu_bios_definitions.h
+ * header file or refer to the SCU BIOS Writers Guide.
+ */
+typedef union OEM_SSC_PARAMETERS
+{
+ struct
+ {
+ U8 ssc_sata_tx_spread_level : 4;
+ U8 ssc_sas_tx_spread_level : 3;
+ U8 ssc_sas_tx_type : 1;
+ } bf;
+
+ U8 do_enable_ssc;
+
+} OEM_SSC_PARAMETERS_T;
+
+/**
+ * @brief This method allows the user to attempt to change the user
+ * parameters utilized by the controller.
+ *
+ * @param[in] controller This parameter specifies the controller on which
+ * to set the user parameters.
+ * @param[in] user_parameters This parameter specifies the USER_PARAMETERS
+ * object containing the potential new values.
+ *
+ * @return Indicate if the update of the user parameters was successful.
+ * @retval SCI_SUCCESS This value is returned if the operation succeeded.
+ * @retval 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.
+ * @retval SCI_FAILURE_INVALID_PARAMETER_VALUE This value is returned if the
+ * user supplied an invalid interrupt coalescence time, spin up
+ * delay interval, etc.
+ */
+SCI_STATUS scic_user_parameters_set(
+ SCI_CONTROLLER_HANDLE_T controller,
+ SCIC_USER_PARAMETERS_T * user_parameters
+);
+
+/**
+ * @brief This method allows the user to retrieve the user parameters
+ * utilized by the controller.
+ *
+ * @param[in] controller This parameter specifies the controller on which
+ * to set the user parameters.
+ * @param[in] user_parameters This parameter specifies the USER_PARAMETERS
+ * object into which the framework shall save it's parameters.
+ *
+ * @return none
+ */
+void scic_user_parameters_get(
+ SCI_CONTROLLER_HANDLE_T controller,
+ SCIC_USER_PARAMETERS_T * user_parameters
+);
+
+/**
+ * @brief This method allows the user to attempt to change the OEM
+ * parameters utilized by the controller.
+ *
+ * @param[in] controller This parameter specifies the controller on which
+ * to set the user parameters.
+ * @param[in] oem_parameters This parameter specifies the OEM parameters
+ * object containing the potential new values.
+ * @param[in] oem_parameters_version This parameter is the OEM block version
+ * value indicating the format of the data associated with
+ * oem_parameters.
+ *
+ * @return Indicate if the update of the user parameters was successful.
+ * @retval SCI_SUCCESS This value is returned if the operation succeeded.
+ * @retval 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.
+ * @retval SCI_FAILURE_INVALID_PARAMETER_VALUE This value is returned if the
+ * user supplied an unsupported value for one of the OEM parameters.
+ */
+SCI_STATUS scic_oem_parameters_set(
+ SCI_CONTROLLER_HANDLE_T controller,
+ SCIC_OEM_PARAMETERS_T * oem_parameters,
+ U8 oem_parameters_version
+);
+
+/**
+ * @brief This method allows the user to retreive the OEM
+ * parameters utilized by the controller.
+ *
+ * @param[in] controller This parameter specifies the controller on which
+ * to set the user parameters.
+ * @param[out] oem_parameters This parameter specifies the OEM parameters
+ * object in which to write the core's OEM parameters.
+ *
+ * @return none
+ */
+void scic_oem_parameters_get(
+ SCI_CONTROLLER_HANDLE_T controller,
+ SCIC_OEM_PARAMETERS_T * oem_parameters
+);
+
+#ifdef __cplusplus
+}
+#endif // __cplusplus
+
+#endif // _SCIC_SDS_USER_PARAMETERS_H_
+
diff --git a/sys/dev/isci/scil/scic_controller.h b/sys/dev/isci/scil/scic_controller.h
new file mode 100644
index 0000000..75804c7
--- /dev/null
+++ b/sys/dev/isci/scil/scic_controller.h
@@ -0,0 +1,856 @@
+/*-
+ * 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.
+ *
+ * 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.
+ *
+ * $FreeBSD$
+ */
+#ifndef _SCIC_CONTROLLER_H_
+#define _SCIC_CONTROLLER_H_
+
+/**
+ * @file
+ *
+ * @brief This file contains all of the interface methods that can be called
+ * by an SCIC user on a controller object.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif // __cplusplus
+
+#include <dev/isci/scil/sci_types.h>
+#include <dev/isci/scil/sci_status.h>
+#include <dev/isci/scil/sci_controller.h>
+#include <dev/isci/scil/scic_config_parameters.h>
+
+/**
+ * @enum
+ *
+ * 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
+};
+
+/**
+ * @enum _SCIC_INTERRUPT_TYPE
+ *
+ * @brief This enumeration depicts the various types of interrupts that
+ * are potentially supported by a SCI Core implementation.
+ */
+typedef enum _SCIC_INTERRUPT_TYPE
+{
+ SCIC_LEGACY_LINE_INTERRUPT_TYPE,
+ SCIC_MSIX_INTERRUPT_TYPE,
+
+ /**
+ * This enumeration value indicates the use of polling.
+ */
+ SCIC_NO_INTERRUPTS
+
+} SCIC_INTERRUPT_TYPE;
+
+/**
+ * @typedef SCIC_CONTROLLER_INTERRUPT_HANDLER
+ *
+ * @brief 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.
+ * @note
+ * 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)(
+ SCI_CONTROLLER_HANDLE_T controller
+);
+
+/**
+ * @brief 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.
+ *
+ * @note 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)(
+ SCI_CONTROLLER_HANDLE_T controller
+);
+
+/**
+ * @struct SCIC_CONTROLLER_HANDLER_METHODS
+ *
+ * @brief This structure contains an interrupt handler and completion
+ * handler function pointers.
+ */
+typedef struct SCIC_CONTROLLER_HANDLER_METHODS
+{
+ SCIC_CONTROLLER_INTERRUPT_HANDLER interrupt_handler;
+ SCIC_CONTROLLER_COMPLETION_HANDLER completion_handler;
+
+} SCIC_CONTROLLER_HANDLER_METHODS_T;
+
+/**
+ * @brief This method will attempt to construct a controller object
+ * utilizing the supplied parameter information.
+ *
+ * @param[in] library This parameter specifies the handle to the library
+ * object associated with the controller being constructed.
+ * @param[in] controller This parameter specifies the controller to be
+ * constructed.
+ * @param[in] user_object This parameter is a reference to the SCIL users
+ * controller object and will be used to associate with the core
+ * controller.
+ *
+ * @return Indicate if the controller was successfully constructed or if
+ * it failed in some way.
+ * @retval SCI_SUCCESS This value is returned if the controller was
+ * successfully constructed.
+ * @retval SCI_WARNING_TIMER_CONFLICT This value is returned if the
+ * interrupt coalescence timer may cause SAS compliance issues
+ * for SMP Target mode response processing.
+ * @retval SCI_FAILURE_UNSUPPORTED_CONTROLLER_TYPE This value is returned if
+ * the controller does not support the supplied type.
+ * @retval SCI_FAILURE_UNSUPPORTED_INIT_DATA_VERSION This value is returned
+ * if the controller does not support the supplied initialization
+ * data version.
+ */
+SCI_STATUS scic_controller_construct(
+ SCI_LIBRARY_HANDLE_T library,
+ SCI_CONTROLLER_HANDLE_T controller,
+ void * user_object
+);
+
+/**
+ * @brief This method will enable all controller interrupts.
+ *
+ * @param[in] controller This parameter specifies the controller for which
+ * to enable interrupts.
+ *
+ * @return none
+ */
+void scic_controller_enable_interrupts(
+ SCI_CONTROLLER_HANDLE_T controller
+);
+
+/**
+ * @brief This method will disable all controller interrupts.
+ *
+ * @param[in] controller This parameter specifies the controller for which
+ * to disable interrupts.
+ *
+ * @return none
+ */
+void scic_controller_disable_interrupts(
+ SCI_CONTROLLER_HANDLE_T controller
+);
+
+/**
+ * @brief 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.
+ *
+ * @param[in] 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)
+ * @param[in] 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.
+ * @param[in] handler_methods The caller provides a pointer to a buffer of
+ * type SCIC_CONTROLLER_HANDLER_METHODS_T. The size depends on
+ * the combination of the interrupt_type and message_count input
+ * parameters:
+ * SCIC_LEGACY_LINE_INTERRUPT_TYPE:
+ * - size = sizeof(SCIC_CONTROLLER_HANDLER_METHODS_T)
+ * SCIC_MSIX_INTERRUPT_TYPE:
+ * - size = message_count*sizeof(SCIC_CONTROLLER_HANDLER_METHODS_T)
+ * @param[out] 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 SCIC_CONTROLLER_HANDLER_METHODS_T element
+ * regardless that the message_count parameter is zero.
+ * For SCIC_MSIX_INTERRUPT_TYPE, the buffer receives an array of
+ * elements of type SCIC_CONTROLLER_HANDLER_METHODS_T 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.
+ *
+ * @return Indicate if the handler retrieval operation was successful.
+ * @retval SCI_SUCCESS This value is returned if retrieval succeeded.
+ * @retval 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.
+ */
+SCI_STATUS scic_controller_get_handler_methods(
+ SCIC_INTERRUPT_TYPE interrupt_type,
+ U16 message_count,
+ SCIC_CONTROLLER_HANDLER_METHODS_T * handler_methods
+);
+
+/**
+ * @brief 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.
+ *
+ * @pre The SCI Core user must have called scic_controller_construct()
+ * on the supplied controller object previously.
+ *
+ * @param[in] controller This parameter specifies the controller to be
+ * initialized.
+ *
+ * @return Indicate if the controller was successfully initialized or if
+ * it failed in some way.
+ * @retval SCI_SUCCESS This value is returned if the controller hardware
+ * was successfully initialized.
+ */
+SCI_STATUS scic_controller_initialize(
+ SCI_CONTROLLER_HANDLE_T controller
+);
+
+/**
+ * @brief 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.
+ *
+ * @param[in] controller the handle to the controller object for which
+ * to return the suggested start timeout.
+ *
+ * @return This method returns the number of milliseconds for the
+ * suggested start operation timeout.
+ */
+U32 scic_controller_get_suggested_start_timeout(
+ SCI_CONTROLLER_HANDLE_T controller
+);
+
+/**
+ * @brief 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.
+ *
+ * @pre The SCI Core user must have filled in the physical memory
+ * descriptor structure via the
+ * sci_controller_get_memory_descriptor_list() method.
+ * @pre The SCI Core user must have invoked the scic_controller_initialize()
+ * method prior to invoking this method.
+ *
+ * @pre The controller must be in the INITIALIZED or STARTED state.
+ *
+ * @param[in] controller the handle to the controller object to start.
+ * @param[in] timeout This parameter specifies the number of milliseconds
+ * in which the start operation should complete.
+ *
+ * @return Indicate if the controller start method succeeded or failed in
+ * some way.
+ * @retval SCI_SUCCESS if the start operation succeeded.
+ * @retval SCI_WARNING_ALREADY_IN_STATE if the controller is already in
+ * the STARTED state.
+ * @retval SCI_FAILURE_INVALID_STATE if the controller is not either in
+ * the INITIALIZED or STARTED states.
+ * @retval SCI_FAILURE_INVALID_MEMORY_DESCRIPTOR if there are
+ * inconsistent or invalid values in the supplied
+ * SCI_PHYSICAL_MEMORY_DESCRIPTOR array.
+ */
+SCI_STATUS scic_controller_start(
+ SCI_CONTROLLER_HANDLE_T controller,
+ U32 timeout
+);
+
+/**
+ * @brief 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.
+ *
+ * @pre The controller must be in the STARTED or STOPPED state.
+ *
+ * @param[in] controller the handle to the controller object to stop.
+ * @param[in] timeout This parameter specifies the number of milliseconds
+ * in which the stop operation should complete.
+ *
+ * @return Indicate if the controller stop method succeeded or failed in
+ * some way.
+ * @retval SCI_SUCCESS if the stop operation successfully began.
+ * @retval SCI_WARNING_ALREADY_IN_STATE if the controller is already in
+ * the STOPPED state.
+ * @retval SCI_FAILURE_INVALID_STATE if the controller is not either in
+ * the STARTED or STOPPED states.
+ */
+SCI_STATUS scic_controller_stop(
+ SCI_CONTROLLER_HANDLE_T controller,
+ U32 timeout
+);
+
+/**
+ * @brief 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.
+ *
+ * @param[in] controller the handle to the controller object to reset.
+ *
+ * @return Indicate if the controller reset method succeeded or failed in
+ * some way.
+ * @retval SCI_SUCCESS if the reset operation successfully started.
+ * @retval SCI_FATAL_ERROR if the controller reset operation is unable to
+ * complete.
+ */
+SCI_STATUS scic_controller_reset(
+ SCI_CONTROLLER_HANDLE_T controller
+);
+
+/**
+ * @brief 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.
+ *
+ * @warning
+ * - 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.
+ *
+ * @param[in] controller the handle to the controller object for which
+ * to start an IO request.
+ * @param[in] remote_device the handle to the remote device object for which
+ * to start an IO request.
+ * @param[in] io_request the handle to the io request object to start.
+ * @param[in] 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.
+ * @see scic_controller_allocate_tag() for more information
+ * on allocating a tag.
+ *
+ * @return Indicate if the controller successfully started the IO request.
+ * @retval SCI_IO_SUCCESS if the IO request was successfully started.
+ *
+ * @todo Determine the failure situations and return values.
+ */
+SCI_IO_STATUS scic_controller_start_io(
+ SCI_CONTROLLER_HANDLE_T controller,
+ SCI_REMOTE_DEVICE_HANDLE_T remote_device,
+ SCI_IO_REQUEST_HANDLE_T io_request,
+ U16 io_tag
+);
+
+#if !defined(DISABLE_TASK_MANAGEMENT)
+
+/**
+ * @brief This method is called by the SCIC user to send/start a framework
+ * task management request.
+ *
+ * @warning
+ * - 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.
+ *
+ * @param[in] controller the handle to the controller object for which
+ * to start the task management request.
+ * @param[in] remote_device the handle to the remote device object for which
+ * to start the task management request.
+ * @param[in] task_request the handle to the task request object to start.
+ * @param[in] 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.
+ * @see scic_controller_allocate_tag() for more information
+ * on allocating a tag.
+ *
+ * @return Indicate if the controller successfully started the IO request.
+ * @retval SCI_TASK_SUCCESS if the task request was successfully started.
+ * @retval 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.
+ */
+SCI_TASK_STATUS scic_controller_start_task(
+ SCI_CONTROLLER_HANDLE_T controller,
+ SCI_REMOTE_DEVICE_HANDLE_T remote_device,
+ SCI_TASK_REQUEST_HANDLE_T task_request,
+ U16 io_tag
+);
+
+/**
+ * @brief 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).
+ *
+ * @param[in] controller The handle to the controller object for which
+ * to complete the task management request.
+ * @param[in] remote_device The handle to the remote device object for which
+ * to complete the task management request.
+ * @param[in] task_request the handle to the task management request object
+ * to complete.
+ *
+ * @return Indicate if the controller successfully completed the task
+ * management request.
+ * @retval SCI_SUCCESS if the completion process was successful.
+ */
+SCI_STATUS scic_controller_complete_task(
+ SCI_CONTROLLER_HANDLE_T controller,
+ SCI_REMOTE_DEVICE_HANDLE_T remote_device,
+ SCI_TASK_REQUEST_HANDLE_T task_request
+);
+
+#else // !defined(DISABLE_TASK_MANAGEMENT)
+
+#define scic_controller_start_task(controller, dev, task, tag) SCI_TASK_FAILURE
+#define scic_controller_complete_task(controller, dev, task) SCI_FAILURE
+
+#endif // !defined(DISABLE_TASK_MANAGEMENT)
+
+/**
+ * @brief 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.
+ *
+ * @param[in] controller the handle to the controller object for which
+ * to terminate a request.
+ * @param[in] remote_device the handle to the remote device object for which
+ * to terminate a request.
+ * @param[in] request the handle to the io or task management request
+ * object to terminate.
+ *
+ * @return Indicate if the controller successfully began the terminate process
+ * for the IO request.
+ * @retval SCI_SUCCESS if the terminate process was successfully started for
+ * the request.
+ *
+ * @todo Determine the failure situations and return values.
+ */
+SCI_STATUS scic_controller_terminate_request(
+ SCI_CONTROLLER_HANDLE_T controller,
+ SCI_REMOTE_DEVICE_HANDLE_T remote_device,
+ SCI_IO_REQUEST_HANDLE_T request
+);
+
+/**
+ * @brief 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).
+ *
+ * @warning
+ * - 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).
+ *
+ * @param[in] controller The handle to the controller object for which
+ * to complete the IO request.
+ * @param[in] remote_device The handle to the remote device object for which
+ * to complete the IO request.
+ * @param[in] io_request the handle to the io request object to complete.
+ *
+ * @return Indicate if the controller successfully completed the IO request.
+ * @retval SCI_SUCCESS if the completion process was successful.
+ */
+SCI_STATUS scic_controller_complete_io(
+ SCI_CONTROLLER_HANDLE_T controller,
+ SCI_REMOTE_DEVICE_HANDLE_T remote_device,
+ SCI_IO_REQUEST_HANDLE_T io_request
+);
+
+
+/**
+ * @brief This method simply provides the user with a unique handle for a
+ * given SAS/SATA core port index.
+ *
+ * @param[in] controller This parameter represents the handle to the
+ * controller object from which to retrieve a port (SAS or
+ * SATA) handle.
+ * @param[in] 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.
+ * @param[out] port_handle This parameter specifies the retrieved port handle
+ * to be provided to the caller.
+ *
+ * @return Indicate if the retrieval of the port handle was successful.
+ * @retval SCI_SUCCESS This value is returned if the retrieval was successful.
+ * @retval SCI_FAILURE_INVALID_PORT This value is returned if the supplied
+ * port id is not in the supported range.
+ */
+SCI_STATUS scic_controller_get_port_handle(
+ SCI_CONTROLLER_HANDLE_T controller,
+ U8 port_index,
+ SCI_PORT_HANDLE_T * port_handle
+);
+
+/**
+ * @brief This method simply provides the user with a unique handle for a
+ * given SAS/SATA phy index/identifier.
+ *
+ * @param[in] controller This parameter represents the handle to the
+ * controller object from which to retrieve a phy (SAS or
+ * SATA) handle.
+ * @param[in] 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.
+ * @param[out] phy_handle This parameter specifies the retrieved phy handle
+ * to be provided to the caller.
+ *
+ * @return Indicate if the retrieval of the phy handle was successful.
+ * @retval SCI_SUCCESS This value is returned if the retrieval was successful.
+ * @retval SCI_FAILURE_INVALID_PHY This value is returned if the supplied phy
+ * id is not in the supported range.
+ */
+SCI_STATUS scic_controller_get_phy_handle(
+ SCI_CONTROLLER_HANDLE_T controller,
+ U8 phy_index,
+ SCI_PHY_HANDLE_T * phy_handle
+);
+
+/**
+ * @brief 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.
+ *
+ * @warning 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.).
+ *
+ * @param[in] controller the handle to the controller object for which to
+ * allocate the tag.
+ *
+ * @return An unsigned integer representing an available IO tag.
+ * @retval SCI_CONTROLLER_INVALID_IO_TAG This value is returned if there
+ * are no currently available tags to be allocated.
+ * @retval All return other values indicate a legitimate tag.
+ */
+U16 scic_controller_allocate_io_tag(
+ SCI_CONTROLLER_HANDLE_T controller
+);
+
+/**
+ * @brief 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().
+ *
+ * @warning
+ * - 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.
+ *
+ * @param[in] controller This parameter specifies the handle to the
+ * controller object for which to free/return the tag.
+ * @param[in] io_tag This parameter represents the tag to be freed to the
+ * pool of available tags.
+ *
+ * @return This method returns an indication of whether the tag was
+ * successfully put back (freed) to the pool of available tags.
+ * @retval SCI_SUCCESS This return value indicates the tag was successfully
+ * placed into the pool of available IO tags.
+ * @retval SCI_FAILURE_INVALID_IO_TAG This value is returned if the supplied
+ * tag is not a valid IO tag value.
+ */
+SCI_STATUS scic_controller_free_io_tag(
+ SCI_CONTROLLER_HANDLE_T controller,
+ U16 io_tag
+);
+
+/**
+ * @brief This method returns the size of the core's scratch RAM.
+ *
+ * @return Size of the scratch RAM in dwords.
+ */
+U32 scic_controller_get_scratch_ram_size(
+ SCI_CONTROLLER_HANDLE_T controller
+);
+
+/**
+ * @brief This method allows the user to read a U32 from the core's
+ * scratch RAM.
+ *
+ * @param[in] controller This parameter represents the handle to the
+ * controller object for which to read scratch RAM.
+ * @param[in] offset The offset (in dwords) into the scratch RAM.
+ * @param[out] value The location where the read value should be stored.
+ *
+ * @return Indicate if the user specified a valid offset into the
+ * scratch RAM.
+ * @retval SCI_SUCCESS The scratch RAM was successfully read.
+ * @retval SCI_FAILURE_INVALID_PARAMETER_VALUE The user specified an
+ * invalid offset.
+ */
+SCI_STATUS scic_controller_read_scratch_ram_dword(
+ SCI_CONTROLLER_HANDLE_T controller,
+ U32 offset,
+ U32 * value
+);
+
+/**
+ * @brief This method allows the user to write a U32 to the core's
+ * scratch RAM.
+ *
+ * @param[in] controller This parameter represents the handle to the
+ * controller object for which to write scratch RAM.
+ * @param[in] offset The offset (in dwords) into the scratch RAM.
+ * @param[out] value The value to be written to scratch RAM.
+ *
+ * @return Indicate if the user specified a valid offset into the
+ * scratch RAM.
+ * @retval SCI_SUCCESS The scratch RAM was successfully written.
+ * @retval SCI_FAILURE_INVALID_PARAMETER_VALUE The user specified an
+ * invalid offset.
+ */
+SCI_STATUS scic_controller_write_scratch_ram_dword(
+ SCI_CONTROLLER_HANDLE_T controller,
+ U32 offset,
+ U32 value
+);
+
+/**
+ * @brief This method allows the user to configure the SCI core into
+ * either a performance mode or a memory savings mode.
+ *
+ * @param[in] controller This parameter represents the handle to the
+ * controller object for which to update the operating
+ * mode.
+ * @param[in] mode This parameter specifies the new mode for the
+ * controller.
+ *
+ * @return Indicate if the user successfully change the operating mode
+ * of the controller.
+ * @retval SCI_SUCCESS The user successfully updated the mode.
+ */
+SCI_STATUS scic_controller_set_mode(
+ SCI_CONTROLLER_HANDLE_T controller,
+ SCI_CONTROLLER_MODE mode
+);
+
+
+#if !defined(DISABLE_INTERRUPTS)
+/**
+ * @brief This method allows the user to configure the interrupt coalescence.
+ *
+ * @param[in] controller This parameter represents the handle to the
+ * controller object for which its interrupt coalesce register
+ * is overridden.
+ *
+ * @param[in] 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.
+ * @param[in] 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.
+ *
+ * @return Indicate if the user successfully set the interrupt coalesce parameters.
+ * @retval SCI_SUCCESS The user successfully updated the interrutp coalescence.
+ * @retval SCI_FAILURE_INVALID_PARAMETER_VALUE The user input value is out of range.
+ */
+SCI_STATUS scic_controller_set_interrupt_coalescence(
+ SCI_CONTROLLER_HANDLE_T controller,
+ U32 coalesce_number,
+ U32 coalesce_timeout
+);
+
+/**
+ * @brief This method retrieves the interrupt coalescing values
+ *
+ * @param[in] controller This parameter specifies the controller for
+ * which its interrupt coalescing number is read.
+ *
+ * @param[out] coalesce_number, interrupt coalescing number read from controller.
+ *
+ * @param[out] coalesce_timeout, timeout value in microseconds.
+ *
+ * @return None
+ */
+void scic_controller_get_interrupt_coalescence(
+ SCI_CONTROLLER_HANDLE_T controller,
+ U32 * coalesce_number,
+ U32 * coalesce_timeout
+);
+#else // !defined(DISABLE_INTERRUPTS)
+#define scic_controller_set_interrupt_coalescence(controller, num, timeout) \
+ SCI_FAILURE
+#define scic_controller_get_interrupt_coalescence(controller, num, timeout)
+#endif // !defined(DISABLE_INTERRUPTS)
+
+
+/**
+ * @brief This method suspend the controller, reinitialize RAMs, then resume
+ * the controller.
+ *
+ * @param[in] controller This parameter specifies the controller which is transitioning.
+ *
+ * @param[in] restrict_completions This parameter specifies whether the controller should
+ * ignore completion processing for non-fastpath events. This will cause
+ * the completions to be thrown away.
+ *
+ * @return SCI_STATUS The status of controller transition.
+ */
+SCI_STATUS scic_controller_transition(
+ SCI_CONTROLLER_HANDLE_T controller,
+ BOOL restrict_completions
+);
+
+
+/**
+ * @brief This method suspends the controller.
+ *
+ * @param[in] controller This parameter specifies the controller which is to be suspended.
+ *
+ * @return SCI_STATUS The status of controller suspend.
+ */
+SCI_STATUS scic_controller_suspend(
+ SCI_CONTROLLER_HANDLE_T controller
+);
+
+/**
+ * @brief This method resumes the controller.
+ *
+ * @param[in] controller This parameter specifies the controller which is to be resumed.
+ *
+ * @return SCI_STATUS The status of controller resume.
+ */
+SCI_STATUS scic_controller_resume(
+ SCI_CONTROLLER_HANDLE_T controller
+);
+
+SCI_STATUS scic_controller_get_max_ports(
+ SCI_CONTROLLER_HANDLE_T controller,
+ U8 * count
+);
+
+SCI_STATUS scic_controller_get_max_phys(
+ SCI_CONTROLLER_HANDLE_T controller,
+ U8 * count
+);
+
+#ifdef __cplusplus
+}
+#endif // __cplusplus
+
+#endif // _SCIC_CONTROLLER_H_
+
diff --git a/sys/dev/isci/scil/scic_io_request.h b/sys/dev/isci/scil/scic_io_request.h
new file mode 100644
index 0000000..ee1405e
--- /dev/null
+++ b/sys/dev/isci/scil/scic_io_request.h
@@ -0,0 +1,761 @@
+/*-
+ * 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.
+ *
+ * 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.
+ *
+ * $FreeBSD$
+ */
+#ifndef _SCIC_IO_REQUEST_H_
+#define _SCIC_IO_REQUEST_H_
+
+/**
+ * @file
+ *
+ * @brief This file contains the structures and interface methods that
+ * can be referenced and used by the SCI user for the SCI IO request
+ * object.
+ *
+ * @todo Determine the failure situations and return values.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif // __cplusplus
+
+#include <dev/isci/scil/sci_types.h>
+#include <dev/isci/scil/sci_status.h>
+#include <dev/isci/scil/intel_sas.h>
+
+/**
+ * @struct SCIC_IO_SSP_PARAMETERS
+ * @brief This structure contains additional optional parameters for SSP
+ * IO requests. These parameters are utilized with the
+ * scic_io_request_construct_advanced_ssp() method.
+ *
+ * @todo Add Block-guard/DIF, TLR
+ */
+typedef struct SCIC_IO_SSP_PARAMETERS
+{
+ /**
+ * 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;
+
+} SCIC_IO_SSP_PARAMETERS_T;
+
+/**
+ * @struct SCIC_IO_PARAMETERS
+ * @brief This structure contains additional optional parameters for
+ * STP/SATA IO requests. These parameters are utilized with the
+ * scic_io_request_construct_advanced_sata() method.
+ */
+typedef struct SCIC_IO_SATA_PARAMETERS
+{
+ /**
+ * This field indicates whether or not to construct the Scatter-Gather
+ * List elements for the SATA request. This is used in scenarios
+ * where Scatter-gather-list processing/translation is done by the
+ * user.
+ */
+ BOOL do_translate_sgl;
+
+} SCIC_IO_SATA_PARAMETERS_T;
+
+/**
+ * @struct SCIC_PASSTHRU_REQUEST_CALLBACKS
+ * @brief 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
+ *
+ */
+typedef 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 *);
+
+} SCIC_PASSTHRU_REQUEST_CALLBACKS_T;
+
+/**
+ * @struct SCIC_SSP_PASSTHRU_REQUEST_CALLBACKS
+ * @brief 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
+ *
+ */
+typedef struct SCIC_SSP_PASSTHRU_REQUEST_CALLBACKS
+{
+ /**
+ * Common callbacks for all Passthru requests
+ */
+ SCIC_PASSTHRU_REQUEST_CALLBACKS_T 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 *);
+} SCIC_SSP_PASSTHRU_REQUEST_CALLBACKS_T;
+
+/**
+ * @struct SCIC_STP_PASSTHRU_REQUEST_CALLBACKS
+ * @brief 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
+ *
+ */
+typedef struct SCIC_STP_PASSTHRU_REQUEST_CALLBACKS
+{
+ /**
+ * Common callbacks for all Passthru requests
+ */
+ SCIC_PASSTHRU_REQUEST_CALLBACKS_T 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 *);
+
+} SCIC_STP_PASSTHRU_REQUEST_CALLBACKS_T;
+
+/**
+ * @struct SCIC_SMP_PASSTHRU_REQUEST_CALLBACKS
+ * @brief 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
+ *
+ */
+typedef struct SCIC_SMP_PASSTHRU_REQUEST_CALLBACKS
+{
+ /**
+ * Common callbacks for all Passthru requests
+ */
+ SCIC_PASSTHRU_REQUEST_CALLBACKS_T 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 * );
+
+} SCIC_SMP_PASSTHRU_REQUEST_CALLBACKS_T;
+
+/**
+ * @brief 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;
+
+
+/**
+ * @brief This method simply returns the size required to build an SCI
+ * based IO request object.
+ *
+ * @return Return the size of the SCI IO request object.
+ */
+U32 scic_io_request_get_object_size(
+ void
+);
+
+/**
+ * @brief 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.
+ *
+ * @note The SCI core implementation will create an association between
+ * the user IO request object and the core IO request object.
+ *
+ * @param[in] scic_controller the handle to the core controller object
+ * for which to build an IO request.
+ * @param[in] scic_remote_device the handle to the core remote device
+ * object for which to build an IO request.
+ * @param[in] 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.
+ * @param[in] 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.
+ * @param[in] scic_io_request_memory This parameter specifies the memory
+ * location to be utilized when building the core request.
+ * @param[out] 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.
+ *
+ * @return Indicate if the controller successfully built the IO request.
+ * @retval SCI_SUCCESS This value is returned if the IO request was
+ * successfully built.
+ */
+SCI_STATUS scic_io_request_construct(
+ SCI_CONTROLLER_HANDLE_T scic_controller,
+ SCI_REMOTE_DEVICE_HANDLE_T scic_remote_device,
+ U16 io_tag,
+ void * user_io_request_object,
+ void * scic_io_request_memory,
+ SCI_IO_REQUEST_HANDLE_T * new_scic_io_request_handle
+);
+
+/**
+ * @brief This method is called by the SCI user to build an SSP
+ * IO request.
+ *
+ * @pre
+ * - The user must have previously called scic_io_request_construct()
+ * on the supplied IO request.
+ *
+ * @param[in] scic_io_request This parameter specifies the handle to the
+ * io request object to be built.
+ *
+ * @return Indicate if the controller successfully built the IO request.
+ * @retval SCI_SUCCESS This value is returned if the IO request was
+ * successfully built.
+ * @retval SCI_FAILURE_UNSUPPORTED_PROTOCOL This value is returned if the
+ * remote_device does not support the SSP protocol.
+ * @retval 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.
+ */
+SCI_STATUS scic_io_request_construct_basic_ssp(
+ SCI_IO_REQUEST_HANDLE_T scic_io_request
+);
+
+/**
+ * @brief This method is called by the SCI user to build an SSP
+ * IO request with additional parameters that provide additional
+ * flexibility from the standard scic_io_request_construct_basic_ssp()
+ * method.
+ *
+ * @pre
+ * - The user must have previously called scic_io_request_construct()
+ * on the supplied IO request.
+ *
+ * @param[in] scic_io_request This parameter specifies the handle to the
+ * io request object to be built.
+ * @param[in] io_parameters the additional parameter information to
+ * be added to the outgoing IO request.
+ *
+ * @return Indicate if the controller successfully built the IO request.
+ * @retval SCI_SUCCESS This value is returned if the IO request was
+ * successfully built.
+ * @retval SCI_FAILURE_UNSUPPORTED_PROTOCOL This value is returned if the
+ * remote_device does not support the SSP protocol.
+ * @retval 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.
+ *
+ * @todo Determine the failure situations and return values.
+ */
+SCI_STATUS scic_io_request_construct_advanced_ssp(
+ SCI_IO_REQUEST_HANDLE_T scic_io_request,
+ SCIC_IO_SSP_PARAMETERS_T * io_parameters
+);
+
+#if !defined(DISABLE_PASS_THROUGH)
+
+/**
+ * @brief This method will build an IO request based on the user information
+ * supplied in the pass-through IO request object.
+ *
+ * @param[in] scic_io_request This parameter specifies the handle to the
+ * io request object to be built.
+ *
+ * @param[in] ssp_passthru_cb This parameter specifies the pointer to
+ * the structure containing the callback to the function
+ * pointers to get the needed fields from the pass-through
+ * reqiest instead of SRB
+ *
+ * @return Indicate if the controller successfully built the IO request.
+ * @retval SCI_SUCCESS This value is returned if the IO request was
+ * successfully built.
+ * @retval 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.
+ */
+SCI_STATUS scic_io_request_construct_ssp_pass_through(
+ void * scic_io_request_memory,
+ SCIC_SSP_PASSTHRU_REQUEST_CALLBACKS_T *ssp_passthru_cb
+);
+
+#else // !defined(DISABLE_PASS_THROUGH)
+
+#define scic_io_request_construct_ssp_pass_through(memory, cb) SCI_FAILURE
+
+#endif // !defined(DISABLE_PASS_THROUGH)
+
+/**
+ * @brief This method is called by the SCI Core user to build an STP
+ * IO request.
+ *
+ * @pre
+ * - The user must have previously called scic_io_request_construct()
+ * on the supplied IO request.
+ *
+ * @param[in] scic_io_request This parameter specifies the handle to the
+ * io request object to be built.
+ *
+ * @return Indicate if the controller successfully built the IO request.
+ * @retval SCI_SUCCESS This value is returned if the IO request was
+ * successfully built.
+ * @retval SCI_FAILURE_UNSUPPORTED_PROTOCOL This value is returned if the
+ * remote_device does not support the STP protocol.
+ * @retval 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.
+ */
+SCI_STATUS scic_io_request_construct_basic_sata(
+ SCI_IO_REQUEST_HANDLE_T scic_io_request
+);
+
+/**
+ * @brief This method is called by the SCI Core user to build an STP
+ * IO request.
+ *
+ * @pre
+ * - The user must have previously called scic_io_request_construct()
+ * on the supplied IO request.
+ *
+ * @param[in] scic_io_request This parameter specifies the handle to the
+ * io request object to be built.
+ *
+ * @return Indicate if the controller successfully built the IO request.
+ * @retval SCI_SUCCESS This value is returned if the IO request was
+ * successfully built.
+ * @retval SCI_FAILURE_UNSUPPORTED_PROTOCOL This value is returned if the
+ * remote_device does not support the STP protocol.
+ * @retval 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.
+ */
+SCI_STATUS scic_io_request_construct_advanced_sata(
+ SCI_IO_REQUEST_HANDLE_T scic_io_request,
+ SCIC_IO_SATA_PARAMETERS_T * io_parameters
+);
+
+#if !defined(DISABLE_PASS_THROUGH)
+
+/**
+ * @brief This method is called by the SCI user to build an STP pass-through
+ * IO request.
+ *
+ * @pre
+ * - The user must have previously called scic_io_request_construct()
+ * on the supplied IO request.
+ *
+ * @param[in] scic_io_request This parameter specifies the handle to the
+ * io request object to be built.
+ *
+ * @param[in] passthru_cb This parameter specifies the pointer to the callback
+ * structure that contains the function pointers
+ *
+ * @return Indicate if the controller successfully built the IO request.
+ */
+SCI_STATUS scic_io_request_construct_sata_pass_through(
+ SCI_IO_REQUEST_HANDLE_T scic_io_request,
+ SCIC_STP_PASSTHRU_REQUEST_CALLBACKS_T *passthru_cb
+
+);
+
+#else // !defined(DISABLE_PASS_THROUGH)
+
+#define scic_io_request_construct_sata_pass_through(io, cb) SCI_FAILURE
+
+#endif // !defined(DISABLE_PASS_THROUGH)
+
+/**
+ * @brief This method is called by the SCI user to build an SMP
+ * IO request.
+ *
+ * @pre
+ * - The user must have previously called scic_io_request_construct()
+ * on the supplied IO request.
+ *
+ * @param[in] scic_io_request This parameter specifies the handle to the
+ * io request object to be built.
+ *
+ * @return Indicate if the controller successfully built the IO request.
+ * @retval SCI_SUCCESS This value is returned if the IO request was
+ * successfully built.
+ * @retval SCI_FAILURE_UNSUPPORTED_PROTOCOL This value is returned if the
+ * remote_device does not support the SMP protocol.
+ * @retval 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.
+ */
+SCI_STATUS scic_io_request_construct_smp(
+ SCI_IO_REQUEST_HANDLE_T scic_io_request
+);
+
+
+/**
+ * @brief This method is called by the SCI user to build an SMP pass-through
+ * IO request.
+ *
+ * @pre
+ * - The user must have previously called scic_io_request_construct()
+ * on the supplied IO request.
+ *
+ * @param[in] scic_smp_request This parameter specifies the handle to the
+ * io request object to be built.
+ *
+ * @param[in] passthru_cb This parameter specifies the pointer to the callback
+ * structure that contains the function pointers
+ *
+ * @return Indicate if the controller successfully built the IO request.
+ */
+SCI_STATUS scic_io_request_construct_smp_pass_through(
+ SCI_IO_REQUEST_HANDLE_T scic_smp_request,
+ SCIC_SMP_PASSTHRU_REQUEST_CALLBACKS_T *passthru_cb
+);
+
+/**
+ * @brief This method returns the controller specific IO/Task request status.
+ * These status values are unique to the specific controller being
+ * managed by the SCIC.
+ *
+ * @param[in] io_request the handle to the IO or task management request
+ * object for which to retrieve the status.
+ *
+ * @return This method returns a value indicating the controller specific
+ * request status.
+ */
+U32 scic_request_get_controller_status(
+ SCI_IO_REQUEST_HANDLE_T io_request
+);
+
+/**
+ * @brief This method returns the user specific IO/Task request status.
+ *
+ * @param[in] io_request the handle to the IO or task management request
+ * object for which to retrieve the status.
+ *
+ * @return This method returns a value indicating the user specific
+ * request status.
+ */
+U32 scic_request_get_sci_status(
+ SCI_IO_REQUEST_HANDLE_T io_request
+);
+
+
+/**
+ * @brief This method will return the address to the command information
+ * unit.
+ *
+ * @param[in] scic_io_request This parameter specifies the handle to the
+ * io request object to be built.
+ *
+ * @return The address of the SSP/SMP command information unit.
+ */
+void * scic_io_request_get_command_iu_address(
+ SCI_IO_REQUEST_HANDLE_T scic_io_request
+);
+
+/**
+ * @brief 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.
+ *
+ * @param[in] scic_io_request This parameter specifies the handle to the
+ * io request object to be built.
+ *
+ * @return The address of the SSP/SMP response information unit.
+ */
+void * scic_io_request_get_response_iu_address(
+ SCI_IO_REQUEST_HANDLE_T scic_io_request
+);
+
+/**
+ * @brief This method will return the IO tag utilized by the IO request.
+ *
+ * @param[in] scic_io_request This parameter specifies the handle to the
+ * io request object for which to return the IO tag.
+ *
+ * @return An unsigned integer representing the IO tag being utilized.
+ * @retval SCI_CONTROLLER_INVALID_IO_TAG This value is returned if the IO
+ * does not currently have an IO tag allocated to it.
+ * @retval All return other values indicate a legitimate tag.
+ */
+U16 scic_io_request_get_io_tag(
+ SCI_IO_REQUEST_HANDLE_T scic_io_request
+);
+
+/**
+ * @brief This method will inform the user of the protocol with which
+ * the supplied IO request was created.
+ *
+ * @param[in] scic_io_request This parameter specifies the IO request
+ * for which to retrieve the protocol.
+ *
+ * @return This method returns the transport protocol utilized for the
+ * the supplied request. Please refer to SCIC_TRANSPORT_PROTOCOL
+ * for more information.
+ */
+SCIC_TRANSPORT_PROTOCOL scic_io_request_get_protocol(
+ SCI_IO_REQUEST_HANDLE_T scic_io_request
+);
+
+/**
+ * @brief 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.
+ *
+ * @param[in] scic_io_request This parameter specifies the handle to the
+ * io request object to which to assign the ncq tag.
+ * @param[in] 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.
+ *
+ * @return none
+ *
+ * @note This function is only valid for SATA NCQ requests.
+ */
+void scic_stp_io_request_set_ncq_tag(
+ SCI_IO_REQUEST_HANDLE_T scic_io_request,
+ U16 ncq_tag
+);
+
+/**
+ * @brief This method will return the address of the host to device register
+ * fis region for the io request object.
+ *
+ * @param[in] scic_io_request This parameter specifies the handle to the io
+ * request object from which to get the host to device register fis
+ * buffer.
+ *
+ * @return The address of the host to device register fis buffer in the io
+ * request object.
+ *
+ * @note This function is only valid for SATA requests.
+ */
+void * scic_stp_io_request_get_h2d_reg_address(
+ SCI_IO_REQUEST_HANDLE_T scic_io_request
+);
+
+/**
+ * @brief This method will return the address of the device to host register
+ * fis region for the io request object.
+ *
+ * @param[in] scic_io_request This parameter specifies teh handle to the io
+ * request object from which to get the device to host register fis
+ * buffer.
+ *
+ * @return The address fo the device to host register fis ending the io
+ * request.
+ *
+ * @note This function is only valid for SATA requests.
+ */
+void * scic_stp_io_request_get_d2h_reg_address(
+ SCI_IO_REQUEST_HANDLE_T scic_io_request
+);
+
+/**
+ * @brief This method will return the rx frame for the io request object that
+ * contains the given offset.
+ *
+ * @param[in] scic_io_request This parameter specifies the handle to the io
+ * request object which has received the frame data.
+ * @param[in] offset This parameter specifies which frame is being requested.
+ *
+ * @return The return is a pointer to the frame buffer data.
+ *
+ * @note Frame buffers are only 1024 bytes in size. Reading past the end of a
+ * frame will have unexpected results.
+ */
+void * scic_io_request_get_rx_frame(
+ SCI_IO_REQUEST_HANDLE_T scic_io_request,
+ U32 offset
+);
+
+/**
+ * @brief This method will return the number of bytes transferred from the SCU
+ *
+ * @param[in] 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
+ *
+ * @return 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 (
+ SCI_IO_REQUEST_HANDLE_T scic_io_request
+);
+
+#ifdef __cplusplus
+}
+#endif // __cplusplus
+
+#endif // _SCIC_IO_REQUEST_H_
+
diff --git a/sys/dev/isci/scil/scic_library.h b/sys/dev/isci/scil/scic_library.h
new file mode 100644
index 0000000..269ffd7
--- /dev/null
+++ b/sys/dev/isci/scil/scic_library.h
@@ -0,0 +1,275 @@
+/*-
+ * 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.
+ *
+ * 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.
+ *
+ * $FreeBSD$
+ */
+#ifndef _SCIC_LIBRARY_H_
+#define _SCIC_LIBRARY_H_
+
+/**
+ * @file
+ *
+ * @brief This file contains all of the interface methods that can be called
+ * by an SCI Core user on the library object. The library is the
+ * container of all other objects being managed (i.e. controllers,
+ * target devices, sas ports, etc.).
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif // __cplusplus
+
+#include <dev/isci/scil/sci_types.h>
+#include <dev/isci/scil/sci_status.h>
+
+
+/**
+ * @enum _SCIC_LIBRARY_IO_MODE
+ * @brief This enumeration depicts the different IO modes in which the SCI
+ * library and it's controllers can operate.
+ */
+typedef enum _SCIC_LIBRARY_IO_MODE
+{
+ /**
+ * In this mode the SCI library will operate in a polling mode for
+ * operations. In other words, the library will not return from a
+ * send io method until the completion for the IO has been received.
+ */
+ SCIC_IO_MODE_POLLING,
+
+ /**
+ * In this mode the SCI library returns after committing the IO request
+ * to the controller hardware. Completion of the request will occur
+ * asynchronously.
+ */
+ SCIC_IO_MODE_ASYNCHRONOUS
+
+} SCIC_LIBRARY_IO_MODE;
+
+
+struct sci_pci_common_header;
+
+/**
+ * @brief This method will contsruct the core library based on the supplied
+ * parameter information. By default, libraries are considered
+ * "ready" as soon as they are constructed.
+ *
+ * @param[in] library_memory a pointer to the memory at which the
+ * library object is located.
+ * @param[in] max_controller_count the maximum number of controllers that
+ * this library can manage.
+ *
+ * @return An opaque library handle to be used by the SCI user for all
+ * subsequent library operations.
+ */
+SCI_LIBRARY_HANDLE_T scic_library_construct(
+ void * library_memory,
+ U8 max_controller_count
+);
+
+/**
+ * This method sets the PCI header information required for proper
+ * controller object creation/allocation.
+ *
+ * @param[in] library the handle to the library object for which to allocate
+ * a controller.
+ * @param[in] pci_header a pointer to the pci header data for the pci
+ * device for which this library is being created.
+ *
+ * @return none
+ */
+void scic_library_set_pci_info(
+ SCI_LIBRARY_HANDLE_T library,
+ struct sci_pci_common_header * pci_header
+);
+
+/**
+ * @brief This method returns the size of the core library object.
+ *
+ * @param[in] max_controller_count the maximum number of controllers that
+ * this library can manage.
+ *
+ * @return a positive integer value indicating the size (in bytes) of the
+ * library object.
+ */
+U32 scic_library_get_object_size(
+ U8 max_controller_count
+);
+
+/**
+ *
+ *
+ */
+U8 scic_library_get_pci_device_controller_count(
+ SCI_LIBRARY_HANDLE_T library
+);
+
+/**
+ * @brief This method will allocate the next available core controller object
+ * that can be managed by this core library.
+ *
+ * @param[in] library the handle to the library object for which to allocate
+ * a controller.
+ * @param[out] new_controller This parameter specifies a pointer to the
+ * controller handle that was added to the library.
+
+ * @return Indicate if the controller was successfully allocated or if iti
+ * failed in some way.
+ * @retval SCI_SUCCESS if the controller was successfully allocated.
+ * @retval SCI_FAILURE_INSUFFICIENT_RESOURCES if the library has no more
+ * available controller objects to allocate.
+ */
+SCI_STATUS scic_library_allocate_controller(
+ SCI_LIBRARY_HANDLE_T library,
+ SCI_CONTROLLER_HANDLE_T * new_controller
+);
+
+/**
+ * @brief This method will attempt to free the supplied controller to the
+ * library.
+ *
+ * @param[in] library the handle to the library object for which to free
+ * a controller.
+ * @param[in] controller the handle to the controller object to be freed
+ * from the library.
+ *
+ * @return Indicate if the controller was successfully freed or if it failed
+ * in some way.
+ * @retval SCI_SUCCESS if the controller was successfully freed.
+ * @retval SCI_FAILURE_CONTROLLER_NOT_FOUND if the supplied controller is
+ * not managed by the supplied library.
+ */
+SCI_STATUS scic_library_free_controller(
+ SCI_LIBRARY_HANDLE_T library,
+ SCI_CONTROLLER_HANDLE_T controller
+);
+
+/**
+ * @brief This method returns the maximum size (in bytes) that an individual
+ * SGL element can address using this library.
+ *
+ * @note SGL size is restricted to the lowest common denominator across all
+ * controllers managed by the library.
+ * @todo Does the byte count have to be DWORD aligned?
+ *
+ * @param[in] library the handle to the library object for which to
+ * determine the maximum SGL size.
+ *
+ * @return Return the maximum size (in bytes) for an SGE for any controller
+ * managed by this library.
+ */
+U32 scic_library_get_max_sge_size(
+ SCI_LIBRARY_HANDLE_T library
+);
+
+/**
+ * @brief This method returns the maximum number of SGL elements for a
+ * single IO request using this library.
+ *
+ * @note SGE count is restricted to the lowest common denominator across all
+ * controllers managed by the library.
+ *
+ * @param[in] library the handle to the library object for which to
+ * determine the maximum number of SGEs per IO request.
+ *
+ * @return Return the maximum number of SGEs for an IO request for any
+ * controller in this library.
+ */
+U32 scic_library_get_max_sge_count(
+ SCI_LIBRARY_HANDLE_T library
+);
+
+/**
+ * @brief This method returns the maximum length for any IO request that
+ * can be handled by the underlying controllers
+ *
+ * @note IO length is restricted to the lowest common denominator across all
+ * controllers managed by the library.
+ *
+ * @param[in] library the handle to the library object for which to
+ * determine the maximum length for all IO requests.
+ *
+ * @return Return the maximum length for all IO requests for any
+ * controller in this library.
+ */
+U32 scic_library_get_max_io_length(
+ SCI_LIBRARY_HANDLE_T library
+);
+
+/**
+ * @brief This method returns the minimum number of timers needed. If the
+ * user supplies timers less then the number specified via this
+ * call, then the user runs the risk of improper operation.
+ *
+ * @return This method returns a value representing the minimum number of
+ * timers required by this framework implementation
+ */
+U16 scic_library_get_min_timer_count(
+ void
+);
+
+/**
+ * @brief This method returns the maximum number of timers that could
+ * be ever be in use by this component at a given time.
+ *
+ * @return This method returns a value representing the minimum number of
+ * timers required by this framework implementation
+ */
+U16 scic_library_get_max_timer_count(
+ void
+);
+
+#ifdef __cplusplus
+}
+#endif // __cplusplus
+
+#endif // _SCIC_LIBRARY_H_
+
diff --git a/sys/dev/isci/scil/scic_logger.h b/sys/dev/isci/scil/scic_logger.h
new file mode 100644
index 0000000..0a9e50b
--- /dev/null
+++ b/sys/dev/isci/scil/scic_logger.h
@@ -0,0 +1,136 @@
+/*-
+ * 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.
+ *
+ * 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.
+ *
+ * $FreeBSD$
+ */
+#ifndef _SCIC_LOGGER_H_
+#define _SCIC_LOGGER_H_
+
+/**
+ * @file
+ *
+ * @brief This file contains all of the SCI Core specific logger object
+ * constant definitions.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif // __cplusplus
+
+#include <dev/isci/scil/sci_logger.h>
+
+
+/* The following is a list of log objects for which log information can */
+/* be enabled or disabled. */
+
+/** Enables/disables logging specific to the library. */
+#define SCIC_LOG_OBJECT_LIBRARY 0x00000001
+
+/** Enables/disables logging specific to the controller. */
+#define SCIC_LOG_OBJECT_CONTROLLER 0x00000002
+
+/** Enables/disables logging specific to the sas port. */
+#define SCIC_LOG_OBJECT_PORT 0x00000004
+
+/** Enables/disables logging specific to the SAS phy. */
+#define SCIC_LOG_OBJECT_PHY 0x00000008
+
+/** Enables/disables logging specific to the SSP remote target. */
+#define SCIC_LOG_OBJECT_SSP_REMOTE_TARGET 0x00000010
+
+/** Enables/disables logging specific to the STP remote target. */
+#define SCIC_LOG_OBJECT_STP_REMOTE_TARGET 0x00000020
+
+/** Enables/disables logging specific to the SMP remote target. */
+#define SCIC_LOG_OBJECT_SMP_REMOTE_TARGET 0x00000040
+
+/** Enables/disables logging specific to the SMP remote initiator. */
+#define SCIC_LOG_OBJECT_SMP_REMOTE_INITIATOR 0x00000080
+
+/** Enables/disables logging specific to the SSP IO requests. */
+#define SCIC_LOG_OBJECT_SSP_IO_REQUEST 0x00000100
+
+/** Enables/disables logging specific to the STP IO requests. */
+#define SCIC_LOG_OBJECT_STP_IO_REQUEST 0x00000200
+
+/** Enables/disables logging specific to the SMP IO requests. */
+#define SCIC_LOG_OBJECT_SMP_IO_REQUEST 0x00000400
+
+/** Enables/disables logging specific to the SMP IO response. */
+#define SCIC_LOG_OBJECT_SMP_IO_RESPONSE 0x00000800
+
+/** Enables/disables logging specific to the initialization. */
+#define SCIC_LOG_OBJECT_INITIALIZATION 0x00001000
+
+/** Enables/disables logging specific to the SGPIO. */
+#define SCIC_LOG_OBJECT_SGPIO 0x00002000
+
+/** Enables/disables logging specific to staggered spin up. */
+#define SCIC_LOG_OBJECT_STAGGERED_SPIN_UP 0x00004000
+
+/** Enables/disables logging specific to the controller unsolicited frames. */
+#define SCIC_LOG_OBJECT_UNSOLICITED_FRAMES 0x00008000
+
+/** Enables/disables logging specific to the received controller events. */
+#define SCIC_LOG_OBJECT_RECEIVED_EVENTS 0x00010000
+
+/** Enables/disables logging specific to the controller completion queue */
+#define SCIC_LOG_OBJECT_COMPLETION_QUEUE 0x00020000
+
+/** Enables/disables logging specific to the task management requests. */
+#define SCIC_LOG_OBJECT_TASK_MANAGEMENT 0x00040000
+
+#ifdef __cplusplus
+}
+#endif // __cplusplus
+
+#endif // _SCIC_LOGGER_H_
+
diff --git a/sys/dev/isci/scil/scic_overview.h b/sys/dev/isci/scil/scic_overview.h
new file mode 100644
index 0000000..87216c8
--- /dev/null
+++ b/sys/dev/isci/scil/scic_overview.h
@@ -0,0 +1,88 @@
+/*-
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 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.
+ *
+ * $FreeBSD$
+ */
+#ifndef _SCIC_OVERVIEW_H_
+#define _SCIC_OVERVIEW_H_
+
+/**
+
+@page core_section SCI Core
+
+@section scic_introduction_section Introduction
+
+The Storage Controller Interface Core (SCIC) provides the underlying fundamental
+hardware abstractions required to implement a standard SAS/SATA storage driver.
+
+The following is a list of features that may be found in a core implementation:
+-# hardware interrupt handling
+-# hardware event handling
+-# hardware state machine handling
+-# IO and task management state machine handling
+-# Phy staggered spin up
+
+@image latex sci_core.eps "SCI Core Class Diagram" width=16cm
+
+@note
+For the SCU Driver Standard implementation of the SCI Core interface the
+following definitions should be used to augment the cardinalities described
+in the previous diagram:
+-# There are exactly 4 scic_phy objects in the scic_controller.
+-# There are exactly 4 scic_port objects in the scic_controller.
+-# There can be a maximum of 4 scic_phy objects managed in a single scic_port.
+-# The maximum number of supported controllers in a library is a truly flexible
+ value, but the likely maximum number is 4.
+
+*/
+
+#endif // _SCIC_OVERVIEW_H_
+
diff --git a/sys/dev/isci/scil/scic_phy.h b/sys/dev/isci/scil/scic_phy.h
new file mode 100644
index 0000000..754cf5d
--- /dev/null
+++ b/sys/dev/isci/scil/scic_phy.h
@@ -0,0 +1,462 @@
+/*-
+ * 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.
+ *
+ * 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.
+ *
+ * $FreeBSD$
+ */
+#ifndef _SCIC_PHY_H_
+#define _SCIC_PHY_H_
+
+/**
+ * @file
+ *
+ * @brief This file contains all of the interface methods that can be called
+ * by an SCIC user on a phy (SAS or SATA) object.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif // __cplusplus
+
+#include <dev/isci/scil/sci_types.h>
+#include <dev/isci/scil/sci_status.h>
+
+#include <dev/isci/scil/intel_sata.h>
+#include <dev/isci/scil/intel_sas.h>
+
+
+/**
+ * @struct SCIC_PHY_PROPERTIES
+ * @brief This structure defines the properties common to all phys
+ * that can be retrieved.
+ */
+typedef 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.
+ */
+ SCI_PORT_HANDLE_T owning_port;
+
+ /**
+ * This field specifies the maximum link rate for which this phy
+ * will negotiate.
+ */
+ SCI_SAS_LINK_RATE max_link_rate;
+
+ /**
+ * This field specifies the link rate at which the phy is
+ * currently operating.
+ */
+ SCI_SAS_LINK_RATE negotiated_link_rate;
+
+ /**
+ * This field indicates the identify address frame that will be
+ * transmitted to the connected phy.
+ */
+ SCI_SAS_IDENTIFY_ADDRESS_FRAME_T transmit_iaf;
+
+ /**
+ * This field specifies the index of the phy in relation to other
+ * phys within the controller. This index is zero relative.
+ */
+ U8 index;
+
+} SCIC_PHY_PROPERTIES_T;
+
+/**
+ * @struct SCIC_SAS_PHY_PROPERTIES
+ * @brief This structure defines the properties, specific to a
+ * SAS phy, that can be retrieved.
+ */
+typedef struct SCIC_SAS_PHY_PROPERTIES
+{
+ /**
+ * This field delineates the Identify Address Frame received
+ * from the remote end point.
+ */
+ SCI_SAS_IDENTIFY_ADDRESS_FRAME_T received_iaf;
+
+ /**
+ * This field delineates the Phy capabilities structure received
+ * from the remote end point.
+ */
+ SAS_CAPABILITIES_T received_capabilities;
+
+} SCIC_SAS_PHY_PROPERTIES_T;
+
+/**
+ * @struct SCIC_SATA_PHY_PROPERTIES
+ * @brief This structure defines the properties, specific to a
+ * SATA phy, that can be retrieved.
+ */
+typedef struct SCIC_SATA_PHY_PROPERTIES
+{
+ /**
+ * This field delineates the signature FIS received from the
+ * attached target.
+ */
+ SATA_FIS_REG_D2H_T signature_fis;
+
+ /**
+ * This field specifies to the user if a port selector is connected
+ * on the specified phy.
+ */
+ BOOL is_port_selector_present;
+
+} SCIC_SATA_PHY_PROPERTIES_T;
+
+/**
+ * @enum SCIC_PHY_COUNTER_ID
+ * @brief This enumeration depicts the various pieces of optional
+ * information that can be retrieved for a specific phy.
+ */
+typedef 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_DWORD,
+
+ /**
+ * 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_PHY_COUNTER_ID_T;
+
+/**
+ * @brief This method will enable the user to retrieve information
+ * common to all phys, such as: the negotiated link rate,
+ * the phy id, etc.
+ *
+ * @param[in] phy This parameter specifies the phy for which to retrieve
+ * the properties.
+ * @param[out] properties This parameter specifies the properties
+ * structure into which to copy the requested information.
+ *
+ * @return Indicate if the user specified a valid phy.
+ * @retval SCI_SUCCESS This value is returned if the specified phy was valid.
+ * @retval SCI_FAILURE_INVALID_PHY This value is returned if the specified phy
+ * is not valid. When this value is returned, no data is copied to the
+ * properties output parameter.
+ */
+SCI_STATUS scic_phy_get_properties(
+ SCI_PHY_HANDLE_T phy,
+ SCIC_PHY_PROPERTIES_T * properties
+);
+
+/**
+ * @brief 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.
+ *
+ * @param[in] phy this parameter specifies the phy for which to
+ * retrieve properties.
+ * @param[out] properties This parameter specifies the properties
+ * structure into which to copy the requested information.
+ *
+ * @return This method returns an indication as to whether the SAS
+ * phy properties were successfully retrieved.
+ * @retval SCI_SUCCESS This value is returned if the SAS properties
+ * are successfully retrieved.
+ * @retval SCI_FAILURE This value is returned if the SAS properties
+ * are not successfully retrieved (e.g. It's not a SAS Phy).
+ */
+SCI_STATUS scic_sas_phy_get_properties(
+ SCI_PHY_HANDLE_T phy,
+ SCIC_SAS_PHY_PROPERTIES_T * properties
+);
+
+/**
+ * @brief This method will enable the user to retrieve information
+ * specific to a SATA phy, such as: the recieved signature
+ * FIS, if a port selector is present, etc.
+ *
+ * @param[in] phy this parameter specifies the phy for which to
+ * retrieve properties.
+ * @param[out] properties This parameter specifies the properties
+ * structure into which to copy the requested information.
+ *
+ * @return This method returns an indication as to whether the SATA
+ * phy properties were successfully retrieved.
+ * @retval SCI_SUCCESS This value is returned if the SATA properties
+ * are successfully retrieved.
+ * @retval SCI_FAILURE This value is returned if the SATA properties
+ * are not successfully retrieved (e.g. It's not a SATA Phy).
+ */
+SCI_STATUS scic_sata_phy_get_properties(
+ SCI_PHY_HANDLE_T phy,
+ SCIC_SATA_PHY_PROPERTIES_T * properties
+);
+
+/**
+ * @brief This method allows the SCIC user to instruct the SCIC
+ * implementation to send the SATA port selection signal.
+ *
+ * @param[in] phy this parameter specifies the phy for which to send
+ * the port selection signal.
+ *
+ * @return An indication of whether the port selection signal was
+ * successfully executed.
+ * @retval SCI_SUCCESS This value is returned if the port selection signal
+ * was successfully transmitted.
+ */
+SCI_STATUS scic_sata_phy_send_port_selection_signal(
+ SCI_PHY_HANDLE_T phy
+);
+
+/**
+ * @brief This method requests the SCI implementation to begin tracking
+ * information specified by the supplied parameters.
+ *
+ * @param[in] phy this parameter specifies the phy for which to enable
+ * the information type.
+ * @param[in] counter_id this parameter specifies the information
+ * type to be enabled.
+ *
+ * @return Indicate if enablement of the information type was successful.
+ * @retval SCI_SUCCESS This value is returned if the information type was
+ * successfully enabled.
+ * @retval SCI_FAILURE_UNSUPPORTED_INFORMATION_FIELD This value is returned
+ * if the supplied information type is not supported.
+ */
+SCI_STATUS scic_phy_enable_counter(
+ SCI_PHY_HANDLE_T phy,
+ SCIC_PHY_COUNTER_ID_T counter_id
+);
+
+/**
+ * @brief This method requests the SCI implementation to stop tracking
+ * information specified by the supplied parameters.
+ *
+ * @param[in] phy this parameter specifies the phy for which to disable
+ * the information type.
+ * @param[in] counter_id this parameter specifies the information
+ * type to be disabled.
+ *
+ * @return Indicate if disablement of the information type was successful.
+ * @retval SCI_SUCCESS This value is returned if the information type was
+ * successfully disabled.
+ * @retval SCI_FAILURE_UNSUPPORTED_INFORMATION_FIELD This value is returned
+ * if the supplied information type is not supported.
+ */
+SCI_STATUS scic_phy_disable_counter(
+ SCI_PHY_HANDLE_T phy,
+ SCIC_PHY_COUNTER_ID_T counter_id
+);
+
+/**
+ * @brief This method requests the SCI implementation to retrieve
+ * tracking information specified by the supplied parameters.
+ *
+ * @param[in] phy this parameter specifies the phy for which to retrieve
+ * the information type.
+ * @param[in] counter_id this parameter specifies the information
+ * type to be retrieved.
+ * @param[out] data this parameter is a 32-bit pointer to a location
+ * where the data being retrieved is to be placed.
+ *
+ * @return Indicate if retrieval of the information type was successful.
+ * @retval SCI_SUCCESS This value is returned if the information type was
+ * successfully retrieved.
+ * @retval SCI_FAILURE_UNSUPPORTED_INFORMATION_FIELD This value is returned
+ * if the supplied information type is not supported.
+ */
+SCI_STATUS scic_phy_get_counter(
+ SCI_PHY_HANDLE_T phy,
+ SCIC_PHY_COUNTER_ID_T counter_id,
+ U32 * data
+);
+
+/**
+ * @brief This method requests the SCI implementation to clear (reset)
+ * tracking information specified by the supplied parameters.
+ *
+ * @param[in] phy this parameter specifies the phy for which to clear
+ * the information type.
+ * @param[in] counter_id this parameter specifies the information
+ * type to be cleared.
+ *
+ * @return Indicate if clearing of the information type was successful.
+ * @retval SCI_SUCCESS This value is returned if the information type was
+ * successfully cleared.
+ * @retval SCI_FAILURE_UNSUPPORTED_INFORMATION_FIELD This value is returned
+ * if the supplied information type is not supported.
+ */
+SCI_STATUS scic_phy_clear_counter(
+ SCI_PHY_HANDLE_T phy,
+ SCIC_PHY_COUNTER_ID_T counter_id
+);
+
+/**
+ * @brief This method will attempt to stop the phy object.
+ *
+ * @param[in] this_phy
+ *
+ * @return SCI_STATUS
+ * @retval SCI_SUCCESS if the phy is going to stop
+ * SCI_INVALID_STATE if the phy is not in a valid state
+ * to stop
+ */
+SCI_STATUS scic_phy_stop(
+ SCI_PHY_HANDLE_T phy
+);
+
+/**
+ * @brief This method will attempt to start the phy object. This
+ * request is only valid when the phy is in the stopped
+ * state
+ *
+ * @param[in] this_phy
+ *
+ * @return SCI_STATUS
+ */
+SCI_STATUS scic_phy_start(
+ SCI_PHY_HANDLE_T phy
+);
+
+#ifdef __cplusplus
+}
+#endif // __cplusplus
+
+#endif // _SCIC_PHY_H_
+
diff --git a/sys/dev/isci/scil/scic_port.h b/sys/dev/isci/scil/scic_port.h
new file mode 100644
index 0000000..4c4ee05
--- /dev/null
+++ b/sys/dev/isci/scil/scic_port.h
@@ -0,0 +1,239 @@
+/*-
+ * 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.
+ *
+ * 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.
+ *
+ * $FreeBSD$
+ */
+#ifndef _SCIC_PORT_H_
+#define _SCIC_PORT_H_
+
+/**
+ * @file
+ *
+ * @brief This file contains all of the interface methods that can be called
+ * by an SCI Core user on a SAS or SATA port.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif // __cplusplus
+
+#include <dev/isci/scil/sci_types.h>
+#include <dev/isci/scil/sci_status.h>
+#include <dev/isci/scil/intel_sas.h>
+
+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
+ * @brief This structure defines the properties that can be retrieved
+ * for each end-point local or remote (attached) port in the
+ * controller.
+ */
+typedef struct SCIC_PORT_END_POINT_PROPERTIES
+{
+ /**
+ * This field indicates the SAS address for the associated end
+ * point in the port.
+ */
+ SCI_SAS_ADDRESS_T sas_address;
+
+ /**
+ * This field indicates the protocols supported by the associated
+ * end-point in the port.
+ */
+ SCI_SAS_IDENTIFY_ADDRESS_FRAME_PROTOCOLS_T protocols;
+
+} SCIC_PORT_END_POINT_PROPERTIES_T;
+
+/**
+ * @struct SCIC_PORT_PROPERTIES
+ * @brief This structure defines the properties that can be retrieved
+ * for each port in the controller.
+ */
+typedef 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.
+ */
+ SCIC_PORT_END_POINT_PROPERTIES_T local;
+
+ /**
+ * This field indicates the remote (attached) end-point properties
+ * for the port.
+ */
+ SCIC_PORT_END_POINT_PROPERTIES_T remote;
+
+ /**
+ * This field specifies the phys contained inside the port.
+ */
+ U32 phy_mask;
+
+} SCIC_PORT_PROPERTIES_T;
+
+/**
+ * @brief This method simply returns the properties regarding the
+ * port, such as: physical index, protocols, sas address, etc.
+ *
+ * @param[in] port this parameter specifies the port for which to retrieve
+ * the physical index.
+ * @param[out] properties This parameter specifies the properties
+ * structure into which to copy the requested information.
+ *
+ * @return Indicate if the user specified a valid port.
+ * @retval SCI_SUCCESS This value is returned if the specified port was valid.
+ * @retval 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.
+ */
+SCI_STATUS scic_port_get_properties(
+ SCI_PORT_HANDLE_T port,
+ SCIC_PORT_PROPERTIES_T * properties
+);
+
+/**
+ * @brief This method will add a phy to an existing port.
+ *
+ * @param[in] port This parameter specifies the port in which to add a new
+ * phy.
+ * @param[in] phy This parameter specifies the phy to be added to the port.
+ *
+ * @return Indicate if the phy was successfully added to the port.
+ * @retval SCI_SUCCESS This value is returned if the phy was successfully
+ * added to the port.
+ * @retval SCI_FAILURE_INVALID_PORT This value is returned if the supplied
+ * port is not valid.
+ * @retval SCI_FAILURE_INVALID_PHY This value is returned if the supplied
+ * phy is either invalid or already contained in another port.
+ */
+SCI_STATUS scic_port_add_phy(
+ SCI_PORT_HANDLE_T port,
+ SCI_PHY_HANDLE_T phy
+);
+
+/**
+ * @brief This method will remove a phy from an existing port.
+ *
+ * @param[in] port This parameter specifies the port in which to remove a
+ * phy.
+ * @param[in] phy This parameter specifies the phy to be removed from the
+ * port.
+ *
+ * @return Indicate if the phy was successfully removed from the port.
+ * @retval SCI_SUCCESS This value is returned if the phy was successfully
+ * removed from the port.
+ * @retval SCI_FAILURE_INVALID_PORT This value is returned if the supplied
+ * port is not valid.
+ * @retval SCI_FAILURE_INVALID_PHY This value is returned if the supplied
+ * phy is either invalid or
+ * not contained in the port.
+ */
+SCI_STATUS scic_port_remove_phy(
+ SCI_PORT_HANDLE_T port,
+ SCI_PHY_HANDLE_T phy
+);
+
+/**
+ * @brief 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.
+ *
+ * @note 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.
+ *
+ * @param[in] port a handle corresponding to the SAS port to be
+ * hard reset.
+ * @param[in] reset_timeout This parameter specifies the number of
+ * milliseconds in which the port reset operation should complete.
+ *
+ * @return Return a status indicating whether the hard reset started
+ * successfully.
+ * @retval SCI_SUCCESS This value is returned if the hard reset operation
+ * started successfully.
+ */
+SCI_STATUS scic_port_hard_reset(
+ SCI_PORT_HANDLE_T port,
+ U32 reset_timeout
+);
+
+/**
+ * @brief This API method enables the broadcast change notification from
+ * underneath hardware.
+ *
+ * @param[in] port The port upon which broadcast change notifications
+ * (BCN) are to be enabled.
+ *
+ * @return none
+ */
+void scic_port_enable_broadcast_change_notification(
+ SCI_PORT_HANDLE_T port
+);
+
+#ifdef __cplusplus
+}
+#endif // __cplusplus
+
+#endif // _SCIC_PORT_H_
+
diff --git a/sys/dev/isci/scil/scic_remote_device.h b/sys/dev/isci/scil/scic_remote_device.h
new file mode 100644
index 0000000..9abd04d
--- /dev/null
+++ b/sys/dev/isci/scil/scic_remote_device.h
@@ -0,0 +1,442 @@
+/*-
+ * 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.
+ *
+ * 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.
+ *
+ * $FreeBSD$
+ */
+#ifndef _SCIC_REMOTE_DEVICE_H_
+#define _SCIC_REMOTE_DEVICE_H_
+
+/**
+ * @file
+ *
+ * @brief This file contains all of the interface methods that can be called
+ * by an SCIC user on the device object.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif // __cplusplus
+
+#include <dev/isci/scil/sci_types.h>
+#include <dev/isci/scil/sci_status.h>
+#include <dev/isci/scil/intel_sas.h>
+
+
+/**
+ * @brief
+ */
+typedef 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_NOT_READY_REASON_CODE_T;
+
+/**
+ * @brief This method simply returns the maximum memory space needed to
+ * store a remote device object.
+ *
+ * @return a positive integer value indicating the size (in bytes) of the
+ * remote device object.
+ */
+U32 scic_remote_device_get_object_size(
+ void
+);
+
+/**
+ * @brief This method will perform the construction common to all
+ * remote device objects.
+ *
+ * @note 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.
+ * @note
+ *
+ * @param[in] port This parameter specifies the SAS/SATA Port handle
+ * corresponding to the port through which this device
+ * is to be accessed.
+ * @param[in] remote_device_memory This parameter specifies the memory
+ * location to be used by the SCIC implementation to store the
+ * SCIC REMOTE DEVICE.
+ * @param[out] new_remote_device_handle An opaque remote device handle to
+ * be used by the SCIC user for all subsequent remote device
+ * operations.
+ *
+ * @return none
+ */
+void scic_remote_device_construct(
+ SCI_PORT_HANDLE_T port,
+ void * remote_device_memory,
+ SCI_REMOTE_DEVICE_HANDLE_T * new_remote_device_handle
+);
+
+/**
+ * @brief 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.
+ *
+ * @pre The user must have previously called scic_remote_device_construct()
+ *
+ * @note 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.
+ *
+ * @param[in] remote_device This parameter specifies the remote device to be
+ * destructed.
+ *
+ * @return Indicate if the remote device was successfully constructed.
+ * @retval SCI_SUCCESS Returned if the device was successfully constructed.
+ * @retval 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().
+ * @retval 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.
+ * @retval SCI_FAILURE_INSUFFICIENT_RESOURCES This value is returned if
+ * the core controller associated with the supplied parameters
+ * is unable to support additional remote devices.
+ */
+SCI_STATUS scic_remote_device_da_construct(
+ SCI_REMOTE_DEVICE_HANDLE_T remote_device
+);
+
+/**
+ * @brief This method will construct an SCIC_REMOTE_DEVICE object for an
+ * expander attached (ea) device from an SMP Discover Response.
+ *
+ * @pre The user must have previously called scic_remote_device_construct()
+ *
+ * @note 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.
+ *
+ * @param[in] remote_device This parameter specifies the remote device to be
+ * destructed.
+ * @param[in] discover_response This parameter specifies the SMP
+ * Discovery Response to be used in device creation.
+ *
+ * @return Indicate if the remote device was successfully constructed.
+ * @retval SCI_SUCCESS Returned if the device was successfully constructed.
+ * @retval 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().
+ * @retval 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.
+ * @retval SCI_FAILURE_INSUFFICIENT_RESOURCES This value is returned if
+ * the core controller associated with the supplied parameters
+ * is unable to support additional remote devices.
+ */
+SCI_STATUS scic_remote_device_ea_construct(
+ SCI_REMOTE_DEVICE_HANDLE_T remote_device,
+ SMP_RESPONSE_DISCOVER_T * discover_response
+);
+
+/**
+ * @brief This method is utilized to free up a core's remote device object.
+ *
+ * @note 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.
+ *
+ * @param[in] remote_device This parameter specifies the remote device to be
+ * destructed.
+ *
+ * @return The return value shall indicate if the device was successfully
+ * destructed or if some failure occurred.
+ * @retval SCI_STATUS This value is returned if the device is successfully
+ * destructed.
+ * @retval 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.).
+ */
+SCI_STATUS scic_remote_device_destruct(
+ SCI_REMOTE_DEVICE_HANDLE_T remote_device
+);
+
+#if !defined(DISABLE_WIDE_PORTED_TARGETS)
+/**
+ * @brief This method will attempt to set port width for a remote device.
+ *
+ * @param[in] remote_device This parameter specifies the remote device
+ * object for which to set new port width.
+ * @param[in] new_port_width The new port width to update.
+ *
+ * @return Indicate if the device port width was successfully updated.
+ * @retval SCI_SUCCESS This value is returned when port width update was successful.
+ * @retval SCI_FAILURE The port width update failed.
+ */
+SCI_STATUS scic_remote_device_set_port_width(
+ SCI_REMOTE_DEVICE_HANDLE_T remote_device,
+ U8 new_port_width
+);
+
+/**
+ * @brief This method retrieve the SCIC's record of a remote device's port width.
+ *
+ * @param[in] remote_device This parameter specifies the remote device
+ * object for which to retrieve the port width value.
+ *
+ * @return The SCIC's record of a remote device's port width
+ */
+U8 scic_remote_device_get_port_width(
+ SCI_REMOTE_DEVICE_HANDLE_T remote_device
+);
+
+#define scic_remote_device_da_add_phy(device, phy) SCI_FAILURE
+#define scic_remote_device_ea_add_phy(device, response) SCI_FAILURE
+#define scic_remote_device_remove_phy(device) SCI_FAILURE
+
+#else // !defined(DISABLE_WIDE_PORTED_TARGETS)
+
+#define scic_remote_device_set_port_width(device, port_width) SCI_FAILURE
+#define scic_remote_device_get_port_width(device) (1)
+
+#define scic_remote_device_da_add_phy(device, phy) SCI_FAILURE
+#define scic_remote_device_ea_add_phy(device, response) SCI_FAILURE
+#define scic_remote_device_remove_phy(device) SCI_FAILURE
+
+#endif // !defined(DISABLE_WIDE_PORTED_TARGETS)
+
+/**
+ * @brief This method will start the supplied remote device. This method
+ * enables normal IO requests to flow through to the remote device.
+ *
+ * @param[in] remote_device This parameter specifies the device to be
+ * started.
+ * @param[in] timeout This parameter specifies the number of milliseconds
+ * in which the start operation should complete.
+ *
+ * @return An indication of whether the device was successfully started.
+ * @retval SCI_SUCCESS This value is returned if the device was successfully
+ * started.
+ * @retval 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.
+ */
+SCI_STATUS scic_remote_device_start(
+ SCI_REMOTE_DEVICE_HANDLE_T remote_device,
+ U32 timeout
+);
+
+/**
+ * @brief 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.
+ *
+ * @param[in] remote_device This parameter specifies the device to be
+ * stopped.
+ * @param[in] timeout This parameter specifies the number of milliseconds
+ * in which the stop operation should complete.
+ *
+ * @return An indication of whether the device was successfully stopped.
+ * @retval SCI_SUCCESS This value is returned if the transmission and reception
+ * for the device was successfully stopped.
+ */
+SCI_STATUS scic_remote_device_stop(
+ SCI_REMOTE_DEVICE_HANDLE_T remote_device,
+ U32 timeout
+);
+
+/**
+ * @brief 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.
+ *
+ * @note 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.
+ *
+ * @param[in] remote_device This parameter specifies the device to be
+ * reset.
+ *
+ * @return An indication of whether the device reset was accepted.
+ * @retval SCI_SUCCESS This value is returned if the device reset is started.
+ */
+SCI_STATUS scic_remote_device_reset(
+ SCI_REMOTE_DEVICE_HANDLE_T remote_device
+);
+
+/**
+ * @brief This method informs the device object that the reset operation is
+ * complete and the device can resume operation again.
+ *
+ * @param[in] remote_device This parameter specifies the device which is to
+ * be informed of the reset complete operation.
+ *
+ * @return An indication that the device is resuming operation.
+ * @retval SCI_SUCCESS the device is resuming operation.
+ */
+SCI_STATUS scic_remote_device_reset_complete(
+ SCI_REMOTE_DEVICE_HANDLE_T remote_device
+);
+
+/**
+ * @brief This method returns the suggested target reset timeout. SAS and
+ * SATA devices have different timeout values in milliseconds for
+ * target reset operations.
+ *
+ * @param[in] remote_device This parameter specifies the device which is to
+ * be informed of the reset complete operation.
+ *
+ * @return The suggested reset timeout value for the specified target device
+ * in milliseconds.
+ */
+U32 scic_remote_device_get_suggested_reset_timeout(
+ SCI_REMOTE_DEVICE_HANDLE_T remote_device
+);
+
+/**
+ * @brief This method will set the maximum link speed to be utilized
+ * when connections are established for the supplied remote device.
+ *
+ * @pre The remote device must previously have been stopped for this
+ * call to succeed.
+ *
+ * @param[in] remote_device This parameter specifies the device for which
+ * to set the maximum connection rate.
+ * @param[in] connection_rate This parameter specifies the maximum link rate
+ * to be utilized for all connections to the supplied remote
+ * device.
+ *
+ * @return An indication as to whether the connection rate was successfully
+ * updated.
+ * @retval SCI_SUCCESS This value is returned if the connection rate was
+ * successfully updated.
+ * @retval SCI_FAILURE_INVALID_STATE This value is returned if the remote
+ * device is not in a stopped state or some other state that allows
+ * for a maximum connection rate change.
+ */
+SCI_STATUS scic_remote_device_set_max_connection_rate(
+ SCI_REMOTE_DEVICE_HANDLE_T remote_device,
+ SCI_SAS_LINK_RATE connection_rate
+);
+
+/**
+ * @brief This method simply returns the link rate at which communications
+ * to the remote device occur.
+ *
+ * @param[in] remote_device This parameter specifies the device for which
+ * to get the connection rate.
+ *
+ * @return Return the link rate at which we transfer for the supplied
+ * remote device.
+ */
+SCI_SAS_LINK_RATE scic_remote_device_get_connection_rate(
+ SCI_REMOTE_DEVICE_HANDLE_T remote_device
+);
+
+/**
+ * @brief This method will indicate which protocols are supported by this
+ * remote device.
+ *
+ * @param[in] remote_device This parameter specifies the device for which
+ * to return the protocol.
+ * @param[out] protocols This parameter specifies the output values, from
+ * the remote device object, which indicate the protocols
+ * supported by the supplied remote_device.
+ *
+ * @return 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(
+ SCI_REMOTE_DEVICE_HANDLE_T remote_device,
+ SMP_DISCOVER_RESPONSE_PROTOCOLS_T * protocols
+);
+
+/**
+ * @brief This method will indicate the SAS address for the remote device.
+ *
+ * @param[in] remote_device This parameter specifies the device for which
+ * to return the SAS address.
+ * @param[out] sas_address This parameter specifies a pointer to a SAS
+ * address structure into which the core will copy the SAS
+ * address for the remote device.
+ *
+ * @return none
+ */
+void scic_remote_device_get_sas_address(
+ SCI_REMOTE_DEVICE_HANDLE_T remote_device,
+ SCI_SAS_ADDRESS_T * sas_address
+);
+
+#if !defined(DISABLE_ATAPI)
+/**
+ * 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.
+ *
+ * @param[in] this_device The device whose type is to be decided.
+ *
+ * @return BOOL Indicate a device is ATAPI device or not.
+ */
+BOOL scic_remote_device_is_atapi(
+ SCI_REMOTE_DEVICE_HANDLE_T device_handle
+);
+#else // !defined(DISABLE_ATAPI)
+#define scic_remote_device_is_atapi(device_handle) FALSE
+#endif // !defined(DISABLE_ATAPI)
+
+#ifdef __cplusplus
+}
+#endif // __cplusplus
+
+#endif // _SCIC_REMOTE_DEVICE_H_
+
diff --git a/sys/dev/isci/scil/scic_sds_controller.c b/sys/dev/isci/scil/scic_sds_controller.c
new file mode 100644
index 0000000..1fc7b92
--- /dev/null
+++ b/sys/dev/isci/scil/scic_sds_controller.c
@@ -0,0 +1,7042 @@
+/*-
+ * 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.
+ *
+ * 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 <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/**
+ * @file
+ *
+ * @brief This file contains the implementation of the SCIC_SDS_CONTROLLER
+ * public, protected, and private methods.
+ */
+
+#include <dev/isci/types.h>
+#include <dev/isci/scil/sci_util.h>
+#include <dev/isci/scil/scic_controller.h>
+#include <dev/isci/scil/scic_port.h>
+#include <dev/isci/scil/scic_phy.h>
+#include <dev/isci/scil/scic_remote_device.h>
+#include <dev/isci/scil/scic_user_callback.h>
+#include <dev/isci/scil/scic_sds_pci.h>
+#include <dev/isci/scil/scic_sds_library.h>
+#include <dev/isci/scil/scic_sds_controller.h>
+#include <dev/isci/scil/scic_sds_controller_registers.h>
+#include <dev/isci/scil/scic_sds_port.h>
+#include <dev/isci/scil/scic_sds_phy.h>
+#include <dev/isci/scil/scic_sds_remote_device.h>
+#include <dev/isci/scil/scic_sds_request.h>
+#include <dev/isci/scil/scic_sds_logger.h>
+#include <dev/isci/scil/scic_sds_port_configuration_agent.h>
+#include <dev/isci/scil/scu_constants.h>
+#include <dev/isci/scil/scu_event_codes.h>
+#include <dev/isci/scil/scu_completion_codes.h>
+#include <dev/isci/scil/scu_task_context.h>
+#include <dev/isci/scil/scu_remote_node_context.h>
+#include <dev/isci/scil/scu_unsolicited_frame.h>
+#include <dev/isci/scil/intel_pci.h>
+#include <dev/isci/scil/scic_sgpio.h>
+#include <dev/isci/scil/scic_sds_phy_registers.h>
+
+#define SCU_CONTEXT_RAM_INIT_STALL_TIME 200
+#define SCIC_SDS_CONTROLLER_MIN_TIMER_COUNT 3
+#define SCIC_SDS_CONTROLLER_MAX_TIMER_COUNT 3
+
+#define SCU_MAX_ZPT_DWORD_INDEX 131
+
+/**
+ * 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
+
+/**
+ * This macro will return the cycle bit of the completion queue entry
+ */
+#define COMPLETION_QUEUE_CYCLE_BIT(x) ((x) & 0x80000000)
+
+/**
+ * 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)
+
+/**
+ * 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)
+
+
+/**
+ * This macro will normalize the completion queue cycle pointer so it
+ * matches the completion queue cycle bit
+ */
+#define NORMALIZE_GET_POINTER_CYCLE_BIT(x) \
+ (((U32)(SMU_CQGR_CYCLE_BIT & (x))) << (31 - SMU_COMPLETION_QUEUE_GET_CYCLE_BIT_SHIFT))
+
+/**
+ * This macro will normalize the completion queue event entry so its value
+ * can be used as an index.
+ */
+#define NORMALIZE_EVENT_POINTER(x) \
+ ( \
+ ((U32)((x) & SMU_COMPLETION_QUEUE_GET_EVENT_POINTER_MASK)) \
+ >> SMU_COMPLETION_QUEUE_GET_EVENT_POINTER_SHIFT \
+ )
+
+/**
+ * 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 \
+ )
+
+/**
+ * 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 \
+ )
+
+//****************************************************************************-
+//* SCIC SDS Controller Initialization Methods
+//****************************************************************************-
+
+/**
+ * @brief This timer is used to start another phy after we have given up on
+ * the previous phy to transition to the ready state.
+ *
+ * @param[in] controller
+ */
+static
+void scic_sds_controller_phy_startup_timeout_handler(
+ void *controller
+)
+{
+ SCI_STATUS status;
+ SCIC_SDS_CONTROLLER_T *this_controller;
+ this_controller = (SCIC_SDS_CONTROLLER_T *)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.
+ *
+ * @param this_controller
+ */
+static
+SCI_STATUS scic_sds_controller_initialize_phy_startup(
+ SCIC_SDS_CONTROLLER_T *this_controller
+)
+{
+ this_controller->phy_startup_timer = scic_cb_timer_create(
+ this_controller,
+ scic_sds_controller_phy_startup_timeout_handler,
+ this_controller
+ );
+
+ if (this_controller->phy_startup_timer == NULL)
+ {
+ return SCI_FAILURE_INSUFFICIENT_RESOURCES;
+ }
+ else
+ {
+ this_controller->next_phy_to_start = 0;
+ this_controller->phy_startup_timer_pending = FALSE;
+ }
+
+ return SCI_SUCCESS;
+}
+
+/**
+ * This method initializes the power control operations for the controller
+ * object.
+ *
+ * @param this_controller
+ */
+void scic_sds_controller_initialize_power_control(
+ SCIC_SDS_CONTROLLER_T *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;
+ this_controller->power_control.remote_devices_granted_power = 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)
+
+// ---------------------------------------------------------------------------
+
+/**
+ * @brief This method builds the memory descriptor table for this
+ * controller.
+ *
+ * @param[in] this_controller This parameter specifies the controller
+ * object for which to build the memory table.
+ *
+ * @return none
+ */
+void scic_sds_controller_build_memory_descriptor_table(
+ SCIC_SDS_CONTROLLER_T *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(SCU_REMOTE_NODE_CONTEXT_T),
+ 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(SCU_TASK_CONTEXT_T),
+ 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
+ );
+}
+
+/**
+ * @brief This method validates the driver supplied memory descriptor
+ * table.
+ *
+ * @param[in] this_controller
+ *
+ * @return SCI_STATUS
+ */
+SCI_STATUS scic_sds_controller_validate_memory_descriptor_table(
+ SCIC_SDS_CONTROLLER_T *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(SCU_REMOTE_NODE_CONTEXT_T),
+ 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(SCU_TASK_CONTEXT_T),
+ 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;
+}
+
+/**
+ * @brief This method initializes the controller with the physical memory
+ * addresses that are used to communicate with the driver.
+ *
+ * @param[in] this_controller
+ *
+ * @return none
+ */
+void scic_sds_controller_ram_initialization(
+ SCIC_SDS_CONTROLLER_T *this_controller
+)
+{
+ SCI_PHYSICAL_MEMORY_DESCRIPTOR_T *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 = (SCU_REMOTE_NODE_CONTEXT_T *)
+ 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 = (SCU_TASK_CONTEXT_T *)
+ 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);
+
+ //enable the ECC correction and detection.
+ SCU_SECR0_WRITE(
+ this_controller,
+ (SIGNLE_BIT_ERROR_CORRECTION_ENABLE
+ | MULTI_BIT_ERROR_REPORTING_ENABLE
+ | SINGLE_BIT_ERROR_REPORTING_ENABLE) );
+ SCU_SECR1_WRITE(
+ this_controller,
+ (SIGNLE_BIT_ERROR_CORRECTION_ENABLE
+ | MULTI_BIT_ERROR_REPORTING_ENABLE
+ | SINGLE_BIT_ERROR_REPORTING_ENABLE) );
+}
+
+/**
+ * @brief This method initializes the task context data for the controller.
+ *
+ * @param[in] this_controller
+ *
+ * @return none
+ */
+void scic_sds_controller_assign_task_entries(
+ SCIC_SDS_CONTROLLER_T *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);
+}
+
+/**
+ * @brief This method initializes the hardware completion queue.
+ *
+ * @param[in] this_controller
+ */
+void scic_sds_controller_initialize_completion_queue(
+ SCIC_SDS_CONTROLLER_T *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);
+
+ this_controller->completion_queue_get = 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;
+ }
+}
+
+/**
+ * @brief This method initializes the hardware unsolicited frame queue.
+ *
+ * @param[in] this_controller
+ */
+void scic_sds_controller_initialize_unsolicited_frame_queue(
+ SCIC_SDS_CONTROLLER_T *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);
+}
+
+/**
+ * @brief This method enables the hardware port task scheduler.
+ *
+ * @param[in] this_controller
+ */
+void scic_sds_controller_enable_port_task_scheduler(
+ SCIC_SDS_CONTROLLER_T *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);
+}
+
+// ---------------------------------------------------------------------------
+
+#ifdef ARLINGTON_BUILD
+/**
+ * This method will read from the lexington status register. This is required
+ * as a read fence to the lexington register writes.
+ *
+ * @param this_controller
+ */
+void scic_sds_controller_lex_status_read_fence(
+ SCIC_SDS_CONTROLLER_T *this_controller
+)
+{
+ U32 lex_status;
+
+ // Read Fence
+ lex_status = lex_register_read(
+ this_controller, this_controller->lex_registers + 0xC4);
+
+ SCIC_LOG_TRACE((
+ sci_base_object_get_logger(this_controller),
+ SCIC_LOG_OBJECT_CONTROLLER,
+ "Controller 0x%x lex_status = 0x%08x\n",
+ this_controller, lex_status
+ ));
+}
+
+/**
+ * This method will initialize the arlington through the LEX_BAR.
+ *
+ * @param this_controller
+ */
+void scic_sds_controller_lex_atux_initialization(
+ SCIC_SDS_CONTROLLER_T *this_controller
+)
+{
+ // 1. Reset all SCU PHY
+ lex_register_write(
+ this_controller, this_controller->lex_registers + 0x28, 0x0020FFFF) ;
+
+ // 2. Write to LEX_CTRL
+ lex_register_write(
+ this_controller, this_controller->lex_registers + 0xC0, 0x00000700);
+
+ scic_sds_controller_lex_status_read_fence(this_controller);
+
+ // 3. Enable PCI Master
+ lex_register_write(
+ this_controller, this_controller->lex_registers + 0x70, 0x00000002);
+
+ // 4. Enable SCU Register Clock Domain
+ lex_register_write(
+ this_controller, this_controller->lex_registers + 0xC0, 0x00000300);
+
+ scic_sds_controller_lex_status_read_fence(this_controller);
+
+ // 5.1 Release PHY-A Reg Reset
+ lex_register_write(
+ this_controller, this_controller->lex_registers + 0x28, 0x0000FFFF);
+
+ // 5.2 Initialize the AFE for PHY-A
+ scic_sds_controller_afe_initialization(this_controller);
+
+ scic_sds_controller_lex_status_read_fence(this_controller);
+
+#if 0
+ // 5.3 Release PHY Reg Reset
+ lex_register_write(
+ this_controller, this_controller->lex_registers + 0x28, 0x0000FFFF);
+#endif
+
+ // 6.1 Release PHY-B Reg Reset
+ lex_register_write(
+ this_controller, this_controller->lex_registers + 0x28, 0x0040FFFF) ;
+
+ // 6.2 Initialize the AFE for PHY-B
+ scic_sds_controller_afe_initialization(this_controller);
+
+ scic_sds_controller_lex_status_read_fence(this_controller);
+
+#if 0
+ // 6.3 Release PHY-B Reg Reset
+ lex_register_write(
+ this_controller, this_controller->lex_registers + 0x28, 0x0040FFFF) ;
+#endif
+
+ // 7. Enable SCU clock domaion
+ lex_register_write(
+ this_controller, this_controller->lex_registers + 0xC0, 0x00000100);
+
+ scic_sds_controller_lex_status_read_fence(this_controller);
+
+ // 8. Release LEX SCU Reset
+ lex_register_write(
+ this_controller, this_controller->lex_registers + 0xC0, 0x00000000);
+
+ scic_sds_controller_lex_status_read_fence(this_controller);
+
+#if !defined(DISABLE_INTERRUPTS)
+ // 8a. Set legacy interrupts (SCU INTx to PCI-x INTA)
+ lex_register_write(
+ this_controller, this_controller->lex_registers + 0xC0, 0x00000800);
+
+ scic_sds_controller_lex_status_read_fence(this_controller);
+#endif
+
+#if 0
+ // 9. Override TXOLVL
+ //write to lex_ctrl
+ lex_register_write(
+ this_controller, this_controller->lex_registers + 0xC0, 0x27800000);
+#endif
+
+ // 10. Release PHY-A & PHY-B Resets
+ lex_register_write(
+ this_controller, this_controller->lex_registers + 0x28, 0x0000FF77);
+
+ lex_register_write(
+ this_controller, this_controller->lex_registers + 0x28, 0x0000FF55);
+
+ lex_register_write(
+ this_controller, this_controller->lex_registers + 0x28, 0x0000FF11);
+
+ lex_register_write(
+ this_controller, this_controller->lex_registers + 0x28, 0x0000FF00);
+
+ lex_register_write(
+ this_controller, this_controller->lex_registers + 0x28, 0x0003FF00);
+}
+#endif // ARLINGTON_BUILD
+
+// ---------------------------------------------------------------------------
+
+#ifdef ARLINGTON_BUILD
+/**
+ * This method enables chipwatch on the arlington board
+ *
+ * @param[in] this_controller
+ */
+void scic_sds_controller_enable_chipwatch(
+ SCIC_SDS_CONTROLLER_T *this_controller
+)
+{
+ lex_register_write(
+ this_controller, this_controller->lex_registers + 0x88, 0x09090909);
+
+ lex_register_write(
+ this_controller, this_controller->lex_registers + 0x8C, 0xcac9c862);
+}
+#endif
+
+/**
+ * This macro is used to delay between writes to the AFE registers
+ * during AFE initialization.
+ */
+#define AFE_REGISTER_WRITE_DELAY 10
+
+/**
+ * Initialize the AFE for this phy index.
+ *
+ * @todo We need to read the AFE setup from the OEM parameters
+ *
+ * @param[in] this_controller
+ *
+ * @return none
+ */
+#if defined(ARLINGTON_BUILD)
+void scic_sds_controller_afe_initialization(
+ SCIC_SDS_CONTROLLER_T *this_controller
+)
+{
+ // 1. Establish Power
+ // Hold Bias, PLL, and RX TX in reset and powerdown
+ // pe_afe0_rst_n = 0
+ // pe_afe0_txpdn0,1,2,3 = 1
+ // pe_afe0_rxpdn0,1,2,3 = 1
+ // pe_afe0_txrst0,1,2,3_n = 0
+ // pe_afe0_rxrst0,1,2,3_n = 0
+ // wait 1us
+ // pe_afe0_rst_n = 1
+ // wait 1us
+ scu_afe_register_write(
+ this_controller, afe_pll_control, 0x00247506);
+
+ // 2. Write 0x00000000 to AFE XCVR Ctrl2
+ scu_afe_register_write(
+ this_controller, afe_dfx_transceiver_status_clear, 0x00000000);
+
+ // 3. afe0_override_en = 0
+ // afe0_pll_dis_override = 0
+ // afe0_tx_rst_override = 0
+ // afe0_pll_dis = 1
+ // pe_afe0_txrate = 01
+ // pe_afe0_rxrate = 01
+ // pe_afe0_txdis = 11
+ // pe_afe0_txoob = 1
+ // pe_afe0_txovlv = 9'b001110000
+ scu_afe_register_write(
+ this_controller, afe_transceiver_control0[0], 0x0700141e);
+
+ // 4. Configure PLL Unit
+ // Write 0x00200506 to AFE PLL Ctrl Register 0
+ scu_afe_register_write(this_controller, afe_pll_control, 0x00200506);
+ scu_afe_register_write(this_controller, afe_pll_dfx_control, 0x10000080);
+
+ // 5. Configure Bias Unit
+ scu_afe_register_write(this_controller, afe_bias_control[0], 0x00124814);
+ scu_afe_register_write(this_controller, afe_bias_control[1], 0x24900000);
+
+ // 6. Configure Transceiver Units
+ scu_afe_register_write(
+ this_controller, afe_transceiver_control0[0], 0x0702941e);
+
+ scu_afe_register_write(
+ this_controller, afe_transceiver_control1[0], 0x0000000a);
+
+ // 7. Configure RX Units
+ scu_afe_register_write(
+ this_controller, afe_transceiver_equalization_control[0], 0x00ba2223);
+
+ scu_afe_register_write(
+ this_controller, reserved_0028_003c[2], 0x00000000);
+
+ // 8. Configure TX Units
+ scu_afe_register_write(
+ this_controller, afe_dfx_transmit_control_register[0], 0x03815428);
+
+ // 9. Transfer control to PE signals
+ scu_afe_register_write(
+ this_controller, afe_dfx_transceiver_status_clear, 0x00000010);
+
+ // 10. Release PLL Powerdown
+ scu_afe_register_write(this_controller, afe_pll_control, 0x00200504);
+
+ // 11. Release PLL Reset
+ scu_afe_register_write(this_controller, afe_pll_control, 0x00200505);
+
+ // 12. Wait for PLL to Lock
+ // (afe0_comm_sta [1:0] should go to 1'b11, and
+ // [5:2] is 0x5, 0x6, 0x7, 0x8, or 0x9
+ scu_afe_register_write(this_controller, afe_pll_control, 0x00200501);
+
+ while ((scu_afe_register_read(this_controller, afe_common_status) & 0x03) != 0x03)
+ {
+ // Give time for the PLLs to lock
+ scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY);
+ }
+
+ // 13. pe_afe0_rxpdn0 = 0
+ // pe_afe0_rxrst0 = 1
+ // pe_afe0_txrst0_n = 1
+ // pe_afe_txoob0_n = 0
+ scu_afe_register_write(
+ this_controller, afe_transceiver_control0[0], 0x07028c11);
+}
+
+#elif defined(PLEASANT_RIDGE_BUILD)
+
+void scic_sds_controller_afe_initialization(
+ SCIC_SDS_CONTROLLER_T *this_controller
+)
+{
+ U32 afe_status;
+ U32 phy_id;
+
+#if defined(SPREADSHEET_AFE_SETTINGS)
+ // Clear DFX Status registers
+ scu_afe_register_write(
+ this_controller, afe_dfx_master_control0, 0x0000000f);
+ // Configure bias currents to normal
+ scu_afe_register_write(
+ this_controller, afe_bias_control, 0x0000aa00);
+ // Enable PLL
+ scu_afe_register_write(
+ this_controller, afe_pll_control0, 0x80000908);
+
+ // Wait for the PLL to lock
+ do
+ {
+ scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY);
+ afe_status = scu_afe_register_read(
+ this_controller, afe_common_block_status);
+ }
+ while((afe_status & 0x00001000) == 0);
+
+ for (phy_id = 0; phy_id < SCI_MAX_PHYS; phy_id++)
+ {
+ // Initialize transceiver channels
+ scu_afe_register_write(
+ this_controller, scu_afe_xcvr[phy_id].afe_channel_control, 0x00000157);
+ // Configure transceiver modes
+ scu_afe_register_write(
+ this_controller, scu_afe_xcvr[phy_id].afe_xcvr_control0, 0x38016d1a);
+ // Configure receiver parameters
+ scu_afe_register_write(
+ this_controller, scu_afe_xcvr[phy_id].afe_xcvr_control1, 0x01501014);
+ // Configure transmitter parameters
+ scu_afe_register_write(
+ this_controller, scu_afe_xcvr[phy_id].afe_tx_control, 0x00000000);
+ // Configure transmitter equalization
+ scu_afe_register_write(
+ this_controller, scu_afe_xcvr[phy_id].afe_tx_amp_control0, 0x000bdd08);
+ scu_afe_register_write(
+ this_controller, scu_afe_xcvr[phy_id].afe_tx_amp_control1, 0x000ffc00);
+ scu_afe_register_write(
+ this_controller, scu_afe_xcvr[phy_id].afe_tx_amp_control2, 0x000b7c09);
+ scu_afe_register_write(
+ this_controller, scu_afe_xcvr[phy_id].afe_tx_amp_control3, 0x000afc6e);
+ // Configure transmitter SSC parameters
+ scu_afe_register_write(
+ this_controller, scu_afe_xcvr[phy_id].afe_tx_ssc_control, 0x00000000);
+ // Configure receiver parameters
+ scu_afe_register_write(
+ this_controller, scu_afe_xcvr[phy_id].afe_rx_ssc_control0, 0x3208903f);
+
+ // Start power on sequence
+ // Enable bias currents to transceivers and wait 200ns
+ scu_afe_register_write(
+ this_controller, scu_afe_xcvr[phy_id].afe_channel_control, 0x00000154);
+ scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY);
+ // Take receiver out of power down and wait 200ns
+ scu_afe_register_write(
+ this_controller, scu_afe_xcvr[phy_id].afe_xcvr_control0, 0x3801611a);
+ scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY);
+ // Take receiver out of reset and wait 200ns
+ scu_afe_register_write(
+ this_controller, scu_afe_xcvr[phy_id].afe_xcvr_control0, 0x3801631a);
+ scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY);
+ // Take transmitter out of power down and wait 200ns
+ scu_afe_register_write(
+ this_controller, scu_afe_xcvr[phy_id].afe_xcvr_control0, 0x38016318);
+ scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY);
+ // Take transmitter out of reset and wait 200ns
+ scu_afe_register_write(
+ this_controller, scu_afe_xcvr[phy_id].afe_xcvr_control0, 0x38016319);
+ scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY);
+ // Take transmitter out of DC idle
+ scu_afe_register_write(
+ this_controller, scu_afe_xcvr[phy_id].afe_xcvr_control0, 0x38016319);
+ scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY);
+ }
+
+ // Transfer control to the PEs
+ scu_afe_register_write(
+ this_controller, afe_dfx_master_control0, 0x00010f00);
+#else // !defined(SPREADSHEET_AFE_SETTINGS)
+ // These are the AFEE settings used by the SV group
+ // Clear DFX Status registers
+ scu_afe_register_write(
+ this_controller, afe_dfx_master_control0, 0x0081000f);
+ // Configure bias currents to normal
+ scu_afe_register_write(
+ this_controller, afe_bias_control, 0x0000aa00);
+ // Enable PLL
+ scu_afe_register_write(
+ this_controller, afe_pll_control0, 0x80000908);
+
+ // Wait for the PLL to lock
+ // Note: this is done later in the SV shell script however this looks
+ // like the location to do this since we have enabled the PLL.
+ do
+ {
+ scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY);
+ afe_status = scu_afe_register_read(
+ this_controller, afe_common_block_status);
+ }
+ while((afe_status & 0x00001000) == 0);
+
+ // Make sure BIST is disabled
+ scu_afe_register_write(
+ this_controller, afe_dfx_master_control1, 0x00000000);
+ // Shorten SAS SNW lock time
+ scu_afe_register_write(
+ this_controller, afe_pmsn_master_control0, 0x7bd316ad);
+
+ for (phy_id = 0; phy_id < SCI_MAX_PHYS; phy_id++)
+ {
+ // Initialize transceiver channels
+ scu_afe_register_write(
+ this_controller, scu_afe_xcvr[phy_id].afe_channel_control, 0x00000174);
+ // Configure SSC control
+ scu_afe_register_write(
+ this_controller, scu_afe_xcvr[phy_id].afe_tx_ssc_control, 0x00030000);
+ // Configure transceiver modes
+ scu_afe_register_write(
+ this_controller, scu_afe_xcvr[phy_id].afe_xcvr_control0, 0x0000651a);
+ // Power up TX RX and RX OOB
+ scu_afe_register_write(
+ this_controller, scu_afe_xcvr[phy_id].afe_xcvr_control0, 0x00006518);
+ // Enable RX OOB Detect
+ scu_afe_register_write(
+ this_controller, scu_afe_xcvr[phy_id].afe_xcvr_control0, 0x00006518);
+ scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY);
+ #if 0
+ // Configure transmitter parameters
+ scu_afe_register_write(
+ this_controller, scu_afe_xcvr[phy_id].afe_tx_control, 0x00000000);
+ // Configure transmitter equalization
+ scu_afe_register_write(
+ this_controller, scu_afe_xcvr[phy_id].afe_tx_amp_control0, 0x000bdd08);
+ scu_afe_register_write(
+ this_controller, scu_afe_xcvr[phy_id].afe_tx_amp_control1, 0x000ffc00);
+ scu_afe_register_write(
+ this_controller, scu_afe_xcvr[phy_id].afe_tx_amp_control2, 0x000b7c09);
+ scu_afe_register_write(
+ this_controller, scu_afe_xcvr[phy_id].afe_tx_amp_control3, 0x000afc6e);
+ // Configure transmitter SSC parameters
+ // Power up TX RX
+
+ scu_afe_register_write(
+ this_controller, scu_afe_xcvr[phy_id].afe_channel_control, 0x00000154);
+ scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY);
+
+ // FFE = Max
+ scu_afe_register_write(
+ this_controller, scu_afe_xcvr[phy_id].afe_dfx_rx_control1, 0x00000080);
+ // DFE1-5 = small
+ scu_afe_register_write(
+ this_controller, scu_afe_xcvr[phy_id].afe_dfx_rx_control1, 0x01041042);
+ // Enable DFE/FFE and freeze
+ scu_afe_register_write(
+ this_controller, scu_afe_xcvr[phy_id].afe_rx_ssc_control0, 0x320891bf);
+ #endif
+ // Take receiver out of power down and wait 200ns
+ scu_afe_register_write(
+ this_controller, scu_afe_xcvr[phy_id].afe_xcvr_control0, 0x00006118);
+ scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY);
+ // TX Electrical Idle
+ scu_afe_register_write(
+ this_controller, scu_afe_xcvr[phy_id].afe_xcvr_control0, 0x00006108);
+ scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY);
+
+ // Leave DFE/FFE on
+ scu_afe_register_write(
+ this_controller, scu_afe_xcvr[phy_id].afe_rx_ssc_control0, 0x0317108f);
+
+ // Configure receiver parameters
+ scu_afe_register_write(
+ this_controller, scu_afe_xcvr[phy_id].afe_xcvr_control1, 0x01e00021);
+
+ // Bring RX out of reset
+ scu_afe_register_write(
+ this_controller, scu_afe_xcvr[phy_id].afe_xcvr_control0, 0x00006109);
+ scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY);
+
+ scu_afe_register_write(
+ this_controller, scu_afe_xcvr[phy_id].afe_xcvr_control0, 0x00006009);
+ scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY);
+
+ scu_afe_register_write(
+ this_controller, scu_afe_xcvr[phy_id].afe_xcvr_control0, 0x00006209);
+ scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY);
+ }
+
+ // Transfer control to the PEs
+ scu_afe_register_write(
+ this_controller, afe_dfx_master_control0, 0x00010f00);
+#endif
+}
+
+#elif defined(PBG_HBA_A0_BUILD) || defined(PBG_HBA_A2_BUILD) || defined(PBG_HBA_BETA_BUILD) || defined(PBG_BUILD)
+
+void scic_sds_controller_afe_initialization(
+ SCIC_SDS_CONTROLLER_T *this_controller
+)
+{
+ U32 afe_status;
+ U32 phy_id;
+ U8 cable_selection_mask;
+
+ if (
+ (this_controller->pci_revision != SCIC_SDS_PCI_REVISION_A0)
+ && (this_controller->pci_revision != SCIC_SDS_PCI_REVISION_A2)
+ && (this_controller->pci_revision != SCIC_SDS_PCI_REVISION_B0)
+ && (this_controller->pci_revision != SCIC_SDS_PCI_REVISION_C0)
+ && (this_controller->pci_revision != SCIC_SDS_PCI_REVISION_C1)
+ )
+ {
+ // A programming bug has occurred if we are attempting to
+ // support a PCI revision other than those listed. Default
+ // to B0, and attempt to limp along if it isn't B0.
+ ASSERT(FALSE);
+ this_controller->pci_revision = SCIC_SDS_PCI_REVISION_C1;
+ }
+
+ cable_selection_mask =
+ this_controller->oem_parameters.sds1.controller.cable_selection_mask;
+
+ // These are the AFEE settings used by the SV group
+ // Clear DFX Status registers
+ scu_afe_register_write(
+ this_controller, afe_dfx_master_control0, 0x0081000f);
+ scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY);
+
+ if (
+ (this_controller->pci_revision == SCIC_SDS_PCI_REVISION_B0)
+ || (this_controller->pci_revision == SCIC_SDS_PCI_REVISION_C0)
+ || (this_controller->pci_revision == SCIC_SDS_PCI_REVISION_C1)
+ )
+ {
+ // PM Rx Equalization Save, PM SPhy Rx Acknowledgement Timer, PM Stagger Timer
+ scu_afe_register_write(
+ this_controller, afe_pmsn_master_control2, 0x0007FFFF);
+ scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY);
+ }
+
+ // Configure bias currents to normal
+ if (this_controller->pci_revision == SCIC_SDS_PCI_REVISION_A0)
+ scu_afe_register_write(this_controller, afe_bias_control, 0x00005500);
+ else if (this_controller->pci_revision == SCIC_SDS_PCI_REVISION_A2)
+ scu_afe_register_write(this_controller, afe_bias_control, 0x00005A00);
+ else if ( (this_controller->pci_revision == SCIC_SDS_PCI_REVISION_B0)
+ || (this_controller->pci_revision == SCIC_SDS_PCI_REVISION_C0) )
+ scu_afe_register_write(this_controller, afe_bias_control, 0x00005F00);
+ else if (this_controller->pci_revision == SCIC_SDS_PCI_REVISION_C1)
+ scu_afe_register_write(this_controller, afe_bias_control, 0x00005500);
+ // For C0 the AFE BIAS Controll is unchanged
+
+ scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY);
+
+ // Enable PLL
+ if ( (this_controller->pci_revision == SCIC_SDS_PCI_REVISION_A0)
+ || (this_controller->pci_revision == SCIC_SDS_PCI_REVISION_A2) )
+ {
+ scu_afe_register_write(this_controller, afe_pll_control0, 0x80040908);
+ }
+ else if ( (this_controller->pci_revision == SCIC_SDS_PCI_REVISION_B0)
+ || (this_controller->pci_revision == SCIC_SDS_PCI_REVISION_C0) )
+ {
+ scu_afe_register_write(this_controller, afe_pll_control0, 0x80040A08);
+ }
+ else if (this_controller->pci_revision == SCIC_SDS_PCI_REVISION_C1)
+ {
+ scu_afe_register_write(this_controller, afe_pll_control0, 0x80000b08);
+ scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY);
+ scu_afe_register_write(this_controller, afe_pll_control0, 0x00000b08);
+ scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY);
+ scu_afe_register_write(this_controller, afe_pll_control0, 0x80000b08);
+ }
+
+ scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY);
+
+ // Wait for the PLL to lock
+ // Note: this is done later in the SV shell script however this looks
+ // like the location to do this since we have enabled the PLL.
+ do
+ {
+ afe_status = scu_afe_register_read(
+ this_controller, afe_common_block_status);
+ scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY);
+ }
+ while((afe_status & 0x00001000) == 0);
+
+ if ( (this_controller->pci_revision == SCIC_SDS_PCI_REVISION_A0)
+ || (this_controller->pci_revision == SCIC_SDS_PCI_REVISION_A2) )
+ {
+ // Shorten SAS SNW lock time (RxLock timer value from 76 us to 50 us)
+ scu_afe_register_write(
+ this_controller, afe_pmsn_master_control0, 0x7bcc96ad);
+ scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY);
+ }
+
+ for (phy_id = 0; phy_id < SCI_MAX_PHYS; phy_id++)
+ {
+ U8 cable_length_long = (cable_selection_mask >> phy_id) & 1;
+ U8 cable_length_medium = (cable_selection_mask >> (phy_id + 4)) & 1;
+
+ if ( (this_controller->pci_revision == SCIC_SDS_PCI_REVISION_A0)
+ || (this_controller->pci_revision == SCIC_SDS_PCI_REVISION_A2) )
+ {
+ // All defaults, except the Receive Word Alignament/Comma Detect
+ // Enable....(0xe800)
+ scu_afe_register_write(
+ this_controller, scu_afe_xcvr[phy_id].afe_xcvr_control0, 0x00004512
+ );
+ scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY);
+
+ scu_afe_register_write(
+ this_controller, scu_afe_xcvr[phy_id].afe_xcvr_control1, 0x0050100F
+ );
+ scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY);
+ }
+ else if (this_controller->pci_revision == SCIC_SDS_PCI_REVISION_B0)
+ {
+ // Configure transmitter SSC parameters
+ scu_afe_register_write(
+ this_controller, scu_afe_xcvr[phy_id].afe_tx_ssc_control, 0x00030000
+ );
+ scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY);
+ }
+ else if (this_controller->pci_revision == SCIC_SDS_PCI_REVISION_C0)
+ {
+ // Configure transmitter SSC parameters
+ scu_afe_register_write(
+ this_controller, scu_afe_xcvr[phy_id].afe_tx_ssc_control, 0x00010202
+ );
+ scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY);
+
+ // All defaults, except the Receive Word Alignament/Comma Detect
+ // Enable....(0xe800)
+ scu_afe_register_write(
+ this_controller, scu_afe_xcvr[phy_id].afe_xcvr_control0, 0x00014500
+ );
+ scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY);
+ }
+ else if (this_controller->pci_revision == SCIC_SDS_PCI_REVISION_C1)
+ {
+ // Configure transmitter SSC parameters
+ scu_afe_register_write(
+ this_controller, scu_afe_xcvr[phy_id].afe_tx_ssc_control, 0x00010202
+ );
+ scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY);
+
+ // All defaults, except the Receive Word Alignament/Comma Detect
+ // Enable....(0xe800)
+ scu_afe_register_write(
+ this_controller, scu_afe_xcvr[phy_id].afe_xcvr_control0, 0x0001C500
+ );
+ 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 (this_controller->pci_revision == SCIC_SDS_PCI_REVISION_A0)
+ {
+ scu_afe_register_write(
+ this_controller,
+ scu_afe_xcvr[phy_id].afe_channel_control,
+ 0x000003D4
+ );
+ }
+ else if (this_controller->pci_revision == SCIC_SDS_PCI_REVISION_A2)
+ {
+ scu_afe_register_write(
+ this_controller,
+ scu_afe_xcvr[phy_id].afe_channel_control,
+ 0x000003F0
+ );
+ }
+ else if (this_controller->pci_revision == SCIC_SDS_PCI_REVISION_B0)
+ {
+ // Power down TX and RX (PWRDNTX and PWRDNRX)
+ scu_afe_register_write(
+ this_controller,
+ scu_afe_xcvr[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_register_write(
+ this_controller,
+ scu_afe_xcvr[phy_id].afe_channel_control,
+ 0x000003d4
+ );
+ }
+ else if (this_controller->pci_revision == SCIC_SDS_PCI_REVISION_C0)
+ {
+ scu_afe_register_write(
+ this_controller,
+ scu_afe_xcvr[phy_id].afe_channel_control,
+ 0x000001e7
+ );
+
+ 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_register_write(
+ this_controller,
+ scu_afe_xcvr[phy_id].afe_channel_control,
+ 0x000001e4
+ );
+ }
+ else if (this_controller->pci_revision == SCIC_SDS_PCI_REVISION_C1)
+ {
+ scu_afe_register_write(
+ this_controller,
+ scu_afe_xcvr[phy_id].afe_channel_control,
+ cable_length_long ? 0x000002F7 :
+ cable_length_medium ? 0x000001F7 : 0x000001F7
+ );
+
+ 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_register_write(
+ this_controller,
+ scu_afe_xcvr[phy_id].afe_channel_control,
+ cable_length_long ? 0x000002F4 :
+ cable_length_medium ? 0x000001F4 : 0x000001F4
+ );
+ }
+
+ scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY);
+
+ if ( (this_controller->pci_revision == SCIC_SDS_PCI_REVISION_A0)
+ || (this_controller->pci_revision == SCIC_SDS_PCI_REVISION_A2) )
+ {
+ // Enable TX equalization (0xe824)
+ scu_afe_register_write(
+ this_controller,
+ scu_afe_xcvr[phy_id].afe_tx_control,
+ 0x00040000
+ );
+ scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY);
+ }
+
+ if ( (this_controller->pci_revision == SCIC_SDS_PCI_REVISION_A0)
+ || (this_controller->pci_revision == SCIC_SDS_PCI_REVISION_A2)
+ || (this_controller->pci_revision == SCIC_SDS_PCI_REVISION_B0) )
+ {
+ // RDPI=0x0(RX Power On), RXOOBDETPDNC=0x0, TPD=0x0(TX Power On),
+ // RDD=0x0(RX Detect Enabled) ....(0xe800)
+ scu_afe_register_write(
+ this_controller, scu_afe_xcvr[phy_id].afe_xcvr_control0, 0x00004100);
+ scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY);
+ }
+ else if (this_controller->pci_revision == SCIC_SDS_PCI_REVISION_C0)
+ {
+ scu_afe_register_write(
+ this_controller, scu_afe_xcvr[phy_id].afe_xcvr_control0, 0x00014100);
+ scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY);
+ }
+ else if (this_controller->pci_revision == SCIC_SDS_PCI_REVISION_C1)
+ {
+ scu_afe_register_write(
+ this_controller, scu_afe_xcvr[phy_id].afe_xcvr_control0, 0x0001c100);
+ scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY);
+ }
+
+ // Leave DFE/FFE on
+ if (this_controller->pci_revision == SCIC_SDS_PCI_REVISION_A0)
+ {
+ scu_afe_register_write(
+ this_controller,
+ scu_afe_xcvr[phy_id].afe_rx_ssc_control0,
+ 0x3F09983F
+ );
+ }
+ else if (this_controller->pci_revision == SCIC_SDS_PCI_REVISION_A2)
+ {
+ scu_afe_register_write(
+ this_controller,
+ scu_afe_xcvr[phy_id].afe_rx_ssc_control0,
+ 0x3F11103F
+ );
+ }
+ else if (this_controller->pci_revision == SCIC_SDS_PCI_REVISION_B0)
+ {
+ scu_afe_register_write(
+ this_controller,
+ scu_afe_xcvr[phy_id].afe_rx_ssc_control0,
+ 0x3F11103F
+ );
+ scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY);
+
+ // Enable TX equalization (0xe824)
+ scu_afe_register_write(
+ this_controller, scu_afe_xcvr[phy_id].afe_tx_control, 0x00040000);
+ }
+ else if (this_controller->pci_revision == SCIC_SDS_PCI_REVISION_C0)
+ {
+ scu_afe_register_write(
+ this_controller, scu_afe_xcvr[phy_id].afe_xcvr_control1, 0x01400c0f);
+ scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY);
+
+ scu_afe_register_write(
+ this_controller, scu_afe_xcvr[phy_id].afe_rx_ssc_control0, 0x3f6f103f);
+ scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY);
+
+ // Enable TX equalization (0xe824)
+ scu_afe_register_write(
+ this_controller, scu_afe_xcvr[phy_id].afe_tx_control, 0x00040000);
+ }
+ else if (this_controller->pci_revision == SCIC_SDS_PCI_REVISION_C1)
+ {
+ scu_afe_register_write(
+ this_controller, scu_afe_xcvr[phy_id].afe_xcvr_control1,
+ cable_length_long ? 0x01500C0C :
+ cable_length_medium ? 0x01400C0D : 0x02400C0D
+ );
+ scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY);
+
+ scu_afe_register_write(
+ this_controller, scu_afe_xcvr[phy_id].afe_dfx_rx_control1, 0x000003e0);
+ scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY);
+
+ scu_afe_register_write(
+ this_controller, scu_afe_xcvr[phy_id].afe_rx_ssc_control0,
+ cable_length_long ? 0x33091C1F :
+ cable_length_medium ? 0x3315181F : 0x2B17161F
+ );
+ scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY);
+
+ // Enable TX equalization (0xe824)
+ scu_afe_register_write(
+ this_controller, scu_afe_xcvr[phy_id].afe_tx_control, 0x00040000);
+ }
+
+ scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY);
+
+ scu_afe_register_write(
+ this_controller, scu_afe_xcvr[phy_id].afe_tx_amp_control0,
+ this_controller->oem_parameters.sds1.phys[phy_id].afe_tx_amp_control0
+ );
+ scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY);
+
+ scu_afe_register_write(
+ this_controller, scu_afe_xcvr[phy_id].afe_tx_amp_control1,
+ this_controller->oem_parameters.sds1.phys[phy_id].afe_tx_amp_control1
+ );
+ scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY);
+
+ scu_afe_register_write(
+ this_controller, scu_afe_xcvr[phy_id].afe_tx_amp_control2,
+ this_controller->oem_parameters.sds1.phys[phy_id].afe_tx_amp_control2
+ );
+ scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY);
+
+ scu_afe_register_write(
+ this_controller, scu_afe_xcvr[phy_id].afe_tx_amp_control3,
+ this_controller->oem_parameters.sds1.phys[phy_id].afe_tx_amp_control3
+ );
+ scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY);
+ }
+
+ // Transfer control to the PEs
+ scu_afe_register_write(
+ this_controller, afe_dfx_master_control0, 0x00010f00);
+ scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY);
+}
+#else
+ #error "Unsupported board type"
+#endif
+
+//****************************************************************************-
+//* SCIC SDS Controller Internal Start/Stop Routines
+//****************************************************************************-
+
+
+/**
+ * @brief 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.
+ *
+ * @param[in,out] this_controller This parameter indicates the controller
+ * object for which to transition to ready.
+ * @param[in] status This parameter indicates the status value to be
+ * pass into the call to scic_cb_controller_start_complete().
+ *
+ * @return none.
+ */
+static
+void scic_sds_controller_transition_to_ready(
+ SCIC_SDS_CONTROLLER_T *this_controller,
+ SCI_STATUS status
+)
+{
+ SCIC_LOG_TRACE((
+ sci_base_object_get_logger(this_controller),
+ SCIC_LOG_OBJECT_CONTROLLER,
+ "scic_sds_controller_transition_to_ready(0x%x, 0x%x) enter\n",
+ this_controller, 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);
+ }
+}
+
+/**
+ * @brief This method is the general timeout handler for the controller.
+ * It will take the correct timetout action based on the current
+ * controller state
+ *
+ * @param[in] controller This parameter indicates the controller on which
+ * a timeout occurred.
+ *
+ * @return none
+ */
+void scic_sds_controller_timeout_handler(
+ SCI_CONTROLLER_HANDLE_T controller
+)
+{
+ SCI_BASE_CONTROLLER_STATES current_state;
+ SCIC_SDS_CONTROLLER_T *this_controller;
+ this_controller = (SCIC_SDS_CONTROLLER_T *)controller;
+
+ current_state = sci_base_state_machine_get_state(
+ scic_sds_controller_get_base_state_machine(this_controller)
+ );
+
+ if (current_state == SCI_BASE_CONTROLLER_STATE_STARTING)
+ {
+ scic_sds_controller_transition_to_ready(
+ this_controller, 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(this_controller),
+ SCI_BASE_CONTROLLER_STATE_FAILED
+ );
+
+ scic_cb_controller_stop_complete(controller, SCI_FAILURE_TIMEOUT);
+ }
+ else
+ {
+ /// @todo Now what do we want to do in this case?
+ SCIC_LOG_ERROR((
+ sci_base_object_get_logger(this_controller),
+ SCIC_LOG_OBJECT_CONTROLLER,
+ "Controller timer fired when controller was not in a state being timed.\n"
+ ));
+ }
+}
+
+/**
+ * @brief
+ *
+ * @param[in] this_controller
+ *
+ * @return SCI_STATUS
+ */
+SCI_STATUS scic_sds_controller_stop_ports(
+ SCIC_SDS_CONTROLLER_T *this_controller
+)
+{
+ U32 index;
+ SCI_STATUS status;
+ SCI_STATUS port_status;
+
+ status = SCI_SUCCESS;
+
+ for (index = 0; index < this_controller->logical_port_entries; index++)
+ {
+ port_status = this_controller->port_table[index].
+ state_handlers->parent.stop_handler(&this_controller->port_table[index].parent);
+ if (
+ (port_status != SCI_SUCCESS)
+ && (port_status != SCI_FAILURE_INVALID_STATE)
+ )
+ {
+ status = SCI_FAILURE;
+
+ SCIC_LOG_WARNING((
+ sci_base_object_get_logger(this_controller),
+ SCIC_LOG_OBJECT_CONTROLLER | SCIC_LOG_OBJECT_PORT,
+ "Controller stop operation failed to stop port %d because of status %d.\n",
+ this_controller->port_table[index].logical_port_index, port_status
+ ));
+ }
+ }
+
+ return status;
+}
+
+/**
+ * @brief
+ *
+ * @param[in] this_controller
+ */
+static
+void scic_sds_controller_phy_timer_start(
+ SCIC_SDS_CONTROLLER_T *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;
+}
+
+/**
+ * @brief
+ *
+ * @param[in] this_controller
+ */
+void scic_sds_controller_phy_timer_stop(
+ SCIC_SDS_CONTROLLER_T *this_controller
+)
+{
+ scic_cb_timer_stop(
+ this_controller,
+ this_controller->phy_startup_timer
+ );
+
+ this_controller->phy_startup_timer_pending = FALSE;
+}
+
+/**
+ * @brief This method is called internally to determine whether the
+ * controller start process is complete. This is only true when:
+ * - 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.
+ *
+ * @param[in] this_controller This parameter specifies the controller
+ * object for which to start the next phy.
+ *
+ * @return BOOL
+ */
+BOOL scic_sds_controller_is_start_complete(
+ SCIC_SDS_CONTROLLER_T *this_controller
+)
+{
+ U8 index;
+
+ for (index = 0; index < SCI_MAX_PHYS; index++)
+ {
+ SCIC_SDS_PHY_T *the_phy = & this_controller->phy_table[index];
+
+ if (
+ (
+ this_controller->oem_parameters.sds1.controller.mode_type
+ == SCIC_PORT_AUTOMATIC_CONFIGURATION_MODE
+ )
+ || (
+ (
+ this_controller->oem_parameters.sds1.controller.mode_type
+ == SCIC_PORT_MANUAL_CONFIGURATION_MODE
+ )
+ && (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)
+ )
+ || (
+ this_controller->port_agent.phy_ready_mask
+ != this_controller->port_agent.phy_configured_mask
+ )
+ )
+ {
+ return FALSE;
+ }
+ }
+ }
+
+ return TRUE;
+}
+
+/**
+ * @brief 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()).
+ *
+ * @param[in] this_controller This parameter specifies the controller
+ * object for which to start the next phy.
+ *
+ * @return SCI_STATUS
+ */
+SCI_STATUS scic_sds_controller_start_next_phy(
+ SCIC_SDS_CONTROLLER_T *this_controller
+)
+{
+ SCI_STATUS status;
+
+ status = SCI_SUCCESS;
+
+ if (this_controller->phy_startup_timer_pending == FALSE)
+ {
+ if (this_controller->next_phy_to_start == SCI_MAX_PHYS)
+ {
+ // The controller has successfully finished the start process.
+ // Inform the SCI Core user and transition to the READY state.
+ if (scic_sds_controller_is_start_complete(this_controller) == TRUE)
+ {
+ scic_sds_controller_transition_to_ready(
+ this_controller, SCI_SUCCESS
+ );
+ }
+ }
+ else
+ {
+ SCIC_SDS_PHY_T * the_phy;
+
+ the_phy = &this_controller->phy_table[this_controller->next_phy_to_start];
+
+ if (
+ this_controller->oem_parameters.sds1.controller.mode_type
+ == 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_phy_start(the_phy);
+
+ if (status == SCI_SUCCESS)
+ {
+ scic_sds_controller_phy_timer_start(this_controller);
+ }
+ else
+ {
+ SCIC_LOG_WARNING((
+ sci_base_object_get_logger(this_controller),
+ SCIC_LOG_OBJECT_CONTROLLER | SCIC_LOG_OBJECT_PHY,
+ "Controller stop operation failed to stop phy %d because of status %d.\n",
+ this_controller->phy_table[this_controller->next_phy_to_start].phy_index,
+ status
+ ));
+ }
+
+ this_controller->next_phy_to_start++;
+ }
+ }
+
+ return status;
+}
+
+/**
+ * @brief
+ *
+ * @param[in] this_controller
+ *
+ * @return SCI_STATUS
+ */
+SCI_STATUS scic_sds_controller_stop_phys(
+ SCIC_SDS_CONTROLLER_T *this_controller
+)
+{
+ U32 index;
+ SCI_STATUS status;
+ SCI_STATUS phy_status;
+
+ status = SCI_SUCCESS;
+
+ for (index = 0; index < SCI_MAX_PHYS; index++)
+ {
+ phy_status = scic_phy_stop(&this_controller->phy_table[index]);
+
+ if (
+ (phy_status != SCI_SUCCESS)
+ && (phy_status != SCI_FAILURE_INVALID_STATE)
+ )
+ {
+ status = SCI_FAILURE;
+
+ SCIC_LOG_WARNING((
+ sci_base_object_get_logger(this_controller),
+ SCIC_LOG_OBJECT_CONTROLLER | SCIC_LOG_OBJECT_PHY,
+ "Controller stop operation failed to stop phy %d because of status %d.\n",
+ this_controller->phy_table[index].phy_index, phy_status
+ ));
+ }
+ }
+
+ return status;
+}
+
+/**
+ * @brief
+ *
+ * @param[in] this_controller
+ *
+ * @return SCI_STATUS
+ */
+SCI_STATUS scic_sds_controller_stop_devices(
+ SCIC_SDS_CONTROLLER_T *this_controller
+)
+{
+ U32 index;
+ SCI_STATUS status;
+ 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)
+ )
+ {
+ SCIC_LOG_WARNING((
+ sci_base_object_get_logger(this_controller),
+ SCIC_LOG_OBJECT_CONTROLLER | SCIC_LOG_OBJECT_SSP_REMOTE_TARGET,
+ "Controller stop operation failed to stop device 0x%x because of status %d.\n",
+ 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.
+ *
+ * @param this_controller
+ */
+static
+void scic_sds_controller_power_control_timer_start(
+ SCIC_SDS_CONTROLLER_T *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;
+}
+
+/**
+ * This method stops the power control timer for this controller object.
+ *
+ * @param this_controller
+ */
+static
+void scic_sds_controller_power_control_timer_stop(
+ SCIC_SDS_CONTROLLER_T *this_controller
+)
+{
+ if (this_controller->power_control.timer_started)
+ {
+ scic_cb_timer_stop(
+ this_controller, this_controller->power_control.timer
+ );
+
+ this_controller->power_control.timer_started = FALSE;
+ }
+}
+
+/**
+ * This method stops and starts the power control timer for this controller object.
+ *
+ * @param this_controller
+ */
+static
+void scic_sds_controller_power_control_timer_restart(
+ SCIC_SDS_CONTROLLER_T *this_controller
+)
+{
+ scic_sds_controller_power_control_timer_stop(this_controller);
+ scic_sds_controller_power_control_timer_start(this_controller);
+}
+
+
+/**
+ * @brief
+ *
+ * @param[in] controller
+ */
+void scic_sds_controller_power_control_timer_handler(
+ void *controller
+)
+{
+ SCIC_SDS_CONTROLLER_T *this_controller;
+ this_controller = (SCIC_SDS_CONTROLLER_T *)controller;
+
+ this_controller->power_control.remote_devices_granted_power = 0;
+
+ if (this_controller->power_control.phys_waiting == 0)
+ {
+ this_controller->power_control.timer_started = FALSE;
+ }
+ else
+ {
+ SCIC_SDS_PHY_T *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)
+ {
+ if ( this_controller->power_control.remote_devices_granted_power <
+ this_controller->oem_parameters.sds1.controller.max_number_concurrent_device_spin_up
+ )
+ {
+ the_phy = this_controller->power_control.requesters[i];
+ this_controller->power_control.requesters[i] = NULL;
+ this_controller->power_control.phys_waiting--;
+ this_controller->power_control.remote_devices_granted_power ++;
+ scic_sds_phy_consume_power_handler(the_phy);
+
+ if (the_phy->protocol == SCIC_SDS_PHY_PROTOCOL_SAS)
+ {
+ U8 j;
+ SCIC_SDS_PHY_T * current_requester_phy;
+
+ for (j = 0; j < SCI_MAX_PHYS; j++)
+ {
+ current_requester_phy = this_controller->power_control.requesters[j];
+
+ //Search the power_control queue to see if there are other phys attached to
+ //the same remote device. If found, take all of them out of await_sas_power state.
+ if (current_requester_phy != NULL &&
+ current_requester_phy != the_phy &&
+ current_requester_phy->phy_type.sas.identify_address_frame_buffer.sas_address.high
+ == the_phy->phy_type.sas.identify_address_frame_buffer.sas_address.high &&
+ current_requester_phy->phy_type.sas.identify_address_frame_buffer.sas_address.low
+ == the_phy->phy_type.sas.identify_address_frame_buffer.sas_address.low)
+ {
+ this_controller->power_control.requesters[j] = NULL;
+ this_controller->power_control.phys_waiting--;
+ scic_sds_phy_consume_power_handler(current_requester_phy);
+ }
+ }
+ }
+ }
+ else
+ {
+ 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);
+ }
+}
+
+/**
+ * @brief This method inserts the phy in the stagger spinup control queue.
+ *
+ * @param[in] this_controller
+ * @param[in] the_phy
+ */
+void scic_sds_controller_power_control_queue_insert(
+ SCIC_SDS_CONTROLLER_T *this_controller,
+ SCIC_SDS_PHY_T *the_phy
+)
+{
+ ASSERT (the_phy != NULL);
+
+ if( this_controller->power_control.remote_devices_granted_power <
+ this_controller->oem_parameters.sds1.controller.max_number_concurrent_device_spin_up
+ )
+ {
+ this_controller->power_control.remote_devices_granted_power ++;
+ scic_sds_phy_consume_power_handler(the_phy);
+
+ //stop and start the power_control timer. When the timer fires, the
+ //no_of_devices_granted_power will be set to 0
+ scic_sds_controller_power_control_timer_restart (this_controller);
+ }
+ else
+ {
+ //there are phys, attached to the same sas address as this phy, are already
+ //in READY state, this phy don't need wait.
+ U8 i;
+ SCIC_SDS_PHY_T * current_phy;
+ for(i = 0; i < SCI_MAX_PHYS; i++)
+ {
+ current_phy = &this_controller->phy_table[i];
+
+ if (current_phy->parent.state_machine.current_state_id == SCI_BASE_PHY_STATE_READY &&
+ current_phy->protocol == SCIC_SDS_PHY_PROTOCOL_SAS &&
+ current_phy->phy_type.sas.identify_address_frame_buffer.sas_address.high
+ == the_phy->phy_type.sas.identify_address_frame_buffer.sas_address.high &&
+ current_phy->phy_type.sas.identify_address_frame_buffer.sas_address.low
+ == the_phy->phy_type.sas.identify_address_frame_buffer.sas_address.low)
+ {
+ scic_sds_phy_consume_power_handler(the_phy);
+ break;
+ }
+ }
+
+ if (i == SCI_MAX_PHYS)
+ {
+ //Add the phy in the waiting list
+ this_controller->power_control.requesters[the_phy->phy_index] = the_phy;
+ this_controller->power_control.phys_waiting++;
+ }
+ }
+}
+
+/**
+ * @brief This method removes the phy from the stagger spinup control
+ * queue.
+ *
+ * @param[in] this_controller
+ * @param[in] the_phy
+ */
+void scic_sds_controller_power_control_queue_remove(
+ SCIC_SDS_CONTROLLER_T *this_controller,
+ SCIC_SDS_PHY_T *the_phy
+)
+{
+ ASSERT (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
+//****************************************************************************-
+
+/**
+ * @brief This method returns a TRUE value if the completion queue has
+ * entries that can be processed
+ *
+ * @param[in] this_controller
+ *
+ * @return BOOL
+ * @retval 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(
+ SCIC_SDS_CONTROLLER_T *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;
+}
+
+// ---------------------------------------------------------------------------
+
+/**
+ * @brief This method processes a task completion notification. This is
+ * called from within the controller completion handler.
+ *
+ * @param[in] this_controller
+ * @param[in] completion_entry
+ *
+ * @return none
+ */
+static
+void scic_sds_controller_task_completion(
+ SCIC_SDS_CONTROLLER_T *this_controller,
+ U32 completion_entry
+)
+{
+ U32 index;
+ SCIC_SDS_REQUEST_T *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);
+ }
+}
+
+/**
+ * @brief This method processes an SDMA completion event. This is called
+ * from within the controller completion handler.
+ *
+ * @param[in] this_controller
+ * @param[in] completion_entry
+ *
+ * @return none
+ */
+static
+void scic_sds_controller_sdma_completion(
+ SCIC_SDS_CONTROLLER_T *this_controller,
+ U32 completion_entry
+)
+{
+ U32 index;
+ SCIC_SDS_REQUEST_T *io_request;
+ SCIC_SDS_REMOTE_DEVICE_T *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];
+ SCIC_LOG_ERROR((
+ sci_base_object_get_logger(this_controller),
+ SCIC_LOG_OBJECT_CONTROLLER
+ | SCIC_LOG_OBJECT_SMP_IO_REQUEST
+ | SCIC_LOG_OBJECT_SSP_IO_REQUEST
+ | SCIC_LOG_OBJECT_STP_IO_REQUEST,
+ "SCIC SDS Completion type SDMA %x for io request %x\n",
+ 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];
+ SCIC_LOG_ERROR((
+ sci_base_object_get_logger(this_controller),
+ SCIC_LOG_OBJECT_CONTROLLER
+ | SCIC_LOG_OBJECT_SSP_REMOTE_TARGET
+ | SCIC_LOG_OBJECT_SMP_REMOTE_TARGET
+ | SCIC_LOG_OBJECT_STP_REMOTE_TARGET,
+ "SCIC SDS Completion type SDMA %x for remote device %x\n",
+ completion_entry,
+ device
+ ));
+ /// @todo For a port RNC operation we need to fail the device
+ break;
+
+ default:
+ SCIC_LOG_ERROR((
+ sci_base_object_get_logger(this_controller),
+ SCIC_LOG_OBJECT_CONTROLLER,
+ "SCIC SDS Completion unknown SDMA completion type %x\n",
+ completion_entry
+ ));
+ break;
+ }
+
+ /// This is an unexpected completion type and is un-recoverable
+ /// Transition to the failed state and wait for a controller reset
+ sci_base_state_machine_change_state(
+ scic_sds_controller_get_base_state_machine(this_controller),
+ SCI_BASE_CONTROLLER_STATE_FAILED
+ );
+}
+
+/**
+ * This method processes an unsolicited frame message. This is called from
+ * within the controller completion handler.
+ *
+ * @param[in] this_controller
+ * @param[in] completion_entry
+ *
+ * @return none
+ */
+static
+void scic_sds_controller_unsolicited_frame(
+ SCIC_SDS_CONTROLLER_T *this_controller,
+ U32 completion_entry
+)
+{
+ U32 index;
+ U32 frame_index;
+
+ SCU_UNSOLICITED_FRAME_HEADER_T * frame_header;
+ SCIC_SDS_PHY_T * phy;
+ SCIC_SDS_REMOTE_DEVICE_T * device;
+
+ 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?
+ }
+}
+
+/**
+ * @brief This method processes an event completion entry. This is called
+ * from within the controller completion handler.
+ *
+ * @param[in] this_controller
+ * @param[in] completion_entry
+ *
+ * @return none
+ */
+static
+void scic_sds_controller_event_completion(
+ SCIC_SDS_CONTROLLER_T *this_controller,
+ U32 completion_entry
+)
+{
+ U32 index;
+ SCIC_SDS_REQUEST_T *io_request;
+ SCIC_SDS_REMOTE_DEVICE_T *device;
+ SCIC_SDS_PHY_T *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.
+ SCIC_LOG_ERROR((
+ sci_base_object_get_logger(this_controller),
+ SCIC_LOG_OBJECT_CONTROLLER,
+ "SCIC Controller 0x%x received SMU command error 0x%x\n",
+ this_controller, completion_entry
+ ));
+ break;
+
+ case SCU_EVENT_TYPE_FATAL_MEMORY_ERROR:
+ // report fatal memory error
+ this_controller->parent.error = SCI_CONTROLLER_FATAL_MEMORY_ERROR;
+
+ sci_base_state_machine_change_state(
+ scic_sds_controller_get_base_state_machine(this_controller),
+ SCI_BASE_CONTROLLER_STATE_FAILED
+ );
+
+ //continue as in following events
+ case SCU_EVENT_TYPE_SMU_PCQ_ERROR:
+ case SCU_EVENT_TYPE_SMU_ERROR:
+ SCIC_LOG_ERROR((
+ sci_base_object_get_logger(this_controller),
+ SCIC_LOG_OBJECT_CONTROLLER,
+ "SCIC Controller 0x%x received fatal controller event 0x%x\n",
+ 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
+ {
+ SCIC_LOG_WARNING((
+ sci_base_object_get_logger(this_controller),
+ SCIC_LOG_OBJECT_CONTROLLER |
+ SCIC_LOG_OBJECT_SMP_IO_REQUEST |
+ SCIC_LOG_OBJECT_SSP_IO_REQUEST |
+ SCIC_LOG_OBJECT_STP_IO_REQUEST,
+ "SCIC Controller 0x%x received event 0x%x for io request object that doesnt exist.\n",
+ 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
+ {
+ SCIC_LOG_WARNING((
+ sci_base_object_get_logger(this_controller),
+ SCIC_LOG_OBJECT_CONTROLLER |
+ SCIC_LOG_OBJECT_SMP_REMOTE_TARGET |
+ SCIC_LOG_OBJECT_SSP_REMOTE_TARGET |
+ SCIC_LOG_OBJECT_STP_REMOTE_TARGET,
+ "SCIC Controller 0x%x received event 0x%x for remote device object that doesnt exist.\n",
+ 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
+ {
+ SCIC_LOG_ERROR((
+ sci_base_object_get_logger(this_controller),
+ SCIC_LOG_OBJECT_CONTROLLER |
+ SCIC_LOG_OBJECT_SMP_REMOTE_TARGET |
+ SCIC_LOG_OBJECT_SSP_REMOTE_TARGET |
+ SCIC_LOG_OBJECT_STP_REMOTE_TARGET,
+ "SCIC Controller 0x%x received event 0x%x for remote device object 0x%0x that doesnt exist.\n",
+ this_controller, completion_entry, index
+ ));
+ }
+ break;
+
+ default:
+ SCIC_LOG_WARNING((
+ sci_base_object_get_logger(this_controller),
+ SCIC_LOG_OBJECT_CONTROLLER,
+ "SCIC Controller received unknown event code %x\n",
+ completion_entry
+ ));
+ break;
+ }
+}
+
+/**
+ * @brief This method is a private routine for processing the completion
+ * queue entries.
+ *
+ * @param[in] this_controller
+ *
+ * @return none
+ */
+static
+void scic_sds_controller_process_completions(
+ SCIC_SDS_CONTROLLER_T *this_controller
+)
+{
+ U32 completion_count = 0;
+ U32 completion_entry;
+ U32 get_index;
+ U32 get_cycle;
+ U32 event_index;
+ U32 event_cycle;
+
+ SCIC_LOG_TRACE((
+ sci_base_object_get_logger(this_controller),
+ SCIC_LOG_OBJECT_CONTROLLER,
+ "scic_sds_controller_process_completions(0x%x) enter\n",
+ this_controller
+ ));
+
+ SCIC_LOG_TRACE((
+ sci_base_object_get_logger(this_controller),
+ SCIC_LOG_OBJECT_COMPLETION_QUEUE,
+ "completion queue begining get : 0x%08x\n",
+ 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);
+
+ SCIC_LOG_TRACE((
+ sci_base_object_get_logger(this_controller),
+ SCIC_LOG_OBJECT_COMPLETION_QUEUE,
+ "completion queue entry : 0x%08x\n",
+ 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:
+ 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:
+ SCIC_LOG_WARNING((
+ sci_base_object_get_logger(this_controller),
+ SCIC_LOG_OBJECT_CONTROLLER,
+ "SCIC Controller received unknown completion type %x\n",
+ 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);
+ }
+
+ SCIC_LOG_TRACE((
+ sci_base_object_get_logger(this_controller),
+ SCIC_LOG_OBJECT_COMPLETION_QUEUE,
+ "completion queue ending get : 0x%08x\n",
+ this_controller->completion_queue_get
+ ));
+
+}
+
+/**
+ * @brief This method is a private routine for processing the completion
+ * queue entries.
+ *
+ * @param[in] this_controller
+ *
+ * @return none
+ */
+static
+void scic_sds_controller_transitioned_process_completions(
+ SCIC_SDS_CONTROLLER_T * this_controller
+)
+{
+ U32 completion_count = 0;
+ U32 completion_entry;
+ U32 get_index;
+ U32 get_cycle;
+ U32 event_index;
+ U32 event_cycle;
+
+ SCIC_LOG_TRACE((
+ sci_base_object_get_logger(this_controller),
+ SCIC_LOG_OBJECT_CONTROLLER,
+ "scic_sds_controller_transitioned_process_completions(0x%x) enter\n",
+ this_controller
+ ));
+
+ SCIC_LOG_TRACE((
+ sci_base_object_get_logger(this_controller),
+ SCIC_LOG_OBJECT_COMPLETION_QUEUE,
+ "completion queue begining get : 0x%08x\n",
+ 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);
+
+ SCIC_LOG_TRACE((
+ sci_base_object_get_logger(this_controller),
+ SCIC_LOG_OBJECT_COMPLETION_QUEUE,
+ "completion queue entry : 0x%08x\n",
+ 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:
+ INCREMENT_EVENT_QUEUE_GET(this_controller, event_index, event_cycle);
+ // Fall-through
+
+ case SCU_COMPLETION_TYPE_EVENT:
+ case SCU_COMPLETION_TYPE_SDMA:
+ case SCU_COMPLETION_TYPE_UFI:
+ default:
+ SCIC_LOG_WARNING((
+ sci_base_object_get_logger(this_controller),
+ SCIC_LOG_OBJECT_CONTROLLER,
+ "SCIC Controller ignoring completion type %x\n",
+ 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);
+ }
+
+ SCIC_LOG_TRACE((
+ sci_base_object_get_logger(this_controller),
+ SCIC_LOG_OBJECT_COMPLETION_QUEUE,
+ "completion queue ending get : 0x%08x\n",
+ this_controller->completion_queue_get
+ ));
+}
+
+//****************************************************************************-
+//* SCIC SDS Controller Interrupt and Completion functions
+//****************************************************************************-
+
+/**
+ * @brief This method provides standard (common) processing of interrupts
+ * for polling and legacy based interrupts.
+ *
+ * @param[in] controller
+ * @param[in] interrupt_status
+ *
+ * @return This method returns a boolean (BOOL) indication as to
+ * whether an completions are pending to be processed.
+ * @retval TRUE if an interrupt is to be processed
+ * @retval FALSE if no interrupt was pending
+ */
+static
+BOOL scic_sds_controller_standard_interrupt_handler(
+ SCIC_SDS_CONTROLLER_T *this_controller,
+ U32 interrupt_status
+)
+{
+ BOOL is_completion_needed = FALSE;
+
+ SCIC_LOG_TRACE((
+ sci_base_object_get_logger(this_controller),
+ SCIC_LOG_OBJECT_CONTROLLER,
+ "scic_sds_controller_standard_interrupt_handler(0x%d,0x%d) enter\n",
+ this_controller, interrupt_status
+ ));
+
+ 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;
+}
+
+/**
+ * @brief This is the method provided to handle polling for interrupts
+ * for the controller object.
+ *
+ * @param[in] controller
+ *
+ * @return BOOL
+ * @retval TRUE if an interrupt is to be processed
+ * @retval FALSE if no interrupt was pending
+ */
+static
+BOOL scic_sds_controller_polling_interrupt_handler(
+ SCI_CONTROLLER_HANDLE_T controller
+)
+{
+ U32 interrupt_status;
+ SCIC_SDS_CONTROLLER_T *this_controller = (SCIC_SDS_CONTROLLER_T*)controller;
+
+ SCIC_LOG_TRACE((
+ sci_base_object_get_logger(controller),
+ SCIC_LOG_OBJECT_CONTROLLER,
+ "scic_sds_controller_polling_interrupt_handler(0x%d) enter\n",
+ controller
+ ));
+
+ /*
+ * 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(this_controller);
+ if ((interrupt_status &
+ (SMU_ISR_COMPLETION |
+ SMU_ISR_QUEUE_ERROR |
+ SMU_ISR_QUEUE_SUSPEND)) == 0)
+ {
+ return FALSE;
+ }
+
+ return scic_sds_controller_standard_interrupt_handler(
+ controller, interrupt_status
+ );
+}
+
+/**
+ * @brief This is the method provided to handle completions when interrupt
+ * polling is in use.
+ *
+ * @param[in] controller
+ *
+ * @return none
+ */
+static
+void scic_sds_controller_polling_completion_handler(
+ SCI_CONTROLLER_HANDLE_T controller
+)
+{
+ SCIC_SDS_CONTROLLER_T *this_controller = (SCIC_SDS_CONTROLLER_T *)controller;
+
+ SCIC_LOG_TRACE((
+ sci_base_object_get_logger(controller),
+ SCIC_LOG_OBJECT_CONTROLLER,
+ "scic_sds_controller_polling_completion_handler(0x%d) enter\n",
+ controller
+ ));
+
+ if (this_controller->encountered_fatal_error == TRUE)
+ {
+ SCIC_LOG_ERROR((
+ sci_base_object_get_logger(this_controller),
+ SCIC_LOG_OBJECT_CONTROLLER,
+ "SCIC Controller has encountered a fatal error.\n"
+ ));
+
+ sci_base_state_machine_change_state(
+ scic_sds_controller_get_base_state_machine(this_controller),
+ SCI_BASE_CONTROLLER_STATE_FAILED
+ );
+ }
+ else if (scic_sds_controller_completion_queue_has_entries(this_controller))
+ {
+ if (this_controller->restrict_completions == FALSE)
+ scic_sds_controller_process_completions(this_controller);
+ else
+ scic_sds_controller_transitioned_process_completions(this_controller);
+ }
+
+ /*
+ * 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(
+ this_controller,
+ (U32)(SMU_ISR_COMPLETION | SMU_ISR_QUEUE_ERROR | SMU_ISR_QUEUE_SUSPEND)
+ );
+}
+
+#if !defined(DISABLE_INTERRUPTS)
+/**
+ * @brief This is the method provided to handle legacy interrupts for the
+ * controller object.
+ *
+ * @param[in] controller
+ *
+ * @return BOOL
+ * @retval TRUE if an interrupt is processed
+ * FALSE if no interrupt was processed
+ */
+static
+BOOL scic_sds_controller_legacy_interrupt_handler(
+ SCI_CONTROLLER_HANDLE_T controller
+)
+{
+ U32 interrupt_status;
+ BOOL is_completion_needed;
+ SCIC_SDS_CONTROLLER_T *this_controller = (SCIC_SDS_CONTROLLER_T*)controller;
+
+ interrupt_status = SMU_ISR_READ(this_controller);
+ is_completion_needed = scic_sds_controller_standard_interrupt_handler(
+ this_controller, interrupt_status
+ );
+
+ return is_completion_needed;
+}
+
+
+/**
+ * @brief 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.
+ *
+ * @param[in] controller
+ *
+ * @return none
+ */
+static
+void scic_sds_controller_legacy_completion_handler(
+ SCI_CONTROLLER_HANDLE_T controller
+)
+{
+ SCIC_SDS_CONTROLLER_T *this_controller = (SCIC_SDS_CONTROLLER_T *)controller;
+
+ SCIC_LOG_TRACE((
+ sci_base_object_get_logger(controller),
+ SCIC_LOG_OBJECT_CONTROLLER,
+ "scic_sds_controller_legacy_completion_handler(0x%d) enter\n",
+ controller
+ ));
+
+ scic_sds_controller_polling_completion_handler(controller);
+
+ SMU_IMR_WRITE(this_controller, 0x00000000);
+
+#ifdef IMR_READ_FENCE
+ {
+ volatile U32 int_mask_value = 0;
+ ULONG count = 0;
+
+ /*
+ * Temporary code since we have seen with legacy interrupts
+ * that interrupts are still masked after clearing the mask
+ * above. This may be an Arlington problem or it may be an
+ * old driver problem. Presently this code is turned off
+ * since we have not seen this problem recently.
+ */
+ do
+ {
+ int_mask_value = SMU_IMR_READ(this_controler);
+
+ if (count++ > 10)
+ {
+ #ifdef ALLOW_ENTER_DEBUGGER
+ __debugbreak();
+ #endif
+ break;
+ }
+ } while (int_mask_value != 0);
+ }
+#endif
+}
+
+/**
+ * @brief 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.
+ *
+ * @param[in] controller
+ *
+ * @return BOOL
+ * @retval TRUE if an interrupt is processed
+ * FALSE if no interrupt was processed
+ */
+static
+BOOL scic_sds_controller_single_vector_interrupt_handler(
+ SCI_CONTROLLER_HANDLE_T controller
+)
+{
+ U32 interrupt_status;
+ SCIC_SDS_CONTROLLER_T *this_controller;
+ this_controller = (SCIC_SDS_CONTROLLER_T *)controller;
+
+ // 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(this_controller, 0xFFFFFFFF);
+
+ interrupt_status = SMU_ISR_READ(this_controller);
+ interrupt_status &= (SMU_ISR_QUEUE_ERROR | SMU_ISR_QUEUE_SUSPEND);
+
+ if (
+ (interrupt_status == 0)
+ && scic_sds_controller_completion_queue_has_entries(this_controller)
+ )
+ {
+ // 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(this_controller, 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(this_controller, 0x00000000);
+ SMU_IMR_WRITE(this_controller, 0x00000000);
+
+ return FALSE;
+}
+
+/**
+ * @brief This is the method provided to handle completions for a single
+ * MSIX message.
+ *
+ * @param[in] controller
+ */
+static
+void scic_sds_controller_single_vector_completion_handler(
+ SCI_CONTROLLER_HANDLE_T controller
+)
+{
+ U32 interrupt_status;
+ SCIC_SDS_CONTROLLER_T *this_controller;
+ this_controller = (SCIC_SDS_CONTROLLER_T *)controller;
+
+ SCIC_LOG_TRACE((
+ sci_base_object_get_logger(controller),
+ SCIC_LOG_OBJECT_CONTROLLER,
+ "scic_sds_controller_single_vector_completion_handler(0x%d) enter\n",
+ controller
+ ));
+
+ interrupt_status = SMU_ISR_READ(this_controller);
+ interrupt_status &= (SMU_ISR_QUEUE_ERROR | SMU_ISR_QUEUE_SUSPEND);
+
+ if (interrupt_status & SMU_ISR_QUEUE_ERROR)
+ {
+ SCIC_LOG_ERROR((
+ sci_base_object_get_logger(this_controller),
+ SCIC_LOG_OBJECT_CONTROLLER,
+ "SCIC Controller has encountered a fatal error.\n"
+ ));
+
+ // 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(this_controller),
+ SCI_BASE_CONTROLLER_STATE_FAILED
+ );
+ return;
+ }
+
+ if (
+ (interrupt_status & SMU_ISR_QUEUE_SUSPEND)
+ && !scic_sds_controller_completion_queue_has_entries(this_controller)
+ )
+ {
+ SCIC_LOG_ERROR((
+ sci_base_object_get_logger(this_controller),
+ SCIC_LOG_OBJECT_CONTROLLER,
+ "SCIC Controller has encountered a fatal error.\n"
+ ));
+
+ // 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(this_controller),
+ SCI_BASE_CONTROLLER_STATE_FAILED
+ );
+ return;
+ }
+
+ if (scic_sds_controller_completion_queue_has_entries(this_controller))
+ {
+ scic_sds_controller_process_completions(this_controller);
+
+ // We dont care which interrupt got us to processing the completion queu
+ // so clear them both.
+ SMU_ISR_WRITE(
+ this_controller,
+ (SMU_ISR_COMPLETION | SMU_ISR_QUEUE_SUSPEND)
+ );
+ }
+
+ SMU_IMR_WRITE(this_controller, 0x00000000);
+}
+
+/**
+ * @brief This is the method provided to handle a MSIX message for a normal
+ * completion.
+ *
+ * @param[in] controller
+ *
+ * @return BOOL
+ * @retval TRUE if an interrupt is processed
+ * FALSE if no interrupt was processed
+ */
+static
+BOOL scic_sds_controller_normal_vector_interrupt_handler(
+ SCI_CONTROLLER_HANDLE_T controller
+)
+{
+ SCIC_SDS_CONTROLLER_T *this_controller;
+ this_controller = (SCIC_SDS_CONTROLLER_T *)controller;
+
+ if (scic_sds_controller_completion_queue_has_entries(this_controller))
+ {
+ 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(this_controller, 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(this_controller, 0xFF000000);
+ SMU_IMR_WRITE(this_controller, 0x00000000);
+ }
+
+ return FALSE;
+}
+
+/**
+ * @brief This is the method provided to handle the completions for a
+ * normal MSIX message.
+ *
+ * @param[in] controller
+ */
+static
+void scic_sds_controller_normal_vector_completion_handler(
+ SCI_CONTROLLER_HANDLE_T controller
+)
+{
+ SCIC_SDS_CONTROLLER_T *this_controller;
+ this_controller = (SCIC_SDS_CONTROLLER_T *)controller;
+
+ SCIC_LOG_TRACE((
+ sci_base_object_get_logger(controller),
+ SCIC_LOG_OBJECT_CONTROLLER,
+ "scic_sds_controller_normal_vector_completion_handler(0x%d) enter\n",
+ controller
+ ));
+
+ // Empty out the completion queue
+ if (scic_sds_controller_completion_queue_has_entries(this_controller))
+ {
+ scic_sds_controller_process_completions(this_controller);
+ }
+
+ // Clear the interrupt and enable all interrupts again
+ SMU_ISR_WRITE(this_controller, SMU_ISR_COMPLETION);
+ // Could we write the value of SMU_ISR_COMPLETION?
+ SMU_IMR_WRITE(this_controller, 0xFF000000);
+ SMU_IMR_WRITE(this_controller, 0x00000000);
+}
+
+/**
+ * @brief 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.
+ *
+ * @param[in] controller
+ *
+ * @return BOOL
+ * @retval TRUE if an interrupt is processed
+ * FALSE if no interrupt was processed
+ */
+static
+BOOL scic_sds_controller_error_vector_interrupt_handler(
+ SCI_CONTROLLER_HANDLE_T controller
+)
+{
+ U32 interrupt_status;
+ SCIC_SDS_CONTROLLER_T *this_controller;
+ this_controller = (SCIC_SDS_CONTROLLER_T *)controller;
+
+
+ interrupt_status = SMU_ISR_READ(this_controller);
+ 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(this_controller, 0x000000FF);
+ SMU_IMR_WRITE(this_controller, 0x00000000);
+
+ return FALSE;
+}
+
+/**
+ * @brief This is the method provided to handle the error completions when
+ * the hardware is using two MSIX messages.
+ *
+ * @param[in] controller
+ */
+static
+void scic_sds_controller_error_vector_completion_handler(
+ SCI_CONTROLLER_HANDLE_T controller
+)
+{
+ U32 interrupt_status;
+ SCIC_SDS_CONTROLLER_T *this_controller;
+ this_controller = (SCIC_SDS_CONTROLLER_T *)controller;
+
+ SCIC_LOG_TRACE((
+ sci_base_object_get_logger(controller),
+ SCIC_LOG_OBJECT_CONTROLLER,
+ "scic_sds_controller_error_vector_completion_handler(0x%d) enter\n",
+ controller
+ ));
+
+ interrupt_status = SMU_ISR_READ(this_controller);
+
+ if (
+ (interrupt_status & SMU_ISR_QUEUE_SUSPEND)
+ && scic_sds_controller_completion_queue_has_entries(this_controller)
+ )
+ {
+ scic_sds_controller_process_completions(this_controller);
+
+ SMU_ISR_WRITE(this_controller, SMU_ISR_QUEUE_SUSPEND);
+ }
+ else
+ {
+ SCIC_LOG_ERROR((
+ sci_base_object_get_logger(this_controller),
+ SCIC_LOG_OBJECT_CONTROLLER,
+ "SCIC Controller reports CRC error on completion ISR %x\n",
+ interrupt_status
+ ));
+
+ sci_base_state_machine_change_state(
+ scic_sds_controller_get_base_state_machine(this_controller),
+ 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(this_controller, 0x00000000);
+}
+
+#endif // !defined(DISABLE_INTERRUPTS)
+
+//****************************************************************************-
+//* SCIC SDS Controller External Methods
+//****************************************************************************-
+
+/**
+ * @brief This method returns the sizeof the SCIC SDS Controller Object
+ *
+ * @return U32
+ */
+U32 scic_sds_controller_get_object_size(void)
+{
+ return sizeof(SCIC_SDS_CONTROLLER_T);
+}
+
+/**
+ * This method returns the minimum number of timers that are required by the
+ * controller object. This will include required timers for phys and ports.
+ *
+ * @return U32
+ * @retval The minimum number of timers that are required to make this
+ * controller operational.
+ */
+U32 scic_sds_controller_get_min_timer_count(void)
+{
+ return SCIC_SDS_CONTROLLER_MIN_TIMER_COUNT
+ + scic_sds_port_get_min_timer_count()
+ + scic_sds_phy_get_min_timer_count();
+}
+
+/**
+ * This method returns the maximum number of timers that are required by the
+ * controller object. This will include required timers for phys and ports.
+ *
+ * @return U32
+ * @retval The maximum number of timers that will be used by the controller
+ * object
+ */
+U32 scic_sds_controller_get_max_timer_count(void)
+{
+ return SCIC_SDS_CONTROLLER_MAX_TIMER_COUNT
+ + scic_sds_port_get_max_timer_count()
+ + scic_sds_phy_get_max_timer_count();
+}
+
+/**
+ * @brief
+ *
+ * @param[in] this_controller
+ * @param[in] the_port
+ * @param[in] the_phy
+ *
+ * @return none
+ */
+void scic_sds_controller_link_up(
+ SCIC_SDS_CONTROLLER_T *this_controller,
+ SCIC_SDS_PORT_T *the_port,
+ SCIC_SDS_PHY_T *the_phy
+)
+{
+ if (this_controller->state_handlers->link_up_handler != NULL)
+ {
+ this_controller->state_handlers->link_up_handler(
+ this_controller, the_port, the_phy);
+ }
+ else
+ {
+ SCIC_LOG_INFO((
+ sci_base_object_get_logger(this_controller),
+ SCIC_LOG_OBJECT_CONTROLLER,
+ "SCIC Controller linkup event from phy %d in unexpected state %d\n",
+ the_phy->phy_index,
+ sci_base_state_machine_get_state(
+ scic_sds_controller_get_base_state_machine(this_controller))
+ ));
+ }
+}
+
+/**
+ * @brief
+ *
+ * @param[in] this_controller
+ * @param[in] the_port
+ * @param[in] the_phy
+ */
+void scic_sds_controller_link_down(
+ SCIC_SDS_CONTROLLER_T *this_controller,
+ SCIC_SDS_PORT_T *the_port,
+ SCIC_SDS_PHY_T *the_phy
+)
+{
+ if (this_controller->state_handlers->link_down_handler != NULL)
+ {
+ this_controller->state_handlers->link_down_handler(
+ this_controller, the_port, the_phy);
+ }
+ else
+ {
+ SCIC_LOG_INFO((
+ sci_base_object_get_logger(this_controller),
+ SCIC_LOG_OBJECT_CONTROLLER,
+ "SCIC Controller linkdown event from phy %d in unexpected state %d\n",
+ the_phy->phy_index,
+ sci_base_state_machine_get_state(
+ scic_sds_controller_get_base_state_machine(this_controller))
+ ));
+ }
+}
+
+/**
+ * @brief This method is called by the remote device to inform the controller
+ * that this remote device has started.
+ *
+ * @param[in] this_controller
+ * @param[in] the_device
+ */
+void scic_sds_controller_remote_device_started(
+ SCIC_SDS_CONTROLLER_T * this_controller,
+ SCIC_SDS_REMOTE_DEVICE_T * the_device
+)
+{
+ if (this_controller->state_handlers->remote_device_started_handler != NULL)
+ {
+ this_controller->state_handlers->remote_device_started_handler(
+ this_controller, the_device
+ );
+ }
+ else
+ {
+ SCIC_LOG_INFO((
+ sci_base_object_get_logger(this_controller),
+ SCIC_LOG_OBJECT_CONTROLLER,
+ "SCIC Controller 0x%x remote device started event from device 0x%x in unexpected state %d\n",
+ this_controller,
+ the_device,
+ sci_base_state_machine_get_state(
+ scic_sds_controller_get_base_state_machine(this_controller))
+ ));
+ }
+}
+
+/**
+ * @brief This is a helper method to determine if any remote devices on this
+ * controller are still in the stopping state.
+ *
+ * @param[in] this_controller
+ */
+BOOL scic_sds_controller_has_remote_devices_stopping(
+ SCIC_SDS_CONTROLLER_T * this_controller
+)
+{
+ U32 index;
+
+ for (index = 0; index < this_controller->remote_node_entries; index++)
+ {
+ if (
+ (this_controller->device_table[index] != NULL)
+ && (
+ this_controller->device_table[index]->parent.state_machine.current_state_id
+ == SCI_BASE_REMOTE_DEVICE_STATE_STOPPING
+ )
+ )
+ {
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+/**
+ * @brief This method is called by the remote device to inform the controller
+ * object that the remote device has stopped.
+ *
+ * @param[in] this_controller
+ * @param[in] the_device
+ */
+void scic_sds_controller_remote_device_stopped(
+ SCIC_SDS_CONTROLLER_T * this_controller,
+ SCIC_SDS_REMOTE_DEVICE_T * the_device
+)
+{
+ if (this_controller->state_handlers->remote_device_stopped_handler != NULL)
+ {
+ this_controller->state_handlers->remote_device_stopped_handler(
+ this_controller, the_device
+ );
+ }
+ else
+ {
+ SCIC_LOG_INFO((
+ sci_base_object_get_logger(this_controller),
+ SCIC_LOG_OBJECT_CONTROLLER,
+ "SCIC Controller 0x%x remote device stopped event from device 0x%x in unexpected state %d\n",
+ this_controller,
+ the_device,
+ sci_base_state_machine_get_state(
+ scic_sds_controller_get_base_state_machine(this_controller))
+ ));
+ }
+}
+
+/**
+ * @brief This method will write to the SCU PCP register the request value.
+ * The method is used to suspend/resume ports, devices, and phys.
+ *
+ * @param[in] this_controller
+ * @param[in] request
+ */
+void scic_sds_controller_post_request(
+ SCIC_SDS_CONTROLLER_T *this_controller,
+ U32 request
+)
+{
+ SCIC_LOG_INFO((
+ sci_base_object_get_logger(this_controller),
+ SCIC_LOG_OBJECT_CONTROLLER | SCIC_LOG_OBJECT_COMPLETION_QUEUE,
+ "SCIC Controller 0x%08x post request 0x%08x\n",
+ this_controller, request
+ ));
+
+ SMU_PCP_WRITE(this_controller, request);
+}
+
+/**
+ * @brief This method will copy the soft copy of the task context into
+ * the physical memory accessible by the controller.
+ *
+ * @note 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).
+ *
+ * @param[in] this_controller This parameter specifies the controller for
+ * which to copy the task context.
+ * @param[in] this_request This parameter specifies the request for which
+ * the task context is being copied.
+ *
+ * @return none
+ */
+void scic_sds_controller_copy_task_context(
+ SCIC_SDS_CONTROLLER_T *this_controller,
+ SCIC_SDS_REQUEST_T *this_request
+)
+{
+ SCU_TASK_CONTEXT_T *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(SCU_TASK_CONTEXT_T, 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;
+}
+
+/**
+ * @brief This method returns the task context buffer for the given io tag.
+ *
+ * @param[in] this_controller
+ * @param[in] io_tag
+ *
+ * @return struct SCU_TASK_CONTEXT*
+ */
+SCU_TASK_CONTEXT_T * scic_sds_controller_get_task_context_buffer(
+ SCIC_SDS_CONTROLLER_T * 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;
+}
+
+/**
+ * @brief This method returnst the sequence value from the io tag value
+ *
+ * @param[in] this_controller
+ * @param[in] io_tag
+ *
+ * @return U16
+ */
+U16 scic_sds_controller_get_io_sequence_from_tag(
+ SCIC_SDS_CONTROLLER_T *this_controller,
+ U16 io_tag
+)
+{
+ return scic_sds_io_tag_get_sequence(io_tag);
+}
+
+/**
+ * @brief This method returns the IO request associated with the tag value
+ *
+ * @param[in] this_controller
+ * @param[in] io_tag
+ *
+ * @return SCIC_SDS_IO_REQUEST_T*
+ * @retval NULL if there is no valid IO request at the tag value
+ */
+SCIC_SDS_REQUEST_T *scic_sds_controller_get_io_request_from_tag(
+ SCIC_SDS_CONTROLLER_T *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;
+}
+
+/**
+ * @brief 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.
+ *
+ * @param[in] this_controller This is the controller object which contains
+ * the set of free remote node ids
+ * @param[in] the_devce This is the device object which is requesting the a
+ * remote node id
+ * @param[out] node_id This is the remote node id that is assinged to the
+ * device if one is available
+ *
+ * @return SCI_STATUS
+ * @retval SCI_FAILURE_OUT_OF_RESOURCES if there are no available remote
+ * node index available.
+ */
+SCI_STATUS scic_sds_controller_allocate_remote_node_context(
+ SCIC_SDS_CONTROLLER_T * this_controller,
+ SCIC_SDS_REMOTE_DEVICE_T * 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;
+}
+
+/**
+ * @brief 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.
+ *
+ * @param[in] this_controller
+ * @param[in] the_device
+ * @param[in] node_id
+ *
+ * @return none
+ */
+void scic_sds_controller_free_remote_node_context(
+ SCIC_SDS_CONTROLLER_T * this_controller,
+ SCIC_SDS_REMOTE_DEVICE_T * 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
+ );
+ }
+}
+
+/**
+ * @brief This method returns the SCU_REMOTE_NODE_CONTEXT for the specified
+ * remote node id.
+ *
+ * @param[in] this_controller
+ * @param[in] node_id
+ *
+ * @return SCU_REMOTE_NODE_CONTEXT_T*
+ */
+SCU_REMOTE_NODE_CONTEXT_T *scic_sds_controller_get_remote_node_context_buffer(
+ SCIC_SDS_CONTROLLER_T *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;
+}
+
+/**
+ * This method will combind the frame header and frame buffer to create
+ * a SATA D2H register FIS
+ *
+ * @param[out] resposne_buffer This is the buffer into which the D2H register
+ * FIS will be constructed.
+ * @param[in] frame_header This is the frame header returned by the hardware.
+ * @param[in] frame_buffer This is the frame buffer returned by the hardware.
+ *
+ * @erturn 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(SATA_FIS_REG_D2H_T) - sizeof(U32)
+ );
+}
+
+/**
+ * @brief 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.
+ *
+ * @param[in] this_controller
+ * @param[in] frame_index
+ *
+ * @return none
+ */
+void scic_sds_controller_release_frame(
+ SCIC_SDS_CONTROLLER_T *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);
+}
+
+#ifdef SCI_LOGGING
+void scic_sds_controller_initialize_state_logging(
+ SCIC_SDS_CONTROLLER_T *this_controller
+)
+{
+ sci_base_state_machine_logger_initialize(
+ &this_controller->parent.state_machine_logger,
+ &this_controller->parent.state_machine,
+ &this_controller->parent.parent,
+ scic_cb_logger_log_states,
+ "SCIC_SDS_CONTROLLER_T", "base state machine",
+ SCIC_LOG_OBJECT_CONTROLLER
+ );
+}
+
+void scic_sds_controller_deinitialize_state_logging(
+ SCIC_SDS_CONTROLLER_T *this_controller
+)
+{
+ sci_base_state_machine_logger_deinitialize(
+ &this_controller->parent.state_machine_logger,
+ &this_controller->parent.state_machine
+ );
+}
+#endif
+
+/**
+ * @brief 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.
+ *
+ * @param[in] controller This parameter specifies the controller for
+ * which to set the configuration parameters to their
+ * default values.
+ *
+ * @return none
+ */
+static
+void scic_sds_controller_set_default_config_parameters(
+ SCIC_SDS_CONTROLLER_T *this_controller
+)
+{
+ U16 index;
+
+ // Default to APC mode.
+ this_controller->oem_parameters.sds1.controller.mode_type = SCIC_PORT_AUTOMATIC_CONFIGURATION_MODE;
+
+ // Default to 1
+ this_controller->oem_parameters.sds1.controller.max_number_concurrent_device_spin_up = 1;
+
+ // Default to no SSC operation.
+ this_controller->oem_parameters.sds1.controller.ssc_sata_tx_spread_level = 0;
+ this_controller->oem_parameters.sds1.controller.ssc_sas_tx_spread_level = 0;
+ this_controller->oem_parameters.sds1.controller.ssc_sas_tx_type = 0;
+
+ // Default to all phys to using short cables
+ this_controller->oem_parameters.sds1.controller.cable_selection_mask = 0;
+
+ // 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 6G (i.e. Gen 3) for now. User can override if
+ // they choose.
+ this_controller->user_parameters.sds1.phys[index].max_speed_generation = 2;
+
+ //the frequencies cannot be 0
+ this_controller->user_parameters.sds1.phys[index].align_insertion_frequency = 0x7f;
+ this_controller->user_parameters.sds1.phys[index].in_connection_align_insertion_frequency = 0xff;
+ this_controller->user_parameters.sds1.phys[index].notify_enable_spin_up_insertion_frequency = 0x33;
+
+ // 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.sci_format.high
+ = 0x5FCFFFFF;
+
+ // Add in controller index to ensure each controller will have unique SAS addresses by default.
+ this_controller->oem_parameters.sds1.phys[index].sas_address.sci_format.low
+ = 0x00000001 + this_controller->controller_index;
+
+ if ( (this_controller->pci_revision == SCIC_SDS_PCI_REVISION_A0)
+ || (this_controller->pci_revision == SCIC_SDS_PCI_REVISION_A2)
+ || (this_controller->pci_revision == SCIC_SDS_PCI_REVISION_B0) )
+ {
+ this_controller->oem_parameters.sds1.phys[index].afe_tx_amp_control0 = 0x000E7C03;
+ this_controller->oem_parameters.sds1.phys[index].afe_tx_amp_control1 = 0x000E7C03;
+ this_controller->oem_parameters.sds1.phys[index].afe_tx_amp_control2 = 0x000E7C03;
+ this_controller->oem_parameters.sds1.phys[index].afe_tx_amp_control3 = 0x000E7C03;
+ }
+ else // This must be SCIC_SDS_PCI_REVISION_C0
+ {
+ this_controller->oem_parameters.sds1.phys[index].afe_tx_amp_control0 = 0x000BDD08;
+ this_controller->oem_parameters.sds1.phys[index].afe_tx_amp_control1 = 0x000B7069;
+ this_controller->oem_parameters.sds1.phys[index].afe_tx_amp_control2 = 0x000B7C09;
+ this_controller->oem_parameters.sds1.phys[index].afe_tx_amp_control3 = 0x000AFC6E;
+ }
+ }
+
+ 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 = 20;
+
+}
+
+
+/**
+ * @brief This method release resources in SCI controller.
+ *
+ * @param[in] this_controller This parameter specifies the core
+ * controller and associated objects whose resources are to be
+ * released.
+ *
+ * @return This method returns a value indicating if the operation succeeded.
+ * @retval SCI_SUCCESS This value indicates that all the timers are destroyed.
+ * @retval SCI_FAILURE This value indicates certain failure during the process
+ * of cleaning timer resource.
+ */
+static
+SCI_STATUS scic_sds_controller_release_resource(
+ SCIC_SDS_CONTROLLER_T * this_controller
+)
+{
+ SCIC_SDS_PORT_T * port;
+ SCIC_SDS_PHY_T * phy;
+ U8 index;
+
+ SCIC_LOG_TRACE((
+ sci_base_object_get_logger(this_controller),
+ SCIC_LOG_OBJECT_CONTROLLER | SCIC_LOG_OBJECT_INITIALIZATION,
+ "scic_sds_controller_release_resource(0x%x) enter\n",
+ this_controller
+ ));
+
+ if(this_controller->phy_startup_timer != NULL)
+ {
+ scic_cb_timer_destroy(this_controller, this_controller->phy_startup_timer);
+ this_controller->phy_startup_timer = NULL;
+ }
+
+ if(this_controller->power_control.timer != NULL)
+ {
+ scic_cb_timer_destroy(this_controller, this_controller->power_control.timer);
+ this_controller->power_control.timer = NULL;
+ }
+
+ if(this_controller->timeout_timer != NULL)
+ {
+ scic_cb_timer_destroy(this_controller, this_controller->timeout_timer);
+ this_controller->timeout_timer = NULL;
+ }
+
+ scic_sds_port_configuration_agent_release_resource(
+ this_controller,
+ &this_controller->port_agent);
+
+ for(index = 0; index < SCI_MAX_PORTS+1; index++)
+ {
+ port = &this_controller->port_table[index];
+ scic_sds_port_release_resource(this_controller, port);
+ }
+
+ for(index = 0; index < SCI_MAX_PHYS; index++)
+ {
+ phy = &this_controller->phy_table[index];
+ scic_sds_phy_release_resource(this_controller, phy);
+ }
+
+ return SCI_SUCCESS;
+}
+
+
+/**
+ * @brief This method process the ports configured message from port configuration
+ * agent.
+ *
+ * @param[in] this_controller This parameter specifies the core
+ * controller that its ports are configured.
+ *
+ * @return None.
+ */
+void scic_sds_controller_port_agent_configured_ports(
+ SCIC_SDS_CONTROLLER_T * this_controller
+)
+{
+ //simply transit to ready. The function below checks the controller state
+ scic_sds_controller_transition_to_ready(
+ this_controller, SCI_SUCCESS
+ );
+}
+
+
+//****************************************************************************-
+//* SCIC Controller Public Methods
+//****************************************************************************-
+
+SCI_STATUS scic_controller_construct(
+ SCI_LIBRARY_HANDLE_T library,
+ SCI_CONTROLLER_HANDLE_T controller,
+ void * user_object
+)
+{
+ SCIC_SDS_LIBRARY_T *my_library;
+ SCIC_SDS_CONTROLLER_T *this_controller;
+
+ my_library = (SCIC_SDS_LIBRARY_T *)library;
+ this_controller = (SCIC_SDS_CONTROLLER_T *)controller;
+
+ SCIC_LOG_TRACE((
+ sci_base_object_get_logger(library),
+ SCIC_LOG_OBJECT_CONTROLLER | SCIC_LOG_OBJECT_INITIALIZATION,
+ "scic_controller_construct(0x%x, 0x%x) enter\n",
+ library, controller
+ ));
+
+ // Just clear out the memory of the structure to be safe.
+ memset(this_controller, 0, sizeof(SCIC_SDS_CONTROLLER_T));
+
+ // Make sure that the static data is assigned before moving onto the
+ // base constroller construct as this will cause the controller to
+ // enter its initial state and the controller_index and pci_revision
+ // will be required to complete those operations correctly
+ this_controller->controller_index =
+ scic_sds_library_get_controller_index(my_library, this_controller);
+
+ this_controller->pci_revision = my_library->pci_revision;
+
+ sci_base_controller_construct(
+ &this_controller->parent,
+ sci_base_object_get_logger(my_library),
+ scic_sds_controller_state_table,
+ this_controller->memory_descriptors,
+ ARRAY_SIZE(this_controller->memory_descriptors),
+ NULL
+ );
+
+ sci_object_set_association(controller, user_object);
+
+ scic_sds_controller_initialize_state_logging(this_controller);
+
+ scic_sds_pci_bar_initialization(this_controller);
+
+ return SCI_SUCCESS;
+}
+
+// ---------------------------------------------------------------------------
+
+SCI_STATUS scic_controller_initialize(
+ SCI_CONTROLLER_HANDLE_T controller
+)
+{
+ SCI_STATUS status = SCI_FAILURE_INVALID_STATE;
+ SCIC_SDS_CONTROLLER_T *this_controller;
+ this_controller = (SCIC_SDS_CONTROLLER_T *)controller;
+
+ SCIC_LOG_TRACE((
+ sci_base_object_get_logger(controller),
+ SCIC_LOG_OBJECT_CONTROLLER,
+ "scic_controller_initialize(0x%x, 0x%d) enter\n",
+ controller
+ ));
+
+ if (this_controller->state_handlers->parent.initialize_handler != NULL)
+ {
+ status = this_controller->state_handlers->parent.initialize_handler(
+ (SCI_BASE_CONTROLLER_T *)controller
+ );
+ }
+ else
+ {
+ SCIC_LOG_WARNING((
+ sci_base_object_get_logger(this_controller),
+ SCIC_LOG_OBJECT_CONTROLLER,
+ "SCIC Controller initialize operation requested in invalid state %d\n",
+ sci_base_state_machine_get_state(
+ scic_sds_controller_get_base_state_machine(this_controller))
+ ));
+ }
+
+ return status;
+}
+
+// ---------------------------------------------------------------------------
+
+U32 scic_controller_get_suggested_start_timeout(
+ SCI_CONTROLLER_HANDLE_T controller
+)
+{
+ // Validate the user supplied parameters.
+ if (controller == 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));
+}
+
+// ---------------------------------------------------------------------------
+
+SCI_STATUS scic_controller_start(
+ SCI_CONTROLLER_HANDLE_T controller,
+ U32 timeout
+)
+{
+ SCI_STATUS status = SCI_FAILURE_INVALID_STATE;
+ SCIC_SDS_CONTROLLER_T *this_controller;
+ this_controller = (SCIC_SDS_CONTROLLER_T *)controller;
+
+ SCIC_LOG_TRACE((
+ sci_base_object_get_logger(controller),
+ SCIC_LOG_OBJECT_CONTROLLER,
+ "scic_controller_start(0x%x, 0x%d) enter\n",
+ controller, timeout
+ ));
+
+ if (this_controller->state_handlers->parent.start_handler != NULL)
+ {
+ status = this_controller->state_handlers->parent.start_handler(
+ (SCI_BASE_CONTROLLER_T *)controller, timeout
+ );
+ }
+ else
+ {
+ SCIC_LOG_WARNING((
+ sci_base_object_get_logger(this_controller),
+ SCIC_LOG_OBJECT_CONTROLLER,
+ "SCIC Controller start operation requested in invalid state %d\n",
+ sci_base_state_machine_get_state(
+ scic_sds_controller_get_base_state_machine(this_controller))
+ ));
+ }
+
+ return status;
+}
+
+// ---------------------------------------------------------------------------
+
+SCI_STATUS scic_controller_stop(
+ SCI_CONTROLLER_HANDLE_T controller,
+ U32 timeout
+)
+{
+ SCI_STATUS status = SCI_FAILURE_INVALID_STATE;
+ SCIC_SDS_CONTROLLER_T *this_controller;
+ this_controller = (SCIC_SDS_CONTROLLER_T *)controller;
+
+ SCIC_LOG_TRACE((
+ sci_base_object_get_logger(controller),
+ SCIC_LOG_OBJECT_CONTROLLER,
+ "scic_controller_stop(0x%x, 0x%d) enter\n",
+ controller, timeout
+ ));
+
+ if (this_controller->state_handlers->parent.stop_handler != NULL)
+ {
+ status = this_controller->state_handlers->parent.stop_handler(
+ (SCI_BASE_CONTROLLER_T *)controller, timeout
+ );
+ }
+ else
+ {
+ SCIC_LOG_WARNING((
+ sci_base_object_get_logger(this_controller),
+ SCIC_LOG_OBJECT_CONTROLLER,
+ "SCIC Controller stop operation requested in invalid state %d\n",
+ sci_base_state_machine_get_state(
+ scic_sds_controller_get_base_state_machine(this_controller))
+ ));
+ }
+
+ return status;
+}
+
+// ---------------------------------------------------------------------------
+
+SCI_STATUS scic_controller_reset(
+ SCI_CONTROLLER_HANDLE_T controller
+)
+{
+ SCI_STATUS status = SCI_FAILURE_INVALID_STATE;
+ SCIC_SDS_CONTROLLER_T *this_controller;
+ this_controller = (SCIC_SDS_CONTROLLER_T *)controller;
+
+ SCIC_LOG_TRACE((
+ sci_base_object_get_logger(controller),
+ SCIC_LOG_OBJECT_CONTROLLER,
+ "scic_controller_reset(0x%x) enter\n",
+ controller
+ ));
+
+ if (this_controller->state_handlers->parent.reset_handler != NULL)
+ {
+ status = this_controller->state_handlers->parent.reset_handler(
+ (SCI_BASE_CONTROLLER_T *)controller
+ );
+ }
+ else
+ {
+ SCIC_LOG_WARNING((
+ sci_base_object_get_logger(this_controller),
+ SCIC_LOG_OBJECT_CONTROLLER,
+ "SCIC Controller reset operation requested in invalid state %d\n",
+ sci_base_state_machine_get_state(
+ scic_sds_controller_get_base_state_machine(this_controller))
+ ));
+ }
+
+ return status;
+}
+
+// ---------------------------------------------------------------------------
+
+SCI_STATUS scic_controller_get_handler_methods(
+ SCIC_INTERRUPT_TYPE interrupt_type,
+ U16 message_count,
+ SCIC_CONTROLLER_HANDLER_METHODS_T *handler_methods
+)
+{
+ SCI_STATUS status = SCI_FAILURE_UNSUPPORTED_MESSAGE_COUNT;
+
+ switch (interrupt_type)
+ {
+#if !defined(DISABLE_INTERRUPTS)
+ 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;
+#endif // !defined(DISABLE_INTERRUPTS)
+
+ 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;
+}
+
+// ---------------------------------------------------------------------------
+
+SCI_IO_STATUS scic_controller_start_io(
+ SCI_CONTROLLER_HANDLE_T controller,
+ SCI_REMOTE_DEVICE_HANDLE_T remote_device,
+ SCI_IO_REQUEST_HANDLE_T io_request,
+ U16 io_tag
+)
+{
+ SCI_IO_STATUS status;
+ SCIC_SDS_CONTROLLER_T *this_controller;
+ this_controller = (SCIC_SDS_CONTROLLER_T *)controller;
+
+ SCIC_LOG_TRACE((
+ sci_base_object_get_logger(controller),
+ SCIC_LOG_OBJECT_CONTROLLER,
+ "scic_controller_start_io(0x%x, 0x%x, 0x%x, 0x%x) enter\n",
+ controller, remote_device, io_request, io_tag
+ ));
+
+ status = this_controller->state_handlers->parent.start_io_handler(
+ &this_controller->parent,
+ (SCI_BASE_REMOTE_DEVICE_T *)remote_device,
+ (SCI_BASE_REQUEST_T *)io_request,
+ io_tag
+ );
+
+ return status;
+}
+
+// ---------------------------------------------------------------------------
+
+SCI_STATUS scic_controller_terminate_request(
+ SCI_CONTROLLER_HANDLE_T controller,
+ SCI_REMOTE_DEVICE_HANDLE_T remote_device,
+ SCI_IO_REQUEST_HANDLE_T request
+)
+{
+ SCI_STATUS status;
+ SCIC_SDS_CONTROLLER_T *this_controller;
+ this_controller = (SCIC_SDS_CONTROLLER_T *)controller;
+
+ SCIC_LOG_TRACE((
+ sci_base_object_get_logger(controller),
+ SCIC_LOG_OBJECT_CONTROLLER,
+ "scic_controller_terminate_request(0x%x, 0x%x, 0x%x) enter\n",
+ controller, remote_device, request
+ ));
+
+ status = this_controller->state_handlers->terminate_request_handler(
+ &this_controller->parent,
+ (SCI_BASE_REMOTE_DEVICE_T *)remote_device,
+ (SCI_BASE_REQUEST_T *)request
+ );
+
+ return status;
+}
+
+// ---------------------------------------------------------------------------
+
+SCI_STATUS scic_controller_complete_io(
+ SCI_CONTROLLER_HANDLE_T controller,
+ SCI_REMOTE_DEVICE_HANDLE_T remote_device,
+ SCI_IO_REQUEST_HANDLE_T io_request
+)
+{
+ SCI_STATUS status;
+ SCIC_SDS_CONTROLLER_T *this_controller;
+ this_controller = (SCIC_SDS_CONTROLLER_T *)controller;
+
+ SCIC_LOG_TRACE((
+ sci_base_object_get_logger(controller),
+ SCIC_LOG_OBJECT_CONTROLLER,
+ "scic_controller_complete_io(0x%x, 0x%x, 0x%x) enter\n",
+ controller, remote_device, io_request
+ ));
+
+ status = this_controller->state_handlers->parent.complete_io_handler(
+ &this_controller->parent,
+ (SCI_BASE_REMOTE_DEVICE_T *)remote_device,
+ (SCI_BASE_REQUEST_T *)io_request
+ );
+
+ return status;
+}
+
+// ---------------------------------------------------------------------------
+
+#if !defined(DISABLE_TASK_MANAGEMENT)
+
+SCI_TASK_STATUS scic_controller_start_task(
+ SCI_CONTROLLER_HANDLE_T controller,
+ SCI_REMOTE_DEVICE_HANDLE_T remote_device,
+ SCI_TASK_REQUEST_HANDLE_T task_request,
+ U16 task_tag
+)
+{
+ SCI_TASK_STATUS status = SCI_FAILURE_INVALID_STATE;
+ SCIC_SDS_CONTROLLER_T *this_controller;
+ this_controller = (SCIC_SDS_CONTROLLER_T *)controller;
+
+ SCIC_LOG_TRACE((
+ sci_base_object_get_logger(controller),
+ SCIC_LOG_OBJECT_CONTROLLER,
+ "scic_controller_start_task(0x%x, 0x%x, 0x%x, 0x%x) enter\n",
+ controller, remote_device, task_request, task_tag
+ ));
+
+ if (this_controller->state_handlers->parent.start_task_handler != NULL)
+ {
+ status = this_controller->state_handlers->parent.start_task_handler(
+ &this_controller->parent,
+ (SCI_BASE_REMOTE_DEVICE_T *)remote_device,
+ (SCI_BASE_REQUEST_T *)task_request,
+ task_tag
+ );
+ }
+ else
+ {
+ SCIC_LOG_INFO((
+ sci_base_object_get_logger(controller),
+ SCIC_LOG_OBJECT_CONTROLLER,
+ "SCIC Controller starting task from invalid state\n"
+ ));
+ }
+
+ return status;
+}
+
+// ---------------------------------------------------------------------------
+
+SCI_STATUS scic_controller_complete_task(
+ SCI_CONTROLLER_HANDLE_T controller,
+ SCI_REMOTE_DEVICE_HANDLE_T remote_device,
+ SCI_TASK_REQUEST_HANDLE_T task_request
+)
+{
+ SCI_STATUS status = SCI_FAILURE_INVALID_STATE;
+ SCIC_SDS_CONTROLLER_T *this_controller;
+ this_controller = (SCIC_SDS_CONTROLLER_T *)controller;
+
+ SCIC_LOG_TRACE((
+ sci_base_object_get_logger(controller),
+ SCIC_LOG_OBJECT_CONTROLLER,
+ "scic_controller_complete_task(0x%x, 0x%x, 0x%x) enter\n",
+ controller, remote_device, task_request
+ ));
+
+ if (this_controller->state_handlers->parent.complete_task_handler != NULL)
+ {
+ status = this_controller->state_handlers->parent.complete_task_handler(
+ &this_controller->parent,
+ (SCI_BASE_REMOTE_DEVICE_T *)remote_device,
+ (SCI_BASE_REQUEST_T *)task_request
+ );
+ }
+ else
+ {
+ SCIC_LOG_INFO((
+ sci_base_object_get_logger(controller),
+ SCIC_LOG_OBJECT_CONTROLLER,
+ "SCIC Controller completing task from invalid state\n"
+ ));
+ }
+
+ return status;
+}
+
+#endif // !defined(DISABLE_TASK_MANAGEMENT)
+
+// ---------------------------------------------------------------------------
+
+SCI_STATUS scic_controller_get_port_handle(
+ SCI_CONTROLLER_HANDLE_T controller,
+ U8 port_index,
+ SCI_PORT_HANDLE_T * port_handle
+)
+{
+ SCIC_SDS_CONTROLLER_T *this_controller;
+ this_controller = (SCIC_SDS_CONTROLLER_T *)controller;
+
+ SCIC_LOG_TRACE((
+ sci_base_object_get_logger(controller),
+ SCIC_LOG_OBJECT_CONTROLLER,
+ "scic_controller_get_port_handle(0x%x, 0x%x, 0x%x) enter\n",
+ controller, port_index, port_handle
+ ));
+
+ if (port_index < this_controller->logical_port_entries)
+ {
+ *port_handle = &this_controller->port_table[port_index];
+
+ return SCI_SUCCESS;
+ }
+
+ return SCI_FAILURE_INVALID_PORT;
+}
+
+// ---------------------------------------------------------------------------
+
+SCI_STATUS scic_controller_get_phy_handle(
+ SCI_CONTROLLER_HANDLE_T controller,
+ U8 phy_index,
+ SCI_PHY_HANDLE_T * phy_handle
+)
+{
+ SCIC_SDS_CONTROLLER_T *this_controller;
+ this_controller = (SCIC_SDS_CONTROLLER_T *)controller;
+
+ SCIC_LOG_TRACE((
+ sci_base_object_get_logger(controller),
+ SCIC_LOG_OBJECT_CONTROLLER,
+ "scic_controller_get_phy_handle(0x%x, 0x%x, 0x%x) enter\n",
+ controller, phy_index, phy_handle
+ ));
+
+ if (phy_index < ARRAY_SIZE(this_controller->phy_table))
+ {
+ *phy_handle = &this_controller->phy_table[phy_index];
+
+ return SCI_SUCCESS;
+ }
+
+ SCIC_LOG_ERROR((
+ sci_base_object_get_logger(this_controller),
+ SCIC_LOG_OBJECT_PORT | SCIC_LOG_OBJECT_CONTROLLER,
+ "Controller:0x%x PhyId:0x%x invalid phy index\n",
+ this_controller, phy_index
+ ));
+
+ return SCI_FAILURE_INVALID_PHY;
+}
+
+// ---------------------------------------------------------------------------
+
+U16 scic_controller_allocate_io_tag(
+ SCI_CONTROLLER_HANDLE_T controller
+)
+{
+ U16 task_context;
+ U16 sequence_count;
+ SCIC_SDS_CONTROLLER_T *this_controller;
+ this_controller = (SCIC_SDS_CONTROLLER_T *)controller;
+
+ SCIC_LOG_TRACE((
+ sci_base_object_get_logger(controller),
+ SCIC_LOG_OBJECT_CONTROLLER,
+ "scic_controller_allocate_io_tag(0x%x) enter\n",
+ controller
+ ));
+
+ if (!sci_pool_empty(this_controller->tci_pool))
+ {
+ sci_pool_get(this_controller->tci_pool, task_context);
+
+ sequence_count = this_controller->io_request_sequence[task_context];
+
+ return scic_sds_io_tag_construct(sequence_count, task_context);
+ }
+
+ return SCI_CONTROLLER_INVALID_IO_TAG;
+}
+
+// ---------------------------------------------------------------------------
+
+SCI_STATUS scic_controller_free_io_tag(
+ SCI_CONTROLLER_HANDLE_T controller,
+ U16 io_tag
+)
+{
+ U16 sequence;
+ U16 index;
+
+ SCIC_SDS_CONTROLLER_T *this_controller;
+ this_controller = (SCIC_SDS_CONTROLLER_T *)controller;
+
+ ASSERT(io_tag != SCI_CONTROLLER_INVALID_IO_TAG);
+
+ SCIC_LOG_TRACE((
+ sci_base_object_get_logger(controller),
+ SCIC_LOG_OBJECT_CONTROLLER,
+ "scic_controller_free_io_tag(0x%x, 0x%x) enter\n",
+ controller, io_tag
+ ));
+
+ sequence = scic_sds_io_tag_get_sequence(io_tag);
+ index = scic_sds_io_tag_get_index(io_tag);
+
+ if (!sci_pool_full(this_controller->tci_pool))
+ {
+ if (sequence == this_controller->io_request_sequence[index])
+ {
+ scic_sds_io_sequence_increment(
+ this_controller->io_request_sequence[index]);
+
+ sci_pool_put(this_controller->tci_pool, index);
+
+ return SCI_SUCCESS;
+ }
+ }
+
+ return SCI_FAILURE_INVALID_IO_TAG;
+}
+
+// ---------------------------------------------------------------------------
+
+void scic_controller_enable_interrupts(
+ SCI_CONTROLLER_HANDLE_T controller
+)
+{
+ SCIC_SDS_CONTROLLER_T *this_controller;
+ this_controller = (SCIC_SDS_CONTROLLER_T *)controller;
+
+ ASSERT(this_controller->smu_registers != NULL);
+
+ SMU_IMR_WRITE(this_controller, 0x00000000);
+}
+
+// ---------------------------------------------------------------------------
+
+void scic_controller_disable_interrupts(
+ SCI_CONTROLLER_HANDLE_T controller
+)
+{
+ SCIC_SDS_CONTROLLER_T *this_controller;
+ this_controller = (SCIC_SDS_CONTROLLER_T *)controller;
+
+ ASSERT(this_controller->smu_registers != NULL);
+
+ SMU_IMR_WRITE(this_controller, 0xffffffff);
+}
+
+// ---------------------------------------------------------------------------
+
+SCI_STATUS scic_controller_set_mode(
+ SCI_CONTROLLER_HANDLE_T controller,
+ SCI_CONTROLLER_MODE operating_mode
+)
+{
+ SCIC_SDS_CONTROLLER_T *this_controller = (SCIC_SDS_CONTROLLER_T*)controller;
+ SCI_STATUS status = SCI_SUCCESS;
+
+ SCIC_LOG_TRACE((
+ sci_base_object_get_logger(controller),
+ SCIC_LOG_OBJECT_CONTROLLER,
+ "scic_controller_set_mode(0x%x, 0x%x) enter\n",
+ controller, operating_mode
+ ));
+
+ if (
+ (this_controller->parent.state_machine.current_state_id
+ == SCI_BASE_CONTROLLER_STATE_INITIALIZING)
+ || (this_controller->parent.state_machine.current_state_id
+ == SCI_BASE_CONTROLLER_STATE_INITIALIZED)
+ )
+ {
+ switch (operating_mode)
+ {
+ case SCI_MODE_SPEED:
+ this_controller->remote_node_entries =
+ MIN(this_controller->remote_node_entries, SCI_MAX_REMOTE_DEVICES);
+ this_controller->task_context_entries =
+ MIN(this_controller->task_context_entries, SCU_IO_REQUEST_COUNT);
+ this_controller->uf_control.buffers.count =
+ MIN(this_controller->uf_control.buffers.count, SCU_UNSOLICITED_FRAME_COUNT);
+ this_controller->completion_event_entries =
+ MIN(this_controller->completion_event_entries, SCU_EVENT_COUNT);
+ this_controller->completion_queue_entries =
+ MIN(this_controller->completion_queue_entries, SCU_COMPLETION_QUEUE_COUNT);
+
+ scic_sds_controller_build_memory_descriptor_table(this_controller);
+ break;
+
+ case SCI_MODE_SIZE:
+ this_controller->remote_node_entries =
+ MIN(this_controller->remote_node_entries, SCI_MIN_REMOTE_DEVICES);
+ this_controller->task_context_entries =
+ MIN(this_controller->task_context_entries, SCI_MIN_IO_REQUESTS);
+ this_controller->uf_control.buffers.count =
+ MIN(this_controller->uf_control.buffers.count, SCU_MIN_UNSOLICITED_FRAMES);
+ this_controller->completion_event_entries =
+ MIN(this_controller->completion_event_entries, SCU_MIN_EVENTS);
+ this_controller->completion_queue_entries =
+ MIN(this_controller->completion_queue_entries, SCU_MIN_COMPLETION_QUEUE_ENTRIES);
+
+ scic_sds_controller_build_memory_descriptor_table(this_controller);
+ break;
+
+ default:
+ status = SCI_FAILURE_INVALID_PARAMETER_VALUE;
+ break;
+ }
+ }
+ else
+ status = SCI_FAILURE_INVALID_STATE;
+
+ return status;
+}
+
+/**
+ * This method will reset the controller hardware.
+ *
+ * @param[in] this_controller The controller that is to be reset.
+ */
+void scic_sds_controller_reset_hardware(
+ SCIC_SDS_CONTROLLER_T * this_controller
+)
+{
+ // Disable interrupts so we dont take any spurious interrupts
+ scic_controller_disable_interrupts(this_controller);
+
+ // Reset the SCU
+ SMU_SMUSRCR_WRITE(this_controller, 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(this_controller, 0x00000000);
+
+ // The write to the UFQGP clears the UFQPR
+ SCU_UFQGP_WRITE(this_controller, 0x00000000);
+}
+
+// ---------------------------------------------------------------------------
+
+SCI_STATUS scic_user_parameters_set(
+ SCI_CONTROLLER_HANDLE_T controller,
+ SCIC_USER_PARAMETERS_T * scic_parms
+)
+{
+ SCIC_SDS_CONTROLLER_T * this_controller = (SCIC_SDS_CONTROLLER_T*)controller;
+
+ if (
+ (this_controller->parent.state_machine.current_state_id
+ == SCI_BASE_CONTROLLER_STATE_RESET)
+ || (this_controller->parent.state_machine.current_state_id
+ == SCI_BASE_CONTROLLER_STATE_INITIALIZING)
+ || (this_controller->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;
+
+ if (
+ (scic_parms->sds1.phys[index].in_connection_align_insertion_frequency < 3) ||
+ (scic_parms->sds1.phys[index].align_insertion_frequency == 0) ||
+ (scic_parms->sds1.phys[index].notify_enable_spin_up_insertion_frequency == 0)
+ )
+ {
+ return SCI_FAILURE_INVALID_PARAMETER_VALUE;
+ }
+ }
+
+ if (
+ (scic_parms->sds1.stp_inactivity_timeout == 0) ||
+ (scic_parms->sds1.ssp_inactivity_timeout == 0) ||
+ (scic_parms->sds1.stp_max_occupancy_timeout == 0) ||
+ (scic_parms->sds1.ssp_max_occupancy_timeout == 0) ||
+ (scic_parms->sds1.no_outbound_task_timeout == 0)
+ )
+ {
+ return SCI_FAILURE_INVALID_PARAMETER_VALUE;
+ }
+
+ memcpy(
+ (&this_controller->user_parameters), scic_parms, sizeof(*scic_parms));
+
+ return SCI_SUCCESS;
+ }
+
+ return SCI_FAILURE_INVALID_STATE;
+}
+
+// ---------------------------------------------------------------------------
+
+void scic_user_parameters_get(
+ SCI_CONTROLLER_HANDLE_T controller,
+ SCIC_USER_PARAMETERS_T * scic_parms
+)
+{
+ SCIC_SDS_CONTROLLER_T * this_controller = (SCIC_SDS_CONTROLLER_T*)controller;
+
+ memcpy(scic_parms, (&this_controller->user_parameters), sizeof(*scic_parms));
+}
+
+// ---------------------------------------------------------------------------
+SCI_STATUS scic_oem_parameters_set(
+ SCI_CONTROLLER_HANDLE_T controller,
+ SCIC_OEM_PARAMETERS_T * scic_parms,
+ U8 scic_parms_version
+)
+{
+ SCIC_SDS_CONTROLLER_T * this_controller = (SCIC_SDS_CONTROLLER_T*)controller;
+ SCI_BIOS_OEM_PARAM_ELEMENT_T *old_oem_params =
+ (SCI_BIOS_OEM_PARAM_ELEMENT_T *)(&(scic_parms->sds1));
+
+
+ if (
+ (this_controller->parent.state_machine.current_state_id
+ == SCI_BASE_CONTROLLER_STATE_RESET)
+ || (this_controller->parent.state_machine.current_state_id
+ == SCI_BASE_CONTROLLER_STATE_INITIALIZING)
+ || (this_controller->parent.state_machine.current_state_id
+ == SCI_BASE_CONTROLLER_STATE_INITIALIZED)
+ )
+ {
+ U16 index;
+ U8 combined_phy_mask = 0;
+
+ /*
+ * Set the OEM parameter version for the controller. This comes
+ * from the OEM parameter block header or the registry depending
+ * on what WCDL is set to retrieve.
+ */
+ this_controller->oem_parameters_version = scic_parms_version;
+
+ // 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.sci_format.high == 0
+ && scic_parms->sds1.phys[index].sas_address.sci_format.low == 0
+ )
+ {
+ return SCI_FAILURE_INVALID_PARAMETER_VALUE;
+ }
+
+#if defined(PBG_HBA_A0_BUILD) || defined(PBG_HBA_A2_BUILD) || defined(PBG_HBA_BETA_BUILD) || defined(PBG_BUILD)
+ if (
+ (scic_parms->sds1.phys[index].afe_tx_amp_control0 == 0) ||
+ (scic_parms->sds1.phys[index].afe_tx_amp_control1 == 0) ||
+ (scic_parms->sds1.phys[index].afe_tx_amp_control2 == 0) ||
+ (scic_parms->sds1.phys[index].afe_tx_amp_control3 == 0)
+ )
+ {
+ return SCI_FAILURE_INVALID_PARAMETER_VALUE;
+ }
+#endif
+ }
+
+ if (scic_parms->sds1.controller.mode_type == SCIC_PORT_AUTOMATIC_CONFIGURATION_MODE)
+ {
+ for(index=0; index<SCI_MAX_PHYS; index++)
+ {
+ if (scic_parms->sds1.ports[index].phy_mask != 0)
+ {
+ return SCI_FAILURE_INVALID_PARAMETER_VALUE;
+ }
+ }
+ }
+ else if (scic_parms->sds1.controller.mode_type == SCIC_PORT_MANUAL_CONFIGURATION_MODE)
+ {
+ for(index=0; index<SCI_MAX_PHYS; index++)
+ {
+ combined_phy_mask |= scic_parms->sds1.ports[index].phy_mask;
+ }
+
+ if (combined_phy_mask == 0)
+ {
+ return SCI_FAILURE_INVALID_PARAMETER_VALUE;
+ }
+ }
+ else
+ {
+ return SCI_FAILURE_INVALID_PARAMETER_VALUE;
+ }
+
+ if (scic_parms->sds1.controller.max_number_concurrent_device_spin_up > MAX_CONCURRENT_DEVICE_SPIN_UP_COUNT)
+ {
+ return SCI_FAILURE_INVALID_PARAMETER_VALUE;
+ }
+
+ if (old_oem_params->controller.do_enable_ssc != 0)
+ {
+ if ( (scic_parms_version == SCI_OEM_PARAM_VER_1_0)
+ && (old_oem_params->controller.do_enable_ssc != 0x01))
+ return SCI_FAILURE_INVALID_PARAMETER_VALUE;
+
+ if (scic_parms_version >= SCI_OEM_PARAM_VER_1_1)
+ {
+ SCI_BIOS_OEM_PARAM_ELEMENT_v_1_1_T *oem_params =
+ (SCI_BIOS_OEM_PARAM_ELEMENT_v_1_1_T*)(&(scic_parms->sds1));
+
+ U8 test = oem_params->controller.ssc_sata_tx_spread_level;
+ if ( !((test == 0x0) || (test == 0x2) || (test == 0x3) ||
+ (test == 0x6) || (test == 0x7)) )
+ return SCI_FAILURE_INVALID_PARAMETER_VALUE;
+
+ test = oem_params->controller.ssc_sas_tx_spread_level;
+ if (oem_params->controller.ssc_sas_tx_type == 0)
+ {
+ if ( !((test == 0x0) || (test == 0x2) || (test == 0x3)) )
+ return SCI_FAILURE_INVALID_PARAMETER_VALUE;
+ }
+ else
+ if (oem_params->controller.ssc_sas_tx_type == 1)
+ {
+ if ( !((test == 0x0) || (test == 0x3) || (test == 0x6)) )
+ return SCI_FAILURE_INVALID_PARAMETER_VALUE;
+ }
+ }
+ }
+
+ memcpy(
+ (&this_controller->oem_parameters), scic_parms, sizeof(*scic_parms));
+ return SCI_SUCCESS;
+ }
+
+ return SCI_FAILURE_INVALID_STATE;
+}
+
+// ---------------------------------------------------------------------------
+
+void scic_oem_parameters_get(
+ SCI_CONTROLLER_HANDLE_T controller,
+ SCIC_OEM_PARAMETERS_T * scic_parms
+)
+{
+ SCIC_SDS_CONTROLLER_T * this_controller = (SCIC_SDS_CONTROLLER_T*)controller;
+
+ memcpy(scic_parms, (&this_controller->oem_parameters), sizeof(*scic_parms));
+}
+
+// ---------------------------------------------------------------------------
+
+#if !defined(DISABLE_INTERRUPTS)
+
+#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
+
+SCI_STATUS scic_controller_set_interrupt_coalescence(
+ SCI_CONTROLLER_HANDLE_T controller,
+ U32 coalesce_number,
+ U32 coalesce_timeout
+)
+{
+ SCIC_SDS_CONTROLLER_T * scic_controller = (SCIC_SDS_CONTROLLER_T *)controller;
+ 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;
+}
+
+// ---------------------------------------------------------------------------
+
+void scic_controller_get_interrupt_coalescence(
+ SCI_CONTROLLER_HANDLE_T controller,
+ U32 * coalesce_number,
+ U32 * coalesce_timeout
+)
+{
+ SCIC_SDS_CONTROLLER_T * scic_controller = (SCIC_SDS_CONTROLLER_T *)controller;
+ *coalesce_number = scic_controller->interrupt_coalesce_number;
+ *coalesce_timeout = scic_controller->interrupt_coalesce_timeout;
+}
+
+#endif // !defined(DISABLE_INTERRUPTS)
+
+// ---------------------------------------------------------------------------
+
+U32 scic_controller_get_scratch_ram_size(
+ SCI_CONTROLLER_HANDLE_T controller
+)
+{
+ return SCU_SCRATCH_RAM_SIZE_IN_DWORDS;
+}
+
+// ---------------------------------------------------------------------------
+
+SCI_STATUS scic_controller_read_scratch_ram_dword(
+ SCI_CONTROLLER_HANDLE_T controller,
+ U32 offset,
+ U32 * value
+)
+{
+ U32 zpt_index;
+ SCIC_SDS_CONTROLLER_T * scic_controller = (SCIC_SDS_CONTROLLER_T *)controller;
+ U32 status = SMU_SMUCSR_READ(scic_controller);
+
+ //Check if the SCU Scratch RAM been initialized, if not return zeros
+ if ((status & SCU_RAM_INIT_COMPLETED) != SCU_RAM_INIT_COMPLETED)
+ {
+ *value = 0x00000000;
+ return SCI_SUCCESS;
+ }
+
+ if (offset < scic_controller_get_scratch_ram_size(controller))
+ {
+ if(offset <= SCU_MAX_ZPT_DWORD_INDEX)
+ {
+ zpt_index = offset + (offset - (offset % 4)) + 4;
+
+ *value = scu_controller_scratch_ram_register_read(scic_controller,zpt_index);
+ }
+ else //offset > SCU_MAX_ZPT_DWORD_INDEX
+ {
+ offset = offset - 132;
+
+ zpt_index = offset + (offset - (offset % 4)) + 4;
+
+ *value = scu_controller_scratch_ram_register_read_ext(scic_controller,zpt_index);
+ }
+
+ return SCI_SUCCESS;
+ }
+ else
+ {
+ return SCI_FAILURE_INVALID_PARAMETER_VALUE;
+ }
+}
+
+// ---------------------------------------------------------------------------
+
+SCI_STATUS scic_controller_write_scratch_ram_dword(
+ SCI_CONTROLLER_HANDLE_T controller,
+ U32 offset,
+ U32 value
+)
+{
+ U32 zpt_index;
+
+ if (offset < scic_controller_get_scratch_ram_size(controller))
+ {
+ SCIC_SDS_CONTROLLER_T * scic_controller = (SCIC_SDS_CONTROLLER_T *)controller;
+
+ if(offset <= SCU_MAX_ZPT_DWORD_INDEX)
+ {
+ zpt_index = offset + (offset - (offset % 4)) + 4;
+
+ scu_controller_scratch_ram_register_write(scic_controller,zpt_index,value);
+ }
+ else //offset > SCU_MAX_ZPT_DWORD_INDEX
+ {
+ offset = offset - 132;
+
+ zpt_index = offset + (offset - (offset % 4)) + 4;
+
+ scu_controller_scratch_ram_register_write_ext(scic_controller,zpt_index,value);
+
+ }
+
+ return SCI_SUCCESS;
+ }
+ else
+ {
+ return SCI_FAILURE_INVALID_PARAMETER_VALUE;
+ }
+}
+
+// ---------------------------------------------------------------------------
+
+SCI_STATUS scic_controller_suspend(
+ SCI_CONTROLLER_HANDLE_T controller
+)
+{
+ SCIC_SDS_CONTROLLER_T * this_controller = (SCIC_SDS_CONTROLLER_T*)controller;
+ U8 index;
+
+ // As a precaution, disable interrupts. The user is required
+ // to re-enable interrupts if so desired after the call.
+ scic_controller_disable_interrupts(controller);
+
+ // Stop all the timers
+ // Maybe change the states of the objects to avoid processing stuff.
+
+
+ // Suspend the Ports in order to ensure no unexpected
+ // frame reception occurs on the links from the target
+ for (index = 0; index < SCI_MAX_PORTS; index++)
+ scic_sds_port_suspend_port_task_scheduler(
+ &(this_controller->port_table[index]));
+
+ // Disable/Reset the completion queue and unsolicited frame
+ // queue.
+ SMU_CQGR_WRITE(this_controller, 0x00000000);
+ SCU_UFQGP_WRITE(this_controller, 0x00000000);
+
+ // Clear any interrupts that may be pending or may have been generated
+ // by setting CQGR and CQPR back to 0
+ SMU_ISR_WRITE(this_controller, 0xFFFFFFFF);
+
+ //reset the software get pointer to completion queue.
+ this_controller->completion_queue_get = 0;
+
+ return SCI_SUCCESS;
+}
+
+// ---------------------------------------------------------------------------
+
+SCI_STATUS scic_controller_resume(
+ SCI_CONTROLLER_HANDLE_T controller
+)
+{
+ SCIC_SDS_CONTROLLER_T * this_controller = (SCIC_SDS_CONTROLLER_T*)controller;
+ U8 index;
+
+ // Initialize the completion queue and unsolicited frame queue.
+ scic_sds_controller_initialize_completion_queue(this_controller);
+ scic_sds_controller_initialize_unsolicited_frame_queue(this_controller);
+
+ this_controller->restrict_completions = FALSE;
+
+ // Release the port suspensions to allow for further successful
+ // operation.
+ for (index = 0; index < SCI_MAX_PORTS; index++)
+ scic_sds_port_resume_port_task_scheduler(
+ &(this_controller->port_table[index]));
+
+ //check the link layer status register DWORD sync acquired bit to detect
+ //link down event. If there is any link down event happened during controller
+ //suspension, restart phy state machine.
+ for (index = 0; index < SCI_MAX_PHYS; index ++)
+ {
+ SCIC_SDS_PHY_T * curr_phy = &this_controller->phy_table[index];
+ U32 link_layer_status = SCU_SAS_LLSTA_READ(curr_phy);
+
+ if ((link_layer_status & SCU_SAS_LLSTA_DWORD_SYNCA_BIT) == 0)
+ {
+ //Need to put the phy back to start OOB. Then an appropriate link event
+ //message will be send to scic user.
+ scic_sds_phy_restart_starting_state(curr_phy);
+ }
+ }
+
+ return SCI_SUCCESS;
+}
+
+// ---------------------------------------------------------------------------
+
+SCI_STATUS scic_controller_transition(
+ SCI_CONTROLLER_HANDLE_T controller,
+ BOOL restrict_completions
+)
+{
+ SCI_STATUS result = SCI_FAILURE_INVALID_STATE;
+ SCIC_SDS_CONTROLLER_T * this_controller = (SCIC_SDS_CONTROLLER_T*)controller;
+ U8 index;
+
+ SCIC_LOG_TRACE((
+ sci_base_object_get_logger(controller),
+ SCIC_LOG_OBJECT_CONTROLLER,
+ "scic_controller_transition(0x%x) enter\n",
+ controller
+ ));
+
+ if (this_controller->parent.state_machine.current_state_id
+ == SCI_BASE_CONTROLLER_STATE_READY)
+ {
+ // Ensure that there are no outstanding IO operations at this
+ // time.
+ for (index = 0; index < SCI_MAX_PORTS; index++)
+ {
+ if (this_controller->port_table[index].started_request_count != 0)
+ return result;
+ }
+
+ scic_controller_suspend(controller);
+
+ // Loop through the memory descriptor list and reprogram
+ // the silicon memory registers accordingly.
+ result = scic_sds_controller_validate_memory_descriptor_table(
+ this_controller);
+ if (result == SCI_SUCCESS)
+ {
+ scic_sds_controller_ram_initialization(this_controller);
+ this_controller->restrict_completions = restrict_completions;
+ }
+
+ scic_controller_resume(controller);
+ }
+
+ return result;
+}
+
+// ---------------------------------------------------------------------------
+
+SCI_STATUS scic_controller_get_max_ports(
+ SCI_CONTROLLER_HANDLE_T controller,
+ U8 * count
+)
+{
+ *count = SCI_MAX_PORTS;
+ return SCI_SUCCESS;
+}
+
+// ---------------------------------------------------------------------------
+
+SCI_STATUS scic_controller_get_max_phys(
+ SCI_CONTROLLER_HANDLE_T controller,
+ U8 * count
+)
+{
+ *count = SCI_MAX_PHYS;
+ return SCI_SUCCESS;
+}
+
+
+//******************************************************************************
+//* CONTROLLER STATE MACHINE
+//******************************************************************************
+
+/**
+ * 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) \
+ ( \
+ ( ((U32)((dcc_value) & SMU_DEVICE_CONTEXT_CAPACITY_MAX_LP_MASK)) \
+ >> SMU_DEVICE_CONTEXT_CAPACITY_MAX_LP_SHIFT ) + 1\
+ )
+
+/**
+ * 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) \
+ ( \
+ ( ((U32)((dcc_value) & SMU_DEVICE_CONTEXT_CAPACITY_MAX_TC_MASK)) \
+ >> SMU_DEVICE_CONTEXT_CAPACITY_MAX_TC_SHIFT ) + 1\
+ )
+
+/**
+ * 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) \
+ ( \
+ ( ( (U32)((dcc_value) & SMU_DEVICE_CONTEXT_CAPACITY_MAX_RNC_MASK) )\
+ >> SMU_DEVICE_CONTEXT_CAPACITY_MAX_RNC_SHIFT ) + 1\
+ )
+
+//*****************************************************************************
+//* DEFAULT STATE HANDLERS
+//*****************************************************************************
+
+/**
+ * This method is called when the SCIC_SDS_CONTROLLER default start
+ * io/task handler is in place.
+ * - Issue a warning message
+ *
+ * @param[in] controller This is SCI_BASE_CONTROLLER object which is cast
+ * into a SCIC_SDS_CONTROLLER object.
+ * @param[in] remote_device This is SCI_BASE_REMOTE_DEVICE which, if it was
+ * used, would be cast to a SCIC_SDS_REMOTE_DEVICE.
+ * @param[in] io_request This is the SCI_BASE_REQUEST which, if it was used,
+ * would be cast to a SCIC_SDS_IO_REQUEST.
+ * @param[in] io_tag This is the IO tag to be assigned to the IO request or
+ * SCI_CONTROLLER_INVALID_IO_TAG.
+ *
+ * @return SCI_STATUS
+ * @retval SCI_FAILURE_INVALID_STATE
+ */
+static
+SCI_STATUS scic_sds_controller_default_start_operation_handler(
+ SCI_BASE_CONTROLLER_T *controller,
+ SCI_BASE_REMOTE_DEVICE_T *remote_device,
+ SCI_BASE_REQUEST_T *io_request,
+ U16 io_tag
+)
+{
+ SCIC_SDS_CONTROLLER_T *this_controller;
+ this_controller = (SCIC_SDS_CONTROLLER_T *)controller;
+
+ SCIC_LOG_WARNING((
+ sci_base_object_get_logger(this_controller),
+ SCIC_LOG_OBJECT_CONTROLLER,
+ "SCIC Controller requested to start an io/task from invalid state %d\n",
+ sci_base_state_machine_get_state(
+ scic_sds_controller_get_base_state_machine(this_controller))
+ ));
+
+ return SCI_FAILURE_INVALID_STATE;
+}
+
+/**
+ * This method is called when the SCIC_SDS_CONTROLLER default
+ * request handler is in place.
+ * - Issue a warning message
+ *
+ * @param[in] controller This is SCI_BASE_CONTROLLER object which is cast
+ * into a SCIC_SDS_CONTROLLER object.
+ * @param[in] remote_device This is SCI_BASE_REMOTE_DEVICE which, if it was
+ * used, would be cast to a SCIC_SDS_REMOTE_DEVICE.
+ * @param[in] io_request This is the SCI_BASE_REQUEST which, if it was used,
+ * would be cast to a SCIC_SDS_IO_REQUEST.
+ *
+ * @return SCI_STATUS
+ * @retval SCI_FAILURE_INVALID_STATE
+ */
+static
+SCI_STATUS scic_sds_controller_default_request_handler(
+ SCI_BASE_CONTROLLER_T *controller,
+ SCI_BASE_REMOTE_DEVICE_T *remote_device,
+ SCI_BASE_REQUEST_T *io_request
+)
+{
+ SCIC_SDS_CONTROLLER_T *this_controller;
+ this_controller = (SCIC_SDS_CONTROLLER_T *)controller;
+
+ SCIC_LOG_WARNING((
+ sci_base_object_get_logger(this_controller),
+ SCIC_LOG_OBJECT_CONTROLLER,
+ "SCIC Controller request operation from invalid state %d\n",
+ sci_base_state_machine_get_state(
+ scic_sds_controller_get_base_state_machine(this_controller))
+ ));
+
+ return SCI_FAILURE_INVALID_STATE;
+}
+
+//*****************************************************************************
+//* GENERAL (COMMON) STATE HANDLERS
+//*****************************************************************************
+
+/**
+ * This method is called when the SCIC_SDS_CONTROLLER is in the ready state
+ * reset handler is in place.
+ * - Transition to SCI_BASE_CONTROLLER_STATE_RESETTING
+ *
+ * @param[in] controller The SCI_BASE_CONTROLLER object which is cast into a
+ * SCIC_SDS_CONTROLLER object.
+ *
+ * @return SCI_STATUS
+ * @retval SCI_SUCCESS
+ */
+static
+SCI_STATUS scic_sds_controller_general_reset_handler(
+ SCI_BASE_CONTROLLER_T *controller
+)
+{
+ SCIC_SDS_CONTROLLER_T *this_controller;
+ this_controller = (SCIC_SDS_CONTROLLER_T *)controller;
+
+ SCIC_LOG_TRACE((
+ sci_base_object_get_logger(controller),
+ SCIC_LOG_OBJECT_CONTROLLER,
+ "scic_sds_controller_resetting_state_enter(0x%x) enter\n",
+ controller
+ ));
+
+ //Release resource. So far only resource to be released are timers.
+ scic_sds_controller_release_resource(this_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
+//*****************************************************************************
+
+/**
+ * This method is the SCIC_SDS_CONTROLLER initialize handler for the reset
+ * state.
+ * - Currently this function does nothing
+ *
+ * @param[in] controller This is the SCI_BASE_CONTROLLER object which is cast
+ * into a SCIC_SDS_CONTROLLER object.
+ *
+ * @return SCI_STATUS
+ * @retval SCI_FAILURE
+ *
+ * @todo This function is not yet implemented and is a valid request from the
+ * reset state.
+ */
+static
+SCI_STATUS scic_sds_controller_reset_state_initialize_handler(
+ SCI_BASE_CONTROLLER_T *controller
+)
+{
+ U32 index;
+ SCI_STATUS result = SCI_SUCCESS;
+ SCIC_SDS_CONTROLLER_T *this_controller;
+
+ this_controller = (SCIC_SDS_CONTROLLER_T *)controller;
+
+ SCIC_LOG_TRACE((
+ sci_base_object_get_logger(controller),
+ SCIC_LOG_OBJECT_CONTROLLER | SCIC_LOG_OBJECT_INITIALIZATION,
+ "scic_sds_controller_reset_state_initialize_handler(0x%x) enter\n",
+ 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(
+ controller,
+ scic_sds_controller_timeout_handler,
+ controller
+ );
+
+ scic_sds_controller_initialize_power_control(this_controller);
+
+ /// todo: This should really be done in the reset state enter but
+ /// the controller has not yet been initialized before getting
+ /// to the reset enter state so the PCI BAR is not yet assigned
+ scic_sds_controller_reset_hardware(this_controller);
+
+#if defined(ARLINGTON_BUILD)
+ scic_sds_controller_lex_atux_initialization(this_controller);
+#elif defined(PLEASANT_RIDGE_BUILD) \
+ || defined(PBG_HBA_A0_BUILD) \
+ || defined(PBG_HBA_A2_BUILD)
+ scic_sds_controller_afe_initialization(this_controller);
+#elif defined(PBG_HBA_BETA_BUILD) || defined(PBG_BUILD)
+ // 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);
+#else // !defined(ARLINGTON_BUILD) && !defined(PLEASANT_RIDGE_BUILD)
+ // What other systems do we want to add here?
+#endif // !defined(ARLINGTON_BUILD) && !defined(PLEASANT_RIDGE_BUILD)
+
+ 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;
+ }
+ }
+ }
+
+#ifdef ARLINGTON_BUILD
+ scic_sds_controller_enable_chipwatch(this_controller);
+#endif
+
+ 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
+ );
+ }
+
+ // 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);
+
+ // 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);
+ }
+
+ // 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].tl,
+ &this_controller->scu_registers->peg0.pe[index].ll
+ );
+ }
+ }
+
+ //Initialize the SGPIO Unit for HARDWARE controlled SGPIO
+ if(result == SCI_SUCCESS)
+ {
+ scic_sgpio_hardware_initialize(this_controller);
+ }
+
+ 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.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
+ {
+ //stay in the same state and release the resource
+ scic_sds_controller_release_resource(this_controller);
+
+ SCIC_LOG_TRACE((
+ sci_base_object_get_logger(controller),
+ SCIC_LOG_OBJECT_CONTROLLER | SCIC_LOG_OBJECT_INITIALIZATION,
+ "Invalid Port Configuration from scic_sds_controller_reset_state_initialize_handler(0x%x) \n",
+ controller
+ ));
+
+ }
+
+ return result;
+}
+
+//*****************************************************************************
+//* INITIALIZED STATE HANDLERS
+//*****************************************************************************
+
+/**
+ * This method is the 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.
+ *
+ * @param[in] controller This is the SCI_BASE_CONTROLLER object which is cast
+ * into a SCIC_SDS_CONTROLLER object.
+ * @param[in] timeout This is the allowed time for the controller object to
+ * reach the started state.
+ *
+ * @return SCI_STATUS
+ * @retval SCI_SUCCESS if all of the controller start operations complete
+ * @retval SCI_FAILURE_UNSUPPORTED_INFORMATION_FIELD if one or more of the
+ * memory descriptor fields is invalid.
+ */
+static
+SCI_STATUS scic_sds_controller_initialized_state_start_handler(
+ SCI_BASE_CONTROLLER_T * controller,
+ U32 timeout
+)
+{
+ U16 index;
+ SCI_STATUS result;
+ SCIC_SDS_CONTROLLER_T * this_controller;
+
+ this_controller = (SCIC_SDS_CONTROLLER_T *)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(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);
+
+ // Setup the phy start timer
+ result = scic_sds_controller_initialize_phy_startup(this_controller);
+ }
+
+ // Start all of the ports on this controller
+ for (
+ index = 0;
+ (index < this_controller->logical_port_entries) && (result == SCI_SUCCESS);
+ index++
+ )
+ {
+ result = this_controller->port_table[index].
+ state_handlers->parent.start_handler(&this_controller->port_table[index].parent);
+ }
+
+ if (SCI_SUCCESS == result)
+ {
+ scic_sds_controller_start_next_phy(this_controller);
+
+ // See if the user requested to timeout this operation.
+ if (timeout != 0)
+ scic_cb_timer_start(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;
+}
+
+//*****************************************************************************
+//* STARTING STATE HANDLERS
+//*****************************************************************************
+
+/**
+ * This method is called when the 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
+ *
+ * @param[in] controller This is SCIC_SDS_CONTROLLER which receives the link up
+ * notification.
+ * @param[in] port This is SCIC_SDS_PORT with which the phy is associated.
+ * @param[in] phy This is the SCIC_SDS_PHY which has gone link up.
+ *
+ * @return none
+ */
+static
+void scic_sds_controller_starting_state_link_up_handler(
+ SCIC_SDS_CONTROLLER_T *this_controller,
+ SCIC_SDS_PORT_T *port,
+ SCIC_SDS_PHY_T *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);
+}
+
+/**
+ * This method is called when the SCIC_SDS_CONTROLLER is in the starting state
+ * link down handler is called.
+ * - Report the link down condition to the port object
+ *
+ * @param[in] controller This is SCIC_SDS_CONTROLLER which receives the
+ * link down notification.
+ * @param[in] port This is SCIC_SDS_PORT with which the phy is associated.
+ * @param[in] phy This is the SCIC_SDS_PHY which has gone link down.
+ *
+ * @return none
+ */
+static
+void scic_sds_controller_starting_state_link_down_handler(
+ SCIC_SDS_CONTROLLER_T *this_controller,
+ SCIC_SDS_PORT_T *port,
+ SCIC_SDS_PHY_T *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
+//*****************************************************************************
+
+/**
+ * This method is called when the SCIC_SDS_CONTROLLER is in the ready state
+ * stop handler is called.
+ * - Start the timeout timer
+ * - Transition to SCI_BASE_CONTROLLER_STATE_STOPPING.
+ *
+ * @param[in] controller The SCI_BASE_CONTROLLER object which is cast into a
+ * SCIC_SDS_CONTROLLER object.
+ * @param[in] timeout The timeout for when the stop operation should report a
+ * failure.
+ *
+ * @return SCI_STATUS
+ * @retval SCI_SUCCESS
+ */
+static
+SCI_STATUS scic_sds_controller_ready_state_stop_handler(
+ SCI_BASE_CONTROLLER_T *controller,
+ U32 timeout
+)
+{
+ SCIC_SDS_CONTROLLER_T *this_controller;
+ this_controller = (SCIC_SDS_CONTROLLER_T *)controller;
+
+ // See if the user requested to timeout this operation
+ if (timeout != 0)
+ scic_cb_timer_start(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;
+}
+
+/**
+ * This method is called when the 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
+ *
+ * @param[in] controller This is SCI_BASE_CONTROLLER object which is cast
+ * into a SCIC_SDS_CONTROLLER object.
+ * @param[in] remote_device This is SCI_BASE_REMOTE_DEVICE which is cast to a
+ * SCIC_SDS_REMOTE_DEVICE object.
+ * @param[in] io_request This is the SCI_BASE_REQUEST which is cast to a
+ * SCIC_SDS_IO_REQUEST object.
+ * @param[in] io_tag This is the IO tag to be assigned to the IO request or
+ * SCI_CONTROLLER_INVALID_IO_TAG.
+ *
+ * @return SCI_STATUS
+ * @retval SCI_SUCCESS if the start io operation succeeds
+ * @retval SCI_FAILURE_INSUFFICIENT_RESOURCES if the IO tag could not be
+ * allocated for the io request.
+ * @retval SCI_FAILURE_INVALID_STATE if one or more objects are not in a valid
+ * state to accept io requests.
+ *
+ * @todo How does the io_tag parameter get assigned to the io request?
+ */
+static
+SCI_STATUS scic_sds_controller_ready_state_start_io_handler(
+ SCI_BASE_CONTROLLER_T *controller,
+ SCI_BASE_REMOTE_DEVICE_T *remote_device,
+ SCI_BASE_REQUEST_T *io_request,
+ U16 io_tag
+)
+{
+ SCI_STATUS status;
+
+ SCIC_SDS_CONTROLLER_T *this_controller;
+ SCIC_SDS_REQUEST_T *the_request;
+ SCIC_SDS_REMOTE_DEVICE_T *the_device;
+
+ this_controller = (SCIC_SDS_CONTROLLER_T *)controller;
+ the_request = (SCIC_SDS_REQUEST_T *)io_request;
+ the_device = (SCIC_SDS_REMOTE_DEVICE_T *)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;
+}
+
+/**
+ * This method is called when the 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
+ *
+ * @param[in] controller This is SCI_BASE_CONTROLLER object which is cast
+ * into a SCIC_SDS_CONTROLLER object.
+ * @param[in] remote_device This is SCI_BASE_REMOTE_DEVICE which is cast to a
+ * SCIC_SDS_REMOTE_DEVICE object.
+ * @param[in] io_request This is the SCI_BASE_REQUEST which is cast to a
+ * SCIC_SDS_IO_REQUEST object.
+ *
+ * @return SCI_STATUS
+ * @retval SCI_SUCCESS if the start io operation succeeds
+ * @retval SCI_FAILURE_INVALID_STATE if one or more objects are not in a valid
+ * state to accept io requests.
+ */
+static
+SCI_STATUS scic_sds_controller_ready_state_complete_io_handler(
+ SCI_BASE_CONTROLLER_T *controller,
+ SCI_BASE_REMOTE_DEVICE_T *remote_device,
+ SCI_BASE_REQUEST_T *io_request
+)
+{
+ U16 index;
+ SCI_STATUS status;
+ SCIC_SDS_CONTROLLER_T *this_controller;
+ SCIC_SDS_REQUEST_T *the_request;
+ SCIC_SDS_REMOTE_DEVICE_T *the_device;
+
+ this_controller = (SCIC_SDS_CONTROLLER_T *)controller;
+ the_request = (SCIC_SDS_REQUEST_T *)io_request;
+ the_device = (SCIC_SDS_REMOTE_DEVICE_T *)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;
+}
+
+/**
+ * This method is called when the SCIC_SDS_CONTROLLER is in the ready state
+ * and the continue io handler is called.
+ *
+ * @param[in] controller This is SCI_BASE_CONTROLLER object which is cast
+ * into a SCIC_SDS_CONTROLLER object.
+ * @param[in] remote_device This is SCI_BASE_REMOTE_DEVICE which is cast to a
+ * SCIC_SDS_REMOTE_DEVICE object.
+ * @param[in] io_request This is the SCI_BASE_REQUEST which is cast to a
+ * SCIC_SDS_IO_REQUEST object.
+ *
+ * @return SCI_STATUS
+ */
+static
+SCI_STATUS scic_sds_controller_ready_state_continue_io_handler(
+ SCI_BASE_CONTROLLER_T *controller,
+ SCI_BASE_REMOTE_DEVICE_T *remote_device,
+ SCI_BASE_REQUEST_T *io_request
+)
+{
+ SCIC_SDS_CONTROLLER_T *this_controller;
+ SCIC_SDS_REQUEST_T *the_request;
+
+ the_request = (SCIC_SDS_REQUEST_T *)io_request;
+ this_controller = (SCIC_SDS_CONTROLLER_T *)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;
+}
+
+/**
+ * This method is called when the 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
+ *
+ * @param[in] controller This is SCI_BASE_CONTROLLER object which is cast
+ * into a SCIC_SDS_CONTROLLER object.
+ * @param[in] remote_device This is SCI_BASE_REMOTE_DEVICE which is cast to a
+ * SCIC_SDS_REMOTE_DEVICE object.
+ * @param[in] io_request This is the SCI_BASE_REQUEST which is cast to a
+ * SCIC_SDS_IO_REQUEST object.
+ * @param[in] task_tag This is the task tag to be assigned to the task request
+ * or SCI_CONTROLLER_INVALID_IO_TAG.
+ *
+ * @return SCI_STATUS
+ * @retval SCI_SUCCESS if the start io operation succeeds
+ * @retval SCI_FAILURE_INSUFFICIENT_RESOURCES if the IO tag could not be
+ * allocated for the io request.
+ * @retval SCI_FAILURE_INVALID_STATE if one or more objects are not in a valid
+ * state to accept io requests.
+ *
+ * @todo How does the io tag get assigned in this code path?
+ */
+static
+SCI_STATUS scic_sds_controller_ready_state_start_task_handler(
+ SCI_BASE_CONTROLLER_T *controller,
+ SCI_BASE_REMOTE_DEVICE_T *remote_device,
+ SCI_BASE_REQUEST_T *io_request,
+ U16 task_tag
+)
+{
+ SCIC_SDS_CONTROLLER_T *this_controller = (SCIC_SDS_CONTROLLER_T *)
+ controller;
+ SCIC_SDS_REQUEST_T *the_request = (SCIC_SDS_REQUEST_T *)
+ io_request;
+ SCIC_SDS_REMOTE_DEVICE_T *the_device = (SCIC_SDS_REMOTE_DEVICE_T *)
+ remote_device;
+ 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;
+}
+
+/**
+ * This method is called when the 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
+ *
+ * @param[in] controller This is SCI_BASE_CONTROLLER object which is cast
+ * into a SCIC_SDS_CONTROLLER object.
+ * @param[in] remote_device This is SCI_BASE_REMOTE_DEVICE which is cast to a
+ * SCIC_SDS_REMOTE_DEVICE object.
+ * @param[in] io_request This is the SCI_BASE_REQUEST which is cast to a
+ * SCIC_SDS_IO_REQUEST object.
+ *
+ * @return SCI_STATUS
+ * @retval SCI_SUCCESS if the start io operation succeeds
+ * @retval SCI_FAILURE_INVALID_STATE if one or more objects are not in a valid
+ * state to accept io requests.
+ */
+static
+SCI_STATUS scic_sds_controller_ready_state_terminate_request_handler(
+ SCI_BASE_CONTROLLER_T *controller,
+ SCI_BASE_REMOTE_DEVICE_T *remote_device,
+ SCI_BASE_REQUEST_T *io_request
+)
+{
+ SCIC_SDS_CONTROLLER_T *this_controller = (SCIC_SDS_CONTROLLER_T *)
+ controller;
+ SCIC_SDS_REQUEST_T *the_request = (SCIC_SDS_REQUEST_T *)
+ io_request;
+ 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;
+}
+
+/**
+ * This method is called when the 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
+ *
+ * @param[in] controller This is SCIC_SDS_CONTROLLER which receives the link up
+ * notification.
+ * @param[in] port This is SCIC_SDS_PORT with which the phy is associated.
+ * @param[in] phy This is the SCIC_SDS_PHY which has gone link up.
+ *
+ * @return none
+ */
+static
+void scic_sds_controller_ready_state_link_up_handler(
+ SCIC_SDS_CONTROLLER_T *this_controller,
+ SCIC_SDS_PORT_T *port,
+ SCIC_SDS_PHY_T *phy
+)
+{
+ this_controller->port_agent.link_up_handler(
+ this_controller, &this_controller->port_agent, port, phy
+ );
+}
+
+/**
+ * This method is called when the SCIC_SDS_CONTROLLER is in the starting state
+ * link down handler is called.
+ * - Report the link down condition to the port object
+ *
+ * @param[in] controller This is SCIC_SDS_CONTROLLER which receives the
+ * link down notification.
+ * @param[in] port This is SCIC_SDS_PORT with which the phy is associated.
+ * @param[in] phy This is the SCIC_SDS_PHY which has gone link down.
+ *
+ * @return none
+ */
+static
+void scic_sds_controller_ready_state_link_down_handler(
+ SCIC_SDS_CONTROLLER_T *this_controller,
+ SCIC_SDS_PORT_T *port,
+ SCIC_SDS_PHY_T *phy
+)
+{
+ this_controller->port_agent.link_down_handler(
+ this_controller, &this_controller->port_agent, port, phy
+ );
+}
+
+//*****************************************************************************
+//* STOPPING STATE HANDLERS
+//*****************************************************************************
+
+/**
+ * This method is called when the SCIC_SDS_CONTROLLER is in a stopping state
+ * and the complete io handler is called.
+ * - This function is not yet implemented
+ *
+ * @param[in] controller This is SCI_BASE_CONTROLLER object which is cast
+ * into a SCIC_SDS_CONTROLLER object.
+ * @param[in] remote_device This is SCI_BASE_REMOTE_DEVICE which is cast to a
+ * SCIC_SDS_REMOTE_DEVICE object.
+ * @param[in] io_request This is the SCI_BASE_REQUEST which is cast to a
+ * SCIC_SDS_IO_REQUEST object.
+ *
+ * @return SCI_STATUS
+ * @retval SCI_FAILURE
+ */
+static
+SCI_STATUS scic_sds_controller_stopping_state_complete_io_handler(
+ SCI_BASE_CONTROLLER_T *controller,
+ SCI_BASE_REMOTE_DEVICE_T *remote_device,
+ SCI_BASE_REQUEST_T *io_request
+)
+{
+ SCIC_SDS_CONTROLLER_T *this_controller;
+ this_controller = (SCIC_SDS_CONTROLLER_T *)controller;
+
+ /// @todo Implement this function
+ return SCI_FAILURE;
+}
+
+/**
+ * This method is called when the SCIC_SDS_CONTROLLER is in a stopping state
+ * and the a remote device has stopped.
+ *
+ * @param[in] controller This is SCI_BASE_CONTROLLER object which is cast
+ * into a SCIC_SDS_CONTROLLER object.
+ * @param[in] remote_device This is SCI_BASE_REMOTE_DEVICE which is cast to a
+ * SCIC_SDS_REMOTE_DEVICE object.
+ *
+ * @return none
+ */
+static
+void scic_sds_controller_stopping_state_device_stopped_handler(
+ SCIC_SDS_CONTROLLER_T * controller,
+ SCIC_SDS_REMOTE_DEVICE_T * remote_device
+)
+{
+ if (!scic_sds_controller_has_remote_devices_stopping(controller))
+ {
+ sci_base_state_machine_change_state(
+ &controller->parent.state_machine,
+ SCI_BASE_CONTROLLER_STATE_STOPPED
+ );
+ }
+}
+
+//*****************************************************************************
+//* STOPPED STATE HANDLERS
+//*****************************************************************************
+
+//*****************************************************************************
+//* FAILED STATE HANDLERS
+//*****************************************************************************
+
+/**
+ * This method is called when the SCIC_SDS_CONTROLLER failed state start
+ * io/task handler is in place.
+ * - Issue a warning message
+ *
+ * @param[in] controller This is SCI_BASE_CONTROLLER object which is cast
+ * into a SCIC_SDS_CONTROLLER object.
+ * @param[in] remote_device This is SCI_BASE_REMOTE_DEVICE which, if it was
+ * used, would be cast to a SCIC_SDS_REMOTE_DEVICE.
+ * @param[in] io_request This is the SCI_BASE_REQUEST which, if it was used,
+ * would be cast to a SCIC_SDS_IO_REQUEST.
+ * @param[in] io_tag This is the IO tag to be assigned to the IO request or
+ * SCI_CONTROLLER_INVALID_IO_TAG.
+ *
+ * @return SCI_FAILURE
+ * @retval SCI_FAILURE
+ */
+static
+SCI_STATUS scic_sds_controller_failed_state_start_operation_handler(
+ SCI_BASE_CONTROLLER_T *controller,
+ SCI_BASE_REMOTE_DEVICE_T *remote_device,
+ SCI_BASE_REQUEST_T *io_request,
+ U16 io_tag
+)
+{
+ SCIC_SDS_CONTROLLER_T *this_controller;
+ this_controller = (SCIC_SDS_CONTROLLER_T *)controller;
+
+ SCIC_LOG_WARNING((
+ sci_base_object_get_logger(this_controller),
+ SCIC_LOG_OBJECT_CONTROLLER,
+ "SCIC Controller requested to start an io/task from failed state %d\n",
+ sci_base_state_machine_get_state(
+ scic_sds_controller_get_base_state_machine(this_controller))
+ ));
+
+ return SCI_FAILURE;
+}
+
+/**
+ * This method is called when the SCIC_SDS_CONTROLLER is in the failed state
+ * reset handler is in place.
+ * - Transition to SCI_BASE_CONTROLLER_STATE_RESETTING
+ *
+ * @param[in] controller The SCI_BASE_CONTROLLER object which is cast into a
+ * SCIC_SDS_CONTROLLER object.
+ *
+ * @return SCI_STATUS
+ * @retval SCI_FAILURE if fatal memory error occurred
+ */
+static
+SCI_STATUS scic_sds_controller_failed_state_reset_handler(
+ SCI_BASE_CONTROLLER_T *controller
+)
+{
+ SCIC_SDS_CONTROLLER_T *this_controller;
+ this_controller = (SCIC_SDS_CONTROLLER_T *)controller;
+
+ if (this_controller->parent.error == SCI_CONTROLLER_FATAL_MEMORY_ERROR) {
+ SCIC_LOG_TRACE((
+ sci_base_object_get_logger(controller),
+ SCIC_LOG_OBJECT_CONTROLLER,
+ "scic_sds_controller_resetting_state_enter(0x%x) enter\n not allowed with fatal memory error",
+ controller
+ ));
+
+ return SCI_FAILURE;
+ } else {
+ return scic_sds_controller_general_reset_handler(controller);
+ }
+}
+
+/**
+ * This method is called when the SCIC_SDS_CONTROLLER is in the failed state
+ * and the terminate request handler is called.
+ * - call the io request terminate function
+ * - if successful
+ * - post the terminate request to the SCU hardware
+ *
+ * @param[in] controller This is SCI_BASE_CONTROLLER object which is cast
+ * into a SCIC_SDS_CONTROLLER object.
+ * @param[in] remote_device This is SCI_BASE_REMOTE_DEVICE which is cast to a
+ * SCIC_SDS_REMOTE_DEVICE object.
+ * @param[in] io_request This is the SCI_BASE_REQUEST which is cast to a
+ * SCIC_SDS_IO_REQUEST object.
+ *
+ * @return SCI_STATUS
+ * @retval SCI_SUCCESS if the start io operation succeeds
+ * @retval SCI_FAILURE_INVALID_STATE if one or more objects are not in a valid
+ * state to accept io requests.
+ */
+static
+SCI_STATUS scic_sds_controller_failed_state_terminate_request_handler(
+ SCI_BASE_CONTROLLER_T *controller,
+ SCI_BASE_REMOTE_DEVICE_T *remote_device,
+ SCI_BASE_REQUEST_T *io_request
+)
+{
+ SCIC_SDS_REQUEST_T *the_request = (SCIC_SDS_REQUEST_T *)
+ io_request;
+
+ return scic_sds_io_request_terminate(the_request);
+}
+
+SCIC_SDS_CONTROLLER_STATE_HANDLER_T
+ scic_sds_controller_state_handler_table[SCI_BASE_CONTROLLER_MAX_STATES] =
+{
+ // SCI_BASE_CONTROLLER_STATE_INITIAL
+ {
+ {
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ scic_sds_controller_default_start_operation_handler,
+ scic_sds_controller_default_start_operation_handler,
+ scic_sds_controller_default_request_handler,
+ scic_sds_controller_default_request_handler,
+ scic_sds_controller_default_request_handler,
+ NULL,
+ NULL
+ },
+ scic_sds_controller_default_request_handler,
+ NULL,
+ NULL,
+ NULL,
+ NULL
+ },
+ // SCI_BASE_CONTROLLER_STATE_RESET
+ {
+ {
+ NULL,
+ NULL,
+ NULL,
+ scic_sds_controller_reset_state_initialize_handler,
+ scic_sds_controller_default_start_operation_handler,
+ scic_sds_controller_default_start_operation_handler,
+ scic_sds_controller_default_request_handler,
+ scic_sds_controller_default_request_handler,
+ scic_sds_controller_default_request_handler,
+ NULL,
+ NULL
+ },
+ scic_sds_controller_default_request_handler,
+ NULL,
+ NULL,
+ NULL,
+ NULL
+ },
+ // SCI_BASE_CONTROLLER_STATE_INITIALIZING
+ {
+ {
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ scic_sds_controller_default_start_operation_handler,
+ scic_sds_controller_default_start_operation_handler,
+ scic_sds_controller_default_request_handler,
+ scic_sds_controller_default_request_handler,
+ scic_sds_controller_default_request_handler,
+ NULL,
+ NULL
+ },
+ scic_sds_controller_default_request_handler,
+ NULL,
+ NULL,
+ NULL,
+ NULL
+ },
+ // SCI_BASE_CONTROLLER_STATE_INITIALIZED
+ {
+ {
+ scic_sds_controller_initialized_state_start_handler,
+ NULL,
+ NULL,
+ NULL,
+ scic_sds_controller_default_start_operation_handler,
+ scic_sds_controller_default_start_operation_handler,
+ scic_sds_controller_default_request_handler,
+ scic_sds_controller_default_request_handler,
+ scic_sds_controller_default_request_handler,
+ NULL,
+ NULL
+ },
+ scic_sds_controller_default_request_handler,
+ NULL,
+ NULL,
+ NULL,
+ NULL
+ },
+ // SCI_BASE_CONTROLLER_STATE_STARTING
+ {
+ {
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ scic_sds_controller_default_start_operation_handler,
+ scic_sds_controller_default_start_operation_handler,
+ scic_sds_controller_default_request_handler,
+ scic_sds_controller_default_request_handler,
+ scic_sds_controller_default_request_handler,
+ NULL,
+ NULL
+ },
+ scic_sds_controller_default_request_handler,
+ scic_sds_controller_starting_state_link_up_handler,
+ scic_sds_controller_starting_state_link_down_handler,
+ NULL,
+ NULL
+ },
+ // SCI_BASE_CONTROLLER_STATE_READY
+ {
+ {
+ NULL,
+ scic_sds_controller_ready_state_stop_handler,
+ scic_sds_controller_general_reset_handler,
+ NULL,
+ scic_sds_controller_ready_state_start_io_handler,
+ scic_sds_controller_default_start_operation_handler,
+ scic_sds_controller_ready_state_complete_io_handler,
+ scic_sds_controller_default_request_handler,
+ scic_sds_controller_ready_state_continue_io_handler,
+ scic_sds_controller_ready_state_start_task_handler,
+ scic_sds_controller_ready_state_complete_io_handler
+ },
+ scic_sds_controller_ready_state_terminate_request_handler,
+ scic_sds_controller_ready_state_link_up_handler,
+ scic_sds_controller_ready_state_link_down_handler,
+ NULL,
+ NULL
+ },
+ // SCI_BASE_CONTROLLER_STATE_RESETTING
+ {
+ {
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ scic_sds_controller_default_start_operation_handler,
+ scic_sds_controller_default_start_operation_handler,
+ scic_sds_controller_default_request_handler,
+ scic_sds_controller_default_request_handler,
+ scic_sds_controller_default_request_handler,
+ NULL,
+ NULL
+ },
+ scic_sds_controller_default_request_handler,
+ NULL,
+ NULL,
+ NULL,
+ NULL
+ },
+ // SCI_BASE_CONTROLLER_STATE_STOPPING
+ {
+ {
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ scic_sds_controller_default_start_operation_handler,
+ scic_sds_controller_default_start_operation_handler,
+ scic_sds_controller_stopping_state_complete_io_handler,
+ scic_sds_controller_default_request_handler,
+ scic_sds_controller_default_request_handler,
+ NULL,
+ NULL
+ },
+ scic_sds_controller_default_request_handler,
+ NULL,
+ NULL,
+ NULL,
+ scic_sds_controller_stopping_state_device_stopped_handler
+ },
+ // SCI_BASE_CONTROLLER_STATE_STOPPED
+ {
+ {
+ NULL,
+ NULL,
+ scic_sds_controller_failed_state_reset_handler,
+ NULL,
+ scic_sds_controller_default_start_operation_handler,
+ scic_sds_controller_default_start_operation_handler,
+ scic_sds_controller_default_request_handler,
+ scic_sds_controller_default_request_handler,
+ scic_sds_controller_default_request_handler,
+ NULL,
+ NULL
+ },
+ scic_sds_controller_default_request_handler,
+ NULL,
+ NULL,
+ NULL,
+ NULL
+ },
+ // SCI_BASE_CONTROLLER_STATE_FAILED
+ {
+ {
+ NULL,
+ NULL,
+ scic_sds_controller_general_reset_handler,
+ NULL,
+ scic_sds_controller_failed_state_start_operation_handler,
+ scic_sds_controller_failed_state_start_operation_handler,
+ scic_sds_controller_default_request_handler,
+ scic_sds_controller_default_request_handler,
+ scic_sds_controller_default_request_handler,
+ NULL,
+ NULL
+ },
+ scic_sds_controller_failed_state_terminate_request_handler,
+ NULL,
+ NULL,
+ NULL
+ }
+};
+
+/**
+ * This method implements the actions taken by the SCIC_SDS_CONTROLLER on
+ * entry to the SCI_BASE_CONTROLLER_STATE_INITIAL.
+ * - Set the state handlers to the controllers initial state.
+ *
+ * @param[in] object This is the SCI_BASE_OBJECT which is cast to a
+ * SCIC_SDS_CONTROLLER object.
+ *
+ * @return none
+ *
+ * @todo This function should initialze the controller object.
+ */
+static
+void scic_sds_controller_initial_state_enter(
+ SCI_BASE_OBJECT_T *object
+)
+{
+ SCIC_SDS_CONTROLLER_T *this_controller;
+ this_controller= (SCIC_SDS_CONTROLLER_T *)object;
+
+ scic_sds_controller_set_base_state_handlers(
+ this_controller, SCI_BASE_CONTROLLER_STATE_INITIAL);
+
+ sci_base_state_machine_change_state(
+ &this_controller->parent.state_machine, SCI_BASE_CONTROLLER_STATE_RESET);
+}
+
+/**
+ * This method implements the actions taken by the SCIC_SDS_CONTROLLER on
+ * entry to the SCI_BASE_CONTROLLER_STATE_RESET.
+ * - Set the state handlers to the controllers reset state.
+ *
+ * @param[in] object This is the SCI_BASE_OBJECT which is cast to a
+ * SCIC_SDS_CONTROLLER object.
+ *
+ * @return none
+ */
+static
+void scic_sds_controller_reset_state_enter(
+ SCI_BASE_OBJECT_T *object
+)
+{
+ U8 index;
+ SCIC_SDS_CONTROLLER_T *this_controller;
+ this_controller= (SCIC_SDS_CONTROLLER_T *)object;
+
+ scic_sds_controller_set_base_state_handlers(
+ this_controller, SCI_BASE_CONTROLLER_STATE_RESET);
+
+ scic_sds_port_configuration_agent_construct(&this_controller->port_agent);
+
+ // Construct the ports for this controller
+ for (index = 0; index < (SCI_MAX_PORTS + 1); index++)
+ {
+ scic_sds_port_construct(
+ &this_controller->port_table[index],
+ (index == SCI_MAX_PORTS) ? SCIC_SDS_DUMMY_PORT : index,
+ this_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(
+ &this_controller->phy_table[index],
+ &this_controller->port_table[SCI_MAX_PORTS],
+ index
+ );
+ }
+
+ this_controller->invalid_phy_mask = 0;
+
+ // Set the default maximum values
+ this_controller->completion_event_entries = SCU_EVENT_COUNT;
+ this_controller->completion_queue_entries = SCU_COMPLETION_QUEUE_COUNT;
+ this_controller->remote_node_entries = SCI_MAX_REMOTE_DEVICES;
+ this_controller->logical_port_entries = SCI_MAX_PORTS;
+ this_controller->task_context_entries = SCU_IO_REQUEST_COUNT;
+ this_controller->uf_control.buffers.count = SCU_UNSOLICITED_FRAME_COUNT;
+ this_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(this_controller);
+}
+
+/**
+ * This method implements the actions taken by the SCIC_SDS_CONTROLLER on
+ * entry to the SCI_BASE_CONTROLLER_STATE_INITIALIZING.
+ * - Set the state handlers to the controllers initializing state.
+ *
+ * @param[in] object This is the SCI_BASE_OBJECT which is cast to a
+ * SCIC_SDS_CONTROLLER object.
+ *
+ * @return none
+ */
+static
+void scic_sds_controller_initializing_state_enter(
+ SCI_BASE_OBJECT_T *object
+)
+{
+ SCIC_SDS_CONTROLLER_T *this_controller;
+ this_controller= (SCIC_SDS_CONTROLLER_T *)object;
+
+ scic_sds_controller_set_base_state_handlers(
+ this_controller, SCI_BASE_CONTROLLER_STATE_INITIALIZING);
+}
+
+/**
+ * This method implements the actions taken by the SCIC_SDS_CONTROLLER on
+ * entry to the SCI_BASE_CONTROLLER_STATE_INITIALIZED.
+ * - Set the state handlers to the controllers initialized state.
+ *
+ * @param[in] object This is the SCI_BASE_OBJECT which is cast to a
+ * SCIC_SDS_CONTROLLER object.
+ *
+ * @return none
+ */
+static
+void scic_sds_controller_initialized_state_enter(
+ SCI_BASE_OBJECT_T *object
+)
+{
+ SCIC_SDS_CONTROLLER_T *this_controller;
+ this_controller= (SCIC_SDS_CONTROLLER_T *)object;
+
+ scic_sds_controller_set_base_state_handlers(
+ this_controller, SCI_BASE_CONTROLLER_STATE_INITIALIZED);
+}
+
+/**
+ * This method implements the actions taken by the SCIC_SDS_CONTROLLER on
+ * entry to the SCI_BASE_CONTROLLER_STATE_STARTING.
+ * - Set the state handlers to the controllers starting state.
+ *
+ * @param[in] object This is the SCI_BASE_OBJECT which is cast to a
+ * SCIC_SDS_CONTROLLER object.
+ *
+ * @return none
+ */
+static
+void scic_sds_controller_starting_state_enter(
+ SCI_BASE_OBJECT_T *object
+)
+{
+ SCIC_SDS_CONTROLLER_T *this_controller;
+ this_controller= (SCIC_SDS_CONTROLLER_T *)object;
+
+ scic_sds_controller_set_base_state_handlers(
+ this_controller, SCI_BASE_CONTROLLER_STATE_STARTING);
+
+}
+
+/**
+ * This method implements the actions taken by the SCIC_SDS_CONTROLLER on exit
+ * from the SCI_BASE_CONTROLLER_STATE_STARTING.
+ * - This function stops the controller starting timeout timer.
+ *
+ * @param[in] object This is the SCI_BASE_OBJECT which is cast to a
+ * SCIC_SDS_CONTROLLER object.
+ *
+ * @return none
+ */
+static
+void scic_sds_controller_starting_state_exit(
+ SCI_BASE_OBJECT_T *object
+)
+{
+ SCIC_SDS_CONTROLLER_T *this_controller;
+ this_controller= (SCIC_SDS_CONTROLLER_T *)object;
+
+ scic_cb_timer_stop(object, this_controller->timeout_timer);
+
+ // We are done with this timer since we are exiting the starting
+ // state so remove it
+ scic_cb_timer_destroy(
+ this_controller,
+ this_controller->phy_startup_timer
+ );
+
+ this_controller->phy_startup_timer = NULL;
+}
+
+/**
+ * This method implements the actions taken by the SCIC_SDS_CONTROLLER on
+ * entry to the SCI_BASE_CONTROLLER_STATE_READY.
+ * - Set the state handlers to the controllers ready state.
+ *
+ * @param[in] object This is the SCI_BASE_OBJECT which is cast to a
+ * SCIC_SDS_CONTROLLER object.
+ *
+ * @return none
+ */
+static
+void scic_sds_controller_ready_state_enter(
+ SCI_BASE_OBJECT_T *object
+)
+{
+ U32 clock_gating_unit_value;
+ SCIC_SDS_CONTROLLER_T *this_controller;
+ this_controller= (SCIC_SDS_CONTROLLER_T *)object;
+
+ scic_sds_controller_set_base_state_handlers(
+ this_controller, SCI_BASE_CONTROLLER_STATE_READY);
+
+ /**
+ * enable clock gating for power control of the scu unit
+ */
+ clock_gating_unit_value = SMU_CGUCR_READ(this_controller);
+
+ clock_gating_unit_value &= ~( SMU_CGUCR_GEN_BIT(REGCLK_ENABLE)
+ | SMU_CGUCR_GEN_BIT(TXCLK_ENABLE)
+ | SMU_CGUCR_GEN_BIT(XCLK_ENABLE) );
+ clock_gating_unit_value |= SMU_CGUCR_GEN_BIT(IDLE_ENABLE);
+
+ SMU_CGUCR_WRITE(this_controller, clock_gating_unit_value);
+
+ //set the default interrupt coalescence number and timeout value.
+ scic_controller_set_interrupt_coalescence(
+ this_controller, 0x10, 250);
+}
+
+/**
+ * This method implements the actions taken by the SCIC_SDS_CONTROLLER on exit
+ * from the SCI_BASE_CONTROLLER_STATE_READY.
+ * - This function does nothing.
+ *
+ * @param[in] object This is the SCI_BASE_OBJECT which is cast to a
+ * SCIC_SDS_CONTROLLER object.
+ *
+ * @return none
+ */
+static
+void scic_sds_controller_ready_state_exit(
+ SCI_BASE_OBJECT_T *object
+)
+{
+ U32 clock_gating_unit_value;
+ SCIC_SDS_CONTROLLER_T *this_controller;
+ this_controller= (SCIC_SDS_CONTROLLER_T *)object;
+
+ /**
+ * restore clock gating for power control of the scu unit
+ */
+ clock_gating_unit_value = SMU_CGUCR_READ(this_controller);
+
+ clock_gating_unit_value &= ~SMU_CGUCR_GEN_BIT(IDLE_ENABLE);
+ clock_gating_unit_value |= ( SMU_CGUCR_GEN_BIT(REGCLK_ENABLE)
+ | SMU_CGUCR_GEN_BIT(TXCLK_ENABLE)
+ | SMU_CGUCR_GEN_BIT(XCLK_ENABLE) );
+
+ SMU_CGUCR_WRITE(this_controller, clock_gating_unit_value);
+
+ //disable interrupt coalescence.
+ scic_controller_set_interrupt_coalescence(this_controller, 0, 0);
+}
+
+/**
+ * This method implements the actions taken by the SCIC_SDS_CONTROLLER on
+ * entry to the SCI_BASE_CONTROLLER_STATE_READY.
+ * - Set the state handlers to the controllers ready state.
+ * - Stop all of the remote devices on this controller
+ * - Stop the ports on this controller
+ * - Stop the phys on this controller
+ *
+ * @param[in] object This is the SCI_BASE_OBJECT which is cast to a
+ * SCIC_SDS_CONTROLLER object.
+ *
+ * @return none
+ */
+static
+void scic_sds_controller_stopping_state_enter(
+ SCI_BASE_OBJECT_T *object
+)
+{
+ SCIC_SDS_CONTROLLER_T *this_controller;
+ this_controller= (SCIC_SDS_CONTROLLER_T *)object;
+
+ scic_sds_controller_set_base_state_handlers(
+ this_controller, SCI_BASE_CONTROLLER_STATE_STOPPING);
+
+ // Stop all of the components for this controller in the reverse order
+ // from which they are initialized.
+ scic_sds_controller_stop_devices(this_controller);
+ scic_sds_controller_stop_ports(this_controller);
+
+ if (!scic_sds_controller_has_remote_devices_stopping(this_controller))
+ {
+ sci_base_state_machine_change_state(
+ &this_controller->parent.state_machine,
+ SCI_BASE_CONTROLLER_STATE_STOPPED
+ );
+ }
+}
+
+/**
+ * This method implements the actions taken by the SCIC_SDS_CONTROLLER on exit
+ * from the SCI_BASE_CONTROLLER_STATE_STOPPING.
+ * - This function stops the controller stopping timeout timer.
+ *
+ * @param[in] object This is the SCI_BASE_OBJECT which is cast to a
+ * SCIC_SDS_CONTROLLER object.
+ *
+ * @return none
+ */
+static
+void scic_sds_controller_stopping_state_exit(
+ SCI_BASE_OBJECT_T *object
+)
+{
+ SCIC_SDS_CONTROLLER_T *this_controller;
+ this_controller= (SCIC_SDS_CONTROLLER_T *)object;
+
+ scic_cb_timer_stop(this_controller, this_controller->timeout_timer);
+}
+
+/**
+ * This method implements the actions taken by the SCIC_SDS_CONTROLLER on
+ * entry to the SCI_BASE_CONTROLLER_STATE_STOPPED.
+ * - Set the state handlers to the controllers stopped state.
+ *
+ * @param[in] object This is the SCI_BASE_OBJECT which is cast to a
+ * SCIC_SDS_CONTROLLER object.
+ *
+ * @return none
+ */
+static
+void scic_sds_controller_stopped_state_enter(
+ SCI_BASE_OBJECT_T *object
+)
+{
+ SCIC_SDS_CONTROLLER_T *this_controller;
+ this_controller= (SCIC_SDS_CONTROLLER_T *)object;
+
+ scic_sds_controller_set_base_state_handlers(
+ this_controller, SCI_BASE_CONTROLLER_STATE_STOPPED);
+
+ // We are done with this timer until the next timer we initialize
+ scic_cb_timer_destroy(
+ this_controller,
+ this_controller->timeout_timer
+ );
+ this_controller->timeout_timer = NULL;
+
+ // Controller has stopped so disable all the phys on this controller
+ scic_sds_controller_stop_phys(this_controller);
+
+ scic_sds_port_configuration_agent_destroy(
+ this_controller,
+ &this_controller->port_agent
+ );
+
+ scic_cb_controller_stop_complete(this_controller, SCI_SUCCESS);
+}
+
+/**
+ * This method implements the actions taken by the 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
+ *
+ * @param[in] object This is the SCI_BASE_OBJECT which is cast to a
+ * SCIC_SDS_CONTROLLER object.
+ *
+ * @return none
+ */
+static
+void scic_sds_controller_resetting_state_enter(
+ SCI_BASE_OBJECT_T *object
+)
+{
+ SCIC_SDS_CONTROLLER_T *this_controller;
+ this_controller= (SCIC_SDS_CONTROLLER_T *)object;
+
+ SCIC_LOG_TRACE((
+ sci_base_object_get_logger(this_controller),
+ SCIC_LOG_OBJECT_CONTROLLER,
+ "scic_sds_controller_resetting_state_enter(0x%x) enter\n",
+ this_controller
+ ));
+
+ scic_sds_controller_set_base_state_handlers(
+ this_controller, SCI_BASE_CONTROLLER_STATE_RESETTING);
+
+ 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
+ );
+}
+
+static
+SCI_STATUS scic_sds_abort_reqests(
+ SCIC_SDS_CONTROLLER_T * controller,
+ SCIC_SDS_REMOTE_DEVICE_T * remote_device,
+ SCIC_SDS_PORT_T * port
+)
+{
+ SCI_STATUS status = SCI_SUCCESS;
+ SCI_STATUS terminate_status = SCI_SUCCESS;
+ SCIC_SDS_REQUEST_T *the_request;
+ U32 index;
+ U32 request_count;
+
+ if (remote_device != NULL)
+ request_count = remote_device->started_request_count;
+ else if (port != NULL)
+ request_count = port->started_request_count;
+ else
+ request_count = SCI_MAX_IO_REQUESTS;
+
+
+ for (index = 0;
+ (index < SCI_MAX_IO_REQUESTS) && (request_count > 0);
+ index++)
+ {
+ the_request = controller->io_request_table[index];
+
+ if (the_request != NULL)
+ {
+ if (the_request->target_device == remote_device
+ || the_request->target_device->owning_port == port
+ || (remote_device == NULL && port == NULL))
+ {
+ terminate_status = scic_controller_terminate_request(
+ controller,
+ the_request->target_device,
+ the_request
+ );
+
+ if (terminate_status != SCI_SUCCESS)
+ status = terminate_status;
+
+ request_count--;
+ }
+ }
+ }
+
+ return status;
+}
+
+SCI_STATUS scic_sds_terminate_reqests(
+ SCIC_SDS_CONTROLLER_T *this_controller,
+ SCIC_SDS_REMOTE_DEVICE_T *this_remote_device,
+ SCIC_SDS_PORT_T *this_port
+)
+{
+ SCI_STATUS status = SCI_SUCCESS;
+ SCI_STATUS abort_status = SCI_SUCCESS;
+
+ // move all request to abort state
+ abort_status = scic_sds_abort_reqests(this_controller, this_remote_device, this_port);
+
+ if (abort_status != SCI_SUCCESS)
+ status = abort_status;
+
+ //move all request to complete state
+ if (this_controller->parent.error == SCI_CONTROLLER_FATAL_MEMORY_ERROR)
+ abort_status = scic_sds_abort_reqests(this_controller, this_remote_device, this_port);
+
+ if (abort_status != SCI_SUCCESS)
+ status = abort_status;
+
+ return status;
+}
+
+static
+SCI_STATUS scic_sds_terminate_all_requests(
+ SCIC_SDS_CONTROLLER_T * controller
+)
+{
+ return scic_sds_terminate_reqests(controller, NULL, NULL);
+}
+
+/**
+ * This method implements the actions taken by the SCIC_SDS_CONTROLLER on
+ * entry to the SCI_BASE_CONTROLLER_STATE_FAILED.
+ * - Set the state handlers to the controllers failed state.
+ *
+ * @param[in] object This is the SCI_BASE_OBJECT which is cast to a
+ * SCIC_SDS_CONTROLLER object.
+ *
+ * @return none
+ */
+static
+void scic_sds_controller_failed_state_enter(
+ SCI_BASE_OBJECT_T *object
+)
+{
+ SCIC_SDS_CONTROLLER_T *this_controller;
+ this_controller= (SCIC_SDS_CONTROLLER_T *)object;
+
+ scic_sds_controller_set_base_state_handlers(
+ this_controller, SCI_BASE_CONTROLLER_STATE_FAILED);
+
+ if (this_controller->parent.error == SCI_CONTROLLER_FATAL_MEMORY_ERROR)
+ scic_sds_terminate_all_requests(this_controller);
+ else
+ scic_sds_controller_release_resource(this_controller);
+
+ //notify framework the controller failed.
+ scic_cb_controller_error(this_controller,
+ this_controller->parent.error);
+}
+
+// ---------------------------------------------------------------------------
+
+SCI_BASE_STATE_T
+ scic_sds_controller_state_table[SCI_BASE_CONTROLLER_MAX_STATES] =
+{
+ {
+ SCI_BASE_CONTROLLER_STATE_INITIAL,
+ scic_sds_controller_initial_state_enter,
+ NULL,
+ },
+ {
+ SCI_BASE_CONTROLLER_STATE_RESET,
+ scic_sds_controller_reset_state_enter,
+ NULL,
+ },
+ {
+ SCI_BASE_CONTROLLER_STATE_INITIALIZING,
+ scic_sds_controller_initializing_state_enter,
+ NULL,
+ },
+ {
+ SCI_BASE_CONTROLLER_STATE_INITIALIZED,
+ scic_sds_controller_initialized_state_enter,
+ NULL,
+ },
+ {
+ SCI_BASE_CONTROLLER_STATE_STARTING,
+ scic_sds_controller_starting_state_enter,
+ scic_sds_controller_starting_state_exit,
+ },
+ {
+ SCI_BASE_CONTROLLER_STATE_READY,
+ scic_sds_controller_ready_state_enter,
+ scic_sds_controller_ready_state_exit,
+ },
+ {
+ SCI_BASE_CONTROLLER_STATE_RESETTING,
+ scic_sds_controller_resetting_state_enter,
+ NULL,
+ },
+ {
+ SCI_BASE_CONTROLLER_STATE_STOPPING,
+ scic_sds_controller_stopping_state_enter,
+ scic_sds_controller_stopping_state_exit,
+ },
+ {
+ SCI_BASE_CONTROLLER_STATE_STOPPED,
+ scic_sds_controller_stopped_state_enter,
+ NULL,
+ },
+ {
+ SCI_BASE_CONTROLLER_STATE_FAILED,
+ scic_sds_controller_failed_state_enter,
+ NULL,
+ }
+};
+
diff --git a/sys/dev/isci/scil/scic_sds_controller.h b/sys/dev/isci/scil/scic_sds_controller.h
new file mode 100644
index 0000000..9829a7b
--- /dev/null
+++ b/sys/dev/isci/scil/scic_sds_controller.h
@@ -0,0 +1,840 @@
+/*-
+ * 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.
+ *
+ * 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.
+ *
+ * $FreeBSD$
+ */
+#ifndef _SCIC_SDS_CONTROLLER_H_
+#define _SCIC_SDS_CONTROLLER_H_
+
+/**
+ * @file
+ *
+ * @brief This file contains the structures, constants and prototypes used for
+ * the core controller object.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif // __cplusplus
+
+#include <dev/isci/scil/sci_pool.h>
+#include <dev/isci/scil/sci_controller_constants.h>
+#include <dev/isci/scil/sci_memory_descriptor_list.h>
+#include <dev/isci/scil/sci_base_controller.h>
+#include <dev/isci/scil/scic_config_parameters.h>
+#include <dev/isci/scil/scic_sds_port.h>
+#include <dev/isci/scil/scic_sds_phy.h>
+#include <dev/isci/scil/scic_sds_remote_node_table.h>
+#include <dev/isci/scil/scu_registers.h>
+#include <dev/isci/scil/scu_constants.h>
+#include <dev/isci/scil/scu_remote_node_context.h>
+#include <dev/isci/scil/scu_task_context.h>
+#include <dev/isci/scil/scu_unsolicited_frame.h>
+#include <dev/isci/scil/scic_sds_unsolicited_frame_control.h>
+#include <dev/isci/scil/scic_sds_port_configuration_agent.h>
+#include <dev/isci/scil/scic_sds_pci.h>
+
+struct SCIC_SDS_REMOTE_DEVICE;
+struct SCIC_SDS_REQUEST;
+
+
+#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
+};
+
+/**
+ * @struct SCIC_POWER_CONTROL
+ *
+ * This structure defines the fields for managing power control for direct
+ * attached disk devices.
+ */
+typedef 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 used to keep track of how many remote devices have been granted to consume power
+ */
+ U8 remote_devices_granted_power;
+
+ /**
+ * This field is an array of phys that we are waiting on. The phys are direct
+ * mapped into requesters via SCIC_SDS_PHY_T.phy_index
+ */
+ SCIC_SDS_PHY_T *requesters[SCI_MAX_PHYS];
+
+} SCIC_POWER_CONTROL_T;
+
+/**
+ * @struct SCIC_SDS_CONTROLLER
+ *
+ * This structure represents the SCU contoller object.
+ */
+typedef struct SCIC_SDS_CONTROLLER
+{
+ /**
+ * The SCI_BASE_CONTROLLER is the parent object for the SCIC_SDS_CONTROLLER
+ * object.
+ */
+ SCI_BASE_CONTROLLER_T parent;
+
+ /**
+ * This field is the driver timer object handler used to time the controller
+ * object start and stop requests.
+ */
+ void *timeout_timer;
+
+ /**
+ * This field is the current set of state handlers assigned to this controller
+ * object.
+ */
+ struct SCIC_SDS_CONTROLLER_STATE_HANDLER *state_handlers;
+
+ /**
+ * This field contains the user parameters to be utilized for this
+ * core controller object.
+ */
+ SCIC_USER_PARAMETERS_T user_parameters;
+
+ /**
+ * This field contains the OEM parameters version defining the structure
+ * layout. It comes from the version in the OEM block header.
+ */
+ U8 oem_parameters_version;
+
+ /**
+ * This field contains the OEM parameters to be utilized for this
+ * core controller object.
+ */
+ SCIC_OEM_PARAMETERS_T oem_parameters;
+
+ /**
+ * This field contains the port configuration agent for this controller.
+ */
+ SCIC_SDS_PORT_CONFIGURATION_AGENT_T 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
+ */
+ SCIC_REMOTE_NODE_TABLE_T 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 SCIC_POWER_CONTROL data used to controll when direct
+ * attached devices can consume power.
+ */
+ SCIC_POWER_CONTROL_T 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.
+ */
+ SCU_TASK_CONTEXT_T *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.
+ */
+ SCU_REMOTE_NODE_CONTEXT_T *remote_node_context_table;
+
+ /**
+ * This field is the array of physical memory requiremets for this controller
+ * object.
+ */
+ SCI_PHYSICAL_MEMORY_DESCRIPTOR_T 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.
+ */
+ SCIC_SDS_UNSOLICITED_FRAME_CONTROL_T 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 is the controller index for this controller object.
+ */
+ U8 controller_index;
+
+ /**
+ * This field is the PCI revision code for the controller object.
+ */
+ enum SCU_CONTROLLER_PCI_REVISION_CODE pci_revision;
+
+ /*
+ * 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;
+
+ // Hardware memory mapped register space
+#ifdef ARLINGTON_BUILD
+ /**
+ * This field is a pointer to the memory mapped register space for the
+ * LEX_REGISTERS.
+ */
+ LEX_REGISTERS_T *lex_registers;
+#endif
+
+ /**
+ * This field is a pointer to the memory mapped register space for the
+ * SMU_REGISTERS.
+ */
+ SMU_REGISTERS_T *smu_registers;
+
+ /**
+ * This field is a pointer to the memory mapped register space for the
+ * SCU_REGISTERS.
+ */
+ SCU_REGISTERS_T *scu_registers;
+
+} SCIC_SDS_CONTROLLER_T;
+
+
+typedef void (*SCIC_SDS_CONTROLLER_PHY_HANDLER_T)(
+ struct SCIC_SDS_CONTROLLER *controller,
+ struct SCIC_SDS_PORT *port,
+ struct SCIC_SDS_PHY *phy
+ );
+
+typedef void (*SCIC_SDS_CONTROLLER_DEVICE_HANDLER_T)(
+ struct SCIC_SDS_CONTROLLER * controller,
+ struct SCIC_SDS_REMOTE_DEVICE * device
+ );
+/**
+ * @struct SCIC_SDS_CONTROLLER_STATE_HANDLER
+ *
+ * This structure contains the SDS core specific definition for the state
+ * handlers.
+ */
+typedef struct SCIC_SDS_CONTROLLER_STATE_HANDLER
+{
+ SCI_BASE_CONTROLLER_STATE_HANDLER_T parent;
+
+ SCI_BASE_CONTROLLER_REQUEST_HANDLER_T terminate_request_handler;
+ SCIC_SDS_CONTROLLER_PHY_HANDLER_T link_up_handler;
+ SCIC_SDS_CONTROLLER_PHY_HANDLER_T link_down_handler;
+ SCIC_SDS_CONTROLLER_DEVICE_HANDLER_T remote_device_started_handler;
+ SCIC_SDS_CONTROLLER_DEVICE_HANDLER_T remote_device_stopped_handler;
+
+} SCIC_SDS_CONTROLLER_STATE_HANDLER_T;
+
+extern SCIC_SDS_CONTROLLER_STATE_HANDLER_T
+ scic_sds_controller_state_handler_table[];
+extern SCI_BASE_STATE_T scic_sds_controller_state_table[];
+
+/**
+ * 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; \
+ } \
+}
+
+/**
+ * This is a helper macro that sets the state handlers for the controller
+ * object
+ */
+#define scic_sds_controller_set_state_handlers(this_controller, handlers) \
+ ((this_controller)->state_handlers = (handlers))
+
+/**
+ * This is a helper macro that gets the base state machine for the
+ * controller object
+ */
+#define scic_sds_controller_get_base_state_machine(this_contoroller) \
+ (&(this_controller)->parent.state_machine)
+
+/**
+ * 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)
+
+/**
+ * This is a helper macro that sets the base state machine state handlers
+ * based on the state id
+ */
+#define scic_sds_controller_set_base_state_handlers(this_controller, state_id) \
+ scic_sds_controller_set_state_handlers( \
+ this_controller, &scic_sds_controller_state_handler_table[(state_id)])
+
+/**
+ * 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))
+
+/**
+ * This macro reads the smu_register for this controller
+ */
+#define smu_register_read(controller, reg) \
+ scic_sds_pci_read_smu_dword((controller), &(reg))
+
+/**
+ * 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))
+
+/**
+ * This macro reads the scu_register for this controller
+ */
+#define scu_register_read(controller, reg) \
+ scic_sds_pci_read_scu_dword((controller), &(reg))
+
+#ifdef ARLINGTON_BUILD
+ /**
+ * This macro writes to the lex_register for this controller.
+ */
+ #define lex_register_write(controller, reg, value) \
+ scic_cb_pci_write_dword((controller), (reg), (value))
+
+ /**
+ * This macro reads from the lex_register for this controller.
+ */
+ #define lex_register_read(controller, reg) \
+ scic_cb_pci_read_dword((controller), (reg))
+#endif // ARLINGTON_BUILD
+
+/**
+ * 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
+
+/**
+ * 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))
+
+/**
+ * This macro returns the IO sequence from the IO tag value.
+ */
+#define scic_sds_io_tag_get_sequence(io_tag) \
+ (((io_tag) & 0xF000) >> 12)
+
+/**
+ * This macro returns the TCi from the io tag value
+ */
+#define scic_sds_io_tag_get_index(io_tag) \
+ ((io_tag) & 0x0FFF)
+
+/**
+ * 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 \
+ )
+
+/**
+ * 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))
+
+/**
+ * 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);
+
+// ---------------------------------------------------------------------------
+
+U32 scic_sds_controller_get_min_timer_count(void);
+U32 scic_sds_controller_get_max_timer_count(void);
+
+// ---------------------------------------------------------------------------
+
+void scic_sds_controller_post_request(
+ SCIC_SDS_CONTROLLER_T *this_controller,
+ U32 request
+);
+
+// ---------------------------------------------------------------------------
+
+void scic_sds_controller_release_frame(
+ SCIC_SDS_CONTROLLER_T *this_controller,
+ U32 frame_index
+);
+
+void scic_sds_controller_copy_sata_response(
+ void * response_buffer,
+ void * frame_header,
+ void * frame_buffer
+);
+
+// ---------------------------------------------------------------------------
+
+SCI_STATUS scic_sds_controller_allocate_remote_node_context(
+ SCIC_SDS_CONTROLLER_T *this_controller,
+ struct SCIC_SDS_REMOTE_DEVICE *the_device,
+ U16 *node_id
+);
+
+void scic_sds_controller_free_remote_node_context(
+ SCIC_SDS_CONTROLLER_T *this_controller,
+ struct SCIC_SDS_REMOTE_DEVICE *the_device,
+ U16 node_id
+);
+
+SCU_REMOTE_NODE_CONTEXT_T *scic_sds_controller_get_remote_node_context_buffer(
+ SCIC_SDS_CONTROLLER_T *this_controller,
+ U16 node_id
+);
+
+// ---------------------------------------------------------------------------
+
+struct SCIC_SDS_REQUEST *scic_sds_controller_get_io_request_from_tag(
+ SCIC_SDS_CONTROLLER_T *this_controller,
+ U16 io_tag
+);
+
+U16 scic_sds_controller_get_io_sequence_from_tag(
+ SCIC_SDS_CONTROLLER_T *this_controller,
+ U16 io_tag
+);
+
+SCU_TASK_CONTEXT_T *scic_sds_controller_get_task_context_buffer(
+ SCIC_SDS_CONTROLLER_T *this_controller,
+ U16 io_tag
+);
+
+//-----------------------------------------------------------------------------
+
+SCI_STATUS scic_sds_terminate_reqests(
+ SCIC_SDS_CONTROLLER_T *this_controller,
+ struct SCIC_SDS_REMOTE_DEVICE *this_remote_device,
+ struct SCIC_SDS_PORT *this_port
+);
+
+//*****************************************************************************
+//* CORE CONTROLLER POWER CONTROL METHODS
+//*****************************************************************************
+
+void scic_sds_controller_power_control_timer_handler(
+ void *controller
+);
+
+void scic_sds_controller_power_control_queue_insert(
+ SCIC_SDS_CONTROLLER_T *this_controller,
+ struct SCIC_SDS_PHY *the_phy
+);
+
+void scic_sds_controller_power_control_queue_remove(
+ SCIC_SDS_CONTROLLER_T *this_controller,
+ struct SCIC_SDS_PHY *the_phy
+);
+
+//*****************************************************************************
+//* CORE CONTROLLER PHY MESSAGE PROCESSING
+//*****************************************************************************
+
+void scic_sds_controller_link_up(
+ SCIC_SDS_CONTROLLER_T *this_controller,
+ struct SCIC_SDS_PORT *the_port,
+ struct SCIC_SDS_PHY *the_phy
+);
+
+void scic_sds_controller_link_down(
+ SCIC_SDS_CONTROLLER_T *this_controller,
+ struct SCIC_SDS_PORT *the_port,
+ struct SCIC_SDS_PHY *the_phy
+);
+
+//*****************************************************************************
+//* CORE CONTROLLER PORT AGENT MESSAGE PROCESSING
+//*****************************************************************************
+void scic_sds_controller_port_agent_configured_ports(
+ SCIC_SDS_CONTROLLER_T * this_controller
+);
+
+//*****************************************************************************
+//* CORE CONTROLLER REMOTE DEVICE MESSAGE PROCESSING
+//*****************************************************************************
+
+BOOL scic_sds_controller_has_remote_devices_stopping(
+ SCIC_SDS_CONTROLLER_T * this_controller
+);
+
+void scic_sds_controller_remote_device_started(
+ SCIC_SDS_CONTROLLER_T * this_controller,
+ struct SCIC_SDS_REMOTE_DEVICE * the_device
+);
+
+void scic_sds_controller_remote_device_stopped(
+ SCIC_SDS_CONTROLLER_T * this_controller,
+ struct SCIC_SDS_REMOTE_DEVICE * the_device
+);
+
+//*****************************************************************************
+//* CORE CONTROLLER PRIVATE METHODS
+//*****************************************************************************
+
+#ifdef SCI_LOGGING
+void scic_sds_controller_initialize_state_logging(
+ SCIC_SDS_CONTROLLER_T *this_controller
+);
+
+void scic_sds_controller_deinitialize_state_logging(
+ SCIC_SDS_CONTROLLER_T *this_controller
+);
+#else
+#define scic_sds_controller_initialize_state_logging(x)
+#define scic_sds_controller_deinitialize_state_logging(x)
+#endif
+
+SCI_STATUS scic_sds_controller_validate_memory_descriptor_table(
+ SCIC_SDS_CONTROLLER_T *this_controller
+);
+
+void scic_sds_controller_ram_initialization(
+ SCIC_SDS_CONTROLLER_T *this_controller
+);
+
+void scic_sds_controller_assign_task_entries(
+ SCIC_SDS_CONTROLLER_T *this_controller
+);
+
+void scic_sds_controller_afe_initialization(
+ SCIC_SDS_CONTROLLER_T * this_controller
+);
+
+void scic_sds_controller_enable_port_task_scheduler(
+ SCIC_SDS_CONTROLLER_T *this_controller
+);
+
+void scic_sds_controller_initialize_completion_queue(
+ SCIC_SDS_CONTROLLER_T *this_controller
+);
+
+void scic_sds_controller_initialize_unsolicited_frame_queue(
+ SCIC_SDS_CONTROLLER_T *this_controller
+);
+
+void scic_sds_controller_phy_timer_stop(
+ SCIC_SDS_CONTROLLER_T *this_controller
+);
+
+BOOL scic_sds_controller_is_start_complete(
+ SCIC_SDS_CONTROLLER_T *this_controller
+);
+
+SCI_STATUS scic_sds_controller_start_next_phy(
+ SCIC_SDS_CONTROLLER_T *this_controller
+);
+
+SCI_STATUS scic_sds_controller_stop_phys(
+ SCIC_SDS_CONTROLLER_T *this_controller
+);
+
+SCI_STATUS scic_sds_controller_stop_ports(
+ SCIC_SDS_CONTROLLER_T *this_controller
+);
+
+SCI_STATUS scic_sds_controller_stop_devices(
+ SCIC_SDS_CONTROLLER_T *this_controller
+);
+
+void scic_sds_controller_copy_task_context(
+ SCIC_SDS_CONTROLLER_T *this_controller,
+ struct SCIC_SDS_REQUEST *this_request
+);
+
+void scic_sds_controller_timeout_handler(
+ SCI_CONTROLLER_HANDLE_T controller
+);
+
+void scic_sds_controller_initialize_power_control(
+ SCIC_SDS_CONTROLLER_T *this_controller
+);
+
+void scic_sds_controller_register_setup(
+ SCIC_SDS_CONTROLLER_T *this_controller
+);
+
+void scic_sds_controller_reset_hardware(
+ SCIC_SDS_CONTROLLER_T * this_controller
+);
+
+#ifdef ARLINGTON_BUILD
+void scic_sds_controller_lex_atux_initialization(
+ SCIC_SDS_CONTROLLER_T *this_controller
+);
+
+void scic_sds_controller_enable_chipwatch(
+ SCIC_SDS_CONTROLLER_T *this_controller
+);
+#endif // ARLINGTON_BUILD
+
+void scic_sds_controller_build_memory_descriptor_table(
+ SCIC_SDS_CONTROLLER_T *this_controller
+);
+
+#ifdef __cplusplus
+}
+#endif // __cplusplus
+
+#endif // _SCIC_SDS_CONTROLLER_H_
diff --git a/sys/dev/isci/scil/scic_sds_controller_registers.h b/sys/dev/isci/scil/scic_sds_controller_registers.h
new file mode 100644
index 0000000..e4a0fb4
--- /dev/null
+++ b/sys/dev/isci/scil/scic_sds_controller_registers.h
@@ -0,0 +1,598 @@
+/*-
+ * 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.
+ *
+ * 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.
+ *
+ * $FreeBSD$
+ */
+#ifndef _SCIC_SDS_CONTROLLER_REGISTERS_H_
+#define _SCIC_SDS_CONTROLLER_REGISTERS_H_
+
+/**
+ * @file
+ *
+ * @brief This file contains macros used to perform the register reads/writes
+ * to the SCU hardware.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif // __cplusplus
+
+#include <dev/isci/scil/scu_registers.h>
+#include <dev/isci/scil/scic_sds_controller.h>
+
+/**
+ * @name 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) \
+ )
+/*@}*/
+
+/**
+ * @name 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_register_read(controller, reg) \
+ scu_register_read( \
+ (controller), \
+ (controller)->scu_registers->afe.reg \
+ )
+/*@}*/
+
+/**
+ * @name SGPIO_PEG0_REGISTER_ACCESS_MACROS
+ */
+/*@{*/
+#define scu_sgpio_peg0_register_read(controller, reg) \
+ scu_register_read( \
+ (controller), \
+ (controller)->scu_registers->peg0.sgpio.reg \
+ )
+
+#define scu_sgpio_peg0_register_write(controller, reg, value) \
+ scu_register_write( \
+ (controller), \
+ (controller)->scu_registers->peg0.sgpio.reg, \
+ (value) \
+ )
+/*@}*/
+
+/**
+ * @name 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 \
+ )
+/*@}*/
+
+/**
+ * @name SCRATCH_RAM_REGISTER_ACCESS_MACROS
+ */
+/*@{*/
+// Scratch RAM access may be needed before the scu_registers pointer
+// has been initialized. So instead, explicitly cast BAR1 to a
+// SCU_REGISTERS_T data structure.
+
+// Scratch RAM is stored in the Zoning Permission Table for OROM use.
+#define scu_controller_scratch_ram_register_write(controller, index, value) \
+ scu_register_write( \
+ (controller), \
+ ((SCU_REGISTERS_T *)scic_cb_pci_get_bar(controller, PATSBURG_SCU_BAR))->peg0.zpt0.table[index], \
+ value \
+ )
+
+#define scu_controller_scratch_ram_register_read(controller, index) \
+ scu_register_read( \
+ (controller), \
+ ((SCU_REGISTERS_T *)scic_cb_pci_get_bar(controller, PATSBURG_SCU_BAR))->peg0.zpt0.table[index] \
+ )
+
+#define scu_controller_scratch_ram_register_write_ext(controller, index, value) \
+ scu_register_write( \
+ (controller), \
+ ((SCU_REGISTERS_T *)scic_cb_pci_get_bar(controller, PATSBURG_SCU_BAR))->peg0.zpt1.table[index], \
+ value \
+ )
+
+#define scu_controller_scratch_ram_register_read_ext(controller, index) \
+ scu_register_read( \
+ (controller), \
+ ((SCU_REGISTERS_T *)scic_cb_pci_get_bar(controller, PATSBURG_SCU_BAR))->peg0.zpt1.table[index] \
+ )
+/*@}*/
+
+
+//*****************************************************************************
+//* SMU REGISTERS
+//*****************************************************************************
+
+/**
+ * @name 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, \
+ sci_cb_physical_address_lower(address) \
+ );\
+ scic_sds_controller_smu_register_write( \
+ controller, \
+ host_task_table_upper, \
+ sci_cb_physical_address_upper(address) \
+ ); \
+}
+
+#define SMU_CQBAR_WRITE(controller, address) \
+{ \
+ scic_sds_controller_smu_register_write( \
+ controller, \
+ completion_queue_lower, \
+ sci_cb_physical_address_lower(address) \
+ ); \
+ scic_sds_controller_smu_register_write( \
+ controller, \
+ completion_queue_upper, \
+ sci_cb_physical_address_upper(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, \
+ sci_cb_physical_address_lower(address) \
+ ); \
+ scic_sds_controller_smu_register_write( \
+ controller, \
+ remote_node_context_upper, \
+ sci_cb_physical_address_upper(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_CGUCR_READ(controller) \
+ scic_sds_controller_smu_register_read( \
+ controller, clock_gating_control \
+ )
+
+#define SMU_CGUCR_WRITE(controller, value) \
+ scic_sds_controller_smu_register_write( \
+ controller, clock_gating_control, value \
+ )
+
+#define SMU_CQPR_READ(controller) \
+ scic_sds_controller_smu_register_read( \
+ controller, completion_queue_put \
+ )
+
+/*@}*/
+
+/**
+ * @name 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
+//****************************************************************************
+
+/**
+ * @name 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) \
+ )
+/*@}*/
+
+/**
+ * @name SCU_SDMA_REGISTERS
+ */
+/*@{*/
+#define SCU_PUFATHAR_WRITE(controller, address) \
+{ \
+ scu_sdma_register_write( \
+ controller, \
+ uf_address_table_lower, \
+ sci_cb_physical_address_lower(address) \
+ ); \
+ scu_sdma_register_write( \
+ controller, \
+ uf_address_table_upper, \
+ sci_cb_physical_address_upper(address) \
+ ); \
+}
+
+#define SCU_UFHBAR_WRITE(controller, address) \
+{ \
+ scu_sdma_register_write( \
+ controller, \
+ uf_header_base_address_lower, \
+ sci_cb_physical_address_lower(address) \
+ ); \
+ scu_sdma_register_write( \
+ controller, \
+ uf_header_base_address_upper, \
+ sci_cb_physical_address_upper(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 CRAM AND FBRAM Registers
+//*****************************************************************************
+/**
+ * @name SCU_CRAM_REGISTER_ACCESS_MACROS
+ */
+/*@{*/
+#define scu_cram_register_read(controller, reg) \
+ scu_register_read( \
+ (controller), \
+ (controller)->scu_registers->cram.reg \
+ )
+
+#define scu_cram_register_write(controller, reg, value) \
+ scu_register_write( \
+ (controller), \
+ (controller)->scu_registers->cram.reg, \
+ (value) \
+ )
+/*@}*/
+
+/**
+ * @name SCU_FBRAM_REGISTER_ACCESS_MACROS
+ */
+/*@{*/
+#define scu_fbram_register_read(controller, reg) \
+ scu_register_read( \
+ (controller), \
+ (controller)->scu_registers->fbram.reg \
+ )
+
+#define scu_fbram_register_write(controller, reg, value) \
+ scu_register_write( \
+ (controller), \
+ (controller)->scu_registers->fbram.reg, \
+ (value) \
+ )
+/*@}*/
+
+
+/**
+ * @name SCU_CRAM_REGISTERS
+ */
+/*@{*/
+
+// SRAM ECC CONTROL REGISTER BITS
+#define SIGNLE_BIT_ERROR_CORRECTION_ENABLE 0x00000001
+#define MULTI_BIT_ERROR_REPORTING_ENABLE 0x00000002
+#define SINGLE_BIT_ERROR_REPORTING_ENABLE 0x00000004
+
+//SRAM ECC control register (SECR0)
+#define SCU_SECR0_WRITE(controller, value) \
+ scu_cram_register_write( \
+ controller, \
+ sram_ecc_control_0, \
+ value \
+ )
+/*@}*/
+
+/**
+ * @name SCU_FBRAM_REGISTERS
+ */
+/*@{*/
+
+//SRAM ECC control register (SECR1)
+#define SCU_SECR1_WRITE(controller, value) \
+ scu_fbram_register_write( \
+ controller, \
+ sram_ecc_control_1, \
+ value \
+ )
+/*@}*/
+
+
+//*****************************************************************************
+//* SCU Port Task Scheduler Group Registers
+//*****************************************************************************
+
+/**
+ * @name 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) \
+ )
+/*@}*/
+
+/**
+ * @name 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 \
+ )
+/*@}*/
+
+#ifdef __cplusplus
+}
+#endif // __cplusplus
+
+#endif // _SCIC_SDS_CONTROLLER_REGISTERS_H_
diff --git a/sys/dev/isci/scil/scic_sds_library.c b/sys/dev/isci/scil/scic_sds_library.c
new file mode 100644
index 0000000..5337516
--- /dev/null
+++ b/sys/dev/isci/scil/scic_sds_library.c
@@ -0,0 +1,287 @@
+/*-
+ * 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.
+ *
+ * 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 <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/**
+ * @file
+ *
+ * @brief This file contains the implementation of the public methods for a
+ * SCIC_SDS_LIBRARY object.
+ */
+
+#include <dev/isci/scil/scic_library.h>
+#include <dev/isci/scil/scic_sds_library.h>
+#include <dev/isci/scil/scic_sds_controller.h>
+#include <dev/isci/scil/scic_sds_request.h>
+#include <dev/isci/scil/scic_sds_remote_device.h>
+#include <dev/isci/scil/intel_pci.h>
+#include <dev/isci/scil/scic_sds_pci.h>
+#include <dev/isci/scil/scu_constants.h>
+
+struct SCIC_SDS_CONTROLLER;
+
+#define SCIC_LIBRARY_CONTROLLER_MEMORY_START(library) \
+ ((char *)(library) + sizeof(SCIC_SDS_LIBRARY_T))
+
+// ---------------------------------------------------------------------------
+
+U32 scic_library_get_object_size(
+ U8 max_controller_count
+)
+{
+ return sizeof(SCIC_SDS_LIBRARY_T)
+ + scic_sds_controller_get_object_size() * max_controller_count;
+}
+
+// ---------------------------------------------------------------------------
+
+SCI_LIBRARY_HANDLE_T scic_library_construct(
+ void * library_memory,
+ U8 max_controller_count
+)
+{
+ SCI_STATUS status;
+ SCIC_SDS_LIBRARY_T *this_library;
+
+ this_library = (SCIC_SDS_LIBRARY_T *)library_memory;
+
+ this_library->max_controller_count = max_controller_count;
+
+ this_library->controllers =
+ (SCIC_SDS_CONTROLLER_T *)((char *)library_memory + sizeof(SCIC_SDS_LIBRARY_T));
+
+ SCI_BASE_LIBRARY_CONSTRUCT(this_library,
+ &this_library->parent,
+ max_controller_count,
+ struct SCIC_SDS_CONTROLLER,
+ status);
+ return this_library;
+}
+
+// ---------------------------------------------------------------------------
+
+void scic_library_set_pci_info(
+ SCI_LIBRARY_HANDLE_T library,
+ SCI_PCI_COMMON_HEADER_T * pci_header
+)
+{
+ SCIC_SDS_LIBRARY_T *this_library;
+ this_library = (SCIC_SDS_LIBRARY_T *)library;
+
+ this_library->pci_device = pci_header->device_id;
+
+#if defined(PBG_HBA_A0_BUILD)
+ this_library->pci_revision = SCIC_SDS_PCI_REVISION_A0;
+#elif defined(PBG_HBA_A2_BUILD)
+ this_library->pci_revision = SCIC_SDS_PCI_REVISION_A2;
+#elif defined(PBG_HBA_BETA_BUILD)
+ this_library->pci_revision = SCIC_SDS_PCI_REVISION_B0;
+#elif defined(PBG_BUILD)
+ // The SCU PCI function revision ID for A0/A2 is not populated
+ // properly. As a result, we force the revision ID to A2 for
+ // this situation. Therefore, the standard PBG build will not
+ // work for A0.
+ if (pci_header->revision == SCIC_SDS_PCI_REVISION_A0)
+ this_library->pci_revision = SCIC_SDS_PCI_REVISION_A2;
+ else
+ this_library->pci_revision = pci_header->revision;
+#endif
+}
+
+// ---------------------------------------------------------------------------
+
+SCI_STATUS scic_library_allocate_controller(
+ SCI_LIBRARY_HANDLE_T library,
+ SCI_CONTROLLER_HANDLE_T *new_controller
+)
+{
+ SCI_STATUS status;
+ SCIC_SDS_LIBRARY_T *this_library;
+
+ this_library = (SCIC_SDS_LIBRARY_T *)library;
+
+ if (
+ ( (this_library->pci_device >= 0x1D60)
+ && (this_library->pci_device <= 0x1D62)
+ )
+ || ( (this_library->pci_device >= 0x1D64)
+ && (this_library->pci_device <= 0x1D65)
+ )
+ || ( (this_library->pci_device >= 0x1D68)
+ && (this_library->pci_device <= 0x1D6F)
+ )
+ )
+ {
+ SCI_BASE_LIBRARY_ALLOCATE_CONTROLLER(
+ this_library, new_controller, &status);
+ }
+ else
+ status = SCI_FAILURE_UNSUPPORTED_PCI_DEVICE_ID;
+
+ return status;
+}
+
+// ---------------------------------------------------------------------------
+
+SCI_STATUS scic_library_free_controller(
+ SCI_LIBRARY_HANDLE_T library,
+ SCI_CONTROLLER_HANDLE_T controller
+)
+{
+ SCI_STATUS status;
+ SCIC_SDS_LIBRARY_T *this_library;
+ this_library = (SCIC_SDS_LIBRARY_T *)library;
+
+ SCI_BASE_LIBRARY_FREE_CONTROLLER(
+ this_library, controller, struct SCIC_SDS_CONTROLLER, &status);
+
+ return status;
+}
+
+// ---------------------------------------------------------------------------
+
+U8 scic_library_get_pci_device_controller_count(
+ SCI_LIBRARY_HANDLE_T library
+)
+{
+ SCIC_SDS_LIBRARY_T *this_library;
+ U16 device_id;
+
+ this_library = (SCIC_SDS_LIBRARY_T *)library;
+ device_id = this_library->pci_device;
+
+ //Check if we are on a b0 or c0 which has 2 controllers
+ if (
+ // Warning: If 0x1d66 is ever defined to be a single controller
+ // this logic will fail.
+ // If 0x1d63 or 0x1d67 is ever defined to be dual
+ // controller this logic will fail.
+ ((device_id & 0xFFF1) == 0x1D60)
+ && (
+ (this_library->pci_revision == SCU_PBG_HBA_REV_B0)
+ || (this_library->pci_revision == SCU_PBG_HBA_REV_C0)
+ || (this_library->pci_revision == SCU_PBG_HBA_REV_C1)
+ )
+ )
+ return 2;
+ else
+ return 1;
+}
+
+// ---------------------------------------------------------------------------
+
+U32 scic_library_get_max_sge_size(
+ SCI_LIBRARY_HANDLE_T library
+)
+{
+ return SCU_IO_REQUEST_MAX_SGE_SIZE;
+}
+
+// ---------------------------------------------------------------------------
+
+U32 scic_library_get_max_sge_count(
+ SCI_LIBRARY_HANDLE_T library
+)
+{
+ return SCU_IO_REQUEST_SGE_COUNT;
+}
+
+// ---------------------------------------------------------------------------
+
+U32 scic_library_get_max_io_length(
+ SCI_LIBRARY_HANDLE_T library
+)
+{
+ return SCU_IO_REQUEST_MAX_TRANSFER_LENGTH;
+}
+
+// ---------------------------------------------------------------------------
+
+U16 scic_library_get_min_timer_count(void)
+{
+ return (U16) (scic_sds_controller_get_min_timer_count()
+ + scic_sds_remote_device_get_min_timer_count()
+ + scic_sds_request_get_min_timer_count());
+}
+
+// ---------------------------------------------------------------------------
+
+U16 scic_library_get_max_timer_count(void)
+{
+ return (U16) (scic_sds_controller_get_max_timer_count()
+ + scic_sds_remote_device_get_max_timer_count()
+ + scic_sds_request_get_max_timer_count());
+}
+
+/**
+ *
+ */
+U8 scic_sds_library_get_controller_index(
+ SCIC_SDS_LIBRARY_T * library,
+ SCIC_SDS_CONTROLLER_T * controller
+)
+{
+ U8 index;
+
+ for (index = 0; index < library->max_controller_count; index++)
+ {
+ if (controller == &library->controllers[index])
+ {
+ return index;
+ }
+ }
+
+ return 0xff;
+}
+
diff --git a/sys/dev/isci/scil/scic_sds_library.h b/sys/dev/isci/scil/scic_sds_library.h
new file mode 100644
index 0000000..d6a7c83
--- /dev/null
+++ b/sys/dev/isci/scil/scic_sds_library.h
@@ -0,0 +1,118 @@
+/*-
+ * 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.
+ *
+ * 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.
+ *
+ * $FreeBSD$
+ */
+#ifndef _SCIC_SDS_LIBRARY_H_
+#define _SCIC_SDS_LIBRARY_H_
+
+/**
+ * @file
+ *
+ * @brief This file contains the structures used by the core library object.
+ * All of the functionality for the core library is in the
+ * sci_base_library.h file.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif // __cplusplus
+
+#include <dev/isci/scil/sci_base_library.h>
+#include <dev/isci/scil/scic_sds_pci.h>
+
+// Forward declar the controllers
+struct SCIC_SDS_CONTROLLER;
+
+/**
+ * @struct SCIC_SDS_LIBRARY
+ *
+ * This structure contains data used by the core library.
+ */
+typedef struct SCIC_SDS_LIBRARY
+{
+ /*
+ * The SCI_BASE_LIBRARY is the parent object for the SCIC_SDS_LIBRARY
+ * object.
+ */
+ SCI_BASE_LIBRARY_T parent;
+
+ /**
+ * This is the count of the maximum number of controllers that this library
+ * can contain.
+ */
+ U32 max_controller_count;
+
+ /**
+ * The PCI header for this library object all libraries must have the same
+ * pci device id.
+ */
+ U16 pci_device;
+ U8 pci_revision;
+
+ /**
+ * This field is the array of controllers that are contained within the
+ * library object.
+ */
+ struct SCIC_SDS_CONTROLLER *controllers;
+
+} SCIC_SDS_LIBRARY_T;
+
+U8 scic_sds_library_get_controller_index(
+ struct SCIC_SDS_LIBRARY * library,
+ struct SCIC_SDS_CONTROLLER * controller
+);
+
+#ifdef __cplusplus
+}
+#endif // __cplusplus
+
+#endif // _SCIC_SDS_LIBRARY_H_
diff --git a/sys/dev/isci/scil/scic_sds_logger.h b/sys/dev/isci/scil/scic_sds_logger.h
new file mode 100644
index 0000000..56e50dc
--- /dev/null
+++ b/sys/dev/isci/scil/scic_sds_logger.h
@@ -0,0 +1,93 @@
+/*-
+ * 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.
+ *
+ * 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.
+ *
+ * $FreeBSD$
+ */
+#ifndef _SCIC_SDS_LOGGER_H_
+#define _SCIC_SDS_LOGGER_H_
+
+/**
+ * @file
+ *
+ * @brief This file contains some macros to remap the user callbacks for log
+ * messages.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif // __cplusplus
+
+#include <dev/isci/scil/scic_logger.h>
+#include <dev/isci/scil/scic_user_callback.h>
+
+#if defined (SCI_LOGGING)
+
+#define SCIC_LOG_ERROR(x) scic_cb_logger_log_error x
+#define SCIC_LOG_WARNING(x) scic_cb_logger_log_warning x
+#define SCIC_LOG_INFO(x) scic_cb_logger_log_info x
+#define SCIC_LOG_TRACE(x) scic_cb_logger_log_trace x
+#define SCIC_LOG_STATES(x) scic_cb_logger_log_states x
+
+#else // defined (SCI_LOGGING)
+
+#define SCIC_LOG_ERROR(x)
+#define SCIC_LOG_WARNING(x)
+#define SCIC_LOG_INFO(x)
+#define SCIC_LOG_TRACE(x)
+#define SCIC_LOG_STATES(x)
+
+#endif // defined (SCI_LOGGING)
+
+#ifdef __cplusplus
+}
+#endif // __cplusplus
+
+#endif // _SCIC_SDS_LOGGER_H_
diff --git a/sys/dev/isci/scil/scic_sds_pci.c b/sys/dev/isci/scil/scic_sds_pci.c
new file mode 100644
index 0000000..d5d6200
--- /dev/null
+++ b/sys/dev/isci/scil/scic_sds_pci.c
@@ -0,0 +1,247 @@
+/*-
+ * 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.
+ *
+ * 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 <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/**
+ * @file
+ *
+ * @brief This file contains the method implementations utilized in writing
+ * out PCI data for the SCI core.
+ */
+
+#include <dev/isci/scil/scic_user_callback.h>
+
+#include <dev/isci/scil/scic_sds_pci.h>
+#include <dev/isci/scil/scic_sds_controller.h>
+
+/**
+ * @brief This method reads from the driver the BARs that are needed to
+ * determine the virtual memory space for the controller registers
+ *
+ * @param[in] this_controller The controller for which to read the base
+ * address registers.
+ */
+void scic_sds_pci_bar_initialization(
+ SCIC_SDS_CONTROLLER_T* this_controller
+)
+{
+#ifdef ARLINGTON_BUILD
+
+ #define ARLINGTON_LEX_BAR 0
+ #define ARLINGTON_SMU_BAR 1
+ #define ARLINGTON_SCU_BAR 2
+ #define LEX_REGISTER_OFFSET 0x40000
+
+ this_controller->lex_registers =
+ ((char *)scic_cb_pci_get_bar(
+ this_controller, ARLINGTON_LEX_BAR) + LEX_REGISTER_OFFSET);
+ this_controller->smu_registers =
+ (SMU_REGISTERS_T *)scic_cb_pci_get_bar(this_controller, ARLINGTON_SMU_BAR);
+ this_controller->scu_registers =
+ (SCU_REGISTERS_T *)scic_cb_pci_get_bar(this_controller, ARLINGTON_SCU_BAR);
+
+#else // !ARLINGTON_BUILD
+
+#if !defined(ENABLE_PCI_IO_SPACE_ACCESS)
+
+ this_controller->smu_registers =
+ (SMU_REGISTERS_T *)(
+ (char *)scic_cb_pci_get_bar(this_controller, PATSBURG_SMU_BAR)
+ +(0x4000 * this_controller->controller_index));
+ this_controller->scu_registers =
+ (SCU_REGISTERS_T *)(
+ (char *)scic_cb_pci_get_bar(this_controller, PATSBURG_SCU_BAR)
+ +(0x400000 * this_controller->controller_index));
+
+#else // !defined(ENABLE_PCI_IO_SPACE_ACCESS)
+
+ if (this_controller->controller_index == 0)
+ {
+ this_controller->smu_registers = (SMU_REGISTERS_T *)
+ scic_cb_pci_get_bar(this_controller, PATSBURG_IO_SPACE_BAR0);
+ }
+ else
+ {
+ if (this_controller->pci_revision == SCU_PBG_HBA_REV_B0)
+ {
+ // SCU B0 violates PCI spec for size of IO bar this is corrected
+ // in subsequent version of the hardware so we can safely use the
+ // else condition below.
+ this_controller->smu_registers = (SMU_REGISTERS_T *)
+ (scic_cb_pci_get_bar(this_controller, PATSBURG_IO_SPACE_BAR0) + 0x100);
+ }
+ else
+ {
+ this_controller->smu_registers = (SMU_REGISTERS_T *)
+ scic_cb_pci_get_bar(this_controller, PATSBURG_IO_SPACE_BAR1);
+ }
+ }
+
+ // No need to get the bar. We will be using the offset to write to
+ // input/output ports via 0xA0 and 0xA4.
+ this_controller->scu_registers = (SCU_REGISTERS_T *) 0;
+
+#endif // !defined(ENABLE_PCI_IO_SPACE_ACCESS)
+
+#endif // ARLINGTON_BUILD
+}
+
+#if defined(ENABLE_PCI_IO_SPACE_ACCESS) && !defined(ARLINGTON_BUILD)
+
+/**
+ * @brief This method will read from PCI memory for the SMU register
+ * space via IO space access.
+ *
+ * @param[in] controller The controller for which to read a DWORD.
+ * @param[in] address This parameter depicts the address from
+ * which to read.
+ *
+ * @return The value being returned from the PCI memory location.
+ *
+ * @todo This PCI memory access calls likely need to be optimized into macro?
+ */
+U32 scic_sds_pci_read_smu_dword(
+ SCI_CONTROLLER_HANDLE_T controller,
+ void * address
+)
+{
+ return scic_cb_pci_read_dword(controller, address);
+}
+
+/**
+ * @brief This method will write to PCI memory for the SMU register
+ * space via IO space access.
+ *
+ * @param[in] controller The controller for which to read a DWORD.
+ * @param[in] address This parameter depicts the address into
+ * which to write.
+ * @param[out] write_value This parameter depicts the value being written
+ * into the PCI memory location.
+ *
+ * @todo This PCI memory access calls likely need to be optimized into macro?
+ */
+void scic_sds_pci_write_smu_dword(
+ SCI_CONTROLLER_HANDLE_T controller,
+ void * address,
+ U32 write_value
+)
+{
+ scic_cb_pci_write_dword(controller, address, write_value);
+}
+
+/**
+ * @brief This method will read from PCI memory for the SCU register
+ * space via IO space access.
+ *
+ * @param[in] controller The controller for which to read a DWORD.
+ * @param[in] address This parameter depicts the address from
+ * which to read.
+ *
+ * @return The value being returned from the PCI memory location.
+ *
+ * @todo This PCI memory access calls likely need to be optimized into macro?
+ */
+U32 scic_sds_pci_read_scu_dword(
+ SCI_CONTROLLER_HANDLE_T controller,
+ void * address
+)
+{
+ SCIC_SDS_CONTROLLER_T * this_controller = (SCIC_SDS_CONTROLLER_T*)controller;
+
+ scic_cb_pci_write_dword(
+ controller,
+ (void*) ((char *)(this_controller->smu_registers) + SCU_MMR_ADDRESS_WINDOW_OFFSET),
+ (U32) address
+ );
+
+ return scic_cb_pci_read_dword(
+ controller,
+ (void*) ((char *)(this_controller->smu_registers) + SCU_MMR_DATA_WINDOW_OFFSET)
+ );
+}
+
+/**
+ * @brief This method will write to PCI memory for the SCU register
+ * space via IO space access.
+ *
+ * @param[in] controller The controller for which to read a DWORD.
+ * @param[in] address This parameter depicts the address into
+ * which to write.
+ * @param[out] write_value This parameter depicts the value being written
+ * into the PCI memory location.
+ *
+ * @todo This PCI memory access calls likely need to be optimized into macro?
+ */
+void scic_sds_pci_write_scu_dword(
+ SCI_CONTROLLER_HANDLE_T controller,
+ void * address,
+ U32 write_value
+)
+{
+ SCIC_SDS_CONTROLLER_T * this_controller = (SCIC_SDS_CONTROLLER_T*)controller;
+
+ scic_cb_pci_write_dword(
+ controller,
+ (void*) ((char *)(this_controller->smu_registers) + SCU_MMR_ADDRESS_WINDOW_OFFSET),
+ (U32) address
+ );
+
+ scic_cb_pci_write_dword(
+ controller,
+ (void*) ((char *)(this_controller->smu_registers) + SCU_MMR_DATA_WINDOW_OFFSET),
+ write_value
+ );
+}
+
+#endif // defined(ENABLE_PCI_IO_SPACE_ACCESS)
diff --git a/sys/dev/isci/scil/scic_sds_pci.h b/sys/dev/isci/scil/scic_sds_pci.h
new file mode 100644
index 0000000..8ddcd7d
--- /dev/null
+++ b/sys/dev/isci/scil/scic_sds_pci.h
@@ -0,0 +1,138 @@
+/*-
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 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.
+ *
+ * $FreeBSD$
+ */
+#ifndef _SCIC_SDS_PCI_H_
+#define _SCIC_SDS_PCI_H_
+
+/**
+ * @file
+ *
+ * @brief This file contains the prototypes/macros utilized in writing
+ * out PCI data for the SCI core.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif // __cplusplus
+
+#include <dev/isci/scil/sci_types.h>
+
+#define PATSBURG_SMU_BAR 0
+#define PATSBURG_SCU_BAR 1
+#define PATSBURG_IO_SPACE_BAR0 2
+#define PATSBURG_IO_SPACE_BAR1 3
+
+#define SCIC_SDS_PCI_REVISION_A0 0
+#define SCIC_SDS_PCI_REVISION_A2 2
+#define SCIC_SDS_PCI_REVISION_B0 4
+#define SCIC_SDS_PCI_REVISION_C0 5
+#define SCIC_SDS_PCI_REVISION_C1 6
+
+enum SCU_CONTROLLER_PCI_REVISION_CODE
+{
+ SCU_PBG_HBA_REV_A0 = SCIC_SDS_PCI_REVISION_A0,
+ SCU_PBG_HBA_REV_A2 = SCIC_SDS_PCI_REVISION_A2,
+ SCU_PBG_HBA_REV_B0 = SCIC_SDS_PCI_REVISION_B0,
+ SCU_PBG_HBA_REV_C0 = SCIC_SDS_PCI_REVISION_C0,
+ SCU_PBG_HBA_REV_C1 = SCIC_SDS_PCI_REVISION_C1
+};
+
+struct SCIC_SDS_CONTROLLER;
+
+void scic_sds_pci_bar_initialization(
+ struct SCIC_SDS_CONTROLLER * this_controller
+);
+
+#if !defined(ENABLE_PCI_IO_SPACE_ACCESS) || defined(ARLINGTON_BUILD)
+
+#define scic_sds_pci_read_smu_dword scic_cb_pci_read_dword
+#define scic_sds_pci_write_smu_dword scic_cb_pci_write_dword
+#define scic_sds_pci_read_scu_dword scic_cb_pci_read_dword
+#define scic_sds_pci_write_scu_dword scic_cb_pci_write_dword
+
+#else // !defined(ENABLE_PCI_IO_SPACE_ACCESS)
+
+// These two registers form the Data/Index pair equivalent in the
+// SCU. They are only used for access registers in BAR 1, not BAR 0.
+#define SCU_MMR_ADDRESS_WINDOW_OFFSET 0xA0
+#define SCU_MMR_DATA_WINDOW_OFFSET 0xA4
+
+U32 scic_sds_pci_read_smu_dword(
+ SCI_CONTROLLER_HANDLE_T controller,
+ void * address
+);
+
+void scic_sds_pci_write_smu_dword(
+ SCI_CONTROLLER_HANDLE_T controller,
+ void * address,
+ U32 write_value
+);
+
+U32 scic_sds_pci_read_scu_dword(
+ SCI_CONTROLLER_HANDLE_T controller,
+ void * address
+);
+
+void scic_sds_pci_write_scu_dword(
+ SCI_CONTROLLER_HANDLE_T controller,
+ void * address,
+ U32 write_value
+);
+
+#endif // !defined(ENABLE_PCI_IO_SPACE_ACCESS)
+
+#ifdef __cplusplus
+}
+#endif // __cplusplus
+
+#endif // _SCIC_SDS_PCI_H_
diff --git a/sys/dev/isci/scil/scic_sds_phy.c b/sys/dev/isci/scil/scic_sds_phy.c
new file mode 100644
index 0000000..f53ab3d
--- /dev/null
+++ b/sys/dev/isci/scil/scic_sds_phy.c
@@ -0,0 +1,4036 @@
+/*-
+ * 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.
+ *
+ * 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 <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/**
+ * @file
+ *
+ * @brief This file contains the implementation of the SCIC_SDS_PHY public and
+ * protected methods.
+ */
+
+#include <dev/isci/scil/scic_user_callback.h>
+#include <dev/isci/scil/scic_phy.h>
+#include <dev/isci/scil/scic_sds_phy.h>
+#include <dev/isci/scil/scic_sds_port.h>
+#include <dev/isci/scil/scic_sds_controller_registers.h>
+#include <dev/isci/scil/scic_sds_phy_registers.h>
+#include <dev/isci/scil/scic_sds_logger.h>
+#include <dev/isci/scil/scic_sds_remote_node_context.h>
+#include <dev/isci/scil/sci_util.h>
+#include <dev/isci/scil/scic_sds_controller.h>
+#include <dev/isci/scil/scu_event_codes.h>
+#include <dev/isci/scil/sci_base_state.h>
+#include <dev/isci/scil/intel_ata.h>
+#include <dev/isci/scil/intel_sata.h>
+#include <dev/isci/scil/sci_base_state_machine.h>
+#include <dev/isci/scil/scic_sds_port_registers.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)
+
+#define AFE_REGISTER_WRITE_DELAY 10
+
+//*****************************************************************************
+//* SCIC SDS PHY Internal Methods
+//*****************************************************************************
+
+/**
+ * @brief This method will initialize the phy transport layer registers
+ *
+ * @param[in] this_phy
+ * @param[in] transport_layer_registers
+ *
+ * @return SCI_STATUS
+ */
+static
+SCI_STATUS scic_sds_phy_transport_layer_initialization(
+ SCIC_SDS_PHY_T *this_phy,
+ SCU_TRANSPORT_LAYER_REGISTERS_T *transport_layer_registers
+)
+{
+ U32 tl_control;
+
+ SCIC_LOG_TRACE((
+ sci_base_object_get_logger(this_phy),
+ SCIC_LOG_OBJECT_PHY,
+ "scic_sds_phy_link_layer_initialization(this_phy:0x%x, link_layer_registers:0x%x)\n",
+ this_phy, transport_layer_registers
+ ));
+
+ this_phy->transport_layer_registers = transport_layer_registers;
+
+ SCU_STPTLDARNI_WRITE(this_phy, SCIC_SDS_REMOTE_NODE_CONTEXT_INVALID_INDEX);
+
+ // Hardware team recommends that we enable the STP prefetch for all transports
+ tl_control = SCU_TLCR_READ(this_phy);
+ tl_control |= SCU_TLCR_GEN_BIT(STP_WRITE_DATA_PREFETCH);
+ SCU_TLCR_WRITE(this_phy, tl_control);
+
+ return SCI_SUCCESS;
+}
+
+/**
+ * @brief This method will initialize the phy link layer registers
+ *
+ * @param[in] this_phy
+ * @param[in] link_layer_registers
+ *
+ * @return SCI_STATUS
+ */
+static
+SCI_STATUS scic_sds_phy_link_layer_initialization(
+ SCIC_SDS_PHY_T *this_phy,
+ SCU_LINK_LAYER_REGISTERS_T *link_layer_registers
+)
+{
+ U32 phy_configuration;
+ SAS_CAPABILITIES_T phy_capabilities;
+ U32 parity_check = 0;
+ U32 parity_count = 0;
+ U32 link_layer_control;
+ U32 phy_timer_timeout_values;
+ U32 clksm_value = 0;
+
+ SCIC_LOG_TRACE((
+ sci_base_object_get_logger(this_phy),
+ SCIC_LOG_OBJECT_PHY,
+ "scic_sds_phy_link_layer_initialization(this_phy:0x%x, link_layer_registers:0x%x)\n",
+ this_phy, link_layer_registers
+ ));
+
+ 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.sci_format.high
+ );
+ SCU_SAS_TISSAL_WRITE(
+ this_phy,
+ this_phy->owning_port->owning_controller->oem_parameters.sds1.phys[
+ this_phy->phy_index].sas_address.sci_format.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;
+
+ /*
+ * Set up SSC settings according to version of OEM Parameters.
+ */
+ {
+ U8 header_version, enable_sata, enable_sas,
+ sata_spread, sas_type, sas_spread;
+ OEM_SSC_PARAMETERS_T ssc;
+
+ header_version = this_phy->owning_port->owning_controller->
+ oem_parameters_version;
+
+ ssc.bf.ssc_sata_tx_spread_level =
+ this_phy->owning_port->owning_controller->oem_parameters.sds1.controller.ssc_sata_tx_spread_level;
+ ssc.bf.ssc_sas_tx_spread_level =
+ this_phy->owning_port->owning_controller->oem_parameters.sds1.controller.ssc_sas_tx_spread_level;
+ ssc.bf.ssc_sas_tx_type =
+ this_phy->owning_port->owning_controller->oem_parameters.sds1.controller.ssc_sas_tx_type;
+ enable_sata = enable_sas = sata_spread = sas_type = sas_spread = 0;
+
+ if (header_version == SCI_OEM_PARAM_VER_1_0)
+ {
+ /*
+ * Version 1.0 is merely turning SSC on to default values.;
+ */
+ if (ssc.do_enable_ssc != 0)
+ {
+ enable_sas = enable_sata = TRUE;
+ sas_type = 0x0; // Downspreading
+ sata_spread = 0x2; // +0 to -1419 PPM
+ sas_spread = 0x2; // +0 to -1419 PPM
+ }
+ }
+ else // header_version >= SCI_OEM_PARAM_VER_1_1
+ {
+ /*
+ * Version 1.1 can turn on SAS and SATA independently and
+ * specify spread levels. Also can specify spread type for SAS.
+ */
+ if ((sata_spread = ssc.bf.ssc_sata_tx_spread_level) != 0)
+ enable_sata = TRUE; // Downspreading only
+ if ((sas_spread = ssc.bf.ssc_sas_tx_spread_level) != 0)
+ {
+ enable_sas = TRUE;
+ sas_type = ssc.bf.ssc_sas_tx_type;
+ }
+ }
+
+ if (enable_sas == TRUE)
+ {
+ U32 reg_val = scu_afe_register_read(
+ this_phy->owning_port->owning_controller,
+ scu_afe_xcvr[this_phy->phy_index].
+ afe_xcvr_control0);
+ reg_val |= (0x00100000 | (((U32)sas_type) << 19));
+ scu_afe_register_write(
+ this_phy->owning_port->owning_controller,
+ scu_afe_xcvr[this_phy->phy_index].afe_xcvr_control0,
+ reg_val);
+
+ reg_val = scu_afe_register_read(
+ this_phy->owning_port->owning_controller,
+ scu_afe_xcvr[this_phy->phy_index].
+ afe_tx_ssc_control);
+ reg_val |= (((U32)(sas_spread)) << 8);
+ scu_afe_register_write(
+ this_phy->owning_port->owning_controller,
+ scu_afe_xcvr[this_phy->phy_index].afe_tx_ssc_control,
+ reg_val);
+ 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;
+ }
+
+ if (enable_sata == TRUE)
+ {
+ U32 reg_val = scu_afe_register_read(
+ this_phy->owning_port->owning_controller,
+ scu_afe_xcvr[this_phy->phy_index].
+ afe_tx_ssc_control);
+ reg_val |= (U32)sata_spread;
+ scu_afe_register_write(
+ this_phy->owning_port->owning_controller,
+ scu_afe_xcvr[this_phy->phy_index].afe_tx_ssc_control,
+ reg_val);
+
+ reg_val = scu_link_layer_register_read(
+ this_phy,
+ stp_control);
+ reg_val |= (U32)(1 << 12);
+ scu_link_layer_register_write(
+ this_phy,
+ stp_control,
+ reg_val);
+ }
+ }
+
+ // 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,
+ this_phy->owning_port->owning_controller->user_parameters.sds1.
+ phys[this_phy->phy_index].notify_enable_spin_up_insertion_frequency
+ )
+ );
+
+ // Write the ALIGN Insertion Ferequency for connected phy and inpendent of connected state
+ clksm_value = SCU_ALIGN_INSERTION_FREQUENCY_GEN_VAL (
+ CONNECTED,
+ this_phy->owning_port->owning_controller->user_parameters.sds1.
+ phys[this_phy->phy_index].in_connection_align_insertion_frequency
+ );
+
+ clksm_value |= SCU_ALIGN_INSERTION_FREQUENCY_GEN_VAL (
+ GENERAL,
+ this_phy->owning_port->owning_controller->user_parameters.sds1.
+ phys[this_phy->phy_index].align_insertion_frequency
+ );
+
+ SCU_SAS_CLKSM_WRITE ( this_phy, clksm_value);
+
+
+#if defined(PBG_HBA_A0_BUILD) || defined(PBG_HBA_A2_BUILD) || defined(PBG_HBA_BETA_BUILD)
+ /// @todo Provide a way to write this register correctly
+ scu_link_layer_register_write(this_phy, afe_lookup_table_control, 0x02108421);
+#elif defined(PBG_BUILD)
+ if (
+ (this_phy->owning_port->owning_controller->pci_revision == SCIC_SDS_PCI_REVISION_C0)
+ || (this_phy->owning_port->owning_controller->pci_revision == SCIC_SDS_PCI_REVISION_C1)
+ )
+ {
+ scu_link_layer_register_write(this_phy, afe_lookup_table_control, 0x04210400);
+ scu_link_layer_register_write(this_phy, sas_primitive_timeout, 0x20A7C05);
+ }
+ else
+ {
+ 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
+ );
+
+#if PHY_MAX_LINK_SPEED_GENERATION == SCIC_SDS_PARM_GEN1_SPEED
+#define COMPILED_MAX_LINK_RATE SCU_SAS_LINK_LAYER_CONTROL_MAX_LINK_RATE_GEN1
+#elif PHY_MAX_LINK_SPEED_GENERATION == SCIC_SDS_PARM_GEN2_SPEED
+#define COMPILED_MAX_LINK_RATE SCU_SAS_LINK_LAYER_CONTROL_MAX_LINK_RATE_GEN2
+#else
+#define COMPILED_MAX_LINK_RATE SCU_SAS_LINK_LAYER_CONTROL_MAX_LINK_RATE_GEN3
+#endif // PHY_MAX_LINK_SPEED_GENERATION
+
+ 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
+ );
+
+ phy_timer_timeout_values = scu_link_layer_register_read(
+ this_phy,
+ phy_timer_timeout_values
+ );
+
+ // Clear the default 0x36 (54us) RATE_CHANGE timeout value.
+ phy_timer_timeout_values &= ~SCU_SAS_PHYTOV_GEN_VAL(RATE_CHANGE, 0xFF);
+
+ // Set RATE_CHANGE timeout value to 0x3B (59us). This ensures SCU can
+ // lock with 3Gb drive when SCU max rate is set to 1.5Gb.
+ phy_timer_timeout_values |= SCU_SAS_PHYTOV_GEN_VAL(RATE_CHANGE, 0x3B);
+
+ scu_link_layer_register_write(
+ this_phy, phy_timer_timeout_values, phy_timer_timeout_values
+ );
+
+ // 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(PBG_HBA_A0_BUILD) || defined(PBG_HBA_A2_BUILD)
+ scu_link_layer_register_write(
+ this_phy,
+ maximum_arbitration_wait_timer_timeout,
+ SCIC_SDS_PHY_MAX_ARBITRATION_WAIT_TIME
+ );
+#endif // defined(PBG_HBA_A0_BUILD) || defined(PBG_HBA_A2_BUILD)
+
+ // Disable the link layer hang detection timer
+ scu_link_layer_register_write(
+ this_phy, link_layer_hang_detection_timeout, 0x00000000
+ );
+
+ // 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.
+ *
+ * @param[in] cookie This object is cast to the SCIC_SDS_PHY_T object.
+ *
+ * @return none
+ */
+void scic_sds_phy_sata_timeout( SCI_OBJECT_HANDLE_T cookie)
+{
+ SCIC_SDS_PHY_T * this_phy = (SCIC_SDS_PHY_T *)cookie;
+
+ SCIC_LOG_INFO((
+ sci_base_object_get_logger(this_phy),
+ SCIC_LOG_OBJECT_PHY,
+ "SCIC SDS Phy 0x%x did not receive signature fis before timeout.\n",
+ this_phy
+ ));
+
+ sci_base_state_machine_stop(
+ scic_sds_phy_get_starting_substate_machine(this_phy));
+
+ sci_base_state_machine_change_state(
+ scic_sds_phy_get_base_state_machine(this_phy),
+ SCI_BASE_PHY_STATE_STARTING
+ );
+}
+
+//*****************************************************************************
+//* SCIC SDS PHY External Methods
+//*****************************************************************************
+
+/**
+ * @brief This method returns the object size for a phy object.
+ *
+ * @return U32
+ */
+U32 scic_sds_phy_get_object_size(void)
+{
+ return sizeof(SCIC_SDS_PHY_T);
+}
+
+/**
+ * @brief This method returns the minimum number of timers required for a
+ * phy object.
+ *
+ * @return U32
+ */
+U32 scic_sds_phy_get_min_timer_count(void)
+{
+ return SCIC_SDS_PHY_MIN_TIMER_COUNT;
+}
+
+/**
+ * @brief This method returns the maximum number of timers required for a
+ * phy object.
+ *
+ * @return U32
+ */
+U32 scic_sds_phy_get_max_timer_count(void)
+{
+ return SCIC_SDS_PHY_MAX_TIMER_COUNT;
+}
+
+#ifdef SCI_LOGGING
+static
+void scic_sds_phy_initialize_state_logging(
+ SCIC_SDS_PHY_T *this_phy
+)
+{
+ sci_base_state_machine_logger_initialize(
+ &this_phy->parent.state_machine_logger,
+ &this_phy->parent.state_machine,
+ &this_phy->parent.parent,
+ scic_cb_logger_log_states,
+ "SCIC_SDS_PHY_T", "base state machine",
+ SCIC_LOG_OBJECT_PHY
+ );
+
+ sci_base_state_machine_logger_initialize(
+ &this_phy->starting_substate_machine_logger,
+ &this_phy->starting_substate_machine,
+ &this_phy->parent.parent,
+ scic_cb_logger_log_states,
+ "SCIC_SDS_PHY_T", "starting substate machine",
+ SCIC_LOG_OBJECT_PHY
+ );
+}
+#endif // SCI_LOGGING
+
+#ifdef SCIC_DEBUG_ENABLED
+/**
+ * Debug code to record the state transitions in the phy
+ *
+ * @param our_observer
+ * @param the_state_machine
+ */
+void scic_sds_phy_observe_state_change(
+ SCI_BASE_OBSERVER_T * our_observer,
+ SCI_BASE_SUBJECT_T * the_subject
+)
+{
+ SCIC_SDS_PHY_T *this_phy;
+ SCI_BASE_STATE_MACHINE_T *the_state_machine;
+
+ U8 transition_requestor;
+ U32 base_state_id;
+ U32 starting_substate_id;
+
+ the_state_machine = (SCI_BASE_STATE_MACHINE_T *)the_subject;
+ this_phy = (SCIC_SDS_PHY_T *)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
+/**
+ * This method initializes the state record debug information for the phy
+ * object.
+ *
+ * @pre The state machines for the phy object must be constructed before this
+ * function is called.
+ *
+ * @param this_phy The phy which is being initialized.
+ */
+void scic_sds_phy_initialize_state_recording(
+ SCIC_SDS_PHY_T *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
+
+/**
+ * @brief This method will construct the SCIC_SDS_PHY object
+ *
+ * @param[in] this_phy
+ * @param[in] owning_port
+ * @param[in] phy_index
+ *
+ * @return none
+ */
+void scic_sds_phy_construct(
+ SCIC_SDS_PHY_T *this_phy,
+ SCIC_SDS_PORT_T *owning_port,
+ U8 phy_index
+)
+{
+ // Call the base constructor first
+ // Copy the logger from the port (this could be the dummy port)
+ sci_base_phy_construct(
+ &this_phy->parent,
+ sci_base_object_get_logger(owning_port),
+ 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;
+ this_phy->sata_timeout_timer = NULL;
+
+ // Clear out the identification buffer data
+ memset(&this_phy->phy_type, 0, sizeof(this_phy->phy_type));
+
+ // Clear out the error counter data
+ memset(this_phy->error_counter, 0, sizeof(this_phy->error_counter));
+
+ // 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 SCI_LOGGING
+ scic_sds_phy_initialize_state_logging(this_phy);
+ #endif // SCI_LOGGING
+
+ #ifdef SCIC_DEBUG_ENABLED
+ scic_sds_phy_initialize_state_recording(this_phy);
+ #endif // SCIC_DEBUG_ENABLED
+}
+
+/**
+ * @brief 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.
+ *
+ * @param[in] this_phy This parameter specifies the phy for which to
+ * retrieve the containing port.
+ *
+ * @return This method returns a handle to a port that contains
+ * the supplied phy.
+ * @retval 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).
+ * @retval !SCI_INVALID_HANDLE All other values indicate a handle/pointer
+ * to the port containing the phy.
+ */
+SCI_PORT_HANDLE_T scic_sds_phy_get_port(
+ SCIC_SDS_PHY_T *this_phy
+)
+{
+ SCIC_LOG_TRACE((
+ sci_base_object_get_logger(this_phy),
+ SCIC_LOG_OBJECT_PHY,
+ "scic_phy_get_port(0x%x) enter\n",
+ 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;
+}
+
+/**
+ * @brief This method will assign a port to the phy object.
+ *
+ * @param[in, out] this_phy This parameter specifies the phy for which
+ * to assign a port object.
+ * @param[in] the_port This parameter is the port to assing to the phy.
+ */
+void scic_sds_phy_set_port(
+ SCIC_SDS_PHY_T * this_phy,
+ SCIC_SDS_PORT_T * 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);
+ }
+}
+
+/**
+ * @brief This method will initialize the constructed phy
+ *
+ * @param[in] this_phy
+ * @param[in] link_layer_registers
+ *
+ * @return SCI_STATUS
+ */
+SCI_STATUS scic_sds_phy_initialize(
+ SCIC_SDS_PHY_T *this_phy,
+ void *transport_layer_registers,
+ SCU_LINK_LAYER_REGISTERS_T *link_layer_registers
+)
+{
+ SCIC_LOG_TRACE((
+ sci_base_object_get_logger(this_phy),
+ SCIC_LOG_OBJECT_PHY,
+ "scic_sds_phy_initialize(this_phy:0x%x, link_layer_registers:0x%x)\n",
+ this_phy, link_layer_registers
+ ));
+
+ // Perfrom the initialization of the TL hardware
+ scic_sds_phy_transport_layer_initialization(this_phy, transport_layer_registers);
+
+ // Perofrm the initialization of the PE hardware
+ scic_sds_phy_link_layer_initialization(this_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(this_phy),
+ SCI_BASE_PHY_STATE_STOPPED
+ );
+
+ return SCI_SUCCESS;
+}
+
+/**
+ * This method assigns the direct attached device ID for this phy.
+ *
+ * @param[in] this_phy The phy for which the direct attached device id is to
+ * be assigned.
+ * @param[in] device_id The direct attached device ID to assign to the phy.
+ * This will either be the RNi for the device or an invalid RNi if there
+ * is no current device assigned to the phy.
+ */
+void scic_sds_phy_setup_transport(
+ SCIC_SDS_PHY_T * this_phy,
+ U32 device_id
+)
+{
+ U32 tl_control;
+
+ SCU_STPTLDARNI_WRITE(this_phy, device_id);
+
+ // The read should guarntee that the first write gets posted
+ // before the next write
+ tl_control = SCU_TLCR_READ(this_phy);
+ tl_control |= SCU_TLCR_GEN_BIT(CLEAR_TCI_NCQ_MAPPING_TABLE);
+ SCU_TLCR_WRITE(this_phy, tl_control);
+}
+
+/**
+ * This function will perform the register reads/writes to suspend the SCU
+ * hardware protocol engine.
+ *
+ * @param[in,out] this_phy The phy object to be suspended.
+ *
+ * @return none
+ */
+void scic_sds_phy_suspend(
+ SCIC_SDS_PHY_T * 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);
+
+ scic_sds_phy_setup_transport(
+ this_phy, SCIC_SDS_REMOTE_NODE_CONTEXT_INVALID_INDEX
+ );
+}
+
+/**
+ * This function will perform the register reads/writes required to resume the
+ * SCU hardware protocol engine.
+ *
+ * @param[in,out] this_phy The phy object to resume.
+ *
+ * @return none
+ */
+void scic_sds_phy_resume(
+ SCIC_SDS_PHY_T * 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);
+}
+
+/**
+ * @brief This method returns the local sas address assigned to this phy.
+ *
+ * @param[in] this_phy This parameter specifies the phy for which
+ * to retrieve the local SAS address.
+ * @param[out] sas_address This parameter specifies the location into
+ * which to copy the local SAS address.
+ *
+ * @return none
+ */
+void scic_sds_phy_get_sas_address(
+ SCIC_SDS_PHY_T *this_phy,
+ SCI_SAS_ADDRESS_T *sas_address
+)
+{
+ SCIC_LOG_TRACE((
+ sci_base_object_get_logger(this_phy),
+ SCIC_LOG_OBJECT_PHY,
+ "scic_sds_phy_get_sas_address(this_phy:0x%x, sas_address:0x%x)\n",
+ this_phy, sas_address
+ ));
+
+ sas_address->high = SCU_SAS_TISSAH_READ(this_phy);
+ sas_address->low = SCU_SAS_TISSAL_READ(this_phy);
+}
+
+/**
+ * @brief This method returns the remote end-point (i.e. attached)
+ * sas address assigned to this phy.
+ *
+ * @param[in] this_phy This parameter specifies the phy for which
+ * to retrieve the remote end-point SAS address.
+ * @param[out] sas_address This parameter specifies the location into
+ * which to copy the remote end-point SAS address.
+ *
+ * @return none
+ */
+void scic_sds_phy_get_attached_sas_address(
+ SCIC_SDS_PHY_T *this_phy,
+ SCI_SAS_ADDRESS_T *sas_address
+)
+{
+ SCIC_LOG_TRACE((
+ sci_base_object_get_logger(this_phy),
+ SCIC_LOG_OBJECT_PHY,
+ "scic_sds_phy_get_attached_sas_address(0x%x, 0x%x) enter\n",
+ this_phy, 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;
+}
+
+/**
+ * @brief This method returns the supported protocols assigned to
+ * this phy
+ *
+ * @param[in] this_phy
+ * @param[out] protocols
+ */
+void scic_sds_phy_get_protocols(
+ SCIC_SDS_PHY_T *this_phy,
+ SCI_SAS_IDENTIFY_ADDRESS_FRAME_PROTOCOLS_T * protocols
+)
+{
+ U32 tiid_value = SCU_SAS_TIID_READ(this_phy);
+
+ //Check each bit of this register. please refer to
+ //SAS Transmit Identification Register (SAS_TIID).
+ if (tiid_value & 0x2)
+ protocols->u.bits.smp_target = 1;
+
+ if (tiid_value & 0x4)
+ protocols->u.bits.stp_target = 1;
+
+ if (tiid_value & 0x8)
+ protocols->u.bits.ssp_target = 1;
+
+ if (tiid_value & 0x200)
+ protocols->u.bits.smp_initiator = 1;
+
+ if ((tiid_value & 0x400))
+ protocols->u.bits.stp_initiator = 1;
+
+ if (tiid_value & 0x800)
+ protocols->u.bits.ssp_initiator = 1;
+
+ SCIC_LOG_TRACE((
+ sci_base_object_get_logger(this_phy),
+ SCIC_LOG_OBJECT_PHY,
+ "scic_sds_phy_get_protocols(this_phy:0x%x, protocols:0x%x)\n",
+ this_phy, protocols->u.all
+ ));
+}
+
+/**
+ * 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.
+ *
+ * @note The caller will get the entire set of bits for the protocol value.
+ *
+ * @param[in] this_phy The parameter is the phy object for which the attached
+ * phy protcols are to be returned.
+ * @param[out] protocols The parameter is the returned protocols for the
+ * attached phy.
+ */
+void scic_sds_phy_get_attached_phy_protocols(
+ SCIC_SDS_PHY_T *this_phy,
+ SCI_SAS_IDENTIFY_ADDRESS_FRAME_PROTOCOLS_T * protocols
+)
+{
+ SCIC_LOG_TRACE((
+ sci_base_object_get_logger(this_phy),
+ SCIC_LOG_OBJECT_PHY,
+ "scic_sds_phy_get_attached_phy_protocols(this_phy:0x%x, protocols:0x%x[0x%x])\n",
+ this_phy, protocols, protocols->u.all
+ ));
+
+ 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;
+ }
+}
+
+
+/**
+ * @brief This method release resources in for a scic phy.
+ *
+ * @param[in] controller This parameter specifies the core controller, one of
+ * its phy's resources are to be released.
+ * @param[in] this_phy This parameter specifies the phy whose resourse is to
+ * be released.
+ */
+void scic_sds_phy_release_resource(
+ SCIC_SDS_CONTROLLER_T * controller,
+ SCIC_SDS_PHY_T * this_phy
+)
+{
+ SCIC_LOG_TRACE((
+ sci_base_object_get_logger(this_phy),
+ SCIC_LOG_OBJECT_PHY,
+ "scic_sds_phy_release_resource(0x%x, 0x%x)\n",
+ controller, this_phy
+ ));
+
+ //Currently, the only resource to be released is a timer.
+ if (this_phy->sata_timeout_timer != NULL)
+ {
+ scic_cb_timer_destroy(controller, this_phy->sata_timeout_timer);
+ this_phy->sata_timeout_timer = NULL;
+ }
+}
+
+
+//*****************************************************************************
+//* SCIC SDS PHY Handler Redirects
+//*****************************************************************************
+
+/**
+ * @brief This method will attempt to reset the phy. This
+ * request is only valid when the phy is in an ready
+ * state
+ *
+ * @param[in] this_phy
+ *
+ * @return SCI_STATUS
+ */
+SCI_STATUS scic_sds_phy_reset(
+ SCIC_SDS_PHY_T * this_phy
+)
+{
+ SCIC_LOG_TRACE((
+ sci_base_object_get_logger(this_phy),
+ SCIC_LOG_OBJECT_PHY,
+ "scic_sds_phy_reset(this_phy:0x%08x)\n",
+ this_phy
+ ));
+
+ return this_phy->state_handlers->parent.reset_handler(
+ &this_phy->parent
+ );
+}
+
+/**
+ * @brief This method will process the event code recieved.
+ *
+ * @param[in] this_phy
+ * @param[in] event_code
+ *
+ * @return SCI_STATUS
+ */
+SCI_STATUS scic_sds_phy_event_handler(
+ SCIC_SDS_PHY_T *this_phy,
+ U32 event_code
+)
+{
+ SCIC_LOG_TRACE((
+ sci_base_object_get_logger(this_phy),
+ SCIC_LOG_OBJECT_PHY,
+ "scic_sds_phy_event_handler(this_phy:0x%08x, event_code:%x)\n",
+ this_phy, event_code
+ ));
+
+ return this_phy->state_handlers->event_handler(this_phy, event_code);
+}
+
+/**
+ * @brief This method will process the frame index recieved.
+ *
+ * @param[in] this_phy
+ * @param[in] frame_index
+ *
+ * @return SCI_STATUS
+ */
+SCI_STATUS scic_sds_phy_frame_handler(
+ SCIC_SDS_PHY_T *this_phy,
+ U32 frame_index
+)
+{
+ SCIC_LOG_TRACE((
+ sci_base_object_get_logger(this_phy),
+ SCIC_LOG_OBJECT_PHY,
+ "scic_sds_phy_frame_handler(this_phy:0x%08x, frame_index:%d)\n",
+ this_phy, frame_index
+ ));
+
+ return this_phy->state_handlers->frame_handler(this_phy, frame_index);
+}
+
+/**
+ * @brief This method will give the phy permission to consume power
+ *
+ * @param[in] this_phy
+ *
+ * @return SCI_STATUS
+ */
+SCI_STATUS scic_sds_phy_consume_power_handler(
+ SCIC_SDS_PHY_T *this_phy
+)
+{
+ SCIC_LOG_TRACE((
+ sci_base_object_get_logger(this_phy),
+ SCIC_LOG_OBJECT_PHY,
+ "scic_sds_phy_consume_power_handler(this_phy:0x%08x)\n",
+ this_phy
+ ));
+
+ return this_phy->state_handlers->consume_power_handler(this_phy);
+}
+
+//*****************************************************************************
+//* SCIC PHY Public Methods
+//*****************************************************************************
+
+SCI_STATUS scic_phy_get_properties(
+ SCI_PHY_HANDLE_T phy,
+ SCIC_PHY_PROPERTIES_T * properties
+)
+{
+ SCIC_SDS_PHY_T *this_phy;
+ U8 max_speed_generation;
+
+ this_phy = (SCIC_SDS_PHY_T *)phy;
+
+ SCIC_LOG_TRACE((
+ sci_base_object_get_logger(this_phy),
+ SCIC_LOG_OBJECT_PHY,
+ "scic_phy_get_properties(0x%x, 0x%x) enter\n",
+ this_phy, properties
+ ));
+
+ if (phy == SCI_INVALID_HANDLE)
+ {
+ return SCI_FAILURE_INVALID_PHY;
+ }
+
+ memset(properties, 0, sizeof(SCIC_PHY_PROPERTIES_T));
+
+ //get max link rate of this phy set by user.
+ max_speed_generation =
+ this_phy->owning_port->owning_controller->user_parameters.sds1.
+ phys[this_phy->phy_index].max_speed_generation;
+
+ properties->negotiated_link_rate = this_phy->max_negotiated_speed;
+
+ if (max_speed_generation == SCIC_SDS_PARM_GEN3_SPEED)
+ properties->max_link_rate = SCI_SAS_600_GB;
+ else if (max_speed_generation == SCIC_SDS_PARM_GEN2_SPEED)
+ properties->max_link_rate = SCI_SAS_300_GB;
+ else
+ properties->max_link_rate = SCI_SAS_150_GB;
+
+ properties->index = this_phy->phy_index;
+ properties->owning_port = scic_sds_phy_get_port(this_phy);
+
+ scic_sds_phy_get_protocols(this_phy, &properties->transmit_iaf.protocols);
+
+ properties->transmit_iaf.sas_address.high =
+ this_phy->owning_port->owning_controller->oem_parameters.sds1.
+ phys[this_phy->phy_index].sas_address.sci_format.high;
+
+ properties->transmit_iaf.sas_address.low =
+ this_phy->owning_port->owning_controller->oem_parameters.sds1.
+ phys[this_phy->phy_index].sas_address.sci_format.low;
+
+ return SCI_SUCCESS;
+}
+
+// ---------------------------------------------------------------------------
+
+SCI_STATUS scic_sas_phy_get_properties(
+ SCI_PHY_HANDLE_T phy,
+ SCIC_SAS_PHY_PROPERTIES_T * properties
+)
+{
+ SCIC_SDS_PHY_T *this_phy;
+ this_phy = (SCIC_SDS_PHY_T *)phy;
+
+ SCIC_LOG_TRACE((
+ sci_base_object_get_logger(this_phy),
+ SCIC_LOG_OBJECT_PHY,
+ "scic_sas_phy_get_properties(0x%x, 0x%x) enter\n",
+ this_phy, properties
+ ));
+
+ if (this_phy->protocol == SCIC_SDS_PHY_PROTOCOL_SAS)
+ {
+ memcpy(
+ &properties->received_iaf,
+ &this_phy->phy_type.sas.identify_address_frame_buffer,
+ sizeof(SCI_SAS_IDENTIFY_ADDRESS_FRAME_T)
+ );
+
+ properties->received_capabilities.u.all
+ = SCU_SAS_RECPHYCAP_READ(this_phy);
+
+ return SCI_SUCCESS;
+ }
+
+ return SCI_FAILURE;
+}
+
+// ---------------------------------------------------------------------------
+
+SCI_STATUS scic_sata_phy_get_properties(
+ SCI_PHY_HANDLE_T phy,
+ SCIC_SATA_PHY_PROPERTIES_T * properties
+)
+{
+ SCIC_SDS_PHY_T *this_phy;
+ this_phy = (SCIC_SDS_PHY_T *)phy;
+
+ SCIC_LOG_TRACE((
+ sci_base_object_get_logger(this_phy),
+ SCIC_LOG_OBJECT_PHY,
+ "scic_sata_phy_get_properties(0x%x, 0x%x) enter\n",
+ this_phy, properties
+ ));
+
+ if (this_phy->protocol == SCIC_SDS_PHY_PROTOCOL_SATA)
+ {
+ memcpy(
+ &properties->signature_fis,
+ &this_phy->phy_type.sata.signature_fis_buffer,
+ sizeof(SATA_FIS_REG_D2H_T)
+ );
+
+ /// @todo add support for port selectors.
+ properties->is_port_selector_present = FALSE;
+
+ return SCI_SUCCESS;
+ }
+
+ return SCI_FAILURE;
+}
+
+// ---------------------------------------------------------------------------
+
+#if !defined(DISABLE_PORT_SELECTORS)
+
+SCI_STATUS scic_sata_phy_send_port_selection_signal(
+ SCI_PHY_HANDLE_T phy
+)
+{
+ SCIC_SDS_PHY_T *this_phy;
+ this_phy = (SCIC_SDS_PHY_T *)phy;
+
+ SCIC_LOG_TRACE((
+ sci_base_object_get_logger(this_phy),
+ SCIC_LOG_OBJECT_PHY,
+ "scic_sata_phy_send_port_selection_signals(0x%x) enter\n",
+ this_phy
+ ));
+
+ /// @todo To be implemented
+ ASSERT(FALSE);
+ return SCI_FAILURE;
+}
+
+#endif // !defined(DISABLE_PORT_SELECTORS)
+
+// ---------------------------------------------------------------------------
+
+#if !defined(DISABLE_PHY_COUNTERS)
+
+SCI_STATUS scic_phy_enable_counter(
+ SCI_PHY_HANDLE_T phy,
+ SCIC_PHY_COUNTER_ID_T counter_id
+)
+{
+ SCIC_SDS_PHY_T *this_phy;
+ SCI_STATUS status = SCI_SUCCESS;
+ this_phy = (SCIC_SDS_PHY_T *)phy;
+
+ SCIC_LOG_TRACE((
+ sci_base_object_get_logger(this_phy),
+ SCIC_LOG_OBJECT_PHY,
+ "scic_phy_enable_counter(0x%x, 0x%x) enter\n",
+ this_phy, counter_id
+ ));
+
+ switch(counter_id)
+ {
+ case SCIC_PHY_COUNTER_RECEIVED_DONE_ACK_NAK_TIMEOUT:
+ {
+ U32 control = SCU_SAS_ECENCR_READ(this_phy);
+ control |= (1 << SCU_ERR_CNT_RX_DONE_ACK_NAK_TIMEOUT_INDEX);
+ SCU_SAS_ECENCR_WRITE(this_phy, control);
+ }
+ break;
+ case SCIC_PHY_COUNTER_TRANSMITTED_DONE_ACK_NAK_TIMEOUT:
+ {
+ U32 control = SCU_SAS_ECENCR_READ(this_phy);
+ control |= (1 << SCU_ERR_CNT_TX_DONE_ACK_NAK_TIMEOUT_INDEX);
+ SCU_SAS_ECENCR_WRITE(this_phy, control);
+ }
+ break;
+ case SCIC_PHY_COUNTER_INACTIVITY_TIMER_EXPIRED:
+ {
+ U32 control = SCU_SAS_ECENCR_READ(this_phy);
+ control |= (1 << SCU_ERR_CNT_INACTIVITY_TIMER_EXPIRED_INDEX);
+ SCU_SAS_ECENCR_WRITE(this_phy, control);
+ }
+ break;
+ case SCIC_PHY_COUNTER_RECEIVED_DONE_CREDIT_TIMEOUT:
+ {
+ U32 control = SCU_SAS_ECENCR_READ(this_phy);
+ control |= (1 << SCU_ERR_CNT_RX_DONE_CREDIT_TIMEOUT_INDEX);
+ SCU_SAS_ECENCR_WRITE(this_phy, control);
+ }
+ break;
+ case SCIC_PHY_COUNTER_TRANSMITTED_DONE_CREDIT_TIMEOUT:
+ {
+ U32 control = SCU_SAS_ECENCR_READ(this_phy);
+ control |= (1 << SCU_ERR_CNT_TX_DONE_CREDIT_TIMEOUT_INDEX);
+ SCU_SAS_ECENCR_WRITE(this_phy, control);
+ }
+ break;
+ case SCIC_PHY_COUNTER_RECEIVED_CREDIT_BLOCKED:
+ {
+ U32 control = SCU_SAS_ECENCR_READ(this_phy);
+ control |= (1 << SCU_ERR_CNT_RX_CREDIT_BLOCKED_RECEIVED_INDEX);
+ SCU_SAS_ECENCR_WRITE(this_phy, control);
+ }
+ break;
+
+ // These error counters are enabled by default, and cannot be
+ // disabled. Return SCI_SUCCESS to denote that they are
+ // enabled, hiding the fact that enabling the counter is
+ // a no-op.
+ case SCIC_PHY_COUNTER_RECEIVED_FRAME:
+ case SCIC_PHY_COUNTER_TRANSMITTED_FRAME:
+ case SCIC_PHY_COUNTER_RECEIVED_FRAME_DWORD:
+ case SCIC_PHY_COUNTER_TRANSMITTED_FRAME_DWORD:
+ case SCIC_PHY_COUNTER_LOSS_OF_SYNC_ERROR:
+ case SCIC_PHY_COUNTER_RECEIVED_DISPARITY_ERROR:
+ case SCIC_PHY_COUNTER_RECEIVED_FRAME_CRC_ERROR:
+ case SCIC_PHY_COUNTER_RECEIVED_SHORT_FRAME:
+ case SCIC_PHY_COUNTER_RECEIVED_FRAME_WITHOUT_CREDIT:
+ case SCIC_PHY_COUNTER_RECEIVED_FRAME_AFTER_DONE:
+ case SCIC_PHY_COUNTER_SN_DWORD_SYNC_ERROR:
+ break;
+
+ default:
+ status = SCI_FAILURE;
+ break;
+ }
+ return status;
+}
+
+// ---------------------------------------------------------------------------
+
+SCI_STATUS scic_phy_disable_counter(
+ SCI_PHY_HANDLE_T phy,
+ SCIC_PHY_COUNTER_ID_T counter_id
+)
+{
+ SCIC_SDS_PHY_T *this_phy;
+ SCI_STATUS status = SCI_SUCCESS;
+
+ this_phy = (SCIC_SDS_PHY_T *)phy;
+
+ SCIC_LOG_TRACE((
+ sci_base_object_get_logger(this_phy),
+ SCIC_LOG_OBJECT_PHY,
+ "scic_phy_disable_counter(0x%x, 0x%x) enter\n",
+ this_phy, counter_id
+ ));
+
+ switch(counter_id)
+ {
+ case SCIC_PHY_COUNTER_RECEIVED_DONE_ACK_NAK_TIMEOUT:
+ {
+ U32 control = SCU_SAS_ECENCR_READ(this_phy);
+ control &= ~(1 << SCU_ERR_CNT_RX_DONE_ACK_NAK_TIMEOUT_INDEX);
+ SCU_SAS_ECENCR_WRITE(this_phy, control);
+ }
+ break;
+ case SCIC_PHY_COUNTER_TRANSMITTED_DONE_ACK_NAK_TIMEOUT:
+ {
+ U32 control = SCU_SAS_ECENCR_READ(this_phy);
+ control &= ~(1 << SCU_ERR_CNT_TX_DONE_ACK_NAK_TIMEOUT_INDEX);
+ SCU_SAS_ECENCR_WRITE(this_phy, control);
+ }
+ break;
+ case SCIC_PHY_COUNTER_INACTIVITY_TIMER_EXPIRED:
+ {
+ U32 control = SCU_SAS_ECENCR_READ(this_phy);
+ control &= ~(1 << SCU_ERR_CNT_INACTIVITY_TIMER_EXPIRED_INDEX);
+ SCU_SAS_ECENCR_WRITE(this_phy, control);
+ }
+ break;
+ case SCIC_PHY_COUNTER_RECEIVED_DONE_CREDIT_TIMEOUT:
+ {
+ U32 control = SCU_SAS_ECENCR_READ(this_phy);
+ control &= ~(1 << SCU_ERR_CNT_RX_DONE_CREDIT_TIMEOUT_INDEX);
+ SCU_SAS_ECENCR_WRITE(this_phy, control);
+ }
+ break;
+ case SCIC_PHY_COUNTER_TRANSMITTED_DONE_CREDIT_TIMEOUT:
+ {
+ U32 control = SCU_SAS_ECENCR_READ(this_phy);
+ control &= ~(1 << SCU_ERR_CNT_TX_DONE_CREDIT_TIMEOUT_INDEX);
+ SCU_SAS_ECENCR_WRITE(this_phy, control);
+ }
+ break;
+ case SCIC_PHY_COUNTER_RECEIVED_CREDIT_BLOCKED:
+ {
+ U32 control = SCU_SAS_ECENCR_READ(this_phy);
+ control &= ~(1 << SCU_ERR_CNT_RX_CREDIT_BLOCKED_RECEIVED_INDEX);
+ SCU_SAS_ECENCR_WRITE(this_phy, control);
+ }
+ break;
+
+ // These error counters cannot be disabled, so return SCI_FAILURE.
+ case SCIC_PHY_COUNTER_RECEIVED_FRAME:
+ case SCIC_PHY_COUNTER_TRANSMITTED_FRAME:
+ case SCIC_PHY_COUNTER_RECEIVED_FRAME_DWORD:
+ case SCIC_PHY_COUNTER_TRANSMITTED_FRAME_DWORD:
+ case SCIC_PHY_COUNTER_LOSS_OF_SYNC_ERROR:
+ case SCIC_PHY_COUNTER_RECEIVED_DISPARITY_ERROR:
+ case SCIC_PHY_COUNTER_RECEIVED_FRAME_CRC_ERROR:
+ case SCIC_PHY_COUNTER_RECEIVED_SHORT_FRAME:
+ case SCIC_PHY_COUNTER_RECEIVED_FRAME_WITHOUT_CREDIT:
+ case SCIC_PHY_COUNTER_RECEIVED_FRAME_AFTER_DONE:
+ case SCIC_PHY_COUNTER_SN_DWORD_SYNC_ERROR:
+ default:
+ status = SCI_FAILURE;
+ break;
+ }
+ return status;
+}
+
+// ---------------------------------------------------------------------------
+
+SCI_STATUS scic_phy_get_counter(
+ SCI_PHY_HANDLE_T phy,
+ SCIC_PHY_COUNTER_ID_T counter_id,
+ U32 * data
+)
+{
+ SCIC_SDS_PHY_T *this_phy;
+ SCI_STATUS status = SCI_SUCCESS;
+ this_phy = (SCIC_SDS_PHY_T *)phy;
+
+ SCIC_LOG_TRACE((
+ sci_base_object_get_logger(this_phy),
+ SCIC_LOG_OBJECT_PHY,
+ "scic_phy_get_counter(0x%x, 0x%x) enter\n",
+ this_phy, counter_id
+ ));
+
+ switch(counter_id)
+ {
+ case SCIC_PHY_COUNTER_RECEIVED_FRAME:
+ *data = scu_link_layer_register_read(this_phy, received_frame_count);
+ break;
+ case SCIC_PHY_COUNTER_TRANSMITTED_FRAME:
+ *data = scu_link_layer_register_read(this_phy, transmit_frame_count);
+ break;
+ case SCIC_PHY_COUNTER_RECEIVED_FRAME_DWORD:
+ *data = scu_link_layer_register_read(this_phy, received_dword_count);
+ break;
+ case SCIC_PHY_COUNTER_TRANSMITTED_FRAME_DWORD:
+ *data = scu_link_layer_register_read(this_phy, transmit_dword_count);
+ break;
+ case SCIC_PHY_COUNTER_LOSS_OF_SYNC_ERROR:
+ *data = scu_link_layer_register_read(this_phy, loss_of_sync_error_count);
+ break;
+ case SCIC_PHY_COUNTER_RECEIVED_DISPARITY_ERROR:
+ *data = scu_link_layer_register_read(this_phy, running_disparity_error_count);
+ break;
+ case SCIC_PHY_COUNTER_RECEIVED_FRAME_CRC_ERROR:
+ *data = scu_link_layer_register_read(this_phy, received_frame_crc_error_count);
+ break;
+ case SCIC_PHY_COUNTER_RECEIVED_DONE_ACK_NAK_TIMEOUT:
+ *data = this_phy->error_counter[SCU_ERR_CNT_RX_DONE_ACK_NAK_TIMEOUT_INDEX];
+ break;
+ case SCIC_PHY_COUNTER_TRANSMITTED_DONE_ACK_NAK_TIMEOUT:
+ *data = this_phy->error_counter[SCU_ERR_CNT_TX_DONE_ACK_NAK_TIMEOUT_INDEX];
+ break;
+ case SCIC_PHY_COUNTER_INACTIVITY_TIMER_EXPIRED:
+ *data = this_phy->error_counter[SCU_ERR_CNT_INACTIVITY_TIMER_EXPIRED_INDEX];
+ break;
+ case SCIC_PHY_COUNTER_RECEIVED_DONE_CREDIT_TIMEOUT:
+ *data = this_phy->error_counter[SCU_ERR_CNT_RX_DONE_CREDIT_TIMEOUT_INDEX];
+ break;
+ case SCIC_PHY_COUNTER_TRANSMITTED_DONE_CREDIT_TIMEOUT:
+ *data = this_phy->error_counter[SCU_ERR_CNT_TX_DONE_CREDIT_TIMEOUT_INDEX];
+ break;
+ case SCIC_PHY_COUNTER_RECEIVED_CREDIT_BLOCKED:
+ *data = this_phy->error_counter[SCU_ERR_CNT_RX_CREDIT_BLOCKED_RECEIVED_INDEX];
+ break;
+ case SCIC_PHY_COUNTER_RECEIVED_SHORT_FRAME:
+ *data = scu_link_layer_register_read(this_phy, received_short_frame_count);
+ break;
+ case SCIC_PHY_COUNTER_RECEIVED_FRAME_WITHOUT_CREDIT:
+ *data = scu_link_layer_register_read(this_phy, received_frame_without_credit_count);
+ break;
+ case SCIC_PHY_COUNTER_RECEIVED_FRAME_AFTER_DONE:
+ *data = scu_link_layer_register_read(this_phy, received_frame_after_done_count);
+ break;
+ case SCIC_PHY_COUNTER_SN_DWORD_SYNC_ERROR:
+ *data = scu_link_layer_register_read(this_phy, phy_reset_problem_count);
+ break;
+ default:
+ status = SCI_FAILURE;
+ break;
+ }
+
+ return status;
+}
+
+// ---------------------------------------------------------------------------
+
+SCI_STATUS scic_phy_clear_counter(
+ SCI_PHY_HANDLE_T phy,
+ SCIC_PHY_COUNTER_ID_T counter_id
+)
+{
+ SCIC_SDS_PHY_T *this_phy;
+ SCI_STATUS status = SCI_SUCCESS;
+ this_phy = (SCIC_SDS_PHY_T *)phy;
+
+ SCIC_LOG_TRACE((
+ sci_base_object_get_logger(this_phy),
+ SCIC_LOG_OBJECT_PHY,
+ "scic_phy_clear_counter(0x%x, 0x%x) enter\n",
+ this_phy, counter_id
+ ));
+
+ switch(counter_id)
+ {
+ case SCIC_PHY_COUNTER_RECEIVED_FRAME:
+ scu_link_layer_register_write(this_phy, received_frame_count, 0);
+ break;
+ case SCIC_PHY_COUNTER_TRANSMITTED_FRAME:
+ scu_link_layer_register_write(this_phy, transmit_frame_count, 0);
+ break;
+ case SCIC_PHY_COUNTER_RECEIVED_FRAME_DWORD:
+ scu_link_layer_register_write(this_phy, received_dword_count, 0);
+ break;
+ case SCIC_PHY_COUNTER_TRANSMITTED_FRAME_DWORD:
+ scu_link_layer_register_write(this_phy, transmit_dword_count, 0);
+ break;
+ case SCIC_PHY_COUNTER_LOSS_OF_SYNC_ERROR:
+ scu_link_layer_register_write(this_phy, loss_of_sync_error_count, 0);
+ break;
+ case SCIC_PHY_COUNTER_RECEIVED_DISPARITY_ERROR:
+ scu_link_layer_register_write(this_phy, running_disparity_error_count, 0);
+ break;
+ case SCIC_PHY_COUNTER_RECEIVED_FRAME_CRC_ERROR:
+ scu_link_layer_register_write(this_phy, received_frame_crc_error_count, 0);
+ break;
+ case SCIC_PHY_COUNTER_RECEIVED_DONE_ACK_NAK_TIMEOUT:
+ this_phy->error_counter[SCU_ERR_CNT_RX_DONE_ACK_NAK_TIMEOUT_INDEX] = 0;
+ break;
+ case SCIC_PHY_COUNTER_TRANSMITTED_DONE_ACK_NAK_TIMEOUT:
+ this_phy->error_counter[SCU_ERR_CNT_TX_DONE_ACK_NAK_TIMEOUT_INDEX] = 0;
+ break;
+ case SCIC_PHY_COUNTER_INACTIVITY_TIMER_EXPIRED:
+ this_phy->error_counter[SCU_ERR_CNT_INACTIVITY_TIMER_EXPIRED_INDEX] = 0;
+ break;
+ case SCIC_PHY_COUNTER_RECEIVED_DONE_CREDIT_TIMEOUT:
+ this_phy->error_counter[SCU_ERR_CNT_RX_DONE_CREDIT_TIMEOUT_INDEX] = 0;
+ break;
+ case SCIC_PHY_COUNTER_TRANSMITTED_DONE_CREDIT_TIMEOUT:
+ this_phy->error_counter[SCU_ERR_CNT_TX_DONE_CREDIT_TIMEOUT_INDEX] = 0;
+ break;
+ case SCIC_PHY_COUNTER_RECEIVED_CREDIT_BLOCKED:
+ this_phy->error_counter[SCU_ERR_CNT_RX_CREDIT_BLOCKED_RECEIVED_INDEX] = 0;
+ break;
+ case SCIC_PHY_COUNTER_RECEIVED_SHORT_FRAME:
+ scu_link_layer_register_write(this_phy, received_short_frame_count, 0);
+ break;
+ case SCIC_PHY_COUNTER_RECEIVED_FRAME_WITHOUT_CREDIT:
+ scu_link_layer_register_write(this_phy, received_frame_without_credit_count, 0);
+ break;
+ case SCIC_PHY_COUNTER_RECEIVED_FRAME_AFTER_DONE:
+ scu_link_layer_register_write(this_phy, received_frame_after_done_count, 0);
+ break;
+ case SCIC_PHY_COUNTER_SN_DWORD_SYNC_ERROR:
+ scu_link_layer_register_write(this_phy, phy_reset_problem_count, 0);
+ break;
+ default:
+ status = SCI_FAILURE;
+ }
+
+ return status;
+}
+
+#endif // !defined(DISABLE_PHY_COUNTERS)
+
+SCI_STATUS scic_phy_stop(
+ SCI_PHY_HANDLE_T phy
+)
+{
+ SCIC_SDS_PHY_T *this_phy;
+ this_phy = (SCIC_SDS_PHY_T *)phy;
+
+ SCIC_LOG_TRACE((
+ sci_base_object_get_logger(this_phy),
+ SCIC_LOG_OBJECT_PHY,
+ "scic_phy_stop(this_phy:0x%x)\n",
+ this_phy
+ ));
+
+ return this_phy->state_handlers->parent.stop_handler(&this_phy->parent);
+}
+
+SCI_STATUS scic_phy_start(
+ SCI_PHY_HANDLE_T phy
+)
+{
+ SCIC_SDS_PHY_T *this_phy;
+ this_phy = (SCIC_SDS_PHY_T *)phy;
+
+ SCIC_LOG_TRACE((
+ sci_base_object_get_logger(this_phy),
+ SCIC_LOG_OBJECT_PHY,
+ "scic_phy_start(this_phy:0x%x)\n",
+ this_phy
+ ));
+
+ return this_phy->state_handlers->parent.start_handler(&this_phy->parent);
+}
+
+//******************************************************************************
+//* PHY STATE MACHINE
+//******************************************************************************
+
+//***************************************************************************
+//* DEFAULT HANDLERS
+//***************************************************************************
+
+/**
+ * This is the default method for phy a start request. It will report a
+ * warning and exit.
+ *
+ * @param[in] phy This is the SCI_BASE_PHY object which is cast into a
+ * SCIC_SDS_PHY object.
+ *
+ * @return SCI_STATUS
+ * @retval SCI_FAILURE_INVALID_STATE
+ */
+SCI_STATUS scic_sds_phy_default_start_handler(
+ SCI_BASE_PHY_T *phy
+)
+{
+ SCIC_SDS_PHY_T *this_phy;
+ this_phy = (SCIC_SDS_PHY_T *)phy;
+
+ SCIC_LOG_WARNING((
+ sci_base_object_get_logger(this_phy),
+ SCIC_LOG_OBJECT_PHY,
+ "SCIC Phy 0x%08x requested to start from invalid state %d\n",
+ this_phy,
+ sci_base_state_machine_get_state(&this_phy->parent.state_machine)
+ ));
+
+ return SCI_FAILURE_INVALID_STATE;
+
+}
+
+/**
+ * This is the default method for phy a stop request. It will report a
+ * warning and exit.
+ *
+ * @param[in] phy This is the SCI_BASE_PHY object which is cast into a
+ * SCIC_SDS_PHY object.
+ *
+ * @return SCI_STATUS
+ * @retval SCI_FAILURE_INVALID_STATE
+ */
+SCI_STATUS scic_sds_phy_default_stop_handler(
+ SCI_BASE_PHY_T *phy
+)
+{
+ SCIC_SDS_PHY_T *this_phy;
+ this_phy = (SCIC_SDS_PHY_T *)phy;
+
+ SCIC_LOG_WARNING((
+ sci_base_object_get_logger(this_phy),
+ SCIC_LOG_OBJECT_PHY,
+ "SCIC Phy 0x%08x requested to stop from invalid state %d\n",
+ this_phy,
+ sci_base_state_machine_get_state(&this_phy->parent.state_machine)
+ ));
+
+ return SCI_FAILURE_INVALID_STATE;
+}
+
+/**
+ * This is the default method for phy a reset request. It will report a
+ * warning and exit.
+ *
+ * @param[in] phy This is the SCI_BASE_PHY object which is cast into a
+ * SCIC_SDS_PHY object.
+ *
+ * @return SCI_STATUS
+ * @retval SCI_FAILURE_INVALID_STATE
+ */
+SCI_STATUS scic_sds_phy_default_reset_handler(
+ SCI_BASE_PHY_T * phy
+)
+{
+ SCIC_SDS_PHY_T *this_phy;
+ this_phy = (SCIC_SDS_PHY_T *)phy;
+
+ SCIC_LOG_WARNING((
+ sci_base_object_get_logger(this_phy),
+ SCIC_LOG_OBJECT_PHY,
+ "SCIC Phy 0x%08x requested to reset from invalid state %d\n",
+ this_phy,
+ sci_base_state_machine_get_state(&this_phy->parent.state_machine)
+ ));
+
+ return SCI_FAILURE_INVALID_STATE;
+}
+
+/**
+ * This is the default method for phy a destruct request. It will report a
+ * warning and exit.
+ *
+ * @param[in] phy This is the SCI_BASE_PHY object which is cast into a
+ * SCIC_SDS_PHY object.
+ *
+ * @return SCI_STATUS
+ * @retval SCI_FAILURE_INVALID_STATE
+ */
+SCI_STATUS scic_sds_phy_default_destroy_handler(
+ SCI_BASE_PHY_T *phy
+)
+{
+ SCIC_SDS_PHY_T *this_phy;
+ this_phy = (SCIC_SDS_PHY_T *)phy;
+
+ /// @todo Implement something for the default
+ SCIC_LOG_WARNING((
+ sci_base_object_get_logger(this_phy),
+ SCIC_LOG_OBJECT_PHY,
+ "SCIC Phy 0x%08x requested to destroy from invalid state %d\n",
+ this_phy,
+ sci_base_state_machine_get_state(&this_phy->parent.state_machine)
+ ));
+
+ return SCI_FAILURE_INVALID_STATE;
+}
+
+/**
+ * This is the default method for a phy frame handling request. It will
+ * report a warning, release the frame and exit.
+ *
+ * @param[in] phy This is the SCI_BASE_PHY object which is cast into a
+ * SCIC_SDS_PHY object.
+ * @param[in] frame_index This is the frame index that was received from the
+ * SCU hardware.
+ *
+ * @return SCI_STATUS
+ * @retval SCI_FAILURE_INVALID_STATE
+ */
+SCI_STATUS scic_sds_phy_default_frame_handler(
+ SCIC_SDS_PHY_T *this_phy,
+ U32 frame_index
+)
+{
+ SCIC_LOG_WARNING((
+ sci_base_object_get_logger(this_phy),
+ SCIC_LOG_OBJECT_PHY,
+ "SCIC Phy 0x%08x recieved unexpected frame data %d while in state %d\n",
+ 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;
+}
+
+/**
+ * This is the default method for a phy event handler. It will report a
+ * warning and exit.
+ *
+ * @param[in] phy This is the SCI_BASE_PHY object which is cast into a
+ * SCIC_SDS_PHY object.
+ * @param[in] event_code This is the event code that was received from the SCU
+ * hardware.
+ *
+ * @return SCI_STATUS
+ * @retval SCI_FAILURE_INVALID_STATE
+ */
+SCI_STATUS scic_sds_phy_default_event_handler(
+ SCIC_SDS_PHY_T *this_phy,
+ U32 event_code
+)
+{
+ SCIC_LOG_WARNING((
+ sci_base_object_get_logger(this_phy),
+ SCIC_LOG_OBJECT_PHY,
+ "SCIC Phy 0x%08x received unexpected event status %x while in state %d\n",
+ this_phy, event_code,
+ sci_base_state_machine_get_state(&this_phy->parent.state_machine)
+ ));
+
+ return SCI_FAILURE_INVALID_STATE;
+}
+
+/**
+ * This is the default method for a phy consume power handler. It will report
+ * a warning and exit.
+ *
+ * @param[in] phy This is the SCI_BASE_PHY object which is cast into a
+ * SCIC_SDS_PHY object.
+ *
+ * @return SCI_STATUS
+ * @retval SCI_FAILURE_INVALID_STATE
+ */
+SCI_STATUS scic_sds_phy_default_consume_power_handler(
+ SCIC_SDS_PHY_T *this_phy
+)
+{
+ SCIC_LOG_WARNING((
+ sci_base_object_get_logger(this_phy),
+ SCIC_LOG_OBJECT_PHY,
+ "SCIC Phy 0x%08x given unexpected permission to consume power while in state %d\n",
+ this_phy,
+ sci_base_state_machine_get_state(&this_phy->parent.state_machine)
+ ));
+
+ return SCI_FAILURE_INVALID_STATE;
+}
+
+//******************************************************************************
+//* PHY STOPPED STATE HANDLERS
+//******************************************************************************
+
+/**
+ * This method takes the 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.
+ *
+ * @param[in] phy This is the SCI_BASE_PHY object which is cast into a
+ * SCIC_SDS_PHY object.
+ *
+ * @return SCI_STATUS
+ * @retval SCI_SUCCESS
+ */
+static
+SCI_STATUS scic_sds_phy_stopped_state_start_handler(
+ SCI_BASE_PHY_T *phy
+)
+{
+ SCIC_SDS_PHY_T *this_phy;
+ this_phy = (SCIC_SDS_PHY_T *)phy;
+
+
+
+ // Create the SIGNATURE FIS Timeout timer for this phy
+ this_phy->sata_timeout_timer = scic_cb_timer_create(
+ scic_sds_phy_get_controller(this_phy),
+ scic_sds_phy_sata_timeout,
+ this_phy
+ );
+
+ if (this_phy->sata_timeout_timer != NULL)
+ {
+ sci_base_state_machine_change_state(
+ scic_sds_phy_get_base_state_machine(this_phy),
+ SCI_BASE_PHY_STATE_STARTING
+ );
+ }
+
+ return SCI_SUCCESS;
+}
+
+/**
+ * This method takes the SCIC_SDS_PHY from a stopped state and destroys it.
+ * - This function takes no action.
+ *
+ * @todo Shouldnt this function transition the SCI_BASE_PHY::state_machine to
+ * the SCI_BASE_PHY_STATE_FINAL?
+ *
+ * @param[in] phy This is the SCI_BASE_PHY object which is cast into a
+ * SCIC_SDS_PHY object.
+ *
+ * @return SCI_STATUS
+ * @retval SCI_SUCCESS
+ */
+static
+SCI_STATUS scic_sds_phy_stopped_state_destroy_handler(
+ SCI_BASE_PHY_T *phy
+)
+{
+ SCIC_SDS_PHY_T *this_phy;
+ this_phy = (SCIC_SDS_PHY_T *)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
+//******************************************************************************
+
+/**
+ * This method takes the 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.
+ *
+ * @param[in] phy This is the SCI_BASE_PHY object which is cast into a
+ * SCIC_SDS_PHY object.
+ *
+ * @return SCI_STATUS
+ * @retval SCI_SUCCESS
+ */
+static
+SCI_STATUS scic_sds_phy_ready_state_stop_handler(
+ SCI_BASE_PHY_T *phy
+)
+{
+ SCIC_SDS_PHY_T *this_phy;
+ this_phy = (SCIC_SDS_PHY_T *)phy;
+
+ sci_base_state_machine_change_state(
+ scic_sds_phy_get_base_state_machine(this_phy),
+ SCI_BASE_PHY_STATE_STOPPED
+ );
+
+ scic_sds_controller_link_down(
+ scic_sds_phy_get_controller(this_phy),
+ scic_sds_phy_get_port(this_phy),
+ this_phy
+ );
+
+ return SCI_SUCCESS;
+}
+
+/**
+ * This method takes the 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.
+ *
+ * @param[in] phy This is the SCI_BASE_PHY object which is cast into a
+ * SCIC_SDS_PHY object.
+ *
+ * @return SCI_STATUS
+ * @retval SCI_SUCCESS
+ */
+static
+SCI_STATUS scic_sds_phy_ready_state_reset_handler(
+ SCI_BASE_PHY_T * phy
+)
+{
+ SCIC_SDS_PHY_T * this_phy;
+ this_phy = (SCIC_SDS_PHY_T *)phy;
+
+ sci_base_state_machine_change_state(
+ scic_sds_phy_get_base_state_machine(this_phy),
+ SCI_BASE_PHY_STATE_RESETTING
+ );
+
+ return SCI_SUCCESS;
+}
+
+/**
+ * This method request the 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 SCIC_SDS_PHY back to the SCI_BASE_PHY_STATE_STARTING
+ * state.
+ * - any other event recived will report a warning message
+ *
+ * @param[in] phy This is the SCIC_SDS_PHY object which has received the
+ * event.
+ *
+ * @return SCI_STATUS
+ * @retval SCI_SUCCESS if the event received is a link failure
+ * @retval SCI_FAILURE_INVALID_STATE for any other event received.
+ */
+static
+SCI_STATUS scic_sds_phy_ready_state_event_handler(
+ SCIC_SDS_PHY_T *this_phy,
+ U32 event_code
+)
+{
+ 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;
+
+ case SCU_EVENT_ERR_CNT(RX_CREDIT_BLOCKED_RECEIVED):
+ case SCU_EVENT_ERR_CNT(TX_DONE_CREDIT_TIMEOUT):
+ case SCU_EVENT_ERR_CNT(RX_DONE_CREDIT_TIMEOUT):
+ case SCU_EVENT_ERR_CNT(INACTIVITY_TIMER_EXPIRED):
+ case SCU_EVENT_ERR_CNT(TX_DONE_ACK_NAK_TIMEOUT):
+ case SCU_EVENT_ERR_CNT(RX_DONE_ACK_NAK_TIMEOUT):
+ {
+ U32 error_counter_index =
+ scu_get_event_specifier(event_code) >> SCU_EVENT_SPECIFIC_CODE_SHIFT;
+
+ this_phy->error_counter[error_counter_index]++;
+ result = SCI_SUCCESS;
+ }
+ break;
+
+ default:
+ SCIC_LOG_WARNING((
+ sci_base_object_get_logger(this_phy),
+ SCIC_LOG_OBJECT_PHY | SCIC_LOG_OBJECT_RECEIVED_EVENTS,
+ "SCIC PHY 0x%x ready state machine recieved unexpected event_code %x\n",
+ this_phy, event_code
+ ));
+ result = SCI_FAILURE_INVALID_STATE;
+ break;
+ }
+
+ return result;
+}
+
+// ---------------------------------------------------------------------------
+
+/**
+ * This is the resetting state event handler.
+ *
+ * @param[in] this_phy This is the SCIC_SDS_PHY object which is receiving the
+ * event.
+ * @param[in] event_code This is the event code to be processed.
+ *
+ * @return SCI_STATUS
+ * @retval SCI_FAILURE_INVALID_STATE
+ */
+static
+SCI_STATUS scic_sds_phy_resetting_state_event_handler(
+ SCIC_SDS_PHY_T *this_phy,
+ U32 event_code
+)
+{
+ 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:
+ SCIC_LOG_WARNING((
+ sci_base_object_get_logger(this_phy),
+ SCIC_LOG_OBJECT_PHY | SCIC_LOG_OBJECT_RECEIVED_EVENTS,
+ "SCIC PHY 0x%x resetting state machine recieved unexpected event_code %x\n",
+ this_phy, event_code
+ ));
+
+ result = SCI_FAILURE_INVALID_STATE;
+ break;
+ }
+
+ return result;
+}
+
+// ---------------------------------------------------------------------------
+
+SCIC_SDS_PHY_STATE_HANDLER_T
+ 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 method will stop the 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.
+ *
+ * @param[in] this_phy This is the SCIC_SDS_PHY object to stop.
+ *
+ * @return none
+ */
+static
+void scu_link_layer_stop_protocol_engine(
+ SCIC_SDS_PHY_T *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 SCIC_SDS_PHY
+ * object.
+ *
+ * @param[in] this_phy This is the SCIC_SDS_PHY object on which to start the
+ * OOB/SN state machine.
+ */
+static
+void scu_link_layer_start_oob(
+ SCIC_SDS_PHY_T *this_phy
+)
+{
+ U32 scu_sas_pcfg_value;
+
+ /* Reset OOB sequence - start */
+ 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(HARD_RESET));
+ SCU_SAS_PCFG_WRITE(this_phy, scu_sas_pcfg_value);
+ SCU_SAS_PCFG_READ(this_phy);
+ /* Reset OOB sequence - end */
+
+ /* Start OOB sequence - start */
+ scu_sas_pcfg_value = SCU_SAS_PCFG_READ(this_phy);
+ scu_sas_pcfg_value |= SCU_SAS_PCFG_GEN_BIT(OOB_ENABLE);
+ SCU_SAS_PCFG_WRITE(this_phy, scu_sas_pcfg_value);
+ SCU_SAS_PCFG_READ(this_phy);
+ /* Start OOB sequence - end */
+}
+
+/**
+ * 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.
+ *
+ * @param[in] this_phy
+ */
+static
+void scu_link_layer_tx_hard_reset(
+ SCIC_SDS_PHY_T *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
+//****************************************************************************
+
+/**
+ * This method will perform the actions required by the 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.
+ *
+ * @param[in] object This is the SCI_BASE_OBJECT which is cast to a
+ * SCIC_SDS_PHY object.
+ *
+ * @return none
+ */
+static
+void scic_sds_phy_initial_state_enter(
+ SCI_BASE_OBJECT_T *object
+)
+{
+ SCIC_SDS_PHY_T *this_phy;
+ this_phy = (SCIC_SDS_PHY_T *)object;
+
+ scic_sds_phy_set_base_state_handlers(this_phy, SCI_BASE_PHY_STATE_INITIAL);
+}
+
+/**
+ * This method will perform the actions required by the 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.
+ *
+ * @param[in] object This is the SCI_BASE_OBJECT which is cast to a
+ * SCIC_SDS_PHY object.
+ *
+ * @return none
+ */
+static
+void scic_sds_phy_stopped_state_enter(
+ SCI_BASE_OBJECT_T *object
+)
+{
+ SCIC_SDS_PHY_T *this_phy;
+ this_phy = (SCIC_SDS_PHY_T *)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);
+
+ if (this_phy->sata_timeout_timer != NULL)
+ {
+ scic_cb_timer_destroy(
+ scic_sds_phy_get_controller(this_phy),
+ this_phy->sata_timeout_timer
+ );
+
+ this_phy->sata_timeout_timer = NULL;
+ }
+
+ scu_link_layer_stop_protocol_engine(this_phy);
+}
+
+/**
+ * This method will perform the actions required by the 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
+ * SCIC_SDS_CONTROLLER is informed that the phy has gone link down.
+ *
+ * @param[in] object This is the SCI_BASE_OBJECT which is cast to a
+ * SCIC_SDS_PHY object.
+ *
+ * @return none
+ */
+static
+void scic_sds_phy_starting_state_enter(
+ SCI_BASE_OBJECT_T *object
+)
+{
+ SCIC_SDS_PHY_T *this_phy;
+ this_phy = (SCIC_SDS_PHY_T *)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
+ );
+ }
+}
+
+/**
+ * This method will perform the actions required by the 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 SCIC_SDS_CONTROLLER is informed that the phy object has gone link
+ * up.
+ *
+ * @param[in] object This is the SCI_BASE_OBJECT which is cast to a
+ * SCIC_SDS_PHY object.
+ *
+ * @return none
+ */
+static
+void scic_sds_phy_ready_state_enter(
+ SCI_BASE_OBJECT_T *object
+)
+{
+ SCIC_SDS_PHY_T *this_phy;
+ this_phy = (SCIC_SDS_PHY_T *)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
+ );
+}
+
+/**
+ * This method will perform the actions required by the SCIC_SDS_PHY on
+ * exiting the SCI_BASE_PHY_STATE_INITIAL. This function suspends the SCU
+ * hardware protocol engine represented by this SCIC_SDS_PHY object.
+ *
+ * @param[in] object This is the SCI_BASE_OBJECT which is cast to a
+ * SCIC_SDS_PHY object.
+ *
+ * @return none
+ */
+static
+void scic_sds_phy_ready_state_exit(
+ SCI_BASE_OBJECT_T *object
+)
+{
+ SCIC_SDS_PHY_T *this_phy;
+ this_phy = (SCIC_SDS_PHY_T *)object;
+
+ scic_sds_phy_suspend(this_phy);
+}
+
+/**
+ * This method will perform the actions required by the 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.
+ *
+ * @param[in] object This is the SCI_BASE_OBJECT which is cast to a
+ * SCIC_SDS_PHY object.
+ *
+ * @return none
+ */
+static
+void scic_sds_phy_resetting_state_enter(
+ SCI_BASE_OBJECT_T *object
+)
+{
+ SCIC_SDS_PHY_T * this_phy;
+ this_phy = (SCIC_SDS_PHY_T *)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
+ );
+ }
+}
+
+/**
+ * This method will perform the actions required by the 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.
+ *
+ * @param[in] object This is the SCI_BASE_OBJECT which is cast to a
+ * SCIC_SDS_PHY object.
+ *
+ * @return none
+ */
+static
+void scic_sds_phy_final_state_enter(
+ SCI_BASE_OBJECT_T *object
+)
+{
+ SCIC_SDS_PHY_T *this_phy;
+ this_phy = (SCIC_SDS_PHY_T *)object;
+
+ scic_sds_phy_set_base_state_handlers(this_phy, SCI_BASE_PHY_STATE_FINAL);
+
+ // Nothing to do here
+}
+
+// ---------------------------------------------------------------------------
+
+SCI_BASE_STATE_T scic_sds_phy_state_table[SCI_BASE_PHY_MAX_STATES] =
+{
+ {
+ SCI_BASE_PHY_STATE_INITIAL,
+ scic_sds_phy_initial_state_enter,
+ NULL,
+ },
+ {
+ SCI_BASE_PHY_STATE_STOPPED,
+ scic_sds_phy_stopped_state_enter,
+ NULL,
+ },
+ {
+ SCI_BASE_PHY_STATE_STARTING,
+ scic_sds_phy_starting_state_enter,
+ NULL,
+ },
+ {
+ SCI_BASE_PHY_STATE_READY,
+ scic_sds_phy_ready_state_enter,
+ scic_sds_phy_ready_state_exit,
+ },
+ {
+ SCI_BASE_PHY_STATE_RESETTING,
+ scic_sds_phy_resetting_state_enter,
+ NULL,
+ },
+ {
+ SCI_BASE_PHY_STATE_FINAL,
+ scic_sds_phy_final_state_enter,
+ NULL,
+ }
+};
+
+//******************************************************************************
+//* PHY STARTING SUB-STATE MACHINE
+//******************************************************************************
+
+//*****************************************************************************
+//* SCIC SDS PHY HELPER FUNCTIONS
+//*****************************************************************************
+
+
+/**
+ * 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.
+ *
+ * @param[in] this_phy The phy object that received SAS PHY DETECTED.
+ *
+ * @return none
+ */
+static
+void scic_sds_phy_start_sas_link_training(
+ SCIC_SDS_PHY_T * 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 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.
+ *
+ * @param[in] this_phy The phy object that received a SATA SPINUP HOLD event
+ *
+ * @return none
+ */
+static
+void scic_sds_phy_start_sata_link_training(
+ SCIC_SDS_PHY_T * 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;
+}
+
+/**
+ * @brief This method performs processing common to all protocols upon
+ * completion of link training.
+ *
+ * @param[in,out] this_phy This parameter specifies the phy object for which
+ * link training has completed.
+ * @param[in] max_link_rate This parameter specifies the maximum link
+ * rate to be associated with this phy.
+ * @param[in] next_state This parameter specifies the next state for the
+ * phy's starting sub-state machine.
+ *
+ * @return none
+ */
+static
+void scic_sds_phy_complete_link_training(
+ SCIC_SDS_PHY_T * this_phy,
+ 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 method restarts the SCIC_SDS_PHY objects base state machine in the
+ * starting state from any starting substate.
+ *
+ * @param[in] this_phy The SCIC_SDS_PHY object to restart.
+ *
+ * @return none
+ */
+void scic_sds_phy_restart_starting_state(
+ SCIC_SDS_PHY_T *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 general handlers
+//*****************************************************************************
+
+static
+SCI_STATUS scic_sds_phy_starting_substate_general_stop_handler(
+ SCI_BASE_PHY_T *phy
+)
+{
+ SCIC_SDS_PHY_T *this_phy;
+ this_phy = (SCIC_SDS_PHY_T *)phy;
+
+ sci_base_state_machine_stop(
+ &this_phy->starting_substate_machine
+ );
+
+ sci_base_state_machine_change_state(
+ &phy->state_machine,
+ SCI_BASE_PHY_STATE_STOPPED
+ );
+
+ return SCI_SUCCESS;
+}
+
+//*****************************************************************************
+//* SCIC SDS PHY EVENT_HANDLERS
+//*****************************************************************************
+
+/**
+ * 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
+ *
+ * @param[in] phy This SCIC_SDS_PHY object which has received an event.
+ * @param[in] event_code This is the event code which the phy object is to
+ * decode.
+ *
+ * @return SCI_STATUS
+ * @retval SCI_SUCCESS on any valid event notification
+ * @retval SCI_FAILURE on any unexpected event notifation
+ */
+static
+SCI_STATUS scic_sds_phy_starting_substate_await_ossp_event_handler(
+ SCIC_SDS_PHY_T *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:
+ SCIC_LOG_WARNING((
+ sci_base_object_get_logger(this_phy),
+ SCIC_LOG_OBJECT_PHY | SCIC_LOG_OBJECT_RECEIVED_EVENTS,
+ "PHY starting substate machine recieved unexpected event_code %x\n",
+ event_code
+ ));
+
+ result = SCI_FAILURE;
+ break;
+ }
+
+ return result;
+}
+
+/**
+ * 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
+ *
+ * @param[in] phy This SCIC_SDS_PHY object which has received an event.
+ * @param[in] event_code This is the event code which the phy object is to
+ * decode.
+ *
+ * @return SCI_STATUS
+ * @retval SCI_SUCCESS on any valid event notification
+ * @retval SCI_FAILURE on any unexpected event notifation
+ */
+static
+SCI_STATUS scic_sds_phy_starting_substate_await_sas_phy_speed_event_handler(
+ SCIC_SDS_PHY_T *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:
+ SCIC_LOG_WARNING((
+ sci_base_object_get_logger(this_phy),
+ SCIC_LOG_OBJECT_PHY | SCIC_LOG_OBJECT_RECEIVED_EVENTS,
+ "PHY starting substate machine recieved unexpected event_code %x\n",
+ event_code
+ ));
+
+ result = SCI_FAILURE;
+ break;
+ }
+
+ return result;
+}
+
+/**
+ * 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
+ *
+ * @param[in] phy This SCIC_SDS_PHY object which has received an event.
+ * @param[in] event_code This is the event code which the phy object is to
+ * decode.
+ *
+ * @return SCI_STATUS
+ * @retval SCI_SUCCESS on any valid event notification
+ * @retval SCI_FAILURE on any unexpected event notifation
+ */
+static
+SCI_STATUS scic_sds_phy_starting_substate_await_iaf_uf_event_handler(
+ SCIC_SDS_PHY_T *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:
+ SCIC_LOG_WARNING((
+ sci_base_object_get_logger(this_phy),
+ SCIC_LOG_OBJECT_PHY | SCIC_LOG_OBJECT_RECEIVED_EVENTS,
+ "PHY starting substate machine recieved unexpected event_code %x\n",
+ event_code
+ ));
+
+ result = SCI_FAILURE;
+ break;
+ }
+
+ return result;
+}
+
+/**
+ * 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
+ *
+ * @param[in] phy This SCIC_SDS_PHY object which has received an event.
+ * @param[in] event_code This is the event code which the phy object is to
+ * decode.
+ *
+ * @return SCI_STATUS
+ * @retval SCI_SUCCESS on a link failure event
+ * @retval SCI_FAILURE on any unexpected event notifation
+ */
+static
+SCI_STATUS scic_sds_phy_starting_substate_await_sas_power_event_handler(
+ SCIC_SDS_PHY_T *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:
+ SCIC_LOG_WARNING((
+ sci_base_object_get_logger(this_phy),
+ SCIC_LOG_OBJECT_PHY | SCIC_LOG_OBJECT_RECEIVED_EVENTS,
+ "PHY starting substate machine recieved unexpected event_code %x\n",
+ event_code
+ ));
+
+ result = SCI_FAILURE;
+ break;
+ }
+
+ return result;
+}
+
+/**
+ * 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
+ *
+ * @param[in] phy This SCIC_SDS_PHY object which has received an event.
+ * @param[in] event_code This is the event code which the phy object is to
+ * decode.
+ *
+ * @return SCI_STATUS
+ * @retval SCI_SUCCESS on a link failure event
+ * @retval SCI_FAILURE on any unexpected event notifation
+ */
+static
+SCI_STATUS scic_sds_phy_starting_substate_await_sata_power_event_handler(
+ SCIC_SDS_PHY_T *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:
+ SCIC_LOG_WARNING((
+ sci_base_object_get_logger(this_phy),
+ SCIC_LOG_OBJECT_PHY | SCIC_LOG_OBJECT_RECEIVED_EVENTS,
+ "PHY starting substate machine recieved unexpected event_code %x\n",
+ event_code
+ ));
+
+ result = SCI_FAILURE;
+ break;
+ }
+
+ return result;
+}
+
+/**
+ * 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
+ *
+ * @param[in] phy This SCIC_SDS_PHY object which has received an event.
+ * @param[in] event_code This is the event code which the phy object is to
+ * decode.
+ *
+ * @return SCI_STATUS
+ * @retval SCI_SUCCESS on a link failure event
+ * @retval SCI_FAILURE on any unexpected event notifation
+ */
+static
+SCI_STATUS scic_sds_phy_starting_substate_await_sata_phy_event_handler(
+ SCIC_SDS_PHY_T *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:
+ SCIC_LOG_WARNING((
+ sci_base_object_get_logger(this_phy),
+ SCIC_LOG_OBJECT_PHY | SCIC_LOG_OBJECT_RECEIVED_EVENTS,
+ "PHY starting substate machine recieved unexpected event_code %x\n",
+ event_code
+ ));
+
+ result = SCI_FAILURE;
+ break;
+ }
+
+ return result;
+}
+
+/**
+ * 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
+ *
+ * @param[in] phy This SCIC_SDS_PHY object which has received an event.
+ * @param[in] event_code This is the event code which the phy object is to
+ * decode.
+ *
+ * @return SCI_STATUS
+ * @retval SCI_SUCCESS on any valid event notification
+ * @retval SCI_FAILURE on any unexpected event notifation
+ */
+static
+SCI_STATUS scic_sds_phy_starting_substate_await_sata_speed_event_handler(
+ SCIC_SDS_PHY_T *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:
+ SCIC_LOG_WARNING((
+ sci_base_object_get_logger(this_phy),
+ SCIC_LOG_OBJECT_PHY | SCIC_LOG_OBJECT_RECEIVED_EVENTS,
+ "PHY starting substate machine recieved unexpected event_code %x\n",
+ event_code
+ ));
+
+ result = SCI_FAILURE;
+ break;
+ }
+
+ return result;
+}
+
+/**
+ * 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
+ *
+ * @param[in] phy This SCIC_SDS_PHY object which has received an event.
+ * @param[in] event_code This is the event code which the phy object is to
+ * decode.
+ *
+ * @return SCI_STATUS
+ * @retval SCI_SUCCESS on any valid event notification
+ * @retval SCI_FAILURE on any unexpected event notifation
+ */
+static
+SCI_STATUS scic_sds_phy_starting_substate_await_sig_fis_event_handler(
+ SCIC_SDS_PHY_T *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:
+ SCIC_LOG_WARNING((
+ sci_base_object_get_logger(this_phy),
+ SCIC_LOG_OBJECT_PHY | SCIC_LOG_OBJECT_RECEIVED_EVENTS,
+ "PHY starting substate machine recieved unexpected event_code %x\n",
+ event_code
+ ));
+
+ result = SCI_FAILURE;
+ break;
+ }
+
+ return result;
+}
+
+
+//*****************************************************************************
+//* SCIC SDS PHY FRAME_HANDLERS
+//*****************************************************************************
+
+/**
+ * This method decodes the unsolicited frame when the 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
+ *
+ * @param[in] phy This is SCIC_SDS_PHY object which is being requested to
+ * decode the frame data.
+ * @param[in] frame_index This is the index of the unsolicited frame which was
+ * received for this phy.
+ *
+ * @return SCI_STATUS
+ * @retval SCI_SUCCESS
+ */
+static
+SCI_STATUS scic_sds_phy_starting_substate_await_iaf_uf_frame_handler(
+ SCIC_SDS_PHY_T *this_phy,
+ U32 frame_index
+)
+{
+ SCI_STATUS result;
+ U32 *frame_words;
+ SCI_SAS_IDENTIFY_ADDRESS_FRAME_T *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 = (SCI_SAS_IDENTIFY_ADDRESS_FRAME_T *)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(SCI_SAS_IDENTIFY_ADDRESS_FRAME_T)
+ );
+
+ 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
+ {
+ SCIC_LOG_WARNING((
+ sci_base_object_get_logger(this_phy),
+ SCIC_LOG_OBJECT_PHY | SCIC_LOG_OBJECT_UNSOLICITED_FRAMES,
+ "PHY starting substate machine recieved unexpected frame id %x\n",
+ 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;
+}
+
+/**
+ * This method decodes the unsolicited frame when the 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
+ *
+ * @param[in] phy This is SCIC_SDS_PHY object which is being requested to
+ * decode the frame data.
+ * @param[in] frame_index This is the index of the unsolicited frame which was
+ * received for this phy.
+ *
+ * @return SCI_STATUS
+ * @retval SCI_SUCCESS
+ *
+ * @todo Must decode the SIGNATURE FIS data
+ */
+static
+SCI_STATUS scic_sds_phy_starting_substate_await_sig_fis_frame_handler(
+ SCIC_SDS_PHY_T *this_phy,
+ U32 frame_index
+)
+{
+ SCI_STATUS result;
+ U32 * frame_words;
+ SATA_FIS_HEADER_T * 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 = (SATA_FIS_HEADER_T *)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
+ {
+ SCIC_LOG_WARNING((
+ sci_base_object_get_logger(this_phy),
+ SCIC_LOG_OBJECT_PHY | SCIC_LOG_OBJECT_UNSOLICITED_FRAMES,
+ "PHY starting substate machine recieved unexpected frame id %x\n",
+ 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
+//*****************************************************************************
+
+/**
+ * This method is called by the 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.
+ *
+ * @param[in] phy This is the SCI_BASE_PHY object which is cast into a
+ * SCIC_SDS_PHY object.
+ *
+ * @return SCI_STATUS
+ * @retval SCI_SUCCESS
+ */
+static
+SCI_STATUS scic_sds_phy_starting_substate_await_sas_power_consume_power_handler(
+ SCIC_SDS_PHY_T *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;
+}
+
+/**
+ * This method is called by the 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.
+ *
+ * @param[in] phy This is the SCI_BASE_PHY object which is cast into a
+ * SCIC_SDS_PHY object.
+ *
+ * @return SCI_STATUS
+ * @retval SCI_SUCCESS
+ */
+static
+SCI_STATUS scic_sds_phy_starting_substate_await_sata_power_consume_power_handler(
+ SCIC_SDS_PHY_T *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;
+}
+
+// ---------------------------------------------------------------------------
+
+SCIC_SDS_PHY_STATE_HANDLER_T
+ 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_starting_substate_general_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_starting_substate_general_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_starting_substate_general_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_starting_substate_general_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_starting_substate_general_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_starting_substate_general_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_starting_substate_general_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_starting_substate_general_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_starting_substate_general_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
+ }
+};
+
+/**
+ * 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
+//****************************************************************************
+
+/**
+ * This method will perform the actions required by the SCIC_SDS_PHY on
+ * entering the SCIC_SDS_PHY_STARTING_SUBSTATE_INITIAL.
+ * - The initial state handlers are put in place for the SCIC_SDS_PHY
+ * object.
+ * - The state is changed to the wait phy type event notification.
+ *
+ * @param[in] object This is the SCI_BASE_OBJECT which is cast to a
+ * SCIC_SDS_PHY object.
+ *
+ * @return none
+ */
+static
+void scic_sds_phy_starting_initial_substate_enter(
+ SCI_BASE_OBJECT_T *object
+)
+{
+ SCIC_SDS_PHY_T *this_phy;
+ this_phy = (SCIC_SDS_PHY_T *)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
+ );
+}
+
+/**
+ * This method will perform the actions required by the SCIC_SDS_PHY on
+ * entering the SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_PHY_TYPE_EN.
+ * - Set the SCIC_SDS_PHY object state handlers for this state.
+ *
+ * @param[in] object This is the SCI_BASE_OBJECT which is cast to a
+ * SCIC_SDS_PHY object.
+ *
+ * @return none
+ */
+static
+void scic_sds_phy_starting_await_ossp_en_substate_enter(
+ SCI_BASE_OBJECT_T *object
+)
+{
+ SCIC_SDS_PHY_T *this_phy;
+ this_phy = (SCIC_SDS_PHY_T *)object;
+
+ scic_sds_phy_set_starting_substate_handlers(
+ this_phy, SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_OSSP_EN
+ );
+}
+
+/**
+ * This method will perform the actions required by the SCIC_SDS_PHY on
+ * entering the SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_SPEED_EN.
+ * - Set the SCIC_SDS_PHY object state handlers for this state.
+ *
+ * @param[in] object This is the SCI_BASE_OBJECT which is cast to a
+ * SCIC_SDS_PHY object.
+ *
+ * @return none
+ */
+static
+void scic_sds_phy_starting_await_sas_speed_en_substate_enter(
+ SCI_BASE_OBJECT_T *object
+)
+{
+ SCIC_SDS_PHY_T *this_phy;
+ this_phy = (SCIC_SDS_PHY_T *)object;
+
+ scic_sds_phy_set_starting_substate_handlers(
+ this_phy, SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_SAS_SPEED_EN
+ );
+}
+
+/**
+ * This method will perform the actions required by the SCIC_SDS_PHY on
+ * entering the SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_IAF_UF.
+ * - Set the SCIC_SDS_PHY object state handlers for this state.
+ *
+ * @param[in] object This is the SCI_BASE_OBJECT which is cast to a
+ * SCIC_SDS_PHY object.
+ *
+ * @return none
+ */
+static
+void scic_sds_phy_starting_await_iaf_uf_substate_enter(
+ SCI_BASE_OBJECT_T *object
+)
+{
+ SCIC_SDS_PHY_T *this_phy;
+ this_phy = (SCIC_SDS_PHY_T *)object;
+
+ scic_sds_phy_set_starting_substate_handlers(
+ this_phy, SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_IAF_UF
+ );
+}
+
+/**
+ * This method will perform the actions required by the SCIC_SDS_PHY on
+ * entering the SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_SAS_POWER.
+ * - Set the SCIC_SDS_PHY object state handlers for this state.
+ * - Add this phy object to the power control queue
+ *
+ * @param[in] object This is the SCI_BASE_OBJECT which is cast to a
+ * SCIC_SDS_PHY object.
+ *
+ * @return none
+ */
+static
+void scic_sds_phy_starting_await_sas_power_substate_enter(
+ SCI_BASE_OBJECT_T *object
+)
+{
+ SCIC_SDS_PHY_T *this_phy;
+ this_phy = (SCIC_SDS_PHY_T *)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
+ );
+}
+
+/**
+ * This method will perform the actions required by the SCIC_SDS_PHY on
+ * exiting the SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_SAS_POWER.
+ * - Remove the SCIC_SDS_PHY object from the power control queue.
+ *
+ * @param[in] object This is the SCI_BASE_OBJECT which is cast to a
+ * SCIC_SDS_PHY object.
+ *
+ * @return none
+ */
+static
+void scic_sds_phy_starting_await_sas_power_substate_exit(
+ SCI_BASE_OBJECT_T *object
+)
+{
+ SCIC_SDS_PHY_T *this_phy;
+ this_phy = (SCIC_SDS_PHY_T *)object;
+
+ scic_sds_controller_power_control_queue_remove(
+ scic_sds_phy_get_controller(this_phy), this_phy
+ );
+}
+
+/**
+ * This method will perform the actions required by the SCIC_SDS_PHY on
+ * entering the SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_SATA_POWER.
+ * - Set the SCIC_SDS_PHY object state handlers for this state.
+ * - Add this phy object to the power control queue
+ *
+ * @param[in] object This is the SCI_BASE_OBJECT which is cast to a
+ * SCIC_SDS_PHY object.
+ *
+ * @return none
+ */
+static
+void scic_sds_phy_starting_await_sata_power_substate_enter(
+ SCI_BASE_OBJECT_T *object
+)
+{
+ SCIC_SDS_PHY_T *this_phy;
+ this_phy = (SCIC_SDS_PHY_T *)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
+ );
+}
+
+/**
+ * This method will perform the actions required by the SCIC_SDS_PHY on
+ * exiting the SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_SATA_POWER.
+ * - Remove the SCIC_SDS_PHY object from the power control queue.
+ *
+ * @param[in] object This is the SCI_BASE_OBJECT which is cast to a
+ * SCIC_SDS_PHY object.
+ *
+ * @return none
+ */
+static
+void scic_sds_phy_starting_await_sata_power_substate_exit(
+ SCI_BASE_OBJECT_T *object
+)
+{
+ SCIC_SDS_PHY_T *this_phy;
+ this_phy = (SCIC_SDS_PHY_T *)object;
+
+ scic_sds_controller_power_control_queue_remove(
+ scic_sds_phy_get_controller(this_phy),
+ this_phy
+ );
+}
+
+/**
+ * This method will perform the actions required by the SCIC_SDS_PHY on
+ * entering the SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_SATA_PHY_EN.
+ * - Set the SCIC_SDS_PHY object state handlers for this state.
+ *
+ * @param[in] object This is the SCI_BASE_OBJECT which is cast to a
+ * SCIC_SDS_PHY object.
+ *
+ * @return none
+ */
+static
+void scic_sds_phy_starting_await_sata_phy_substate_enter(
+ SCI_BASE_OBJECT_T *object
+)
+{
+ SCIC_SDS_PHY_T *this_phy;
+ this_phy = (SCIC_SDS_PHY_T *)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
+ );
+}
+
+/**
+ * This method will perform the actions required by the 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
+ *
+ * @param[in] object This is the SCI_BASE_OBJECT which is cast to a
+ * SCIC_SDS_PHY object.
+ *
+ * @return none
+ */
+static
+void scic_sds_phy_starting_await_sata_phy_substate_exit(
+ SCI_BASE_OBJECT_T *object
+)
+{
+ SCIC_SDS_PHY_T *this_phy;
+ this_phy = (SCIC_SDS_PHY_T *)object;
+
+ scic_cb_timer_stop(
+ scic_sds_phy_get_controller(this_phy),
+ this_phy->sata_timeout_timer
+ );
+}
+
+/**
+ * This method will perform the actions required by the SCIC_SDS_PHY on
+ * entering the SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_SATA_SPEED_EN.
+ * - Set the SCIC_SDS_PHY object state handlers for this state.
+ *
+ * @param[in] object This is the SCI_BASE_OBJECT which is cast to a
+ * SCIC_SDS_PHY object.
+ *
+ * @return none
+ */
+static
+void scic_sds_phy_starting_await_sata_speed_substate_enter(
+ SCI_BASE_OBJECT_T *object
+)
+{
+ SCIC_SDS_PHY_T *this_phy;
+ this_phy = (SCIC_SDS_PHY_T *)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
+ );
+}
+
+/**
+ * This method will perform the actions required by the 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
+ *
+ * @param[in] object This is the SCI_BASE_OBJECT which is cast to a
+ * SCIC_SDS_PHY object.
+ *
+ * @return none
+ */
+static
+void scic_sds_phy_starting_await_sata_speed_substate_exit(
+ SCI_BASE_OBJECT_T *object
+)
+{
+ SCIC_SDS_PHY_T *this_phy;
+ this_phy = (SCIC_SDS_PHY_T *)object;
+
+ scic_cb_timer_stop(
+ scic_sds_phy_get_controller(this_phy),
+ this_phy->sata_timeout_timer
+ );
+}
+
+/**
+ * This method will perform the actions required by the SCIC_SDS_PHY on
+ * entering the SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_SIG_FIS_UF.
+ * - Set the SCIC_SDS_PHY object state handlers for this state.
+ * - Start the SIGNATURE FIS timeout timer
+ *
+ * @param[in] object This is the SCI_BASE_OBJECT which is cast to a
+ * SCIC_SDS_PHY object.
+ *
+ * @return none
+ */
+static
+void scic_sds_phy_starting_await_sig_fis_uf_substate_enter(
+ SCI_BASE_OBJECT_T *object
+)
+{
+ BOOL continue_to_ready_state;
+ SCIC_SDS_PHY_T * this_phy;
+
+ this_phy = (SCIC_SDS_PHY_T *)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;
+ }
+}
+
+/**
+ * This method will perform the actions required by the SCIC_SDS_PHY on
+ * exiting the SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_SIG_FIS_UF.
+ * - Stop the SIGNATURE FIS timeout timer.
+ *
+ * @param[in] object This is the SCI_BASE_OBJECT which is cast to a
+ * SCIC_SDS_PHY object.
+ *
+ * @return none
+ */
+static
+void scic_sds_phy_starting_await_sig_fis_uf_substate_exit(
+ SCI_BASE_OBJECT_T *object
+)
+{
+ SCIC_SDS_PHY_T *this_phy;
+ this_phy = (SCIC_SDS_PHY_T *)object;
+
+ scic_cb_timer_stop(
+ scic_sds_phy_get_controller(this_phy),
+ this_phy->sata_timeout_timer
+ );
+}
+
+/**
+ * This method will perform the actions required by the SCIC_SDS_PHY on
+ * entering the SCIC_SDS_PHY_STARTING_SUBSTATE_FINAL.
+ * - Set the SCIC_SDS_PHY object state handlers for this state.
+ * - Change base state machine to the ready state.
+ *
+ * @param[in] object This is the SCI_BASE_OBJECT which is cast to a
+ * SCIC_SDS_PHY object.
+ *
+ * @return none
+ */
+static
+void scic_sds_phy_starting_final_substate_enter(
+ SCI_BASE_OBJECT_T *object
+)
+{
+ SCIC_SDS_PHY_T *this_phy;
+ this_phy = (SCIC_SDS_PHY_T *)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);
+}
+
+// ---------------------------------------------------------------------------
+
+SCI_BASE_STATE_T
+ scic_sds_phy_starting_substates[SCIC_SDS_PHY_STARTING_MAX_SUBSTATES] =
+{
+ {
+ SCIC_SDS_PHY_STARTING_SUBSTATE_INITIAL,
+ scic_sds_phy_starting_initial_substate_enter,
+ NULL,
+ },
+ {
+ SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_OSSP_EN,
+ scic_sds_phy_starting_await_ossp_en_substate_enter,
+ NULL,
+ },
+ {
+ SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_SAS_SPEED_EN,
+ scic_sds_phy_starting_await_sas_speed_en_substate_enter,
+ NULL,
+ },
+ {
+ SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_IAF_UF,
+ scic_sds_phy_starting_await_iaf_uf_substate_enter,
+ NULL,
+ },
+ {
+ SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_SAS_POWER,
+ scic_sds_phy_starting_await_sas_power_substate_enter,
+ scic_sds_phy_starting_await_sas_power_substate_exit,
+ },
+ {
+ SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_SATA_POWER,
+ scic_sds_phy_starting_await_sata_power_substate_enter,
+ scic_sds_phy_starting_await_sata_power_substate_exit
+ },
+ {
+ SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_SATA_PHY_EN,
+ scic_sds_phy_starting_await_sata_phy_substate_enter,
+ scic_sds_phy_starting_await_sata_phy_substate_exit
+ },
+ {
+ SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_SATA_SPEED_EN,
+ scic_sds_phy_starting_await_sata_speed_substate_enter,
+ scic_sds_phy_starting_await_sata_speed_substate_exit
+ },
+ {
+ SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_SIG_FIS_UF,
+ scic_sds_phy_starting_await_sig_fis_uf_substate_enter,
+ scic_sds_phy_starting_await_sig_fis_uf_substate_exit
+ },
+ {
+ SCIC_SDS_PHY_STARTING_SUBSTATE_FINAL,
+ scic_sds_phy_starting_final_substate_enter,
+ NULL,
+ }
+};
+
diff --git a/sys/dev/isci/scil/scic_sds_phy.h b/sys/dev/isci/scil/scic_sds_phy.h
new file mode 100644
index 0000000..d8a3c73
--- /dev/null
+++ b/sys/dev/isci/scil/scic_sds_phy.h
@@ -0,0 +1,531 @@
+/*-
+ * 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.
+ *
+ * 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.
+ *
+ * $FreeBSD$
+ */
+#ifndef _SCIC_SDS_PHY_H_
+#define _SCIC_SDS_PHY_H_
+
+/**
+ * @file
+ *
+ * @brief This file contains the structures, constants and prototypes for the
+ * SCIC_SDS_PHY object.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif // __cplusplus
+
+#include <dev/isci/scil/intel_sata.h>
+#include <dev/isci/scil/intel_sas.h>
+#include <dev/isci/scil/sci_base_phy.h>
+#include <dev/isci/scil/scu_registers.h>
+#include <dev/isci/scil/scu_event_codes.h>
+
+/**
+ * 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
+ */
+typedef struct SCIC_SDS_PHY_STATE_RECORD
+{
+ SCI_BASE_OBSERVER_T base_state_observer;
+ SCI_BASE_OBSERVER_T starting_state_observer;
+
+ U16 index;
+
+ U32 state_transition_table[MAX_STATE_TRANSITION_RECORD];
+
+} SCIC_SDS_PHY_STATE_RECORD_T;
+#endif // SCIC_DEBUG_ENABLED
+
+/**
+ * @enum
+ *
+ * @brief 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
+ *
+ * @brief This structure contains or references all of the data necessary to
+ * represent the core phy object and SCU harware protocol engine.
+ */
+typedef struct SCIC_SDS_PHY
+{
+ SCI_BASE_PHY_T 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.
+ */
+ 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
+ {
+ SCI_SAS_IDENTIFY_ADDRESS_FRAME_T identify_address_frame_buffer;
+
+ } sas;
+
+ struct
+ {
+ SATA_FIS_REG_D2H_T 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;
+
+ SCI_BASE_STATE_MACHINE_T starting_substate_machine;
+
+ #ifdef SCI_LOGGING
+ SCI_BASE_STATE_MACHINE_LOGGER_T starting_substate_machine_logger;
+ #endif
+
+ #ifdef SCIC_DEBUG_ENABLED
+ SCIC_SDS_PHY_STATE_RECORD_T state_record;
+ #endif // SCIC_DEBUG_ENABLED
+
+ /**
+ * This field tracks how many errors of each type have been detected since
+ * the last controller reset or counter clear. Note that these are only
+ * for the error types that our driver needs to count manually. See
+ * SCU_ERR_CNT_* values defined in scu_event_codes.h.
+ */
+ U32 error_counter[SCU_ERR_CNT_MAX_INDEX];
+
+ /**
+ * This field is the pointer to the transport layer register for the SCU
+ * hardware.
+ */
+ SCU_TRANSPORT_LAYER_REGISTERS_T *transport_layer_registers;
+
+ /**
+ * This field points to the link layer register set within the SCU.
+ */
+ SCU_LINK_LAYER_REGISTERS_T *link_layer_registers;
+
+} SCIC_SDS_PHY_T;
+
+
+typedef SCI_STATUS (*SCIC_SDS_PHY_EVENT_HANDLER_T)(SCIC_SDS_PHY_T *, U32);
+typedef SCI_STATUS (*SCIC_SDS_PHY_FRAME_HANDLER_T)(SCIC_SDS_PHY_T *, U32);
+typedef SCI_STATUS (*SCIC_SDS_PHY_POWER_HANDLER_T)(SCIC_SDS_PHY_T *);
+
+/**
+ * @struct SCIC_SDS_PHY_STATE_HANDLER
+ */
+typedef struct SCIC_SDS_PHY_STATE_HANDLER
+{
+ /**
+ * This is the SCI_BASE_PHY object state handlers.
+ */
+ SCI_BASE_PHY_STATE_HANDLER_T 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;
+
+} SCIC_SDS_PHY_STATE_HANDLER_T;
+
+extern SCIC_SDS_PHY_STATE_HANDLER_T scic_sds_phy_state_handler_table[];
+extern SCI_BASE_STATE_T scic_sds_phy_state_table[];
+extern SCI_BASE_STATE_T scic_sds_phy_starting_substates[];
+extern SCIC_SDS_PHY_STATE_HANDLER_T
+ scic_sds_phy_starting_substate_handler_table[];
+
+
+/**
+ * This macro returns the phy index for the specified phy
+ */
+#define scic_sds_phy_get_index(phy) \
+ ((phy)->phy_index)
+
+/**
+ * @brief This macro returns the controller for this phy
+ */
+#define scic_sds_phy_get_controller(phy) \
+ (scic_sds_port_get_controller((phy)->owning_port))
+
+/**
+ * @brief This macro returns the state machine for the base phy
+ */
+#define scic_sds_phy_get_base_state_machine(phy) \
+ (&(phy)->parent.state_machine)
+
+/**
+ * @brief This macro returns the starting substate machine for
+ * this phy
+ */
+#define scic_sds_phy_get_starting_substate_machine(phy) \
+ (&(phy)->starting_substate_machine)
+
+/**
+ * @brief This macro sets the state handlers for this phy object
+ */
+#define scic_sds_phy_set_state_handlers(phy, handlers) \
+ ((phy)->state_handlers = (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)] \
+ )
+
+/**
+ * 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) \
+ ) \
+ )
+
+// ---------------------------------------------------------------------------
+
+U32 scic_sds_phy_get_object_size(void);
+
+U32 scic_sds_phy_get_min_timer_count(void);
+
+U32 scic_sds_phy_get_max_timer_count(void);
+
+// ---------------------------------------------------------------------------
+
+void scic_sds_phy_construct(
+ struct SCIC_SDS_PHY *this_phy,
+ struct SCIC_SDS_PORT *owning_port,
+ U8 phy_index
+);
+
+SCI_PORT_HANDLE_T scic_sds_phy_get_port(
+ SCIC_SDS_PHY_T *this_phy
+);
+
+void scic_sds_phy_set_port(
+ struct SCIC_SDS_PHY *this_phy,
+ struct SCIC_SDS_PORT *owning_port
+);
+
+SCI_STATUS scic_sds_phy_initialize(
+ SCIC_SDS_PHY_T *this_phy,
+ void *transport_layer_registers,
+ SCU_LINK_LAYER_REGISTERS_T *link_layer_registers
+);
+
+SCI_STATUS scic_sds_phy_reset(
+ SCIC_SDS_PHY_T * this_phy
+);
+
+void scic_sds_phy_sata_timeout(
+ SCI_OBJECT_HANDLE_T cookie
+);
+
+// ---------------------------------------------------------------------------
+
+void scic_sds_phy_suspend(
+ struct SCIC_SDS_PHY *this_phy
+);
+
+void scic_sds_phy_resume(
+ struct SCIC_SDS_PHY *this_phy
+);
+
+void scic_sds_phy_setup_transport(
+ struct SCIC_SDS_PHY * this_phy,
+ U32 device_id
+);
+
+// ---------------------------------------------------------------------------
+
+SCI_STATUS scic_sds_phy_event_handler(
+ SCIC_SDS_PHY_T *this_phy,
+ U32 event_code
+);
+
+SCI_STATUS scic_sds_phy_frame_handler(
+ SCIC_SDS_PHY_T *this_phy,
+ U32 frame_index
+);
+
+SCI_STATUS scic_sds_phy_consume_power_handler(
+ SCIC_SDS_PHY_T *this_phy
+);
+
+void scic_sds_phy_get_sas_address(
+ SCIC_SDS_PHY_T *this_phy,
+ SCI_SAS_ADDRESS_T *sas_address
+);
+
+void scic_sds_phy_get_attached_sas_address(
+ SCIC_SDS_PHY_T *this_phy,
+ SCI_SAS_ADDRESS_T *sas_address
+);
+
+void scic_sds_phy_get_protocols(
+ SCIC_SDS_PHY_T *this_phy,
+ SCI_SAS_IDENTIFY_ADDRESS_FRAME_PROTOCOLS_T * protocols
+);
+
+void scic_sds_phy_get_attached_phy_protocols(
+ SCIC_SDS_PHY_T *this_phy,
+ SCI_SAS_IDENTIFY_ADDRESS_FRAME_PROTOCOLS_T * protocols
+);
+
+//****************************************************************************-
+//* SCIC SDS PHY Handler Methods
+//****************************************************************************-
+
+SCI_STATUS scic_sds_phy_default_start_handler(
+ SCI_BASE_PHY_T *phy
+);
+
+SCI_STATUS scic_sds_phy_default_stop_handler(
+ SCI_BASE_PHY_T *phy
+);
+
+SCI_STATUS scic_sds_phy_default_reset_handler(
+ SCI_BASE_PHY_T * phy
+);
+
+SCI_STATUS scic_sds_phy_default_destroy_handler(
+ SCI_BASE_PHY_T *phy
+);
+
+SCI_STATUS scic_sds_phy_default_frame_handler(
+ SCIC_SDS_PHY_T *phy,
+ U32 frame_index
+);
+
+SCI_STATUS scic_sds_phy_default_event_handler(
+ SCIC_SDS_PHY_T *phy,
+ U32 evnet_code
+);
+
+SCI_STATUS scic_sds_phy_default_consume_power_handler(
+ SCIC_SDS_PHY_T *phy
+);
+
+void scic_sds_phy_release_resource(
+ struct SCIC_SDS_CONTROLLER * controller,
+ struct SCIC_SDS_PHY * phy
+);
+
+void scic_sds_phy_restart_starting_state(
+ struct SCIC_SDS_PHY * this_phy
+);
+
+#ifdef __cplusplus
+}
+#endif // __cplusplus
+
+#endif // _SCIC_SDS_PHY_H_
diff --git a/sys/dev/isci/scil/scic_sds_phy_registers.h b/sys/dev/isci/scil/scic_sds_phy_registers.h
new file mode 100644
index 0000000..14a6be5
--- /dev/null
+++ b/sys/dev/isci/scil/scic_sds_phy_registers.h
@@ -0,0 +1,270 @@
+/*-
+ * 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.
+ *
+ * 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.
+ *
+ * $FreeBSD$
+ */
+#ifndef _SCIC_SDS_PHY_REGISTERS_H_
+#define _SCIC_SDS_PHY_REGISTERS_H_
+
+/**
+ * @file
+ *
+ * @brief This file contains the macros used by the phy object to read/write
+ * to the SCU link layer registers.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif // __cplusplus
+
+#include <dev/isci/scil/scic_sds_controller.h>
+
+//*****************************************************************************
+//* SCU LINK LAYER REGISTER OPERATIONS
+//*****************************************************************************
+
+/**
+ * Macro to read the transport layer register associated with this phy
+ * object.
+ */
+#define scu_transport_layer_read(phy, reg) \
+ scu_register_read( \
+ scic_sds_phy_get_controller(phy), \
+ (phy)->transport_layer_registers->reg \
+ )
+
+/**
+ * Macro to write the transport layer register associated with this phy
+ * object.
+ */
+#define scu_transport_layer_write(phy, reg, value) \
+ scu_register_write( \
+ scic_sds_phy_get_controller(phy), \
+ (phy)->transport_layer_registers->reg, \
+ (value) \
+ )
+
+//****************************************************************************
+//* Transport Layer registers controlled by the phy object
+//****************************************************************************
+
+/**
+ * This macro reads the Transport layer control register
+ */
+#define SCU_TLCR_READ(phy) \
+ scu_transport_layer_read(phy, control)
+
+/**
+ * This macro writes the Transport layer control register
+ */
+#define SCU_TLCR_WRITE(phy, value) \
+ scu_transport_layer_write(phy, control, value)
+
+/**
+ * This macro reads the Transport layer address translation register
+ */
+#define SCU_TLADTR_READ(phy) \
+ scu_transport_layer_read(phy, address_translation)
+
+/**
+ * This macro writes the Transport layer address translation register
+ */
+#define SCU_TLADTR_WRITE(phy) \
+ scu_transport_layer_write(phy, address_translation, value)
+
+/**
+ * This macro writes the STP Transport Layer Direct Attached RNi register.
+ */
+#define SCU_STPTLDARNI_WRITE(phy, index) \
+ scu_transport_layer_write(phy, stp_rni, index)
+
+/**
+ * This macro reads the STP Transport Layer Direct Attached RNi register.
+ */
+#define SCU_STPTLDARNI_READ(phy) \
+ scu_transport_layer_read(phy, stp_rni)
+
+//*****************************************************************************
+//* SCU LINK LAYER REGISTER OPERATIONS
+//*****************************************************************************
+
+/**
+ * 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 \
+ )
+
+/**
+ * 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 CLKSM register
+#define SCU_SAS_CLKSM_READ(phy) \
+ scu_link_layer_register_read(phy, clock_skew_management)
+
+/// This macro writes the CLKSM register
+#define SCU_SAS_CLKSM_WRITE(phy, value) \
+ scu_link_layer_register_write(phy, clock_skew_management, 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);
+
+/// This macro reads the link layer status register
+#define SCU_SAS_LLSTA_READ(phy) \
+ scu_link_layer_register_read(phy, link_layer_status);
+
+#define SCU_SAS_ECENCR_READ(phy) \
+ scu_link_layer_register_read(phy, error_counter_event_notification_control)
+
+#define SCU_SAS_ECENCR_WRITE(phy, value) \
+ scu_link_layer_register_write(phy, error_counter_event_notification_control, value)
+
+#ifdef __cplusplus
+}
+#endif // __cplusplus
+
+#endif // _SCIC_SDS_PHY_REGISTERS_H_
diff --git a/sys/dev/isci/scil/scic_sds_port.c b/sys/dev/isci/scil/scic_sds_port.c
new file mode 100644
index 0000000..220bb1d
--- /dev/null
+++ b/sys/dev/isci/scil/scic_sds_port.c
@@ -0,0 +1,3662 @@
+/*-
+ * 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.
+ *
+ * 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 <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/**
+ * @file
+ *
+ * @brief This file contains the implementation for the public and protected
+ * methods for the SCIC_SDS_PORT object.
+ */
+
+#include <dev/isci/scil/scic_phy.h>
+#include <dev/isci/scil/scic_port.h>
+#include <dev/isci/scil/scic_controller.h>
+#include <dev/isci/scil/scic_user_callback.h>
+
+#include <dev/isci/scil/scic_sds_controller.h>
+#include <dev/isci/scil/scic_sds_port.h>
+#include <dev/isci/scil/scic_sds_phy.h>
+#include <dev/isci/scil/scic_sds_remote_device.h>
+#include <dev/isci/scil/scic_sds_request.h>
+#include <dev/isci/scil/scic_sds_port_registers.h>
+#include <dev/isci/scil/scic_sds_logger.h>
+#include <dev/isci/scil/scic_sds_phy_registers.h>
+
+#include <dev/isci/scil/intel_sas.h>
+#include <dev/isci/scil/scic_sds_remote_node_context.h>
+#include <dev/isci/scil/sci_util.h>
+
+#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)
+#define SCU_DUMMY_INDEX (0xFFFF)
+
+/**
+ * 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.
+ *
+ * @param[in] this_port This is the port object to which the phy is being
+ * assigned.
+ * @param[in] phy_index This is the phy index that is being assigned to the
+ * port.
+ *
+ * @return BOOL
+ * @retval TRUE if this is a valid phy assignment for the port
+ * @retval FALSE if this is not a valid phy assignment for the port
+ */
+BOOL scic_sds_port_is_valid_phy_assignment(
+ SCIC_SDS_PORT_T *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;
+}
+
+/**
+ * @brief This method requests a list (mask) of the phys contained in the
+ * supplied SAS port.
+ *
+ * @param[in] this_port a handle corresponding to the SAS port for which
+ * to return the phy mask.
+ *
+ * @return 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(
+ SCIC_SDS_PORT_T * this_port
+)
+{
+ U32 index;
+ U32 mask;
+
+ SCIC_LOG_TRACE((
+ sci_base_object_get_logger(this_port),
+ SCIC_LOG_OBJECT_PORT,
+ "scic_sds_port_get_phys(0x%x) enter\n",
+ this_port
+ ));
+
+ mask = 0;
+
+ for (index = 0; index < SCI_MAX_PHYS; index++)
+ {
+ if (this_port->phy_table[index] != NULL)
+ {
+ mask |= (1 << index);
+ }
+ }
+
+ return mask;
+}
+
+/**
+ * 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]
+ *
+ * @param[in] this_port This is the port object for which to determine
+ * if the phy mask can be supported.
+ *
+ * @return This method returns a boolean indication specifying if the
+ * phy mask can be supported.
+ * @retval TRUE if this is a valid phy assignment for the port
+ * @retval FALSE if this is not a valid phy assignment for the port
+ */
+BOOL scic_sds_port_is_phy_mask_valid(
+ SCIC_SDS_PORT_T *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 method retrieves a currently active (i.e. connected) phy
+ * contained in the port. Currently, the lowest order phy that is
+ * connected is returned.
+ *
+ * @param[in] this_port This parameter specifies the port from which
+ * to return a connected phy.
+ *
+ * @return This method returns a pointer to a SCIS_SDS_PHY object.
+ * @retval NULL This value is returned if there are no currently
+ * active (i.e. connected to a remote end point) phys
+ * contained in the port.
+ * @retval All other values specify a SCIC_SDS_PHY object that is
+ * active in the port.
+ */
+SCIC_SDS_PHY_T * scic_sds_port_get_a_connected_phy(
+ SCIC_SDS_PORT_T *this_port
+)
+{
+ U32 index;
+ SCIC_SDS_PHY_T *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;
+}
+
+/**
+ * This method attempts to make the assignment of the phy to the port.
+ * If successful the phy is assigned to the ports phy table.
+ *
+ * @param[in, out] port The port object to which the phy assignement
+ * is being made.
+ * @param[in, out] phy The phy which is being assigned to the port.
+ *
+ * @return BOOL
+ * @retval TRUE if the phy assignment can be made.
+ * @retval FALSE if the phy assignement can not be made.
+ *
+ * @note This is a functional test that only fails if the phy is currently
+ * assigned to a different port.
+ */
+SCI_STATUS scic_sds_port_set_phy(
+ SCIC_SDS_PORT_T *port,
+ SCIC_SDS_PHY_T *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;
+}
+
+/**
+ * This method will clear the phy assigned to this port. This method fails
+ * if this phy is not currently assinged to this port.
+ *
+ * @param[in, out] port The port from which the phy is being cleared.
+ * @param[in, out] phy The phy being cleared from the port.
+ *
+ * @return BOOL
+ * @retval TRUE if the phy is removed from the port.
+ * @retval FALSE if this phy is not assined to this port.
+ */
+SCI_STATUS scic_sds_port_clear_phy(
+ SCIC_SDS_PORT_T *port,
+ SCIC_SDS_PHY_T *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;
+}
+
+/**
+ * This method will add a PHY to the selected port.
+ *
+ * @param[in] this_port This parameter specifies the port in which the phy will
+ * be added.
+ *
+ * @param[in] the_phy This parameter is the phy which is to be added to the
+ * port.
+ *
+ * @return This method returns an SCI_STATUS.
+ * @retval SCI_SUCCESS the phy has been added to the port.
+ * @retval Any other status is failre to add the phy to the port.
+ */
+SCI_STATUS scic_sds_port_add_phy(
+ SCIC_SDS_PORT_T * this_port,
+ SCIC_SDS_PHY_T * the_phy
+)
+{
+ return this_port->state_handlers->parent.add_phy_handler(
+ &this_port->parent, &the_phy->parent);
+}
+
+
+/**
+ * This method will remove the PHY from the selected PORT.
+ *
+ * @param[in] this_port This parameter specifies the port in which the phy will
+ * be added.
+ *
+ * @param[in] the_phy This parameter is the phy which is to be added to the
+ * port.
+ *
+ * @return This method returns an SCI_STATUS.
+ * @retval SCI_SUCCESS the phy has been removed from the port.
+ * @retval Any other status is failre to add the phy to the port.
+ */
+SCI_STATUS scic_sds_port_remove_phy(
+ SCIC_SDS_PORT_T * this_port,
+ SCIC_SDS_PHY_T * the_phy
+)
+{
+ return this_port->state_handlers->parent.remove_phy_handler(
+ &this_port->parent, &the_phy->parent);
+}
+
+/**
+ * @brief This method requests the SAS address for the supplied SAS port
+ * from the SCI implementation.
+ *
+ * @param[in] this_port a handle corresponding to the SAS port for which
+ * to return the SAS address.
+ * @param[out] sas_address This parameter specifies a pointer to a SAS
+ * address structure into which the core will copy the SAS
+ * address for the port.
+ *
+ * @return none
+ */
+void scic_sds_port_get_sas_address(
+ SCIC_SDS_PORT_T * this_port,
+ SCI_SAS_ADDRESS_T * sas_address
+)
+{
+ U32 index;
+
+ SCIC_LOG_TRACE((
+ sci_base_object_get_logger(this_port),
+ SCIC_LOG_OBJECT_PORT,
+ "scic_sds_port_get_sas_address(0x%x, 0x%x) enter\n",
+ this_port, sas_address
+ ));
+
+ 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);
+ }
+ }
+}
+
+/**
+ * @brief This method will indicate which protocols are supported by this
+ * port.
+ *
+ * @param[in] this_port a handle corresponding to the SAS port for which
+ * to return the supported protocols.
+ * @param[out] 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.
+ *
+ * @return none
+ */
+static
+void scic_sds_port_get_protocols(
+ SCIC_SDS_PORT_T * this_port,
+ SCI_SAS_IDENTIFY_ADDRESS_FRAME_PROTOCOLS_T * protocols
+)
+{
+ U8 index;
+
+ SCIC_LOG_TRACE((
+ sci_base_object_get_logger(this_port),
+ SCIC_LOG_OBJECT_PORT,
+ "scic_sds_port_get_protocols(0x%x, 0x%x) enter\n",
+ this_port, protocols
+ ));
+
+ 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);
+ }
+ }
+}
+
+/**
+ * @brief This method requests the SAS address for the device directly
+ * attached to this SAS port.
+ *
+ * @param[in] this_port a handle corresponding to the SAS port for which
+ * to return the SAS address.
+ * @param[out] 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.
+ *
+ * @return none
+ */
+void scic_sds_port_get_attached_sas_address(
+ SCIC_SDS_PORT_T * this_port,
+ SCI_SAS_ADDRESS_T * sas_address
+)
+{
+ SCI_SAS_IDENTIFY_ADDRESS_FRAME_PROTOCOLS_T protocols;
+ SCIC_SDS_PHY_T *phy;
+
+ SCIC_LOG_TRACE((
+ sci_base_object_get_logger(this_port),
+ SCIC_LOG_OBJECT_PORT,
+ "scic_sds_port_get_attached_sas_address(0x%x, 0x%x) enter\n",
+ this_port, sas_address
+ ));
+
+ // 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;
+
+ //Need to make up attached STP device's SAS address in
+ //the same order as recorded IAF from SSP device.
+ sas_address->high = SCIC_SWAP_DWORD(sas_address->high);
+ sas_address->low = SCIC_SWAP_DWORD(sas_address->low);
+ }
+ }
+ else
+ {
+ sas_address->high = 0;
+ sas_address->low = 0;
+ }
+}
+
+/**
+ * @brief This method will indicate which protocols are supported by this
+ * remote device.
+ *
+ * @param[in] this_port a handle corresponding to the SAS port for which
+ * to return the supported protocols.
+ * @param[out] 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.
+ *
+ * @return none
+ */
+void scic_sds_port_get_attached_protocols(
+ SCIC_SDS_PORT_T * this_port,
+ SCI_SAS_IDENTIFY_ADDRESS_FRAME_PROTOCOLS_T * protocols
+)
+{
+ SCIC_SDS_PHY_T *phy;
+
+ SCIC_LOG_TRACE((
+ sci_base_object_get_logger(this_port),
+ SCIC_LOG_OBJECT_PORT,
+ "scic_sds_port_get_attached_protocols(0x%x, 0x%x) enter\n",
+ this_port, protocols
+ ));
+
+ // 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;
+}
+
+/**
+ * @brief This method returns the amount of memory requred for a port
+ * object.
+ *
+ * @return U32
+ */
+U32 scic_sds_port_get_object_size(void)
+{
+ return sizeof(SCIC_SDS_PORT_T);
+}
+
+/**
+ * @brief This method returns the minimum number of timers required for all
+ * port objects.
+ *
+ * @return U32
+ */
+U32 scic_sds_port_get_min_timer_count(void)
+{
+ return SCIC_SDS_PORT_MIN_TIMER_COUNT;
+}
+
+/**
+ * @brief This method returns the maximum number of timers required for all
+ * port objects.
+ *
+ * @return U32
+ */
+U32 scic_sds_port_get_max_timer_count(void)
+{
+ return SCIC_SDS_PORT_MAX_TIMER_COUNT;
+}
+
+#ifdef SCI_LOGGING
+void scic_sds_port_initialize_state_logging(
+ SCIC_SDS_PORT_T *this_port
+)
+{
+ sci_base_state_machine_logger_initialize(
+ &this_port->parent.state_machine_logger,
+ &this_port->parent.state_machine,
+ &this_port->parent.parent,
+ scic_cb_logger_log_states,
+ "SCIC_SDS_PORT_T", "base state machine",
+ SCIC_LOG_OBJECT_PORT
+ );
+
+ sci_base_state_machine_logger_initialize(
+ &this_port->ready_substate_machine_logger,
+ &this_port->ready_substate_machine,
+ &this_port->parent.parent,
+ scic_cb_logger_log_states,
+ "SCIC_SDS_PORT_T", "ready substate machine",
+ SCIC_LOG_OBJECT_PORT
+ );
+}
+#endif
+
+/**
+ * This routine will construct a dummy remote node context data structure
+ * This structure will be posted to the hardware to work around a scheduler
+ * error in the hardware.
+ *
+ * @param[in] this_port The logical port on which we need to create the
+ * remote node context.
+ * @param[in] rni The remote node index for this remote node context.
+ *
+ * @return none
+ */
+static
+void scic_sds_port_construct_dummy_rnc(
+ SCIC_SDS_PORT_T *this_port,
+ U16 rni
+)
+{
+ SCU_REMOTE_NODE_CONTEXT_T * rnc;
+
+ rnc = &(this_port->owning_controller->remote_node_context_table[rni]);
+
+ memset(rnc, 0, sizeof(SCU_REMOTE_NODE_CONTEXT_T));
+
+ rnc->ssp.remote_sas_address_hi = 0;
+ rnc->ssp.remote_sas_address_lo = 0;
+
+ rnc->ssp.remote_node_index = rni;
+ rnc->ssp.remote_node_port_width = 1;
+ rnc->ssp.logical_port_index = this_port->physical_port_index;
+
+ rnc->ssp.nexus_loss_timer_enable = FALSE;
+ rnc->ssp.check_bit = FALSE;
+ rnc->ssp.is_valid = TRUE;
+ rnc->ssp.is_remote_node_context = TRUE;
+ rnc->ssp.function_number = 0;
+ rnc->ssp.arbitration_wait_time = 0;
+}
+
+/**
+ * This routine will construct a dummy task context data structure. This
+ * structure will be posted to the hardwre to work around a scheduler error
+ * in the hardware.
+ *
+ * @param[in] this_port The logical port on which we need to create the
+ * remote node context.
+ * context.
+ * @param[in] tci The remote node index for this remote node context.
+ *
+ */
+static
+void scic_sds_port_construct_dummy_task(
+ SCIC_SDS_PORT_T *this_port,
+ U16 tci
+)
+{
+ SCU_TASK_CONTEXT_T * task_context;
+
+ task_context = scic_sds_controller_get_task_context_buffer(this_port->owning_controller, tci);
+
+ memset(task_context, 0, sizeof(SCU_TASK_CONTEXT_T));
+
+ task_context->abort = 0;
+ task_context->priority = 0;
+ task_context->initiator_request = 1;
+ task_context->connection_rate = 1;
+ task_context->protocol_engine_index = 0;
+ task_context->logical_port_index = this_port->physical_port_index;
+ task_context->protocol_type = SCU_TASK_CONTEXT_PROTOCOL_SSP;
+ task_context->task_index = scic_sds_io_tag_get_index(tci);
+ task_context->valid = SCU_TASK_CONTEXT_VALID;
+ task_context->context_type = SCU_TASK_CONTEXT_TYPE;
+
+ task_context->remote_node_index = this_port->reserved_rni;
+ 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;
+}
+
+/**
+ * This routine will free any allocated dummy resources for this port.
+ *
+ * @param[in, out] this_port The port on which the resources are being destroyed.
+ */
+static
+void scic_sds_port_destroy_dummy_resources(
+ SCIC_SDS_PORT_T * this_port
+)
+{
+ if (this_port->reserved_tci != SCU_DUMMY_INDEX)
+ {
+ scic_controller_free_io_tag(
+ this_port->owning_controller, this_port->reserved_tci
+ );
+ }
+
+ if (this_port->reserved_rni != SCU_DUMMY_INDEX)
+ {
+ scic_sds_remote_node_table_release_remote_node_index(
+ &this_port->owning_controller->available_remote_nodes, 1, this_port->reserved_rni
+ );
+ }
+
+ this_port->reserved_rni = SCU_DUMMY_INDEX;
+ this_port->reserved_tci = SCU_DUMMY_INDEX;
+}
+
+/**
+ * @brief
+ *
+ * @param[in] this_port
+ * @param[in] port_index
+ * @param[in] owning_controller
+ */
+void scic_sds_port_construct(
+ SCIC_SDS_PORT_T *this_port,
+ U8 port_index,
+ SCIC_SDS_CONTROLLER_T *owning_controller
+)
+{
+ U32 index;
+
+ sci_base_port_construct(
+ &this_port->parent,
+ sci_base_object_get_logger(owning_controller),
+ 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
+ );
+
+ scic_sds_port_initialize_state_logging(this_port);
+
+ this_port->logical_port_index = SCIC_SDS_DUMMY_PORT;
+ this_port->physical_port_index = port_index;
+ this_port->active_phy_mask = 0;
+ this_port->enabled_phy_mask = 0;
+ this_port->owning_controller = owning_controller;
+
+ this_port->started_request_count = 0;
+ this_port->assigned_device_count = 0;
+
+ this_port->reserved_rni = SCU_DUMMY_INDEX;
+ this_port->reserved_tci = SCU_DUMMY_INDEX;
+
+ this_port->timer_handle = SCI_INVALID_HANDLE;
+
+ this_port->port_task_scheduler_registers = NULL;
+
+ for (index = 0; index < SCI_MAX_PHYS; index++)
+ {
+ this_port->phy_table[index] = NULL;
+ }
+}
+
+/**
+ * @brief This method performs initialization of the supplied port.
+ * Initialization includes:
+ * - state machine initialization
+ * - member variable initialization
+ * - configuring the phy_mask
+ *
+ * @param[in] this_port
+ * @param[in] transport_layer_registers
+ * @param[in] port_task_scheduler_registers
+ * @param[in] port_configuration_regsiter
+ *
+ * @return SCI_STATUS
+ * @retval SCI_FAILURE_UNSUPPORTED_PORT_CONFIGURATION This value is
+ * returned if the phy being added to the port
+ */
+SCI_STATUS scic_sds_port_initialize(
+ SCIC_SDS_PORT_T *this_port,
+ void *port_task_scheduler_registers,
+ void *port_configuration_regsiter,
+ void *viit_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;
+
+ return SCI_SUCCESS;
+}
+
+/**
+ * This method is the a general link up handler for the SCIC_SDS_PORT object.
+ * This function will determine if this SCIC_SDS_PHY can
+ * be assigned to this SCIC_SDS_PORT object. If the 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.
+ *
+ * @param[in] this_port This is the SCIC_SDS_PORT object for which has a phy
+ * that has gone link up.
+ * @param[in] the_phy This is the SCIC_SDS_PHY object that has gone link up.
+ * @param[in] 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.
+ * @param[in] do_resume_phy This parameter specifies whether to resume the phy.
+ * If this function is called from MPC mode, it will be always true.
+ * for APC, this will be false, so that phys could be resumed later
+ *
+ * @return none
+ */
+void scic_sds_port_general_link_up_handler(
+ SCIC_SDS_PORT_T * this_port,
+ SCIC_SDS_PHY_T * the_phy,
+ BOOL do_notify_user,
+ BOOL do_resume_phy
+)
+{
+ SCI_SAS_ADDRESS_T port_sas_address;
+ SCI_SAS_ADDRESS_T 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, do_resume_phy);
+
+ 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);
+ }
+}
+
+// ---------------------------------------------------------------------------
+
+SCI_STATUS scic_port_add_phy(
+ SCI_PORT_HANDLE_T handle,
+ SCI_PHY_HANDLE_T phy
+)
+{
+ #if defined (SCI_LOGGING)
+ SCIC_SDS_PORT_T *this_port = (SCIC_SDS_PORT_T *)handle;
+ #endif // defined (SCI_LOGGING)
+
+ SCIC_LOG_TRACE((
+ sci_base_object_get_logger(this_port),
+ SCIC_LOG_OBJECT_PORT,
+ "scic_port_add_phy(0x%x, 0x%x) enter\n",
+ handle, phy
+ ));
+
+ SCIC_LOG_ERROR((
+ sci_base_object_get_logger(this_port),
+ SCIC_LOG_OBJECT_PORT,
+ "Interface function scic_port_add_phy() has been deprecated. "
+ "PORT configuration is handled through the OEM parameters.\n"
+ ));
+
+ return SCI_FAILURE_ADDING_PHY_UNSUPPORTED;
+
+}
+
+// ---------------------------------------------------------------------------
+
+SCI_STATUS scic_port_remove_phy(
+ SCI_PORT_HANDLE_T handle,
+ SCI_PHY_HANDLE_T phy
+)
+{
+ #if defined (SCI_LOGGING)
+ SCIC_SDS_PORT_T *this_port = (SCIC_SDS_PORT_T *)handle;
+ #endif // defined (SCI_LOGGING)
+
+ SCIC_LOG_TRACE((
+ sci_base_object_get_logger(this_port),
+ SCIC_LOG_OBJECT_PORT,
+ "scic_port_remove_phy(0x%x, 0x%x) enter\n",
+ handle, phy
+ ));
+
+ SCIC_LOG_ERROR((
+ sci_base_object_get_logger(this_port),
+ SCIC_LOG_OBJECT_PORT,
+ "Interface function scic_port_remove_phy() has been deprecated. "
+ "PORT configuration is handled through the OEM parameters.\n"
+ ));
+
+ return SCI_FAILURE_ADDING_PHY_UNSUPPORTED;
+}
+
+// ---------------------------------------------------------------------------
+
+SCI_STATUS scic_port_get_properties(
+ SCI_PORT_HANDLE_T port,
+ SCIC_PORT_PROPERTIES_T * properties
+)
+{
+ SCIC_SDS_PORT_T *this_port = (SCIC_SDS_PORT_T *)port;
+
+ SCIC_LOG_TRACE((
+ sci_base_object_get_logger(this_port),
+ SCIC_LOG_OBJECT_PORT,
+ "scic_port_get_properties(0x%x, 0x%x) enter\n",
+ port, properties
+ ));
+
+ if (
+ (port == SCI_INVALID_HANDLE)
+ || (this_port->logical_port_index == SCIC_SDS_DUMMY_PORT)
+ )
+ {
+ return SCI_FAILURE_INVALID_PORT;
+ }
+
+ properties->index = this_port->logical_port_index;
+ properties->phy_mask = scic_sds_port_get_phys(this_port);
+ scic_sds_port_get_sas_address(this_port, &properties->local.sas_address);
+ scic_sds_port_get_protocols(this_port, &properties->local.protocols);
+ scic_sds_port_get_attached_sas_address(this_port, &properties->remote.sas_address);
+ scic_sds_port_get_attached_protocols(this_port, &properties->remote.protocols);
+
+ return SCI_SUCCESS;
+}
+
+// ---------------------------------------------------------------------------
+
+SCI_STATUS scic_port_hard_reset(
+ SCI_PORT_HANDLE_T handle,
+ U32 reset_timeout
+)
+{
+ SCIC_SDS_PORT_T * this_port = (SCIC_SDS_PORT_T *)handle;
+
+ SCIC_LOG_TRACE((
+ sci_base_object_get_logger(this_port),
+ SCIC_LOG_OBJECT_PORT,
+ "scic_port_hard_reset(0x%x, 0x%x) enter\n",
+ handle, reset_timeout
+ ));
+
+ return this_port->state_handlers->parent.reset_handler(
+ &this_port->parent,
+ reset_timeout
+ );
+}
+
+/**
+ * This method assigns the direct attached device ID for this port.
+ *
+ * @param[in] this_port The port for which the direct attached device id is to
+ * be assigned.
+ * @param[in] device_id The direct attached device ID to assign to the port.
+ * This will be the RNi for the device
+ */
+void scic_sds_port_setup_transports(
+ SCIC_SDS_PORT_T * this_port,
+ U32 device_id
+)
+{
+ U8 index;
+
+ for (index = 0; index < SCI_MAX_PHYS; index++)
+ {
+ if (this_port->active_phy_mask & (1 << index))
+ {
+ scic_sds_phy_setup_transport(this_port->phy_table[index], device_id);
+ }
+ }
+}
+
+/**
+ * This method will resume the phy which is already added in the port.
+ * Activation includes:
+ * - enabling the Protocol Engine in the silicon.
+ * - update the reay mask.
+ *
+ * @param[in] this_port This is the port on which the phy should be enabled.
+ * @return none
+ */
+static
+void scic_sds_port_resume_phy(
+ SCIC_SDS_PORT_T * this_port,
+ SCIC_SDS_PHY_T * the_phy
+)
+{
+ scic_sds_phy_resume (the_phy);
+ this_port->enabled_phy_mask |= 1 << the_phy->phy_index;
+}
+/**
+ * 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.
+ *
+ * @param[in] this_port This is the port on which the phy should be enabled.
+ * @param[in] the_phy This is the specific phy which to enable.
+ * @param[in] 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.
+ * @param[in] do_resume_phy This parameter specifies whether to resume the phy.
+ * If this function is called from MPC mode, it will be always true.
+ * for APC, this will be false, so that phys could be resumed later
+ *
+
+ * @return none
+ */
+void scic_sds_port_activate_phy(
+ SCIC_SDS_PORT_T * this_port,
+ SCIC_SDS_PHY_T * the_phy,
+ BOOL do_notify_user,
+ BOOL do_resume_phy
+)
+{
+ SCIC_SDS_CONTROLLER_T * controller;
+ SCI_SAS_IDENTIFY_ADDRESS_FRAME_PROTOCOLS_T protocols;
+
+ SCIC_LOG_TRACE((
+ sci_base_object_get_logger(this_port),
+ SCIC_LOG_OBJECT_PORT,
+ "scic_sds_port_activate_phy(0x%x,0x%x,0x%x) enter\n",
+ this_port, the_phy, do_notify_user
+ ));
+
+ 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)
+ {
+ if (do_resume_phy == TRUE)
+ {
+ scic_sds_port_resume_phy(this_port, 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 method will deactivate the supplied phy in the port.
+ *
+ * @param[in] this_port This is the port on which the phy should be
+ * deactivated.
+ * @param[in] the_phy This is the specific phy that is no longer
+ * active in the port.
+ * @param[in] 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.
+ *
+ * @return none
+ */
+void scic_sds_port_deactivate_phy(
+ SCIC_SDS_PORT_T * this_port,
+ SCIC_SDS_PHY_T * the_phy,
+ BOOL do_notify_user
+)
+{
+ SCIC_LOG_TRACE((
+ sci_base_object_get_logger(this_port),
+ SCIC_LOG_OBJECT_PORT,
+ "scic_sds_port_deactivate_phy(0x%x,0x%x,0x%x) enter\n",
+ this_port, the_phy, do_notify_user
+ ));
+
+ this_port->active_phy_mask &= ~(1 << the_phy->phy_index);
+ this_port->enabled_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 for APC mode.
+ // For MPC mode, the phy will remain in the port
+ if (this_port->owning_controller->oem_parameters.sds1.controller.mode_type
+ == SCIC_PORT_AUTOMATIC_CONFIGURATION_MODE)
+ {
+ 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 method will disable the phy and report that the phy is not valid for this
+ * port object.
+ *
+ * @param[in] this_port This is the port on which the phy should be disabled.
+ * @param[in] the_phy This is the specific phy which to disabled.
+ *
+ * @return None
+ */
+void scic_sds_port_invalid_link_up(
+ SCIC_SDS_PORT_T * this_port,
+ SCIC_SDS_PHY_T * the_phy
+)
+{
+ SCIC_SDS_CONTROLLER_T * 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);
+ }
+}
+
+/**
+ * @brief 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.
+ *
+ * @param[in] this_port The port for which the wide port condition is to be
+ * checked.
+ *
+ * @return BOOL
+ * @retval TRUE Is returned if this is a wide ported port.
+ * @retval FALSE Is returned if this is a narrow port.
+ */
+static
+BOOL scic_sds_port_is_wide(
+ SCIC_SDS_PORT_T *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);
+}
+
+/**
+ * @brief 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.
+ *
+ * @param[in] this_port The port associated with the phy object.
+ * @param[in] the_phy The phy object that is trying to go link up.
+ *
+ * @return TRUE if the phy object can continue to the link up condition.
+ * @retval TRUE Is returned if this phy can continue to the ready state.
+ * @retval FALSE Is returned if can not continue on to the ready state.
+ *
+ * @note 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(
+ SCIC_SDS_PORT_T *this_port,
+ SCIC_SDS_PHY_T *the_phy
+)
+{
+ SCI_SAS_IDENTIFY_ADDRESS_FRAME_PROTOCOLS_T 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)
+ )
+ {
+ if (scic_sds_port_is_wide(this_port))
+ {
+ //direct attached Sata phy cannot be in wide port.
+ scic_sds_port_invalid_link_up( this_port, the_phy);
+ return FALSE;
+ }
+ else
+ {
+ SCIC_SDS_PORT_T *destination_port = &(this_port->owning_controller->port_table[the_phy->phy_index]);
+
+ //add the phy to the its logical port for direct attached SATA. The phy will be added
+ //to port whose port_index will be the phy_index.
+ SCU_PCSPExCR_WRITE( destination_port, the_phy->phy_index, the_phy->phy_index);
+ }
+ }
+
+ return TRUE;
+}
+
+/**
+ * @brief This method is the entry point for the phy to inform
+ * the port that it is now in a ready state
+ *
+ * @param[in] this_port
+ * @param[in] phy
+ */
+void scic_sds_port_link_up(
+ SCIC_SDS_PORT_T *this_port,
+ SCIC_SDS_PHY_T *the_phy
+)
+{
+ the_phy->is_in_link_training = FALSE;
+
+ this_port->state_handlers->link_up_handler(this_port, the_phy);
+}
+
+/**
+ * @brief This method is the entry point for the phy to inform
+ * the port that it is no longer in a ready state
+ *
+ * @param[in] this_port
+ * @param[in] phy
+ */
+void scic_sds_port_link_down(
+ SCIC_SDS_PORT_T *this_port,
+ SCIC_SDS_PHY_T *the_phy
+)
+{
+ this_port->state_handlers->link_down_handler(this_port, the_phy);
+}
+
+/**
+ * @brief This method is called to start an IO request on this port.
+ *
+ * @param[in] this_port
+ * @param[in] the_device
+ * @param[in] the_io_request
+ *
+ * @return SCI_STATUS
+ */
+SCI_STATUS scic_sds_port_start_io(
+ SCIC_SDS_PORT_T *this_port,
+ SCIC_SDS_REMOTE_DEVICE_T *the_device,
+ SCIC_SDS_REQUEST_T *the_io_request
+)
+{
+ return this_port->state_handlers->start_io_handler(
+ this_port, the_device, the_io_request);
+}
+
+/**
+ * @brief This method is called to complete an IO request to the port.
+ *
+ * @param[in] this_port
+ * @param[in] the_device
+ * @param[in] the_io_request
+ *
+ * @return SCI_STATUS
+ */
+SCI_STATUS scic_sds_port_complete_io(
+ SCIC_SDS_PORT_T *this_port,
+ SCIC_SDS_REMOTE_DEVICE_T *the_device,
+ SCIC_SDS_REQUEST_T *the_io_request
+)
+{
+ return this_port->state_handlers->complete_io_handler(
+ this_port, the_device, the_io_request);
+}
+
+/**
+ * @brief This method is provided to timeout requests for port operations.
+ * Mostly its for the port reset operation.
+ *
+ * @param[in] port This is the parameter or cookie value that is provided
+ * to the timer construct operation.
+ */
+void scic_sds_port_timeout_handler(
+ void *port
+)
+{
+ U32 current_state;
+ SCIC_SDS_PORT_T * this_port;
+
+ this_port = (SCIC_SDS_PORT_T *)port;
+ 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.
+ SCIC_LOG_ERROR((
+ sci_base_object_get_logger(this_port),
+ SCIC_LOG_OBJECT_PORT,
+ "SCIC Port 0x%x failed to stop before tiemout.\n",
+ 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.
+ SCIC_LOG_ERROR((
+ sci_base_object_get_logger(this_port),
+ SCIC_LOG_OBJECT_PORT,
+ "SCIC Port 0x%x is processing a timeout operation in state %d.\n",
+ this_port, current_state
+ ));
+ }
+}
+
+// ---------------------------------------------------------------------------
+
+#ifdef SCIC_DEBUG_ENABLED
+void scic_sds_port_decrement_request_count(
+ SCIC_SDS_PORT_T *this_port
+)
+{
+ if (this_port->started_request_count == 0)
+ {
+ SCIC_LOG_WARNING((
+ sci_base_object_get_logger(this_port),
+ SCIC_LOG_OBJECT_PORT,
+ "SCIC Port object requested to decrement started io count past zero.\n"
+ ));
+ }
+ else
+ {
+ this_port->started_request_count--;
+ }
+}
+#endif
+
+/**
+ * @brief This function updates the hardwares VIIT entry for this port.
+ *
+ * @param[in] this_port
+ */
+void scic_sds_port_update_viit_entry(
+ SCIC_SDS_PORT_T *this_port
+)
+{
+ SCI_SAS_ADDRESS_T 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
+ | ((1UL << this_port->physical_port_index) << SCU_VIIT_ENTRY_LPVIE_SHIFT)
+ | SCU_VIIT_STATUS_ALL_VALID
+ )
+ );
+}
+
+/**
+ * @brief 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.
+ *
+ * @param[in] this_port This parameter specifies the port for which to
+ * retrieve the maximum allowed speed.
+ *
+ * @return This method returns the maximum negotiated speed of the slowest
+ * phy in the port.
+ */
+SCI_SAS_LINK_RATE scic_sds_port_get_max_allowed_speed(
+ SCIC_SDS_PORT_T * this_port
+)
+{
+ U16 index = 0;
+ SCI_SAS_LINK_RATE max_allowed_speed = SCI_SAS_600_GB;
+ SCIC_SDS_PHY_T * 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;
+}
+
+
+/**
+ * @brief This method passes the event to core user.
+ * @param[in] this_port The port that a BCN happens.
+ * @param[in] this_phy The phy that receives BCN.
+ *
+ * @return none
+ */
+void scic_sds_port_broadcast_change_received(
+ SCIC_SDS_PORT_T * this_port,
+ SCIC_SDS_PHY_T * this_phy
+)
+{
+ //notify the user.
+ scic_cb_port_bc_change_primitive_recieved(
+ this_port->owning_controller, this_port, this_phy
+ );
+}
+
+
+/**
+ * @brief This API methhod enables the broadcast change notification from
+ * underneath hardware.
+ * @param[in] this_port The port that a BCN had been disabled from.
+ *
+ * @return none
+ */
+void scic_port_enable_broadcast_change_notification(
+ SCI_PORT_HANDLE_T port
+)
+{
+ SCIC_SDS_PORT_T * this_port = (SCIC_SDS_PORT_T *)port;
+ SCIC_SDS_PHY_T * phy;
+ U32 register_value;
+ U8 index;
+
+ // Loop through all of the phys to enable BCN.
+ for (index = 0; index < SCI_MAX_PHYS; index++)
+ {
+ phy = this_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);
+ }
+ }
+}
+
+/**
+ * @brief This method release resources in for a scic port.
+ *
+ * @param[in] controller This parameter specifies the core controller, one of
+ * its phy's resources are to be released.
+ * @param[in] this_port This parameter specifies the port whose resourse is to
+ * be released.
+ */
+void scic_sds_port_release_resource(
+ SCIC_SDS_CONTROLLER_T * controller,
+ SCIC_SDS_PORT_T *this_port
+)
+{
+ SCIC_LOG_TRACE((
+ sci_base_object_get_logger(this_port),
+ SCIC_LOG_OBJECT_PORT,
+ "scic_sds_port_release_resource(0x%x, 0x%x)\n",
+ controller, this_port
+ ));
+
+ //Currently, the only resource to be released is a timer.
+ if (this_port->timer_handle != NULL)
+ {
+ scic_cb_timer_destroy(controller, this_port->timer_handle);
+ this_port->timer_handle = NULL;
+ }
+}
+
+
+//******************************************************************************
+//* PORT STATE MACHINE
+//******************************************************************************
+
+//***************************************************************************
+//* DEFAULT HANDLERS
+//***************************************************************************
+
+/**
+ * This is the default method for port a start request. It will report a
+ * warning and exit.
+ *
+ * @param[in] port This is the SCI_BASE_PORT object which is cast into a
+ * SCIC_SDS_PORT object.
+ *
+ * @return SCI_STATUS
+ * @retval SCI_FAILURE_INVALID_STATE
+ */
+SCI_STATUS scic_sds_port_default_start_handler(
+ SCI_BASE_PORT_T *port
+)
+{
+ SCIC_LOG_WARNING((
+ sci_base_object_get_logger((SCIC_SDS_PORT_T *)port),
+ SCIC_LOG_OBJECT_PORT,
+ "SCIC Port 0x%08x requested to start while in invalid state %d\n",
+ port,
+ sci_base_state_machine_get_state(
+ scic_sds_port_get_base_state_machine((SCIC_SDS_PORT_T *)port))
+ ));
+
+ return SCI_FAILURE_INVALID_STATE;
+}
+
+/**
+ * This is the default method for a port stop request. It will report a
+ * warning and exit.
+ *
+ * @param[in] port This is the SCI_BASE_PORT object which is cast into a
+ * SCIC_SDS_PORT object.
+ *
+ * @return SCI_STATUS
+ * @retval SCI_FAILURE_INVALID_STATE
+ */
+SCI_STATUS scic_sds_port_default_stop_handler(
+ SCI_BASE_PORT_T *port
+)
+{
+ SCIC_LOG_WARNING((
+ sci_base_object_get_logger((SCIC_SDS_PORT_T *)port),
+ SCIC_LOG_OBJECT_PORT,
+ "SCIC Port 0x%08x requested to stop while in invalid state %d\n",
+ port,
+ sci_base_state_machine_get_state(
+ scic_sds_port_get_base_state_machine((SCIC_SDS_PORT_T *)port))
+ ));
+
+ return SCI_FAILURE_INVALID_STATE;
+}
+
+/**
+ * This is the default method for a port destruct request. It will report a
+ * warning and exit.
+ *
+ * @param[in] port This is the SCI_BASE_PORT object which is cast into a
+ * SCIC_SDS_PORT object.
+ *
+ * @return SCI_STATUS
+ * @retval SCI_FAILURE_INVALID_STATE
+ */
+SCI_STATUS scic_sds_port_default_destruct_handler(
+ SCI_BASE_PORT_T *port
+)
+{
+ SCIC_LOG_WARNING((
+ sci_base_object_get_logger((SCIC_SDS_PORT_T *)port),
+ SCIC_LOG_OBJECT_PORT,
+ "SCIC Port 0x%08x requested to destruct while in invalid state %d\n",
+ port,
+ sci_base_state_machine_get_state(
+ scic_sds_port_get_base_state_machine((SCIC_SDS_PORT_T *)port))
+ ));
+
+ return SCI_FAILURE_INVALID_STATE;
+}
+
+/**
+ * This is the default method for a port reset request. It will report a
+ * warning and exit.
+ *
+ * @param[in] port This is the SCI_BASE_PORT object which is cast into a
+ * SCIC_SDS_PORT object.
+ * @param[in] timeout This is the timeout for the reset request to complete.
+ *
+ * @return SCI_STATUS
+ * @retval SCI_FAILURE_INVALID_STATE
+ */
+SCI_STATUS scic_sds_port_default_reset_handler(
+ SCI_BASE_PORT_T * port,
+ U32 timeout
+)
+{
+ SCIC_LOG_WARNING((
+ sci_base_object_get_logger((SCIC_SDS_PORT_T *)port),
+ SCIC_LOG_OBJECT_PORT,
+ "SCIC Port 0x%08x requested to reset while in invalid state %d\n",
+ port,
+ sci_base_state_machine_get_state(
+ scic_sds_port_get_base_state_machine((SCIC_SDS_PORT_T *)port))
+ ));
+
+ return SCI_FAILURE_INVALID_STATE;
+}
+
+/**
+ * This is the default method for a port add phy request. It will report a
+ * warning and exit.
+ *
+ * @param[in] port This is the SCI_BASE_PORT object which is cast into a
+ * SCIC_SDS_PORT object.
+ *
+ * @return SCI_STATUS
+ * @retval SCI_FAILURE_INVALID_STATE
+ */
+SCI_STATUS scic_sds_port_default_add_phy_handler(
+ SCI_BASE_PORT_T *port,
+ SCI_BASE_PHY_T *phy
+)
+{
+ SCIC_LOG_WARNING((
+ sci_base_object_get_logger((SCIC_SDS_PORT_T *)port),
+ SCIC_LOG_OBJECT_PORT,
+ "SCIC Port 0x%08x requested to add phy 0x%08x while in invalid state %d\n",
+ port, phy,
+ sci_base_state_machine_get_state(
+ scic_sds_port_get_base_state_machine((SCIC_SDS_PORT_T *)port))
+ ));
+
+ return SCI_FAILURE_INVALID_STATE;
+}
+
+/**
+ * This is the default method for a port remove phy request. It will report a
+ * warning and exit.
+ *
+ * @param[in] port This is the SCI_BASE_PORT object which is cast into a
+ * SCIC_SDS_PORT object.
+ *
+ * @return SCI_STATUS
+ * @retval SCI_FAILURE_INVALID_STATE
+ */
+SCI_STATUS scic_sds_port_default_remove_phy_handler(
+ SCI_BASE_PORT_T *port,
+ SCI_BASE_PHY_T *phy
+)
+{
+ SCIC_LOG_WARNING((
+ sci_base_object_get_logger((SCIC_SDS_PORT_T *)port),
+ SCIC_LOG_OBJECT_PORT,
+ "SCIC Port 0x%08x requested to remove phy 0x%08x while in invalid state %d\n",
+ port, phy,
+ sci_base_state_machine_get_state(
+ scic_sds_port_get_base_state_machine((SCIC_SDS_PORT_T *)port))
+ ));
+
+ return SCI_FAILURE_INVALID_STATE;
+}
+
+/**
+ * This is the default method for a port unsolicited frame request. It will
+ * report a warning and exit.
+ *
+ * @param[in] port This is the SCI_BASE_PORT object which is cast into a
+ * SCIC_SDS_PORT object.
+ *
+ * @return SCI_STATUS
+ * @retval SCI_FAILURE_INVALID_STATE
+ *
+ * @todo 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?
+ */
+SCI_STATUS scic_sds_port_default_frame_handler(
+ SCIC_SDS_PORT_T * port,
+ U32 frame_index
+)
+{
+ SCIC_SDS_PORT_T *this_port = (SCIC_SDS_PORT_T *)port;
+
+ SCIC_LOG_WARNING((
+ sci_base_object_get_logger(this_port),
+ SCIC_LOG_OBJECT_PORT,
+ "SCIC Port 0x%08x requested to process frame %d while in invalid state %d\n",
+ port, frame_index,
+ sci_base_state_machine_get_state(
+ scic_sds_port_get_base_state_machine(this_port))
+ ));
+
+ scic_sds_controller_release_frame(
+ scic_sds_port_get_controller(this_port), frame_index
+ );
+
+ return SCI_FAILURE_INVALID_STATE;
+}
+
+/**
+ * This is the default method for a port event request. It will report a
+ * warning and exit.
+ *
+ * @param[in] port This is the SCI_BASE_PORT object which is cast into a
+ * SCIC_SDS_PORT object.
+ *
+ * @return SCI_STATUS
+ * @retval SCI_FAILURE_INVALID_STATE
+ */
+SCI_STATUS scic_sds_port_default_event_handler(
+ SCIC_SDS_PORT_T * port,
+ U32 event_code
+)
+{
+ SCIC_LOG_WARNING((
+ sci_base_object_get_logger((SCIC_SDS_PORT_T *)port),
+ SCIC_LOG_OBJECT_PORT,
+ "SCIC Port 0x%08x requested to process event 0x%08x while in invalid state %d\n",
+ port, event_code,
+ sci_base_state_machine_get_state(
+ scic_sds_port_get_base_state_machine((SCIC_SDS_PORT_T *)port))
+ ));
+
+ return SCI_FAILURE_INVALID_STATE;
+}
+
+/**
+ * This is the default method for a port link up notification. It will report
+ * a warning and exit.
+ *
+ * @param[in] port This is the SCI_BASE_PORT object which is cast into a
+ * SCIC_SDS_PORT object.
+ *
+ * @return SCI_STATUS
+ * @retval SCI_FAILURE_INVALID_STATE
+ */
+void scic_sds_port_default_link_up_handler(
+ SCIC_SDS_PORT_T *this_port,
+ SCIC_SDS_PHY_T *phy
+)
+{
+ SCIC_LOG_WARNING((
+ sci_base_object_get_logger(this_port),
+ SCIC_LOG_OBJECT_PORT,
+ "SCIC Port 0x%08x received link_up notification from phy 0x%08x while in invalid state %d\n",
+ this_port, phy,
+ sci_base_state_machine_get_state(
+ scic_sds_port_get_base_state_machine(this_port))
+ ));
+}
+
+/**
+ * This is the default method for a port link down notification. It will
+ * report a warning and exit.
+ *
+ * @param[in] port This is the SCI_BASE_PORT object which is cast into a
+ * SCIC_SDS_PORT object.
+ *
+ * @return SCI_STATUS
+ * @retval SCI_FAILURE_INVALID_STATE
+ */
+void scic_sds_port_default_link_down_handler(
+ SCIC_SDS_PORT_T *this_port,
+ SCIC_SDS_PHY_T *phy
+)
+{
+ SCIC_LOG_WARNING((
+ sci_base_object_get_logger(this_port),
+ SCIC_LOG_OBJECT_PORT,
+ "SCIC Port 0x%08x received link down notification from phy 0x%08x while in invalid state %d\n",
+ this_port, phy,
+ sci_base_state_machine_get_state(
+ scic_sds_port_get_base_state_machine(this_port))
+ ));
+}
+
+/**
+ * This is the default method for a port start io request. It will report a
+ * warning and exit.
+ *
+ * @param[in] port This is the SCI_BASE_PORT object which is cast into a
+ * SCIC_SDS_PORT object.
+ *
+ * @return SCI_STATUS
+ * @retval SCI_FAILURE_INVALID_STATE
+ */
+SCI_STATUS scic_sds_port_default_start_io_handler(
+ SCIC_SDS_PORT_T *this_port,
+ SCIC_SDS_REMOTE_DEVICE_T *device,
+ SCIC_SDS_REQUEST_T *io_request
+)
+{
+ SCIC_LOG_WARNING((
+ sci_base_object_get_logger(this_port),
+ SCIC_LOG_OBJECT_PORT,
+ "SCIC Port 0x%08x requested to start io request 0x%08x while in invalid state %d\n",
+ this_port, io_request,
+ sci_base_state_machine_get_state(
+ scic_sds_port_get_base_state_machine(this_port))
+ ));
+
+ return SCI_FAILURE_INVALID_STATE;
+}
+
+/**
+ * This is the default method for a port complete io request. It will report
+ * a warning and exit.
+ *
+ * @param[in] port This is the SCI_BASE_PORT object which is cast into a
+ * SCIC_SDS_PORT object.
+ *
+ * @return SCI_STATUS
+ * @retval SCI_FAILURE_INVALID_STATE
+ */
+SCI_STATUS scic_sds_port_default_complete_io_handler(
+ SCIC_SDS_PORT_T *this_port,
+ SCIC_SDS_REMOTE_DEVICE_T *device,
+ SCIC_SDS_REQUEST_T *io_request
+)
+{
+ SCIC_LOG_WARNING((
+ sci_base_object_get_logger(this_port),
+ SCIC_LOG_OBJECT_PORT,
+ "SCIC Port 0x%08x requested to complete io request 0x%08x while in invalid state %d\n",
+ 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
+//****************************************************************************
+
+/**
+ * This is a general complete io request handler for the SCIC_SDS_PORT object.
+ *
+ * @param[in] port This is the SCIC_SDS_PORT object on which the io request
+ * count will be decremented.
+ * @param[in] device This is the SCIC_SDS_REMOTE_DEVICE object to which the io
+ * request is being directed. This parameter is not required to
+ * complete this operation.
+ * @param[in] io_request This is the request that is being completed on this
+ * port object. This parameter is not required to complete this
+ * operation.
+ *
+ * @return SCI_STATUS
+ * @retval SCI_SUCCESS
+ */
+static
+SCI_STATUS scic_sds_port_general_complete_io_handler(
+ SCIC_SDS_PORT_T *port,
+ SCIC_SDS_REMOTE_DEVICE_T *device,
+ SCIC_SDS_REQUEST_T *io_request
+)
+{
+ SCIC_SDS_PORT_T *this_port = (SCIC_SDS_PORT_T *)port;
+
+ scic_sds_port_decrement_request_count(this_port);
+
+ return SCI_SUCCESS;
+}
+
+//****************************************************************************
+//* STOPPED STATE HANDLERS
+//****************************************************************************
+static
+BOOL scic_sds_port_requires_scheduler_workaround(
+ SCIC_SDS_PORT_T * this_port
+)
+{
+ if (
+ (
+ this_port->owning_controller->logical_port_entries
+ < this_port->owning_controller->task_context_entries
+ )
+ && (
+ this_port->owning_controller->logical_port_entries
+ < this_port->owning_controller->remote_node_entries
+ )
+ )
+ {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+
+/**
+ * This method takes the 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.
+ *
+ * @param[in] port This is the SCI_BASE_PORT object which is cast into a
+ * SCIC_SDS_PORT object.
+ *
+ * @return SCI_STATUS
+ * @retval SCI_FAILURE_UNSUPPORTED_PORT_CONFIGURATION This SCIC_SDS_PORT
+ * object could not be started because the port configuration is not
+ * valid.
+ * @retval SCI_SUCCESS the start request is successful and the SCIC_SDS_PORT
+ * object has transitioned to the SCI_BASE_PORT_STATE_READY.
+ */
+static
+SCI_STATUS scic_sds_port_stopped_state_start_handler(
+ SCI_BASE_PORT_T *port
+)
+{
+ U32 phy_mask;
+ SCI_STATUS status = SCI_SUCCESS;
+ SCIC_SDS_PORT_T *this_port = (SCIC_SDS_PORT_T *)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;
+ }
+
+ this_port->timer_handle = scic_cb_timer_create(
+ scic_sds_port_get_controller(this_port),
+ scic_sds_port_timeout_handler,
+ this_port
+ );
+
+ if (this_port->timer_handle == SCI_INVALID_HANDLE)
+ {
+ return SCI_FAILURE_INSUFFICIENT_RESOURCES;
+ }
+
+ if (scic_sds_port_requires_scheduler_workaround(this_port))
+ {
+ if (this_port->reserved_rni == SCU_DUMMY_INDEX)
+ {
+ this_port->reserved_rni =
+ scic_sds_remote_node_table_allocate_remote_node(
+ &this_port->owning_controller->available_remote_nodes, 1
+ );
+
+ if (this_port->reserved_rni != SCU_DUMMY_INDEX)
+ {
+ scic_sds_port_construct_dummy_rnc(
+ this_port,
+ this_port->reserved_rni
+ );
+ }
+ else
+ {
+ status = SCI_FAILURE_INSUFFICIENT_RESOURCES;
+ }
+ }
+
+ if (this_port->reserved_tci == SCU_DUMMY_INDEX)
+ {
+ // Allocate a TCI and remove the sequence nibble
+ this_port->reserved_tci =
+ scic_controller_allocate_io_tag(this_port->owning_controller);
+
+ if (this_port->reserved_tci != SCU_DUMMY_INDEX)
+ {
+ scic_sds_port_construct_dummy_task(this_port, this_port->reserved_tci);
+ }
+ else
+ {
+ status = SCI_FAILURE_INSUFFICIENT_RESOURCES;
+ }
+ }
+ }
+
+ if (status == SCI_SUCCESS)
+ {
+ 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
+ );
+ }
+ else
+ {
+ status = SCI_FAILURE;
+ }
+ }
+
+ if (status != SCI_SUCCESS)
+ {
+ scic_sds_port_destroy_dummy_resources(this_port);
+ }
+
+ return status;
+}
+
+/**
+ * This method takes the SCIC_SDS_PORT that is in a stopped state and handles
+ * a stop request. This function takes no action.
+ *
+ * @param[in] port This is the SCI_BASE_PORT object which is cast into a
+ * SCIC_SDS_PORT object.
+ *
+ * @return SCI_STATUS
+ * @retval SCI_SUCCESS the stop request is successful as the SCIC_SDS_PORT
+ * object is already stopped.
+ */
+static
+SCI_STATUS scic_sds_port_stopped_state_stop_handler(
+ SCI_BASE_PORT_T *port
+)
+{
+ // We are already stopped so there is nothing to do here
+ return SCI_SUCCESS;
+}
+
+/**
+ * This method takes the SCIC_SDS_PORT that is in a stopped state and handles
+ * the destruct request. The stopped state is the only state in which the
+ * SCIC_SDS_PORT can be destroyed. This function causes the port object to
+ * transition to the SCI_BASE_PORT_STATE_FINAL.
+ *
+ * @param[in] port This is the SCI_BASE_PORT object which is cast into a
+ * SCIC_SDS_PORT object.
+ *
+ * @return SCI_STATUS
+ * @retval SCI_SUCCESS
+ */
+static
+SCI_STATUS scic_sds_port_stopped_state_destruct_handler(
+ SCI_BASE_PORT_T *port
+)
+{
+ SCIC_SDS_PORT_T *this_port = (SCIC_SDS_PORT_T *)port;
+
+ sci_base_state_machine_stop(&this_port->parent.state_machine);
+
+ return SCI_SUCCESS;
+}
+
+/**
+ * This method takes the 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.
+ *
+ * @param[in] port This is the SCI_BASE_PORT object which is cast into a
+ * SCIC_SDS_PORT object.
+ * @param[in] phy This is the SCI_BASE_PHY object which is cast into a
+ * SCIC_SDS_PHY object.
+ *
+ * @return SCI_STATUS
+ * @retval SCI_FAILURE_UNSUPPORTED_PORT_CONFIGURATION is returned when the phy
+ * can not be added to the port.
+ * @retval SCI_SUCCESS if the phy is added to the port.
+ */
+static
+SCI_STATUS scic_sds_port_stopped_state_add_phy_handler(
+ SCI_BASE_PORT_T *port,
+ SCI_BASE_PHY_T *phy
+)
+{
+ SCIC_SDS_PORT_T * this_port = (SCIC_SDS_PORT_T *)port;
+ SCIC_SDS_PHY_T * this_phy = (SCIC_SDS_PHY_T *)phy;
+ SCI_SAS_ADDRESS_T 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)
+ {
+ SCI_SAS_ADDRESS_T 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);
+}
+
+
+/**
+ * This method takes the 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.
+ *
+ * @param[in] port This is the SCI_BASE_PORT object which is cast into a
+ * SCIC_SDS_PORT object.
+ * @param[in] phy This is the SCI_BASE_PHY object which is cast into a
+ * SCIC_SDS_PHY object.
+ *
+ * @return SCI_STATUS
+ * @retval SCI_FAILURE_UNSUPPORTED_PORT_CONFIGURATION is returned when the phy
+ * can not be added to the port.
+ * @retval SCI_SUCCESS if the phy is added to the port.
+ */
+static
+SCI_STATUS scic_sds_port_stopped_state_remove_phy_handler(
+ SCI_BASE_PORT_T *port,
+ SCI_BASE_PHY_T *phy
+)
+{
+ SCIC_SDS_PORT_T *this_port = (SCIC_SDS_PORT_T *)port;
+ SCIC_SDS_PHY_T *this_phy = (SCIC_SDS_PHY_T *)phy;
+
+ return scic_sds_port_clear_phy(this_port, this_phy);
+}
+
+//****************************************************************************
+//* READY STATE HANDLERS
+//****************************************************************************
+
+//****************************************************************************
+//* RESETTING STATE HANDLERS
+//****************************************************************************
+
+//****************************************************************************
+//* STOPPING STATE HANDLERS
+//****************************************************************************
+
+/**
+ * This method takes the 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.
+ *
+ * @param[in] port This is the SCIC_SDS_PORT object on which the io request
+ * count will be decremented.
+ * @param[in] device This is the SCIC_SDS_REMOTE_DEVICE object to which the io
+ * request is being directed. This parameter is not required to
+ * complete this operation.
+ * @param[in] io_request This is the request that is being completed on this
+ * port object. This parameter is not required to complete this
+ * operation.
+ *
+ * @return SCI_STATUS
+ * @retval SCI_SUCCESS
+ */
+static
+SCI_STATUS scic_sds_port_stopping_state_complete_io_handler(
+ SCIC_SDS_PORT_T *port,
+ SCIC_SDS_REMOTE_DEVICE_T *device,
+ SCIC_SDS_REQUEST_T *io_request
+)
+{
+ SCIC_SDS_PORT_T *this_port = (SCIC_SDS_PORT_T *)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
+//****************************************************************************
+
+/**
+ * This method will stop a failed port. This causes a transition to the
+ * stopping state.
+ *
+ * @param[in] port This is the port object which is being requested to stop.
+ *
+ * @return SCI_STATUS
+ * @retval SCI_SUCCESS
+ */
+static
+SCI_STATUS scic_sds_port_reset_state_stop_handler(
+ SCI_BASE_PORT_T *port
+)
+{
+ SCIC_SDS_PORT_T *this_port = (SCIC_SDS_PORT_T *)port;
+
+ sci_base_state_machine_change_state(
+ &this_port->parent.state_machine,
+ SCI_BASE_PORT_STATE_STOPPING
+ );
+
+ return SCI_SUCCESS;
+}
+
+/**
+ * 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.
+ *
+ * @param[in] port This is the SCI_BASE_PORT object which is cast into a
+ * SCIC_SDS_PORT object.
+ *
+ * @return SCI_STATUS
+ * @retval SCI_SUCCESS
+ */
+static
+void scic_sds_port_reset_state_link_up_handler(
+ SCIC_SDS_PORT_T *this_port,
+ SCIC_SDS_PHY_T *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, TRUE);
+}
+
+/**
+ * This method process link down notifications that occur during a
+ * port reset operation. Link downs can occur during the reset operation.
+ *
+ * @param[in] port This is the SCI_BASE_PORT object which is cast into a
+ * SCIC_SDS_PORT object.
+ *
+ * @return SCI_STATUS
+ * @retval SCI_SUCCESS
+ */
+static
+void scic_sds_port_reset_state_link_down_handler(
+ SCIC_SDS_PORT_T *this_port,
+ SCIC_SDS_PHY_T *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);
+}
+
+// ---------------------------------------------------------------------------
+
+SCIC_SDS_PORT_STATE_HANDLER_T
+ 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 method will enable the SCU Port Task Scheduler for this port object
+ * but will leave the port task scheduler in a suspended state.
+ *
+ * @param[in] this_port This is the port object which to suspend.
+ *
+ * @return none
+ */
+static
+void scic_sds_port_enable_port_task_scheduler(
+ SCIC_SDS_PORT_T *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 method will disable the SCU port task scheduler for this port
+ * object.
+ *
+ * @param[in] this_port This is the port object which to resume.
+ *
+ * @return none
+ */
+static
+void scic_sds_port_disable_port_task_scheduler(
+ SCIC_SDS_PORT_T *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);
+}
+
+/**
+ *
+ */
+static
+void scic_sds_port_post_dummy_remote_node(
+ SCIC_SDS_PORT_T *this_port
+)
+{
+ U32 command;
+ SCU_REMOTE_NODE_CONTEXT_T * rnc;
+
+ if (this_port->reserved_rni != SCU_DUMMY_INDEX)
+ {
+ rnc = &(this_port->owning_controller->remote_node_context_table[this_port->reserved_rni]);
+
+ rnc->ssp.is_valid = TRUE;
+
+ command = (
+ (SCU_CONTEXT_COMMAND_POST_RNC_32)
+ | (this_port->physical_port_index << SCU_CONTEXT_COMMAND_LOGICAL_PORT_SHIFT)
+ | (this_port->reserved_rni)
+ );
+
+ scic_sds_controller_post_request(this_port->owning_controller, command);
+
+ scic_cb_stall_execution(10);
+
+ command = (
+ (SCU_CONTEXT_COMMAND_POST_RNC_SUSPEND_TX_RX)
+ | (this_port->physical_port_index << SCU_CONTEXT_COMMAND_LOGICAL_PORT_SHIFT)
+ | (this_port->reserved_rni)
+ );
+
+ scic_sds_controller_post_request(this_port->owning_controller, command);
+}
+}
+
+/**
+ *
+ */
+static
+void scic_sds_port_invalidate_dummy_remote_node(
+ SCIC_SDS_PORT_T *this_port
+)
+{
+ U32 command;
+ SCU_REMOTE_NODE_CONTEXT_T * rnc;
+
+ if (this_port->reserved_rni != SCU_DUMMY_INDEX)
+ {
+ rnc = &(this_port->owning_controller->remote_node_context_table[this_port->reserved_rni]);
+
+ rnc->ssp.is_valid = FALSE;
+
+ scic_cb_stall_execution(10);
+
+ command = (
+ (SCU_CONTEXT_COMMAND_POST_RNC_INVALIDATE)
+ | (this_port->physical_port_index << SCU_CONTEXT_COMMAND_LOGICAL_PORT_SHIFT)
+ | (this_port->reserved_rni)
+ );
+
+ scic_sds_controller_post_request(this_port->owning_controller, command);
+}
+}
+
+//******************************************************************************
+//* PORT STATE METHODS
+//******************************************************************************
+
+/**
+ * This method will perform the actions required by the SCIC_SDS_PORT on
+ * entering the SCI_BASE_PORT_STATE_STOPPED. This function sets the stopped
+ * state handlers for the SCIC_SDS_PORT object and disables the port task
+ * scheduler in the hardware.
+ *
+ * @param[in] object This is the SCI_BASE_OBJECT which is cast to a
+ * SCIC_SDS_PORT object.
+ *
+ * @return none
+ */
+static
+void scic_sds_port_stopped_state_enter(
+ SCI_BASE_OBJECT_T *object
+)
+{
+ SCIC_SDS_PORT_T *this_port;
+ this_port = (SCIC_SDS_PORT_T *)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);
+ }
+}
+
+/**
+ * This method will perform the actions required by the SCIC_SDS_PORT on
+ * exiting the SCI_BASE_STATE_STOPPED. This function enables the SCU hardware
+ * port task scheduler.
+ *
+ * @param[in] object This is the SCI_BASE_OBJECT which is cast to a
+ * SCIC_SDS_PORT object.
+ *
+ * @return none
+ */
+static
+void scic_sds_port_stopped_state_exit(
+ SCI_BASE_OBJECT_T *object
+)
+{
+ SCIC_SDS_PORT_T *this_port;
+ this_port = (SCIC_SDS_PORT_T *)object;
+
+ // Enable and suspend the port task scheduler
+ scic_sds_port_enable_port_task_scheduler(this_port);
+}
+
+/**
+ * This method will perform the actions required by the SCIC_SDS_PORT on
+ * entering the SCI_BASE_PORT_STATE_READY. This function sets the ready state
+ * handlers for the SCIC_SDS_PORT object, reports the port object as not ready
+ * and starts the ready substate machine.
+ *
+ * @param[in] object This is the SCI_BASE_OBJECT which is cast to a
+ * SCIC_SDS_PORT object.
+ *
+ * @return none
+ */
+static
+void scic_sds_port_ready_state_enter(
+ SCI_BASE_OBJECT_T *object
+)
+{
+ SCIC_SDS_PORT_T *this_port;
+ this_port = (SCIC_SDS_PORT_T *)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
+ );
+ }
+
+ // Post and suspend the dummy remote node context for this
+ // port.
+ scic_sds_port_post_dummy_remote_node(this_port);
+
+ // Start the ready substate machine
+ sci_base_state_machine_start(
+ scic_sds_port_get_ready_substate_machine(this_port)
+ );
+}
+
+/**
+ * This method will perform the actions required by the SCIC_SDS_PORT on
+ * exiting the SCI_BASE_STATE_READY. This function does nothing.
+ *
+ * @param[in] object This is the SCI_BASE_OBJECT which is cast to a
+ * SCIC_SDS_PORT object.
+ *
+ * @return none
+ */
+static
+void scic_sds_port_ready_state_exit(
+ SCI_BASE_OBJECT_T *object
+)
+{
+ SCIC_SDS_PORT_T *this_port;
+ this_port = (SCIC_SDS_PORT_T *)object;
+
+ sci_base_state_machine_stop(&this_port->ready_substate_machine);
+
+ scic_cb_stall_execution(10);
+ scic_sds_port_invalidate_dummy_remote_node(this_port);
+}
+
+/**
+ * This method will perform the actions required by the SCIC_SDS_PORT on
+ * entering the SCI_BASE_PORT_STATE_RESETTING. This function sets the
+ * resetting state handlers for the SCIC_SDS_PORT object.
+ *
+ * @param[in] object This is the SCI_BASE_OBJECT which is cast to a
+ * SCIC_SDS_PORT object.
+ *
+ * @return none
+ */
+static
+void scic_sds_port_resetting_state_enter(
+ SCI_BASE_OBJECT_T *object
+)
+{
+ SCIC_SDS_PORT_T *this_port;
+ this_port = (SCIC_SDS_PORT_T *)object;
+
+ scic_sds_port_set_base_state_handlers(
+ this_port, SCI_BASE_PORT_STATE_RESETTING
+ );
+}
+
+/**
+ * This method will perform the actions required by the SCIC_SDS_PORT on
+ * exiting the SCI_BASE_STATE_RESETTING. This function does nothing.
+ *
+ * @param[in] object This is the SCI_BASE_OBJECT which is cast to a
+ * SCIC_SDS_PORT object.
+ *
+ * @return none
+ */
+static
+void scic_sds_port_resetting_state_exit(
+ SCI_BASE_OBJECT_T *object
+)
+{
+ SCIC_SDS_PORT_T *this_port;
+ this_port = (SCIC_SDS_PORT_T *)object;
+
+ scic_cb_timer_stop(
+ scic_sds_port_get_controller(this_port),
+ this_port->timer_handle
+ );
+}
+
+/**
+ * This method will perform the actions required by the SCIC_SDS_PORT on
+ * entering the SCI_BASE_PORT_STATE_STOPPING. This function sets the stopping
+ * state handlers for the SCIC_SDS_PORT object.
+ *
+ * @param[in] object This is the SCI_BASE_OBJECT which is cast to a
+ * SCIC_SDS_PORT object.
+ *
+ * @return none
+ */
+static
+void scic_sds_port_stopping_state_enter(
+ SCI_BASE_OBJECT_T *object
+)
+{
+ SCIC_SDS_PORT_T *this_port;
+ this_port = (SCIC_SDS_PORT_T *)object;
+
+ scic_sds_port_set_base_state_handlers(
+ this_port, SCI_BASE_PORT_STATE_STOPPING
+ );
+
+ if (this_port->started_request_count == 0)
+ {
+ sci_base_state_machine_change_state(
+ &this_port->parent.state_machine,
+ SCI_BASE_PORT_STATE_STOPPED
+ );
+ }
+}
+
+/**
+ * This method will perform the actions required by the SCIC_SDS_PORT on
+ * exiting the SCI_BASE_STATE_STOPPING. This function does nothing.
+ *
+ * @param[in] object This is the SCI_BASE_OBJECT which is cast to a
+ * SCIC_SDS_PORT object.
+ *
+ * @return none
+ */
+static
+void scic_sds_port_stopping_state_exit(
+ SCI_BASE_OBJECT_T *object
+)
+{
+ SCIC_SDS_PORT_T *this_port;
+ this_port = (SCIC_SDS_PORT_T *)object;
+
+ scic_cb_timer_stop(
+ scic_sds_port_get_controller(this_port),
+ this_port->timer_handle
+ );
+
+ scic_cb_timer_destroy(
+ scic_sds_port_get_controller(this_port),
+ this_port->timer_handle
+ );
+ this_port->timer_handle = NULL;
+
+ scic_sds_port_destroy_dummy_resources(this_port);
+}
+
+/**
+ * This method will perform the actions required by the SCIC_SDS_PORT on
+ * entering the SCI_BASE_PORT_STATE_STOPPING. This function sets the stopping
+ * state handlers for the SCIC_SDS_PORT object.
+ *
+ * @param[in] object This is the SCI_BASE_OBJECT which is cast to a
+ * SCIC_SDS_PORT object.
+ *
+ * @return none
+ */
+static
+void scic_sds_port_failed_state_enter(
+ SCI_BASE_OBJECT_T *object
+)
+{
+ SCIC_SDS_PORT_T *this_port;
+ this_port = (SCIC_SDS_PORT_T *)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
+ );
+}
+
+// ---------------------------------------------------------------------------
+
+SCI_BASE_STATE_T scic_sds_port_state_table[SCI_BASE_PORT_MAX_STATES] =
+{
+ {
+ SCI_BASE_PORT_STATE_STOPPED,
+ scic_sds_port_stopped_state_enter,
+ scic_sds_port_stopped_state_exit
+ },
+ {
+ SCI_BASE_PORT_STATE_STOPPING,
+ scic_sds_port_stopping_state_enter,
+ scic_sds_port_stopping_state_exit
+ },
+ {
+ SCI_BASE_PORT_STATE_READY,
+ scic_sds_port_ready_state_enter,
+ scic_sds_port_ready_state_exit
+ },
+ {
+ SCI_BASE_PORT_STATE_RESETTING,
+ scic_sds_port_resetting_state_enter,
+ scic_sds_port_resetting_state_exit
+ },
+ {
+ SCI_BASE_PORT_STATE_FAILED,
+ scic_sds_port_failed_state_enter,
+ NULL
+ }
+};
+
+//******************************************************************************
+//* PORT READY SUB-STATE MACHINE
+//******************************************************************************
+
+//****************************************************************************
+//* READY SUBSTATE HANDLERS
+//****************************************************************************
+
+/**
+ * This method is the general ready state stop handler for the SCIC_SDS_PORT
+ * object. This function will transition the ready substate machine to its
+ * final state.
+ *
+ * @param[in] port This is the SCI_BASE_PORT object which is cast into a
+ * SCIC_SDS_PORT object.
+ *
+ * @return SCI_STATUS
+ * @retval SCI_SUCCESS
+ */
+static
+SCI_STATUS scic_sds_port_ready_substate_stop_handler(
+ SCI_BASE_PORT_T *port
+)
+{
+ SCIC_SDS_PORT_T *this_port = (SCIC_SDS_PORT_T *)port;
+
+ sci_base_state_machine_change_state(
+ &this_port->parent.state_machine,
+ SCI_BASE_PORT_STATE_STOPPING
+ );
+
+ return SCI_SUCCESS;
+}
+
+/**
+ * This method is the general ready substate complete io handler for the
+ * SCIC_SDS_PORT object. This function decrments the outstanding request
+ * count for this port object.
+ *
+ * @param[in] port This is the SCI_BASE_PORT object which is cast into a
+ * SCIC_SDS_PORT object.
+ * @param[in] device This is the SCI_BASE_REMOTE_DEVICE object which is not
+ * used in this function.
+ * @param[in] io_request This is the SCI_BASE_REQUEST object which is not used
+ * in this function.
+ *
+ * @return SCI_STATUS
+ * @retval SCI_SUCCESS
+ */
+static
+SCI_STATUS scic_sds_port_ready_substate_complete_io_handler(
+ SCIC_SDS_PORT_T *port,
+ struct SCIC_SDS_REMOTE_DEVICE *device,
+ struct SCIC_SDS_REQUEST *io_request
+)
+{
+ SCIC_SDS_PORT_T *this_port = (SCIC_SDS_PORT_T *)port;
+
+ scic_sds_port_decrement_request_count(this_port);
+
+ return SCI_SUCCESS;
+}
+
+static
+SCI_STATUS scic_sds_port_ready_substate_add_phy_handler(
+ SCI_BASE_PORT_T *port,
+ SCI_BASE_PHY_T *phy
+)
+{
+ SCIC_SDS_PORT_T * this_port = (SCIC_SDS_PORT_T *)port;
+ SCIC_SDS_PHY_T * this_phy = (SCIC_SDS_PHY_T *)phy;
+ 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, FALSE);
+
+ 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
+SCI_STATUS scic_sds_port_ready_substate_remove_phy_handler(
+ SCI_BASE_PORT_T *port,
+ SCI_BASE_PHY_T *phy
+)
+{
+ SCIC_SDS_PORT_T * this_port = (SCIC_SDS_PORT_T *)port;
+ SCIC_SDS_PHY_T * this_phy = (SCIC_SDS_PHY_T *)phy;
+ 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 method is the ready waiting substate link up handler for the
+ * SCIC_SDS_PORT object. This methos will report the link up condition for
+ * this port and will transition to the ready operational substate.
+ *
+ * @param[in] this_port This is the SCIC_SDS_PORT object that which has a phy
+ * that has gone link up.
+ * @param[in] the_phy This is the SCIC_SDS_PHY object that has gone link up.
+ *
+ * @return none
+ */
+static
+void scic_sds_port_ready_waiting_substate_link_up_handler(
+ SCIC_SDS_PORT_T *this_port,
+ SCIC_SDS_PHY_T *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, TRUE);
+
+ sci_base_state_machine_change_state(
+ &this_port->ready_substate_machine,
+ SCIC_SDS_PORT_READY_SUBSTATE_OPERATIONAL
+ );
+}
+
+/**
+ * This method is the ready waiting substate start io handler for the
+ * SCIC_SDS_PORT object. The port object can not accept new requests so the
+ * request is failed.
+ *
+ * @param[in] port This is the SCI_BASE_PORT object which is cast into a
+ * SCIC_SDS_PORT object.
+ * @param[in] device This is the SCI_BASE_REMOTE_DEVICE object which is not
+ * used in this request.
+ * @param[in] io_request This is the SCI_BASE_REQUEST object which is not used
+ * in this function.
+ *
+ * @return SCI_STATUS
+ * @retval SCI_FAILURE_INVALID_STATE
+ */
+static
+SCI_STATUS scic_sds_port_ready_waiting_substate_start_io_handler(
+ SCIC_SDS_PORT_T *port,
+ SCIC_SDS_REMOTE_DEVICE_T *device,
+ SCIC_SDS_REQUEST_T *io_request
+)
+{
+ return SCI_FAILURE_INVALID_STATE;
+}
+
+//****************************************************************************
+//* READY SUBSTATE OPERATIONAL HANDLERS
+//****************************************************************************
+
+/**
+ * This method will casue the port to reset.
+ *
+ * @param[in] port This is the SCI_BASE_PORT object which is cast into a
+ * SCIC_SDS_PORT object.
+ * @param[in] timeout This is the timeout for the reset request to complete.
+ *
+ * @return SCI_STATUS
+ * @retval SCI_SUCCESS
+ */
+static
+SCI_STATUS scic_sds_port_ready_operational_substate_reset_handler(
+ SCI_BASE_PORT_T * port,
+ U32 timeout
+)
+{
+ SCI_STATUS status = SCI_FAILURE_INVALID_PHY;
+ U32 phy_index;
+ SCIC_SDS_PORT_T * this_port = (SCIC_SDS_PORT_T *)port;
+ SCIC_SDS_PHY_T * 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;
+}
+
+/**
+ * This method is the ready operational substate link up handler for the
+ * SCIC_SDS_PORT object. This function notifies the SCI User that the phy has
+ * gone link up.
+ *
+ * @param[in] this_port This is the SCIC_SDS_PORT object that which has a phy
+ * that has gone link up.
+ * @param[in] the_phy This is the SCIC_SDS_PHY object that has gone link up.
+ *
+ * @return none
+ */
+static
+void scic_sds_port_ready_operational_substate_link_up_handler(
+ SCIC_SDS_PORT_T *this_port,
+ SCIC_SDS_PHY_T *the_phy
+)
+{
+ scic_sds_port_general_link_up_handler(this_port, the_phy, TRUE, TRUE);
+}
+
+/**
+ * This method is the ready operational substate link down handler for the
+ * 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.
+ *
+ * @param[in] this_port This is the SCIC_SDS_PORT object that which has a phy
+ * that has gone link down.
+ * @param[in] the_phy This is the SCIC_SDS_PHY object that has gone link down.
+ *
+ * @return none
+ */
+static
+void scic_sds_port_ready_operational_substate_link_down_handler(
+ SCIC_SDS_PORT_T *this_port,
+ SCIC_SDS_PHY_T *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
+ );
+ }
+}
+
+/**
+ * This method is the ready operational substate start io handler for the
+ * SCIC_SDS_PORT object. This function incremetns the outstanding request
+ * count for this port object.
+ *
+ * @param[in] port This is the SCI_BASE_PORT object which is cast into a
+ * SCIC_SDS_PORT object.
+ * @param[in] device This is the SCI_BASE_REMOTE_DEVICE object which is not
+ * used in this function.
+ * @param[in] io_request This is the SCI_BASE_REQUEST object which is not used
+ * in this function.
+ *
+ * @return SCI_STATUS
+ * @retval SCI_SUCCESS
+ */
+static
+SCI_STATUS scic_sds_port_ready_operational_substate_start_io_handler(
+ SCIC_SDS_PORT_T *port,
+ SCIC_SDS_REMOTE_DEVICE_T *device,
+ SCIC_SDS_REQUEST_T *io_request
+)
+{
+ SCIC_SDS_PORT_T *this_port = (SCIC_SDS_PORT_T *)port;
+
+ scic_sds_port_increment_request_count(this_port);
+
+ return SCI_SUCCESS;
+}
+
+//****************************************************************************
+//* READY SUBSTATE OPERATIONAL HANDLERS
+//****************************************************************************
+
+/**
+ * This is the default method for a port add phy request. It will report a
+ * warning and exit.
+ *
+ * @param[in] port This is the SCI_BASE_PORT object which is cast into a
+ * SCIC_SDS_PORT object.
+ *
+ * @return SCI_STATUS
+ * @retval SCI_FAILURE_INVALID_STATE
+ */
+static
+SCI_STATUS scic_sds_port_ready_configuring_substate_add_phy_handler(
+ SCI_BASE_PORT_T *port,
+ SCI_BASE_PHY_T *phy
+)
+{
+ SCIC_SDS_PORT_T * this_port = (SCIC_SDS_PORT_T *)port;
+ SCIC_SDS_PHY_T * this_phy = (SCIC_SDS_PHY_T *)phy;
+ 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, FALSE);
+
+ // 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;
+}
+
+/**
+ * This is the default method for a port remove phy request. It will report a
+ * warning and exit.
+ *
+ * @param[in] port This is the SCI_BASE_PORT object which is cast into a
+ * SCIC_SDS_PORT object.
+ *
+ * @return SCI_STATUS
+ * @retval SCI_FAILURE_INVALID_STATE
+ */
+static
+SCI_STATUS scic_sds_port_ready_configuring_substate_remove_phy_handler(
+ SCI_BASE_PORT_T *port,
+ SCI_BASE_PHY_T *phy
+)
+{
+ SCIC_SDS_PORT_T * this_port = (SCIC_SDS_PORT_T *)port;
+ SCIC_SDS_PHY_T * this_phy = (SCIC_SDS_PHY_T *)phy;
+ 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;
+}
+
+/**
+ * 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.
+ *
+ * @param[in] port This is the port that is being requested to complete
+ * the io request.
+ * @param[in] device This is the device on which the io is completing.
+ * @param[in] io_request This is the io request that is completing.
+ */
+static
+SCI_STATUS scic_sds_port_ready_configuring_substate_complete_io_handler(
+ SCIC_SDS_PORT_T *port,
+ SCIC_SDS_REMOTE_DEVICE_T *device,
+ SCIC_SDS_REQUEST_T *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;
+}
+
+// ---------------------------------------------------------------------------
+
+SCIC_SDS_PORT_STATE_HANDLER_T
+ 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
+ }
+};
+
+/**
+ * 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 method will susped the port task scheduler for this port object.
+ *
+ * @param[in] this_port This is the SCIC_SDS_PORT object to suspend.
+ *
+ * @return none
+ */
+void scic_sds_port_suspend_port_task_scheduler(
+ SCIC_SDS_PORT_T *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);
+}
+
+/**
+ * This method will resume the port task scheduler for this port object.
+ *
+ * @param[in] this_port This is the SCIC_SDS_PORT object to resume.
+ *
+ * @return none
+ */
+void scic_sds_port_resume_port_task_scheduler(
+ SCIC_SDS_PORT_T *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);
+}
+
+/**
+ * This routine will post the dummy request. This will prevent the hardware
+ * scheduler from posting new requests to the front of the scheduler queue
+ * causing a starvation problem for currently ongoing requests.
+ *
+ * @parm[in] this_port The port on which the task must be posted.
+ *
+ * @return none
+ */
+static
+void scic_sds_port_post_dummy_request(
+ SCIC_SDS_PORT_T *this_port
+)
+{
+ U32 command;
+ SCU_TASK_CONTEXT_T * task_context;
+
+ if (this_port->reserved_tci != SCU_DUMMY_INDEX)
+ {
+ task_context = scic_sds_controller_get_task_context_buffer(
+ this_port->owning_controller,
+ this_port->reserved_tci
+ );
+
+ task_context->abort = 0;
+
+ command = (
+ (SCU_CONTEXT_COMMAND_REQUEST_TYPE_POST_TC)
+ | (this_port->physical_port_index << SCU_CONTEXT_COMMAND_LOGICAL_PORT_SHIFT)
+ | (this_port->reserved_tci)
+ );
+
+ scic_sds_controller_post_request(this_port->owning_controller, command);
+}
+}
+
+/**
+ * This routine will abort the dummy request. This will alow the hardware to
+ * power down parts of the silicon to save power.
+ *
+ * @parm[in] this_port The port on which the task must be aborted.
+ *
+ * @return none
+ */
+static
+void scic_sds_port_abort_dummy_request(
+ SCIC_SDS_PORT_T *this_port
+)
+{
+ U32 command;
+ SCU_TASK_CONTEXT_T * task_context;
+
+ if (this_port->reserved_tci != SCU_DUMMY_INDEX)
+ {
+ task_context = scic_sds_controller_get_task_context_buffer(
+ this_port->owning_controller,
+ this_port->reserved_tci
+ );
+
+ task_context->abort = 1;
+
+ command = (
+ (SCU_CONTEXT_COMMAND_REQUEST_POST_TC_ABORT)
+ | (this_port->physical_port_index << SCU_CONTEXT_COMMAND_LOGICAL_PORT_SHIFT)
+ | (this_port->reserved_tci)
+ );
+
+ scic_sds_controller_post_request(this_port->owning_controller, command);
+}
+}
+
+//******************************************************************************
+//* PORT READY SUBSTATE METHODS
+//******************************************************************************
+
+/**
+ * This method will perform the actions required by the 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.
+ *
+ * @param[in] object This is the SCI_BASE_OBJECT which is cast to a
+ * SCIC_SDS_PORT object.
+ *
+ * @return none
+ */
+static
+void scic_sds_port_ready_substate_waiting_enter(
+ SCI_BASE_OBJECT_T *object
+)
+{
+ SCIC_SDS_PORT_T *this_port = (SCIC_SDS_PORT_T *)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
+ );
+ }
+}
+
+/**
+ * This method will perform the actions required by the SCIC_SDS_PORT on
+ * exiting the SCIC_SDS_PORT_READY_SUBSTATE_WAITING. This function resume the
+ * PTSG that was suspended at the entry of this state.
+ *
+ * @param[in] object This is the SCI_BASE_OBJECT which is cast to a
+ * SCIC_SDS_PORT object.
+ *
+ * @return none
+ */
+static
+void scic_sds_port_ready_substate_waiting_exit(
+ SCI_BASE_OBJECT_T *object
+)
+{
+ SCIC_SDS_PORT_T *this_port = (SCIC_SDS_PORT_T *)object;
+ scic_sds_port_resume_port_task_scheduler(this_port);
+}
+
+/**
+ * This method will perform the actions required by the 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.
+ *
+ * @param[in] object This is the SCI_BASE_OBJECT which is cast to a
+ * SCIC_SDS_PORT object.
+ *
+ * @return none
+ */
+static
+void scic_sds_port_ready_substate_operational_enter(
+ SCI_BASE_OBJECT_T *object
+)
+{
+ U32 index;
+ SCIC_SDS_PORT_T *this_port = (SCIC_SDS_PORT_T *)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]
+ );
+
+ //if the bit at the index location for active phy mask is set and
+ //enabled_phy_mask is not set then resume the phy
+ if ( ( (this_port->active_phy_mask ^ this_port->enabled_phy_mask) & (1 << index) ) != 0)
+ {
+ scic_sds_port_resume_phy (
+ this_port,
+ this_port->phy_table[index]
+ );
+ }
+ }
+ }
+
+ scic_sds_port_update_viit_entry(this_port);
+
+ // Post the dummy task for the port so the hardware can schedule
+ // io correctly
+ scic_sds_port_post_dummy_request(this_port);
+}
+
+/**
+ * This method will perform the actions required by the 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.
+ *
+ * @param[in] object This is the SCI_BASE_OBJECT which is cast to a
+ * SCIC_SDS_PORT object.
+ *
+ * @return none
+ */
+static
+void scic_sds_port_ready_substate_operational_exit(
+ SCI_BASE_OBJECT_T *object
+)
+{
+ SCIC_SDS_PORT_T *this_port = (SCIC_SDS_PORT_T *)object;
+
+ // Kill the dummy task for this port if it has not yet posted
+ // the hardware will treat this as a NOP and just return abort
+ // complete.
+ scic_sds_port_abort_dummy_request(this_port);
+
+ scic_cb_port_not_ready(
+ scic_sds_port_get_controller(this_port),
+ this_port,
+ this_port->not_ready_reason
+ );
+}
+
+//******************************************************************************
+//* PORT READY CONFIGURING METHODS
+//******************************************************************************
+
+/**
+ * This method will perform the actions required by the 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.
+ *
+ * @param[in] object This is the SCI_BASE_OBJECT which is cast to a
+ * SCIC_SDS_PORT object.
+ *
+ * @return none
+ */
+static
+void scic_sds_port_ready_substate_configuring_enter(
+ SCI_BASE_OBJECT_T *object
+)
+{
+ SCIC_SDS_PORT_T *this_port = (SCIC_SDS_PORT_T *)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
+ );
+ }
+ //do not wait for IO to go to 0 in this state.
+ else
+ {
+ sci_base_state_machine_change_state(
+ &this_port->ready_substate_machine,
+ SCIC_SDS_PORT_READY_SUBSTATE_OPERATIONAL
+ );
+ }
+}
+
+// ---------------------------------------------------------------------------
+
+SCI_BASE_STATE_T
+ scic_sds_port_ready_substate_table[SCIC_SDS_PORT_READY_MAX_SUBSTATES] =
+{
+ {
+ SCIC_SDS_PORT_READY_SUBSTATE_WAITING,
+ scic_sds_port_ready_substate_waiting_enter,
+ scic_sds_port_ready_substate_waiting_exit
+ },
+ {
+ SCIC_SDS_PORT_READY_SUBSTATE_OPERATIONAL,
+ scic_sds_port_ready_substate_operational_enter,
+ scic_sds_port_ready_substate_operational_exit
+ },
+ {
+ SCIC_SDS_PORT_READY_SUBSTATE_CONFIGURING,
+ scic_sds_port_ready_substate_configuring_enter,
+ NULL
+ }
+};
+
diff --git a/sys/dev/isci/scil/scic_sds_port.h b/sys/dev/isci/scil/scic_sds_port.h
new file mode 100644
index 0000000..c9ac9c4
--- /dev/null
+++ b/sys/dev/isci/scil/scic_sds_port.h
@@ -0,0 +1,595 @@
+/*-
+ * 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.
+ *
+ * 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.
+ *
+ * $FreeBSD$
+ */
+#ifndef _SCIC_SDS_PORT_H_
+#define _SCIC_SDS_PORT_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif // __cplusplus
+
+/**
+ * @file
+ *
+ * @brief This file contains the structures, constants and prototypes for the
+ * SCIC_SDS_PORT_T object.
+ */
+
+#include <dev/isci/scil/sci_controller_constants.h>
+#include <dev/isci/scil/intel_sas.h>
+#include <dev/isci/scil/sci_base_port.h>
+#include <dev/isci/scil/sci_base_phy.h>
+#include <dev/isci/scil/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.
+ */
+typedef struct SCIC_SDS_PORT
+{
+ /**
+ * This field is the oommon base port object.
+ */
+ SCI_BASE_PORT_T 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 phy mask for the port that are already part of the port.
+ */
+ U8 enabled_phy_mask;
+
+ U16 reserved_rni;
+ U16 reserved_tci;
+
+ /**
+ * 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.
+ */
+ SCI_BASE_STATE_MACHINE_T ready_substate_machine;
+
+ #ifdef SCI_LOGGING
+ /**
+ * This field is the ready substate machine logger. It logs each state
+ * transition request in the ready substate machine.
+ */
+ SCI_BASE_STATE_MACHINE_LOGGER_T ready_substate_machine_logger;
+ #endif
+
+ /// Memory mapped hardware register space
+
+ /**
+ * This field is the pointer to the port task scheduler registers for the SCU
+ * hardware.
+ */
+ SCU_PORT_TASK_SCHEDULER_REGISTERS_T *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.
+ */
+ SCU_VIIT_ENTRY_T *viit_registers;
+
+} SCIC_SDS_PORT_T;
+
+
+typedef SCI_STATUS (*SCIC_SDS_PORT_EVENT_HANDLER_T)(struct SCIC_SDS_PORT *, U32);
+
+typedef 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 SCI_STATUS (*SCIC_SDS_PORT_IO_REQUEST_HANDLER_T)(
+ struct SCIC_SDS_PORT *,
+ struct SCIC_SDS_REMOTE_DEVICE *,
+ struct SCIC_SDS_REQUEST *);
+
+typedef struct SCIC_SDS_PORT_STATE_HANDLER
+{
+ SCI_BASE_PORT_STATE_HANDLER_T 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;
+
+} SCIC_SDS_PORT_STATE_HANDLER_T;
+
+extern SCI_BASE_STATE_T scic_sds_port_state_table[];
+extern SCI_BASE_STATE_T scic_sds_port_ready_substate_table[];
+
+extern SCIC_SDS_PORT_STATE_HANDLER_T scic_sds_port_state_handler_table[];
+extern SCIC_SDS_PORT_STATE_HANDLER_T scic_sds_port_ready_substate_handler_table[];
+
+/**
+ * Helper macro to get the owning controller of this port
+ */
+#define scic_sds_port_get_controller(this_port) \
+ ((this_port)->owning_controller)
+
+/**
+ * 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)
+
+/**
+ * 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)])
+
+/**
+ * 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)
+
+/**
+ * Helper macro to set the port object state handlers
+ */
+#define scic_sds_port_set_state_handlers(this_port, handlers) \
+ ((this_port)->state_handlers = (handlers))
+
+/**
+ * This macro returns the physical port index for this port object
+ */
+#define scic_sds_port_get_index(this_port) \
+ ((this_port)->physical_port_index)
+
+/**
+ * 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
+/**
+ * @brief 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.
+ *
+ * @param[in] this_port
+ */
+void scic_sds_port_decrement_request_count(
+ SCIC_SDS_PORT_T *this_port
+);
+#else
+/**
+ * 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
+
+/**
+ * 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 \
+ )
+
+/**
+ * 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)
+
+// ---------------------------------------------------------------------------
+
+U32 scic_sds_port_get_object_size(void);
+
+U32 scic_sds_port_get_min_timer_count(void);
+
+U32 scic_sds_port_get_max_timer_count(void);
+
+// ---------------------------------------------------------------------------
+
+#ifdef SCI_LOGGING
+void scic_sds_port_initialize_state_logging(
+ SCIC_SDS_PORT_T *this_port
+);
+#else
+#define scic_sds_port_initialize_state_logging(x)
+#endif
+
+// ---------------------------------------------------------------------------
+
+void scic_sds_port_construct(
+ SCIC_SDS_PORT_T *this_port,
+ U8 port_index,
+ struct SCIC_SDS_CONTROLLER *owning_controller
+);
+
+SCI_STATUS scic_sds_port_initialize(
+ SCIC_SDS_PORT_T *this_port,
+ void *port_task_scheduler_registers,
+ void *port_configuration_regsiter,
+ void *viit_registers
+);
+
+// ---------------------------------------------------------------------------
+
+SCI_STATUS scic_sds_port_add_phy(
+ struct SCIC_SDS_PORT * this_port,
+ struct SCIC_SDS_PHY * the_phy
+);
+
+SCI_STATUS scic_sds_port_remove_phy(
+ struct SCIC_SDS_PORT * this_port,
+ struct SCIC_SDS_PHY * the_phy
+);
+
+void scic_sds_port_setup_transports(
+ SCIC_SDS_PORT_T * this_port,
+ U32 device_id
+);
+
+void scic_sds_port_activate_phy(
+ SCIC_SDS_PORT_T *this_port,
+ struct SCIC_SDS_PHY *phy,
+ BOOL do_notify_user,
+ BOOL do_resume_phy
+);
+
+void scic_sds_port_deactivate_phy(
+ SCIC_SDS_PORT_T *this_port,
+ struct SCIC_SDS_PHY *phy,
+ BOOL do_notify_user
+);
+
+struct SCIC_SDS_PHY * scic_sds_port_get_a_connected_phy(
+ SCIC_SDS_PORT_T * this_port
+);
+
+void scic_sds_port_invalid_link_up(
+ SCIC_SDS_PORT_T *this_port,
+ struct SCIC_SDS_PHY *phy
+);
+
+void scic_sds_port_general_link_up_handler(
+ SCIC_SDS_PORT_T *this_port,
+ struct SCIC_SDS_PHY *the_phy,
+ BOOL do_notify_user,
+ BOOL do_resume_phy
+);
+
+BOOL scic_sds_port_link_detected(
+ SCIC_SDS_PORT_T *this_port,
+ struct SCIC_SDS_PHY *phy
+);
+
+void scic_sds_port_link_up(
+ SCIC_SDS_PORT_T *this_port,
+ struct SCIC_SDS_PHY *phy
+);
+
+void scic_sds_port_link_down(
+ SCIC_SDS_PORT_T *this_port,
+ struct SCIC_SDS_PHY *phy
+);
+
+// ---------------------------------------------------------------------------
+
+void scic_sds_port_timeout_handler(
+ void *port
+);
+
+// ---------------------------------------------------------------------------
+
+SCI_STATUS scic_sds_port_start_io(
+ SCIC_SDS_PORT_T *this_port,
+ struct SCIC_SDS_REMOTE_DEVICE *the_device,
+ struct SCIC_SDS_REQUEST *the_io_request
+);
+
+SCI_STATUS scic_sds_port_complete_io(
+ SCIC_SDS_PORT_T *this_port,
+ struct SCIC_SDS_REMOTE_DEVICE *the_device,
+ struct SCIC_SDS_REQUEST *the_io_request
+);
+
+// ---------------------------------------------------------------------------
+
+void scic_sds_port_update_viit_entry(
+ SCIC_SDS_PORT_T *this_port
+);
+
+// ---------------------------------------------------------------------------
+
+SCI_STATUS scic_sds_port_default_start_handler(
+ SCI_BASE_PORT_T *port
+);
+
+SCI_STATUS scic_sds_port_default_stop_handler(
+ SCI_BASE_PORT_T *port
+);
+
+SCI_STATUS scic_sds_port_default_destruct_handler(
+ SCI_BASE_PORT_T *port
+);
+
+SCI_STATUS scic_sds_port_default_reset_handler(
+ SCI_BASE_PORT_T * port,
+ U32 timeout
+);
+
+SCI_STATUS scic_sds_port_default_add_phy_handler(
+ SCI_BASE_PORT_T *port,
+ SCI_BASE_PHY_T *phy
+);
+
+SCI_STATUS scic_sds_port_default_remove_phy_handler(
+ SCI_BASE_PORT_T *port,
+ SCI_BASE_PHY_T *phy
+);
+
+SCI_STATUS scic_sds_port_default_frame_handler(
+ struct SCIC_SDS_PORT * port,
+ U32 frame_index
+);
+
+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
+);
+
+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
+);
+
+SCI_STATUS scic_sds_port_default_complete_io_handler(
+ struct SCIC_SDS_PORT *port,
+ struct SCIC_SDS_REMOTE_DEVICE *device,
+ struct SCIC_SDS_REQUEST *io_request
+);
+
+SCI_SAS_LINK_RATE scic_sds_port_get_max_allowed_speed(
+ SCIC_SDS_PORT_T * 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(
+ SCIC_SDS_PORT_T *this_port,
+ U32 phy_index
+);
+
+BOOL scic_sds_port_is_phy_mask_valid(
+ SCIC_SDS_PORT_T * this_port,
+ U32 phy_mask
+);
+
+U32 scic_sds_port_get_phys(
+ SCIC_SDS_PORT_T * this_port
+);
+
+void scic_sds_port_get_sas_address(
+ SCIC_SDS_PORT_T * this_port,
+ SCI_SAS_ADDRESS_T * sas_address
+);
+
+void scic_sds_port_get_attached_sas_address(
+ SCIC_SDS_PORT_T * this_port,
+ SCI_SAS_ADDRESS_T * sas_address
+);
+
+void scic_sds_port_get_attached_protocols(
+ SCIC_SDS_PORT_T * this_port,
+ SCI_SAS_IDENTIFY_ADDRESS_FRAME_PROTOCOLS_T * protocols
+);
+
+SCI_STATUS scic_sds_port_set_phy(
+ struct SCIC_SDS_PORT *port,
+ struct SCIC_SDS_PHY *phy
+);
+
+SCI_STATUS scic_sds_port_clear_phy(
+ struct SCIC_SDS_PORT *port,
+ struct SCIC_SDS_PHY *phy
+);
+
+void scic_sds_port_suspend_port_task_scheduler(
+ SCIC_SDS_PORT_T *this_port
+);
+
+void scic_sds_port_resume_port_task_scheduler(
+ SCIC_SDS_PORT_T *this_port
+);
+
+void scic_sds_port_release_resource(
+ struct SCIC_SDS_CONTROLLER * controller,
+ struct SCIC_SDS_PORT * port
+);
+
+#ifdef __cplusplus
+}
+#endif // __cplusplus
+
+
+#endif // _SCIC_SDS_PORT_H_
diff --git a/sys/dev/isci/scil/scic_sds_port_configuration_agent.c b/sys/dev/isci/scil/scic_sds_port_configuration_agent.c
new file mode 100644
index 0000000..d02d9e2
--- /dev/null
+++ b/sys/dev/isci/scil/scic_sds_port_configuration_agent.c
@@ -0,0 +1,1133 @@
+/*-
+ * 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.
+ *
+ * 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 <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/**
+ * @file
+ *
+ * @brief This file contains the implementation for the public and protected
+ * methods for the port configuration agent.
+ */
+
+#include <dev/isci/scil/scic_controller.h>
+#include <dev/isci/scil/scic_sds_logger.h>
+#include <dev/isci/scil/scic_sds_controller.h>
+#include <dev/isci/scil/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 (250)
+
+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
+//******************************************************************************
+
+/**
+ * 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
+ *
+ * @param[in] address_one A SAS Address to be compared.
+ * @param[in] address_two A SAS Address to be compared.
+ *
+ * @return 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(
+ SCI_SAS_ADDRESS_T address_one,
+ SCI_SAS_ADDRESS_T 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;
+}
+
+/**
+ * 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.
+ *
+ * @param[in] controller The controller object used for the port search.
+ * @param[in] phy The phy object to match.
+ *
+ * @return The port address or the SCI_INVALID_HANDLE if there is no matching
+ * port.
+ *
+ * @retvalue port address if the port can be found to match the phy.
+ * @retvalue SCI_INVALID_HANDLE if there is no matching port for the phy.
+ */
+static
+SCIC_SDS_PORT_T * scic_sds_port_configuration_agent_find_port(
+ SCIC_SDS_CONTROLLER_T * controller,
+ SCIC_SDS_PHY_T * phy
+)
+{
+ U8 port_index;
+ SCI_PORT_HANDLE_T port_handle;
+ SCI_SAS_ADDRESS_T port_sas_address;
+ SCI_SAS_ADDRESS_T port_attached_device_address;
+ SCI_SAS_ADDRESS_T phy_sas_address;
+ SCI_SAS_ADDRESS_T phy_attached_device_address;
+
+ SCIC_LOG_TRACE((
+ sci_base_object_get_logger(controller),
+ SCIC_LOG_OBJECT_CONTROLLER | SCIC_LOG_OBJECT_PORT | SCIC_LOG_OBJECT_PHY,
+ "scic_sds_port_confgiruation_agent_find_port(0x%08x, 0x%08x) enter\n",
+ controller, phy
+ ));
+
+ // 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)
+ {
+ SCIC_SDS_PORT_T * port = (SCIC_SDS_PORT_T *)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;
+}
+
+/**
+ * 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)
+ *
+ * @param[in] controller This is the controller object that contains the
+ * port agent
+ * @param[in] port_agent This is the port configruation agent for
+ * the controller.
+ *
+ * @return SCI_STATUS
+ * @retval SCI_SUCCESS the port configuration is valid for this
+ * port configuration agent.
+ * @retval SCI_FAILURE_UNSUPPORTED_PORT_CONFIGURATION the port configuration
+ * is not valid for this port configuration agent.
+ */
+static
+SCI_STATUS scic_sds_port_configuration_agent_validate_ports(
+ SCIC_SDS_CONTROLLER_T * controller,
+ SCIC_SDS_PORT_CONFIGURATION_AGENT_T * port_agent
+)
+{
+#if !defined(ARLINGTON_BUILD)
+ SCI_SAS_ADDRESS_T first_address;
+ SCI_SAS_ADDRESS_T second_address;
+
+ SCIC_LOG_TRACE((
+ sci_base_object_get_logger(controller),
+ SCIC_LOG_OBJECT_CONTROLLER | SCIC_LOG_OBJECT_PORT,
+ "scic_sds_port_configuration_agent_validate_ports(0x%08x, 0x%08x) enter\n",
+ controller, port_agent
+ ));
+
+ // 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;
+ }
+ }
+#endif // !defined(ARLINGTON_BUILD)
+
+ 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.
+ *
+ * @param[in] controller This is the controller that contains the PHYs to
+ * be verified.
+ */
+static
+SCI_STATUS scic_sds_mpc_agent_validate_phy_configuration(
+ SCIC_SDS_CONTROLLER_T * controller,
+ SCIC_SDS_PORT_CONFIGURATION_AGENT_T * port_agent
+)
+{
+ U32 phy_mask;
+ U32 assigned_phy_mask;
+ SCI_SAS_ADDRESS_T sas_address;
+ SCI_SAS_ADDRESS_T phy_assigned_address;
+ U8 port_index;
+ U8 phy_index;
+
+ assigned_phy_mask = 0;
+ sas_address.high = 0;
+ sas_address.low = 0;
+
+ SCIC_LOG_TRACE((
+ sci_base_object_get_logger(controller),
+ SCIC_LOG_OBJECT_CONTROLLER | SCIC_LOG_OBJECT_PORT,
+ "scic_sds_mpc_agent_validate_phy_configuration(0x%08x, 0x%08x) enter\n",
+ controller, port_agent
+ ));
+
+ 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.
+ *
+ * @param[in] controller This is the core controller object which is used
+ * to obtain the port configuration agent.
+ */
+static
+void scic_sds_mpc_agent_timeout_handler(
+ void * object
+)
+{
+ U8 index;
+ SCIC_SDS_CONTROLLER_T * controller = (SCIC_SDS_CONTROLLER_T *)object;
+ SCIC_SDS_PORT_CONFIGURATION_AGENT_T * port_agent = &controller->port_agent;
+ U16 configure_phy_mask;
+
+ SCIC_LOG_TRACE((
+ sci_base_object_get_logger(controller),
+ SCIC_LOG_OBJECT_CONTROLLER | SCIC_LOG_OBJECT_PORT,
+ "scic_sds_mpc_agent_timeout_handler(0x%08x) enter\n",
+ controller
+ ));
+
+ 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]
+ );
+ }
+ }
+}
+
+/**
+ * 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.
+ *
+ * @param[in] controller This is the controller object that receives the
+ * link up notification.
+ * @param[in] port This is the port object associated with the phy. If the
+ * is no associated port this is an SCI_INVALID_HANDLE.
+ * @param[in] phy This is the phy object which has gone ready.
+ *
+ * @note 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(
+ SCIC_SDS_CONTROLLER_T * controller,
+ SCIC_SDS_PORT_CONFIGURATION_AGENT_T * port_agent,
+ SCIC_SDS_PORT_T * port,
+ SCIC_SDS_PHY_T * phy
+)
+{
+ SCIC_LOG_TRACE((
+ sci_base_object_get_logger(controller),
+ SCIC_LOG_OBJECT_CONTROLLER | SCIC_LOG_OBJECT_PORT | SCIC_LOG_OBJECT_PHY,
+ "scic_sds_mpc_agent_link_up(0x%08x, 0x%08x, 0x%08x, 0x%08x) enter\n",
+ controller, port_agent, port, 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));
+ }
+ }
+}
+
+/**
+ * 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.
+ *
+ * @param[in] controller This is the controller object that receives the
+ * link down notification.
+ * @param[in] 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.
+ * @param[in] phy This is the phy object which has gone link down.
+ *
+ * @note 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(
+ SCIC_SDS_CONTROLLER_T * controller,
+ SCIC_SDS_PORT_CONFIGURATION_AGENT_T * port_agent,
+ SCIC_SDS_PORT_T * port,
+ SCIC_SDS_PHY_T * phy
+)
+{
+ SCIC_LOG_TRACE((
+ sci_base_object_get_logger(controller),
+ SCIC_LOG_OBJECT_CONTROLLER | SCIC_LOG_OBJECT_PORT | SCIC_LOG_OBJECT_PHY,
+ "scic_sds_mpc_agent_link_down(0x%08x, 0x%08x, 0x%08x, 0x%08x) enter\n",
+ controller, port_agent, port, 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
+SCI_STATUS scic_sds_apc_agent_validate_phy_configuration(
+ SCIC_SDS_CONTROLLER_T * controller,
+ SCIC_SDS_PORT_CONFIGURATION_AGENT_T * port_agent
+)
+{
+ U8 phy_index;
+ U8 port_index;
+ SCI_SAS_ADDRESS_T sas_address;
+ SCI_SAS_ADDRESS_T phy_assigned_address;
+
+ SCIC_LOG_TRACE((
+ sci_base_object_get_logger(controller),
+ SCIC_LOG_OBJECT_CONTROLLER | SCIC_LOG_OBJECT_PORT,
+ "scic_sds_apc_agent_validate_phy_configuration(0x%08x, 0x%08x) enter\n",
+ controller, port_agent
+ ));
+
+ 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);
+}
+
+/**
+ * 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.
+ *
+ * @param[in] controller This is the controller that to which the port
+ * agent is assigned.
+ * @param[in] port_agent This is the port agent that is requesting the
+ * timer start operation.
+ * @param[in] phy This is the phy that has caused the timer operation to
+ * be scheduled.
+ * @param[in] timeout This is the timeout in ms.
+ */
+static
+void scic_sds_apc_agent_start_timer(
+ SCIC_SDS_CONTROLLER_T * controller,
+ SCIC_SDS_PORT_CONFIGURATION_AGENT_T * port_agent,
+ SCIC_SDS_PHY_T * phy,
+ U32 timeout
+)
+{
+ SCIC_LOG_TRACE((
+ sci_base_object_get_logger(controller),
+ SCIC_LOG_OBJECT_CONTROLLER | SCIC_LOG_OBJECT_PORT | SCIC_LOG_OBJECT_PHY,
+ "scic_sds_apc_agent_start_timer(0x%08x, 0x%08x, 0x%08x, 0x%08x) enter\n",
+ controller, port_agent, phy, 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);
+}
+
+/**
+ * This method handles the automatic port configuration for link up notifications.
+ *
+ * @param[in] controller This is the controller object that receives the
+ * link up notification.
+ * @param[in] phy This is the phy object which has gone link up.
+ * @param[in] start_timer This tells the routine if it should start the timer for
+ * any phys that might be added to a port in the future.
+ */
+static
+void scic_sds_apc_agent_configure_ports(
+ SCIC_SDS_CONTROLLER_T * controller,
+ SCIC_SDS_PORT_CONFIGURATION_AGENT_T * port_agent,
+ SCIC_SDS_PHY_T * phy,
+ BOOL start_timer
+)
+{
+ U8 port_index;
+ SCI_STATUS status;
+ SCIC_SDS_PORT_T * port;
+ SCI_PORT_HANDLE_T port_handle;
+ enum SCIC_SDS_APC_ACTIVITY apc_activity = SCIC_SDS_APC_SKIP_PHY;
+
+ SCIC_LOG_TRACE((
+ sci_base_object_get_logger(controller),
+ SCIC_LOG_OBJECT_CONTROLLER | SCIC_LOG_OBJECT_PORT | SCIC_LOG_OBJECT_PHY,
+ "scic_sds_apc_agent_configure_ports(0x%08x, 0x%08x, 0x%08x, %d) enter\n",
+ controller, port_agent, phy, start_timer
+ ));
+
+ 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 = (SCIC_SDS_PORT_T *)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;
+ }
+}
+
+/**
+ * This method handles the automatic port configuration for link up notifications.
+ *
+ * @param[in] controller This is the controller object that receives the
+ * link up notification.
+ * @param[in] port This is the port object associated with the phy. If the
+ * is no associated port this is an SCI_INVALID_HANDLE.
+ * @param[in] phy This is the phy object which has gone link up.
+ *
+ * @note 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(
+ SCIC_SDS_CONTROLLER_T * controller,
+ SCIC_SDS_PORT_CONFIGURATION_AGENT_T * port_agent,
+ SCIC_SDS_PORT_T * port,
+ SCIC_SDS_PHY_T * phy
+)
+{
+ SCIC_LOG_TRACE((
+ sci_base_object_get_logger(controller),
+ SCIC_LOG_OBJECT_CONTROLLER | SCIC_LOG_OBJECT_PORT | SCIC_LOG_OBJECT_PHY,
+ "scic_sds_apc_agent_link_up(0x%08x, 0x%08x, 0x%08x, 0x%08x) enter\n",
+ controller, port_agent, port, phy
+ ));
+
+ //the phy is not the part of this port, configure the port with this phy
+ if (port == SCI_INVALID_HANDLE)
+ {
+ port_agent->phy_ready_mask |= (1 << scic_sds_phy_get_index(phy));
+
+ scic_sds_apc_agent_start_timer(
+ controller, port_agent, phy, SCIC_SDS_APC_WAIT_LINK_UP_NOTIFICATION
+ );
+ }
+ else
+ {
+ //the phy is already the part of the port
+
+ //if the PORT'S state is resetting then the link up is from port hard reset
+ //in this case, we need to tell the port that link up is recieved
+ if ( SCI_BASE_PORT_STATE_RESETTING
+ == port->parent.state_machine.current_state_id
+ )
+ {
+ //notify the port that port needs to be ready
+ port_agent->phy_ready_mask |= (1 << scic_sds_phy_get_index(phy));
+ scic_sds_port_link_up(port, phy);
+ }
+ else
+ {
+ ASSERT (0);
+ }
+ }
+}
+
+/**
+ * This method handles the automatic port configuration link down notifications.
+ * If this PHY is * not associated with a port there is no action taken.
+ *
+ * @param[in] controller This is the controller object that receives the
+ * link down notification.
+ * @param[in] port This is the port object associated with the phy. If the
+ * is no associated port this is an SCI_INVALID_HANDLE.
+ * @param[in] phy This is the phy object which has gone link down.
+ *
+ * @note 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(
+ SCIC_SDS_CONTROLLER_T * controller,
+ SCIC_SDS_PORT_CONFIGURATION_AGENT_T * port_agent,
+ SCIC_SDS_PORT_T * port,
+ SCIC_SDS_PHY_T * phy
+)
+{
+ SCIC_LOG_TRACE((
+ sci_base_object_get_logger(controller),
+ SCIC_LOG_OBJECT_CONTROLLER | SCIC_LOG_OBJECT_PORT | SCIC_LOG_OBJECT_PHY,
+ "scic_sds_apc_agent_link_down(0x%08x, 0x%08x, 0x%08x, 0x%08x) enter\n",
+ controller, port_agent, port, 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))
+ {
+ 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.
+ *
+ * @param[in] object This is actually the controller that needs to have the
+ * pending phys configured.
+ */
+static
+void scic_sds_apc_agent_timeout_handler(
+ void * object
+)
+{
+ U32 index;
+ SCIC_SDS_PORT_CONFIGURATION_AGENT_T * port_agent;
+ SCIC_SDS_CONTROLLER_T * controller = (SCIC_SDS_CONTROLLER_T *)object;
+ U16 configure_phy_mask;
+
+ port_agent = scic_sds_controller_get_port_configuration_agent(controller);
+
+ SCIC_LOG_TRACE((
+ sci_base_object_get_logger(controller),
+ SCIC_LOG_OBJECT_CONTROLLER | SCIC_LOG_OBJECT_PORT,
+ "scic_sds_apc_agent_timeout_handler(0x%08x) enter\n",
+ 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
+ );
+ }
+ }
+
+ //Notify the controller ports are configured.
+ if (
+ (port_agent->phy_ready_mask == port_agent->phy_configured_mask) &&
+ (controller->next_phy_to_start == SCI_MAX_PHYS) &&
+ (controller->phy_startup_timer_pending == FALSE)
+ )
+ {
+ // The controller has successfully finished the start process.
+ // Inform the SCI Core user and transition to the READY state.
+ if (scic_sds_controller_is_start_complete(controller) == TRUE)
+ {
+ scic_sds_controller_port_agent_configured_ports(controller);
+ }
+ }
+ }
+}
+
+//******************************************************************************
+// 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.
+ *
+ * @param[in] port_agent This is the port configuration agent for this
+ * controller object.
+ */
+void scic_sds_port_configuration_agent_construct(
+ SCIC_SDS_PORT_CONFIGURATION_AGENT_T * 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;
+ }
+}
+
+/**
+ * This method will construct the port configuration agent for this controller.
+ *
+ * @param[in] controller This is the controller object for which the port
+ * agent is being initialized.
+ *
+ * @param[in] port_agent This is the port configuration agent that is being
+ * initialized. The initialization path is handled differntly
+ * for the automatic port configuration agent and the manual port
+ * configuration agent.
+ *
+ * @return
+ */
+SCI_STATUS scic_sds_port_configuration_agent_initialize(
+ SCIC_SDS_CONTROLLER_T * controller,
+ SCIC_SDS_PORT_CONFIGURATION_AGENT_T * port_agent
+)
+{
+ SCI_STATUS status = SCI_SUCCESS;
+ enum SCIC_PORT_CONFIGURATION_MODE mode;
+
+ SCIC_LOG_TRACE((
+ sci_base_object_get_logger(controller),
+ SCIC_LOG_OBJECT_CONTROLLER | SCIC_LOG_OBJECT_PORT,
+ "scic_sds_port_configuration_agent_initialize(0x%08x, 0x%08x) enter\n",
+ controller, port_agent
+ ));
+
+ mode = controller->oem_parameters.sds1.controller.mode_type;
+
+ 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)
+ {
+ SCIC_LOG_ERROR((
+ sci_base_object_get_logger(controller),
+ SCIC_LOG_OBJECT_CONTROLLER,
+ "Controller 0x%x automatic port configuration agent could not get timer.\n",
+ controller
+ ));
+
+ status = SCI_FAILURE;
+ }
+
+ return status;
+}
+
+/**
+ * This method will destroy the port configuration agent for this controller.
+ *
+ * @param[in] controller This is the controller object for which the port
+ * agent is being destroyed.
+ *
+ * @param[in] port_agent This is the port configuration agent that is being
+ * destroyed.
+ *
+ * @return
+ */
+void scic_sds_port_configuration_agent_destroy(
+ SCIC_SDS_CONTROLLER_T * controller,
+ SCIC_SDS_PORT_CONFIGURATION_AGENT_T * port_agent
+)
+{
+ if (port_agent->timer_pending == TRUE)
+ {
+ scic_cb_timer_stop(controller, port_agent->timer);
+ }
+
+ scic_cb_timer_destroy(controller, port_agent->timer);
+
+ port_agent->timer_pending = FALSE;
+ port_agent->timer = NULL;
+}
+
+
+/**
+ * @brief This method release resources in for a scic port configuration agent.
+ *
+ * @param[in] controller This parameter specifies the core controller, one of
+ * its phy's resources are to be released.
+ * @param[in] this_phy This parameter specifies the phy whose resourse is to
+ * be released.
+ */
+void scic_sds_port_configuration_agent_release_resource(
+ SCIC_SDS_CONTROLLER_T * controller,
+ SCIC_SDS_PORT_CONFIGURATION_AGENT_T * port_agent
+)
+{
+ SCIC_LOG_TRACE((
+ sci_base_object_get_logger(controller),
+ SCIC_LOG_OBJECT_PORT,
+ "scic_sds_port_configuration_agent_release_resource(0x%x, 0x%x)\n",
+ controller, port_agent
+ ));
+
+ //Currently, the only resource to be released is a timer.
+ if (port_agent->timer != NULL)
+ {
+ scic_cb_timer_destroy(controller, port_agent->timer);
+ port_agent->timer = NULL;
+ }
+}
diff --git a/sys/dev/isci/scil/scic_sds_port_configuration_agent.h b/sys/dev/isci/scil/scic_sds_port_configuration_agent.h
new file mode 100644
index 0000000..37f5337
--- /dev/null
+++ b/sys/dev/isci/scil/scic_sds_port_configuration_agent.h
@@ -0,0 +1,128 @@
+/*-
+ * 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.
+ *
+ * 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.
+ *
+ * $FreeBSD$
+ */
+#ifndef _SCIC_SDS_PORT_CONFIGURATION_AGENT_H_
+#define _SCIC_SDS_PORT_CONFIGURATION_AGENT_H_
+
+/**
+ * @file
+ *
+ * @brief This file contains the structures, constants and prototypes used for
+ * the core controller automatic port configuration engine.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif // __cplusplus
+
+#include <dev/isci/scil/scic_sds_port.h>
+#include <dev/isci/scil/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;
+};
+
+typedef 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;
+
+} SCIC_SDS_PORT_CONFIGURATION_AGENT_T;
+
+void scic_sds_port_configuration_agent_construct(
+ SCIC_SDS_PORT_CONFIGURATION_AGENT_T * port_agent
+);
+
+SCI_STATUS scic_sds_port_configuration_agent_initialize(
+ struct SCIC_SDS_CONTROLLER * controller,
+ SCIC_SDS_PORT_CONFIGURATION_AGENT_T * port_agent
+);
+
+void scic_sds_port_configuration_agent_destroy(
+ struct SCIC_SDS_CONTROLLER * controller,
+ SCIC_SDS_PORT_CONFIGURATION_AGENT_T * port_agent
+);
+
+void scic_sds_port_configuration_agent_release_resource(
+ struct SCIC_SDS_CONTROLLER * controller,
+ SCIC_SDS_PORT_CONFIGURATION_AGENT_T * port_agent
+);
+
+#ifdef __cplusplus
+}
+#endif // __cplusplus
+
+#endif // _SCIC_SDS_PORT_CONFIGURATION_AGENT_H_
diff --git a/sys/dev/isci/scil/scic_sds_port_registers.h b/sys/dev/isci/scil/scic_sds_port_registers.h
new file mode 100644
index 0000000..3e56796
--- /dev/null
+++ b/sys/dev/isci/scil/scic_sds_port_registers.h
@@ -0,0 +1,139 @@
+/*-
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 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.
+ *
+ * $FreeBSD$
+ */
+#ifndef _SCIC_SDS_PORT_REGISTERS_H_
+#define _SCIC_SDS_PORT_REGISTERS_H_
+
+/**
+ * @file
+ *
+ * @brief This file contains a set of macros that assist in reading the SCU
+ * hardware registers.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif // __cplusplus
+
+/**
+ * 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 \
+ )
+
+/**
+ * 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) \
+ )
+
+//****************************************************************************
+//* Port Task Scheduler registers controlled by the port object
+//****************************************************************************
+
+/**
+ * Macro to read the port task scheduler control register
+ */
+#define SCU_PTSxCR_READ(port) \
+ scu_port_task_scheduler_read(port, control)
+
+/**
+ * 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
+//****************************************************************************
+
+/**
+ * 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) \
+ )
+
+/**
+ * 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] \
+ )
+
+#ifdef __cplusplus
+}
+#endif // __cplusplus
+
+#endif // _SCIC_SDS_PORT_REGISTERS_H_
diff --git a/sys/dev/isci/scil/scic_sds_remote_device.c b/sys/dev/isci/scil/scic_sds_remote_device.c
new file mode 100644
index 0000000..e683630
--- /dev/null
+++ b/sys/dev/isci/scil/scic_sds_remote_device.c
@@ -0,0 +1,2727 @@
+/*-
+ * 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.
+ *
+ * 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 <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/**
+ * @file
+ *
+ * @brief This file contains the implementation of remote device, it's
+ * methods and state machine.
+ */
+
+#include <dev/isci/scil/intel_sas.h>
+#include <dev/isci/scil/sci_util.h>
+#include <dev/isci/scil/scic_port.h>
+#include <dev/isci/scil/scic_phy.h>
+#include <dev/isci/scil/scic_remote_device.h>
+#include <dev/isci/scil/scic_sds_port.h>
+#include <dev/isci/scil/scic_sds_phy.h>
+#include <dev/isci/scil/scic_sds_remote_device.h>
+#include <dev/isci/scil/scic_sds_request.h>
+#include <dev/isci/scil/scic_sds_controller.h>
+#include <dev/isci/scil/scic_sds_logger.h>
+#include <dev/isci/scil/scic_user_callback.h>
+#include <dev/isci/scil/scic_controller.h>
+#include <dev/isci/scil/scic_sds_logger.h>
+#include <dev/isci/scil/scic_sds_remote_node_context.h>
+#include <dev/isci/scil/scu_event_codes.h>
+
+#define SCIC_SDS_REMOTE_DEVICE_RESET_TIMEOUT (1000)
+
+//*****************************************************************************
+//* CORE REMOTE DEVICE PUBLIC METHODS
+//*****************************************************************************
+
+U32 scic_remote_device_get_object_size(void)
+{
+ return sizeof(SCIC_SDS_REMOTE_DEVICE_T)
+ + sizeof(SCIC_SDS_REMOTE_NODE_CONTEXT_T);
+}
+
+// ---------------------------------------------------------------------------
+
+void scic_remote_device_construct(
+ SCI_PORT_HANDLE_T port,
+ void * remote_device_memory,
+ SCI_REMOTE_DEVICE_HANDLE_T * new_remote_device_handle
+)
+{
+ SCIC_SDS_REMOTE_DEVICE_T *this_device = (SCIC_SDS_REMOTE_DEVICE_T*)
+ remote_device_memory;
+ SCIC_SDS_PORT_T *the_port = (SCIC_SDS_PORT_T*) port;
+
+ SCIC_LOG_TRACE((
+ sci_base_object_get_logger(the_port),
+ SCIC_LOG_OBJECT_SSP_REMOTE_TARGET |
+ SCIC_LOG_OBJECT_STP_REMOTE_TARGET |
+ SCIC_LOG_OBJECT_SMP_REMOTE_TARGET,
+ "scic_remote_device_construct(0x%x, 0x%x, 0x%x) enter\n",
+ port, remote_device_memory, new_remote_device_handle
+ ));
+
+ memset(remote_device_memory, 0, sizeof(SCIC_SDS_REMOTE_DEVICE_T));
+
+ *new_remote_device_handle = this_device;
+ this_device->owning_port = the_port;
+ this_device->started_request_count = 0;
+ this_device->rnc = (SCIC_SDS_REMOTE_NODE_CONTEXT_T *)
+ ((char *)this_device + sizeof(SCIC_SDS_REMOTE_DEVICE_T));
+
+ sci_base_remote_device_construct(
+ &this_device->parent,
+ sci_base_object_get_logger(the_port),
+ scic_sds_remote_device_state_table
+ );
+
+ scic_sds_remote_node_context_construct(
+ this_device,
+ this_device->rnc,
+ SCIC_SDS_REMOTE_NODE_CONTEXT_INVALID_INDEX
+ );
+
+ sci_object_set_association(this_device->rnc, this_device);
+
+ scic_sds_remote_device_initialize_state_logging(this_device);
+}
+
+// ---------------------------------------------------------------------------
+
+SCI_STATUS scic_remote_device_da_construct(
+ SCI_REMOTE_DEVICE_HANDLE_T remote_device
+)
+{
+ SCI_STATUS status;
+ U16 remote_node_index;
+ SCIC_SDS_REMOTE_DEVICE_T *this_device = (SCIC_SDS_REMOTE_DEVICE_T*)
+ remote_device;
+ SCI_SAS_IDENTIFY_ADDRESS_FRAME_PROTOCOLS_T protocols;
+ SCIC_PORT_PROPERTIES_T properties;
+
+ SCIC_LOG_TRACE((
+ sci_base_object_get_logger(this_device->owning_port),
+ SCIC_LOG_OBJECT_SSP_REMOTE_TARGET |
+ SCIC_LOG_OBJECT_STP_REMOTE_TARGET |
+ SCIC_LOG_OBJECT_SMP_REMOTE_TARGET,
+ "scic_remote_device_da_construct(0x%x) enter\n",
+ remote_device
+ ));
+
+ // 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(this_device->owning_port,&protocols);
+ this_device->target_protocols.u.all = protocols.u.all;
+ this_device->is_direct_attached = TRUE;
+#if !defined(DISABLE_ATAPI)
+ this_device->is_atapi = scic_sds_remote_device_is_atapi(this_device);
+#endif
+
+ scic_port_get_properties(this_device->owning_port, &properties);
+ //Get accurate port width from port's phy mask for a DA device.
+ SCI_GET_BITS_SET_COUNT(properties.phy_mask, this_device->device_port_width);
+
+ status = scic_sds_controller_allocate_remote_node_context(
+ this_device->owning_port->owning_controller,
+ this_device,
+ &remote_node_index
+ );
+
+ if (status == SCI_SUCCESS)
+ {
+ scic_sds_remote_node_context_set_remote_node_index(
+ this_device->rnc, remote_node_index
+ );
+
+ scic_sds_port_get_attached_sas_address(
+ this_device->owning_port, &this_device->device_address
+ );
+
+ if (this_device->target_protocols.u.bits.attached_ssp_target)
+ {
+ this_device->has_ready_substate_machine = FALSE;
+ }
+ else if (this_device->target_protocols.u.bits.attached_stp_target)
+ {
+ this_device->has_ready_substate_machine = TRUE;
+
+ sci_base_state_machine_construct(
+ &this_device->ready_substate_machine,
+ &this_device->parent.parent,
+ scic_sds_stp_remote_device_ready_substate_table,
+ SCIC_SDS_STP_REMOTE_DEVICE_READY_SUBSTATE_IDLE
+ );
+ }
+ else if (this_device->target_protocols.u.bits.attached_smp_target)
+ {
+ this_device->has_ready_substate_machine = TRUE;
+
+ //add the SMP ready substate machine construction here
+ sci_base_state_machine_construct(
+ &this_device->ready_substate_machine,
+ &this_device->parent.parent,
+ scic_sds_smp_remote_device_ready_substate_table,
+ SCIC_SDS_SMP_REMOTE_DEVICE_READY_SUBSTATE_IDLE
+ );
+ }
+
+ this_device->connection_rate = scic_sds_port_get_max_allowed_speed(
+ this_device->owning_port
+ );
+
+ /// @todo Should I assign the port width by reading all of the phys on the port?
+ this_device->device_port_width = 1;
+ }
+
+ return status;
+}
+
+
+// ---------------------------------------------------------------------------
+
+void scic_sds_remote_device_get_info_from_smp_discover_response(
+ SCIC_SDS_REMOTE_DEVICE_T * this_device,
+ SMP_RESPONSE_DISCOVER_T * 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;
+}
+
+
+// ---------------------------------------------------------------------------
+
+SCI_STATUS scic_remote_device_ea_construct(
+ SCI_REMOTE_DEVICE_HANDLE_T remote_device,
+ SMP_RESPONSE_DISCOVER_T * discover_response
+)
+{
+ SCI_STATUS status;
+
+ SCIC_SDS_REMOTE_DEVICE_T *this_device;
+ SCIC_SDS_CONTROLLER_T *the_controller;
+
+ this_device = (SCIC_SDS_REMOTE_DEVICE_T *)remote_device;
+
+ SCIC_LOG_TRACE((
+ sci_base_object_get_logger(this_device->owning_port),
+ SCIC_LOG_OBJECT_SSP_REMOTE_TARGET |
+ SCIC_LOG_OBJECT_SMP_REMOTE_TARGET,
+ "scic_remote_device_ea_sas_construct0x%x, 0x%x) enter\n",
+ remote_device, discover_response
+ ));
+
+ the_controller = scic_sds_port_get_controller(this_device->owning_port);
+
+ scic_sds_remote_device_get_info_from_smp_discover_response(
+ this_device, discover_response
+ );
+
+ status = scic_sds_controller_allocate_remote_node_context(
+ the_controller,
+ this_device,
+ &this_device->rnc->remote_node_index
+ );
+
+ if (status == SCI_SUCCESS)
+ {
+ if (this_device->target_protocols.u.bits.attached_ssp_target)
+ {
+ this_device->has_ready_substate_machine = FALSE;
+ }
+ else if (this_device->target_protocols.u.bits.attached_smp_target)
+ {
+ this_device->has_ready_substate_machine = TRUE;
+
+ //add the SMP ready substate machine construction here
+ sci_base_state_machine_construct(
+ &this_device->ready_substate_machine,
+ &this_device->parent.parent,
+ scic_sds_smp_remote_device_ready_substate_table,
+ SCIC_SDS_SMP_REMOTE_DEVICE_READY_SUBSTATE_IDLE
+ );
+ }
+ else if (this_device->target_protocols.u.bits.attached_stp_target)
+ {
+ this_device->has_ready_substate_machine = TRUE;
+
+ sci_base_state_machine_construct(
+ &this_device->ready_substate_machine,
+ &this_device->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.
+ this_device->connection_rate = MIN(
+ scic_sds_port_get_max_allowed_speed( this_device->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?
+ this_device->device_port_width = 1;
+ }
+
+ return status;
+}
+
+// ---------------------------------------------------------------------------
+
+SCI_STATUS scic_remote_device_destruct(
+ SCI_REMOTE_DEVICE_HANDLE_T remote_device
+)
+{
+ SCIC_SDS_REMOTE_DEVICE_T *this_device;
+ this_device = (SCIC_SDS_REMOTE_DEVICE_T *)remote_device;
+
+ SCIC_LOG_TRACE((
+ sci_base_object_get_logger(this_device),
+ SCIC_LOG_OBJECT_SSP_REMOTE_TARGET |
+ SCIC_LOG_OBJECT_STP_REMOTE_TARGET |
+ SCIC_LOG_OBJECT_SMP_REMOTE_TARGET,
+ "scic_remote_device_destruct(0x%x) enter\n",
+ remote_device
+ ));
+
+ return this_device->state_handlers->parent.destruct_handler(&this_device->parent);
+}
+
+// ---------------------------------------------------------------------------
+
+#if !defined(DISABLE_WIDE_PORTED_TARGETS)
+
+SCI_STATUS scic_remote_device_set_port_width(
+ SCI_REMOTE_DEVICE_HANDLE_T remote_device,
+ U8 new_port_width
+)
+{
+ SCIC_SDS_REMOTE_DEVICE_T *this_device;
+
+ this_device = (SCIC_SDS_REMOTE_DEVICE_T *)remote_device;
+
+ SCIC_LOG_TRACE((
+ sci_base_object_get_logger(this_device),
+ SCIC_LOG_OBJECT_SSP_REMOTE_TARGET |
+ SCIC_LOG_OBJECT_STP_REMOTE_TARGET |
+ SCIC_LOG_OBJECT_SMP_REMOTE_TARGET,
+ "scic_remote_device_set_port_width(0x%x, 0x%x) enter\n",
+ remote_device, new_port_width
+ ));
+
+ if(new_port_width != 0)
+ {
+ this_device->device_port_width = new_port_width;
+
+ return SCI_SUCCESS;
+ }
+ else
+ return SCI_FAILURE;
+}
+
+// ---------------------------------------------------------------------------
+
+U8 scic_remote_device_get_port_width(
+ SCI_REMOTE_DEVICE_HANDLE_T remote_device
+)
+{
+ SCIC_SDS_REMOTE_DEVICE_T *this_device;
+
+ this_device = (SCIC_SDS_REMOTE_DEVICE_T *)remote_device;
+
+ SCIC_LOG_TRACE((
+ sci_base_object_get_logger(this_device),
+ SCIC_LOG_OBJECT_SSP_REMOTE_TARGET |
+ SCIC_LOG_OBJECT_STP_REMOTE_TARGET |
+ SCIC_LOG_OBJECT_SMP_REMOTE_TARGET,
+ "scic_remote_device_get_port_width(0x%x) enter\n",
+ remote_device
+ ));
+
+ return (U8)this_device->device_port_width;
+}
+
+#endif // !defined(DISABLE_WIDE_PORTED_TARGETS)
+
+// ---------------------------------------------------------------------------
+
+SCI_STATUS scic_remote_device_start(
+ SCI_REMOTE_DEVICE_HANDLE_T remote_device,
+ U32 timeout
+)
+{
+ SCIC_SDS_REMOTE_DEVICE_T *this_device;
+ this_device = (SCIC_SDS_REMOTE_DEVICE_T *)remote_device;
+
+ SCIC_LOG_TRACE((
+ sci_base_object_get_logger(this_device),
+ SCIC_LOG_OBJECT_SSP_REMOTE_TARGET |
+ SCIC_LOG_OBJECT_STP_REMOTE_TARGET |
+ SCIC_LOG_OBJECT_SMP_REMOTE_TARGET,
+ "scic_remote_device_start(0x%x, 0x%x) enter\n",
+ remote_device, timeout
+ ));
+
+ return this_device->state_handlers->parent.start_handler(&this_device->parent);
+}
+
+// ---------------------------------------------------------------------------
+
+SCI_STATUS scic_remote_device_stop(
+ SCI_REMOTE_DEVICE_HANDLE_T remote_device,
+ U32 timeout
+)
+{
+ SCIC_SDS_REMOTE_DEVICE_T *this_device;
+ this_device = (SCIC_SDS_REMOTE_DEVICE_T *)remote_device;
+
+ SCIC_LOG_TRACE((
+ sci_base_object_get_logger(this_device),
+ SCIC_LOG_OBJECT_SSP_REMOTE_TARGET |
+ SCIC_LOG_OBJECT_STP_REMOTE_TARGET |
+ SCIC_LOG_OBJECT_SMP_REMOTE_TARGET,
+ "scic_remote_device_stop(0x%x, 0x%x) enter\n",
+ remote_device, timeout
+ ));
+
+ return this_device->state_handlers->parent.stop_handler(&this_device->parent);
+}
+
+/**
+ * This method invokes the remote device reset handler.
+ *
+ * @param[in] this_device The remote device for which the reset is being
+ * requested.
+ *
+ * @return SCI_STATUS
+ */
+SCI_STATUS scic_remote_device_reset(
+ SCI_REMOTE_DEVICE_HANDLE_T remote_device
+)
+{
+ SCIC_SDS_REMOTE_DEVICE_T *this_device;
+ this_device = (SCIC_SDS_REMOTE_DEVICE_T *)remote_device;
+
+ SCIC_LOG_TRACE((
+ sci_base_object_get_logger(this_device),
+ SCIC_LOG_OBJECT_SSP_REMOTE_TARGET |
+ SCIC_LOG_OBJECT_STP_REMOTE_TARGET |
+ SCIC_LOG_OBJECT_SMP_REMOTE_TARGET,
+ "scic_remote_device_reset(0x%x) enter\n",
+ remote_device
+ ));
+
+ return this_device->state_handlers->parent.reset_handler(&this_device->parent);
+}
+
+/**
+ * This method invokes the remote device reset handler.
+ *
+ * @param[in] this_device The remote device for which the reset is being
+ * requested.
+ *
+ * @return SCI_STATUS
+ */
+SCI_STATUS scic_remote_device_reset_complete(
+ SCI_REMOTE_DEVICE_HANDLE_T remote_device
+)
+{
+ SCIC_SDS_REMOTE_DEVICE_T *this_device;
+ this_device = (SCIC_SDS_REMOTE_DEVICE_T *)remote_device;
+
+ SCIC_LOG_TRACE((
+ sci_base_object_get_logger(this_device),
+ SCIC_LOG_OBJECT_SSP_REMOTE_TARGET |
+ SCIC_LOG_OBJECT_STP_REMOTE_TARGET |
+ SCIC_LOG_OBJECT_SMP_REMOTE_TARGET,
+ "scic_remote_device_reset_complete(0x%x) enter\n",
+ remote_device
+ ));
+
+ return this_device->state_handlers->parent.reset_complete_handler(&this_device->parent);
+}
+
+/**
+ * This method invokes the remote device reset handler.
+ *
+ * @param[in] this_device The remote device for which the reset is being
+ * requested.
+ *
+ * @return SCI_STATUS
+ */
+U32 scic_remote_device_get_suggested_reset_timeout(
+ SCI_REMOTE_DEVICE_HANDLE_T remote_device
+)
+{
+ SCIC_SDS_REMOTE_DEVICE_T *this_device;
+ this_device = (SCIC_SDS_REMOTE_DEVICE_T *)remote_device;
+
+ SCIC_LOG_TRACE((
+ sci_base_object_get_logger(this_device),
+ SCIC_LOG_OBJECT_SSP_REMOTE_TARGET |
+ SCIC_LOG_OBJECT_STP_REMOTE_TARGET |
+ SCIC_LOG_OBJECT_SMP_REMOTE_TARGET,
+ "scic_remote_device_get_suggested_reset_timeout(0x%x) enter\n",
+ remote_device
+ ));
+
+ if (this_device->target_protocols.u.bits.attached_stp_target)
+ {
+ return SCIC_SDS_SIGNATURE_FIS_TIMEOUT;
+ }
+
+ return SCIC_SDS_REMOTE_DEVICE_RESET_TIMEOUT;
+}
+
+// ---------------------------------------------------------------------------
+
+SCI_STATUS scic_remote_device_set_max_connection_rate(
+ SCI_REMOTE_DEVICE_HANDLE_T remote_device,
+ SCI_SAS_LINK_RATE connection_rate
+)
+{
+ SCIC_SDS_REMOTE_DEVICE_T *this_device;
+ this_device = (SCIC_SDS_REMOTE_DEVICE_T *)remote_device;
+
+ SCIC_LOG_TRACE((
+ sci_base_object_get_logger(this_device),
+ SCIC_LOG_OBJECT_SSP_REMOTE_TARGET |
+ SCIC_LOG_OBJECT_STP_REMOTE_TARGET |
+ SCIC_LOG_OBJECT_SMP_REMOTE_TARGET,
+ "scic_remote_device_set_max_connection_rate(0x%x, 0x%x) enter\n",
+ remote_device, connection_rate
+ ));
+
+ this_device->connection_rate = connection_rate;
+
+ return SCI_SUCCESS;
+}
+
+// ---------------------------------------------------------------------------
+
+SCI_SAS_LINK_RATE scic_remote_device_get_connection_rate(
+ SCI_REMOTE_DEVICE_HANDLE_T remote_device
+)
+{
+ SCIC_SDS_REMOTE_DEVICE_T *this_device;
+ this_device = (SCIC_SDS_REMOTE_DEVICE_T *)remote_device;
+
+ SCIC_LOG_TRACE((
+ sci_base_object_get_logger(this_device),
+ SCIC_LOG_OBJECT_SSP_REMOTE_TARGET |
+ SCIC_LOG_OBJECT_STP_REMOTE_TARGET |
+ SCIC_LOG_OBJECT_SMP_REMOTE_TARGET,
+ "scic_remote_device_get_connection_rate(0x%x) enter\n",
+ remote_device
+ ));
+
+ return this_device->connection_rate;
+}
+
+// ---------------------------------------------------------------------------
+
+void scic_remote_device_get_protocols(
+ SCI_REMOTE_DEVICE_HANDLE_T remote_device,
+ SMP_DISCOVER_RESPONSE_PROTOCOLS_T * protocols
+)
+{
+ SCIC_SDS_REMOTE_DEVICE_T * this_device = (SCIC_SDS_REMOTE_DEVICE_T *)
+ remote_device;
+
+ SCIC_LOG_TRACE((
+ sci_base_object_get_logger(this_device),
+ SCIC_LOG_OBJECT_SSP_REMOTE_TARGET |
+ SCIC_LOG_OBJECT_STP_REMOTE_TARGET |
+ SCIC_LOG_OBJECT_SMP_REMOTE_TARGET,
+ "scic_remote_device_get_protocols(0x%x) enter\n",
+ remote_device
+ ));
+
+ protocols->u.all = this_device->target_protocols.u.all;
+}
+
+// ---------------------------------------------------------------------------
+
+void scic_remote_device_get_sas_address(
+ SCI_REMOTE_DEVICE_HANDLE_T remote_device,
+ SCI_SAS_ADDRESS_T * sas_address
+)
+{
+ SCIC_SDS_REMOTE_DEVICE_T *this_device;
+ this_device = (SCIC_SDS_REMOTE_DEVICE_T *)remote_device;
+
+ SCIC_LOG_TRACE((
+ sci_base_object_get_logger(this_device),
+ SCIC_LOG_OBJECT_SSP_REMOTE_TARGET |
+ SCIC_LOG_OBJECT_STP_REMOTE_TARGET |
+ SCIC_LOG_OBJECT_SMP_REMOTE_TARGET,
+ "scic_remote_device_get_sas_address(0x%x, 0x%x) enter\n",
+ remote_device, sas_address
+ ));
+
+ sas_address->low = this_device->device_address.low;
+ sas_address->high = this_device->device_address.high;
+}
+
+// ---------------------------------------------------------------------------
+#if !defined(DISABLE_ATAPI)
+BOOL scic_remote_device_is_atapi(
+ SCI_REMOTE_DEVICE_HANDLE_T device_handle
+)
+{
+ return ((SCIC_SDS_REMOTE_DEVICE_T *)device_handle)->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)
+
+/**
+ * @brief This method returns the minimum number of timers required for all
+ * remote devices.
+ *
+ * @return U32
+ */
+U32 scic_sds_remote_device_get_min_timer_count(void)
+{
+ return SCIC_SDS_REMOTE_DEVICE_MINIMUM_TIMER_COUNT;
+}
+
+/**
+ * @brief This method returns the maximum number of timers requried for all
+ * remote devices.
+ *
+ * @return U32
+ */
+U32 scic_sds_remote_device_get_max_timer_count(void)
+{
+ return SCIC_SDS_REMOTE_DEVICE_MAXIMUM_TIMER_COUNT;
+}
+
+// ---------------------------------------------------------------------------
+
+#ifdef SCI_LOGGING
+/**
+ * This method will enable and turn on state transition logging for the remote
+ * device object.
+ *
+ * @param[in] this_device The device for which state transition logging is to
+ * be enabled.
+ *
+ * @return Nothing
+ */
+void scic_sds_remote_device_initialize_state_logging(
+ SCIC_SDS_REMOTE_DEVICE_T *this_device
+)
+{
+ sci_base_state_machine_logger_initialize(
+ &this_device->parent.state_machine_logger,
+ &this_device->parent.state_machine,
+ &this_device->parent.parent,
+ scic_cb_logger_log_states,
+ "SCIC_SDS_REMOTE_DEVICE_T", "base state machine",
+ SCIC_LOG_OBJECT_SSP_REMOTE_TARGET |
+ SCIC_LOG_OBJECT_SMP_REMOTE_TARGET |
+ SCIC_LOG_OBJECT_STP_REMOTE_TARGET
+ );
+
+ if (this_device->has_ready_substate_machine)
+ {
+ sci_base_state_machine_logger_initialize(
+ &this_device->ready_substate_machine_logger,
+ &this_device->ready_substate_machine,
+ &this_device->parent.parent,
+ scic_cb_logger_log_states,
+ "SCIC_SDS_REMOTE_DEVICE_T", "ready substate machine",
+ SCIC_LOG_OBJECT_SSP_REMOTE_TARGET |
+ SCIC_LOG_OBJECT_SMP_REMOTE_TARGET |
+ SCIC_LOG_OBJECT_STP_REMOTE_TARGET
+ );
+ }
+}
+
+/**
+ * This method will stop the state machine logging for this object and should
+ * be called before the object is destroyed.
+ *
+ * @param[in] this_device The device on which to stop logging state
+ * transitions.
+ *
+ * @return Nothing
+ */
+void scic_sds_remote_device_deinitialize_state_logging(
+ SCIC_SDS_REMOTE_DEVICE_T *this_device
+)
+{
+ sci_base_state_machine_logger_deinitialize(
+ &this_device->parent.state_machine_logger,
+ &this_device->parent.state_machine
+ );
+
+ if (this_device->has_ready_substate_machine)
+ {
+ sci_base_state_machine_logger_deinitialize(
+ &this_device->ready_substate_machine_logger,
+ &this_device->ready_substate_machine
+ );
+ }
+}
+#endif
+
+/**
+ * This method invokes the remote device suspend state handler.
+ *
+ * @param[in] this_device The remote device for which the suspend is being
+ * requested.
+ *
+ * @return SCI_STATUS
+ */
+SCI_STATUS scic_sds_remote_device_suspend(
+ SCIC_SDS_REMOTE_DEVICE_T *this_device,
+ U32 suspend_type
+)
+{
+ return this_device->state_handlers->suspend_handler(this_device, suspend_type);
+}
+
+/**
+ * This method invokes the remote device resume state handler.
+ *
+ * @param[in] this_device The remote device for which the resume is being
+ * requested.
+ *
+ * @return SCI_STATUS
+ */
+SCI_STATUS scic_sds_remote_device_resume(
+ SCIC_SDS_REMOTE_DEVICE_T *this_device
+)
+{
+ return this_device->state_handlers->resume_handler(this_device);
+}
+
+/**
+ * This method invokes the frame handler for the remote device state machine
+ *
+ * @param[in] this_device The remote device for which the event handling is
+ * being requested.
+ * @param[in] frame_index This is the frame index that is being processed.
+ *
+ * @return SCI_STATUS
+ */
+SCI_STATUS scic_sds_remote_device_frame_handler(
+ SCIC_SDS_REMOTE_DEVICE_T *this_device,
+ U32 frame_index
+)
+{
+ return this_device->state_handlers->frame_handler(this_device, frame_index);
+}
+
+/**
+ * This method invokes the remote device event handler.
+ *
+ * @param[in] this_device The remote device for which the event handling is
+ * being requested.
+ * @param[in] event_code This is the event code that is to be processed.
+ *
+ * @return SCI_STATUS
+ */
+SCI_STATUS scic_sds_remote_device_event_handler(
+ SCIC_SDS_REMOTE_DEVICE_T *this_device,
+ U32 event_code
+)
+{
+ return this_device->state_handlers->event_handler(this_device, event_code);
+}
+
+/**
+ * This method invokes the remote device start io handler.
+ *
+ * @param[in] controller The controller that is starting the io request.
+ * @param[in] this_device The remote device for which the start io handling is
+ * being requested.
+ * @param[in] io_request The io request that is being started.
+ *
+ * @return SCI_STATUS
+ */
+SCI_STATUS scic_sds_remote_device_start_io(
+ SCIC_SDS_CONTROLLER_T *controller,
+ SCIC_SDS_REMOTE_DEVICE_T *this_device,
+ SCIC_SDS_REQUEST_T *io_request
+)
+{
+ return this_device->state_handlers->parent.start_io_handler(
+ &this_device->parent, &io_request->parent);
+}
+
+/**
+ * This method invokes the remote device complete io handler.
+ *
+ * @param[in] controller The controller that is completing the io request.
+ * @param[in] this_device The remote device for which the complete io handling
+ * is being requested.
+ * @param[in] io_request The io request that is being completed.
+ *
+ * @return SCI_STATUS
+ */
+SCI_STATUS scic_sds_remote_device_complete_io(
+ SCIC_SDS_CONTROLLER_T *controller,
+ SCIC_SDS_REMOTE_DEVICE_T *this_device,
+ SCIC_SDS_REQUEST_T *io_request
+)
+{
+ return this_device->state_handlers->parent.complete_io_handler(
+ &this_device->parent, &io_request->parent);
+}
+
+/**
+ * This method invokes the remote device start task handler.
+ *
+ * @param[in] controller The controller that is starting the task request.
+ * @param[in] this_device The remote device for which the start task handling
+ * is being requested.
+ * @param[in] io_request The task request that is being started.
+ *
+ * @return SCI_STATUS
+ */
+SCI_STATUS scic_sds_remote_device_start_task(
+ SCIC_SDS_CONTROLLER_T *controller,
+ SCIC_SDS_REMOTE_DEVICE_T *this_device,
+ SCIC_SDS_REQUEST_T *io_request
+)
+{
+ return this_device->state_handlers->parent.start_task_handler(
+ &this_device->parent, &io_request->parent);
+}
+
+/**
+ * This method takes the request and bulids an appropriate SCU context for the
+ * request and then requests the controller to post the request.
+ *
+ * @param[in] this_device
+ * @param[in] request
+ *
+ * @return none
+ */
+void scic_sds_remote_device_post_request(
+ SCIC_SDS_REMOTE_DEVICE_T * 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 method check the signature fis of a stp device to decide whether
+ * a device is atapi or not.
+ *
+ * @param[in] this_device The device to be checked.
+ *
+ * @return TRUE if a device is atapi device. False if a device is not atapi.
+ */
+BOOL scic_sds_remote_device_is_atapi(
+ SCIC_SDS_REMOTE_DEVICE_T * this_device
+)
+{
+ if (!this_device->target_protocols.u.bits.attached_stp_target)
+ return FALSE;
+ else if (this_device->is_direct_attached)
+ {
+ SCIC_SDS_PHY_T * phy;
+ SCIC_SATA_PHY_PROPERTIES_T properties;
+ SATA_FIS_REG_D2H_T * 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 // !defined(DISABLE_ATAPI)
+
+//******************************************************************************
+//* REMOTE DEVICE STATE MACHINE
+//******************************************************************************
+
+/**
+ * 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.
+ *
+ * @param[in] user_parameter This is cast to a remote device object.
+ *
+ * @return none
+ */
+static
+void scic_sds_cb_remote_device_rnc_destruct_complete(
+ void * user_parameter
+)
+{
+ SCIC_SDS_REMOTE_DEVICE_T * this_device;
+ this_device = (SCIC_SDS_REMOTE_DEVICE_T *)user_parameter;
+
+ ASSERT(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
+ );
+}
+
+/**
+ * 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.
+ *
+ * @param[in] user_parameter This is cast to a remote device object.
+ *
+ * @return none
+ */
+static
+void scic_sds_remote_device_resume_complete_handler(
+ void * user_parameter
+)
+{
+ SCIC_SDS_REMOTE_DEVICE_T * this_device;
+ this_device = (SCIC_SDS_REMOTE_DEVICE_T *)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
+ );
+ }
+}
+
+/**
+ * This method will perform the STP request start processing common
+ * to IO requests and task requests of all types.
+ *
+ * @param[in] device This parameter specifies the device for which the
+ * request is being started.
+ * @param[in] request This parameter specifies the request being started.
+ * @param[in] status This parameter specifies the current start operation
+ * status.
+ *
+ * @return none
+ */
+void scic_sds_remote_device_start_request(
+ SCIC_SDS_REMOTE_DEVICE_T * this_device,
+ SCIC_SDS_REQUEST_T * the_request,
+ 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
+ );
+ }
+}
+
+
+/**
+ * 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.
+ *
+ * @param[in] request This parameter specifies the request being continued.
+ *
+ * @return none
+ */
+void scic_sds_remote_device_continue_request(
+ SCIC_SDS_REMOTE_DEVICE_T * this_device
+)
+{
+ // we need to check if this request is still valid to continue.
+ if (this_device->working_request != NULL)
+ {
+ SCIC_SDS_REQUEST_T * this_request = this_device->working_request;
+
+ this_request->owning_controller->state_handlers->parent.continue_io_handler(
+ &this_request->owning_controller->parent,
+ &this_request->target_device->parent,
+ &this_request->parent
+ );
+ }
+}
+
+/**
+ * @brief This method will terminate all of the IO requests in the
+ * controllers IO request table that were targeted for this
+ * device.
+ *
+ * @param[in] this_device This parameter specifies the remote device
+ * for which to attempt to terminate all requests.
+ *
+ * @return 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
+SCI_STATUS scic_sds_remote_device_terminate_requests(
+ SCIC_SDS_REMOTE_DEVICE_T *this_device
+)
+{
+ return scic_sds_terminate_reqests(
+ this_device->owning_port->owning_controller,
+ this_device,
+ NULL);
+}
+
+//*****************************************************************************
+//* DEFAULT STATE HANDLERS
+//*****************************************************************************
+
+/**
+ * This method is the default start handler. It logs a warning and returns a
+ * failure.
+ *
+ * @param[in] device The SCI_BASE_REMOTE_DEVICE which is then cast into a
+ * SCIC_SDS_REMOTE_DEVICE.
+ *
+ * @return SCI_STATUS
+ * @retval SCI_FAILURE_INVALID_STATE
+ */
+SCI_STATUS scic_sds_remote_device_default_start_handler(
+ SCI_BASE_REMOTE_DEVICE_T *device
+)
+{
+ SCIC_LOG_WARNING((
+ sci_base_object_get_logger((SCIC_SDS_REMOTE_DEVICE_T *)device),
+ SCIC_LOG_OBJECT_SSP_REMOTE_TARGET |
+ SCIC_LOG_OBJECT_SMP_REMOTE_TARGET |
+ SCIC_LOG_OBJECT_STP_REMOTE_TARGET,
+ "SCIC Remote Device requested to start while in wrong state %d\n",
+ sci_base_state_machine_get_state(
+ scic_sds_remote_device_get_base_state_machine((SCIC_SDS_REMOTE_DEVICE_T *)device))
+ ));
+
+ return SCI_FAILURE_INVALID_STATE;
+}
+
+/**
+ * This method is the default stop handler. It logs a warning and returns a
+ * failure.
+ *
+ * @param[in] device The SCI_BASE_REMOTE_DEVICE which is then cast into a
+ * SCIC_SDS_REMOTE_DEVICE.
+ *
+ * @return SCI_STATUS
+ * @retval SCI_FAILURE_INVALID_STATE
+ */
+SCI_STATUS scic_sds_remote_device_default_stop_handler(
+ SCI_BASE_REMOTE_DEVICE_T *device
+)
+{
+ SCIC_LOG_WARNING((
+ sci_base_object_get_logger((SCIC_SDS_REMOTE_DEVICE_T *)device),
+ SCIC_LOG_OBJECT_SSP_REMOTE_TARGET |
+ SCIC_LOG_OBJECT_SMP_REMOTE_TARGET |
+ SCIC_LOG_OBJECT_STP_REMOTE_TARGET,
+ "SCIC Remote Device requested to stop while in wrong state %d\n",
+ sci_base_state_machine_get_state(
+ scic_sds_remote_device_get_base_state_machine((SCIC_SDS_REMOTE_DEVICE_T *)device))
+ ));
+
+ return SCI_FAILURE_INVALID_STATE;
+}
+
+/**
+ * This method is the default fail handler. It logs a warning and returns a
+ * failure.
+ *
+ * @param[in] device The SCI_BASE_REMOTE_DEVICE which is then cast into a
+ * SCIC_SDS_REMOTE_DEVICE.
+ *
+ * @return SCI_STATUS
+ * @retval SCI_FAILURE_INVALID_STATE
+ */
+SCI_STATUS scic_sds_remote_device_default_fail_handler(
+ SCI_BASE_REMOTE_DEVICE_T *device
+)
+{
+ SCIC_LOG_WARNING((
+ sci_base_object_get_logger((SCIC_SDS_REMOTE_DEVICE_T *)device),
+ SCIC_LOG_OBJECT_SSP_REMOTE_TARGET |
+ SCIC_LOG_OBJECT_SMP_REMOTE_TARGET |
+ SCIC_LOG_OBJECT_STP_REMOTE_TARGET,
+ "SCIC Remote Device requested to fail while in wrong state %d\n",
+ sci_base_state_machine_get_state(
+ scic_sds_remote_device_get_base_state_machine((SCIC_SDS_REMOTE_DEVICE_T *)device))
+ ));
+
+ return SCI_FAILURE_INVALID_STATE;
+}
+
+/**
+ * This method is the default destruct handler. It logs a warning and returns
+ * a failure.
+ *
+ * @param[in] device The SCI_BASE_REMOTE_DEVICE which is then cast into a
+ * SCIC_SDS_REMOTE_DEVICE.
+ *
+ * @return SCI_STATUS
+ * @retval SCI_FAILURE_INVALID_STATE
+ */
+SCI_STATUS scic_sds_remote_device_default_destruct_handler(
+ SCI_BASE_REMOTE_DEVICE_T *device
+)
+{
+ SCIC_LOG_WARNING((
+ sci_base_object_get_logger((SCIC_SDS_REMOTE_DEVICE_T *)device),
+ SCIC_LOG_OBJECT_SSP_REMOTE_TARGET |
+ SCIC_LOG_OBJECT_SMP_REMOTE_TARGET |
+ SCIC_LOG_OBJECT_STP_REMOTE_TARGET,
+ "SCIC Remote Device requested to destroy while in wrong state %d\n",
+ sci_base_state_machine_get_state(
+ scic_sds_remote_device_get_base_state_machine((SCIC_SDS_REMOTE_DEVICE_T *)device))
+ ));
+
+ return SCI_FAILURE_INVALID_STATE;
+}
+
+/**
+ * This method is the default reset handler. It logs a warning and returns a
+ * failure.
+ *
+ * @param[in] device The SCI_BASE_REMOTE_DEVICE which is then cast into a
+ * SCIC_SDS_REMOTE_DEVICE.
+ *
+ * @return SCI_STATUS
+ * @retval SCI_FAILURE_INVALID_STATE
+ */
+SCI_STATUS scic_sds_remote_device_default_reset_handler(
+ SCI_BASE_REMOTE_DEVICE_T *device
+)
+{
+ SCIC_LOG_WARNING((
+ sci_base_object_get_logger((SCIC_SDS_REMOTE_DEVICE_T *)device),
+ SCIC_LOG_OBJECT_SSP_REMOTE_TARGET |
+ SCIC_LOG_OBJECT_SMP_REMOTE_TARGET |
+ SCIC_LOG_OBJECT_STP_REMOTE_TARGET,
+ "SCIC Remote Device requested to reset while in wrong state %d\n",
+ sci_base_state_machine_get_state(
+ scic_sds_remote_device_get_base_state_machine((SCIC_SDS_REMOTE_DEVICE_T *)device))
+ ));
+
+ return SCI_FAILURE_INVALID_STATE;
+}
+
+/**
+ * This method is the default reset complete handler. It logs a warning and
+ * returns a failure.
+ *
+ * @param[in] device The SCI_BASE_REMOTE_DEVICE which is then cast into a
+ * SCIC_SDS_REMOTE_DEVICE.
+ *
+ * @return SCI_STATUS
+ * @retval SCI_FAILURE_INVALID_STATE
+ */
+SCI_STATUS scic_sds_remote_device_default_reset_complete_handler(
+ SCI_BASE_REMOTE_DEVICE_T *device
+)
+{
+ SCIC_LOG_WARNING((
+ sci_base_object_get_logger((SCIC_SDS_REMOTE_DEVICE_T *)device),
+ SCIC_LOG_OBJECT_SSP_REMOTE_TARGET |
+ SCIC_LOG_OBJECT_SMP_REMOTE_TARGET |
+ SCIC_LOG_OBJECT_STP_REMOTE_TARGET,
+ "SCIC Remote Device requested to complete reset while in wrong state %d\n",
+ sci_base_state_machine_get_state(
+ scic_sds_remote_device_get_base_state_machine((SCIC_SDS_REMOTE_DEVICE_T *)device))
+ ));
+
+ return SCI_FAILURE_INVALID_STATE;
+}
+
+/**
+ * This method is the default suspend handler. It logs a warning and returns
+ * a failure.
+ *
+ * @param[in] device The SCI_BASE_REMOTE_DEVICE which is then cast into a
+ * SCIC_SDS_REMOTE_DEVICE.
+ *
+ * @return SCI_STATUS
+ * @retval SCI_FAILURE_INVALID_STATE
+ */
+SCI_STATUS scic_sds_remote_device_default_suspend_handler(
+ SCIC_SDS_REMOTE_DEVICE_T *this_device,
+ U32 suspend_type
+)
+{
+ SCIC_LOG_WARNING((
+ sci_base_object_get_logger(this_device),
+ SCIC_LOG_OBJECT_SSP_REMOTE_TARGET |
+ SCIC_LOG_OBJECT_SMP_REMOTE_TARGET |
+ SCIC_LOG_OBJECT_STP_REMOTE_TARGET,
+ "SCIC Remote Device 0x%x requested to suspend %d while in wrong state %d\n",
+ 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;
+}
+
+/**
+ * This method is the default resume handler. It logs a warning and returns a
+ * failure.
+ *
+ * @param[in] device The SCI_BASE_REMOTE_DEVICE which is then cast into a
+ * SCIC_SDS_REMOTE_DEVICE.
+ *
+ * @return SCI_STATUS
+ * @retval SCI_FAILURE_INVALID_STATE
+ */
+SCI_STATUS scic_sds_remote_device_default_resume_handler(
+ SCIC_SDS_REMOTE_DEVICE_T *this_device
+)
+{
+ SCIC_LOG_WARNING((
+ sci_base_object_get_logger(this_device),
+ SCIC_LOG_OBJECT_SSP_REMOTE_TARGET |
+ SCIC_LOG_OBJECT_SMP_REMOTE_TARGET |
+ SCIC_LOG_OBJECT_STP_REMOTE_TARGET,
+ "SCIC Remote Device requested to resume while in wrong state %d\n",
+ sci_base_state_machine_get_state(
+ scic_sds_remote_device_get_base_state_machine(this_device))
+ ));
+
+ return SCI_FAILURE_INVALID_STATE;
+}
+
+#if defined(SCI_LOGGING)
+/**
+ * This is a private method for emitting log messages related to events reported
+ * to the remote device from the controller object.
+ *
+ * @param [in] this_device This is the device object that is receiving the
+ * event.
+ * @param [in] event_code The event code to process.
+ *
+ * @return None
+ */
+static void scic_sds_emit_event_log_message(
+ SCIC_SDS_REMOTE_DEVICE_T * this_device,
+ U32 event_code,
+ char * message_guts,
+ BOOL ready_state
+ )
+{
+ SCIC_LOG_WARNING((
+ sci_base_object_get_logger(this_device),
+ SCIC_LOG_OBJECT_SSP_REMOTE_TARGET |
+ SCIC_LOG_OBJECT_SMP_REMOTE_TARGET |
+ SCIC_LOG_OBJECT_STP_REMOTE_TARGET,
+ "SCIC Remote device 0x%x (state %d) received %s %x while in the %sready %s%d\n",
+ this_device,
+ sci_base_state_machine_get_state(
+ scic_sds_remote_device_get_base_state_machine(this_device)),
+ message_guts, event_code,
+ (ready_state)
+ ? ""
+ : "not ",
+ (this_device->has_ready_substate_machine)
+ ? "substate "
+ : "",
+ (this_device->has_ready_substate_machine)
+ ? sci_base_state_machine_get_state(&this_device->ready_substate_machine)
+ : 0
+ ));
+}
+#else // defined(SCI_LOGGING)
+#define scic_sds_emit_event_log_message(device, event_code, message, state)
+#endif // defined(SCI_LOGGING)
+
+/**
+ * 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.
+ *
+ * @param[in] device The SCI_BASE_REMOTE_DEVICE which is then cast into a
+ * SCIC_SDS_REMOTE_DEVICE.
+ * @param[in] event_code The event code that the SCIC_SDS_CONTROLLER wants the
+ * device object to process.
+ *
+ * @return SCI_STATUS
+ * @retval SCI_FAILURE_INVALID_STATE
+ */
+static
+SCI_STATUS scic_sds_remote_device_core_event_handler(
+ SCIC_SDS_REMOTE_DEVICE_T *this_device,
+ U32 event_code,
+ BOOL is_ready_state
+)
+{
+ 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 );
+
+ scic_sds_emit_event_log_message(
+ this_device, event_code,
+ (is_ready_state)
+ ? "I_T_Nexus_Timeout event"
+ : "I_T_Nexus_Timeout event in wrong state",
+ is_ready_state );
+
+ break;
+ }
+ // Else, fall through and treat as unhandled...
+
+ default:
+ scic_sds_emit_event_log_message( this_device, event_code,
+ (is_ready_state)
+ ? "unexpected event"
+ : "unexpected event in wrong state",
+ is_ready_state );
+ status = SCI_FAILURE_INVALID_STATE;
+ break;
+ }
+
+ return status;
+}
+/**
+ * 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.
+ *
+ * @param[in] device The SCI_BASE_REMOTE_DEVICE which is then cast into a
+ * SCIC_SDS_REMOTE_DEVICE.
+ * @param[in] event_code The event code that the SCIC_SDS_CONTROLLER wants the
+ * device object to process.
+ *
+ * @return SCI_STATUS
+ * @retval SCI_FAILURE_INVALID_STATE
+ */
+SCI_STATUS scic_sds_remote_device_default_event_handler(
+ SCIC_SDS_REMOTE_DEVICE_T *this_device,
+ U32 event_code
+)
+{
+ return scic_sds_remote_device_core_event_handler( this_device,
+ event_code,
+ FALSE );
+}
+
+/**
+ * This method is the default unsolicited frame handler. It logs a warning,
+ * releases the frame and returns a failure.
+ *
+ * @param[in] device The SCI_BASE_REMOTE_DEVICE which is then cast into a
+ * SCIC_SDS_REMOTE_DEVICE.
+ * @param[in] frame_index The frame index for which the SCIC_SDS_CONTROLLER
+ * wants this device object to process.
+ *
+ * @return SCI_STATUS
+ * @retval SCI_FAILURE_INVALID_STATE
+ */
+SCI_STATUS scic_sds_remote_device_default_frame_handler(
+ SCIC_SDS_REMOTE_DEVICE_T *this_device,
+ U32 frame_index
+)
+{
+ SCIC_LOG_WARNING((
+ sci_base_object_get_logger(this_device),
+ SCIC_LOG_OBJECT_SSP_REMOTE_TARGET |
+ SCIC_LOG_OBJECT_SMP_REMOTE_TARGET |
+ SCIC_LOG_OBJECT_STP_REMOTE_TARGET,
+ "SCIC Remote Device requested to handle frame %x while in wrong state %d\n",
+ 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;
+}
+
+/**
+ * This method is the default start io handler. It logs a warning and returns
+ * a failure.
+ *
+ * @param[in] device The SCI_BASE_REMOTE_DEVICE which is then cast into a
+ * SCIC_SDS_REMOTE_DEVICE.
+ * @param[in] request The SCI_BASE_REQUEST which is then cast into a
+ * SCIC_SDS_IO_REQUEST to start.
+ *
+ * @return SCI_STATUS
+ * @retval SCI_FAILURE_INVALID_STATE
+ */
+SCI_STATUS scic_sds_remote_device_default_start_request_handler(
+ SCI_BASE_REMOTE_DEVICE_T *device,
+ SCI_BASE_REQUEST_T *request
+)
+{
+ SCIC_LOG_WARNING((
+ sci_base_object_get_logger((SCIC_SDS_REMOTE_DEVICE_T *)device),
+ SCIC_LOG_OBJECT_SSP_REMOTE_TARGET |
+ SCIC_LOG_OBJECT_SMP_REMOTE_TARGET |
+ SCIC_LOG_OBJECT_STP_REMOTE_TARGET,
+ "SCIC Remote Device requested to start io request %x while in wrong state %d\n",
+ request,
+ sci_base_state_machine_get_state(
+ scic_sds_remote_device_get_base_state_machine((SCIC_SDS_REMOTE_DEVICE_T *)device))
+ ));
+
+ return SCI_FAILURE_INVALID_STATE;
+}
+
+/**
+ * This method is the default complete io handler. It logs a warning and
+ * returns a failure.
+ *
+ * @param[in] device The SCI_BASE_REMOTE_DEVICE which is then cast into a
+ * SCIC_SDS_REMOTE_DEVICE.
+ * @param[in] request The SCI_BASE_REQUEST which is then cast into a
+ * SCIC_SDS_IO_REQUEST to complete.
+ *
+ *
+ * @return SCI_STATUS
+ * @retval SCI_FAILURE_INVALID_STATE
+ */
+SCI_STATUS scic_sds_remote_device_default_complete_request_handler(
+ SCI_BASE_REMOTE_DEVICE_T *device,
+ SCI_BASE_REQUEST_T *request
+)
+{
+ SCIC_LOG_WARNING((
+ sci_base_object_get_logger((SCIC_SDS_REMOTE_DEVICE_T *)device),
+ SCIC_LOG_OBJECT_SSP_REMOTE_TARGET |
+ SCIC_LOG_OBJECT_SMP_REMOTE_TARGET |
+ SCIC_LOG_OBJECT_STP_REMOTE_TARGET,
+ "SCIC Remote Device requested to complete io_request %x while in wrong state %d\n",
+ request,
+ sci_base_state_machine_get_state(
+ scic_sds_remote_device_get_base_state_machine((SCIC_SDS_REMOTE_DEVICE_T *)device))
+ ));
+
+ return SCI_FAILURE_INVALID_STATE;
+}
+
+/**
+ * This method is the default continue io handler. It logs a warning and
+ * returns a failure.
+ *
+ * @param[in] device The SCI_BASE_REMOTE_DEVICE which is then cast into a
+ * SCIC_SDS_REMOTE_DEVICE.
+ * @param[in] request The SCI_BASE_REQUEST which is then cast into a
+ * SCIC_SDS_IO_REQUEST to continue.
+ *
+ * @return SCI_STATUS
+ * @retval SCI_FAILURE_INVALID_STATE
+ */
+SCI_STATUS scic_sds_remote_device_default_continue_request_handler(
+ SCI_BASE_REMOTE_DEVICE_T *device,
+ SCI_BASE_REQUEST_T *request
+)
+{
+ SCIC_LOG_WARNING((
+ sci_base_object_get_logger((SCIC_SDS_REMOTE_DEVICE_T *)device),
+ SCIC_LOG_OBJECT_SSP_REMOTE_TARGET |
+ SCIC_LOG_OBJECT_SMP_REMOTE_TARGET |
+ SCIC_LOG_OBJECT_STP_REMOTE_TARGET,
+ "SCIC Remote Device requested to continue io request %x while in wrong state %d\n",
+ request,
+ sci_base_state_machine_get_state(
+ scic_sds_remote_device_get_base_state_machine((SCIC_SDS_REMOTE_DEVICE_T *)device))
+ ));
+
+ return SCI_FAILURE_INVALID_STATE;
+}
+
+/**
+ * This method is the general suspend handler.
+ *
+ * @param[in] device The SCI_BASE_REMOTE_DEVICE which is then cast into a
+ * SCIC_SDS_REMOTE_DEVICE.
+ *
+ * @return SCI_STATUS
+ * @retval SCI_FAILURE_INVALID_STATE
+ */
+static
+SCI_STATUS scic_sds_remote_device_general_suspend_handler(
+ SCIC_SDS_REMOTE_DEVICE_T *this_device,
+ U32 suspend_type
+)
+{
+ return scic_sds_remote_node_context_suspend(this_device->rnc, suspend_type, NULL, NULL);
+}
+
+/**
+ * This method is the general suspend handler. It logs a warning and returns
+ * a failure.
+ *
+ * @param[in] device The SCI_BASE_REMOTE_DEVICE which is then cast into a
+ * SCIC_SDS_REMOTE_DEVICE.
+ *
+ * @return SCI_STATUS
+ * @retval SCI_FAILURE_INVALID_STATE
+ */
+static
+SCI_STATUS scic_sds_remote_device_general_resume_handler(
+ SCIC_SDS_REMOTE_DEVICE_T *this_device
+)
+{
+ return scic_sds_remote_node_context_resume(this_device->rnc, NULL, NULL);
+}
+
+//*****************************************************************************
+//* NORMAL STATE HANDLERS
+//*****************************************************************************
+
+/**
+ * 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.
+ *
+ * @param[in] device The SCI_BASE_REMOTE_DEVICE which is then cast into a
+ * SCIC_SDS_REMOTE_DEVICE.
+ * @param[in] frame_index The frame index for which the SCIC_SDS_CONTROLLER
+ * wants this device object to process.
+ *
+ * @return SCI_STATUS
+ * @retval SCI_FAILURE_INVALID_STATE
+ */
+SCI_STATUS scic_sds_remote_device_general_frame_handler(
+ SCIC_SDS_REMOTE_DEVICE_T *this_device,
+ U32 frame_index
+)
+{
+ SCI_STATUS result;
+ SCI_SSP_FRAME_HEADER_T *frame_header;
+ SCIC_SDS_REQUEST_T *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;
+}
+
+/**
+ * This is a common method for handling events reported to the remote device
+ * from the controller object.
+ *
+ * @param [in] this_device This is the device object that is receiving the
+ * event.
+ * @param [in] event_code The event code to process.
+ *
+ * @return SCI_STATUS
+ */
+SCI_STATUS scic_sds_remote_device_general_event_handler(
+ SCIC_SDS_REMOTE_DEVICE_T * this_device,
+ U32 event_code
+)
+{
+ return scic_sds_remote_device_core_event_handler( this_device,
+ event_code,
+ TRUE );
+}
+
+//*****************************************************************************
+//* STOPPED STATE HANDLERS
+//*****************************************************************************
+
+/**
+ * This method takes the 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.
+ *
+ * @param[in] device
+ *
+ * @return SCI_STATUS
+ * @retval SCI_SUCCESS if there is an RNC buffer available to construct the
+ * remote device.
+ * @retval SCI_FAILURE_INSUFFICIENT_RESOURCES if there is no RNC buffer
+ * available in which to construct the remote device.
+ */
+static
+SCI_STATUS scic_sds_remote_device_stopped_state_start_handler(
+ SCI_BASE_REMOTE_DEVICE_T *device
+)
+{
+ SCI_STATUS status;
+ SCIC_SDS_REMOTE_DEVICE_T *this_device = (SCIC_SDS_REMOTE_DEVICE_T *)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 method will stop a SCIC_SDS_REMOTE_DEVICE that is already in a stopped
+ * state. This is not considered an error since the device is already
+ * stopped.
+ *
+ * @param[in] this_device The SCI_BASE_REMOTE_DEVICE which is cast into a
+ * SCIC_SDS_REMOTE_DEVICE.
+ *
+ * @return SCI_STATUS
+ * @retval SCI_SUCCESS
+ */
+static
+SCI_STATUS scic_sds_remote_device_stopped_state_stop_handler(
+ SCI_BASE_REMOTE_DEVICE_T *this_device
+)
+{
+ return SCI_SUCCESS;
+}
+
+/**
+ * This method will destruct a 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 SCIC_SDS_REMOTE_DEVICE is returned to the free pool and
+ * the device object transitions to the SCI_BASE_REMOTE_DEVICE_STATE_FINAL.
+ *
+ * @param[in] this_device The SCI_BASE_REMOTE_DEVICE which is cast into a
+ * SCIC_SDS_REMOTE_DEVICE.
+ *
+ * @return SCI_STATUS
+ * @retval SCI_SUCCESS
+ */
+static
+SCI_STATUS scic_sds_remote_device_stopped_state_destruct_handler(
+ SCI_BASE_REMOTE_DEVICE_T *device
+)
+{
+ SCIC_SDS_REMOTE_DEVICE_T *this_device = (SCIC_SDS_REMOTE_DEVICE_T *)device;
+
+ SCIC_SDS_CONTROLLER_T * the_controller =
+ scic_sds_remote_device_get_controller(this_device);
+
+ the_controller->remote_device_sequence[this_device->rnc->remote_node_index]++;
+
+ scic_sds_controller_free_remote_node_context(
+ the_controller,
+ 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
+ );
+
+ sci_base_state_machine_change_state(
+ scic_sds_remote_device_get_base_state_machine(this_device),
+ SCI_BASE_REMOTE_DEVICE_STATE_FINAL
+ );
+
+ scic_sds_remote_device_deinitialize_state_logging(this_device);
+
+ return SCI_SUCCESS;
+}
+
+//*****************************************************************************
+//* STARTING STATE HANDLERS
+//*****************************************************************************
+
+static
+SCI_STATUS scic_sds_remote_device_starting_state_stop_handler(
+ SCI_BASE_REMOTE_DEVICE_T *device
+)
+{
+ SCIC_SDS_REMOTE_DEVICE_T *this_device = (SCIC_SDS_REMOTE_DEVICE_T *)device;
+
+ /*
+ * This device has not yet started so there had better be no IO requests
+ */
+ ASSERT(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 method is the default stop handler for the 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.
+ *
+ * @param[in] device The SCI_BASE_REMOTE_DEVICE object which is cast to a
+ * SCIC_SDS_REMOTE_DEVICE object.
+ *
+ * @return SCI_STATUS
+ * @retval SCI_SUCCESS
+ */
+SCI_STATUS scic_sds_remote_device_ready_state_stop_handler(
+ SCI_BASE_REMOTE_DEVICE_T *device
+)
+{
+ SCIC_SDS_REMOTE_DEVICE_T *this_device = (SCIC_SDS_REMOTE_DEVICE_T *)device;
+ 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;
+}
+
+/**
+ * This is the ready state device reset handler
+ *
+ * @param[in] device The SCI_BASE_REMOTE_DEVICE object which is cast to a
+ * SCIC_SDS_REMOTE_DEVICE object.
+ *
+ * @return SCI_STATUS
+ */
+SCI_STATUS scic_sds_remote_device_ready_state_reset_handler(
+ SCI_BASE_REMOTE_DEVICE_T *device
+)
+{
+ SCIC_SDS_REMOTE_DEVICE_T *this_device = (SCIC_SDS_REMOTE_DEVICE_T *)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;
+}
+
+/**
+ * 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.
+ *
+ * @param[in] device The SCI_BASE_REMOTE_DEVICE which is cast to a
+ * SCIC_SDS_REMOTE_DEVICE for which the request is to be started.
+ * @param[in] request The SCI_BASE_REQUEST which is cast to a
+ * SCIC_SDS_IO_REQUEST that is to be started.
+ *
+ * @return SCI_STATUS
+ * @retval SCI_SUCCESS if the task request is started for this device object.
+ * @retval SCI_FAILURE_INSUFFICIENT_RESOURCES if the io request object could
+ * not get the resources to start.
+ */
+static
+SCI_STATUS scic_sds_remote_device_ready_state_start_task_handler(
+ SCI_BASE_REMOTE_DEVICE_T *device,
+ SCI_BASE_REQUEST_T *request
+)
+{
+ SCI_STATUS result;
+ SCIC_SDS_REMOTE_DEVICE_T *this_device = (SCIC_SDS_REMOTE_DEVICE_T *)device;
+ SCIC_SDS_REQUEST_T *task_request = (SCIC_SDS_REQUEST_T *)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;
+}
+
+/**
+ * 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.
+ *
+ * @param[in] device The SCI_BASE_REMOTE_DEVICE which is cast to a
+ * SCIC_SDS_REMOTE_DEVICE for which the request is to be started.
+ * @param[in] request The SCI_BASE_REQUEST which is cast to a
+ * SCIC_SDS_IO_REQUEST that is to be started.
+ *
+ * @return SCI_STATUS
+ * @retval SCI_SUCCESS if the io request is started for this device object.
+ * @retval SCI_FAILURE_INSUFFICIENT_RESOURCES if the io request object could
+ * not get the resources to start.
+ */
+static
+SCI_STATUS scic_sds_remote_device_ready_state_start_io_handler(
+ SCI_BASE_REMOTE_DEVICE_T *device,
+ SCI_BASE_REQUEST_T *request
+)
+{
+ SCI_STATUS result;
+ SCIC_SDS_REMOTE_DEVICE_T *this_device = (SCIC_SDS_REMOTE_DEVICE_T *)device;
+ SCIC_SDS_REQUEST_T *io_request = (SCIC_SDS_REQUEST_T *)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;
+}
+
+/**
+ * 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.
+ *
+ * @param[in] device The SCI_BASE_REMOTE_DEVICE which is cast to a
+ * SCIC_SDS_REMOTE_DEVICE for which the request is to be completed.
+ * @param[in] request The SCI_BASE_REQUEST which is cast to a
+ * SCIC_SDS_IO_REQUEST that is to be completed.
+ *
+ * @return SCI_STATUS
+ */
+static
+SCI_STATUS scic_sds_remote_device_ready_state_complete_request_handler(
+ SCI_BASE_REMOTE_DEVICE_T *device,
+ SCI_BASE_REQUEST_T *request
+)
+{
+ SCI_STATUS result;
+ SCIC_SDS_REMOTE_DEVICE_T *this_device = (SCIC_SDS_REMOTE_DEVICE_T *)device;
+ SCIC_SDS_REQUEST_T *the_request = (SCIC_SDS_REQUEST_T *)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 method will stop a 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.
+ *
+ * @param[in] this_device The SCI_BASE_REMOTE_DEVICE which is cast into a
+ * SCIC_SDS_REMOTE_DEVICE.
+ *
+ * @return SCI_STATUS
+ * @retval SCI_SUCCESS
+ */
+static
+SCI_STATUS scic_sds_remote_device_stopping_state_stop_handler(
+ SCI_BASE_REMOTE_DEVICE_T *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(
+ (SCIC_SDS_REMOTE_DEVICE_T*)device);
+}
+
+
+/**
+ * This method completes requests for this 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 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.
+ *
+ * @param[in] device The device object for which the request is completing.
+ * @param[in] request The task request that is being completed.
+ *
+ * @return SCI_STATUS
+ */
+static
+SCI_STATUS scic_sds_remote_device_stopping_state_complete_request_handler(
+ SCI_BASE_REMOTE_DEVICE_T *device,
+ SCI_BASE_REQUEST_T *request
+)
+{
+ SCI_STATUS status = SCI_SUCCESS;
+ SCIC_SDS_REQUEST_T *this_request = (SCIC_SDS_REQUEST_T *)request;
+ SCIC_SDS_REMOTE_DEVICE_T *this_device = (SCIC_SDS_REMOTE_DEVICE_T *)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
+//*****************************************************************************
+
+/**
+ * This method will complete the reset operation when the device is in the
+ * resetting state.
+ *
+ * @param[in] device The SCI_BASE_REMOTE_DEVICE which is to be cast into a
+ * SCIC_SDS_REMOTE_DEVICE object.
+ *
+ * @return SCI_STATUS
+ */
+static
+SCI_STATUS scic_sds_remote_device_resetting_state_reset_complete_handler(
+ SCI_BASE_REMOTE_DEVICE_T * device
+)
+{
+ SCIC_SDS_REMOTE_DEVICE_T *this_device = (SCIC_SDS_REMOTE_DEVICE_T *)device;
+
+ sci_base_state_machine_change_state(
+ &this_device->parent.state_machine,
+ SCI_BASE_REMOTE_DEVICE_STATE_READY
+ );
+
+ return SCI_SUCCESS;
+}
+
+/**
+ * This method will stop the remote device while in the resetting state.
+ *
+ * @param[in] device The SCI_BASE_REMOTE_DEVICE which is to be cast into a
+ * SCIC_SDS_REMOTE_DEVICE object.
+ *
+ * @return SCI_STATUS
+ */
+static
+SCI_STATUS scic_sds_remote_device_resetting_state_stop_handler(
+ SCI_BASE_REMOTE_DEVICE_T * device
+)
+{
+ SCIC_SDS_REMOTE_DEVICE_T *this_device = (SCIC_SDS_REMOTE_DEVICE_T *)device;
+
+ sci_base_state_machine_change_state(
+ &this_device->parent.state_machine,
+ SCI_BASE_REMOTE_DEVICE_STATE_STOPPING
+ );
+
+ return SCI_SUCCESS;
+}
+
+/**
+ * This method completes requests for this 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.
+ *
+ * @param[in] device The device object for which the request is completing.
+ * @param[in] request The task request that is being completed.
+ *
+ * @return SCI_STATUS
+ */
+static
+SCI_STATUS scic_sds_remote_device_resetting_state_complete_request_handler(
+ SCI_BASE_REMOTE_DEVICE_T *device,
+ SCI_BASE_REQUEST_T *request
+)
+{
+ SCI_STATUS status = SCI_SUCCESS;
+ SCIC_SDS_REQUEST_T *this_request = (SCIC_SDS_REQUEST_T *)request;
+ SCIC_SDS_REMOTE_DEVICE_T *this_device = (SCIC_SDS_REMOTE_DEVICE_T *)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
+//*****************************************************************************
+
+SCIC_SDS_REMOTE_DEVICE_STATE_HANDLER_T
+ 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_general_suspend_handler,
+ scic_sds_remote_device_general_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
+ },
+#if !defined(DISABLE_WIDE_PORTED_TARGETS)
+ // SCI_BASE_REMOTE_DEVICE_STATE_UPDATING_PORT_WIDTH - unused by SCIC
+ {
+ {
+ 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
+ },
+#endif
+ // 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 is the enter method for the SCI_BASE_REMOTE_DEVICE_STATE_INITIAL it
+ * immediatly transitions the remote device object to the stopped state.
+ *
+ * @param[in] object This is the SCI_BASE_OBJECT that is cast into a
+ * SCIC_SDS_REMOTE_DEVICE.
+ *
+ * @return none
+ */
+static
+void scic_sds_remote_device_initial_state_enter(
+ SCI_BASE_OBJECT_T *object
+)
+{
+ SCIC_SDS_REMOTE_DEVICE_T *this_device = (SCIC_SDS_REMOTE_DEVICE_T *)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
+ );
+}
+
+/**
+ * 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.
+ *
+ * @param[in] object This is the SCI_BASE_OBJECT that is cast into a
+ * SCIC_SDS_REMOTE_DEVICE.
+ *
+ * @return none
+ */
+static
+void scic_sds_remote_device_stopped_state_enter(
+ SCI_BASE_OBJECT_T *object
+)
+{
+ SCIC_SDS_REMOTE_DEVICE_T *this_device = (SCIC_SDS_REMOTE_DEVICE_T *)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
+ );
+ }
+
+ scic_sds_controller_remote_device_stopped(
+ scic_sds_remote_device_get_controller(this_device),
+ this_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.
+ *
+ * @param[in] object This is the SCI_BASE_OBJECT that is cast into a
+ * SCIC_SDS_REMOTE_DEVICE.
+ *
+ * @return none
+ */
+static
+void scic_sds_remote_device_starting_state_enter(
+ SCI_BASE_OBJECT_T *object
+)
+{
+ SCIC_SDS_CONTROLLER_T * the_controller;
+ SCIC_SDS_REMOTE_DEVICE_T * this_device = (SCIC_SDS_REMOTE_DEVICE_T *)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
+ );
+}
+
+
+/**
+ * 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.
+ *
+ * @param[in] object This is the SCI_BASE_OBJECT that is cast into a
+ * SCIC_SDS_REMOTE_DEVICE.
+ *
+ * @return none
+ */
+static
+void scic_sds_remote_device_ready_state_enter(
+ SCI_BASE_OBJECT_T *object
+)
+{
+ SCIC_SDS_CONTROLLER_T * the_controller;
+ SCIC_SDS_REMOTE_DEVICE_T * this_device = (SCIC_SDS_REMOTE_DEVICE_T *)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
+ );
+
+ /// @todo Check the device object for the proper return code for this
+ /// callback
+ scic_cb_remote_device_start_complete(
+ the_controller, this_device, SCI_SUCCESS
+ );
+
+ scic_sds_controller_remote_device_started(
+ the_controller, this_device
+ );
+
+ 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);
+ }
+}
+
+/**
+ * This is the exit method for the SCI_BASE_REMOTE_DEVICE_STATE_READY it does
+ * nothing.
+ *
+ * @param[in] object This is the SCI_BASE_OBJECT that is cast into a
+ * SCIC_SDS_REMOTE_DEVICE.
+ *
+ * @return none
+ */
+static
+void scic_sds_remote_device_ready_state_exit(
+ SCI_BASE_OBJECT_T *object
+)
+{
+ SCIC_SDS_CONTROLLER_T * the_controller;
+ SCIC_SDS_REMOTE_DEVICE_T * this_device = (SCIC_SDS_REMOTE_DEVICE_T *)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
+ );
+ }
+}
+
+/**
+ * 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.
+ *
+ * @param[in] object This is the SCI_BASE_OBJECT that is cast into a
+ * SCIC_SDS_REMOTE_DEVICE.
+ *
+ * @return none
+ */
+static
+void scic_sds_remote_device_stopping_state_enter(
+ SCI_BASE_OBJECT_T *object
+)
+{
+ SCIC_SDS_REMOTE_DEVICE_T *this_device = (SCIC_SDS_REMOTE_DEVICE_T *)object;
+
+ SET_STATE_HANDLER(
+ this_device,
+ scic_sds_remote_device_state_handler_table,
+ SCI_BASE_REMOTE_DEVICE_STATE_STOPPING
+ );
+}
+
+/**
+ * This is the enter method for the SCI_BASE_REMOTE_DEVICE_STATE_FAILED it
+ * sets the stopping state handlers.
+ *
+ * @param[in] object This is the SCI_BASE_OBJECT that is cast into a
+ * SCIC_SDS_REMOTE_DEVICE.
+ *
+ * @return none
+ */
+static
+void scic_sds_remote_device_failed_state_enter(
+ SCI_BASE_OBJECT_T *object
+)
+{
+ SCIC_SDS_REMOTE_DEVICE_T *this_device = (SCIC_SDS_REMOTE_DEVICE_T *)object;
+
+ SET_STATE_HANDLER(
+ this_device,
+ scic_sds_remote_device_state_handler_table,
+ SCI_BASE_REMOTE_DEVICE_STATE_FAILED
+ );
+}
+
+/**
+ * This is the enter method for the SCI_BASE_REMOTE_DEVICE_STATE_RESETTING it
+ * sets the resetting state handlers.
+ *
+ * @param[in] object This is the SCI_BASE_OBJECT that is cast into a
+ * SCIC_SDS_REMOTE_DEVICE.
+ *
+ * @return none
+ */
+static
+void scic_sds_remote_device_resetting_state_enter(
+ SCI_BASE_OBJECT_T *object
+)
+{
+ SCIC_SDS_REMOTE_DEVICE_T *this_device = (SCIC_SDS_REMOTE_DEVICE_T *)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);
+}
+
+/**
+ * This is the exit method for the SCI_BASE_REMOTE_DEVICE_STATE_RESETTING it
+ * does nothing.
+ *
+ * @param[in] object This is the SCI_BASE_OBJECT that is cast into a
+ * SCIC_SDS_REMOTE_DEVICE.
+ *
+ * @return none
+ */
+static
+void scic_sds_remote_device_resetting_state_exit(
+ SCI_BASE_OBJECT_T *object
+)
+{
+ SCIC_SDS_REMOTE_DEVICE_T *this_device = (SCIC_SDS_REMOTE_DEVICE_T *)object;
+
+ scic_sds_remote_node_context_resume(this_device->rnc, NULL, NULL);
+}
+
+/**
+ * This is the enter method for the SCI_BASE_REMOTE_DEVICE_STATE_FINAL it sets
+ * the final state handlers.
+ *
+ * @param[in] object This is the SCI_BASE_OBJECT that is cast into a
+ * SCIC_SDS_REMOTE_DEVICE.
+ *
+ * @return none
+ */
+static
+void scic_sds_remote_device_final_state_enter(
+ SCI_BASE_OBJECT_T *object
+)
+{
+ SCIC_SDS_REMOTE_DEVICE_T *this_device = (SCIC_SDS_REMOTE_DEVICE_T *)object;
+
+ SET_STATE_HANDLER(
+ this_device,
+ scic_sds_remote_device_state_handler_table,
+ SCI_BASE_REMOTE_DEVICE_STATE_FINAL
+ );
+}
+
+// ---------------------------------------------------------------------------
+
+SCI_BASE_STATE_T
+ scic_sds_remote_device_state_table[SCI_BASE_REMOTE_DEVICE_MAX_STATES] =
+{
+ {
+ SCI_BASE_REMOTE_DEVICE_STATE_INITIAL,
+ scic_sds_remote_device_initial_state_enter,
+ NULL
+ },
+ {
+ SCI_BASE_REMOTE_DEVICE_STATE_STOPPED,
+ scic_sds_remote_device_stopped_state_enter,
+ NULL
+ },
+ {
+ SCI_BASE_REMOTE_DEVICE_STATE_STARTING,
+ scic_sds_remote_device_starting_state_enter,
+ NULL
+ },
+ {
+ SCI_BASE_REMOTE_DEVICE_STATE_READY,
+ scic_sds_remote_device_ready_state_enter,
+ scic_sds_remote_device_ready_state_exit
+ },
+ {
+ SCI_BASE_REMOTE_DEVICE_STATE_STOPPING,
+ scic_sds_remote_device_stopping_state_enter,
+ NULL
+ },
+ {
+ SCI_BASE_REMOTE_DEVICE_STATE_FAILED,
+ scic_sds_remote_device_failed_state_enter,
+ NULL
+ },
+ {
+ SCI_BASE_REMOTE_DEVICE_STATE_RESETTING,
+ scic_sds_remote_device_resetting_state_enter,
+ scic_sds_remote_device_resetting_state_exit
+ },
+#if !defined(DISABLE_WIDE_PORTED_TARGETS)
+ { //Not used by SCIC
+ SCI_BASE_REMOTE_DEVICE_STATE_UPDATING_PORT_WIDTH,
+ NULL,
+ NULL
+ },
+#endif //#if !defined(DISABLE_WIDE_PORTED_TARGETS)
+ {
+ SCI_BASE_REMOTE_DEVICE_STATE_FINAL,
+ scic_sds_remote_device_final_state_enter,
+ NULL
+ }
+};
+
diff --git a/sys/dev/isci/scil/scic_sds_remote_device.h b/sys/dev/isci/scil/scic_sds_remote_device.h
new file mode 100644
index 0000000..0e837cf
--- /dev/null
+++ b/sys/dev/isci/scil/scic_sds_remote_device.h
@@ -0,0 +1,646 @@
+/*-
+ * 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.
+ *
+ * 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.
+ *
+ * $FreeBSD$
+ */
+#ifndef _SCIC_SDS_REMOTE_DEVICE_H_
+#define _SCIC_SDS_REMOTE_DEVICE_H_
+
+/**
+ * @file
+ *
+ * @brief This file contains the structures, constants, and prototypes for the
+ * SCIC_SDS_REMOTE_DEVICE object.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif // __cplusplus
+
+#include <dev/isci/scil/intel_sas.h>
+#include <dev/isci/scil/sci_base_remote_device.h>
+#include <dev/isci/scil/sci_base_request.h>
+#include <dev/isci/scil/sci_base_state_machine_logger.h>
+#include <dev/isci/scil/scu_remote_node_context.h>
+#include <dev/isci/scil/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
+ * 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 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
+ *
+ * @brief This structure contains the data for an SCU implementation of
+ * the SCU Core device data.
+ */
+typedef struct SCIC_SDS_REMOTE_DEVICE
+{
+ /**
+ * This field is the common base for all remote device objects.
+ */
+ SCI_BASE_REMOTE_DEVICE_T 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.
+ */
+ SCI_SAS_LINK_RATE connection_rate;
+
+ /**
+ * This field contains the allowed target protocols for this remote device.
+ */
+ SMP_DISCOVER_RESPONSE_PROTOCOLS_T target_protocols;
+
+ /**
+ * This field contains the device SAS address.
+ */
+ SCI_SAS_ADDRESS_T 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 SCIC_SDS_REMOTE_DEVICE object.
+ */
+ SCI_BASE_STATE_MACHINE_T 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;
+
+ #ifdef SCI_LOGGING
+ /**
+ * This field conatins the ready substate machine logger. The logger will
+ * emit a message each time the ready substate machine changes state.
+ */
+ SCI_BASE_STATE_MACHINE_LOGGER_T ready_substate_machine_logger;
+ #endif
+
+} SCIC_SDS_REMOTE_DEVICE_T;
+
+
+typedef SCI_STATUS (*SCIC_SDS_REMOTE_DEVICE_HANDLER_T)(
+ SCIC_SDS_REMOTE_DEVICE_T *this_device);
+
+typedef SCI_STATUS (*SCIC_SDS_REMOTE_DEVICE_SUSPEND_HANDLER_T)(
+ SCIC_SDS_REMOTE_DEVICE_T *this_device,
+ U32 suspend_type);
+
+typedef SCI_STATUS (*SCIC_SDS_REMOTE_DEVICE_RESUME_HANDLER_T)(
+ SCIC_SDS_REMOTE_DEVICE_T *this_device);
+
+typedef SCI_STATUS (*SCIC_SDS_REMOTE_DEVICE_FRAME_HANDLER_T)(
+ SCIC_SDS_REMOTE_DEVICE_T *this_device,
+ U32 frame_index);
+
+typedef SCI_STATUS (*SCIC_SDS_REMOTE_DEVICE_EVENT_HANDLER_T)(
+ SCIC_SDS_REMOTE_DEVICE_T *this_device,
+ U32 event_code);
+
+typedef void (*SCIC_SDS_REMOTE_DEVICE_READY_NOT_READY_HANDLER_T)(
+ SCIC_SDS_REMOTE_DEVICE_T *this_device);
+
+/**
+ * @struct SCIC_SDS_REMOTE_DEVICE_STATE_HANDLER
+ * @brief This structure conains the state handlers that are needed to
+ * process requests for the SCU remote device objects.
+ */
+typedef struct SCIC_SDS_REMOTE_DEVICE_STATE_HANDLER
+{
+ SCI_BASE_REMOTE_DEVICE_STATE_HANDLER_T 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;
+
+} SCIC_SDS_REMOTE_DEVICE_STATE_HANDLER_T;
+
+
+extern SCI_BASE_STATE_T scic_sds_remote_device_state_table[];
+extern SCI_BASE_STATE_T scic_sds_ssp_remote_device_ready_substate_table[];
+extern SCI_BASE_STATE_T scic_sds_stp_remote_device_ready_substate_table[];
+extern SCI_BASE_STATE_T scic_sds_smp_remote_device_ready_substate_table[];
+
+extern SCIC_SDS_REMOTE_DEVICE_STATE_HANDLER_T
+ scic_sds_remote_device_state_handler_table[];
+extern SCIC_SDS_REMOTE_DEVICE_STATE_HANDLER_T
+ scic_sds_ssp_remote_device_ready_substate_handler_table[];
+extern SCIC_SDS_REMOTE_DEVICE_STATE_HANDLER_T
+ scic_sds_stp_remote_device_ready_substate_handler_table[];
+extern SCIC_SDS_REMOTE_DEVICE_STATE_HANDLER_T
+ scic_sds_smp_remote_device_ready_substate_handler_table[];
+
+/**
+ * This macro incrments the request count for this device
+ */
+#define scic_sds_remote_device_increment_request_count(this_device) \
+ ((this_device)->started_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)
+
+/**
+ * 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)
+
+/**
+ * This macro returns the owning port of this remote device obejct.
+ */
+#define scic_sds_remote_device_get_port(this_device) \
+ ((this_device)->owning_port)
+
+/**
+ * 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))
+
+/**
+ * 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))
+
+/**
+ * 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)
+
+/**
+ * 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)
+
+/**
+ * This macro returns the owning port of this device
+ */
+#define scic_sds_remote_device_get_port(this_device) \
+ ((this_device)->owning_port)
+
+/**
+ * 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] \
+ )
+
+/**
+ * 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) \
+ ) \
+ ) \
+ )
+
+/**
+ * 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)))
+
+/**
+ * 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)
+
+/**
+ * This macro builds a remote device context for the SCU post request
+ * operation
+ */
+#define scic_sds_remote_device_build_command_context(device, command) \
+ ( (command) \
+ | ((U32)(scic_sds_remote_device_get_controller_peg((device))) << SCU_CONTEXT_COMMAND_PROTOCOL_ENGINE_GROUP_SHIFT)\
+ | ((U32)(scic_sds_remote_device_get_port_index((device))) << SCU_CONTEXT_COMMAND_LOGICAL_PORT_SHIFT) \
+ | (scic_sds_remote_device_get_index((device))) \
+ )
+
+/**
+ * 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))
+
+// ---------------------------------------------------------------------------
+
+U32 scic_sds_remote_device_get_min_timer_count(void);
+
+U32 scic_sds_remote_device_get_max_timer_count(void);
+
+SCI_STATUS scic_sds_remote_device_frame_handler(
+ SCIC_SDS_REMOTE_DEVICE_T *this_device,
+ U32 frame_index
+);
+
+SCI_STATUS scic_sds_remote_device_event_handler(
+ SCIC_SDS_REMOTE_DEVICE_T *this_device,
+ U32 event_code
+);
+
+SCI_STATUS scic_sds_remote_device_start_io(
+ struct SCIC_SDS_CONTROLLER *controller,
+ SCIC_SDS_REMOTE_DEVICE_T *this_device,
+ struct SCIC_SDS_REQUEST *io_request
+);
+
+SCI_STATUS scic_sds_remote_device_complete_io(
+ struct SCIC_SDS_CONTROLLER *controller,
+ SCIC_SDS_REMOTE_DEVICE_T *this_device,
+ struct SCIC_SDS_REQUEST *io_request
+);
+
+SCI_STATUS scic_sds_remote_device_resume(
+ SCIC_SDS_REMOTE_DEVICE_T *this_device
+);
+
+SCI_STATUS scic_sds_remote_device_suspend(
+ SCIC_SDS_REMOTE_DEVICE_T *this_device,
+ U32 suspend_type
+);
+
+SCI_STATUS scic_sds_remote_device_start_task(
+ struct SCIC_SDS_CONTROLLER *controller,
+ SCIC_SDS_REMOTE_DEVICE_T *this_device,
+ struct SCIC_SDS_REQUEST *io_request
+);
+
+void scic_sds_remote_device_post_request(
+ SCIC_SDS_REMOTE_DEVICE_T * this_device,
+ U32 request
+);
+
+#if !defined(DISABLE_ATAPI)
+BOOL scic_sds_remote_device_is_atapi(
+ SCIC_SDS_REMOTE_DEVICE_T *this_device
+);
+#else // !defined(DISABLE_ATAPI)
+#define scic_sds_remote_device_is_atapi(this_device) FALSE
+#endif // !defined(DISABLE_ATAPI)
+
+// ---------------------------------------------------------------------------
+
+#ifdef SCI_LOGGING
+void scic_sds_remote_device_initialize_state_logging(
+ SCIC_SDS_REMOTE_DEVICE_T *this_device
+);
+
+void scic_sds_remote_device_deinitialize_state_logging(
+ SCIC_SDS_REMOTE_DEVICE_T *this_device
+);
+#else // SCI_LOGGING
+#define scic_sds_remote_device_initialize_state_logging(x)
+#define scic_sds_remote_device_deinitialize_state_logging(x)
+#endif // SCI_LOGGING
+
+// ---------------------------------------------------------------------------
+
+void scic_sds_remote_device_start_request(
+ SCIC_SDS_REMOTE_DEVICE_T * this_device,
+ struct SCIC_SDS_REQUEST * the_request,
+ SCI_STATUS status
+);
+
+void scic_sds_remote_device_continue_request(
+ SCIC_SDS_REMOTE_DEVICE_T * this_device
+);
+
+SCI_STATUS scic_sds_remote_device_default_start_handler(
+ SCI_BASE_REMOTE_DEVICE_T *this_device
+);
+
+SCI_STATUS scic_sds_remote_device_default_stop_handler(
+ SCI_BASE_REMOTE_DEVICE_T *this_device
+);
+
+SCI_STATUS scic_sds_remote_device_default_fail_handler(
+ SCI_BASE_REMOTE_DEVICE_T *this_device
+);
+
+SCI_STATUS scic_sds_remote_device_default_destruct_handler(
+ SCI_BASE_REMOTE_DEVICE_T *this_device
+);
+
+SCI_STATUS scic_sds_remote_device_default_reset_handler(
+ SCI_BASE_REMOTE_DEVICE_T *device
+);
+
+SCI_STATUS scic_sds_remote_device_default_reset_complete_handler(
+ SCI_BASE_REMOTE_DEVICE_T *device
+);
+
+SCI_STATUS scic_sds_remote_device_default_start_request_handler(
+ SCI_BASE_REMOTE_DEVICE_T *device,
+ SCI_BASE_REQUEST_T *request
+);
+
+SCI_STATUS scic_sds_remote_device_default_complete_request_handler(
+ SCI_BASE_REMOTE_DEVICE_T *device,
+ SCI_BASE_REQUEST_T *request
+);
+
+SCI_STATUS scic_sds_remote_device_default_continue_request_handler(
+ SCI_BASE_REMOTE_DEVICE_T *device,
+ SCI_BASE_REQUEST_T *request
+);
+
+SCI_STATUS scic_sds_remote_device_default_suspend_handler(
+ SCIC_SDS_REMOTE_DEVICE_T *this_device,
+ U32 suspend_type
+);
+
+SCI_STATUS scic_sds_remote_device_default_resume_handler(
+ SCIC_SDS_REMOTE_DEVICE_T *this_device
+);
+
+SCI_STATUS scic_sds_remote_device_default_event_handler(
+ SCIC_SDS_REMOTE_DEVICE_T *this_device,
+ U32 event_code
+);
+
+SCI_STATUS scic_sds_remote_device_default_frame_handler(
+ SCIC_SDS_REMOTE_DEVICE_T *this_device,
+ U32 frame_index
+);
+
+// ---------------------------------------------------------------------------
+
+SCI_STATUS scic_sds_remote_device_ready_state_stop_handler(
+ SCI_BASE_REMOTE_DEVICE_T *device
+);
+
+SCI_STATUS scic_sds_remote_device_ready_state_reset_handler(
+ SCI_BASE_REMOTE_DEVICE_T *device
+);
+
+SCI_STATUS scic_sds_remote_device_general_frame_handler(
+ SCIC_SDS_REMOTE_DEVICE_T *this_device,
+ U32 frame_index
+);
+
+SCI_STATUS scic_sds_remote_device_general_event_handler(
+ SCIC_SDS_REMOTE_DEVICE_T *this_device,
+ U32 event_code
+);
+
+SCI_STATUS scic_sds_ssp_remote_device_ready_suspended_substate_resume_handler(
+ SCIC_SDS_REMOTE_DEVICE_T *this_device
+);
+
+// ---------------------------------------------------------------------------
+
+void scic_sds_remote_device_get_info_from_smp_discover_response(
+ SCIC_SDS_REMOTE_DEVICE_T * this_device,
+ SMP_RESPONSE_DISCOVER_T * discover_response
+);
+
+#ifdef __cplusplus
+}
+#endif // __cplusplus
+
+#endif // _SCIC_SDS_REMOTE_DEVICE_H_
diff --git a/sys/dev/isci/scil/scic_sds_remote_node_context.c b/sys/dev/isci/scil/scic_sds_remote_node_context.c
new file mode 100644
index 0000000..c2ec1c2
--- /dev/null
+++ b/sys/dev/isci/scil/scic_sds_remote_node_context.c
@@ -0,0 +1,1500 @@
+/*-
+ * 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.
+*
+* 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 <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/**
+* @file
+*
+* @brief 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 <dev/isci/scil/sci_util.h>
+#include <dev/isci/scil/scic_sds_logger.h>
+#include <dev/isci/scil/scic_sds_controller.h>
+#include <dev/isci/scil/scic_sds_remote_device.h>
+#include <dev/isci/scil/scic_sds_remote_node_context.h>
+#include <dev/isci/scil/sci_base_state_machine.h>
+#include <dev/isci/scil/scic_remote_device.h>
+#include <dev/isci/scil/scic_sds_port.h>
+#include <dev/isci/scil/scu_event_codes.h>
+#include <dev/isci/scil/scu_task_context.h>
+
+/**
+* @brief
+*/
+ void scic_sds_remote_node_context_construct(
+ SCIC_SDS_REMOTE_DEVICE_T * device,
+ SCIC_SDS_REMOTE_NODE_CONTEXT_T * rnc,
+ U16 remote_node_index
+ )
+{
+ memset (rnc, 0, sizeof(SCIC_SDS_REMOTE_NODE_CONTEXT_T) );
+
+ rnc->remote_node_index = remote_node_index;
+ rnc->device = device;
+ rnc->destination_state = SCIC_SDS_REMOTE_NODE_DESTINATION_STATE_UNSPECIFIED;
+
+ rnc->parent.logger = device->parent.parent.logger;
+
+ 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);
+
+ // State logging initialization takes place late for the remote node context
+ // see the resume state handler for the initial state.
+}
+
+/**
+* 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.
+*
+* @note 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.
+*
+* @param[in] this_rnc The RNC for which the is posted request is being made.
+*
+* @return BOOL
+* @retval TRUE if the state machine is not in the initial state
+* @retval FALSE if the state machine is in the initial state
+*/
+ BOOL scic_sds_remote_node_context_is_initialized(
+ SCIC_SDS_REMOTE_NODE_CONTEXT_T * this_rnc
+ )
+{
+ U32 current_state = sci_base_state_machine_get_state(&this_rnc->state_machine);
+
+ if (current_state == SCIC_SDS_REMOTE_NODE_CONTEXT_INITIAL_STATE)
+ {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/**
+* This method will return TRUE if the remote node context is in a READY state
+* otherwise it will return FALSE
+*
+* @param[in] this_rnc The state of the remote node context object to check.
+*
+* @return BOOL
+* @retval TRUE if the remote node context is in the ready state.
+* @retval FALSE if the remote node context is not in the ready state.
+*/
+ BOOL scic_sds_remote_node_context_is_ready(
+ SCIC_SDS_REMOTE_NODE_CONTEXT_T * 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 method will construct the RNC buffer for this remote device object.
+*
+* @param[in] this_device The remote device to use to construct the RNC
+* buffer.
+* @param[in] rnc The buffer into which the remote device data will be copied.
+*
+* @return none
+*/
+ void scic_sds_remote_node_context_construct_buffer(
+ SCIC_SDS_REMOTE_NODE_CONTEXT_T * this_rnc
+ )
+{
+ SCU_REMOTE_NODE_CONTEXT_T * rnc;
+ SCIC_SDS_CONTROLLER_T * 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(SCU_REMOTE_NODE_CONTEXT_T)
+ * 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;
+}
+
+// ---------------------------------------------------------------------------
+
+#ifdef SCI_LOGGING
+/**
+* This method will enable and turn on state transition logging for the remote
+* node context object.
+*
+* @param[in] this_rnc The remote node context for which state transition
+* logging is to be enabled.
+*
+* @return none
+*/
+ void scic_sds_remote_node_context_initialize_state_logging(
+ SCIC_SDS_REMOTE_NODE_CONTEXT_T * this_rnc
+ )
+{
+ sci_base_state_machine_logger_initialize(
+ &this_rnc->state_machine_logger,
+ &this_rnc->state_machine,
+ &this_rnc->parent,
+ scic_cb_logger_log_states,
+ "SCIC_SDS_REMOTE_NODE_CONTEXT_T", "state machine",
+ SCIC_LOG_OBJECT_SSP_REMOTE_TARGET |
+ SCIC_LOG_OBJECT_SMP_REMOTE_TARGET |
+ SCIC_LOG_OBJECT_STP_REMOTE_TARGET
+ );
+}
+
+/**
+* This method will stop the state machine logging for this object and should
+* be called before the object is destroyed.
+*
+* @param[in] this_rnc The remote node context on which to stop logging state
+* transitions.
+*
+* @return none
+*/
+ void scic_sds_remote_node_context_deinitialize_state_logging(
+ SCIC_SDS_REMOTE_NODE_CONTEXT_T * this_rnc
+ )
+{
+ sci_base_state_machine_logger_deinitialize(
+ &this_rnc->state_machine_logger,
+ &this_rnc->state_machine
+ );
+}
+#endif
+
+/**
+* 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.
+*
+* @param[in] this_rnc
+* @param[in] the_callback
+* @param[in] callback_parameter
+*
+* @return none
+*/
+static
+void scic_sds_remote_node_context_setup_to_resume(
+ SCIC_SDS_REMOTE_NODE_CONTEXT_T * this_rnc,
+ SCIC_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 method will setup the remote node context object so it will
+* transistion to its final state.
+*
+* @param[in] this_rnc
+* @param[in] the_callback
+* @param[in] callback_parameter
+*
+* @return none
+*/
+static
+void scic_sds_remote_node_context_setup_to_destory(
+ SCIC_SDS_REMOTE_NODE_CONTEXT_T * this_rnc,
+ SCIC_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 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.
+*
+* @param[in] this_rnc
+* @param[in] the_callback
+* @param[in] callback_parameter
+*/
+static
+SCI_STATUS scic_sds_remote_node_context_continue_to_resume_handler(
+ SCIC_SDS_REMOTE_NODE_CONTEXT_T * this_rnc,
+ SCIC_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;
+}
+
+//******************************************************************************
+//* REMOTE NODE CONTEXT STATE MACHINE
+//******************************************************************************
+
+static
+SCI_STATUS scic_sds_remote_node_context_default_destruct_handler(
+ SCIC_SDS_REMOTE_NODE_CONTEXT_T * this_rnc,
+ SCIC_SDS_REMOTE_NODE_CONTEXT_CALLBACK the_callback,
+ void * callback_parameter
+)
+{
+ SCIC_LOG_WARNING((
+ sci_base_object_get_logger(this_rnc->device),
+ SCIC_LOG_OBJECT_SSP_REMOTE_TARGET |
+ SCIC_LOG_OBJECT_SMP_REMOTE_TARGET |
+ SCIC_LOG_OBJECT_STP_REMOTE_TARGET,
+ "SCIC Remote Node Context 0x%x requested to stop while in unexpected state %d\n",
+ 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
+SCI_STATUS scic_sds_remote_node_context_default_suspend_handler(
+ SCIC_SDS_REMOTE_NODE_CONTEXT_T * this_rnc,
+ U32 suspend_type,
+ SCIC_SDS_REMOTE_NODE_CONTEXT_CALLBACK the_callback,
+ void * callback_parameter
+)
+{
+ SCIC_LOG_WARNING((
+ sci_base_object_get_logger(this_rnc->device),
+ SCIC_LOG_OBJECT_SSP_REMOTE_TARGET |
+ SCIC_LOG_OBJECT_SMP_REMOTE_TARGET |
+ SCIC_LOG_OBJECT_STP_REMOTE_TARGET,
+ "SCIC Remote Node Context 0x%x requested to suspend while in wrong state %d\n",
+ this_rnc, sci_base_state_machine_get_state(&this_rnc->state_machine)
+ ));
+
+ return SCI_FAILURE_INVALID_STATE;
+}
+
+static
+SCI_STATUS scic_sds_remote_node_context_default_resume_handler(
+ SCIC_SDS_REMOTE_NODE_CONTEXT_T * this_rnc,
+ SCIC_SDS_REMOTE_NODE_CONTEXT_CALLBACK the_callback,
+ void * callback_parameter
+)
+{
+ SCIC_LOG_WARNING((
+ sci_base_object_get_logger(this_rnc->device),
+ SCIC_LOG_OBJECT_SSP_REMOTE_TARGET |
+ SCIC_LOG_OBJECT_SMP_REMOTE_TARGET |
+ SCIC_LOG_OBJECT_STP_REMOTE_TARGET,
+ "SCIC Remote Node Context 0x%x requested to resume while in wrong state %d\n",
+ this_rnc, sci_base_state_machine_get_state(&this_rnc->state_machine)
+ ));
+
+ return SCI_FAILURE_INVALID_STATE;
+}
+
+static
+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
+)
+{
+ SCIC_LOG_WARNING((
+ sci_base_object_get_logger(this_rnc->device),
+ SCIC_LOG_OBJECT_SSP_REMOTE_TARGET |
+ SCIC_LOG_OBJECT_SMP_REMOTE_TARGET |
+ SCIC_LOG_OBJECT_STP_REMOTE_TARGET,
+ "SCIC Remote Node Context 0x%x requested to start io 0x%x while in wrong state %d\n",
+ this_rnc, the_request, sci_base_state_machine_get_state(&this_rnc->state_machine)
+ ));
+
+ return SCI_FAILURE_INVALID_STATE;
+}
+
+static
+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
+)
+{
+ SCIC_LOG_WARNING((
+ sci_base_object_get_logger(this_rnc->device),
+ SCIC_LOG_OBJECT_SSP_REMOTE_TARGET |
+ SCIC_LOG_OBJECT_SMP_REMOTE_TARGET |
+ SCIC_LOG_OBJECT_STP_REMOTE_TARGET,
+ "SCIC Remote Node Context 0x%x requested to start task 0x%x while in wrong state %d\n",
+ this_rnc, the_request, sci_base_state_machine_get_state(&this_rnc->state_machine)
+ ));
+
+ return SCI_FAILURE;
+}
+
+static
+SCI_STATUS scic_sds_remote_node_context_default_event_handler(
+ struct SCIC_SDS_REMOTE_NODE_CONTEXT * this_rnc,
+ U32 event_code
+)
+{
+ SCIC_LOG_WARNING((
+ sci_base_object_get_logger(this_rnc->device),
+ SCIC_LOG_OBJECT_SSP_REMOTE_TARGET |
+ SCIC_LOG_OBJECT_SMP_REMOTE_TARGET |
+ SCIC_LOG_OBJECT_STP_REMOTE_TARGET,
+ "SCIC Remote Node Context 0x%x requested to process event 0x%x while in wrong state %d\n",
+ this_rnc, event_code, sci_base_state_machine_get_state(&this_rnc->state_machine)
+ ));
+
+ return SCI_FAILURE_INVALID_STATE;
+}
+
+/**
+* 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.
+*
+* @param[in] this_rnc The rnc for which the task request is targeted.
+* @param[in] the_request The request which is going to be started.
+*
+* @return SCI_STATUS
+* @retval SCI_SUCCESS
+*/
+static
+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 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.
+*
+* @param[in] this_rnc
+* @param[in] the_callback
+* @param[in] callback_parameter
+*
+* @return SCI_STATUS
+*/
+static
+SCI_STATUS scic_sds_remote_node_context_general_destruct_handler(
+ SCIC_SDS_REMOTE_NODE_CONTEXT_T * this_rnc,
+ SCIC_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
+SCI_STATUS scic_sds_remote_node_context_reset_required_start_io_handler(
+ struct SCIC_SDS_REMOTE_NODE_CONTEXT * this_rnc,
+ struct SCIC_SDS_REQUEST * the_request
+)
+{
+ SCIC_LOG_WARNING((
+ sci_base_object_get_logger(this_rnc->device),
+ SCIC_LOG_OBJECT_SSP_REMOTE_TARGET |
+ SCIC_LOG_OBJECT_SMP_REMOTE_TARGET |
+ SCIC_LOG_OBJECT_STP_REMOTE_TARGET,
+ "SCIC Remote Node Context 0x%x requested to start io 0x%x while in wrong state %d\n",
+ this_rnc, the_request, sci_base_state_machine_get_state(&this_rnc->state_machine)
+ ));
+
+ return SCI_FAILURE_REMOTE_DEVICE_RESET_REQUIRED;
+}
+
+// ---------------------------------------------------------------------------
+
+static
+SCI_STATUS scic_sds_remote_node_context_initial_state_resume_handler(
+ SCIC_SDS_REMOTE_NODE_CONTEXT_T * this_rnc,
+ SCIC_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);
+
+#if defined (SCI_LOGGING)
+ // If a remote node context has a logger already, don't work on its state
+ // logging.
+ if (this_rnc->state_machine.previous_state_id
+ != SCIC_SDS_REMOTE_NODE_CONTEXT_INVALIDATING_STATE)
+ scic_sds_remote_node_context_initialize_state_logging(this_rnc);
+#endif
+
+ 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
+SCI_STATUS scic_sds_remote_node_context_posting_state_event_handler(
+ struct SCIC_SDS_REMOTE_NODE_CONTEXT * this_rnc,
+ U32 event_code
+)
+{
+ 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;
+ SCIC_LOG_WARNING((
+ sci_base_object_get_logger(this_rnc->device),
+ SCIC_LOG_OBJECT_SSP_REMOTE_TARGET |
+ SCIC_LOG_OBJECT_SMP_REMOTE_TARGET |
+ SCIC_LOG_OBJECT_STP_REMOTE_TARGET,
+ "SCIC Remote Node Context 0x%x requested to process unexpected event 0x%x while in posting state\n",
+ this_rnc, event_code
+ ));
+ break;
+ }
+
+ return status;
+}
+
+// ---------------------------------------------------------------------------
+
+static
+SCI_STATUS scic_sds_remote_node_context_invalidating_state_destruct_handler(
+ SCIC_SDS_REMOTE_NODE_CONTEXT_T * this_rnc,
+ SCIC_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
+SCI_STATUS scic_sds_remote_node_context_invalidating_state_event_handler(
+ SCIC_SDS_REMOTE_NODE_CONTEXT_T * this_rnc,
+ U32 event_code
+)
+{
+ 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
+ SCIC_LOG_INFO((
+ sci_base_object_get_logger(this_rnc->device),
+ SCIC_LOG_OBJECT_SSP_REMOTE_TARGET |
+ SCIC_LOG_OBJECT_SMP_REMOTE_TARGET |
+ SCIC_LOG_OBJECT_STP_REMOTE_TARGET,
+ "SCIC Remote Node Context 0x%x was suspeneded by hardware while being invalidated.\n",
+ this_rnc
+ ));
+ status = SCI_SUCCESS;
+ break;
+
+ default:
+ SCIC_LOG_WARNING((
+ sci_base_object_get_logger(this_rnc->device),
+ SCIC_LOG_OBJECT_SSP_REMOTE_TARGET |
+ SCIC_LOG_OBJECT_SMP_REMOTE_TARGET |
+ SCIC_LOG_OBJECT_STP_REMOTE_TARGET,
+ "SCIC Remote Node Context 0x%x requested to process event 0x%x while in state %d.\n",
+ this_rnc, event_code, sci_base_state_machine_get_state(&this_rnc->state_machine)
+ ));
+ status = SCI_FAILURE;
+ break;
+ }
+ }
+
+ return status;
+}
+
+// ---------------------------------------------------------------------------
+
+static
+SCI_STATUS scic_sds_remote_node_context_resuming_state_event_handler(
+ struct SCIC_SDS_REMOTE_NODE_CONTEXT * this_rnc,
+ U32 event_code
+)
+{
+ 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
+ SCIC_LOG_INFO((
+ sci_base_object_get_logger(this_rnc->device),
+ SCIC_LOG_OBJECT_SSP_REMOTE_TARGET |
+ SCIC_LOG_OBJECT_SMP_REMOTE_TARGET |
+ SCIC_LOG_OBJECT_STP_REMOTE_TARGET,
+ "SCIC Remote Node Context 0x%x was suspeneded by hardware while being resumed.\n",
+ this_rnc
+ ));
+ status = SCI_SUCCESS;
+ break;
+
+ default:
+ SCIC_LOG_WARNING((
+ sci_base_object_get_logger(this_rnc->device),
+ SCIC_LOG_OBJECT_SSP_REMOTE_TARGET |
+ SCIC_LOG_OBJECT_SMP_REMOTE_TARGET |
+ SCIC_LOG_OBJECT_STP_REMOTE_TARGET,
+ "SCIC Remote Node Context 0x%x requested to process event 0x%x while in state %d.\n",
+ this_rnc, event_code, sci_base_state_machine_get_state(&this_rnc->state_machine)
+ ));
+ status = SCI_FAILURE;
+ break;
+ }
+ }
+
+ return status;
+}
+
+// ---------------------------------------------------------------------------
+
+/**
+* This method will handle the suspend requests from the ready state.
+*
+* @param[in] this_rnc The remote node context object being suspended.
+* @param[in] the_callback The callback when the suspension is complete.
+* @param[in] callback_parameter The parameter that is to be passed into the
+* callback.
+*
+* @return SCI_SUCCESS
+*/
+static
+SCI_STATUS scic_sds_remote_node_context_ready_state_suspend_handler(
+ SCIC_SDS_REMOTE_NODE_CONTEXT_T * this_rnc,
+ U32 suspend_type,
+ SCIC_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 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.
+*
+* @param[in] this_rnc The rnc for which the io request is targeted.
+* @param[in] the_request The request which is going to be started.
+*
+* @return SCI_STATUS
+* @retval SCI_SUCCESS
+*/
+static
+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
+SCI_STATUS scic_sds_remote_node_context_ready_state_event_handler(
+ struct SCIC_SDS_REMOTE_NODE_CONTEXT * this_rnc,
+ U32 event_code
+)
+{
+ 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:
+ SCIC_LOG_WARNING((
+ sci_base_object_get_logger(this_rnc->device),
+ SCIC_LOG_OBJECT_SSP_REMOTE_TARGET |
+ SCIC_LOG_OBJECT_SMP_REMOTE_TARGET |
+ SCIC_LOG_OBJECT_STP_REMOTE_TARGET,
+ "SCIC Remote Node Context 0x%x requested to process event 0x%x while in state %d.\n",
+ this_rnc, event_code, sci_base_state_machine_get_state(&this_rnc->state_machine)
+ ));
+
+ status = SCI_FAILURE;
+ break;
+ }
+
+ return status;
+}
+
+// ---------------------------------------------------------------------------
+
+static
+SCI_STATUS scic_sds_remote_node_context_tx_suspended_state_resume_handler(
+ SCIC_SDS_REMOTE_NODE_CONTEXT_T * this_rnc,
+ SCIC_SDS_REMOTE_NODE_CONTEXT_CALLBACK the_callback,
+ void * callback_parameter
+)
+{
+ SMP_DISCOVER_RESPONSE_PROTOCOLS_T protocols;
+
+ scic_sds_remote_node_context_setup_to_resume(
+ this_rnc, the_callback, callback_parameter
+ );
+
+ // If this is an expander attached SATA device we must invalidate
+ // and repost the RNC since this is the only way to clear the
+ // TCi to NCQ tag mapping table for the RNi
+ // All other device types we can just resume.
+ scic_remote_device_get_protocols(this_rnc->device, &protocols);
+
+ if (
+ (protocols.u.bits.attached_stp_target == 1)
+ && !(this_rnc->device->is_direct_attached)
+ )
+ {
+ sci_base_state_machine_change_state(
+ &this_rnc->state_machine,
+ SCIC_SDS_REMOTE_NODE_CONTEXT_INVALIDATING_STATE
+ );
+ }
+ else
+ {
+ sci_base_state_machine_change_state(
+ &this_rnc->state_machine,
+ SCIC_SDS_REMOTE_NODE_CONTEXT_RESUMING_STATE
+ );
+ }
+
+ return SCI_SUCCESS;
+}
+
+/**
+* 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.
+*
+* @param[in] this_rnc The remote node context which is to receive the task
+* request.
+* @param[in] the_request The task request to be transmitted to to the remote
+* target device.
+*
+* @return SCI_STATUS
+* @retval SCI_SUCCESS
+*/
+static
+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
+SCI_STATUS scic_sds_remote_node_context_tx_rx_suspended_state_resume_handler(
+ SCIC_SDS_REMOTE_NODE_CONTEXT_T * this_rnc,
+ SCIC_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
+SCI_STATUS scic_sds_remote_node_context_await_suspension_state_resume_handler(
+ SCIC_SDS_REMOTE_NODE_CONTEXT_T * this_rnc,
+ SCIC_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 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.
+*
+* @param[in] this_rnc The remote node context which is to receive the task
+* request.
+* @param[in] the_request The task request to be transmitted to to the remote
+* target device.
+*
+* @return SCI_STATUS
+* @retval SCI_SUCCESS
+*/
+static
+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
+SCI_STATUS scic_sds_remote_node_context_await_suspension_state_event_handler(
+ struct SCIC_SDS_REMOTE_NODE_CONTEXT * this_rnc,
+ U32 event_code
+)
+{
+ 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:
+ SCIC_LOG_WARNING((
+ sci_base_object_get_logger(this_rnc->device),
+ SCIC_LOG_OBJECT_SSP_REMOTE_TARGET |
+ SCIC_LOG_OBJECT_SMP_REMOTE_TARGET |
+ SCIC_LOG_OBJECT_STP_REMOTE_TARGET,
+ "SCIC Remote Node Context 0x%x requested to process event 0x%x while in state %d.\n",
+ this_rnc, event_code, sci_base_state_machine_get_state(&this_rnc->state_machine)
+ ));
+
+ status = SCI_FAILURE;
+ break;
+ }
+
+ return status;
+}
+
+// ---------------------------------------------------------------------------
+
+ 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_reset_required_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_reset_required_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_reset_required_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.
+*
+* @param[in out] rnc
+*/
+static
+void scic_sds_remote_node_context_notify_user(
+ SCIC_SDS_REMOTE_NODE_CONTEXT_T *rnc
+)
+{
+ SCIC_SDS_REMOTE_NODE_CONTEXT_CALLBACK local_user_callback = rnc->user_callback;
+ void * local_user_cookie = rnc->user_cookie;
+
+ //we need to set the user_callback to NULL before it is called, because
+ //the user callback's stack may eventually also set up a new set of
+ //user callback. If we nullify the user_callback after it is called,
+ //we are in the risk to lose the freshly set user callback.
+ rnc->user_callback = NULL;
+ rnc->user_cookie = NULL;
+
+ if (local_user_callback != NULL)
+ {
+ (*local_user_callback)(local_user_cookie);
+ }
+}
+
+/**
+* This method will continue the remote node context state machine by
+* requesting to resume the remote node context state machine from its current
+* state.
+*
+* @param[in] rnc
+*/
+static
+void scic_sds_remote_node_context_continue_state_transitions(
+ SCIC_SDS_REMOTE_NODE_CONTEXT_T * 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 method will mark the rnc buffer as being valid and post the request to
+* the hardware.
+*
+* @param[in] this_rnc The remote node context object that is to be
+* validated.
+*
+* @return none
+*/
+static
+void scic_sds_remote_node_context_validate_context_buffer(
+ SCIC_SDS_REMOTE_NODE_CONTEXT_T * this_rnc
+)
+{
+ SCU_REMOTE_NODE_CONTEXT_T *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_setup_transports(
+ this_rnc->device->owning_port,
+ this_rnc->remote_node_index
+ );
+ }
+ }
+}
+
+/**
+* This method will update the RNC buffer and post the invalidate request.
+*
+* @param[in] this_rnc The remote node context object that is to be
+* invalidated.
+*
+* @return none
+*/
+static
+void scic_sds_remote_node_context_invalidate_context_buffer(
+ SCIC_SDS_REMOTE_NODE_CONTEXT_T * this_rnc
+)
+{
+ SCU_REMOTE_NODE_CONTEXT_T *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
+ );
+}
+
+//*****************************************************************************
+//* REMOTE NODE CONTEXT STATE ENTER AND EXIT METHODS
+//*****************************************************************************
+
+/**
+*
+*
+* @param[in] object
+*/
+static
+void scic_sds_remote_node_context_initial_state_enter(
+ SCI_BASE_OBJECT_T * object
+)
+{
+ SCIC_SDS_REMOTE_NODE_CONTEXT_T * rnc;
+ rnc = (SCIC_SDS_REMOTE_NODE_CONTEXT_T *)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);
+
+ // Since we are destroying the remote node context deinitialize the state logging
+ // should we resume the remote node context the state logging will be reinitialized
+ // on the resume handler.
+ scic_sds_remote_node_context_deinitialize_state_logging(rnc);
+ }
+}
+
+/**
+*
+*
+* @param[in] object
+*/
+static
+void scic_sds_remote_node_context_posting_state_enter(
+ SCI_BASE_OBJECT_T * object
+)
+{
+ SCIC_SDS_REMOTE_NODE_CONTEXT_T * this_rnc;
+ this_rnc = (SCIC_SDS_REMOTE_NODE_CONTEXT_T *)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);
+}
+
+/**
+*
+*
+* @param[in] object
+*/
+static
+void scic_sds_remote_node_context_invalidating_state_enter(
+ SCI_BASE_OBJECT_T * object
+)
+{
+ SCIC_SDS_REMOTE_NODE_CONTEXT_T * rnc;
+ rnc = (SCIC_SDS_REMOTE_NODE_CONTEXT_T *)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);
+}
+
+/**
+*
+*
+* @param[in] object
+*/
+static
+void scic_sds_remote_node_context_resuming_state_enter(
+ SCI_BASE_OBJECT_T * object
+)
+{
+ SCIC_SDS_REMOTE_NODE_CONTEXT_T * rnc;
+ SMP_DISCOVER_RESPONSE_PROTOCOLS_T protocols;
+ rnc = (SCIC_SDS_REMOTE_NODE_CONTEXT_T *)object;
+
+ SET_STATE_HANDLER(
+ rnc,
+ scic_sds_remote_node_context_state_handler_table,
+ SCIC_SDS_REMOTE_NODE_CONTEXT_RESUMING_STATE
+ );
+
+ // For direct attached SATA devices we need to clear the TLCR
+ // NCQ to TCi tag mapping on the phy and in cases where we
+ // resume because of a target reset we also need to update
+ // the STPTLDARNI register with the RNi of the device
+ scic_remote_device_get_protocols(rnc->device, &protocols);
+
+ if (
+ (protocols.u.bits.attached_stp_target == 1)
+ && (rnc->device->is_direct_attached)
+ )
+ {
+ scic_sds_port_setup_transports(
+ rnc->device->owning_port, rnc->remote_node_index
+ );
+ }
+
+ scic_sds_remote_device_post_request(
+ rnc->device,
+ SCU_CONTEXT_COMMAND_POST_RNC_RESUME
+ );
+}
+
+/**
+*
+*
+* @param[in] object
+*/
+static
+void scic_sds_remote_node_context_ready_state_enter(
+ SCI_BASE_OBJECT_T * object
+)
+{
+ SCIC_SDS_REMOTE_NODE_CONTEXT_T * rnc;
+ rnc = (SCIC_SDS_REMOTE_NODE_CONTEXT_T *)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);
+ }
+}
+
+/**
+*
+*
+* @param[in] object
+*/
+static
+void scic_sds_remote_node_context_tx_suspended_state_enter(
+ SCI_BASE_OBJECT_T * object
+)
+{
+ SCIC_SDS_REMOTE_NODE_CONTEXT_T * rnc;
+ rnc = (SCIC_SDS_REMOTE_NODE_CONTEXT_T *)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);
+}
+
+/**
+*
+*
+* @param[in] object
+*/
+static
+void scic_sds_remote_node_context_tx_rx_suspended_state_enter(
+ SCI_BASE_OBJECT_T * object
+)
+{
+ SCIC_SDS_REMOTE_NODE_CONTEXT_T * rnc;
+ rnc = (SCIC_SDS_REMOTE_NODE_CONTEXT_T *)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);
+}
+
+/**
+*
+*
+* @param[in] object
+*/
+static
+void scic_sds_remote_node_context_await_suspension_state_enter(
+ SCI_BASE_OBJECT_T * object
+)
+{
+ SCIC_SDS_REMOTE_NODE_CONTEXT_T * rnc;
+ rnc = (SCIC_SDS_REMOTE_NODE_CONTEXT_T *)object;
+
+ SET_STATE_HANDLER(
+ rnc,
+ scic_sds_remote_node_context_state_handler_table,
+ SCIC_SDS_REMOTE_NODE_CONTEXT_AWAIT_SUSPENSION_STATE
+ );
+}
+
+// ---------------------------------------------------------------------------
+
+ SCI_BASE_STATE_T
+ scic_sds_remote_node_context_state_table[
+ SCIC_SDS_REMOTE_NODE_CONTEXT_MAX_STATES] =
+{
+ {
+ SCIC_SDS_REMOTE_NODE_CONTEXT_INITIAL_STATE,
+ scic_sds_remote_node_context_initial_state_enter,
+ NULL
+ },
+ {
+ SCIC_SDS_REMOTE_NODE_CONTEXT_POSTING_STATE,
+ scic_sds_remote_node_context_posting_state_enter,
+ NULL
+ },
+ {
+ SCIC_SDS_REMOTE_NODE_CONTEXT_INVALIDATING_STATE,
+ scic_sds_remote_node_context_invalidating_state_enter,
+ NULL
+ },
+ {
+ SCIC_SDS_REMOTE_NODE_CONTEXT_RESUMING_STATE,
+ scic_sds_remote_node_context_resuming_state_enter,
+ NULL
+ },
+ {
+ SCIC_SDS_REMOTE_NODE_CONTEXT_READY_STATE,
+ scic_sds_remote_node_context_ready_state_enter,
+ NULL
+ },
+ {
+ SCIC_SDS_REMOTE_NODE_CONTEXT_TX_SUSPENDED_STATE,
+ scic_sds_remote_node_context_tx_suspended_state_enter,
+ NULL
+ },
+ {
+ SCIC_SDS_REMOTE_NODE_CONTEXT_TX_RX_SUSPENDED_STATE,
+ scic_sds_remote_node_context_tx_rx_suspended_state_enter,
+ NULL
+ },
+ {
+ SCIC_SDS_REMOTE_NODE_CONTEXT_AWAIT_SUSPENSION_STATE,
+ scic_sds_remote_node_context_await_suspension_state_enter,
+ NULL
+ }
+};
+
diff --git a/sys/dev/isci/scil/scic_sds_remote_node_context.h b/sys/dev/isci/scil/scic_sds_remote_node_context.h
new file mode 100644
index 0000000..1e06671
--- /dev/null
+++ b/sys/dev/isci/scil/scic_sds_remote_node_context.h
@@ -0,0 +1,382 @@
+/*-
+ * 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.
+ *
+ * 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.
+ *
+ * $FreeBSD$
+ */
+#ifndef _SCIC_SDS_REMOTE_NODE_CONTEXT_H_
+#define _SCIC_SDS_REMOTE_NODE_CONTEXT_H_
+
+/**
+ * @file
+ *
+ * @brief 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.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif // __cplusplus
+
+#include <dev/isci/scil/sci_types.h>
+#include <dev/isci/scil/sci_base_state.h>
+#include <dev/isci/scil/sci_base_state_machine.h>
+#include <dev/isci/scil/sci_base_state_machine_logger.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 (*SCIC_SDS_REMOTE_NODE_CONTEXT_CALLBACK)(void *);
+
+typedef SCI_STATUS (*SCIC_SDS_REMOTE_NODE_CONTEXT_OPERATION)(
+ struct SCIC_SDS_REMOTE_NODE_CONTEXT * this_rnc,
+ SCIC_SDS_REMOTE_NODE_CONTEXT_CALLBACK the_callback,
+ void * callback_parameter
+);
+
+typedef SCI_STATUS (*SCIC_SDS_REMOTE_NODE_CONTEXT_SUSPEND_OPERATION)(
+ struct SCIC_SDS_REMOTE_NODE_CONTEXT * this_rnc,
+ U32 suspension_type,
+ SCIC_SDS_REMOTE_NODE_CONTEXT_CALLBACK the_callback,
+ void * callback_parameter
+);
+
+typedef SCI_STATUS (* SCIC_SDS_REMOTE_NODE_CONTEXT_IO_REQUEST)(
+ struct SCIC_SDS_REMOTE_NODE_CONTEXT * this_rnc,
+ struct SCIC_SDS_REQUEST * the_request
+);
+
+typedef SCI_STATUS (*SCIC_SDS_REMOTE_NODE_CONTEXT_EVENT_HANDLER)(
+ struct SCIC_SDS_REMOTE_NODE_CONTEXT * this_rnc,
+ U32 event_code
+);
+
+// ---------------------------------------------------------------------------
+
+typedef 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;
+
+} SCIC_SDS_REMOTE_NODE_CONTEXT_HANDLERS;
+
+// ---------------------------------------------------------------------------
+
+/**
+ * @enum
+ *
+ * This is the enumeration of the remote node context states.
+ */
+typedef 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
+
+} SCIS_SDS_REMOTE_NODE_CONTEXT_STATES;
+
+/**
+ * @enum
+ *
+ * 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
+ *
+ * @brief 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.
+ */
+typedef struct SCIC_SDS_REMOTE_NODE_CONTEXT
+{
+ /**
+ * This contains the information used to maintain the loggers for the base
+ * state machine.
+ */
+ SCI_BASE_OBJECT_T 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.
+ */
+ SCIC_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.
+ */
+ SCI_BASE_STATE_MACHINE_T state_machine;
+
+ SCIC_SDS_REMOTE_NODE_CONTEXT_HANDLERS * state_handlers;
+
+ #ifdef SCI_LOGGING
+ /**
+ * This field conatins the ready substate machine logger. The logger will
+ * emit a message each time the ready substate machine changes state.
+ */
+ SCI_BASE_STATE_MACHINE_LOGGER_T state_machine_logger;
+ #endif
+
+} SCIC_SDS_REMOTE_NODE_CONTEXT_T;
+
+// ---------------------------------------------------------------------------
+
+extern SCI_BASE_STATE_T
+ scic_sds_remote_node_context_state_table[
+ SCIC_SDS_REMOTE_NODE_CONTEXT_MAX_STATES];
+
+extern 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,
+ SCIC_SDS_REMOTE_NODE_CONTEXT_T * rnc,
+ U16 remote_node_index
+);
+
+void scic_sds_remote_node_context_construct_buffer(
+ SCIC_SDS_REMOTE_NODE_CONTEXT_T * rnc
+);
+
+BOOL scic_sds_remote_node_context_is_initialized(
+ SCIC_SDS_REMOTE_NODE_CONTEXT_T * rnc
+);
+
+BOOL scic_sds_remote_node_context_is_ready(
+ SCIC_SDS_REMOTE_NODE_CONTEXT_T * 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))
+
+// ---------------------------------------------------------------------------
+
+#ifdef SCI_LOGGING
+void scic_sds_remote_node_context_initialize_state_logging(
+ SCIC_SDS_REMOTE_NODE_CONTEXT_T *this_rnc
+);
+
+void scic_sds_remote_node_context_deinitialize_state_logging(
+ SCIC_SDS_REMOTE_NODE_CONTEXT_T *this_rnc
+);
+#else // SCI_LOGGING
+#define scic_sds_remote_node_context_initialize_state_logging(x)
+#define scic_sds_remote_node_context_deinitialize_state_logging(x)
+#endif // SCI_LOGGING
+
+#ifdef __cplusplus
+}
+#endif // __cplusplus
+
+#endif // _SCIC_SDS_REMOTE_NODE_CONTEXT_H_
+
diff --git a/sys/dev/isci/scil/scic_sds_remote_node_table.c b/sys/dev/isci/scil/scic_sds_remote_node_table.c
new file mode 100644
index 0000000..d159f27
--- /dev/null
+++ b/sys/dev/isci/scil/scic_sds_remote_node_table.c
@@ -0,0 +1,660 @@
+/*-
+ * 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.
+ *
+ * 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 <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/**
+ * @file
+ *
+ * @brief This file contains the implementation of the
+ * SCIC_SDS_REMOTE_NODE_TABLE public, protected, and private methods.
+ */
+
+#include <dev/isci/scil/scic_sds_remote_node_table.h>
+#include <dev/isci/scil/scic_sds_remote_node_context.h>
+
+/**
+ * This routine will find the bit position in absolute bit terms of the next
+ * available bit for selection. The absolute bit is index * 32 + bit
+ * position. If there are available bits in the first U32 then it is just bit
+ * position.
+ * @param[in] remote_node_table This is the remote node index table from
+ * which the selection will be made.
+ * @param[in] group_table_index This is the index to the group table from
+ * which to search for an available selection.
+ *
+ * @return U32 This is the absolute bit position for an available group.
+ */
+static
+U32 scic_sds_remote_node_table_get_group_index(
+ SCIC_REMOTE_NODE_TABLE_T * 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;
+}
+
+/**
+ * This method will clear the group index entry in the specified group index
+ * table.
+ *
+ * @param[in out] remote_node_table This the remote node table in which to
+ * clear the selector.
+ * @param[in] set_index This is the remote node selector in which the change
+ * will be made.
+ * @param[in] group_index This is the bit index in the table to be modified.
+ *
+ * @return none
+ */
+static
+void scic_sds_remote_node_table_clear_group_index(
+ SCIC_REMOTE_NODE_TABLE_T * remote_node_table,
+ U32 group_table_index,
+ U32 group_index
+)
+{
+ U32 dword_index;
+ U32 bit_index;
+ U32 * group_table;
+
+ ASSERT(group_table_index < SCU_STP_REMOTE_NODE_COUNT);
+ ASSERT(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);
+}
+
+/**
+ * This method will set the group index bit entry in the specified gropu index
+ * table.
+ *
+ * @param[in out] remote_node_table This the remote node table in which to set
+ * the selector.
+ * @param[in] group_table_index This is the remote node selector in which the
+ * change will be made.
+ * @param[in] group_index This is the bit position in the table to be
+ * modified.
+ *
+ * @return none
+ */
+static
+void scic_sds_remote_node_table_set_group_index(
+ SCIC_REMOTE_NODE_TABLE_T * remote_node_table,
+ U32 group_table_index,
+ U32 group_index
+)
+{
+ U32 dword_index;
+ U32 bit_index;
+ U32 * group_table;
+
+ ASSERT(group_table_index < SCU_STP_REMOTE_NODE_COUNT);
+ ASSERT(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);
+}
+
+/**
+ * This method will set the remote to available in the remote node allocation
+ * table.
+ *
+ * @param[in out] remote_node_table This is the remote node table in which to
+ * modify the remote node availability.
+ * @param[in] remote_node_index This is the remote node index that is being
+ * returned to the table.
+ *
+ * @return none
+ */
+static
+void scic_sds_remote_node_table_set_node_index(
+ SCIC_REMOTE_NODE_TABLE_T * remote_node_table,
+ U32 remote_node_index
+)
+{
+ U32 dword_location;
+ U32 dword_remainder;
+ U32 slot_normalized;
+ U32 slot_position;
+
+ ASSERT(
+ (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);
+}
+
+/**
+ * This method clears the remote node index from the table of available remote
+ * nodes.
+ *
+ * @param[in out] remote_node_table This is the remote node table from which
+ * to clear the available remote node bit.
+ * @param[in] remote_node_index This is the remote node index which is to be
+ * cleared from the table.
+ *
+ * @return none
+ */
+static
+void scic_sds_remote_node_table_clear_node_index(
+ SCIC_REMOTE_NODE_TABLE_T * remote_node_table,
+ U32 remote_node_index
+)
+{
+ U32 dword_location;
+ U32 dword_remainder;
+ U32 slot_position;
+ U32 slot_normalized;
+
+ ASSERT(
+ (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));
+}
+
+/**
+ * This method clears the entire table slot at the specified slot index.
+ *
+ * @param[in out] remote_node_table The remote node table from which the slot
+ * will be cleared.
+ * @param[in] group_index The index for the slot that is to be cleared.
+ *
+ * @return none
+ */
+static
+void scic_sds_remote_node_table_clear_group(
+ SCIC_REMOTE_NODE_TABLE_T * remote_node_table,
+ U32 group_index
+)
+{
+ U32 dword_location;
+ U32 dword_remainder;
+ U32 dword_value;
+
+ ASSERT(
+ (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;
+}
+
+/**
+ * THis method sets an entire remote node group in the remote node table.
+ *
+ * @param[in] remote_node_table
+ * @param[in] group_index
+ */
+static
+void scic_sds_remote_node_table_set_group(
+ SCIC_REMOTE_NODE_TABLE_T * remote_node_table,
+ U32 group_index
+)
+{
+ U32 dword_location;
+ U32 dword_remainder;
+ U32 dword_value;
+
+ ASSERT(
+ (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;
+}
+
+/**
+ * This method will return the group value for the specified group index.
+ *
+ * @param[in] remote_node_table This is the remote node table that for which
+ * the group value is to be returned.
+ * @param[in] group_index This is the group index to use to find the group
+ * value.
+ *
+ * @return The bit values at the specified remote node group index.
+ */
+static
+U8 scic_sds_remote_node_table_get_group_value(
+ SCIC_REMOTE_NODE_TABLE_T * 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;
+}
+
+/**
+ * This method will initialize the remote node table for use.
+ *
+ * @param[in out] remote_node_table The remote that which is to be
+ * initialized.
+ * @param[in] remote_node_entries The number of entries to put in the table.
+ *
+ * @return none
+ */
+void scic_sds_remote_node_table_initialize(
+ SCIC_REMOTE_NODE_TABLE_T * 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);
+ }
+}
+
+/**
+ * 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.
+ *
+ * @param[in out] remote_node_table The remote node table from which to
+ * allocate a remote node.
+ * @param[in] table_index The group index that is to be used for the search.
+ *
+ * @return 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(
+ SCIC_REMOTE_NODE_TABLE_T * 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;
+}
+
+/**
+ * This method will allocate three consecutive remote node context entries. If
+ * there are no remaining triple entries the function will return a failure.
+ *
+ * @param[in] remote_node_table This is the remote node table from which to
+ * allocate the remote node entries.
+ * @param[in] group_table_index THis is the group table index which must equal
+ * two (2) for this operation.
+ *
+ * @return 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(
+ SCIC_REMOTE_NODE_TABLE_T * 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;
+}
+
+/**
+ * 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).
+ *
+ * @param[in] remote_node_table This is the remote node table from which the
+ * remote node allocation is to take place.
+ * @param[in] 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).
+ *
+ * @return 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(
+ SCIC_REMOTE_NODE_TABLE_T * 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;
+}
+
+/**
+ * This method will free a single remote node index back to the remote node
+ * table. This routine will update the remote node groups
+ *
+ * @param[in] remote_node_table
+ * @param[in] remote_node_index
+ */
+static
+void scic_sds_remote_node_table_release_single_remote_node(
+ SCIC_REMOTE_NODE_TABLE_T * 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.
+ ASSERT(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);
+}
+
+/**
+ * This method will release a group of three consecutive remote nodes back to
+ * the free remote nodes.
+ *
+ * @param[in] remote_node_table This is the remote node table to which the
+ * remote node index is to be freed.
+ * @param[in] remote_node_index This is the remote node index which is being
+ * freed.
+ */
+static
+void scic_sds_remote_node_table_release_triple_remote_node(
+ SCIC_REMOTE_NODE_TABLE_T * 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);
+}
+
+/**
+ * This method will release the remote node index back into the remote node
+ * table free pool.
+ *
+ * @param[in] remote_node_table The remote node table to which the remote node
+ * index is to be freed.
+ * @param[in] remote_node_count This is the count of consecutive remote nodes
+ * that are to be freed.
+ * @param[in] remote_node_index This is the remote node index of the start of
+ * the number of remote nodes to be freed.
+ */
+void scic_sds_remote_node_table_release_remote_node_index(
+ SCIC_REMOTE_NODE_TABLE_T * 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/sys/dev/isci/scil/scic_sds_remote_node_table.h b/sys/dev/isci/scil/scic_sds_remote_node_table.h
new file mode 100644
index 0000000..8912c17
--- /dev/null
+++ b/sys/dev/isci/scil/scic_sds_remote_node_table.h
@@ -0,0 +1,190 @@
+/*-
+ * 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.
+ *
+ * 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.
+ *
+ * $FreeBSD$
+ */
+#ifndef _SCIC_SDS_REMOTE_NODE_TABLE_H_
+#define _SCIC_SDS_REMOTE_NODE_TABLE_H_
+
+/**
+ * @file
+ *
+ * @brief This file contains the structures, constants and prototypes used for
+ * the remote node table.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif // __cplusplus
+
+#include <dev/isci/scil/sci_types.h>
+#include <dev/isci/scil/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
+ */
+typedef 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)];
+
+} SCIC_REMOTE_NODE_TABLE_T;
+
+// ---------------------------------------------------------------------------
+
+void scic_sds_remote_node_table_initialize(
+ SCIC_REMOTE_NODE_TABLE_T * remote_node_table,
+ U32 remote_node_entries
+);
+
+U16 scic_sds_remote_node_table_allocate_remote_node(
+ SCIC_REMOTE_NODE_TABLE_T * remote_node_table,
+ U32 remote_node_count
+);
+
+void scic_sds_remote_node_table_release_remote_node_index(
+ SCIC_REMOTE_NODE_TABLE_T * remote_node_table,
+ U32 remote_node_count,
+ U16 remote_node_index
+);
+
+#ifdef __cplusplus
+}
+#endif // __cplusplus
+
+#endif // _SCIC_SDS_REMOTE_NODE_TABLE_H_
diff --git a/sys/dev/isci/scil/scic_sds_request.c b/sys/dev/isci/scil/scic_sds_request.c
new file mode 100644
index 0000000..020cdf8
--- /dev/null
+++ b/sys/dev/isci/scil/scic_sds_request.c
@@ -0,0 +1,2890 @@
+/*-
+ * 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.
+ *
+ * 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 <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/**
+ * @file
+ *
+ * @brief This file contains the implementation for the operations on an
+ * SCIC_SDS_IO_REQUEST object.
+ */
+
+#include <dev/isci/scil/intel_sat.h>
+#include <dev/isci/scil/intel_sata.h>
+#include <dev/isci/scil/intel_sas.h>
+#include <dev/isci/scil/sci_util.h>
+#include <dev/isci/scil/sci_base_request.h>
+#include <dev/isci/scil/scic_controller.h>
+#include <dev/isci/scil/scic_io_request.h>
+#include <dev/isci/scil/scic_remote_device.h>
+#include <dev/isci/scil/scic_user_callback.h>
+#include <dev/isci/scil/scic_sds_logger.h>
+#include <dev/isci/scil/scic_sds_request.h>
+#include <dev/isci/scil/scic_sds_pci.h>
+#include <dev/isci/scil/scic_sds_stp_request.h>
+#include <dev/isci/scil/scic_sds_controller.h>
+#include <dev/isci/scil/scic_sds_controller_registers.h>
+#include <dev/isci/scil/scic_sds_remote_device.h>
+#include <dev/isci/scil/scic_sds_port.h>
+#include <dev/isci/scil/scic_task_request.h>
+#include <dev/isci/scil/scu_constants.h>
+#include <dev/isci/scil/scu_task_context.h>
+#include <dev/isci/scil/scic_sds_smp_request.h>
+#include <dev/isci/sci_environment.h>
+#include <dev/isci/scil/scic_sds_unsolicited_frame_control.h>
+#include <dev/isci/scil/sci_types.h>
+#include <dev/isci/scil/scu_completion_codes.h>
+#include <dev/isci/scil/intel_scsi.h>
+
+#if !defined(DISABLE_ATAPI)
+#include <dev/isci/scil/scic_sds_stp_packet_request.h>
+#endif
+
+/**
+* @struct SCI_SINGLE_LEVEL_LUN
+*
+* @brief this struct decribes the single level LUN structure
+* as per the SAM 4.
+*/
+typedef struct SCI_SINGLE_LEVEL_LUN
+{
+ U8 bus_id : 6;
+ U8 address_method : 2;
+ U8 lun_number;
+ U8 second_level_lun[2];
+ U8 third_level_lun[2];
+ U8 forth_level_lun[2];
+
+} SCI_SINGLE_LEVEL_LUN_T;
+
+
+//****************************************************************************
+//* 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
+//****************************************************************************
+
+/**
+ * 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)
+
+
+/**
+ * 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.The sizeof(U32) are needed for DWORD alignment of the command IU
+ * and response IU
+ */
+#define scic_ssp_io_request_get_object_size() \
+ ( \
+ sizeof(SCI_SSP_COMMAND_IU_T) \
+ + sizeof (U32) \
+ + sizeof(SCI_SSP_RESPONSE_IU_T) \
+ + sizeof (U32) \
+ )
+
+/**
+ * This macro returns the address of the ssp command buffer in the io
+ * request memory
+ */
+#define scic_sds_ssp_request_get_command_buffer_unaligned(memory) \
+ ((SCI_SSP_COMMAND_IU_T *)( \
+ ((char *)(memory)) + sizeof(SCIC_SDS_REQUEST_T) \
+ ))
+
+/**
+ * This macro aligns the ssp command buffer in DWORD alignment
+*/
+#define scic_sds_ssp_request_align_command_buffer(address) \
+ ((SCI_SSP_COMMAND_IU_T *)( \
+ (((POINTER_UINT)(address)) + (sizeof(U32) - 1)) \
+ & ~(sizeof(U32)- 1) \
+ ))
+
+/**
+ * This macro returns the DWORD-aligned ssp command buffer
+*/
+#define scic_sds_ssp_request_get_command_buffer(memory) \
+ ((SCI_SSP_COMMAND_IU_T *) \
+ ((char *)scic_sds_ssp_request_align_command_buffer( \
+ (char *) scic_sds_ssp_request_get_command_buffer_unaligned(memory) \
+ )))
+
+/**
+ * This macro returns the address of the ssp response buffer in the io
+ * request memory
+ */
+#define scic_sds_ssp_request_get_response_buffer_unaligned(memory) \
+ ((SCI_SSP_RESPONSE_IU_T *)( \
+ ((char *)(scic_sds_ssp_request_get_command_buffer(memory))) \
+ + sizeof(SCI_SSP_COMMAND_IU_T) \
+ ))
+
+/**
+ * This macro aligns the ssp response buffer in DWORD-aligned fashion
+ */
+#define scic_sds_ssp_request_align_response_buffer(memory) \
+ ((SCI_SSP_RESPONSE_IU_T *)( \
+ (((POINTER_UINT)(memory)) + (sizeof(U32) - 1)) \
+ & ~(sizeof(U32)- 1) \
+ ))
+
+/**
+ * This macro returns the DWORD-aligned ssp response buffer
+*/
+#define scic_sds_ssp_request_get_response_buffer(memory) \
+ ((SCI_SSP_RESPONSE_IU_T *) \
+ ((char *)scic_sds_ssp_request_align_response_buffer ( \
+ (char *)scic_sds_ssp_request_get_response_buffer_unaligned(memory) \
+ )))
+
+/**
+ * This macro returns the address of the task context buffer in the io
+ * request memory
+ */
+#define scic_sds_ssp_request_get_task_context_buffer_unaligned(memory) \
+ ((SCU_TASK_CONTEXT_T *)( \
+ ((char *)(scic_sds_ssp_request_get_response_buffer(memory))) \
+ + sizeof(SCI_SSP_RESPONSE_IU_T) \
+ ))
+
+/**
+ * This macro returns the aligned task context buffer
+ */
+#define scic_sds_ssp_request_get_task_context_buffer(memory) \
+ ((SCU_TASK_CONTEXT_T *)( \
+ ((char *)scic_sds_request_align_task_context_buffer( \
+ (char *)scic_sds_ssp_request_get_task_context_buffer_unaligned(memory)) \
+ )))
+
+/**
+ * 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) \
+ ((SCU_SGL_ELEMENT_PAIR_T *)( \
+ ((char *)(scic_sds_ssp_request_get_task_context_buffer(memory))) \
+ + sizeof(SCU_TASK_CONTEXT_T) \
+ ))
+
+#if !defined(DISABLE_TASK_MANAGEMENT)
+
+/**
+ * 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(SCI_SSP_TASK_IU_T) \
+ + sizeof(SCI_SSP_RESPONSE_IU_T) \
+ )
+
+/**
+ * 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) \
+ ((SCI_SSP_TASK_IU_T *)( \
+ ((char *)(memory)) + sizeof(SCIC_SDS_REQUEST_T) \
+ ))
+
+/**
+ * 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) \
+ ((SCI_SSP_RESPONSE_IU_T *)( \
+ ((char *)(scic_sds_ssp_task_request_get_command_buffer(memory))) \
+ + sizeof(SCI_SSP_TASK_IU_T) \
+ ))
+
+/**
+ * This macro returs the task context buffer for the SSP task request.
+ */
+#define scic_sds_ssp_task_request_get_task_context_buffer(memory) \
+ ((SCU_TASK_CONTEXT_T *)( \
+ ((char *)(scic_sds_ssp_task_request_get_response_buffer(memory))) \
+ + sizeof(SCI_SSP_RESPONSE_IU_T) \
+ ))
+
+#endif // !defined(DISABLE_TASK_MANAGEMENT)
+
+
+//****************************************************************************
+//* SCIC SDS IO REQUEST PRIVATE METHODS
+//****************************************************************************
+
+#ifdef SCI_LOGGING
+/**
+ * This method will initialize state transition logging for the task request
+ * object.
+ *
+ * @param[in] this_request This is the request for which to track state
+ * transitions.
+ */
+void scic_sds_request_initialize_state_logging(
+ SCIC_SDS_REQUEST_T *this_request
+)
+{
+ sci_base_state_machine_logger_initialize(
+ &this_request->parent.state_machine_logger,
+ &this_request->parent.state_machine,
+ &this_request->parent.parent,
+ scic_cb_logger_log_states,
+ this_request->is_task_management_request ?
+ "SCIC_SDS_IO_REQUEST_T(Task)" : "SCIC_SDS_IO_REQUEST_T(IO)",
+ "base state machine",
+ SCIC_LOG_OBJECT_SMP_IO_REQUEST |
+ SCIC_LOG_OBJECT_STP_IO_REQUEST |
+ SCIC_LOG_OBJECT_SSP_IO_REQUEST
+ );
+
+ if (this_request->has_started_substate_machine)
+ {
+ sci_base_state_machine_logger_initialize(
+ &this_request->started_substate_machine_logger,
+ &this_request->started_substate_machine,
+ &this_request->parent.parent,
+ scic_cb_logger_log_states,
+ "SCIC_SDS_IO_REQUEST_T(Task)", "starting substate machine",
+ SCIC_LOG_OBJECT_SMP_IO_REQUEST |
+ SCIC_LOG_OBJECT_STP_IO_REQUEST |
+ SCIC_LOG_OBJECT_SSP_IO_REQUEST
+ );
+ }
+}
+
+/**
+ * This method will stop the state transition logging for the task request
+ * object.
+ *
+ * @param[in] this_request The task request object on which to stop state
+ * transition logging.
+ */
+void scic_sds_request_deinitialize_state_logging(
+ SCIC_SDS_REQUEST_T *this_request
+)
+{
+ sci_base_state_machine_logger_deinitialize(
+ &this_request->parent.state_machine_logger,
+ &this_request->parent.state_machine
+ );
+
+ if (this_request->has_started_substate_machine)
+ {
+ sci_base_state_machine_logger_deinitialize(
+ &this_request->started_substate_machine_logger,
+ &this_request->started_substate_machine
+ );
+ }
+}
+#endif // SCI_LOGGING
+
+/**
+ * This method returns the size required to store an SSP IO request object.
+ *
+ * @return U32
+ */
+static
+U32 scic_sds_ssp_request_get_object_size(void)
+{
+ return sizeof(SCIC_SDS_REQUEST_T)
+ + scic_ssp_io_request_get_object_size()
+ + sizeof(SCU_TASK_CONTEXT_T)
+ + CACHE_LINE_SIZE
+ + sizeof(SCU_SGL_ELEMENT_PAIR_T) * SCU_MAX_SGL_ELEMENT_PAIRS;
+}
+
+/**
+ * @brief This method returns the sgl element pair for the specificed
+ * sgl_pair index.
+ *
+ * @param[in] this_request This parameter specifies the IO request for which
+ * to retrieve the Scatter-Gather List element pair.
+ * @param[in] sgl_pair_index This parameter specifies the index into the SGL
+ * element pair to be retrieved.
+ *
+ * @return This method returns a pointer to an SCU_SGL_ELEMENT_PAIR.
+ */
+SCU_SGL_ELEMENT_PAIR_T *scic_sds_request_get_sgl_element_pair(
+ SCIC_SDS_REQUEST_T *this_request,
+ U32 sgl_pair_index
+)
+{
+ SCU_TASK_CONTEXT_T *task_context;
+
+ task_context = (SCU_TASK_CONTEXT_T *)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];
+}
+
+/**
+ * @brief This function will build the SGL list for an IO request.
+ *
+ * @param[in] this_request This parameter specifies the IO request for which
+ * to build the Scatter-Gather List.
+ *
+ * @return none
+ */
+void scic_sds_request_build_sgl(
+ SCIC_SDS_REQUEST_T *this_request
+)
+{
+ void *os_sge;
+ void *os_handle;
+ SCI_PHYSICAL_ADDRESS physical_address;
+ U32 sgl_pair_index = 0;
+ SCU_SGL_ELEMENT_PAIR_T *scu_sgl_list = NULL;
+ SCU_SGL_ELEMENT_PAIR_T *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 =
+ sci_cb_physical_address_upper(physical_address);
+ previous_pair->next_pair_lower =
+ sci_cb_physical_address_lower(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;
+ }
+}
+
+/**
+ * @brief This method initializes common portions of the io request object.
+ * This includes construction of the SCI_BASE_REQUEST_T parent.
+ *
+ * @param[in] the_controller This parameter specifies the controller for which
+ * the request is being constructed.
+ * @param[in] the_target This parameter specifies the remote device for which
+ * the request is being constructed.
+ * @param[in] 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.
+ * @param[in] user_io_request_object This parameter specifies the user
+ * request object for which the request is being constructed.
+ * @param[in] this_request This parameter specifies the request being
+ * constructed.
+ *
+ * @return none
+ */
+static
+void scic_sds_general_request_construct(
+ SCIC_SDS_CONTROLLER_T * the_controller,
+ SCIC_SDS_REMOTE_DEVICE_T * the_target,
+ U16 io_tag,
+ void * user_io_request_object,
+ SCIC_SDS_REQUEST_T * this_request
+)
+{
+ sci_base_request_construct(
+ &this_request->parent,
+ sci_base_object_get_logger(the_controller),
+ 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->sat_protocol = 0xFF;
+ 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);
+ }
+}
+
+/**
+ * @brief This method build the remainder of the IO request object.
+ *
+ * @pre The scic_sds_general_request_construct() must be called before this
+ * call is valid.
+ *
+ * @param[in] this_request This parameter specifies the request object being
+ * constructed.
+ *
+ * @return none
+ */
+void scic_sds_ssp_io_request_assign_buffers(
+ SCIC_SDS_REQUEST_T *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);
+ }
+}
+
+/**
+ * @brief This method constructs the SSP Command IU data for this io
+ * request object.
+ *
+ * @param[in] this_request This parameter specifies the request object for
+ * which the SSP command information unit is being built.
+ *
+ * @return none
+ */
+static
+void scic_sds_io_request_build_ssp_command_iu(
+ SCIC_SDS_REQUEST_T *this_request
+)
+{
+ SCI_SINGLE_LEVEL_LUN_T lun;
+ SCI_SSP_COMMAND_IU_T *command_frame;
+ void *os_handle;
+ U32 cdb_length;
+ U32 *cdb_buffer;
+
+ command_frame =
+ (SCI_SSP_COMMAND_IU_T *)this_request->command_buffer;
+
+ os_handle = scic_sds_request_get_user_request(this_request);
+
+ ((U32 *)&lun)[0] = 0;
+ ((U32 *)&lun)[1] = 0;
+ lun.lun_number = scic_cb_ssp_io_request_get_lun(os_handle) &0xff;
+ /// @todo Is it ok to leave junk at the end of the cdb buffer?
+ scic_word_copy_with_swap(
+ (U32 *)command_frame->lun,
+ (U32 *)&lun,
+ sizeof(lun));
+
+ ((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);
+}
+
+#if !defined(DISABLE_TASK_MANAGEMENT)
+
+/**
+ * @brief This method constructs the SSP Task IU data for this io request
+ * object.
+ *
+ * @param[in] this_request
+ *
+ * @return none
+ */
+static
+void scic_sds_task_request_build_ssp_task_iu(
+ SCIC_SDS_REQUEST_T *this_request
+)
+{
+ SCI_SSP_TASK_IU_T *command_frame;
+ void *os_handle;
+
+ command_frame =
+ (SCI_SSP_TASK_IU_T *)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);
+}
+
+#endif // !defined(DISABLE_TASK_MANAGEMENT)
+
+/**
+ * @brief This method is will fill in the SCU Task Context for any type of
+ * SSP request.
+ *
+ * @param[in] this_request
+ * @param[in] task_context
+ *
+ * @return none
+ */
+static
+void scu_ssp_reqeust_construct_task_context(
+ SCIC_SDS_REQUEST_T * this_request,
+ SCU_TASK_CONTEXT_T * task_context
+)
+{
+ SCI_PHYSICAL_ADDRESS physical_address;
+ SCIC_SDS_CONTROLLER_T *owning_controller;
+ SCIC_SDS_REMOTE_DEVICE_T *target_device;
+ SCIC_SDS_PORT_T *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 =
+ sci_cb_physical_address_upper(physical_address);
+ task_context->command_iu_lower =
+ sci_cb_physical_address_lower(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 =
+ sci_cb_physical_address_upper(physical_address);
+ task_context->response_iu_lower =
+ sci_cb_physical_address_lower(physical_address);
+}
+
+/**
+ * @brief This method is will fill in the SCU Task Context for a SSP IO
+ * request.
+ *
+ * @param[in] this_request
+ *
+ * @return none
+ */
+static
+void scu_ssp_io_request_construct_task_context(
+ SCIC_SDS_REQUEST_T *this_request,
+ SCI_IO_REQUEST_DATA_DIRECTION data_direction,
+ U32 transfer_length_bytes
+)
+{
+ SCU_TASK_CONTEXT_T *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(SCI_SSP_COMMAND_IU_T) / 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);
+ }
+}
+
+#if !defined(DISABLE_TASK_MANAGEMENT)
+
+/**
+ * @brief This method will fill in the remainder of the io request object
+ * for SSP Task requests.
+ *
+ * @param[in] this_request
+ *
+ * @return none
+ */
+void scic_sds_ssp_task_request_assign_buffers(
+ SCIC_SDS_REQUEST_T *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);
+ }
+}
+
+/**
+ * @brief 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.
+ *
+ * @param[in] this_request This parameter specifies the task request object
+ * being constructed.
+ *
+ * @return none
+ */
+static
+void scu_ssp_task_request_construct_task_context(
+ SCIC_SDS_REQUEST_T *this_request
+)
+{
+ SCU_TASK_CONTEXT_T *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(SCI_SSP_TASK_IU_T) / sizeof(U32);
+}
+
+#endif // !defined(DISABLE_TASK_MANAGEMENT)
+
+#if !defined(DISABLE_PASS_THROUGH)
+/**
+ * @brief This method constructs the SSP Command IU data for this
+ * ssp passthrough comand request object.
+ *
+ * @param[in] this_request This parameter specifies the request object for
+ * which the SSP command information unit is being built.
+ *
+ * @return SCI_STATUS, returns invalid parameter is cdb > 16
+ */
+static
+SCI_STATUS scic_sds_io_request_build_ssp_command_iu_pass_through(
+ SCIC_SDS_REQUEST_T *this_request,
+ SCIC_SSP_PASSTHRU_REQUEST_CALLBACKS_T *ssp_passthru_cb
+)
+{
+ SCI_SSP_COMMAND_IU_T *command_frame;
+ U32 cdb_length = 0, additional_cdb_length = 0;
+ U8 *cdb_buffer, *additional_cdb_buffer;
+ U8 *scsi_lun;
+ SCI_STATUS sci_status = SCI_SUCCESS;
+ SCI_SINGLE_LEVEL_LUN_T lun;
+
+ command_frame =
+ (SCI_SSP_COMMAND_IU_T *)this_request->command_buffer;
+
+ //get the lun
+ ssp_passthru_cb->scic_cb_ssp_passthru_get_lun (
+ this_request,
+ &scsi_lun
+ );
+ memset(&lun, 0, sizeof(lun));
+ lun.lun_number = *scsi_lun;
+ scic_word_copy_with_swap(
+ (U32 *)command_frame->lun,
+ (U32 *)&lun,
+ sizeof(lun));
+
+ ((U32 *)command_frame)[2] = 0;
+
+ ssp_passthru_cb->scic_cb_ssp_passthru_get_cdb(
+ this_request,
+ &cdb_length,
+ &cdb_buffer,
+ &additional_cdb_length,
+ &additional_cdb_buffer
+ );
+
+ command_frame->additional_cdb_length = additional_cdb_length;
+
+ // ----------- TODO
+ ///todo: what to do with additional cdb length and buffer as the current command buffer is
+ // 16 bytes in intel_sas.h
+ // ??? see the SAS command IU
+ if (additional_cdb_length > 0)
+ {
+ return SCI_FAILURE_INVALID_PARAMETER_VALUE;
+ }
+
+ /// @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)
+ );
+
+ /////-------- End fo TODO
+
+ command_frame->enable_first_burst = 0;
+ command_frame->task_priority = 0; //todo: check with Richard ????
+
+ //get the task attribute
+ command_frame->task_attribute = ssp_passthru_cb->scic_cb_ssp_passthru_get_task_attribute (
+ this_request
+ );
+
+ return sci_status;
+}
+#endif // !defined(DISABLE_PASS_THROUGH)
+
+//****************************************************************************
+//* SCIC Interface Implementation
+//****************************************************************************
+
+#if !defined(DISABLE_TASK_MANAGEMENT)
+/**
+ * This method returns the size required to store an SSP task request object.
+ *
+ * @return U32
+ */
+static
+U32 scic_sds_ssp_task_request_get_object_size(void)
+{
+ return sizeof(SCIC_SDS_REQUEST_T)
+ + scic_ssp_task_request_get_object_size()
+ + sizeof(SCU_TASK_CONTEXT_T)
+ + CACHE_LINE_SIZE;
+}
+
+
+U32 scic_task_request_get_object_size(void)
+{
+ U32 ssp_task_request_size;
+ U32 stp_task_request_size;
+
+ ssp_task_request_size = scic_sds_ssp_task_request_get_object_size();
+ stp_task_request_size = scic_sds_stp_task_request_get_object_size();
+
+ return MAX(ssp_task_request_size, stp_task_request_size);
+}
+
+#endif // !defined(DISABLE_TASK_MANAGEMENT)
+
+// ---------------------------------------------------------------------------
+
+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));
+}
+
+// ---------------------------------------------------------------------------
+
+SCIC_TRANSPORT_PROTOCOL scic_io_request_get_protocol(
+ SCI_IO_REQUEST_HANDLE_T scic_io_request
+)
+{
+ SCIC_SDS_REQUEST_T * this_request = (SCIC_SDS_REQUEST_T * )scic_io_request;
+ return this_request->protocol;
+}
+
+// ---------------------------------------------------------------------------
+
+U32 scic_sds_request_get_min_timer_count(void)
+{
+ return SCIC_SDS_IO_REQUEST_MINIMUM_TIMER_COUNT;
+}
+
+// ---------------------------------------------------------------------------
+
+U32 scic_sds_request_get_max_timer_count(void)
+{
+ return SCIC_SDS_IO_REQUEST_MAXIMUM_TIMER_COUNT;
+}
+
+// ---------------------------------------------------------------------------
+
+SCI_STATUS scic_io_request_construct(
+ SCI_CONTROLLER_HANDLE_T scic_controller,
+ SCI_REMOTE_DEVICE_HANDLE_T scic_remote_device,
+ U16 io_tag,
+ void * user_io_request_object,
+ void * scic_io_request_memory,
+ SCI_IO_REQUEST_HANDLE_T * new_scic_io_request_handle
+)
+{
+ SCI_STATUS status = SCI_SUCCESS;
+ SCIC_SDS_REQUEST_T * this_request;
+ SMP_DISCOVER_RESPONSE_PROTOCOLS_T device_protocol;
+
+ this_request = (SCIC_SDS_REQUEST_T * )scic_io_request_memory;
+
+ SCIC_LOG_TRACE((
+ sci_base_object_get_logger(scic_controller),
+ (SCIC_LOG_OBJECT_SSP_IO_REQUEST
+ |SCIC_LOG_OBJECT_SMP_IO_REQUEST
+ |SCIC_LOG_OBJECT_STP_IO_REQUEST),
+ "scic_io_request_construct(0x%x, 0x%x, 0x02x, 0x%x, 0x%x, 0x%x) enter\n",
+ scic_controller, scic_remote_device,
+ io_tag, user_io_request_object,
+ this_request, new_scic_io_request_handle
+ ));
+
+ // Build the common part of the request
+ scic_sds_general_request_construct(
+ (SCIC_SDS_CONTROLLER_T *)scic_controller,
+ (SCIC_SDS_REMOTE_DEVICE_T *)scic_remote_device,
+ io_tag,
+ user_io_request_object,
+ this_request
+ );
+
+ if (
+ scic_sds_remote_device_get_index((SCIC_SDS_REMOTE_DEVICE_T *)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(SATA_FIS_REG_H2D_T));
+ }
+ else if (device_protocol.u.bits.attached_smp_target)
+ {
+ scic_sds_smp_request_assign_buffers(this_request);
+ memset(this_request->command_buffer, 0, sizeof(SMP_REQUEST_T));
+ }
+ else
+ {
+ status = SCI_FAILURE_UNSUPPORTED_PROTOCOL;
+ }
+
+ if (status == SCI_SUCCESS)
+ {
+ memset(
+ this_request->task_context_buffer,
+ 0,
+ SCI_FIELD_OFFSET(SCU_TASK_CONTEXT_T, sgl_pair_ab)
+ );
+ *new_scic_io_request_handle = scic_io_request_memory;
+ }
+
+ return status;
+}
+
+// ---------------------------------------------------------------------------
+
+#if !defined(DISABLE_TASK_MANAGEMENT)
+
+SCI_STATUS scic_task_request_construct(
+ SCI_CONTROLLER_HANDLE_T controller,
+ SCI_REMOTE_DEVICE_HANDLE_T remote_device,
+ U16 io_tag,
+ void *user_io_request_object,
+ void *scic_task_request_memory,
+ SCI_TASK_REQUEST_HANDLE_T *new_scic_task_request_handle
+)
+{
+ SCI_STATUS status = SCI_SUCCESS;
+ SCIC_SDS_REQUEST_T * this_request = (SCIC_SDS_REQUEST_T *)
+ scic_task_request_memory;
+ SMP_DISCOVER_RESPONSE_PROTOCOLS_T device_protocol;
+
+ SCIC_LOG_TRACE((
+ sci_base_object_get_logger(controller),
+ (SCIC_LOG_OBJECT_SSP_IO_REQUEST
+ |SCIC_LOG_OBJECT_SMP_IO_REQUEST
+ |SCIC_LOG_OBJECT_STP_IO_REQUEST),
+ "scic_task_request_construct(0x%x, 0x%x, 0x02x, 0x%x, 0x%x, 0x%x) enter\n",
+ controller, remote_device,
+ io_tag, user_io_request_object,
+ scic_task_request_memory, new_scic_task_request_handle
+ ));
+
+ // Build the common part of the request
+ scic_sds_general_request_construct(
+ (SCIC_SDS_CONTROLLER_T *)controller,
+ (SCIC_SDS_REMOTE_DEVICE_T *)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(SCU_TASK_CONTEXT_T));
+ *new_scic_task_request_handle = scic_task_request_memory;
+ }
+
+ return status;
+}
+
+#endif // !defined(DISABLE_TASK_MANAGEMENT)
+
+// ---------------------------------------------------------------------------
+
+SCI_STATUS scic_io_request_construct_basic_ssp(
+ SCI_IO_REQUEST_HANDLE_T scic_io_request
+)
+{
+ void *os_handle;
+ SCIC_SDS_REQUEST_T *this_request;
+ this_request = (SCIC_SDS_REQUEST_T *)scic_io_request;
+
+ SCIC_LOG_TRACE((
+ sci_base_object_get_logger(this_request),
+ SCIC_LOG_OBJECT_SSP_IO_REQUEST,
+ "scic_io_request_construct_basic_ssp(0x%x) enter\n",
+ this_request
+ ));
+
+ this_request->protocol = SCIC_SSP_PROTOCOL;
+
+ os_handle = scic_sds_request_get_user_request(this_request);
+
+ scu_ssp_io_request_construct_task_context(
+ this_request,
+ 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(this_request);
+
+ scic_sds_request_initialize_state_logging(this_request);
+
+ sci_base_state_machine_change_state(
+ &this_request->parent.state_machine,
+ SCI_BASE_REQUEST_STATE_CONSTRUCTED
+ );
+
+ return SCI_SUCCESS;
+}
+
+// ---------------------------------------------------------------------------
+
+#if !defined(DISABLE_TASK_MANAGEMENT)
+
+SCI_STATUS scic_task_request_construct_ssp(
+ SCI_TASK_REQUEST_HANDLE_T scic_task_request
+)
+{
+ SCIC_SDS_REQUEST_T *this_request = (SCIC_SDS_REQUEST_T *)
+ scic_task_request;
+
+ SCIC_LOG_TRACE((
+ sci_base_object_get_logger(this_request),
+ SCIC_LOG_OBJECT_SSP_IO_REQUEST,
+ "scic_task_request_construct_ssp(0x%x) enter\n",
+ this_request
+ ));
+
+ // Construct the SSP Task SCU Task Context
+ scu_ssp_task_request_construct_task_context(this_request);
+
+ // Fill in the SSP Task IU
+ scic_sds_task_request_build_ssp_task_iu(this_request);
+
+ scic_sds_request_initialize_state_logging(this_request);
+
+ sci_base_state_machine_change_state(
+ &this_request->parent.state_machine,
+ SCI_BASE_REQUEST_STATE_CONSTRUCTED
+ );
+
+ return SCI_SUCCESS;
+}
+
+#endif // !defined(DISABLE_TASK_MANAGEMENT)
+
+// ---------------------------------------------------------------------------
+
+SCI_STATUS scic_io_request_construct_advanced_ssp(
+ SCI_IO_REQUEST_HANDLE_T scic_io_request,
+ SCIC_IO_SSP_PARAMETERS_T * io_parameters
+)
+{
+ SCIC_LOG_TRACE((
+ sci_base_object_get_logger(scic_io_request),
+ SCIC_LOG_OBJECT_SSP_IO_REQUEST,
+ "scic_io_request_construct_advanced_ssp(0x%x, 0x%x) enter\n",
+ io_parameters, scic_io_request
+ ));
+
+ /// @todo Implement after 1.1
+ return SCI_FAILURE;
+}
+
+// ---------------------------------------------------------------------------
+
+#if !defined(DISABLE_PASS_THROUGH)
+SCI_STATUS scic_io_request_construct_ssp_pass_through (
+ void * scic_io_request,
+ SCIC_SSP_PASSTHRU_REQUEST_CALLBACKS_T *ssp_passthru_cb
+)
+{
+ SCI_STATUS status = SCI_SUCCESS;
+ SCIC_SDS_REQUEST_T * this_request;
+
+ this_request = (SCIC_SDS_REQUEST_T * )scic_io_request;
+
+ SCIC_LOG_TRACE((
+ sci_base_object_get_logger(scic_io_request),
+ SCIC_LOG_OBJECT_STP_IO_REQUEST,
+ "scic_io_request_construct_ssp_pass_through(0x%x) enter\n",
+ scic_io_request
+ ));
+
+ //build the task context from the pass through buffer
+ scu_ssp_io_request_construct_task_context(
+ this_request,
+ ssp_passthru_cb->common_callbacks.scic_cb_passthru_get_data_direction (this_request),
+ ssp_passthru_cb->common_callbacks.scic_cb_passthru_get_transfer_length(this_request)
+ );
+
+ //build the ssp command iu from the pass through buffer
+ status = scic_sds_io_request_build_ssp_command_iu_pass_through (
+ this_request,
+ ssp_passthru_cb
+ );
+ if (status != SCI_SUCCESS)
+ {
+ return status;
+ }
+
+ /* initialize the logging */
+ scic_sds_request_initialize_state_logging(this_request);
+
+ sci_base_state_machine_change_state(
+ &this_request->parent.state_machine,
+ SCI_BASE_REQUEST_STATE_CONSTRUCTED
+ );
+
+ return status;
+}
+#endif // !defined(DISABLE_PASS_THROUGH)
+
+// ---------------------------------------------------------------------------
+
+#if !defined(DISABLE_TASK_MANAGEMENT)
+
+SCI_STATUS scic_task_request_construct_sata(
+ SCI_TASK_REQUEST_HANDLE_T scic_task_request
+)
+{
+ SCI_STATUS status;
+ SCIC_SDS_REQUEST_T * this_request;
+ U8 sat_protocol;
+
+ this_request = (SCIC_SDS_REQUEST_T *)scic_task_request;
+
+ SCIC_LOG_TRACE((
+ sci_base_object_get_logger(this_request),
+ SCIC_LOG_OBJECT_STP_IO_REQUEST,
+ "scic_task_request_construct_sata(0x%x) enter\n",
+ this_request
+ ));
+
+ sat_protocol =
+ scic_cb_request_get_sat_protocol(this_request->user_request);
+
+ this_request->sat_protocol = sat_protocol;
+
+ switch (sat_protocol)
+ {
+ 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_PIO_DATA_IN:
+ status = scic_sds_stp_pio_request_construct(this_request, sat_protocol, FALSE);
+ break;
+
+ default:
+ SCIC_LOG_ERROR((
+ sci_base_object_get_logger(this_request),
+ SCIC_LOG_OBJECT_STP_IO_REQUEST,
+ "SCIC IO Request 0x%x received un-handled SAT Protocl %d.\n",
+ this_request, sat_protocol
+ ));
+
+ status = SCI_FAILURE;
+ break;
+ }
+
+ if (status == SCI_SUCCESS)
+ {
+ scic_sds_request_initialize_state_logging(this_request);
+
+ sci_base_state_machine_change_state(
+ &this_request->parent.state_machine,
+ SCI_BASE_REQUEST_STATE_CONSTRUCTED
+ );
+ }
+
+ return status;
+}
+
+#endif // !defined(DISABLE_TASK_MANAGEMENT)
+
+// ---------------------------------------------------------------------------
+
+#if !defined(DISABLE_PASS_THROUGH)
+SCI_STATUS scic_io_request_construct_sata_pass_through(
+ SCI_IO_REQUEST_HANDLE_T scic_io_request,
+ SCIC_STP_PASSTHRU_REQUEST_CALLBACKS_T *passthru_cb
+)
+{
+ SCI_STATUS status = SCI_SUCCESS;
+ SCIC_SDS_REQUEST_T * this_request;
+ U8 sat_protocol;
+ U8 * reg_fis;
+ U32 transfer_length;
+ SCI_IO_REQUEST_DATA_DIRECTION data_direction;
+
+ this_request = (SCIC_SDS_REQUEST_T * )scic_io_request;
+
+ SCIC_LOG_TRACE((
+ sci_base_object_get_logger(scic_io_request),
+ SCIC_LOG_OBJECT_STP_IO_REQUEST,
+ "scic_io_request_construct_sata_pass_through(0x%x) enter\n",
+ scic_io_request
+ ));
+
+ passthru_cb->scic_cb_stp_passthru_get_register_fis(this_request, &reg_fis);
+
+ if (reg_fis == NULL)
+ {
+ status = SCI_FAILURE_INVALID_PARAMETER_VALUE;
+ }
+
+ if (status == SCI_SUCCESS)
+ {
+ //copy the H2D Reg fis blindly from the request to the SCU command buffer
+ memcpy ((U8 *)this_request->command_buffer, (U8 *)reg_fis, sizeof(SATA_FIS_REG_H2D_T));
+
+ //continue to create the request
+ sat_protocol = passthru_cb->scic_cb_stp_passthru_get_protocol(this_request);
+ transfer_length = passthru_cb->common_callbacks.scic_cb_passthru_get_transfer_length(this_request);
+ data_direction = passthru_cb->common_callbacks.scic_cb_passthru_get_data_direction(this_request);
+
+ status = scic_sds_io_request_construct_sata(
+ this_request,
+ sat_protocol,
+ transfer_length,
+ data_direction,
+ TRUE,
+ TRUE
+ );
+
+ this_request->protocol = SCIC_STP_PROTOCOL;
+ }
+
+ return status;
+}
+#endif // !defined(DISABLE_PASS_THROUGH)
+
+// ---------------------------------------------------------------------------
+
+U16 scic_io_request_get_io_tag(
+ SCI_IO_REQUEST_HANDLE_T scic_io_request
+)
+{
+ SCIC_SDS_REQUEST_T *this_request;
+ this_request = (SCIC_SDS_REQUEST_T *)scic_io_request;
+
+ SCIC_LOG_TRACE((
+ sci_base_object_get_logger(scic_io_request),
+ SCIC_LOG_OBJECT_SMP_IO_REQUEST,
+ "scic_io_request_get_io_tag(0x%x) enter\n",
+ scic_io_request
+ ));
+
+ return this_request->io_tag;
+}
+
+// ---------------------------------------------------------------------------
+
+U32 scic_request_get_controller_status(
+ SCI_IO_REQUEST_HANDLE_T io_request
+)
+{
+ SCIC_SDS_REQUEST_T * this_request = (SCIC_SDS_REQUEST_T*)io_request;
+ return this_request->scu_status;
+}
+
+U32 scic_request_get_sci_status(
+ SCI_IO_REQUEST_HANDLE_T io_request
+)
+{
+ SCIC_SDS_REQUEST_T * this_request = (SCIC_SDS_REQUEST_T*)io_request;
+ return this_request->sci_status;
+}
+
+// ---------------------------------------------------------------------------
+
+void * scic_io_request_get_rx_frame(
+ SCI_IO_REQUEST_HANDLE_T scic_io_request,
+ U32 offset
+)
+{
+ void * frame_buffer = NULL;
+ SCIC_SDS_REQUEST_T * this_request = (SCIC_SDS_REQUEST_T *)scic_io_request;
+
+ ASSERT(offset < SCU_UNSOLICITED_FRAME_BUFFER_SIZE);
+
+ if (this_request->saved_rx_frame_index != SCU_INVALID_FRAME_INDEX)
+ {
+ scic_sds_unsolicited_frame_control_get_buffer(
+ &(this_request->owning_controller->uf_control),
+ this_request->saved_rx_frame_index,
+ &frame_buffer
+ );
+ }
+
+ return frame_buffer;
+}
+
+void * scic_io_request_get_command_iu_address(
+ SCI_IO_REQUEST_HANDLE_T scic_io_request
+)
+{
+ SCIC_SDS_REQUEST_T * this_request = (SCIC_SDS_REQUEST_T *)scic_io_request;
+
+ return this_request->command_buffer;
+}
+
+// ---------------------------------------------------------------------------
+
+void * scic_io_request_get_response_iu_address(
+ SCI_IO_REQUEST_HANDLE_T scic_io_request
+)
+{
+ SCIC_SDS_REQUEST_T * this_request = (SCIC_SDS_REQUEST_T *)scic_io_request;
+
+ return this_request->response_buffer;
+}
+
+// ---------------------------------------------------------------------------
+#define SCU_TASK_CONTEXT_SRAM 0x200000
+U32 scic_io_request_get_number_of_bytes_transferred (
+ SCI_IO_REQUEST_HANDLE_T scic_io_request
+)
+{
+ U32 ret_val = 0;
+ SCIC_SDS_REQUEST_T * scic_sds_request;
+
+ scic_sds_request = (SCIC_SDS_REQUEST_T *) scic_io_request;
+
+ 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 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(SCU_TASK_CONTEXT_T, type.ssp.data_offset) ) +
+ ( ( sizeof (SCU_TASK_CONTEXT_T) ) * scic_sds_io_tag_get_index (scic_sds_request->io_tag))
+ )
+ );
+ }
+
+ return ret_val;
+}
+
+//****************************************************************************
+//* SCIC SDS Interface Implementation
+//****************************************************************************
+
+/**
+ * This method invokes the base state start request handler for the
+ * SCIC_SDS_IO_REQUEST_T object.
+ *
+ * @param[in] this_request The SCIC_SDS_IO_REQUEST_T object for which the
+ * start operation is to be executed.
+ *
+ * @return SCI_STATUS
+ */
+SCI_STATUS scic_sds_request_start(
+ SCIC_SDS_REQUEST_T *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 method invokes the base state terminate request handber for the
+ * SCIC_SDS_IO_REQUEST_T object.
+ *
+ * @param[in] this_request The SCIC_SDS_IO_REQUEST_T object for which the
+ * start operation is to be executed.
+ *
+ * @return SCI_STATUS
+ */
+SCI_STATUS scic_sds_io_request_terminate(
+ SCIC_SDS_REQUEST_T *this_request
+)
+{
+ return this_request->state_handlers->parent.abort_handler(
+ &this_request->parent);
+}
+
+/**
+ * This method invokes the base state request completion handler for the
+ * SCIC_SDS_IO_REQUEST_T object.
+ *
+ * @param[in] this_request The SCIC_SDS_IO_REQUEST_T object for which the
+ * start operation is to be executed.
+ *
+ * @return SCI_STATUS
+ */
+SCI_STATUS scic_sds_io_request_complete(
+ SCIC_SDS_REQUEST_T *this_request
+)
+{
+ return this_request->state_handlers->parent.complete_handler(
+ &this_request->parent);
+}
+
+/**
+ * This method invokes the core state handler for the SCIC_SDS_IO_REQUEST_T
+ * object.
+ *
+ * @param[in] this_request The SCIC_SDS_IO_REQUEST_T object for which the
+ * start operation is to be executed.
+ * @param[in] event_code The event code returned by the hardware for the task
+ * reqeust.
+ *
+ * @return SCI_STATUS
+ */
+SCI_STATUS scic_sds_io_request_event_handler(
+ SCIC_SDS_REQUEST_T * this_request,
+ U32 event_code
+)
+{
+ return this_request->state_handlers->event_handler(this_request, event_code);
+}
+
+/**
+ * This method invokes the core state frame handler for the
+ * SCIC_SDS_IO_REQUEST_T object.
+ *
+ * @param[in] this_request The SCIC_SDS_IO_REQUEST_T object for which the
+ * start operation is to be executed.
+ * @param[in] frame_index The frame index returned by the hardware for the
+ * reqeust object.
+ *
+ * @return SCI_STATUS
+ */
+SCI_STATUS scic_sds_io_request_frame_handler(
+ SCIC_SDS_REQUEST_T * this_request,
+ U32 frame_index
+)
+{
+ return this_request->state_handlers->frame_handler(this_request, frame_index);
+}
+
+/**
+ * This method invokes the core state task complete handler for the
+ * SCIC_SDS_IO_REQUEST_T object.
+ *
+ * @param[in] this_request The SCIC_SDS_IO_REQUEST_T object for which the task
+ * start operation is to be executed.
+ *
+ * @return SCI_STATUS
+ */
+SCI_STATUS scic_sds_task_request_complete(
+ SCIC_SDS_REQUEST_T *this_request
+)
+{
+ return this_request->state_handlers->parent.complete_handler(&this_request->parent);
+}
+
+//****************************************************************************
+//* SCIC SDS PROTECTED METHODS
+//****************************************************************************
+
+/**
+ * @brief This method copies response data for requests returning response
+ * data instead of sense data.
+ *
+ * @param[in] this_request This parameter specifies the request object for
+ * which to copy the response data.
+ *
+ * @return none
+ */
+void scic_sds_io_request_copy_response(
+ SCIC_SDS_REQUEST_T *this_request
+)
+{
+ void * response_buffer;
+ U32 user_response_length;
+ U32 core_response_length;
+ SCI_SSP_RESPONSE_IU_T * ssp_response;
+
+ ssp_response = (SCI_SSP_RESPONSE_IU_T *)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);
+}
+
+//******************************************************************************
+//* REQUEST STATE MACHINE
+//******************************************************************************
+
+//*****************************************************************************
+//* DEFAULT STATE HANDLERS
+//*****************************************************************************
+
+/**
+ * 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.
+ *
+ * @param[in] request This is the SCI_BASE_REQUEST_T object that is cast to
+ * the SCIC_SDS_IO_REQUEST_T object for which the start operation is
+ * requested.
+ *
+ * @return SCI_STATUS
+ * @retval SCI_FAILURE_INVALID_STATE
+ */
+SCI_STATUS scic_sds_request_default_start_handler(
+ SCI_BASE_REQUEST_T *request
+)
+{
+ SCIC_LOG_WARNING((
+ sci_base_object_get_logger((SCIC_SDS_REQUEST_T *)request),
+ (
+ SCIC_LOG_OBJECT_SSP_IO_REQUEST
+ | SCIC_LOG_OBJECT_STP_IO_REQUEST
+ | SCIC_LOG_OBJECT_SMP_IO_REQUEST
+ ),
+ "SCIC IO Request requested to start while in wrong state %d\n",
+ sci_base_state_machine_get_state(
+ &((SCIC_SDS_REQUEST_T *)request)->parent.state_machine)
+ ));
+
+ return SCI_FAILURE_INVALID_STATE;
+}
+
+/**
+ * This method is the default action to take when an SCIC_SDS_IO_REQUEST_T
+ * object receives a scic_sds_request_terminate() request. The default action
+ * is to log a warning and return a failure status.
+ *
+ * @param[in] request This is the SCI_BASE_REQUEST_T object that is cast to
+ * the SCIC_SDS_IO_REQUEST_T object for which the start operation is
+ * requested.
+ *
+ * @return SCI_STATUS
+ * @retval SCI_FAILURE_INVALID_STATE
+ */
+SCI_STATUS scic_sds_request_default_abort_handler(
+ SCI_BASE_REQUEST_T *request
+)
+{
+ SCIC_LOG_WARNING((
+ sci_base_object_get_logger((SCIC_SDS_REQUEST_T *)request),
+ (
+ SCIC_LOG_OBJECT_SSP_IO_REQUEST
+ | SCIC_LOG_OBJECT_STP_IO_REQUEST
+ | SCIC_LOG_OBJECT_SMP_IO_REQUEST
+ ),
+ "SCIC IO Request requested to abort while in wrong state %d\n",
+ sci_base_state_machine_get_state(
+ &((SCIC_SDS_REQUEST_T *)request)->parent.state_machine)
+ ));
+
+ return SCI_FAILURE_INVALID_STATE;
+}
+
+/**
+ * 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.
+ *
+ * @param[in] request This is the SCI_BASE_REQUEST_T object that is cast to
+ * the SCIC_SDS_IO_REQUEST_T object for which the start operation is
+ * requested.
+ *
+ * @return SCI_STATUS
+ * @retval SCI_FAILURE_INVALID_STATE
+ */
+SCI_STATUS scic_sds_request_default_complete_handler(
+ SCI_BASE_REQUEST_T *request
+)
+{
+ SCIC_LOG_WARNING((
+ sci_base_object_get_logger((SCIC_SDS_REQUEST_T *)request),
+ (
+ SCIC_LOG_OBJECT_SSP_IO_REQUEST
+ | SCIC_LOG_OBJECT_STP_IO_REQUEST
+ | SCIC_LOG_OBJECT_SMP_IO_REQUEST
+ ),
+ "SCIC IO Request requested to complete while in wrong state %d\n",
+ sci_base_state_machine_get_state(
+ &((SCIC_SDS_REQUEST_T *)request)->parent.state_machine)
+ ));
+
+ return SCI_FAILURE_INVALID_STATE;
+}
+
+/**
+ * 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.
+ *
+ * @param[in] request This is the SCI_BASE_REQUEST_T object that is cast to
+ * the SCIC_SDS_IO_REQUEST_T object for which the start operation is
+ * requested.
+ *
+ * @return SCI_STATUS
+ * @retval SCI_FAILURE_INVALID_STATE
+ */
+SCI_STATUS scic_sds_request_default_destruct_handler(
+ SCI_BASE_REQUEST_T *request
+)
+{
+ SCIC_LOG_WARNING((
+ sci_base_object_get_logger((SCIC_SDS_REQUEST_T *)request),
+ (
+ SCIC_LOG_OBJECT_SSP_IO_REQUEST
+ | SCIC_LOG_OBJECT_STP_IO_REQUEST
+ | SCIC_LOG_OBJECT_SMP_IO_REQUEST
+ ),
+ "SCIC IO Request requested to destroy while in wrong state %d\n",
+ sci_base_state_machine_get_state(
+ &((SCIC_SDS_REQUEST_T *)request)->parent.state_machine)
+ ));
+
+ return SCI_FAILURE_INVALID_STATE;
+}
+
+/**
+ * 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.
+ *
+ * @param[in] request This is the SCI_BASE_REQUEST_T object that is cast to
+ * the SCIC_SDS_IO_REQUEST_T object for which the start operation is
+ * requested.
+ *
+ * @return SCI_STATUS
+ * @retval SCI_FAILURE_INVALID_STATE
+ */
+SCI_STATUS scic_sds_request_default_tc_completion_handler(
+ SCIC_SDS_REQUEST_T * this_request,
+ U32 completion_code
+)
+{
+ SCIC_LOG_WARNING((
+ sci_base_object_get_logger(this_request),
+ (
+ SCIC_LOG_OBJECT_SSP_IO_REQUEST
+ | SCIC_LOG_OBJECT_STP_IO_REQUEST
+ | SCIC_LOG_OBJECT_SMP_IO_REQUEST
+ ),
+ "SCIC IO Request given task completion notification %x while in wrong state %d\n",
+ completion_code,
+ sci_base_state_machine_get_state(&this_request->parent.state_machine)
+ ));
+
+ return SCI_FAILURE_INVALID_STATE;
+
+}
+
+/**
+ * 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.
+ *
+ * @param[in] request This is the SCI_BASE_REQUEST_T object that is cast to
+ * the SCIC_SDS_IO_REQUEST_T object for which the start operation is
+ * requested.
+ *
+ * @return SCI_STATUS
+ * @retval SCI_FAILURE_INVALID_STATE
+ */
+SCI_STATUS scic_sds_request_default_event_handler(
+ SCIC_SDS_REQUEST_T * this_request,
+ U32 event_code
+)
+{
+ SCIC_LOG_WARNING((
+ sci_base_object_get_logger(this_request),
+ (
+ SCIC_LOG_OBJECT_SSP_IO_REQUEST
+ | SCIC_LOG_OBJECT_STP_IO_REQUEST
+ | SCIC_LOG_OBJECT_SMP_IO_REQUEST
+ ),
+ "SCIC IO Request given event code notification %x while in wrong state %d\n",
+ event_code,
+ sci_base_state_machine_get_state(&this_request->parent.state_machine)
+ ));
+
+ return SCI_FAILURE_INVALID_STATE;
+}
+
+/**
+ * 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.
+ *
+ * @param[in] request This is the SCI_BASE_REQUEST_T object that is cast to
+ * the SCIC_SDS_IO_REQUEST_T object for which the start operation is
+ * requested.
+ *
+ * @return SCI_STATUS
+ * @retval SCI_FAILURE_INVALID_STATE
+ */
+SCI_STATUS scic_sds_request_default_frame_handler(
+ SCIC_SDS_REQUEST_T * this_request,
+ U32 frame_index
+)
+{
+ SCIC_LOG_WARNING((
+ sci_base_object_get_logger(this_request),
+ (
+ SCIC_LOG_OBJECT_SSP_IO_REQUEST
+ | SCIC_LOG_OBJECT_STP_IO_REQUEST
+ | SCIC_LOG_OBJECT_SMP_IO_REQUEST
+ ),
+ "SCIC IO Request given unexpected frame %x while in state %d\n",
+ 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
+//*****************************************************************************
+
+/**
+ * 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.
+ *
+ * @param[in] request This is the SCI_BASE_REQUEST_T object that is cast to
+ * the SCIC_SDS_IO_REQUEST_T object for which the start operation is
+ * requested.
+ *
+ * @return SCI_STATUS
+ * @retval SCI_SUCCESS
+ * @retval SCI_FAILURE_INSUFFICIENT_RESOURCES
+ */
+static
+SCI_STATUS scic_sds_request_constructed_state_start_handler(
+ SCI_BASE_REQUEST_T *request
+)
+{
+ SCU_TASK_CONTEXT_T *task_context;
+ SCIC_SDS_REQUEST_T *this_request = (SCIC_SDS_REQUEST_T *)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;
+}
+
+/**
+ * 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.
+ *
+ * @param[in] request This is the SCI_BASE_REQUEST_T object that is cast to
+ * the SCIC_SDS_IO_REQUEST_T object for which the start operation is
+ * requested.
+ *
+ * @return SCI_STATUS
+ * @retval SCI_SUCCESS
+ */
+static
+SCI_STATUS scic_sds_request_constructed_state_abort_handler(
+ SCI_BASE_REQUEST_T *request
+)
+{
+ SCIC_SDS_REQUEST_T *this_request = (SCIC_SDS_REQUEST_T *)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
+//*****************************************************************************
+
+/**
+ * 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.
+ *
+ * @param[in] request This is the SCI_BASE_REQUEST_T object that is cast to
+ * the SCIC_SDS_IO_REQUEST_T object for which the start operation is
+ * requested.
+ *
+ * @return SCI_STATUS
+ * @retval SCI_SUCCESS
+ */
+SCI_STATUS scic_sds_request_started_state_abort_handler(
+ SCI_BASE_REQUEST_T *request
+)
+{
+ SCIC_SDS_REQUEST_T *this_request = (SCIC_SDS_REQUEST_T *)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;
+}
+
+/**
+ * @brief 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.
+ *
+ * @param[in] this_request This parameter specifies the request for which
+ * a completion occurred.
+ * @param[in] completion_code This parameter specifies the completion code
+ * recieved from the SCU.
+ *
+ * @return none
+ */
+SCI_STATUS scic_sds_request_started_state_tc_completion_handler(
+ SCIC_SDS_REQUEST_T * this_request,
+ U32 completion_code
+)
+{
+ U8 data_present;
+ SCI_SSP_RESPONSE_IU_T * 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.
+ SCI_SSP_RESPONSE_IU_T *response = (SCI_SSP_RESPONSE_IU_T *)
+ this_request->response_buffer;
+ scic_word_copy_with_swap(
+ this_request->response_buffer,
+ this_request->response_buffer,
+ sizeof(SCI_SSP_RESPONSE_IU_T) / 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(SCI_SSP_RESPONSE_IU_T) / 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 =
+ (SCI_SSP_RESPONSE_IU_T *)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_LOG_ERROR((
+ sci_base_object_get_logger(this_request),
+ SCIC_LOG_OBJECT_STP_IO_REQUEST,
+ "SCIC IO Request 0x%x returning REMOTE_DEVICE_RESET_REQUIRED for completion code 0x%x\n",
+ this_request, completion_code
+ ));
+ 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_LOG_ERROR((
+ sci_base_object_get_logger(this_request),
+ SCIC_LOG_OBJECT_SSP_IO_REQUEST,
+ "SCIC IO Request 0x%x returning CONTROLLER_SPECIFIC_IO_ERR for completion code 0x%x\n",
+ this_request, completion_code
+ ));
+ 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_LOG_ERROR((
+ sci_base_object_get_logger(this_request),
+ SCIC_LOG_OBJECT_SSP_IO_REQUEST | SCIC_LOG_OBJECT_STP_IO_REQUEST,
+ "SCIC IO Request 0x%x returning CONTROLLER_SPECIFIC_IO_ERR for completion code 0x%x\n",
+ this_request, completion_code
+ ));
+ 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;
+}
+
+/**
+ * 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.
+ *
+ * @param[in] request This is the SCI_BASE_REQUEST_T object that is cast to
+ * the SCIC_SDS_IO_REQUEST_T object for which the start operation is
+ * requested.
+ * @param[in] frame_index This is the index of the unsolicited frame to be
+ * processed.
+ *
+ * @return SCI_STATUS
+ * @retval SCI_SUCCESS
+ * @retval SCI_FAILURE_INVALID_PARAMETER_VALUE
+ */
+static
+SCI_STATUS scic_sds_request_started_state_frame_handler(
+ SCIC_SDS_REQUEST_T * this_request,
+ U32 frame_index
+)
+{
+ SCI_STATUS status;
+ SCI_SSP_FRAME_HEADER_T *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)
+ {
+ SCI_SSP_RESPONSE_IU_T *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(SCI_SSP_RESPONSE_IU_T)
+ );
+
+ response_buffer = (SCI_SSP_RESPONSE_IU_T *)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?
+ SCIC_LOG_ERROR((
+ sci_base_object_get_logger(this_request),
+ SCIC_LOG_OBJECT_SSP_IO_REQUEST,
+ "SCIC IO Request 0x%x received unexpected frame %d type 0x%02x\n",
+ 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
+//*****************************************************************************
+
+
+/**
+ * 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.
+ *
+ * @todo Consider stopping the state machine instead of transitioning to the
+ * final state?
+ *
+ * @param[in] request This is the SCI_BASE_REQUEST_T object that is cast to
+ * the SCIC_SDS_IO_REQUEST_T object for which the start operation is
+ * requested.
+ *
+ * @return SCI_STATUS
+ * @retval SCI_SUCCESS
+ */
+static
+SCI_STATUS scic_sds_request_completed_state_complete_handler(
+ SCI_BASE_REQUEST_T *request
+)
+{
+ SCIC_SDS_REQUEST_T *this_request = (SCIC_SDS_REQUEST_T *)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
+ );
+
+ scic_sds_request_deinitialize_state_logging(this_request);
+
+ return SCI_SUCCESS;
+}
+
+//*****************************************************************************
+//* ABORTING STATE HANDLERS
+//*****************************************************************************
+
+/**
+ * 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.
+ *
+ * @param[in] request This is the SCI_BASE_REQUEST_T object that is cast to
+ * the SCIC_SDS_IO_REQUEST_T object for which the start operation is
+ * requested.
+ *
+ * @return SCI_STATUS
+ * @retval SCI_SUCCESS
+ */
+static
+SCI_STATUS scic_sds_request_aborting_state_abort_handler(
+ SCI_BASE_REQUEST_T *request
+)
+{
+ SCIC_SDS_REQUEST_T *this_request = (SCIC_SDS_REQUEST_T *)request;
+
+ sci_base_state_machine_change_state(
+ &this_request->parent.state_machine,
+ SCI_BASE_REQUEST_STATE_COMPLETED
+ );
+
+ return SCI_SUCCESS;
+}
+
+/**
+ * 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.
+ *
+ * @param[in] request This is the SCI_BASE_REQUEST_T object that is cast to
+ * the SCIC_SDS_IO_REQUEST_T object for which the start operation is
+ * requested.
+ *
+ * @return SCI_STATUS
+ * @retval SCI_SUCCESS
+ */
+static
+SCI_STATUS scic_sds_request_aborting_state_tc_completion_handler(
+ SCIC_SDS_REQUEST_T * this_request,
+ U32 completion_code
+)
+{
+ SCIC_LOG_TRACE((
+ sci_base_object_get_logger(this_request),
+ SCIC_LOG_OBJECT_TASK_MANAGEMENT,
+ "scic_sds_request_aborting_state_tc_completion_handler(0x%x,0x%x) enter\n",
+ this_request, 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;
+}
+
+/**
+ * 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.
+ *
+ * @param[in] request This is the SCI_BASE_REQUEST_T object that is cast to
+ * the SCIC_SDS_IO_REQUEST_T object for which the start operation is
+ * requested.
+ *
+ * @return SCI_STATUS
+ * @retval SCI_SUCCESS
+ */
+static
+SCI_STATUS scic_sds_request_aborting_state_frame_handler(
+ SCIC_SDS_REQUEST_T * 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;
+}
+
+// ---------------------------------------------------------------------------
+
+SCIC_SDS_IO_REQUEST_STATE_HANDLER_T
+ scic_sds_request_state_handler_table[SCI_BASE_REQUEST_MAX_STATES] =
+{
+ // SCI_BASE_REQUEST_STATE_INITIAL
+ {
+ {
+ scic_sds_request_default_start_handler,
+ scic_sds_request_default_abort_handler,
+ scic_sds_request_default_complete_handler,
+ scic_sds_request_default_destruct_handler
+ },
+ scic_sds_request_default_tc_completion_handler,
+ scic_sds_request_default_event_handler,
+ scic_sds_request_default_frame_handler
+ },
+ // SCI_BASE_REQUEST_STATE_CONSTRUCTED
+ {
+ {
+ scic_sds_request_constructed_state_start_handler,
+ scic_sds_request_constructed_state_abort_handler,
+ scic_sds_request_default_complete_handler,
+ scic_sds_request_default_destruct_handler
+ },
+ scic_sds_request_default_tc_completion_handler,
+ scic_sds_request_default_event_handler,
+ scic_sds_request_default_frame_handler
+ },
+ // SCI_BASE_REQUEST_STATE_STARTED
+ {
+ {
+ scic_sds_request_default_start_handler,
+ scic_sds_request_started_state_abort_handler,
+ scic_sds_request_default_complete_handler,
+ scic_sds_request_default_destruct_handler
+ },
+ scic_sds_request_started_state_tc_completion_handler,
+ scic_sds_request_default_event_handler,
+ scic_sds_request_started_state_frame_handler
+ },
+ // SCI_BASE_REQUEST_STATE_COMPLETED
+ {
+ {
+ scic_sds_request_default_start_handler,
+ scic_sds_request_default_abort_handler,
+ scic_sds_request_completed_state_complete_handler,
+ scic_sds_request_default_destruct_handler
+ },
+ scic_sds_request_default_tc_completion_handler,
+ scic_sds_request_default_event_handler,
+ scic_sds_request_default_frame_handler
+ },
+ // SCI_BASE_REQUEST_STATE_ABORTING
+ {
+ {
+ scic_sds_request_default_start_handler,
+ scic_sds_request_aborting_state_abort_handler,
+ scic_sds_request_default_complete_handler,
+ scic_sds_request_default_destruct_handler
+ },
+ scic_sds_request_aborting_state_tc_completion_handler,
+ scic_sds_request_default_event_handler,
+ scic_sds_request_aborting_state_frame_handler,
+ },
+ // SCI_BASE_REQUEST_STATE_FINAL
+ {
+ {
+ scic_sds_request_default_start_handler,
+ scic_sds_request_default_abort_handler,
+ scic_sds_request_default_complete_handler,
+ scic_sds_request_default_destruct_handler
+ },
+ scic_sds_request_default_tc_completion_handler,
+ scic_sds_request_default_event_handler,
+ scic_sds_request_default_frame_handler
+ }
+};
+
+/**
+ * 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.
+ *
+ * @param[in] object This parameter specifies the base object for which the
+ * state transition is occurring.
+ *
+ * @return none
+ */
+static
+void scic_sds_request_initial_state_enter(
+ SCI_BASE_OBJECT_T *object
+)
+{
+ SCIC_SDS_REQUEST_T *this_request = (SCIC_SDS_REQUEST_T *)object;
+
+ SET_STATE_HANDLER(
+ this_request,
+ scic_sds_request_state_handler_table,
+ SCI_BASE_REQUEST_STATE_INITIAL
+ );
+}
+
+/**
+ * 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.
+ *
+ * @param[in] object The io request object that is to enter the constructed
+ * state.
+ *
+ * @return none
+ */
+static
+void scic_sds_request_constructed_state_enter(
+ SCI_BASE_OBJECT_T *object
+)
+{
+ SCIC_SDS_REQUEST_T *this_request = (SCIC_SDS_REQUEST_T *)object;
+
+ SET_STATE_HANDLER(
+ this_request,
+ scic_sds_request_state_handler_table,
+ SCI_BASE_REQUEST_STATE_CONSTRUCTED
+ );
+}
+
+/**
+ * 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.
+ *
+ * @param[in] object This parameter specifies the base object for which the
+ * state transition is occuring. This is cast into a
+ * SCIC_SDS_IO_REQUEST object.
+ *
+ * @return none
+ */
+static
+void scic_sds_request_started_state_enter(
+ SCI_BASE_OBJECT_T *object
+)
+{
+ SCIC_SDS_REQUEST_T *this_request = (SCIC_SDS_REQUEST_T *)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);
+}
+
+/**
+ * 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.
+ *
+ * @param[in] 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.
+ *
+ * @return none
+ */
+static
+void scic_sds_request_started_state_exit(
+ SCI_BASE_OBJECT_T *object
+)
+{
+ SCIC_SDS_REQUEST_T *this_request = (SCIC_SDS_REQUEST_T *)object;
+
+ if (this_request->has_started_substate_machine == TRUE)
+ sci_base_state_machine_stop(&this_request->started_substate_machine);
+}
+
+/**
+ * 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 SCI_STATUS to return in the
+ * completion callback function.
+ *
+ * @param[in] 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.
+ *
+ * @return none
+ */
+static
+void scic_sds_request_completed_state_enter(
+ SCI_BASE_OBJECT_T *object
+)
+{
+ SCIC_SDS_REQUEST_T *this_request = (SCIC_SDS_REQUEST_T *)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
+ );
+ }
+}
+
+/**
+ * This method implements the actions taken when entering the
+ * SCI_BASE_REQUEST_STATE_ABORTING state.
+ *
+ * @param[in] 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.
+ *
+ * @return none
+ */
+static
+void scic_sds_request_aborting_state_enter(
+ SCI_BASE_OBJECT_T *object
+)
+{
+ SCIC_SDS_REQUEST_T *this_request = (SCIC_SDS_REQUEST_T *)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
+ );
+}
+
+/**
+ * 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.
+ *
+ * @param[in] object This parameter specifies the base object for which the
+ * state transition is occuring. This is cast into a
+ * SCIC_SDS_IO_REQUEST object.
+ *
+ * @return none
+ */
+static
+void scic_sds_request_final_state_enter(
+ SCI_BASE_OBJECT_T *object
+)
+{
+ SCIC_SDS_REQUEST_T *this_request = (SCIC_SDS_REQUEST_T *)object;
+
+ SET_STATE_HANDLER(
+ this_request,
+ scic_sds_request_state_handler_table,
+ SCI_BASE_REQUEST_STATE_FINAL
+ );
+}
+
+// ---------------------------------------------------------------------------
+
+SCI_BASE_STATE_T
+ scic_sds_request_state_table[SCI_BASE_REQUEST_MAX_STATES] =
+{
+ {
+ SCI_BASE_REQUEST_STATE_INITIAL,
+ scic_sds_request_initial_state_enter,
+ NULL
+ },
+ {
+ SCI_BASE_REQUEST_STATE_CONSTRUCTED,
+ scic_sds_request_constructed_state_enter,
+ NULL
+ },
+ {
+ SCI_BASE_REQUEST_STATE_STARTED,
+ scic_sds_request_started_state_enter,
+ scic_sds_request_started_state_exit
+ },
+ {
+ SCI_BASE_REQUEST_STATE_COMPLETED,
+ scic_sds_request_completed_state_enter,
+ NULL
+ },
+ {
+ SCI_BASE_REQUEST_STATE_ABORTING,
+ scic_sds_request_aborting_state_enter,
+ NULL
+ },
+ {
+ SCI_BASE_REQUEST_STATE_FINAL,
+ scic_sds_request_final_state_enter,
+ NULL
+ }
+};
+
diff --git a/sys/dev/isci/scil/scic_sds_request.h b/sys/dev/isci/scil/scic_sds_request.h
new file mode 100644
index 0000000..bb8083e
--- /dev/null
+++ b/sys/dev/isci/scil/scic_sds_request.h
@@ -0,0 +1,543 @@
+/*-
+ * 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.
+ *
+ * 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.
+ *
+ * $FreeBSD$
+ */
+#ifndef _SCIC_SDS_IO_REQUEST_H_
+#define _SCIC_SDS_IO_REQUEST_H_
+
+/**
+ * @file
+ *
+ * @brief This file contains the structures, constants and prototypes for the
+ * SCIC_SDS_IO_REQUEST object.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif // __cplusplus
+
+#include <dev/isci/scil/scic_io_request.h>
+
+#include <dev/isci/scil/sci_base_request.h>
+#include <dev/isci/scil/sci_base_state_machine_logger.h>
+#include <dev/isci/scil/scu_task_context.h>
+#include <dev/isci/scil/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
+ *
+ * @brief This enumeration depicts all of the substates for a task
+ * management request to be performed in the STARTED super-state.
+ */
+typedef 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,
+
+ SCIC_SDS_IO_REQUEST_STARTED_TASK_MGMT_MAX_SUBSTATES
+
+} SCIC_SDS_RAW_REQUEST_STARTED_TASK_MGMT_SUBSTATES;
+
+
+/**
+ * @enum _SCIC_SDS_SMP_REQUEST_STARTED_SUBSTATES
+ *
+ * @brief This enumeration depicts all of the substates for a SMP
+ * request to be performed in the STARTED super-state.
+ */
+typedef 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,
+
+ SCIC_SDS_SMP_REQUEST_STARTED_MAX_SUBSTATES
+
+} SCIC_SDS_SMP_REQUEST_STARTED_SUBSTATES;
+
+/**
+ * @struct SCIC_SDS_IO_REQUEST
+ *
+ * @brief This structure contains or references all of the data necessary
+ * to process a task management or normal IO request.
+ */
+typedef struct SCIC_SDS_REQUEST
+{
+ /**
+ * This field indictes the parent object of the request.
+ */
+ SCI_BASE_REQUEST_T 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 sat protocol being utilized for this
+ * IO request, such as SAT_PROTOCOL_PIO_DATA_IN, SAT_PROTOCOL_FPDMA etc.
+ */
+ U8 sat_protocol;
+
+ /**
+ * 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;
+ SCU_TASK_CONTEXT_T *task_context_buffer;
+ SCU_SGL_ELEMENT_PAIR_T *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.
+ */
+ SCI_BASE_STATE_MACHINE_T 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.
+ */
+ struct SCIC_SDS_IO_REQUEST_STATE_HANDLER *state_handlers;
+
+ #ifdef SCI_LOGGING
+ /**
+ * This field is the observer of the started subsate machine
+ */
+ SCI_BASE_STATE_MACHINE_LOGGER_T started_substate_machine_logger;
+ #endif
+
+ /**
+ * 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;
+
+} SCIC_SDS_REQUEST_T;
+
+
+typedef SCI_STATUS (*SCIC_SDS_IO_REQUEST_FRAME_HANDLER_T)(
+ SCIC_SDS_REQUEST_T * this_request,
+ U32 frame_index);
+
+typedef SCI_STATUS (*SCIC_SDS_IO_REQUEST_EVENT_HANDLER_T)(
+ SCIC_SDS_REQUEST_T * this_request,
+ U32 event_code);
+
+typedef SCI_STATUS (*SCIC_SDS_IO_REQUEST_TASK_COMPLETION_HANDLER_T)(
+ SCIC_SDS_REQUEST_T * this_request,
+ U32 completion_code);
+
+/**
+ * @struct SCIC_SDS_IO_REQUEST_STATE_HANDLER
+ *
+ * @brief This is the SDS core definition of the state handlers.
+ */
+typedef struct SCIC_SDS_IO_REQUEST_STATE_HANDLER
+{
+ SCI_BASE_REQUEST_STATE_HANDLER_T 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;
+
+} SCIC_SDS_IO_REQUEST_STATE_HANDLER_T;
+
+extern SCI_BASE_STATE_T scic_sds_request_state_table[];
+extern SCIC_SDS_IO_REQUEST_STATE_HANDLER_T
+ scic_sds_request_state_handler_table[];
+
+extern SCI_BASE_STATE_T scic_sds_io_request_started_task_mgmt_substate_table[];
+extern SCIC_SDS_IO_REQUEST_STATE_HANDLER_T
+ scic_sds_ssp_task_request_started_substate_handler_table[];
+
+extern SCI_BASE_STATE_T scic_sds_smp_request_started_substate_table[];
+extern SCIC_SDS_IO_REQUEST_STATE_HANDLER_T
+ 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)
+
+/**
+ * This macro will return the controller for this io request object
+ */
+#define scic_sds_request_get_controller(this_request) \
+ ((this_request)->owning_controller)
+
+/**
+ * This macro will return the device for this io request object
+ */
+#define scic_sds_request_get_device(this_request) \
+ ((this_request)->target_device)
+
+/**
+ * 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))
+
+/**
+ * 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)
+
+/**
+ * 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) \
+ ((SCU_TASK_CONTEXT_T *)( \
+ (((POINTER_UINT)(address)) + (CACHE_LINE_SIZE - 1)) \
+ & ~(CACHE_LINE_SIZE - 1) \
+ ))
+
+/**
+ * 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) \
+ ((SCU_SGL_ELEMENT_PAIR_T *)( \
+ ((char *)(address)) \
+ + ( \
+ ((~(POINTER_UINT)(address)) + 1) \
+ & (sizeof(SCU_SGL_ELEMENT_PAIR_T) - 1) \
+ ) \
+ ))
+
+/**
+ * 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))
+
+U32 scic_sds_request_get_min_timer_count(void);
+
+U32 scic_sds_request_get_max_timer_count(void);
+
+
+/**
+ * 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); \
+}
+
+/**
+ * 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; \
+}
+
+/**
+ * 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 = \
+ sci_cb_physical_address_upper(scic_cb_sge_get_address_field(os_handle, os_sge)); \
+ (scu_sge).address_lower = \
+ sci_cb_physical_address_lower(scic_cb_sge_get_address_field(os_handle, os_sge)); \
+ (scu_sge).address_modifier = 0; \
+}
+
+//*****************************************************************************
+//* CORE REQUEST PROTOTYPES
+//*****************************************************************************
+
+SCU_SGL_ELEMENT_PAIR_T *scic_sds_request_get_sgl_element_pair(
+ SCIC_SDS_REQUEST_T *this_request,
+ U32 sgl_pair_index
+);
+
+void scic_sds_request_build_sgl(
+ SCIC_SDS_REQUEST_T *this_request
+);
+
+void scic_sds_ssp_io_request_assign_buffers(
+ SCIC_SDS_REQUEST_T *this_request
+);
+
+void scic_sds_ssp_task_request_assign_buffers(
+ SCIC_SDS_REQUEST_T *this_request
+);
+
+void scic_sds_stp_request_assign_buffers(
+ SCIC_SDS_REQUEST_T * this_request
+);
+
+void scic_sds_smp_request_assign_buffers(
+ SCIC_SDS_REQUEST_T * this_request
+);
+
+// ---------------------------------------------------------------------------
+
+SCI_STATUS scic_sds_request_start(
+ SCIC_SDS_REQUEST_T *this_request
+);
+
+SCI_STATUS scic_sds_io_request_terminate(
+ SCIC_SDS_REQUEST_T *this_request
+);
+
+SCI_STATUS scic_sds_io_request_complete(
+ SCIC_SDS_REQUEST_T *this_request
+);
+
+void scic_sds_io_request_copy_response(
+ SCIC_SDS_REQUEST_T *this_request
+);
+
+SCI_STATUS scic_sds_io_request_event_handler(
+ SCIC_SDS_REQUEST_T *this_request,
+ U32 event_code
+);
+
+SCI_STATUS scic_sds_io_request_frame_handler(
+ SCIC_SDS_REQUEST_T *this_request,
+ U32 frame_index
+);
+
+SCI_STATUS scic_sds_task_request_complete(
+ SCIC_SDS_REQUEST_T *this_request
+);
+
+SCI_STATUS scic_sds_task_request_terminate(
+ SCIC_SDS_REQUEST_T *this_request
+);
+
+#ifdef SCI_LOGGING
+void scic_sds_request_initialize_state_logging(
+ SCIC_SDS_REQUEST_T *this_request
+);
+
+void scic_sds_request_deinitialize_state_logging(
+ SCIC_SDS_REQUEST_T *this_request
+);
+#else // SCI_LOGGING
+#define scic_sds_request_initialize_state_logging(x)
+#define scic_sds_request_deinitialize_state_logging(x)
+#endif // SCI_LOGGING
+
+//*****************************************************************************
+//* DEFAULT STATE HANDLERS
+//*****************************************************************************
+
+SCI_STATUS scic_sds_request_default_start_handler(
+ SCI_BASE_REQUEST_T *this_request
+);
+
+SCI_STATUS scic_sds_request_default_abort_handler(
+ SCI_BASE_REQUEST_T *this_request
+);
+
+SCI_STATUS scic_sds_request_default_complete_handler(
+ SCI_BASE_REQUEST_T *this_request
+);
+
+SCI_STATUS scic_sds_request_default_destruct_handler(
+ SCI_BASE_REQUEST_T *this_request
+);
+
+SCI_STATUS scic_sds_request_default_tc_completion_handler(
+ SCIC_SDS_REQUEST_T * this_request,
+ U32 completion_code
+);
+
+SCI_STATUS scic_sds_request_default_event_handler(
+ SCIC_SDS_REQUEST_T * this_request,
+ U32 event_code
+);
+
+SCI_STATUS scic_sds_request_default_frame_handler(
+ SCIC_SDS_REQUEST_T * this_request,
+ U32 frame_index
+);
+
+//*****************************************************************************
+//* STARTED STATE HANDLERS
+//*****************************************************************************
+
+SCI_STATUS scic_sds_request_started_state_abort_handler(
+ SCI_BASE_REQUEST_T *this_request
+);
+
+SCI_STATUS scic_sds_request_started_state_tc_completion_handler(
+ SCIC_SDS_REQUEST_T * this_request,
+ U32 completion_code
+);
+
+#ifdef __cplusplus
+}
+#endif // __cplusplus
+
+#endif // _SCIC_SDS_IO_REQUEST_H_
diff --git a/sys/dev/isci/scil/scic_sds_sgpio.c b/sys/dev/isci/scil/scic_sds_sgpio.c
new file mode 100644
index 0000000..25441c2
--- /dev/null
+++ b/sys/dev/isci/scil/scic_sds_sgpio.c
@@ -0,0 +1,298 @@
+/*-
+ * 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.
+ *
+ * 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 <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/**
+* @file
+*
+* @brief This file contains the implementation of the SGPIO register inteface
+* methods.
+*/
+
+#include <dev/isci/scil/scic_sgpio.h>
+#include <dev/isci/scil/scic_sds_controller_registers.h>
+#include <dev/isci/scil/scic_user_callback.h>
+
+/**
+ * @brief Function writes Value to the
+ * SGPIO Output Data Select Register (SGODSR) for phys specified by
+ * phy_mask paremeter
+ *
+ * @param[in] SCIC_SDS_CONTROLLER_T controller
+ * @param[in] phy_mask - This field is a bit mask that specifies the phys
+ * to be updated.
+ * @param[in] value - Value for write
+ *
+ * @return none
+ */
+static
+void scic_sgpio_write_SGODSR_register(
+ SCIC_SDS_CONTROLLER_T *controller,
+ U32 phy_mask,
+ U32 value
+)
+{
+ U8 phy_index;
+
+ for (phy_index = 0; phy_index < SCI_MAX_PHYS; phy_index++)
+ {
+ if (phy_mask >> phy_index & 1)
+ {
+ scu_sgpio_peg0_register_write(
+ controller, output_data_select[phy_index], value
+ );
+ }
+ }
+}
+
+void scic_sgpio_set_vendor_code(
+ SCI_CONTROLLER_HANDLE_T controller,
+ U8 vendor_specific_sequence
+)
+{
+ SCIC_SDS_CONTROLLER_T * core_controller = (SCIC_SDS_CONTROLLER_T *) controller;
+
+ scu_sgpio_peg0_register_write(
+ core_controller, vendor_specific_code, vendor_specific_sequence);
+}
+
+void scic_sgpio_set_blink_patterns(
+ SCI_CONTROLLER_HANDLE_T controller,
+ U8 pattern_a_low,
+ U8 pattern_a_high,
+ U8 pattern_b_low,
+ U8 pattern_b_high
+)
+{
+ U32 value;
+ SCIC_SDS_CONTROLLER_T * core_controller = (SCIC_SDS_CONTROLLER_T *) controller;
+
+ value = (pattern_b_high << 12) + (pattern_b_low << 8) + (pattern_a_high << 4) + pattern_a_low;
+
+ scu_sgpio_peg0_register_write(
+ core_controller, blink_rate, value);
+}
+
+void scic_sgpio_set_functionality(
+ SCI_CONTROLLER_HANDLE_T controller,
+ BOOL sgpio_mode
+)
+{
+ U32 value = DISABLE_SGPIO_FUNCTIONALITY;
+ SCIC_SDS_CONTROLLER_T * core_controller = (SCIC_SDS_CONTROLLER_T *) controller;
+
+ if(sgpio_mode)
+ {
+ value = ENABLE_SGPIO_FUNCTIONALITY;
+ }
+
+ scu_sgpio_peg0_register_write(
+ core_controller, interface_control, value);
+}
+
+void scic_sgpio_apply_led_blink_pattern(
+ SCI_CONTROLLER_HANDLE_T controller,
+ U32 phy_mask,
+ BOOL error,
+ BOOL locate,
+ BOOL activity,
+ U8 pattern_selection
+)
+{
+ U32 output_value = 0;
+
+ SCIC_SDS_CONTROLLER_T * core_controller = (SCIC_SDS_CONTROLLER_T *) controller;
+
+ // Start with all LEDs turned off
+ output_value = (SGODSR_INVERT_BIT << SGODSR_ERROR_LED_SHIFT)
+ | (SGODSR_INVERT_BIT << SGODSR_LOCATE_LED_SHIFT)
+ | (SGODSR_INVERT_BIT << SGODSR_ACTIVITY_LED_SHIFT);
+
+ if(error)
+ { //apply pattern to error LED
+ output_value |= pattern_selection << SGODSR_ERROR_LED_SHIFT;
+ output_value &= ~(SGODSR_INVERT_BIT << SGODSR_ERROR_LED_SHIFT);
+ }
+ if(locate)
+ { //apply pattern to locate LED
+ output_value |= pattern_selection << SGODSR_LOCATE_LED_SHIFT;
+ output_value &= ~(SGODSR_INVERT_BIT << SGODSR_LOCATE_LED_SHIFT);
+ }
+ if(activity)
+ { //apply pattern to activity LED
+ output_value |= pattern_selection << SGODSR_ACTIVITY_LED_SHIFT;
+ output_value &= ~(SGODSR_INVERT_BIT << SGODSR_ACTIVITY_LED_SHIFT);
+ }
+
+ scic_sgpio_write_SGODSR_register(core_controller, phy_mask, output_value);
+}
+
+void scic_sgpio_set_led_blink_pattern(
+ SCI_CONTROLLER_HANDLE_T controller,
+ SCI_PORT_HANDLE_T port_handle,
+ BOOL error,
+ BOOL locate,
+ BOOL activity,
+ U8 pattern_selection
+)
+{
+ U32 phy_mask;
+
+ SCIC_SDS_PORT_T * port = (SCIC_SDS_PORT_T *) port_handle;
+
+ phy_mask = scic_sds_port_get_phys(port);
+
+ scic_sgpio_apply_led_blink_pattern(
+ controller, phy_mask, error, locate, activity, pattern_selection);
+}
+
+void scic_sgpio_update_led_state(
+ SCI_CONTROLLER_HANDLE_T controller,
+ U32 phy_mask,
+ BOOL error,
+ BOOL locate,
+ BOOL activity
+)
+{
+ U32 output_value;
+
+ SCIC_SDS_CONTROLLER_T * core_controller = (SCIC_SDS_CONTROLLER_T *) controller;
+
+ // Start with all LEDs turned on
+ output_value = 0x00000000;
+
+ if(!error)
+ { //turn off error LED
+ output_value |= SGODSR_INVERT_BIT << SGODSR_ERROR_LED_SHIFT;
+ }
+ if(!locate)
+ { //turn off locate LED
+ output_value |= SGODSR_INVERT_BIT << SGODSR_LOCATE_LED_SHIFT;
+ }
+ if(!activity)
+ { //turn off activity LED
+ output_value |= SGODSR_INVERT_BIT << SGODSR_ACTIVITY_LED_SHIFT;
+ }
+
+ scic_sgpio_write_SGODSR_register(core_controller, phy_mask, output_value);
+}
+
+void scic_sgpio_set_led_state(
+ SCI_CONTROLLER_HANDLE_T controller,
+ SCI_PORT_HANDLE_T port_handle,
+ BOOL error,
+ BOOL locate,
+ BOOL activity
+)
+{
+ U32 phy_mask;
+
+ SCIC_SDS_PORT_T * port = (SCIC_SDS_PORT_T *) port_handle;
+
+ phy_mask = scic_sds_port_get_phys(port);
+
+ scic_sgpio_update_led_state(controller, phy_mask, error, locate, activity);
+}
+
+void scic_sgpio_set_to_hardware_control(
+ SCI_CONTROLLER_HANDLE_T controller,
+ BOOL is_hardware_controlled
+)
+{
+ SCIC_SDS_CONTROLLER_T * core_controller = (SCIC_SDS_CONTROLLER_T *) controller;
+ U8 i;
+ U32 output_value;
+
+ //turn on hardware control for LED's
+ if(is_hardware_controlled)
+ {
+ output_value = SGPIO_HARDWARE_CONTROL;
+ }
+ else //turn off hardware control
+ {
+ output_value = SGPIO_SOFTWARE_CONTROL;
+ }
+
+ for(i = 0; i < SCI_MAX_PHYS; i++)
+ {
+ scu_sgpio_peg0_register_write(
+ core_controller, output_data_select[i], output_value);
+ }
+}
+
+U32 scic_sgpio_read(
+ SCI_CONTROLLER_HANDLE_T controller
+)
+{
+ //Not supported in the SCU hardware returning 0xFFFFFFFF
+ return 0xffffffff;
+}
+
+void scic_sgpio_hardware_initialize(
+ SCI_CONTROLLER_HANDLE_T controller
+)
+{
+ scic_sgpio_set_functionality(controller, TRUE);
+ scic_sgpio_set_to_hardware_control(controller, TRUE);
+ scic_sgpio_set_vendor_code(controller, 0x00);
+}
+
+void scic_sgpio_initialize(
+ SCI_CONTROLLER_HANDLE_T controller
+)
+{
+ scic_sgpio_set_functionality(controller, TRUE);
+ scic_sgpio_set_to_hardware_control(controller, FALSE);
+ scic_sgpio_set_vendor_code(controller, 0x00);
+}
diff --git a/sys/dev/isci/scil/scic_sds_smp_remote_device.c b/sys/dev/isci/scil/scic_sds_smp_remote_device.c
new file mode 100644
index 0000000..579e05c
--- /dev/null
+++ b/sys/dev/isci/scil/scic_sds_smp_remote_device.c
@@ -0,0 +1,371 @@
+/*-
+ * 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.
+ *
+ * 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 <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/**
+ * @file
+ *
+ * @brief This file contains This file contains the SMP remote device
+ * object methods and it's state machines.
+ */
+
+#include <dev/isci/scil/scic_user_callback.h>
+#include <dev/isci/scil/scic_sds_logger.h>
+#include <dev/isci/scil/scic_sds_remote_device.h>
+#include <dev/isci/scil/scic_sds_controller.h>
+#include <dev/isci/scil/scic_sds_port.h>
+#include <dev/isci/scil/scic_sds_request.h>
+#include <dev/isci/scil/scu_event_codes.h>
+#include <dev/isci/scil/scu_task_context.h>
+#include <dev/isci/scil/scic_remote_device.h>
+
+//*****************************************************************************
+//* SMP REMOTE DEVICE READY IDLE SUBSTATE HANDLERS
+//*****************************************************************************
+
+/**
+ * This method will handle the start io operation for a SMP device that is in
+ * the idle state.
+ *
+ * @param [in] device The device the io is sent to.
+ * @param [in] request The io to start.
+ *
+ * @return SCI_STATUS
+ */
+static
+SCI_STATUS scic_sds_smp_remote_device_ready_idle_substate_start_io_handler(
+ SCI_BASE_REMOTE_DEVICE_T * device,
+ SCI_BASE_REQUEST_T * request
+)
+{
+ SCI_STATUS status;
+ SCIC_SDS_REMOTE_DEVICE_T * this_device = (SCIC_SDS_REMOTE_DEVICE_T *)device;
+ SCIC_SDS_REQUEST_T * io_request = (SCIC_SDS_REQUEST_T *)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
+//******************************************************************************
+/**
+ * This device is already handling a command it can not accept new commands
+ * until this one is complete.
+ *
+ * @param[in] device This is the device object that is receiving the IO.
+ *
+ * @param[in] request The io to start.
+ *
+ * @return SCI_STATUS
+ */
+static
+SCI_STATUS scic_sds_smp_remote_device_ready_cmd_substate_start_io_handler(
+ SCI_BASE_REMOTE_DEVICE_T * device,
+ SCI_BASE_REQUEST_T * request
+)
+{
+ return SCI_FAILURE_INVALID_STATE;
+}
+
+
+/**
+ * @brief this is the complete_io_handler for smp device at ready cmd substate.
+ *
+ * @param[in] device This is the device object that is receiving the IO.
+ * @param[in] request The io to start.
+ *
+ * @return SCI_STATUS
+ */
+static
+SCI_STATUS scic_sds_smp_remote_device_ready_cmd_substate_complete_io_handler(
+ SCI_BASE_REMOTE_DEVICE_T * device,
+ SCI_BASE_REQUEST_T * request
+)
+{
+ SCI_STATUS status;
+ SCIC_SDS_REMOTE_DEVICE_T * this_device;
+ SCIC_SDS_REQUEST_T * the_request;
+
+ this_device = (SCIC_SDS_REMOTE_DEVICE_T *)device;
+ the_request = (SCIC_SDS_REQUEST_T *)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
+ {
+ SCIC_LOG_ERROR((
+ sci_base_object_get_logger(this_device),
+ SCIC_LOG_OBJECT_SMP_REMOTE_TARGET,
+ "SCIC SDS Remote Device 0x%x io request 0x%x could not be completd on the port 0x%x failed with status %d.\n",
+ this_device, the_request, this_device->owning_port, status
+ ));
+ }
+ }
+
+ return status;
+}
+
+/**
+ * @brief This is frame handler for smp device ready cmd substate.
+ *
+ * @param[in] this_device This is the device object that is receiving the frame.
+ * @param[in] frame_index The index for the frame received.
+ *
+ * @return SCI_STATUS
+ */
+static
+SCI_STATUS scic_sds_smp_remote_device_ready_cmd_substate_frame_handler(
+ SCIC_SDS_REMOTE_DEVICE_T * this_device,
+ U32 frame_index
+)
+{
+ 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;
+}
+
+// ---------------------------------------------------------------------------
+
+SCIC_SDS_REMOTE_DEVICE_STATE_HANDLER_T
+ 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 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.
+ *
+ * @param[in] object This is the SCI_BASE_OBJECT which is cast into a
+ * SCIC_SDS_REMOTE_DEVICE.
+ *
+ * @return none
+ */
+static
+void scic_sds_smp_remote_device_ready_idle_substate_enter(
+ SCI_BASE_OBJECT_T *object
+)
+{
+ SCIC_SDS_REMOTE_DEVICE_T *this_device = (SCIC_SDS_REMOTE_DEVICE_T *)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);
+}
+
+/**
+ * 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.
+ *
+ * @param[in] object This is the SCI_BASE_OBJECT which is cast into a
+ * SCIC_SDS_REMOTE_DEVICE.
+ *
+ * @return none
+ */
+static
+void scic_sds_smp_remote_device_ready_cmd_substate_enter(
+ SCI_BASE_OBJECT_T *object
+)
+{
+ SCIC_SDS_REMOTE_DEVICE_T *this_device = (SCIC_SDS_REMOTE_DEVICE_T *)object;
+
+ ASSERT(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
+ );
+}
+
+/**
+ * This is the SCIC_SDS_SSP_REMOTE_DEVICE_READY_SUBSTATE_CMD exit method.
+ *
+ * @param[in] object This is the SCI_BASE_OBJECT which is cast into a
+ * SCIC_SDS_REMOTE_DEVICE.
+ *
+ * @return none
+ */
+static
+void scic_sds_smp_remote_device_ready_cmd_substate_exit(
+ SCI_BASE_OBJECT_T *object
+)
+{
+ SCIC_SDS_REMOTE_DEVICE_T * this_device = (SCIC_SDS_REMOTE_DEVICE_T *)object;
+
+ this_device->working_request = NULL;
+}
+
+// ---------------------------------------------------------------------------
+
+SCI_BASE_STATE_T
+ scic_sds_smp_remote_device_ready_substate_table[
+ SCIC_SDS_SMP_REMOTE_DEVICE_READY_MAX_SUBSTATES] =
+{
+ {
+ SCIC_SDS_SMP_REMOTE_DEVICE_READY_SUBSTATE_IDLE,
+ scic_sds_smp_remote_device_ready_idle_substate_enter,
+ NULL
+ },
+ {
+ SCIC_SDS_SMP_REMOTE_DEVICE_READY_SUBSTATE_CMD,
+ scic_sds_smp_remote_device_ready_cmd_substate_enter,
+ scic_sds_smp_remote_device_ready_cmd_substate_exit
+ }
+};
+
diff --git a/sys/dev/isci/scil/scic_sds_smp_request.c b/sys/dev/isci/scil/scic_sds_smp_request.c
new file mode 100644
index 0000000..d6990e5
--- /dev/null
+++ b/sys/dev/isci/scil/scic_sds_smp_request.c
@@ -0,0 +1,872 @@
+/*-
+ * 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.
+ *
+ * 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 <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <dev/isci/scil/scic_sds_smp_request.h>
+#include <dev/isci/scil/scic_sds_logger.h>
+#include <dev/isci/scil/scic_sds_controller.h>
+#include <dev/isci/scil/scic_sds_remote_device.h>
+#include <dev/isci/scil/scic_remote_device.h>
+#include <dev/isci/scil/sci_util.h>
+#include <dev/isci/sci_environment.h>
+#include <dev/isci/scil/intel_sas.h>
+#include <dev/isci/scil/scic_sds_request.h>
+#include <dev/isci/scil/scic_controller.h>
+#include <dev/isci/scil/scu_completion_codes.h>
+#include <dev/isci/scil/scu_task_context.h>
+#include <dev/isci/scil/sci_base_state_machine.h>
+
+/**
+ * This method return the memory space required for STP PIO requests.
+ *
+ * @return U32
+ */
+U32 scic_sds_smp_request_get_object_size(void)
+{
+ return sizeof(SCIC_SDS_REQUEST_T)
+ + sizeof(SMP_REQUEST_T)
+ + sizeof(U32)
+ + sizeof(SMP_RESPONSE_T)
+ + sizeof(U32)
+ + sizeof(SCU_TASK_CONTEXT_T)
+ + CACHE_LINE_SIZE;
+}
+
+/**
+ * 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_unaligned(memory) \
+ ( ((char *)(memory)) + sizeof(SCIC_SDS_REQUEST_T) )
+
+/**
+ * This macro aligns the smp command buffer in DWORD alignment
+*/
+#define scic_sds_smp_request_align_command_buffer(address) \
+ ((char *)( \
+ (((POINTER_UINT)(address)) + (sizeof(U32) - 1)) \
+ & ~(sizeof(U32)- 1) \
+ ))
+
+/**
+ * This macro returns the DWORD-aligned smp command buffer
+*/
+#define scic_sds_smp_request_get_command_buffer(memory) \
+ ((char *) \
+ ((char *)scic_sds_smp_request_align_command_buffer( \
+ (char *) scic_sds_smp_request_get_command_buffer_unaligned(memory) \
+ )))
+
+/**
+ * This macro returns the address of the smp response buffer in the smp request
+ * memory.
+ */
+#define scic_sds_smp_request_get_response_buffer_unaligned(memory) \
+ ( ((char *)(scic_sds_smp_request_get_command_buffer(memory))) \
+ + sizeof(SMP_REQUEST_T) )
+
+/**
+ * This macro aligns the smp command buffer in DWORD alignment
+*/
+#define scic_sds_smp_request_align_response_buffer(address) \
+ ((char *)( \
+ (((POINTER_UINT)(address)) + (sizeof(U32) - 1)) \
+ & ~(sizeof(U32)- 1) \
+ ))
+
+/**
+ * This macro returns the DWORD-aligned smp resposne buffer
+*/
+#define scic_sds_smp_request_get_response_buffer(memory) \
+ ((char *) \
+ ((char *)scic_sds_smp_request_align_response_buffer( \
+ (char *) scic_sds_smp_request_get_response_buffer_unaligned(memory) \
+ )))
+
+/**
+ * This macro returs the task context buffer for the SMP request.
+ */
+#define scic_sds_smp_request_get_task_context_buffer_unaligned(memory) \
+ ((SCU_TASK_CONTEXT_T *)( \
+ ((char *)(scic_sds_smp_request_get_response_buffer(memory))) \
+ + sizeof(SMP_RESPONSE_T) \
+ ))
+
+/**
+ * This macro returns the dword-aligned smp task context buffer
+ */
+#define scic_sds_smp_request_get_task_context_buffer(memory) \
+ ((SCU_TASK_CONTEXT_T *)( \
+ ((char *)scic_sds_request_align_task_context_buffer( \
+ (char *)scic_sds_smp_request_get_task_context_buffer_unaligned(memory)) \
+ )))
+
+/**
+ * @brief This method build the remainder of the IO request object.
+ *
+ * @pre The scic_sds_general_request_construct() must be called before this
+ * call is valid.
+ *
+ * @param[in] this_request This parameter specifies the request object being
+ * constructed.
+ *
+ * @return none
+ */
+
+void scic_sds_smp_request_assign_buffers(
+ SCIC_SDS_REQUEST_T *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);
+ }
+
+}
+/**
+ * @brief This method is called by the SCI user to build an SMP
+ * IO request.
+ *
+ * @pre
+ * - The user must have previously called scic_io_request_construct()
+ * on the supplied IO request.
+ *
+ * @param[in] scic_io_request This parameter specifies the handle to the
+ * io request object to be built.
+ *
+ * @return Indicate if the controller successfully built the IO request.
+ * @retval SCI_SUCCESS This value is returned if the IO request was
+ * successfully built.
+ * @retval SCI_FAILURE_UNSUPPORTED_PROTOCOL This value is returned if the
+ * remote_device does not support the SMP protocol.
+ * @retval 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.
+ */
+SCI_STATUS scic_io_request_construct_smp(
+ SCI_IO_REQUEST_HANDLE_T scic_smp_request
+)
+{
+ SMP_REQUEST_T smp_request;
+
+ SCIC_SDS_REQUEST_T *this_request = (SCIC_SDS_REQUEST_T *) scic_smp_request;
+ SCIC_LOG_TRACE((
+ sci_base_object_get_logger(this_request),
+ SCIC_LOG_OBJECT_SMP_IO_REQUEST,
+ "scic_io_request_construct_smp(0x%x) enter\n",
+ this_request
+ ));
+
+ this_request->protocol = SCIC_SMP_PROTOCOL;
+ 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_smp_request_started_substate_table,
+ SCIC_SDS_SMP_REQUEST_STARTED_SUBSTATE_AWAIT_RESPONSE
+ );
+
+ // Construct the SMP SCU Task Context
+ memcpy((char *)&smp_request,
+ this_request->command_buffer,
+ sizeof(SMP_REQUEST_T));
+
+ // 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_request.header.request_length == 0 )
+ {
+ switch( smp_request.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_request.header.request_length = 2;
+ break;
+ case SMP_FUNCTION_CONFIGURE_ROUTE_INFORMATION:
+ case SMP_FUNCTION_PHY_CONTROL:
+ case SMP_FUNCTION_PHY_TEST:
+ smp_request.header.request_length = 9;
+ break;
+ // Default - zero is a valid default for 2.0.
+ }
+ }
+
+ scu_smp_request_construct_task_context(
+ this_request,
+ &smp_request
+ );
+
+ sci_base_state_machine_change_state(
+ &this_request->parent.state_machine,
+ SCI_BASE_REQUEST_STATE_CONSTRUCTED
+ );
+
+ return SCI_SUCCESS;
+}
+
+/**
+ * @brief This method is called by the SCI user to build an SMP pass-through
+ * IO request.
+ *
+ * @pre
+ * - The user must have previously called scic_io_request_construct()
+ * on the supplied IO request.
+ *
+ * @param[in] scic_smp_request This parameter specifies the handle to the
+ * io request object to be built.
+ *
+ * @param[in] passthru_cb This parameter specifies the pointer to the callback
+ * structure that contains the function pointers
+ *
+ * @return Indicate if the controller successfully built the IO request.
+ */
+SCI_STATUS scic_io_request_construct_smp_pass_through(
+ SCI_IO_REQUEST_HANDLE_T scic_smp_request,
+ SCIC_SMP_PASSTHRU_REQUEST_CALLBACKS_T *passthru_cb
+)
+{
+ SMP_REQUEST_T smp_request;
+ U8 * request_buffer;
+ U32 request_buffer_length_in_bytes;
+
+ SCIC_SDS_REQUEST_T *this_request = (SCIC_SDS_REQUEST_T *) scic_smp_request;
+ SCIC_LOG_TRACE((
+ sci_base_object_get_logger(this_request),
+ SCIC_LOG_OBJECT_SMP_IO_REQUEST,
+ "scic_io_request_construct_smp_pass_through(0x%x) enter\n",
+ this_request
+ ));
+
+ this_request->protocol = SCIC_SMP_PROTOCOL;
+ this_request->has_started_substate_machine = TRUE;
+
+ // Call the callback function to retrieve the SMP passthrough request
+ request_buffer_length_in_bytes = passthru_cb->scic_cb_smp_passthru_get_request (
+ (void *)this_request,
+ &request_buffer
+ );
+
+ //copy the request to smp request
+ memcpy((char *)&smp_request.request.vendor_specific_request,
+ request_buffer,
+ request_buffer_length_in_bytes);
+
+ //the header length in smp_request is in dwords - the sas spec has similar way,
+ //but the csmi header contains the number of bytes, so we need to convert the
+ //number of bytes to number of dwords
+ smp_request.header.request_length = (U8) (request_buffer_length_in_bytes / sizeof (U32));
+
+ //Grab the other needed fields from the smp request using callbacks
+ smp_request.header.smp_frame_type = passthru_cb->scic_cb_smp_passthru_get_frame_type ((void *)this_request);
+ smp_request.header.function = passthru_cb->scic_cb_smp_passthru_get_function ((void *)this_request);
+ smp_request.header.allocated_response_length = passthru_cb->scic_cb_smp_passthru_get_allocated_response_length((void *)this_request);
+
+ // Construct the started sub-state machine.
+ sci_base_state_machine_construct(
+ &this_request->started_substate_machine,
+ &this_request->parent.parent,
+ scic_sds_smp_request_started_substate_table,
+ SCIC_SDS_SMP_REQUEST_STARTED_SUBSTATE_AWAIT_RESPONSE
+ );
+
+ // Construct the SMP SCU Task Context
+ scu_smp_request_construct_task_context (this_request, &smp_request);
+
+ sci_base_state_machine_change_state(
+ &this_request->parent.state_machine,
+ SCI_BASE_REQUEST_STATE_CONSTRUCTED
+ );
+
+ return SCI_SUCCESS;
+}
+
+/**
+ * @brief 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.
+ *
+ * @param[in] this_request This parameter specifies the smp request object
+ * being constructed.
+ *
+ * @return none
+ */
+void scu_smp_request_construct_task_context(
+ SCIC_SDS_REQUEST_T *this_request,
+ SMP_REQUEST_T *smp_request
+)
+{
+ SCI_PHYSICAL_ADDRESS physical_address;
+ SCIC_SDS_CONTROLLER_T *owning_controller;
+ SCIC_SDS_REMOTE_DEVICE_T *target_device;
+ SCIC_SDS_PORT_T *target_port;
+ SCU_TASK_CONTEXT_T *task_context;
+
+ //byte swap the smp request.
+ scic_word_copy_with_swap(
+ this_request->command_buffer,
+ (U32*) smp_request,
+ sizeof(SMP_REQUEST_T)/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);
+
+ SCIC_LOG_TRACE((
+ sci_base_object_get_logger(this_request),
+ SCIC_LOG_OBJECT_SMP_IO_REQUEST,
+ "scu_smp_request_construct_task_context(0x%x) contents\n"
+ " reqlen=%x; function=%x;\n",
+ this_request,
+ smp_request->header.request_length,
+ smp_request->header.function
+ ));
+
+ // 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 =
+ sci_cb_physical_address_upper(physical_address);
+ task_context->command_iu_lower =
+ sci_cb_physical_address_lower(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;
+}
+
+//******************************************************************************
+//* SMP REQUEST STATE MACHINE
+//******************************************************************************
+
+/**
+ * @brief 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.
+ *
+ * @param[in] this_request This parameter specifies the request for which
+ * the unsolicited frame was received.
+ * @param[in] frame_index This parameter indicates the unsolicited frame
+ * index that should contain the response.
+ *
+ * @return This method returns an indication of whether the response
+ * frame was handled successfully or not.
+ * @retval SCI_SUCCESS Currently this value is always returned and indicates
+ * successful processing of the TC response.
+ */
+static
+SCI_STATUS scic_sds_smp_request_await_response_frame_handler(
+ SCIC_SDS_REQUEST_T * this_request,
+ U32 frame_index
+)
+{
+ SCI_STATUS status;
+ void * frame_header;
+ SMP_RESPONSE_HEADER_T * this_frame_header;
+ U8 * user_smp_buffer = this_request->response_buffer;
+
+ // Save off the controller, so that we do not touch the request after it
+ // is completed.
+ SCIC_SDS_CONTROLLER_T * controller = scic_sds_request_get_controller(this_request);
+
+ SCIC_LOG_TRACE((
+ sci_base_object_get_logger(this_request),
+ SCIC_LOG_OBJECT_SMP_IO_REQUEST,
+ "scic_sds_smp_request_await_response_frame_handler(0x%x, 0x%x) enter\n",
+ this_request, frame_index
+ ));
+
+ status = scic_sds_unsolicited_frame_control_get_header(
+ &(controller->uf_control),
+ frame_index,
+ &frame_header
+ );
+
+ //byte swap the header.
+ scic_word_copy_with_swap(
+ (U32*) user_smp_buffer,
+ frame_header,
+ sizeof(SMP_RESPONSE_HEADER_T)/sizeof(U32)
+ );
+ this_frame_header = (SMP_RESPONSE_HEADER_T*) 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(
+ &(controller->uf_control),
+ frame_index,
+ &smp_response_buffer
+ );
+
+ scic_word_copy_with_swap(
+ (U32*) (user_smp_buffer + sizeof(SMP_RESPONSE_HEADER_T)),
+ smp_response_buffer,
+ sizeof(SMP_RESPONSE_BODY_T)/sizeof(U32)
+ );
+ if (this_frame_header->function == SMP_FUNCTION_DISCOVER)
+ {
+ SMP_RESPONSE_T * this_smp_response;
+
+ this_smp_response = (SMP_RESPONSE_T *)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;
+
+ SCIC_LOG_TRACE((
+ sci_base_object_get_logger(this_request),
+ SCIC_LOG_OBJECT_SMP_IO_REQUEST,
+ "scic_sds_smp_request_await_response_frame_handler(0x%x) Found SATA dev, setting STP bit.\n",
+ 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?
+ SCIC_LOG_ERROR((
+ sci_base_object_get_logger(this_request),
+ SCIC_LOG_OBJECT_SMP_IO_REQUEST,
+ "SCIC SMP Request 0x%08x received unexpected frame %d type 0x%02x\n",
+ 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(
+ controller, frame_index
+ );
+
+ return SCI_SUCCESS;
+}
+
+
+/**
+ * @brief 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.
+ *
+ * @param[in] this_request This parameter specifies the request for which
+ * the TC completion was received.
+ * @param[in] completion_code This parameter indicates the completion status
+ * information for the TC.
+ *
+ * @return Indicate if the tc completion handler was successful.
+ * @retval SCI_SUCCESS currently this method always returns success.
+ */
+static
+SCI_STATUS scic_sds_smp_request_await_response_tc_completion_handler(
+ SCIC_SDS_REQUEST_T * this_request,
+ U32 completion_code
+)
+{
+ SCIC_LOG_TRACE((
+ sci_base_object_get_logger(this_request),
+ SCIC_LOG_OBJECT_SMP_IO_REQUEST,
+ "scic_sds_smp_request_await_response_tc_completion_handler(0x%x, 0x%x) enter\n",
+ this_request, 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;
+}
+
+
+/**
+ * @brief 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.
+ *
+ * @param[in] this_request This parameter specifies the request for which
+ * the TC completion was received.
+ * @param[in] completion_code This parameter indicates the completion status
+ * information for the TC.
+ *
+ * @return Indicate if the tc completion handler was successful.
+ * @retval SCI_SUCCESS currently this method always returns success.
+ */
+static
+SCI_STATUS scic_sds_smp_request_await_tc_completion_tc_completion_handler(
+ SCIC_SDS_REQUEST_T * this_request,
+ U32 completion_code
+)
+{
+ SCIC_LOG_TRACE((
+ sci_base_object_get_logger(this_request),
+ SCIC_LOG_OBJECT_SMP_IO_REQUEST,
+ "scic_sds_smp_request_await_tc_completion_tc_completion_handler(0x%x, 0x%x) enter\n",
+ this_request, 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;
+}
+
+
+SCIC_SDS_IO_REQUEST_STATE_HANDLER_T
+scic_sds_smp_request_started_substate_handler_table
+[SCIC_SDS_SMP_REQUEST_STARTED_MAX_SUBSTATES] =
+{
+ // SCIC_SDS_SMP_REQUEST_STARTED_SUBSTATE_AWAIT_RESPONSE
+ {
+ {
+ scic_sds_request_default_start_handler,
+ scic_sds_request_started_state_abort_handler,
+ scic_sds_request_default_complete_handler,
+ scic_sds_request_default_destruct_handler
+ },
+ scic_sds_smp_request_await_response_tc_completion_handler,
+ scic_sds_request_default_event_handler,
+ scic_sds_smp_request_await_response_frame_handler
+ },
+ // SCIC_SDS_SMP_REQUEST_STARTED_SUBSTATE_AWAIT_TC_COMPLETION
+ {
+ {
+ scic_sds_request_default_start_handler,
+ scic_sds_request_started_state_abort_handler,
+ scic_sds_request_default_complete_handler,
+ scic_sds_request_default_destruct_handler
+ },
+ scic_sds_smp_request_await_tc_completion_tc_completion_handler,
+ scic_sds_request_default_event_handler,
+ scic_sds_request_default_frame_handler
+ }
+};
+
+/**
+ * @brief 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.
+ *
+ * @param[in] object This parameter specifies the request object for which
+ * the sub-state change is occuring.
+ *
+ * @return none.
+ */
+static
+void scic_sds_smp_request_started_await_response_substate_enter(
+ SCI_BASE_OBJECT_T *object
+)
+{
+ SCIC_SDS_REQUEST_T *this_request = (SCIC_SDS_REQUEST_T *)object;
+
+ SET_STATE_HANDLER(
+ this_request,
+ scic_sds_smp_request_started_substate_handler_table,
+ SCIC_SDS_SMP_REQUEST_STARTED_SUBSTATE_AWAIT_RESPONSE
+ );
+}
+
+/**
+ * @brief 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.
+ *
+ * @param[in] object This parameter specifies the request object for which
+ * the sub-state change is occuring.
+ *
+ * @return none.
+ */
+static
+void scic_sds_smp_request_started_await_tc_completion_substate_enter(
+ SCI_BASE_OBJECT_T *object
+)
+{
+ SCIC_SDS_REQUEST_T *this_request = (SCIC_SDS_REQUEST_T *)object;
+
+ SET_STATE_HANDLER(
+ this_request,
+ scic_sds_smp_request_started_substate_handler_table,
+ SCIC_SDS_SMP_REQUEST_STARTED_SUBSTATE_AWAIT_TC_COMPLETION
+ );
+}
+
+SCI_BASE_STATE_T scic_sds_smp_request_started_substate_table
+[SCIC_SDS_SMP_REQUEST_STARTED_MAX_SUBSTATES] =
+{
+ {
+ SCIC_SDS_SMP_REQUEST_STARTED_SUBSTATE_AWAIT_RESPONSE,
+ scic_sds_smp_request_started_await_response_substate_enter,
+ NULL
+ },
+ {
+ SCIC_SDS_SMP_REQUEST_STARTED_SUBSTATE_AWAIT_TC_COMPLETION,
+ scic_sds_smp_request_started_await_tc_completion_substate_enter,
+ NULL
+ }
+};
+
+
diff --git a/sys/dev/isci/scil/scic_sds_smp_request.h b/sys/dev/isci/scil/scic_sds_smp_request.h
new file mode 100644
index 0000000..ad9a33a
--- /dev/null
+++ b/sys/dev/isci/scil/scic_sds_smp_request.h
@@ -0,0 +1,83 @@
+/*-
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 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.
+ *
+ * $FreeBSD$
+ */
+#ifndef _SCIC_SDS_SMP_REQUEST_T_
+#define _SCIC_SDS_SMP_REQUEST_T_
+
+#ifdef __cplusplus
+extern "C" {
+#endif // __cplusplus
+
+#include <dev/isci/scil/intel_sas.h>
+#include <dev/isci/scil/sci_types.h>
+#include <dev/isci/scil/scic_sds_request.h>
+
+
+U32 scic_sds_smp_request_get_object_size(void);
+
+void scu_smp_request_construct_task_context(
+ SCIC_SDS_REQUEST_T *this_request,
+ SMP_REQUEST_T *smp_request
+
+);
+
+void scic_sds_smp_request_copy_response(
+ SCIC_SDS_REQUEST_T * this_request
+);
+
+#ifdef __cplusplus
+}
+#endif // __cplusplus
+
+#endif // _SCIC_SDS_SMP_REQUEST_T_
+
diff --git a/sys/dev/isci/scil/scic_sds_ssp_request.c b/sys/dev/isci/scil/scic_sds_ssp_request.c
new file mode 100644
index 0000000..086f479
--- /dev/null
+++ b/sys/dev/isci/scil/scic_sds_ssp_request.c
@@ -0,0 +1,340 @@
+/*-
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 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 <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/**
+ * @file
+ *
+ * @brief This file contains the task management substate handlers for the
+ * SCIC_SDS_IO_REQUEST object.
+ * 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 <dev/isci/scil/intel_sas.h>
+#include <dev/isci/scil/scic_sds_request.h>
+#include <dev/isci/scil/scic_controller.h>
+#include <dev/isci/scil/scic_sds_logger.h>
+#include <dev/isci/scil/scic_sds_controller.h>
+#include <dev/isci/scil/scu_completion_codes.h>
+#include <dev/isci/scil/scu_task_context.h>
+#include <dev/isci/scil/sci_base_state_machine.h>
+
+/**
+ * @brief 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.
+ *
+ * @param[in] this_request This parameter specifies the request for which
+ * the TC completion was received.
+ * @param[in] completion_code This parameter indicates the completion status
+ * information for the TC.
+ *
+ * @return Indicate if the tc completion handler was successful.
+ * @retval SCI_SUCCESS currently this method always returns success.
+ */
+static
+SCI_STATUS scic_sds_ssp_task_request_await_tc_completion_tc_completion_handler(
+ SCIC_SDS_REQUEST_T * this_request,
+ U32 completion_code
+)
+{
+ SCIC_LOG_TRACE((
+ sci_base_object_get_logger(this_request),
+ SCIC_LOG_OBJECT_TASK_MANAGEMENT,
+ "scic_sds_ssp_task_request_await_tc_completion_tc_completion_handler(0x%x, 0x%x) enter\n",
+ this_request, 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.
+ SCIC_LOG_WARNING((
+ sci_base_object_get_logger(this_request),
+ SCIC_LOG_OBJECT_TASK_MANAGEMENT,
+ "TaskRequest:0x%x CompletionCode:%x - ACK/NAK timeout\n",
+ 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;
+}
+
+/**
+ * @brief 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.
+ *
+ * @param[in] this_request This parameter specifies the request for which
+ * the termination was requested.
+ *
+ * @return This method returns an indication as to whether the abort
+ * request was successfully handled.
+ *
+ * @todo 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
+SCI_STATUS scic_sds_ssp_task_request_await_tc_response_abort_handler(
+ SCI_BASE_REQUEST_T * request
+)
+{
+ SCIC_SDS_REQUEST_T *this_request = (SCIC_SDS_REQUEST_T *)request;
+
+ SCIC_LOG_TRACE((
+ sci_base_object_get_logger(this_request),
+ SCIC_LOG_OBJECT_TASK_MANAGEMENT,
+ "scic_sds_ssp_task_request_await_tc_response_abort_handler(0x%x) enter\n",
+ this_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;
+}
+
+/**
+ * @brief 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.
+ *
+ * @param[in] this_request This parameter specifies the request for which
+ * the unsolicited frame was received.
+ * @param[in] frame_index This parameter indicates the unsolicited frame
+ * index that should contain the response.
+ *
+ * @return This method returns an indication of whether the TC response
+ * frame was handled successfully or not.
+ * @retval SCI_SUCCESS Currently this value is always returned and indicates
+ * successful processing of the TC response.
+ *
+ * @todo Should probably update to check frame type and make sure it is
+ * a response frame.
+ */
+static
+SCI_STATUS scic_sds_ssp_task_request_await_tc_response_frame_handler(
+ SCIC_SDS_REQUEST_T * this_request,
+ U32 frame_index
+)
+{
+ // Save off the controller, so that we do not touch the request after it
+ // is completed.
+ SCIC_SDS_CONTROLLER_T * owning_controller = this_request->owning_controller;
+
+ SCIC_LOG_TRACE((
+ sci_base_object_get_logger(this_request),
+ SCIC_LOG_OBJECT_TASK_MANAGEMENT,
+ "scic_sds_ssp_task_request_await_tc_response_frame_handler(0x%x, 0x%x) enter\n",
+ this_request, 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(
+ owning_controller, frame_index
+ );
+
+ return SCI_SUCCESS;
+}
+
+SCIC_SDS_IO_REQUEST_STATE_HANDLER_T
+scic_sds_ssp_task_request_started_substate_handler_table
+[SCIC_SDS_IO_REQUEST_STARTED_TASK_MGMT_MAX_SUBSTATES] =
+{
+ // SCIC_SDS_IO_REQUEST_STARTED_TASK_MGMT_SUBSTATE_AWAIT_TC_COMPLETION
+ {
+ {
+ scic_sds_request_default_start_handler,
+ scic_sds_request_started_state_abort_handler,
+ scic_sds_request_default_complete_handler,
+ scic_sds_request_default_destruct_handler
+ },
+ scic_sds_ssp_task_request_await_tc_completion_tc_completion_handler,
+ scic_sds_request_default_event_handler,
+ scic_sds_request_default_frame_handler
+ },
+ // SCIC_SDS_IO_REQUEST_STARTED_TASK_MGMT_SUBSTATE_AWAIT_TC_RESPONSE
+ {
+ {
+ scic_sds_request_default_start_handler,
+ scic_sds_ssp_task_request_await_tc_response_abort_handler,
+ scic_sds_request_default_complete_handler,
+ scic_sds_request_default_destruct_handler
+ },
+ scic_sds_request_default_tc_completion_handler,
+ scic_sds_request_default_event_handler,
+ scic_sds_ssp_task_request_await_tc_response_frame_handler
+ }
+};
+
+/**
+ * @brief 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.
+ *
+ * @param[in] object This parameter specifies the request object for which
+ * the sub-state change is occuring.
+ *
+ * @return none.
+ */
+static
+void scic_sds_io_request_started_task_mgmt_await_tc_completion_substate_enter(
+ SCI_BASE_OBJECT_T *object
+)
+{
+ SCIC_SDS_REQUEST_T *this_request = (SCIC_SDS_REQUEST_T *)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
+ );
+}
+
+/**
+ * @brief 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.
+ *
+ * @param[in] object This parameter specifies the request object for which
+ * the sub-state change is occuring.
+ *
+ * @return none.
+ */
+static
+void scic_sds_io_request_started_task_mgmt_await_task_response_substate_enter(
+ SCI_BASE_OBJECT_T *object
+)
+{
+ SCIC_SDS_REQUEST_T *this_request = (SCIC_SDS_REQUEST_T *)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
+ );
+}
+
+SCI_BASE_STATE_T scic_sds_io_request_started_task_mgmt_substate_table
+[SCIC_SDS_IO_REQUEST_STARTED_TASK_MGMT_MAX_SUBSTATES] =
+{
+ {
+ SCIC_SDS_IO_REQUEST_STARTED_TASK_MGMT_SUBSTATE_AWAIT_TC_COMPLETION,
+ scic_sds_io_request_started_task_mgmt_await_tc_completion_substate_enter,
+ NULL
+ },
+ {
+ SCIC_SDS_IO_REQUEST_STARTED_TASK_MGMT_SUBSTATE_AWAIT_TC_RESPONSE,
+ scic_sds_io_request_started_task_mgmt_await_task_response_substate_enter,
+ NULL
+ }
+};
+
+
diff --git a/sys/dev/isci/scil/scic_sds_stp_packet_request.c b/sys/dev/isci/scil/scic_sds_stp_packet_request.c
new file mode 100644
index 0000000..59b436b
--- /dev/null
+++ b/sys/dev/isci/scil/scic_sds_stp_packet_request.c
@@ -0,0 +1,978 @@
+/*-
+ * 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.
+ *
+ * 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 <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#if !defined(DISABLE_ATAPI)
+
+#include <dev/isci/scil/scic_sds_stp_packet_request.h>
+#include <dev/isci/scil/scic_sds_logger.h>
+#include <dev/isci/scil/scic_sds_controller.h>
+#include <dev/isci/scil/scic_sds_remote_device.h>
+#include <dev/isci/scil/scic_remote_device.h>
+#include <dev/isci/scil/sci_util.h>
+#include <dev/isci/scil/intel_sas.h>
+#include <dev/isci/scil/intel_ata.h>
+#include <dev/isci/scil/intel_sata.h>
+#include <dev/isci/scil/scic_user_callback.h>
+#include <dev/isci/sci_environment.h>
+#include <dev/isci/scil/intel_sat.h>
+#include <dev/isci/scil/scic_sds_request.h>
+#include <dev/isci/scil/scic_controller.h>
+#include <dev/isci/scil/scu_completion_codes.h>
+#include <dev/isci/scil/scu_task_context.h>
+#include <dev/isci/scil/scic_sds_stp_packet_request.h>
+#include <dev/isci/scil/sci_base_state.h>
+
+/**
+ * @brief 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.
+ *
+ * @param[in] this_request This parameter specifies the stp packet request object
+ * being constructed.
+ *
+ * @return none
+ */
+SCI_STATUS scic_sds_stp_packet_request_construct(
+ SCIC_SDS_REQUEST_T *this_request
+)
+{
+ SATA_FIS_REG_H2D_T * 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(
+ (SCIC_SDS_STP_REQUEST_T*) 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;
+}
+
+
+/**
+ * @brief 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.
+ *
+ * @param[in] this_request This parameter specifies the smp request object
+ * being constructed.
+ * @param[in] task_context The task_context to be reconstruct for packet
+ * request command phase.
+ * @return none
+ */
+void scu_stp_packet_request_command_phase_construct_task_context(
+ SCIC_SDS_REQUEST_T * this_request,
+ SCU_TASK_CONTEXT_T * task_context
+)
+{
+ void * atapi_cdb;
+ U32 atapi_cdb_length;
+ SCIC_SDS_STP_REQUEST_T * stp_request = (SCIC_SDS_STP_REQUEST_T *)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(SATA_FIS_REG_H2D_T));
+
+ 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);
+ }
+}
+
+/**
+ * @brief 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.
+ *
+ * @param[in] this_request This parameter specifies the smp request object
+ * being constructed.
+ * @param[in] task_context The task_context to be reconstruct for packet
+ * request command phase.
+ * @return none
+ */
+void scu_stp_packet_request_command_phase_reconstruct_raw_frame_task_context(
+ SCIC_SDS_REQUEST_T * this_request,
+ SCU_TASK_CONTEXT_T * 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(SATA_FIS_REG_H2D_T));
+ 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.
+ *
+ */
+SCI_STATUS scic_sds_stp_packet_request_process_status_fis(
+ SCIC_SDS_REQUEST_T * this_request,
+ SATA_FIS_REG_D2H_T * status_fis
+)
+{
+ 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(
+ SCIC_SDS_REQUEST_T * this_request
+)
+{
+ void *sge;
+ SCU_SGL_ELEMENT_PAIR_T *scu_sgl_list = NULL;
+ SCU_TASK_CONTEXT_T *task_context;
+ SCI_PHYSICAL_ADDRESS physical_address;
+
+ SCI_SSP_RESPONSE_IU_T * rsp_iu =
+ (SCI_SSP_RESPONSE_IU_T *)this_request->response_buffer;
+ sge = (void*)&rsp_iu->data[0];
+
+ task_context = (SCU_TASK_CONTEXT_T *)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);
+}
+
+//******************************************************************************
+//* STP PACKET REQUEST STATE MACHINES
+//******************************************************************************
+
+/**
+* @brief 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.
+*
+* @param[in] this_request This parameter specifies the request for which
+* the TC completion was received.
+* @param[in] completion_code This parameter indicates the completion status
+* information for the TC.
+*
+* @return Indicate if the tc completion handler was successful.
+* @retval SCI_SUCCESS currently this method always returns success.
+*/
+static
+SCI_STATUS scic_sds_stp_packet_request_packet_phase_await_tc_completion_tc_completion_handler(
+ SCIC_SDS_REQUEST_T * this_request,
+ U32 completion_code
+)
+{
+ SCI_STATUS status = SCI_SUCCESS;
+
+ SCIC_LOG_TRACE((
+ sci_base_object_get_logger(this_request),
+ SCIC_LOG_OBJECT_STP_IO_REQUEST,
+ "scic_sds_stp_packet_request_packet_phase_await_tc_completion_tc_completion_handler(0x%x, 0x%x) enter\n",
+ this_request, 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_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;
+}
+
+
+/**
+ * @brief 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.
+ *
+ * @param[in] this_request This parameter specifies the request for which
+ * the unsolicited frame was received.
+ * @param[in] frame_index This parameter indicates the unsolicited frame
+ * index that should contain the response.
+ *
+ * @return This method returns an indication of whether the pio setup
+ * frame was handled successfully or not.
+ * @retval SCI_SUCCESS Currently this value is always returned and indicates
+ * successful processing of the TC response.
+ *
+ */
+static
+SCI_STATUS scic_sds_stp_packet_request_packet_phase_await_pio_setup_frame_handler(
+ SCIC_SDS_REQUEST_T * request,
+ U32 frame_index
+)
+{
+ SCI_STATUS status;
+ SATA_FIS_HEADER_T * frame_header;
+ U32 * frame_buffer;
+ SCIC_SDS_STP_REQUEST_T * this_request;
+
+ this_request = (SCIC_SDS_STP_REQUEST_T *)request;
+
+ SCIC_LOG_TRACE((
+ sci_base_object_get_logger(this_request),
+ SCIC_LOG_OBJECT_STP_IO_REQUEST,
+ "scic_sds_stp_packet_request_packet_phase_await_pio_setup_frame_handler(0x%x, 0x%x) enter\n",
+ this_request, frame_index
+ ));
+
+ status = scic_sds_unsolicited_frame_control_get_header(
+ &(this_request->parent.owning_controller->uf_control),
+ frame_index,
+ (void**) &frame_header
+ );
+
+ if (status == SCI_SUCCESS)
+ {
+ ASSERT(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)((SATA_FIS_PIO_SETUP_T *)(&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
+ {
+ SCIC_LOG_ERROR((
+ sci_base_object_get_logger(this_request),
+ SCIC_LOG_OBJECT_STP_IO_REQUEST,
+ "SCIC IO Request 0x%x could not get frame header for frame index %d, status %x\n",
+ this_request, frame_index, status
+ ));
+ }
+
+ return status;
+}
+
+
+/**
+ * @brief 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.
+ *
+ * @param[in] this_request This parameter specifies the request for which
+ * the TC completion was received.
+ * @param[in] completion_code This parameter indicates the completion status
+ * information for the TC.
+ *
+ * @return Indicate if the tc completion handler was successful.
+ * @retval SCI_SUCCESS currently this method always returns success.
+ */
+static
+SCI_STATUS scic_sds_stp_packet_request_command_phase_await_tc_completion_tc_completion_handler(
+ SCIC_SDS_REQUEST_T * this_request,
+ U32 completion_code
+)
+{
+ SCI_STATUS status = SCI_SUCCESS;
+ U8 sat_packet_protocol = this_request->sat_protocol;
+
+ SCIC_LOG_TRACE((
+ sci_base_object_get_logger(this_request),
+ SCIC_LOG_OBJECT_STP_IO_REQUEST,
+ "scic_sds_stp_packet_request_command_phase_await_tc_completion_tc_completion_handler(0x%x, 0x%x) enter\n",
+ this_request, completion_code
+ ));
+
+ 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->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;
+ }
+ 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;
+}
+
+
+/**
+* @brief This method processes an unsolicited frame.
+*
+* @param[in] this_request This parameter specifies the request for which
+* the unsolicited frame was received.
+* @param[in] frame_index This parameter indicates the unsolicited frame
+* index that should contain the response.
+*
+* @return This method returns an indication of whether the UF
+* frame was handled successfully or not.
+* @retval SCI_SUCCESS Currently this value is always returned and indicates
+* successful processing of the TC response.
+*
+*/
+static
+SCI_STATUS scic_sds_stp_packet_request_command_phase_common_frame_handler(
+ SCIC_SDS_REQUEST_T * request,
+ U32 frame_index
+)
+{
+ SCI_STATUS status;
+ SATA_FIS_HEADER_T * frame_header;
+ U32 * frame_buffer;
+ SCIC_SDS_STP_REQUEST_T * this_request;
+
+ this_request = (SCIC_SDS_STP_REQUEST_T *)request;
+
+ SCIC_LOG_TRACE((
+ sci_base_object_get_logger(this_request),
+ SCIC_LOG_OBJECT_STP_IO_REQUEST,
+ "scic_sds_stp_packet_request_command_phase_await_d2h_frame_handler(0x%x, 0x%x) enter\n",
+ this_request, frame_index
+ ));
+
+ status = scic_sds_unsolicited_frame_control_get_header(
+ &(this_request->parent.owning_controller->uf_control),
+ frame_index,
+ (void**) &frame_header
+ );
+
+ if (status == SCI_SUCCESS)
+ {
+ ASSERT(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;
+}
+
+/**
+* @brief This method processes an unsolicited frame while the packet request is
+* expecting TC completion. It will process the FIS and construct sense
+* data.
+*
+* @param[in] this_request This parameter specifies the request for which
+* the unsolicited frame was received.
+* @param[in] frame_index This parameter indicates the unsolicited frame
+* index that should contain the response.
+*
+* @return This method returns an indication of whether the UF
+* frame was handled successfully or not.
+* @retval SCI_SUCCESS Currently this value is always returned and indicates
+* successful processing of the TC response.
+*
+*/
+static
+SCI_STATUS scic_sds_stp_packet_request_command_phase_await_tc_completion_frame_handler(
+ SCIC_SDS_REQUEST_T * request,
+ U32 frame_index
+)
+{
+ SCIC_SDS_STP_REQUEST_T * this_request = (SCIC_SDS_STP_REQUEST_T *)request;
+
+ 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;
+}
+
+
+/**
+* @brief This method processes an unsolicited frame while the packet request is
+* expecting TC completion. It will process the FIS and construct sense
+* data.
+*
+* @param[in] this_request This parameter specifies the request for which
+* the unsolicited frame was received.
+* @param[in] frame_index This parameter indicates the unsolicited frame
+* index that should contain the response.
+*
+* @return This method returns an indication of whether the UF
+* frame was handled successfully or not.
+* @retval SCI_SUCCESS Currently this value is always returned and indicates
+* successful processing of the TC response.
+*
+*/
+static
+SCI_STATUS scic_sds_stp_packet_request_command_phase_await_d2h_fis_frame_handler(
+ SCIC_SDS_REQUEST_T * request,
+ U32 frame_index
+)
+{
+ SCI_STATUS status =
+ scic_sds_stp_packet_request_command_phase_common_frame_handler(
+ request, frame_index);
+
+ SCIC_SDS_STP_REQUEST_T * this_request = (SCIC_SDS_STP_REQUEST_T *)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;
+}
+
+static
+SCI_STATUS scic_sds_stp_packet_request_started_completion_delay_complete_handler(
+ SCI_BASE_REQUEST_T *request
+)
+{
+ SCIC_SDS_REQUEST_T * this_request = (SCIC_SDS_REQUEST_T *)request;
+
+ sci_base_state_machine_change_state(
+ &this_request->parent.state_machine,
+ SCI_BASE_REQUEST_STATE_COMPLETED
+ );
+
+ return this_request->sci_status;
+}
+
+// ---------------------------------------------------------------------------
+
+SCIC_SDS_IO_REQUEST_STATE_HANDLER_T
+scic_sds_stp_packet_request_started_substate_handler_table
+[SCIC_SDS_STP_PACKET_REQUEST_STARTED_MAX_SUBSTATES] =
+{
+ // SCIC_SDS_STP_PACKET_REQUEST_STARTED_PACKET_PHASE_AWAIT_TC_COMPLETION_SUBSTATE
+ {
+ {
+ scic_sds_request_default_start_handler,
+ scic_sds_request_started_state_abort_handler,
+ scic_sds_request_default_complete_handler,
+ scic_sds_request_default_destruct_handler
+ },
+ scic_sds_stp_packet_request_packet_phase_await_tc_completion_tc_completion_handler,
+ scic_sds_request_default_event_handler,
+ scic_sds_request_default_frame_handler
+ },
+ // SCIC_SDS_STP_PACKET_REQUEST_STARTED_PACKET_PHASE_AWAIT_PIO_SETUP_SUBSTATE
+ {
+ {
+ scic_sds_request_default_start_handler,
+ scic_sds_request_started_state_abort_handler,
+ scic_sds_request_default_complete_handler,
+ scic_sds_request_default_destruct_handler
+ },
+ scic_sds_request_default_tc_completion_handler,
+ scic_sds_request_default_event_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
+ {
+ {
+ scic_sds_request_default_start_handler,
+ scic_sds_request_started_state_abort_handler,
+ scic_sds_request_default_complete_handler,
+ scic_sds_request_default_destruct_handler
+ },
+ scic_sds_stp_packet_request_command_phase_await_tc_completion_tc_completion_handler,
+ scic_sds_request_default_event_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
+ {
+ {
+ scic_sds_request_default_start_handler,
+ scic_sds_request_started_state_abort_handler,
+ scic_sds_request_default_complete_handler,
+ scic_sds_request_default_destruct_handler
+ },
+ scic_sds_request_default_tc_completion_handler,
+ scic_sds_request_default_event_handler,
+ scic_sds_stp_packet_request_command_phase_await_d2h_fis_frame_handler
+ },
+ // SCIC_SDS_STP_PACKET_REQUEST_STARTED_COMPLETION_DELAY_SUBSTATE
+ {
+ {
+ scic_sds_request_default_start_handler,
+ scic_sds_request_started_state_abort_handler,
+ scic_sds_stp_packet_request_started_completion_delay_complete_handler,
+ scic_sds_request_default_destruct_handler
+ },
+ scic_sds_request_default_tc_completion_handler,
+ scic_sds_request_default_event_handler,
+ scic_sds_request_default_frame_handler
+ }
+};
+
+/**
+ * @file
+ *
+ * @brief This file contains the Packet IO started substate machine
+ * for the SCIC_SDS_IO_REQUEST object.
+ */
+static
+void scic_sds_stp_packet_request_started_packet_phase_await_tc_completion_enter(
+ SCI_BASE_OBJECT_T *object
+)
+{
+ SCIC_SDS_REQUEST_T *this_request = (SCIC_SDS_REQUEST_T *)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
+ );
+}
+
+static
+void scic_sds_stp_packet_request_started_packet_phase_await_pio_setup_enter(
+ SCI_BASE_OBJECT_T *object
+)
+{
+ SCIC_SDS_REQUEST_T *this_request = (SCIC_SDS_REQUEST_T *)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
+ );
+}
+
+static
+void scic_sds_stp_packet_request_started_command_phase_await_tc_completion_enter(
+ SCI_BASE_OBJECT_T *object
+)
+{
+ SCIC_SDS_REQUEST_T *this_request = (SCIC_SDS_REQUEST_T *)object;
+ U8 sat_packet_protocol = this_request->sat_protocol;
+
+ SCU_TASK_CONTEXT_T *task_context;
+ 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
+ );
+}
+
+static
+void scic_sds_stp_packet_request_started_command_phase_await_d2h_fis_enter(
+ SCI_BASE_OBJECT_T *object
+)
+{
+ SCIC_SDS_REQUEST_T *this_request = (SCIC_SDS_REQUEST_T *)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
+ );
+}
+
+static
+void scic_sds_stp_packet_request_started_completion_delay_enter(
+ SCI_BASE_OBJECT_T *object
+)
+{
+ SCIC_SDS_REQUEST_T *this_request = (SCIC_SDS_REQUEST_T *)object;
+
+ SET_STATE_HANDLER(
+ this_request,
+ scic_sds_stp_packet_request_started_substate_handler_table,
+ SCIC_SDS_STP_PACKET_REQUEST_STARTED_COMPLETION_DELAY_SUBSTATE
+ );
+}
+
+
+// ---------------------------------------------------------------------------
+SCI_BASE_STATE_T
+ scic_sds_stp_packet_request_started_substate_table
+ [SCIC_SDS_STP_PACKET_REQUEST_STARTED_MAX_SUBSTATES] =
+{
+ {
+ SCIC_SDS_STP_PACKET_REQUEST_STARTED_PACKET_PHASE_AWAIT_TC_COMPLETION_SUBSTATE,
+ scic_sds_stp_packet_request_started_packet_phase_await_tc_completion_enter,
+ NULL
+ },
+ {
+ SCIC_SDS_STP_PACKET_REQUEST_STARTED_PACKET_PHASE_AWAIT_PIO_SETUP_SUBSTATE,
+ scic_sds_stp_packet_request_started_packet_phase_await_pio_setup_enter,
+ NULL
+ },
+ {
+ SCIC_SDS_STP_PACKET_REQUEST_STARTED_COMMAND_PHASE_AWAIT_TC_COMPLETION_SUBSTATE,
+ scic_sds_stp_packet_request_started_command_phase_await_tc_completion_enter,
+ NULL
+ },
+ {
+ SCIC_SDS_STP_PACKET_REQUEST_STARTED_COMMAND_PHASE_AWAIT_D2H_FIS_SUBSTATE,
+ scic_sds_stp_packet_request_started_command_phase_await_d2h_fis_enter,
+ NULL
+ },
+ {
+ SCIC_SDS_STP_PACKET_REQUEST_STARTED_COMPLETION_DELAY_SUBSTATE,
+ scic_sds_stp_packet_request_started_completion_delay_enter,
+ NULL
+ }
+};
+
+#endif //#if !defined(DISABLE_ATAPI)
+
diff --git a/sys/dev/isci/scil/scic_sds_stp_packet_request.h b/sys/dev/isci/scil/scic_sds_stp_packet_request.h
new file mode 100644
index 0000000..2c51f96
--- /dev/null
+++ b/sys/dev/isci/scil/scic_sds_stp_packet_request.h
@@ -0,0 +1,171 @@
+/*-
+ * 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.
+ *
+ * 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.
+ *
+ * $FreeBSD$
+ */
+#ifndef _SCIC_SDS_STP_PACKET_REQUEST_H_
+#define _SCIC_SDS_STP_PACKET_REQUEST_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif // __cplusplus
+
+#include <dev/isci/scil/intel_sas.h>
+#include <dev/isci/scil/sci_types.h>
+#include <dev/isci/scil/scic_sds_stp_request.h>
+
+/**
+ * @file
+ *
+ * @brief This file contains the structures and constants for PACKET protocol
+ * requests.
+ */
+
+
+/**
+ * @enum
+ *
+ * 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,
+
+ SCIC_SDS_STP_PACKET_REQUEST_STARTED_MAX_SUBSTATES
+};
+
+
+
+#if !defined(DISABLE_ATAPI)
+extern SCI_BASE_STATE_T scic_sds_stp_packet_request_started_substate_table[];
+extern SCIC_SDS_IO_REQUEST_STATE_HANDLER_T
+ scic_sds_stp_packet_request_started_substate_handler_table[];
+#endif // !defined(DISABLE_ATAPI)
+
+#if !defined(DISABLE_ATAPI)
+SCI_STATUS scic_sds_stp_packet_request_construct(
+ SCIC_SDS_REQUEST_T * 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(
+ SCIC_SDS_REQUEST_T * this_request,
+ SCU_TASK_CONTEXT_T * 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(
+ SCIC_SDS_REQUEST_T * this_request,
+ SCU_TASK_CONTEXT_T * 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)
+SCI_STATUS scic_sds_stp_packet_request_process_status_fis(
+ SCIC_SDS_REQUEST_T * this_request,
+ SATA_FIS_REG_D2H_T * 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(
+ SCIC_SDS_REQUEST_T * this_request
+);
+#else // !defined(DISABLE_ATAPI)
+#define scic_sds_stp_packet_internal_request_sense_build_sgl(request)
+#endif // !defined(DISABLE_ATAPI)
+
+#ifdef __cplusplus
+}
+#endif // __cplusplus
+
+#endif // _SCIC_SDS_STP_PACKET_REQUEST_H_
+
diff --git a/sys/dev/isci/scil/scic_sds_stp_pio_request.h b/sys/dev/isci/scil/scic_sds_stp_pio_request.h
new file mode 100644
index 0000000..3a0eb40
--- /dev/null
+++ b/sys/dev/isci/scil/scic_sds_stp_pio_request.h
@@ -0,0 +1,131 @@
+/*-
+ * 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.
+ *
+ * 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.
+ *
+ * $FreeBSD$
+ */
+#ifndef _SCIC_SDS_SATA_PIO_REQUEST_H_
+#define _SCIC_SDS_SATA_PIO_REQUEST_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif // __cplusplus
+
+#include <dev/isci/scil/sci_base_state.h>
+#include <dev/isci/scil/scic_sds_request.h>
+#include <dev/isci/scil/scu_task_context.h>
+
+/**
+ * @file
+ *
+ * @brief This file contains the structures and constants for SATA PIO
+ * requests.
+ */
+
+
+/**
+ * @enum
+ *
+ * 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,
+
+ SCIC_SDS_STP_REQUEST_STARTED_PIO_MAX_SUBSTATES
+};
+
+
+
+
+// ---------------------------------------------------------------------------
+
+extern SCIC_SDS_IO_REQUEST_STATE_HANDLER_T
+ scic_sds_stp_request_started_pio_substate_handler_table[
+ SCIC_SDS_STP_REQUEST_STARTED_PIO_MAX_SUBSTATES];
+
+extern SCI_BASE_STATE_T
+ scic_sds_stp_request_started_pio_substate_table[
+ SCIC_SDS_STP_REQUEST_STARTED_PIO_MAX_SUBSTATES];
+
+// ---------------------------------------------------------------------------
+
+SCU_SGL_ELEMENT_T * scic_sds_stp_request_pio_get_next_sgl(
+ SCIC_SDS_STP_REQUEST_T * this_request
+);
+
+#ifdef __cplusplus
+}
+#endif // __cplusplus
+
+#endif // _SCIC_SDS_SATA_PIO_REQUEST_H_
diff --git a/sys/dev/isci/scil/scic_sds_stp_remote_device.c b/sys/dev/isci/scil/scic_sds_stp_remote_device.c
new file mode 100644
index 0000000..49511c9
--- /dev/null
+++ b/sys/dev/isci/scil/scic_sds_stp_remote_device.c
@@ -0,0 +1,1098 @@
+/*-
+ * 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.
+ *
+ * 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 <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/**
+ * @file
+ *
+ * @brief This file contains the methods and state machines for SATA/STP
+ * remote devices.
+ */
+
+#include <dev/isci/scil/intel_sat.h>
+#include <dev/isci/scil/intel_ata.h>
+#include <dev/isci/scil/intel_sata.h>
+#include <dev/isci/scil/scic_remote_device.h>
+#include <dev/isci/scil/scic_user_callback.h>
+#include <dev/isci/scil/scic_sds_logger.h>
+#include <dev/isci/scil/scic_sds_controller.h>
+#include <dev/isci/scil/scic_sds_port.h>
+#include <dev/isci/scil/scic_sds_remote_device.h>
+#include <dev/isci/scil/scic_sds_request.h>
+#include <dev/isci/scil/scu_event_codes.h>
+#include <dev/isci/scil/scu_completion_codes.h>
+#include <dev/isci/scil/sci_base_state.h>
+
+/**
+ * This method will perform the STP request completion processing common
+ * to IO requests and task requests of all types
+ *
+ * @param[in] device This parameter specifies the device for which the
+ * request is being completed.
+ * @param[in] request This parameter specifies the request being completed.
+ *
+ * @return This method returns an indication as to whether the request
+ * processing completed successfully.
+ */
+static
+SCI_STATUS scic_sds_stp_remote_device_complete_request(
+ SCI_BASE_REMOTE_DEVICE_T * device,
+ SCI_BASE_REQUEST_T * request
+)
+{
+ SCIC_SDS_REMOTE_DEVICE_T * this_device = (SCIC_SDS_REMOTE_DEVICE_T *)device;
+ SCIC_SDS_REQUEST_T * the_request = (SCIC_SDS_REQUEST_T *)request;
+ 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)
+ {
+ SCIC_LOG_ERROR((
+ sci_base_object_get_logger(this_device),
+ SCIC_LOG_OBJECT_STP_REMOTE_TARGET,
+ "Port:0x%x Device:0x%x Request:0x%x Status:0x%x could not complete\n",
+ 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.
+ *
+ * @param[in] device The target device a task management request towards to.
+ * @param[in] request The task request.
+ *
+ * @return 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
+SCI_STATUS scic_sds_stp_remote_device_ready_substate_start_request_handler(
+ SCI_BASE_REMOTE_DEVICE_T * device,
+ SCI_BASE_REQUEST_T * request
+)
+{
+ SCI_STATUS status;
+ SCIC_SDS_REMOTE_DEVICE_T * this_device = (SCIC_SDS_REMOTE_DEVICE_T *)device;
+ SCIC_SDS_REQUEST_T * this_request = (SCIC_SDS_REQUEST_T *)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,
+ (SCIC_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
+ *
+ * @note If this is a softreset we may want to have a different substate.
+ *
+ * @param [in] device
+ * @param [in] request
+ *
+ * @return SCI_STATUS
+ */
+static
+SCI_STATUS scic_sds_stp_remote_device_ready_idle_substate_start_io_handler(
+ SCI_BASE_REMOTE_DEVICE_T * device,
+ SCI_BASE_REQUEST_T * request
+)
+{
+ SCI_STATUS status;
+ SCIC_SDS_REMOTE_DEVICE_T * this_device = (SCIC_SDS_REMOTE_DEVICE_T *)device;
+ SCIC_SDS_REQUEST_T * io_request = (SCIC_SDS_REQUEST_T *)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 (io_request->sat_protocol == 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;
+}
+
+
+/**
+ * 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.
+ *
+ * @param [in] device The device received event.
+ * @param [in] event_code The event code.
+ *
+ * @return SCI_STATUS
+ */
+static
+SCI_STATUS scic_sds_stp_remote_device_ready_idle_substate_event_handler(
+ SCIC_SDS_REMOTE_DEVICE_T * this_device,
+ U32 event_code
+)
+{
+ 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)
+ && (this_device->rnc->destination_state != SCIC_SDS_REMOTE_NODE_DESTINATION_STATE_READY))
+ {
+ status = scic_sds_remote_node_context_resume(
+ this_device->rnc, NULL, NULL);
+ }
+ }
+
+ return status;
+}
+
+
+//*****************************************************************************
+//* STP REMOTE DEVICE READY NCQ SUBSTATE HANDLERS
+//*****************************************************************************
+
+/**
+ *
+ */
+static
+SCI_STATUS scic_sds_stp_remote_device_ready_ncq_substate_start_io_handler(
+ SCI_BASE_REMOTE_DEVICE_T * device,
+ SCI_BASE_REQUEST_T * request
+)
+{
+ SCI_STATUS status;
+ SCIC_SDS_REMOTE_DEVICE_T * this_device = (SCIC_SDS_REMOTE_DEVICE_T *)device;
+ SCIC_SDS_REQUEST_T * io_request = (SCIC_SDS_REQUEST_T *)request;
+
+ if (io_request->sat_protocol == 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.
+ *
+ * @param [in] this_device This is the device object that is receiving the
+ * event.
+ * @param [in] event_code The event code to process.
+ *
+ * @return SCI_STATUS
+ */
+static
+SCI_STATUS scic_sds_stp_remote_device_ready_ncq_substate_event_handler(
+ SCIC_SDS_REMOTE_DEVICE_T * this_device,
+ U32 event_code
+)
+{
+ SCI_STATUS status;
+
+ status = scic_sds_remote_device_general_event_handler(this_device, event_code);
+
+ switch (scu_get_event_code(event_code))
+ {
+ case SCU_EVENT_TL_RNC_SUSPEND_TX:
+ case SCU_EVENT_TL_RNC_SUSPEND_TX_RX:
+ /// @todo We need to decode and understand why the hardware suspended the device.
+ /// The suspension reason was probably due to an SDB error FIS received.
+ break;
+
+ case SCU_EVENT_TL_RNC_SUSPEND_TX_DONE_DATA_LEN_ERR:
+ case SCU_EVENT_TL_RNC_SUSPEND_TX_DONE_OFFSET_ERR:
+ case SCU_EVENT_TL_RNC_SUSPEND_TX_DONE_DMASETUP_DIERR:
+ case SCU_EVENT_TL_RNC_SUSPEND_TX_DONE_XFERCNT_ERR:
+ case SCU_EVENT_TL_RNC_SUSPEND_TX_RX_DONE_PLD_LEN_ERR:
+ 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
+ );
+
+ // We have a notification that the driver requested a suspend operation
+ // this should not happen.
+ SCIC_LOG_WARNING((
+ sci_base_object_get_logger(this_device),
+ SCIC_LOG_OBJECT_STP_REMOTE_TARGET,
+ "SCIC Remote device 0x%x received driver suspend event %x while in ncq ready substate %d\n",
+ this_device, event_code, sci_base_state_machine_get_state(&this_device->ready_substate_machine)
+ ));
+
+ // Since we didnt expect to get here start the device again.
+ status = scic_sds_remote_device_resume(this_device);
+ break;
+
+ case SCU_EVENT_POST_RCN_RELEASE:
+ /// @todo Do we need to store the suspend state on the device?
+ SCIC_LOG_INFO((
+ sci_base_object_get_logger(this_device),
+ SCIC_LOG_OBJECT_STP_REMOTE_TARGET,
+ "SCIC Remote device 0x%x received driver release event %x while in the ready substate %d\n",
+ this_device, event_code, sci_base_state_machine_get_state(&this_device->ready_substate_machine)
+ ));
+ break;
+
+ default:
+ // Some other event just log it and continue
+ SCIC_LOG_WARNING((
+ sci_base_object_get_logger(this_device),
+ SCIC_LOG_OBJECT_STP_REMOTE_TARGET,
+ "SCIC Remote device 0x%x received driver unexpected event %x while in the ready substate %d\n",
+ this_device, event_code, sci_base_state_machine_get_state(&this_device->ready_substate_machine)
+ ));
+
+ status = SCI_FAILURE_INVALID_STATE;
+ break;
+ }
+
+ return status;
+}
+
+/**
+ *
+ *
+ * @param[in] this_device
+ * @param[in] frame_index
+ *
+ * @return SCI_STATUS
+ */
+static
+SCI_STATUS scic_sds_stp_remote_device_ready_ncq_substate_frame_handler(
+ SCIC_SDS_REMOTE_DEVICE_T * this_device,
+ U32 frame_index
+)
+{
+ SCI_STATUS status;
+ SATA_FIS_HEADER_T * 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;
+
+ /** @todo Check sactive and complete associated IO if any. */
+
+ sci_base_state_machine_change_state(
+ &this_device->ready_substate_machine,
+ SCIC_SDS_STP_REMOTE_DEVICE_READY_SUBSTATE_NCQ_ERROR
+ );
+ }
+ else if (
+ (frame_header->fis_type == SATA_FIS_TYPE_REGD2H)
+ && (frame_header->status & ATA_STATUS_REG_ERROR_BIT)
+ )
+ {
+ // Some devices return D2H FIS when an NCQ error is detected.
+ // Treat this like an SDB error FIS ready reason.
+ 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.
+ *
+ * @param[in] device
+ * @param[in] request
+ *
+ * @return SCI_STATUS
+ */
+static
+SCI_STATUS scic_sds_stp_remote_device_ready_cmd_substate_start_io_handler(
+ SCI_BASE_REMOTE_DEVICE_T * device,
+ SCI_BASE_REQUEST_T * request
+)
+{
+ return SCI_FAILURE_INVALID_STATE;
+}
+
+static
+SCI_STATUS scic_sds_stp_remote_device_ready_cmd_substate_suspend_handler(
+ SCIC_SDS_REMOTE_DEVICE_T * this_device,
+ U32 suspend_type
+)
+{
+ SCI_STATUS status;
+
+ status = scic_sds_remote_node_context_suspend(
+ this_device->rnc, suspend_type, NULL, NULL
+ );
+
+ return status;
+}
+
+/**
+ *
+ *
+ * @param[in] this_device
+ * @param[in] frame_index
+ *
+ * @return SCI_STATUS
+ */
+static
+SCI_STATUS scic_sds_stp_remote_device_ready_cmd_substate_frame_handler(
+ SCIC_SDS_REMOTE_DEVICE_T * this_device,
+ U32 frame_index
+)
+{
+ 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 AWAIT RESET SUBSTATE HANDLERS
+//*****************************************************************************
+static
+SCI_STATUS scic_sds_stp_remote_device_ready_await_reset_substate_start_io_handler(
+ SCI_BASE_REMOTE_DEVICE_T * device,
+ SCI_BASE_REQUEST_T * 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.
+ *
+ * @param[in] device This parameter specifies the device for which the
+ * request is being completed.
+ * @param[in] request This parameter specifies the request being completed.
+ *
+ * @return This method returns an indication as to whether the request
+ * processing completed successfully.
+ */
+static
+SCI_STATUS scic_sds_stp_remote_device_ready_await_reset_substate_complete_request_handler(
+ SCI_BASE_REMOTE_DEVICE_T * device,
+ SCI_BASE_REQUEST_T * request
+)
+{
+ SCIC_SDS_REMOTE_DEVICE_T * this_device = (SCIC_SDS_REMOTE_DEVICE_T *)device;
+ SCIC_SDS_REQUEST_T * the_request = (SCIC_SDS_REQUEST_T *)request;
+ 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)
+ {
+ SCIC_LOG_ERROR((
+ sci_base_object_get_logger(this_device),
+ SCIC_LOG_OBJECT_STP_REMOTE_TARGET,
+ "Port:0x%x Device:0x%x Request:0x%x Status:0x%x could not complete\n",
+ this_device->owning_port, this_device, the_request, status
+ ));
+ }
+
+ return status;
+}
+
+#if !defined(DISABLE_ATAPI)
+//*****************************************************************************
+//* STP REMOTE DEVICE READY ATAPI ERROR SUBSTATE HANDLERS
+//*****************************************************************************
+
+/**
+ * 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.
+ *
+ * @param [in] device The device received event.
+ * @param [in] event_code The event code.
+ *
+ * @return SCI_STATUS
+ */
+static
+SCI_STATUS scic_sds_stp_remote_device_ready_atapi_error_substate_event_handler(
+ SCIC_SDS_REMOTE_DEVICE_T * this_device,
+ U32 event_code
+)
+{
+ 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,
+ (SCIC_SDS_REMOTE_NODE_CONTEXT_CALLBACK)
+ this_device->working_request->state_handlers->parent.complete_handler,
+ (void *)this_device->working_request
+ );
+ }
+ }
+
+ return status;
+}
+#endif // !defined(DISABLE_ATAPI)
+
+// ---------------------------------------------------------------------------
+
+SCIC_SDS_REMOTE_DEVICE_STATE_HANDLER_T
+ 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_stp_remote_device_ready_ncq_substate_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
+ }
+};
+
+//*****************************************************************************
+//* STP REMOTE DEVICE READY SUBSTATE PRIVATE METHODS
+//*****************************************************************************
+
+static
+void scic_sds_stp_remote_device_ready_idle_substate_resume_complete_handler(
+ void * user_cookie
+)
+{
+ SCIC_SDS_REMOTE_DEVICE_T * this_device;
+ this_device = (SCIC_SDS_REMOTE_DEVICE_T *)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
+//*****************************************************************************
+
+/**
+ *
+ * @param[in] device This is the SCI base object which is cast into a
+ * SCIC_SDS_REMOTE_DEVICE object.
+ *
+ * @return none
+ */
+static
+void scic_sds_stp_remote_device_ready_idle_substate_enter(
+ SCI_BASE_OBJECT_T * device
+)
+{
+ SCIC_SDS_REMOTE_DEVICE_T * this_device;
+
+ this_device = (SCIC_SDS_REMOTE_DEVICE_T *)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
+//*****************************************************************************
+
+/**
+ *
+ *
+ * @param[in] device This is the SCI base object which is cast into a
+ * SCIC_SDS_REMOTE_DEVICE object.
+ *
+ * @return none
+ */
+static
+void scic_sds_stp_remote_device_ready_cmd_substate_enter(
+ SCI_BASE_OBJECT_T * device
+)
+{
+ SCIC_SDS_REMOTE_DEVICE_T * this_device;
+
+ this_device = (SCIC_SDS_REMOTE_DEVICE_T *)device;
+
+ ASSERT(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
+//*****************************************************************************
+
+/**
+ *
+ *
+ * @param[in] device This is the SCI base object which is cast into a
+ * SCIC_SDS_REMOTE_DEVICE object.
+ *
+ * @return none
+ */
+static
+void scic_sds_stp_remote_device_ready_ncq_substate_enter(
+ SCI_BASE_OBJECT_T * device
+)
+{
+ SCIC_SDS_REMOTE_DEVICE_T * this_device;
+
+ this_device = (SCIC_SDS_REMOTE_DEVICE_T *)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
+//*****************************************************************************
+
+/**
+ *
+ *
+ * @param[in] device This is the SCI base object which is cast into a
+ * SCIC_SDS_REMOTE_DEVICE object.
+ *
+ * @return none
+ */
+static
+void scic_sds_stp_remote_device_ready_ncq_error_substate_enter(
+ SCI_BASE_OBJECT_T * device
+)
+{
+ SCIC_SDS_REMOTE_DEVICE_T * this_device;
+
+ this_device = (SCIC_SDS_REMOTE_DEVICE_T *)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
+//*****************************************************************************
+
+/**
+ * @brief The enter routine to READY AWAIT RESET substate.
+ *
+ * @param[in] device This is the SCI base object which is cast into a
+ * SCIC_SDS_REMOTE_DEVICE object.
+ *
+ * @return none
+ */
+static
+void scic_sds_stp_remote_device_ready_await_reset_substate_enter(
+ SCI_BASE_OBJECT_T * device
+)
+{
+ SCIC_SDS_REMOTE_DEVICE_T * this_device;
+
+ this_device = (SCIC_SDS_REMOTE_DEVICE_T *)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
+//*****************************************************************************
+
+/**
+ * @brief The enter routine to READY ATAPI ERROR substate.
+ *
+ * @param[in] device This is the SCI base object which is cast into a
+ * SCIC_SDS_REMOTE_DEVICE object.
+ *
+ * @return none
+ */
+static
+void scic_sds_stp_remote_device_ready_atapi_error_substate_enter(
+ SCI_BASE_OBJECT_T * device
+)
+{
+ SCIC_SDS_REMOTE_DEVICE_T * this_device;
+
+ this_device = (SCIC_SDS_REMOTE_DEVICE_T *)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)
+
+// ---------------------------------------------------------------------------
+
+SCI_BASE_STATE_T
+ scic_sds_stp_remote_device_ready_substate_table[
+ SCIC_SDS_STP_REMOTE_DEVICE_READY_MAX_SUBSTATES] =
+{
+ {
+ SCIC_SDS_STP_REMOTE_DEVICE_READY_SUBSTATE_IDLE,
+ scic_sds_stp_remote_device_ready_idle_substate_enter,
+ NULL
+ },
+ {
+ SCIC_SDS_STP_REMOTE_DEVICE_READY_SUBSTATE_CMD,
+ scic_sds_stp_remote_device_ready_cmd_substate_enter,
+ NULL
+ },
+ {
+ SCIC_SDS_STP_REMOTE_DEVICE_READY_SUBSTATE_NCQ,
+ scic_sds_stp_remote_device_ready_ncq_substate_enter,
+ NULL
+ },
+ {
+ SCIC_SDS_STP_REMOTE_DEVICE_READY_SUBSTATE_NCQ_ERROR,
+ scic_sds_stp_remote_device_ready_ncq_error_substate_enter,
+ NULL
+ },
+#if !defined(DISABLE_ATAPI)
+ {
+ SCIC_SDS_STP_REMOTE_DEVICE_READY_SUBSTATE_ATAPI_ERROR,
+ scic_sds_stp_remote_device_ready_atapi_error_substate_enter,
+ NULL
+ },
+#endif
+ {
+ SCIC_SDS_STP_REMOTE_DEVICE_READY_SUBSTATE_AWAIT_RESET,
+ scic_sds_stp_remote_device_ready_await_reset_substate_enter,
+ NULL
+ }
+};
+
diff --git a/sys/dev/isci/scil/scic_sds_stp_request.c b/sys/dev/isci/scil/scic_sds_stp_request.c
new file mode 100644
index 0000000..55bbacc
--- /dev/null
+++ b/sys/dev/isci/scil/scic_sds_stp_request.c
@@ -0,0 +1,2581 @@
+/*-
+ * 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.
+ *
+ * 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 <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <dev/isci/scil/intel_sat.h>
+#include <dev/isci/scil/intel_sata.h>
+#include <dev/isci/scil/sci_types.h>
+#include <dev/isci/scil/scic_remote_device.h>
+#include <dev/isci/scil/scic_user_callback.h>
+#include <dev/isci/scil/scic_sds_controller.h>
+#include <dev/isci/scil/scic_sds_remote_device.h>
+#include <dev/isci/scil/scic_sds_stp_request.h>
+#include <dev/isci/scil/scic_sds_stp_pio_request.h>
+#include <dev/isci/scil/scic_sds_logger.h>
+#include <dev/isci/sci_environment.h>
+#include <dev/isci/scil/sci_base_state_machine.h>
+#include <dev/isci/scil/scu_task_context.h>
+#include <dev/isci/scil/intel_ata.h>
+#include <dev/isci/scil/sci_util.h>
+#include <dev/isci/scil/scic_sds_logger.h>
+#include <dev/isci/scil/scic_sds_request.h>
+#include <dev/isci/scil/scic_sds_stp_request.h>
+#include <dev/isci/scil/scu_completion_codes.h>
+#include <dev/isci/scil/scu_event_codes.h>
+#include <dev/isci/scil/sci_base_state.h>
+#include <dev/isci/scil/scic_sds_unsolicited_frame_control.h>
+#include <dev/isci/scil/scic_io_request.h>
+
+#if !defined(DISABLE_ATAPI)
+#include <dev/isci/scil/scic_sds_stp_packet_request.h>
+#endif
+
+/**
+ * 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_unaligned(memory) \
+ ((SATA_FIS_REG_H2D_T *)( \
+ ((char *)(memory)) + sizeof(SCIC_SDS_STP_REQUEST_T) \
+ ))
+
+/**
+ * This macro aligns the stp command buffer in DWORD alignment
+*/
+#define scic_sds_stp_request_align_h2d_reg_buffer(address) \
+ ((SATA_FIS_REG_H2D_T *)( \
+ (((POINTER_UINT)(address)) + (sizeof(U32) - 1)) \
+ & ~(sizeof(U32)- 1) \
+ ))
+
+/**
+ * This macro returns the DWORD-aligned stp command buffer
+*/
+#define scic_sds_stp_request_get_h2d_reg_buffer(memory) \
+ ((SATA_FIS_REG_H2D_T *) \
+ ((char *)scic_sds_stp_request_align_h2d_reg_buffer( \
+ (char *) scic_sds_stp_request_get_h2d_reg_buffer_unaligned(memory) \
+ )))
+
+/**
+ * This macro returns the address of the stp response buffer in the io
+ * request memory
+ */
+#define scic_sds_stp_request_get_response_buffer_unaligned(memory) \
+ ((SATA_FIS_REG_D2H_T *)( \
+ ((char *)(scic_sds_stp_request_get_h2d_reg_buffer(memory))) \
+ + sizeof(SATA_FIS_REG_H2D_T) \
+ ))
+
+
+/**
+ * This macro aligns the stp response buffer in DWORD alignment
+*/
+#define scic_sds_stp_request_align_response_buffer(address) \
+ ((SATA_FIS_REG_D2H_T *)( \
+ (((POINTER_UINT)(address)) + (sizeof(U32) - 1)) \
+ & ~(sizeof(U32)- 1) \
+ ))
+
+/**
+ * This macro returns the DWORD-aligned stp response buffer
+*/
+#define scic_sds_stp_request_get_response_buffer(memory) \
+ ((SATA_FIS_REG_D2H_T *) \
+ ((char *)scic_sds_stp_request_align_response_buffer( \
+ (char *)scic_sds_stp_request_get_response_buffer_unaligned(memory) \
+ )))
+
+
+/**
+ * This macro returns the address of the task context buffer in the io
+ * request memory
+ */
+#define scic_sds_stp_request_get_task_context_buffer_unaligned(memory) \
+ ((SCU_TASK_CONTEXT_T *)( \
+ ((char *)(scic_sds_stp_request_get_response_buffer(memory))) \
+ + sizeof(SCI_SSP_RESPONSE_IU_T) \
+ ))
+
+/**
+ * This macro returns the aligned task context buffer
+ */
+#define scic_sds_stp_request_get_task_context_buffer(memory) \
+ ((SCU_TASK_CONTEXT_T *)( \
+ ((char *)scic_sds_request_align_task_context_buffer( \
+ (char *)scic_sds_stp_request_get_task_context_buffer_unaligned(memory)) \
+ )))
+
+/**
+ * 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) \
+ ((SCU_SGL_ELEMENT_PAIR_T *)( \
+ ((char *)(scic_sds_stp_request_get_task_context_buffer(memory))) \
+ + sizeof(SCU_TASK_CONTEXT_T) \
+ ))
+
+
+/**
+ * This method return the memory space commonly required for STP IO and
+ * task requests.
+ *
+ * @return U32
+ */
+static
+U32 scic_sds_stp_common_request_get_object_size(void)
+{
+ return sizeof(SCIC_SDS_STP_REQUEST_T)
+ + sizeof(SATA_FIS_REG_H2D_T)
+ + sizeof(U32)
+ + sizeof(SATA_FIS_REG_D2H_T)
+ + sizeof(U32)
+ + sizeof(SCU_TASK_CONTEXT_T)
+ + CACHE_LINE_SIZE;
+}
+
+
+/**
+ * This method return the memory space required for STP PIO requests.
+ *
+ * @return U32
+ */
+U32 scic_sds_stp_request_get_object_size(void)
+{
+ return scic_sds_stp_common_request_get_object_size()
+ + sizeof(SCU_SGL_ELEMENT_PAIR_T) * SCU_MAX_SGL_ELEMENT_PAIRS;
+}
+
+
+/**
+ * This method return the memory space required for STP task requests.
+ *
+ * @return U32
+ */
+U32 scic_sds_stp_task_request_get_object_size(void)
+{
+ return scic_sds_stp_common_request_get_object_size();
+}
+
+
+/**
+ *
+ *
+ * @param[in] this_request
+ */
+void scic_sds_stp_request_assign_buffers(
+ SCIC_SDS_REQUEST_T * request
+)
+{
+ SCIC_SDS_STP_REQUEST_T * this_request = (SCIC_SDS_STP_REQUEST_T *)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);
+ }
+}
+
+/**
+ * @brief This method is will fill in the SCU Task Context for any type of
+ * SATA request. This is called from the various SATA constructors.
+ *
+ * @pre The general io request construction is complete.
+ * @pre The buffer assignment for the command buffer is complete.
+ *
+ * @param[in] this_request The general IO request object which is to be used
+ * in constructing the SCU task context.
+ * @param[in] task_context The buffer pointer for the SCU task context which
+ * is being constructed.
+ *
+ * @return none
+ *
+ * @todo Revisit task context construction to determine what is common for
+ * SSP/SMP/STP task context structures.
+ */
+void scu_sata_reqeust_construct_task_context(
+ SCIC_SDS_REQUEST_T * this_request,
+ SCU_TASK_CONTEXT_T * task_context
+)
+{
+ SCI_PHYSICAL_ADDRESS physical_address;
+ SCIC_SDS_CONTROLLER_T *owning_controller;
+ SCIC_SDS_REMOTE_DEVICE_T *target_device;
+ SCIC_SDS_PORT_T *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(SATA_FIS_REG_H2D_T) - 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 =
+ sci_cb_physical_address_upper(physical_address);
+ task_context->command_iu_lower =
+ sci_cb_physical_address_lower(physical_address);
+
+ // SATA Requests do not have a response buffer
+ task_context->response_iu_upper = 0;
+ task_context->response_iu_lower = 0;
+}
+
+/**
+ * This method will perform any general sata request construction.
+ *
+ * @todo What part of SATA IO request construction is general?
+ *
+ * @param[in] this_request
+ *
+ * @return none
+ */
+void scic_sds_stp_non_ncq_request_construct(
+ SCIC_SDS_REQUEST_T * this_request
+)
+{
+ this_request->has_started_substate_machine = TRUE;
+}
+
+/**
+ * This method will perform request construction common to all types of
+ * STP requests that are optimized by the silicon (i.e. UDMA, NCQ).
+ *
+ * @param[in,out] this_request This parameter specifies the request to be
+ * constructed as an optimized request.
+ * @param[in] 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.
+ *
+ * @return This method returns an indication as to whether the construction
+ * was successful.
+ */
+static
+void scic_sds_stp_optimized_request_construct(
+ SCIC_SDS_REQUEST_T * this_request,
+ U8 optimized_task_type,
+ U32 transfer_length,
+ SCI_IO_REQUEST_DATA_DIRECTION data_direction
+)
+{
+ SCU_TASK_CONTEXT_T * 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 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 method performs the operations common to all SATA/STP requests
+ * utilizing the raw frame method.
+ *
+ * @param[in] this_request This parameter specifies the STP request object
+ * for which to construct a RAW command frame task context.
+ * @param[in] task_context This parameter specifies the SCU specific
+ * task context buffer to construct.
+ *
+ * @return none
+ */
+void scu_stp_raw_request_construct_task_context(
+ SCIC_SDS_STP_REQUEST_T * this_request,
+ SCU_TASK_CONTEXT_T * 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(SATA_FIS_REG_H2D_T) - sizeof(U32);
+}
+
+/**
+ * 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.
+ *
+ * @param[in] this_request This parameter specifies the core request
+ * object to construction into an STP/SATA non-data request.
+ *
+ * @return This method currently always returns SCI_SUCCESS
+ */
+SCI_STATUS scic_sds_stp_non_data_request_construct(
+ SCIC_SDS_REQUEST_T * this_request
+)
+{
+ scic_sds_stp_non_ncq_request_construct(this_request);
+
+ // Build the STP task context structure
+ scu_stp_raw_request_construct_task_context(
+ (SCIC_SDS_STP_REQUEST_T*) 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;
+}
+
+
+SCI_STATUS scic_sds_stp_soft_reset_request_construct(
+ SCIC_SDS_REQUEST_T * this_request
+)
+{
+ scic_sds_stp_non_ncq_request_construct(this_request);
+
+ // Build the STP task context structure
+ scu_stp_raw_request_construct_task_context(
+ (SCIC_SDS_STP_REQUEST_T*) 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;
+}
+
+/**
+ * @brief This method constructs the SATA request object.
+ *
+ * @param[in] this_request
+ * @param[in] sat_protocol
+ * @param[in] transfer_length
+ * @param[in] data_direction
+ * @param[in] copy_rx_frame
+ * @param[in] do_translate_sgl This parameter specifies whether SGL
+ * translation should be performed or if the user is handling
+ * it.
+ *
+ * @return SCI_STATUS
+ */
+SCI_STATUS scic_sds_io_request_construct_sata(
+ SCIC_SDS_REQUEST_T * this_request,
+ U8 sat_protocol,
+ U32 transfer_length,
+ SCI_IO_REQUEST_DATA_DIRECTION data_direction,
+ BOOL copy_rx_frame,
+ BOOL do_translate_sgl
+)
+{
+ SCI_STATUS status = SCI_SUCCESS;
+
+ this_request->protocol = SCIC_STP_PROTOCOL;
+
+ this_request->sat_protocol = sat_protocol;
+
+ switch (sat_protocol)
+ {
+ case SAT_PROTOCOL_FPDMA:
+ scic_sds_stp_optimized_request_construct(
+ this_request,
+ SCU_TASK_TYPE_FPDMAQ_READ,
+ transfer_length,
+ data_direction
+ );
+
+ // Copy over the SGL elements
+ if (do_translate_sgl == TRUE)
+ scic_sds_request_build_sgl(this_request);
+ break;
+
+ case SAT_PROTOCOL_UDMA_DATA_IN:
+ case SAT_PROTOCOL_UDMA_DATA_OUT:
+ 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
+ );
+
+ // Copy over the SGL elements
+ if (do_translate_sgl == TRUE)
+ scic_sds_request_build_sgl(this_request);
+
+ 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
+ );
+ break;
+
+ 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_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;
+
+#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:
+ SCIC_LOG_ERROR((
+ sci_base_object_get_logger(this_request),
+ SCIC_LOG_OBJECT_STP_IO_REQUEST,
+ "SCIC IO Request 0x%x received un-handled SAT Protocol %d.\n",
+ this_request, sat_protocol
+ ));
+
+ status = SCI_FAILURE;
+ break;
+ }
+
+ if (status == SCI_SUCCESS)
+ {
+ scic_sds_request_initialize_state_logging(this_request);
+
+ sci_base_state_machine_change_state(
+ &this_request->parent.state_machine,
+ SCI_BASE_REQUEST_STATE_CONSTRUCTED
+ );
+ }
+
+ return status;
+}
+
+//****************************************************************************
+//* SCIC Interface Implementation
+//****************************************************************************
+
+void scic_stp_io_request_set_ncq_tag(
+ SCI_IO_REQUEST_HANDLE_T scic_io_request,
+ 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.
+ */
+ SCIC_SDS_REQUEST_T * this_request = (SCIC_SDS_REQUEST_T *)scic_io_request;
+ this_request->task_context_buffer->type.stp.ncq_tag = ncq_tag;
+}
+
+// ---------------------------------------------------------------------------
+
+void * scic_stp_io_request_get_h2d_reg_address(
+ SCI_IO_REQUEST_HANDLE_T scic_io_request
+)
+{
+ SCIC_SDS_REQUEST_T * this_request = (SCIC_SDS_REQUEST_T *)scic_io_request;
+
+ return this_request->command_buffer;
+}
+
+// ---------------------------------------------------------------------------
+
+void * scic_stp_io_request_get_d2h_reg_address(
+ SCI_IO_REQUEST_HANDLE_T scic_io_request
+)
+{
+ SCIC_SDS_STP_REQUEST_T * this_request = (SCIC_SDS_STP_REQUEST_T *)scic_io_request;
+
+ return &this_request->d2h_reg_fis;
+}
+
+/**
+ * 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
+ *
+ * @param[in] this_request
+ *
+ * @return SCU_SGL_ELEMENT_T*
+ */
+SCU_SGL_ELEMENT_T * scic_sds_stp_request_pio_get_next_sgl(
+ SCIC_SDS_STP_REQUEST_T * this_request
+)
+{
+ SCU_SGL_ELEMENT_T * 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
+ {
+ this_request->type.pio.request_current.sgl_pair =
+ scic_sds_request_get_sgl_element_pair(
+ &(this_request->parent),
+ ++this_request->type.pio.sgl_pair_index
+ );
+
+ 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;
+}
+
+/**
+ * This method will construct the SATA PIO request.
+ *
+ * @param[in] scic_io_request The core request object which is cast to a SATA
+ * PIO request object.
+ *
+ * @return This method returns an indication as to whether the construction
+ * was successful.
+ * @retval SCI_SUCCESS Currently this method always returns this value.
+ */
+SCI_STATUS scic_sds_stp_pio_request_construct(
+ SCIC_SDS_REQUEST_T * scic_io_request,
+ U8 sat_protocol,
+ BOOL copy_rx_frame
+)
+{
+ SCIC_SDS_STP_REQUEST_T * this_request;
+
+ this_request = (SCIC_SDS_STP_REQUEST_T *)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;
+ this_request->type.pio.sgl_pair_index = 0;
+
+ if ((copy_rx_frame) || (sat_protocol == SAT_PROTOCOL_PIO_DATA_OUT))
+ {
+ 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;
+}
+
+//******************************************************************************
+//* STP NON-DATA STATE MACHINE
+//******************************************************************************
+
+/**
+ * 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.
+ *
+ * @param[in] this_request
+ * @param[in] completion_code
+ *
+ * @return This method always successfully processes the TC completion.
+ * @retval SCI_SUCCESS This value is always returned.
+ */
+static
+SCI_STATUS scic_sds_stp_request_non_data_await_h2d_tc_completion_handler(
+ SCIC_SDS_REQUEST_T * this_request,
+ U32 completion_code
+)
+{
+ SCIC_LOG_TRACE((
+ sci_base_object_get_logger(this_request),
+ SCIC_LOG_OBJECT_STP_IO_REQUEST,
+ "scic_sds_stp_request_non_data_await_h2d_tc_completion_handler(0x%x, 0x%x) enter\n",
+ this_request, 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;
+}
+
+/**
+ * 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.
+ *
+ * @param[in] request This parameter specifies the request for which a
+ * frame has been received.
+ * @param[in] frame_index This parameter specifies the index of the frame
+ * that has been received.
+ *
+ * @return Indicate if the received frame was processed successfully.
+ */
+static
+SCI_STATUS scic_sds_stp_request_non_data_await_d2h_frame_handler(
+ SCIC_SDS_REQUEST_T * request,
+ U32 frame_index
+)
+{
+ SCI_STATUS status;
+ SATA_FIS_HEADER_T * frame_header;
+ U32 * frame_buffer;
+ SCIC_SDS_STP_REQUEST_T * this_request = (SCIC_SDS_STP_REQUEST_T *)request;
+
+ // Save off the controller, so that we do not touch the request after it
+ // is completed.
+ SCIC_SDS_CONTROLLER_T * owning_controller = this_request->parent.owning_controller;
+
+ SCIC_LOG_TRACE((
+ sci_base_object_get_logger(this_request),
+ SCIC_LOG_OBJECT_STP_IO_REQUEST,
+ "scic_sds_stp_request_non_data_await_d2h_frame_handler(0x%x, 0x%x) enter\n",
+ this_request, frame_index
+ ));
+
+ status = scic_sds_unsolicited_frame_control_get_header(
+ &(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(
+ &(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:
+ SCIC_LOG_WARNING((
+ sci_base_object_get_logger(this_request),
+ SCIC_LOG_OBJECT_STP_IO_REQUEST,
+ "IO Request:0x%x Frame Id:%d protocol violation occurred\n",
+ 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(
+ owning_controller, frame_index
+ );
+ }
+ else
+ {
+ SCIC_LOG_ERROR((
+ sci_base_object_get_logger(this_request),
+ SCIC_LOG_OBJECT_STP_IO_REQUEST,
+ "SCIC IO Request 0x%x could not get frame header for frame index %d, status %x\n",
+ this_request, frame_index, status
+ ));
+ }
+
+ return status;
+}
+
+// ---------------------------------------------------------------------------
+
+SCIC_SDS_IO_REQUEST_STATE_HANDLER_T
+ scic_sds_stp_request_started_non_data_substate_handler_table
+ [SCIC_SDS_STP_REQUEST_STARTED_NON_DATA_MAX_SUBSTATES] =
+{
+ // SCIC_SDS_STP_REQUEST_STARTED_NON_DATA_AWAIT_H2D_COMPLETION_SUBSTATE
+ {
+ {
+ scic_sds_request_default_start_handler,
+ scic_sds_request_started_state_abort_handler,
+ scic_sds_request_default_complete_handler,
+ scic_sds_request_default_destruct_handler
+ },
+ scic_sds_stp_request_non_data_await_h2d_tc_completion_handler,
+ scic_sds_request_default_event_handler,
+ scic_sds_request_default_frame_handler
+ },
+ // SCIC_SDS_STP_REQUEST_STARTED_NON_DATA_AWAIT_D2H_SUBSTATE
+ {
+ {
+ scic_sds_request_default_start_handler,
+ scic_sds_request_started_state_abort_handler,
+ scic_sds_request_default_complete_handler,
+ scic_sds_request_default_destruct_handler
+ },
+ scic_sds_request_default_tc_completion_handler,
+ scic_sds_request_default_event_handler,
+ scic_sds_stp_request_non_data_await_d2h_frame_handler
+ }
+};
+
+static
+void scic_sds_stp_request_started_non_data_await_h2d_completion_enter(
+ SCI_BASE_OBJECT_T *object
+)
+{
+ SCIC_SDS_REQUEST_T *this_request = (SCIC_SDS_REQUEST_T *)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(
+ SCI_BASE_OBJECT_T *object
+)
+{
+ SCIC_SDS_REQUEST_T *this_request = (SCIC_SDS_REQUEST_T *)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
+ );
+}
+
+// ---------------------------------------------------------------------------
+
+SCI_BASE_STATE_T scic_sds_stp_request_started_non_data_substate_table
+[SCIC_SDS_STP_REQUEST_STARTED_NON_DATA_MAX_SUBSTATES] =
+{
+ {
+ SCIC_SDS_STP_REQUEST_STARTED_NON_DATA_AWAIT_H2D_COMPLETION_SUBSTATE,
+ scic_sds_stp_request_started_non_data_await_h2d_completion_enter,
+ NULL
+ },
+ {
+ SCIC_SDS_STP_REQUEST_STARTED_NON_DATA_AWAIT_D2H_SUBSTATE,
+ scic_sds_stp_request_started_non_data_await_d2h_enter,
+ NULL
+ }
+};
+
+//******************************************************************************
+//* STP PIO STATE MACHINE
+//******************************************************************************
+
+#define SCU_MAX_FRAME_BUFFER_SIZE 0x400 // 1K is the maximum SCU frame data payload
+
+/**
+ * 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
+ *
+ * @param[in] this_request
+ * @param[in] length
+ *
+ * @return SCI_STATUS
+ */
+static
+SCI_STATUS scic_sds_stp_request_pio_data_out_trasmit_data_frame (
+ SCIC_SDS_REQUEST_T * this_request,
+ U32 length
+)
+{
+ SCI_STATUS status = SCI_SUCCESS;
+ SCU_SGL_ELEMENT_T * current_sgl;
+ SCIC_SDS_STP_REQUEST_T * this_sds_stp_request = (SCIC_SDS_STP_REQUEST_T *)this_request;
+
+ // Recycle the TC and reconstruct it for sending out DATA FIS containing
+ // for the data from current_sgl+offset for the input length
+ SCU_TASK_CONTEXT_T * 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.
+ status = this_request->owning_controller->state_handlers->parent.continue_io_handler(
+ &this_request->owning_controller->parent,
+ &this_request->target_device->parent,
+ &this_request->parent
+ );
+
+ return status;
+
+}
+
+/**
+ *
+ *
+ * @param[in] this_request
+ *
+ * @return SCI_STATUS
+ */
+static
+SCI_STATUS scic_sds_stp_request_pio_data_out_transmit_data(
+ SCIC_SDS_REQUEST_T * this_sds_request
+)
+{
+
+ SCU_SGL_ELEMENT_T * current_sgl;
+ U32 sgl_offset;
+ U32 remaining_bytes_in_current_sgl = 0;
+ SCI_STATUS status = SCI_SUCCESS;
+
+ SCIC_SDS_STP_REQUEST_T * this_sds_stp_request = (SCIC_SDS_STP_REQUEST_T *)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;
+}
+
+/**
+ * Copy the data from the buffer for the length specified to the IO reqeust
+ * SGL specified data region.
+ *
+ * @param[in] this_request The request that is used for the SGL processing.
+ * @param[in] data_buffer The buffer of data to be copied.
+ * @param[in] length The length of the data transfer.
+ *
+ * @return SCI_STATUS
+ */
+static
+SCI_STATUS scic_sds_stp_request_pio_data_in_copy_data_buffer(
+ SCIC_SDS_STP_REQUEST_T * this_request,
+ U8 * data_buffer,
+ U32 length
+)
+{
+ SCI_STATUS status;
+ SCU_SGL_ELEMENT_T * current_sgl;
+ U32 sgl_offset;
+ U32 data_offset;
+ U8 * source_address;
+
+ // 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 = this_request->type.pio.current_transfer_bytes;
+ 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
+ {
+#ifdef ENABLE_OSSL_COPY_BUFFER
+ scic_cb_io_request_copy_buffer(this_request, data_buffer, data_offset, length);
+ length = 0;
+#else
+ U8 * destination_address;
+ U32 copy_length;
+
+ destination_address = (U8 *)scic_cb_io_request_get_virtual_address_from_sgl(
+ this_request,
+ data_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;
+#endif
+ }
+ }
+
+ this_request->type.pio.request_current.sgl_offset = sgl_offset;
+
+ return status;
+}
+
+/**
+ * Copy the data buffer to the io request data region.
+ *
+ * @param[in] this_request The PIO DATA IN request that is to receive the
+ * data.
+ * @param[in] data_buffer The buffer to copy from.
+ *
+ * @return SCI_STATUS
+ */
+static
+SCI_STATUS scic_sds_stp_request_pio_data_in_copy_data(
+ SCIC_SDS_STP_REQUEST_T * this_request,
+ U8 * data_buffer
+)
+{
+ 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)
+ {
+ // All data for this PIO request has now been copied, so we don't
+ // technically need to update current_transfer_bytes here - just
+ // doing it for completeness.
+ this_request->type.pio.current_transfer_bytes += this_request->type.pio.pio_transfer_bytes;
+ 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;
+ this_request->type.pio.current_transfer_bytes += SCU_MAX_FRAME_BUFFER_SIZE;
+ }
+ }
+
+ return status;
+}
+
+/**
+ *
+ *
+ * @param[in] this_request
+ * @param[in] completion_code
+ *
+ * @return SCI_STATUS
+ */
+static
+SCI_STATUS scic_sds_stp_request_pio_await_h2d_completion_tc_completion_handler(
+ SCIC_SDS_REQUEST_T * this_request,
+ U32 completion_code
+)
+{
+ SCI_STATUS status = SCI_SUCCESS;
+
+ SCIC_LOG_TRACE((
+ sci_base_object_get_logger(this_request),
+ SCIC_LOG_OBJECT_STP_IO_REQUEST,
+ "scic_sds_stp_request_pio_data_in_await_h2d_completion_tc_completion_handler(0x%x, 0x%x) enter\n",
+ this_request, 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_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;
+}
+
+/**
+ *
+ *
+ * @param[in] this_request
+ * @param[in] frame_index
+ *
+ * @return SCI_STATUS
+ */
+static
+SCI_STATUS scic_sds_stp_request_pio_await_frame_frame_handler(
+ SCIC_SDS_REQUEST_T * request,
+ U32 frame_index
+)
+{
+ SCI_STATUS status;
+ SATA_FIS_HEADER_T * frame_header;
+ U32 * frame_buffer;
+ SCIC_SDS_STP_REQUEST_T * this_request;
+ SCIC_SDS_CONTROLLER_T * owning_controller;
+
+ this_request = (SCIC_SDS_STP_REQUEST_T *)request;
+
+ // Save off the controller, so that we do not touch the request after it
+ // is completed.
+ owning_controller = this_request->parent.owning_controller;
+
+ SCIC_LOG_TRACE((
+ sci_base_object_get_logger(this_request),
+ SCIC_LOG_OBJECT_STP_IO_REQUEST,
+ "scic_sds_stp_request_pio_data_in_await_frame_frame_handler(0x%x, 0x%x) enter\n",
+ this_request, frame_index
+ ));
+
+ status = scic_sds_unsolicited_frame_control_get_header(
+ &(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(
+ &(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)((SATA_FIS_PIO_SETUP_T *)(&frame_buffer[-1]))->transfter_count;
+ this_request->type.pio.ending_status =
+ (U8)((SATA_FIS_PIO_SETUP_T *)(&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(
+ &(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.
+ SCIC_LOG_INFO((
+ sci_base_object_get_logger(this_request),
+ SCIC_LOG_OBJECT_STP_IO_REQUEST,
+ "SCIC PIO Request 0x%x received D2H Register FIS with BSY status 0x%x\n",
+ this_request, frame_header->status
+ ));
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ // Frame is decoded return it to the controller
+ scic_sds_controller_release_frame(
+ owning_controller,
+ frame_index
+ );
+ }
+ else
+ {
+ SCIC_LOG_ERROR((
+ sci_base_object_get_logger(this_request),
+ SCIC_LOG_OBJECT_STP_IO_REQUEST,
+ "SCIC IO Request 0x%x could not get frame header for frame index %d, status %x\n",
+ this_request, frame_index, status
+ ));
+ }
+
+ return status;
+}
+
+/**
+ *
+ *
+ * @param[in] this_request
+ * @param[in] frame_index
+ *
+ * @return SCI_STATUS
+ */
+static
+SCI_STATUS scic_sds_stp_request_pio_data_in_await_data_frame_handler(
+ SCIC_SDS_REQUEST_T * request,
+ U32 frame_index
+)
+{
+ SCI_STATUS status;
+ SATA_FIS_HEADER_T * frame_header;
+ SATA_FIS_DATA_T * frame_buffer;
+ SCIC_SDS_STP_REQUEST_T * this_request;
+ SCIC_SDS_CONTROLLER_T * owning_controller;
+
+ this_request = (SCIC_SDS_STP_REQUEST_T *)request;
+
+ // Save off the controller, so that we do not touch the request after it
+ // is completed.
+ owning_controller = this_request->parent.owning_controller;
+
+ SCIC_LOG_TRACE((
+ sci_base_object_get_logger(this_request),
+ SCIC_LOG_OBJECT_STP_IO_REQUEST,
+ "scic_sds_stp_request_pio_data_in_await_data_frame_handler(0x%x, 0x%x) enter\n",
+ this_request, frame_index
+ ));
+
+ status = scic_sds_unsolicited_frame_control_get_header(
+ &(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(
+ &(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(
+ 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
+ {
+ SCIC_LOG_ERROR((
+ sci_base_object_get_logger(this_request),
+ SCIC_LOG_OBJECT_STP_IO_REQUEST,
+ "SCIC PIO Request 0x%x received frame %d with fis type 0x%02x when expecting a data fis.\n",
+ 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(
+ owning_controller,
+ frame_index
+ );
+ }
+ }
+ else
+ {
+ SCIC_LOG_ERROR((
+ sci_base_object_get_logger(this_request),
+ SCIC_LOG_OBJECT_STP_IO_REQUEST,
+ "SCIC IO Request 0x%x could not get frame header for frame index %d, status %x\n",
+ this_request, frame_index, status
+ ));
+ }
+
+ return status;
+}
+
+
+/**
+ *
+ *
+ * @param[in] this_request
+ * @param[in] completion_code
+ *
+ * @return SCI_STATUS
+ */
+static
+SCI_STATUS scic_sds_stp_request_pio_data_out_await_data_transmit_completion_tc_completion_handler(
+
+ SCIC_SDS_REQUEST_T * this_request,
+ U32 completion_code
+)
+{
+ SCI_STATUS status = SCI_SUCCESS;
+ BOOL all_frames_transferred = FALSE;
+
+ SCIC_SDS_STP_REQUEST_T *this_scic_sds_stp_request = (SCIC_SDS_STP_REQUEST_T *) this_request;
+
+ SCIC_LOG_TRACE((
+ sci_base_object_get_logger(this_request),
+ SCIC_LOG_OBJECT_STP_IO_REQUEST,
+ "scic_sds_stp_request_pio_data_in_await_h2d_completion_tc_completion_handler(0x%x, 0x%x) enter\n",
+ this_request, completion_code
+ ));
+
+ 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 recieved
+ 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;
+}
+
+/**
+ * This method will handle any link layer events while waiting for the data
+ * frame.
+ *
+ * @param[in] request This is the request which is receiving the event.
+ * @param[in] event_code This is the event code that the request on which the
+ * request is expected to take action.
+ *
+ * @return SCI_STATUS
+ * @retval SCI_SUCCESS
+ * @retval SCI_FAILURE
+ */
+static
+SCI_STATUS scic_sds_stp_request_pio_data_in_await_data_event_handler(
+ SCIC_SDS_REQUEST_T * request,
+ U32 event_code
+)
+{
+ 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:
+ SCIC_LOG_ERROR((
+ sci_base_object_get_logger(request),
+ SCIC_LOG_OBJECT_STP_IO_REQUEST,
+ "SCIC PIO Request 0x%x received unexpected event 0x%08x\n",
+ request, event_code
+ ));
+
+ /// @todo Should we fail the PIO request when we get an unexpected event?
+ status = SCI_FAILURE;
+ break;
+ }
+
+ return status;
+}
+
+// ---------------------------------------------------------------------------
+
+SCIC_SDS_IO_REQUEST_STATE_HANDLER_T
+ scic_sds_stp_request_started_pio_substate_handler_table
+ [SCIC_SDS_STP_REQUEST_STARTED_PIO_MAX_SUBSTATES] =
+{
+ // SCIC_SDS_STP_REQUEST_STARTED_PIO_AWAIT_H2D_COMPLETION_SUBSTATE
+ {
+ {
+ scic_sds_request_default_start_handler,
+ scic_sds_request_started_state_abort_handler,
+ scic_sds_request_default_complete_handler,
+ scic_sds_request_default_destruct_handler
+ },
+ scic_sds_stp_request_pio_await_h2d_completion_tc_completion_handler,
+ scic_sds_request_default_event_handler,
+ scic_sds_request_default_frame_handler
+ },
+ // SCIC_SDS_STP_REQUEST_STARTED_PIO_AWAIT_FRAME_SUBSTATE
+ {
+ {
+ scic_sds_request_default_start_handler,
+ //scic_sds_stp_pio_request_data_in_await_frame_abort_handler,
+ scic_sds_request_started_state_abort_handler,
+ scic_sds_request_default_complete_handler,
+ scic_sds_request_default_destruct_handler
+ },
+ scic_sds_request_default_tc_completion_handler,
+ scic_sds_request_default_event_handler,
+ scic_sds_stp_request_pio_await_frame_frame_handler
+ },
+ // SCIC_SDS_STP_REQUEST_STARTED_PIO_DATA_IN_AWAIT_DATA_SUBSTATE
+ {
+ {
+ scic_sds_request_default_start_handler,
+ //scic_sds_stp_pio_request_data_in_await_data_abort_handler,
+ scic_sds_request_started_state_abort_handler,
+ scic_sds_request_default_complete_handler,
+ scic_sds_request_default_destruct_handler
+ },
+ scic_sds_request_default_tc_completion_handler,
+ scic_sds_stp_request_pio_data_in_await_data_event_handler,
+ scic_sds_stp_request_pio_data_in_await_data_frame_handler
+ },
+ //SCIC_SDS_STP_REQUEST_STARTED_PIO_DATA_OUT_TRANSMIT_DATA_SUBSTATE
+ {
+ {
+ scic_sds_request_default_start_handler,
+ scic_sds_request_started_state_abort_handler,
+ scic_sds_request_default_complete_handler,
+ scic_sds_request_default_destruct_handler
+ },
+ scic_sds_stp_request_pio_data_out_await_data_transmit_completion_tc_completion_handler,
+ scic_sds_request_default_event_handler,
+ scic_sds_request_default_frame_handler
+ }
+};
+
+static
+void scic_sds_stp_request_started_pio_await_h2d_completion_enter(
+ SCI_BASE_OBJECT_T *object
+)
+{
+ SCIC_SDS_REQUEST_T *this_request = (SCIC_SDS_REQUEST_T *)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(
+ SCI_BASE_OBJECT_T *object
+)
+{
+ SCIC_SDS_REQUEST_T *this_request = (SCIC_SDS_REQUEST_T *)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(
+ SCI_BASE_OBJECT_T *object
+)
+{
+ SCIC_SDS_REQUEST_T *this_request = (SCIC_SDS_REQUEST_T *)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(
+ SCI_BASE_OBJECT_T *object
+)
+{
+ SCIC_SDS_REQUEST_T *this_request = (SCIC_SDS_REQUEST_T *)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
+ );
+}
+
+// ---------------------------------------------------------------------------
+
+SCI_BASE_STATE_T
+ scic_sds_stp_request_started_pio_substate_table
+ [SCIC_SDS_STP_REQUEST_STARTED_PIO_MAX_SUBSTATES] =
+{
+ {
+ SCIC_SDS_STP_REQUEST_STARTED_PIO_AWAIT_H2D_COMPLETION_SUBSTATE,
+ scic_sds_stp_request_started_pio_await_h2d_completion_enter,
+ NULL
+ },
+ {
+ SCIC_SDS_STP_REQUEST_STARTED_PIO_AWAIT_FRAME_SUBSTATE,
+ scic_sds_stp_request_started_pio_await_frame_enter,
+ NULL
+ },
+ {
+ SCIC_SDS_STP_REQUEST_STARTED_PIO_DATA_IN_AWAIT_DATA_SUBSTATE,
+ scic_sds_stp_request_started_pio_data_in_await_data_enter,
+ NULL
+ },
+ {
+ SCIC_SDS_STP_REQUEST_STARTED_PIO_DATA_OUT_TRANSMIT_DATA_SUBSTATE,
+ scic_sds_stp_request_started_pio_data_out_transmit_data_enter,
+ NULL
+ }
+};
+
+//******************************************************************************
+//* UDMA REQUEST STATE MACHINE
+//******************************************************************************
+
+static
+void scic_sds_stp_request_udma_complete_request(
+ SCIC_SDS_REQUEST_T * this_request,
+ U32 scu_status,
+ 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
+ );
+}
+
+/**
+ *
+ *
+ * @param[in] this_request
+ * @param[in] frame_index
+ *
+ * @return SCI_STATUS
+ */
+static
+SCI_STATUS scic_sds_stp_request_udma_general_frame_handler(
+ SCIC_SDS_REQUEST_T * this_request,
+ U32 frame_index
+)
+{
+ SCI_STATUS status;
+ SATA_FIS_HEADER_T * frame_header;
+ U32 * frame_buffer;
+
+ SCIC_LOG_TRACE((
+ sci_base_object_get_logger(this_request),
+ SCIC_LOG_OBJECT_STP_IO_REQUEST,
+ "scic_sds_stp_pio_request_data_in_await_frame_frame_handler(0x%x, 0x%x) enter\n",
+ this_request, frame_index
+ ));
+
+ 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(
+ &((SCIC_SDS_STP_REQUEST_T *)this_request)->d2h_reg_fis,
+ (U32 *)frame_header,
+ frame_buffer
+ );
+ }
+
+ scic_sds_controller_release_frame(
+ this_request->owning_controller, frame_index);
+
+ return status;
+}
+
+/**
+ * @brief This method process TC completions while in the state where
+ * we are waiting for TC completions.
+ *
+ * @param[in] this_request
+ * @param[in] completion_code
+ *
+ * @return SCI_STATUS
+ */
+static
+SCI_STATUS scic_sds_stp_request_udma_await_tc_completion_tc_completion_handler(
+ SCIC_SDS_REQUEST_T * request,
+ U32 completion_code
+)
+{
+ SCI_STATUS status = SCI_SUCCESS;
+ SCIC_SDS_STP_REQUEST_T * this_request = (SCIC_SDS_STP_REQUEST_T *)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.
+ /// @todo We can retry the command for SCU_TASK_DONE_CMD_LL_R_ERR - this comes only for B0
+ 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_CMD_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_LOG_ERROR((
+ sci_base_object_get_logger(&this_request->parent),
+ SCIC_LOG_OBJECT_STP_IO_REQUEST,
+ "SCIC IO Request 0x%x returning CONTROLLER_SPECIFIC_IO_ERR for completion code 0x%x\n",
+ &this_request->parent, completion_code
+ ));
+ 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
+SCI_STATUS scic_sds_stp_request_udma_await_d2h_reg_fis_frame_handler(
+ SCIC_SDS_REQUEST_T * this_request,
+ U32 frame_index
+)
+{
+ 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;
+}
+
+// ---------------------------------------------------------------------------
+
+SCIC_SDS_IO_REQUEST_STATE_HANDLER_T
+ scic_sds_stp_request_started_udma_substate_handler_table
+ [SCIC_SDS_STP_REQUEST_STARTED_UDMA_MAX_SUBSTATES] =
+{
+ // SCIC_SDS_STP_REQUEST_STARTED_UDMA_AWAIT_TC_COMPLETION_SUBSTATE
+ {
+ {
+ scic_sds_request_default_start_handler,
+ scic_sds_request_started_state_abort_handler,
+ scic_sds_request_default_complete_handler,
+ scic_sds_request_default_destruct_handler
+ },
+ scic_sds_stp_request_udma_await_tc_completion_tc_completion_handler,
+ scic_sds_request_default_event_handler,
+ scic_sds_stp_request_udma_general_frame_handler
+ },
+ // SCIC_SDS_STP_REQUEST_STARTED_UDMA_AWAIT_D2H_REG_FIS_SUBSTATE
+ {
+ {
+ scic_sds_request_default_start_handler,
+ scic_sds_request_started_state_abort_handler,
+ scic_sds_request_default_complete_handler,
+ scic_sds_request_default_destruct_handler
+ },
+ scic_sds_request_default_tc_completion_handler,
+ scic_sds_request_default_event_handler,
+ scic_sds_stp_request_udma_await_d2h_reg_fis_frame_handler
+ }
+};
+
+/**
+ *
+ *
+ * @param[in] object
+ */
+static
+void scic_sds_stp_request_started_udma_await_tc_completion_enter(
+ SCI_BASE_OBJECT_T *object
+)
+{
+ SCIC_SDS_REQUEST_T *this_request = (SCIC_SDS_REQUEST_T *)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.
+ *
+ * @param[in] object
+ */
+static
+void scic_sds_stp_request_started_udma_await_d2h_reg_fis_enter(
+ SCI_BASE_OBJECT_T *object
+)
+{
+ SCIC_SDS_REQUEST_T *this_request = (SCIC_SDS_REQUEST_T *)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
+ );
+}
+
+// ---------------------------------------------------------------------------
+
+SCI_BASE_STATE_T
+ scic_sds_stp_request_started_udma_substate_table
+ [SCIC_SDS_STP_REQUEST_STARTED_UDMA_MAX_SUBSTATES] =
+{
+ {
+ SCIC_SDS_STP_REQUEST_STARTED_UDMA_AWAIT_TC_COMPLETION_SUBSTATE,
+ scic_sds_stp_request_started_udma_await_tc_completion_enter,
+ NULL
+ },
+ {
+ SCIC_SDS_STP_REQUEST_STARTED_UDMA_AWAIT_D2H_REG_FIS_SUBSTATE,
+ scic_sds_stp_request_started_udma_await_d2h_reg_fis_enter,
+ NULL
+ }
+};
+
+//******************************************************************************
+//* STP SOFT RESET STATE MACHINE
+//******************************************************************************
+
+/**
+ * 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.
+ *
+ * @param[in] this_request
+ * @param[in] completion_code
+ *
+ * @return This method always successfully processes the TC completion.
+ * @retval SCI_SUCCESS This value is always returned.
+ */
+static
+SCI_STATUS scic_sds_stp_request_soft_reset_await_h2d_asserted_tc_completion_handler(
+ SCIC_SDS_REQUEST_T * this_request,
+ U32 completion_code
+)
+{
+ SCIC_LOG_TRACE((
+ sci_base_object_get_logger(this_request),
+ SCIC_LOG_OBJECT_STP_IO_REQUEST,
+ "scic_sds_stp_request_soft_reset_await_h2d_tc_completion_handler(0x%x, 0x%x) enter\n",
+ this_request, 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 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.
+ *
+ * @param[in] this_request
+ * @param[in] completion_code
+ *
+ * @return This method always successfully processes the TC completion.
+ * @retval SCI_SUCCESS This value is always returned.
+ */
+static
+SCI_STATUS scic_sds_stp_request_soft_reset_await_h2d_diagnostic_tc_completion_handler(
+ SCIC_SDS_REQUEST_T * this_request,
+ U32 completion_code
+)
+{
+ SCIC_LOG_TRACE((
+ sci_base_object_get_logger(this_request),
+ SCIC_LOG_OBJECT_STP_IO_REQUEST,
+ "scic_sds_stp_request_soft_reset_await_h2d_tc_completion_handler(0x%x, 0x%x) enter\n",
+ this_request, 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;
+}
+
+/**
+ * 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.
+ *
+ * @param[in] request This parameter specifies the request for which a
+ * frame has been received.
+ * @param[in] frame_index This parameter specifies the index of the frame
+ * that has been received.
+ *
+ * @return Indicate if the received frame was processed successfully.
+ */
+static
+SCI_STATUS scic_sds_stp_request_soft_reset_await_d2h_frame_handler(
+ SCIC_SDS_REQUEST_T * request,
+ U32 frame_index
+)
+{
+ SCI_STATUS status;
+ SATA_FIS_HEADER_T * frame_header;
+ U32 * frame_buffer;
+ SCIC_SDS_STP_REQUEST_T * this_request = (SCIC_SDS_STP_REQUEST_T *)request;
+
+ // Save off the controller, so that we do not touch the request after it
+ // is completed.
+ SCIC_SDS_CONTROLLER_T * owning_controller = this_request->parent.owning_controller;
+
+ SCIC_LOG_TRACE((
+ sci_base_object_get_logger(this_request),
+ SCIC_LOG_OBJECT_STP_IO_REQUEST,
+ "scic_sds_stp_request_soft_reset_await_d2h_frame_handler(0x%x, 0x%x) enter\n",
+ this_request, frame_index
+ ));
+
+ status = scic_sds_unsolicited_frame_control_get_header(
+ &(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(
+ &(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:
+ SCIC_LOG_WARNING((
+ sci_base_object_get_logger(this_request),
+ SCIC_LOG_OBJECT_STP_IO_REQUEST,
+ "IO Request:0x%x Frame Id:%d protocol violation occurred\n",
+ 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(
+ owning_controller, frame_index
+ );
+ }
+ else
+ {
+ SCIC_LOG_ERROR((
+ sci_base_object_get_logger(this_request),
+ SCIC_LOG_OBJECT_STP_IO_REQUEST,
+ "SCIC IO Request 0x%x could not get frame header for frame index %d, status %x\n",
+ this_request, frame_index, status
+ ));
+ }
+
+ return status;
+}
+
+// ---------------------------------------------------------------------------
+
+SCIC_SDS_IO_REQUEST_STATE_HANDLER_T
+ scic_sds_stp_request_started_soft_reset_substate_handler_table
+ [SCIC_SDS_STP_REQUEST_STARTED_SOFT_RESET_MAX_SUBSTATES] =
+{
+ // SCIC_SDS_STP_REQUEST_STARTED_SOFT_RESET_AWAIT_H2D_ASSERTED_COMPLETION_SUBSTATE
+ {
+ {
+ scic_sds_request_default_start_handler,
+ scic_sds_request_started_state_abort_handler,
+ scic_sds_request_default_complete_handler,
+ scic_sds_request_default_destruct_handler
+ },
+ scic_sds_stp_request_soft_reset_await_h2d_asserted_tc_completion_handler,
+ scic_sds_request_default_event_handler,
+ scic_sds_request_default_frame_handler
+ },
+ // SCIC_SDS_STP_REQUEST_STARTED_SOFT_RESET_AWAIT_H2D_DIAGNOSTIC_COMPLETION_SUBSTATE
+ {
+ {
+ scic_sds_request_default_start_handler,
+ scic_sds_request_started_state_abort_handler,
+ scic_sds_request_default_complete_handler,
+ scic_sds_request_default_destruct_handler
+ },
+ scic_sds_stp_request_soft_reset_await_h2d_diagnostic_tc_completion_handler,
+ scic_sds_request_default_event_handler,
+ scic_sds_request_default_frame_handler
+ },
+ // SCIC_SDS_STP_REQUEST_STARTED_SOFT_RESET_AWAIT_D2H_RESPONSE_FRAME_SUBSTATE
+ {
+ {
+ scic_sds_request_default_start_handler,
+ scic_sds_request_started_state_abort_handler,
+ scic_sds_request_default_complete_handler,
+ scic_sds_request_default_destruct_handler
+ },
+ scic_sds_request_default_tc_completion_handler,
+ scic_sds_request_default_event_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(
+ SCI_BASE_OBJECT_T *object
+)
+{
+ SCIC_SDS_REQUEST_T *this_request = (SCIC_SDS_REQUEST_T *)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(
+ SCI_BASE_OBJECT_T *object
+)
+{
+ SCI_STATUS status;
+ SCIC_SDS_REQUEST_T *this_request = (SCIC_SDS_REQUEST_T *)object;
+ SATA_FIS_REG_H2D_T *h2d_fis;
+ SCU_TASK_CONTEXT_T *task_context;
+
+ // 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;
+
+ 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_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(
+ SCI_BASE_OBJECT_T *object
+)
+{
+ SCIC_SDS_REQUEST_T *this_request = (SCIC_SDS_REQUEST_T *)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
+ );
+}
+
+// ---------------------------------------------------------------------------
+
+SCI_BASE_STATE_T
+ scic_sds_stp_request_started_soft_reset_substate_table
+ [SCIC_SDS_STP_REQUEST_STARTED_SOFT_RESET_MAX_SUBSTATES] =
+{
+ {
+ SCIC_SDS_STP_REQUEST_STARTED_SOFT_RESET_AWAIT_H2D_ASSERTED_COMPLETION_SUBSTATE,
+ scic_sds_stp_request_started_soft_reset_await_h2d_asserted_completion_enter,
+ NULL
+ },
+ {
+ SCIC_SDS_STP_REQUEST_STARTED_SOFT_RESET_AWAIT_H2D_DIAGNOSTIC_COMPLETION_SUBSTATE,
+ scic_sds_stp_request_started_soft_reset_await_h2d_diagnostic_completion_enter,
+ NULL
+ },
+ {
+ SCIC_SDS_STP_REQUEST_STARTED_SOFT_RESET_AWAIT_D2H_RESPONSE_FRAME_SUBSTATE,
+ scic_sds_stp_request_started_soft_reset_await_d2h_response_enter,
+ NULL
+ }
+};
+
+// ---------------------------------------------------------------------------
+
+SCI_STATUS scic_io_request_construct_basic_sata(
+ SCI_IO_REQUEST_HANDLE_T scic_io_request
+)
+{
+ SCI_STATUS status;
+ SCIC_SDS_REQUEST_T * request = (SCIC_SDS_REQUEST_T *)scic_io_request;
+
+ SCIC_LOG_TRACE((
+ sci_base_object_get_logger(scic_io_request),
+ SCIC_LOG_OBJECT_STP_IO_REQUEST,
+ "scic_io_request_construct_basic_sata(0x%x) enter\n",
+ scic_io_request
+ ));
+
+ status = scic_sds_io_request_construct_sata(
+ request,
+ scic_cb_request_get_sat_protocol(request->user_request),
+ scic_cb_io_request_get_transfer_length(request->user_request),
+ scic_cb_io_request_get_data_direction(request->user_request),
+ scic_cb_io_request_do_copy_rx_frames(request->user_request),
+ TRUE
+ );
+
+ return status;
+}
+
+// ---------------------------------------------------------------------------
+
+SCI_STATUS scic_io_request_construct_advanced_sata(
+ SCI_IO_REQUEST_HANDLE_T scic_io_request,
+ SCIC_IO_SATA_PARAMETERS_T * io_parameters
+)
+{
+ SCI_STATUS status;
+ SCIC_SDS_REQUEST_T * request = (SCIC_SDS_REQUEST_T *)scic_io_request;
+
+ SCIC_LOG_TRACE((
+ sci_base_object_get_logger(scic_io_request),
+ SCIC_LOG_OBJECT_STP_IO_REQUEST,
+ "scic_io_request_construct_basic_sata(0x%x) enter\n",
+ scic_io_request
+ ));
+
+ status = scic_sds_io_request_construct_sata(
+ request,
+ scic_cb_request_get_sat_protocol(request->user_request),
+ scic_sds_request_get_sgl_element_pair(request, 0)->A.length,
+ scic_cb_io_request_get_data_direction(request->user_request),
+ scic_cb_io_request_do_copy_rx_frames(request->user_request),
+ io_parameters->do_translate_sgl
+ );
+
+ return status;
+}
+
diff --git a/sys/dev/isci/scil/scic_sds_stp_request.h b/sys/dev/isci/scil/scic_sds_stp_request.h
new file mode 100644
index 0000000..20b53ab
--- /dev/null
+++ b/sys/dev/isci/scil/scic_sds_stp_request.h
@@ -0,0 +1,280 @@
+/*-
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 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.
+ *
+ * $FreeBSD$
+ */
+#ifndef _SCIC_SDS_STP_REQUEST_T_
+#define _SCIC_SDS_STP_REQUEST_T_
+
+#ifdef __cplusplus
+extern "C" {
+#endif // __cplusplus
+
+#include <dev/isci/scil/intel_sata.h>
+#include <dev/isci/scil/sci_types.h>
+#include <dev/isci/scil/scic_sds_request.h>
+
+/**
+ * @struct
+ *
+ * @brief This structure represents the additional information that is
+ * required to handle SATA PIO requests.
+ */
+typedef struct SCIC_SDS_STP_REQUEST
+{
+ SCIC_SDS_REQUEST_T parent;
+
+ SATA_FIS_REG_D2H_T 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;
+
+ /**
+ * This field keeps track of sgl pair to be retrieved from OS memory for processing.
+ */
+ U8 sgl_pair_index;
+
+ struct
+ {
+ SCU_SGL_ELEMENT_PAIR_T * 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;
+
+} SCIC_SDS_STP_REQUEST_T;
+
+/**
+ * @enum SCIC_SDS_STP_REQUEST_STARTED_UDMA_SUBSTATES
+ *
+ * @brief 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,
+
+ SCIC_SDS_STP_REQUEST_STARTED_UDMA_MAX_SUBSTATES
+};
+
+/**
+ * @enum SCIC_SDS_STP_REQUEST_STARTED_NON_DATA_SUBSTATES
+ *
+ * @brief 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,
+ SCIC_SDS_STP_REQUEST_STARTED_NON_DATA_MAX_SUBSTATES
+};
+
+/**
+ * @enum SCIC_SDS_STP_REQUEST_STARTED_SOFT_RESET_SUBSTATES
+ *
+ * @brief 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,
+
+ SCIC_SDS_STP_REQUEST_STARTED_SOFT_RESET_MAX_SUBSTATES
+};
+
+extern SCIC_SDS_IO_REQUEST_STATE_HANDLER_T
+ scic_sds_stp_request_started_udma_substate_handler_table
+ [SCIC_SDS_STP_REQUEST_STARTED_UDMA_MAX_SUBSTATES];
+
+extern SCI_BASE_STATE_T
+ scic_sds_stp_request_started_udma_substate_table
+ [SCIC_SDS_STP_REQUEST_STARTED_UDMA_MAX_SUBSTATES];
+
+extern SCIC_SDS_IO_REQUEST_STATE_HANDLER_T
+ scic_sds_stp_request_started_non_data_substate_handler_table
+ [SCIC_SDS_STP_REQUEST_STARTED_NON_DATA_MAX_SUBSTATES];
+
+extern SCI_BASE_STATE_T
+ scic_sds_stp_request_started_non_data_substate_table
+ [SCIC_SDS_STP_REQUEST_STARTED_NON_DATA_MAX_SUBSTATES];
+
+
+extern SCIC_SDS_IO_REQUEST_STATE_HANDLER_T
+ scic_sds_stp_request_started_soft_reset_substate_handler_table
+ [SCIC_SDS_STP_REQUEST_STARTED_SOFT_RESET_MAX_SUBSTATES];
+
+extern SCI_BASE_STATE_T
+ scic_sds_stp_request_started_soft_reset_substate_table
+ [SCIC_SDS_STP_REQUEST_STARTED_SOFT_RESET_MAX_SUBSTATES];
+
+// ---------------------------------------------------------------------------
+
+U32 scic_sds_stp_request_get_object_size(void);
+
+U32 scic_sds_stp_task_request_get_object_size(void);
+
+void scu_sata_reqeust_construct_task_context(
+ SCIC_SDS_REQUEST_T * this_request,
+ SCU_TASK_CONTEXT_T * task_context
+);
+
+void scic_sds_stp_non_ncq_request_construct(
+ SCIC_SDS_REQUEST_T *this_request
+);
+
+SCI_STATUS scic_sds_stp_pio_request_construct(
+ SCIC_SDS_REQUEST_T * scic_io_request,
+ U8 sat_protocol,
+ BOOL copy_rx_frame
+);
+
+SCI_STATUS scic_sds_stp_pio_request_construct_pass_through (
+ SCIC_SDS_REQUEST_T * scic_io_request,
+ SCIC_STP_PASSTHRU_REQUEST_CALLBACKS_T *passthru_cb
+);
+
+SCI_STATUS scic_sds_stp_udma_request_construct(
+ SCIC_SDS_REQUEST_T * this_request,
+ U32 transfer_length,
+ SCI_IO_REQUEST_DATA_DIRECTION data_direction
+);
+
+SCI_STATUS scic_sds_stp_non_data_request_construct(
+ SCIC_SDS_REQUEST_T * this_request
+);
+
+SCI_STATUS scic_sds_stp_soft_reset_request_construct(
+ SCIC_SDS_REQUEST_T * this_request
+);
+
+SCI_STATUS scic_sds_stp_ncq_request_construct(
+ SCIC_SDS_REQUEST_T * this_request,
+ U32 transfer_length,
+ SCI_IO_REQUEST_DATA_DIRECTION data_direction
+);
+
+void scu_stp_raw_request_construct_task_context(
+ SCIC_SDS_STP_REQUEST_T * this_request,
+ SCU_TASK_CONTEXT_T * task_context
+
+);
+
+SCI_STATUS scic_sds_io_request_construct_sata(
+ SCIC_SDS_REQUEST_T * this_request,
+ U8 sat_protocol,
+ U32 transfer_length,
+ SCI_IO_REQUEST_DATA_DIRECTION data_direction,
+ BOOL copy_rx_frame,
+ BOOL do_translate_sgl
+);
+
+#ifdef __cplusplus
+}
+#endif // __cplusplus
+
+#endif // _SCIC_SDS_STP_REQUEST_T_
diff --git a/sys/dev/isci/scil/scic_sds_unsolicited_frame_control.c b/sys/dev/isci/scil/scic_sds_unsolicited_frame_control.c
new file mode 100644
index 0000000..2c79b77
--- /dev/null
+++ b/sys/dev/isci/scil/scic_sds_unsolicited_frame_control.c
@@ -0,0 +1,402 @@
+/*-
+ * 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.
+ *
+ * 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 <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/**
+ * @file
+ *
+ * @brief This file contains the implementation of the
+ * SCIC_SDS_UNSOLICITED_FRAME_CONTROL object and it's public,
+ * protected, and private methods.
+ */
+
+#include <dev/isci/scil/scic_sds_unsolicited_frame_control.h>
+#include <dev/isci/scil/scu_registers.h>
+#include <dev/isci/scil/scic_sds_controller.h>
+#include <dev/isci/scil/scic_user_callback.h>
+#include <dev/isci/scil/sci_util.h>
+
+/**
+ * @brief 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.
+ *
+ * @param[in,out] uf_control This parameter specifies the UF control
+ * object for which to update the address table count.
+ *
+ * @return none
+ */
+void scic_sds_unsolicited_frame_control_set_address_table_count(
+ SCIC_SDS_UNSOLICITED_FRAME_CONTROL_T *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;
+ }
+}
+
+/**
+ * @brief 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.
+ *
+ * @param[in,out] uf_control This parameter specifies the unsolicted
+ * frame control object for which to construct the
+ * unsolicited frames objects.
+ * @param[in] uf_buffer_phys_address This parameter specifies the
+ * physical address for the first unsolicited frame
+ * buffer.
+ * @param[in] uf_buffer_virt_address This parameter specifies the
+ * virtual address for the first unsolicited frame
+ * buffer.
+ * @param[in] 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.
+ * @param[in] used_uf_header_entries This parameter specifies
+ * the number of actually utilized UF headers.
+ *
+ * @return none
+ */
+static
+void scic_sds_unsolicited_frame_control_construct_frames(
+ SCIC_SDS_UNSOLICITED_FRAME_CONTROL_T *uf_control,
+ SCI_PHYSICAL_ADDRESS uf_buffer_phys_address,
+ POINTER_UINT uf_buffer_virt_address,
+ U32 unused_uf_header_entries,
+ U32 used_uf_header_entries
+)
+{
+ U32 index;
+ SCIC_SDS_UNSOLICITED_FRAME_T *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
+ );
+ }
+}
+
+/**
+ * @brief This method constructs the various members of the unsolicted
+ * frame control object (buffers, headers, address, table, etc).
+ *
+ * @param[in,out] uf_control This parameter specifies the unsolicited
+ * frame control object to construct.
+ * @param[in] mde This parameter specifies the memory descriptor
+ * from which to derive all of the address information
+ * needed to get the unsolicited frame functionality
+ * working.
+ * @param[in] controller This parameter specifies the controller
+ * object associated with the uf_control being constructed.
+ *
+ * @return none
+ */
+void scic_sds_unsolicited_frame_control_construct(
+ SCIC_SDS_UNSOLICITED_FRAME_CONTROL_T *uf_control,
+ SCI_PHYSICAL_MEMORY_DESCRIPTOR_T *mde,
+ SCIC_SDS_CONTROLLER_T *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;
+ SCI_PHYSICAL_ADDRESS 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(SCU_UNSOLICITED_FRAME_HEADER_T);
+ used_uf_header_bytes = used_uf_header_entries
+ * sizeof(SCU_UNSOLICITED_FRAME_HEADER_T);
+
+ // 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 = (SCU_UNSOLICITED_FRAME_HEADER_T*)
+ ((U8 *)mde->virtual_address + used_uf_buffer_bytes - unused_uf_header_bytes);
+
+ // 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 = (SCI_PHYSICAL_ADDRESS*)
+ ((U8 *)mde->virtual_address + used_uf_buffer_bytes + used_uf_header_bytes);
+
+ 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,
+ (POINTER_UINT) mde->virtual_address,
+ unused_uf_header_entries,
+ used_uf_header_entries
+ );
+}
+
+/**
+ * @brief This method returns the frame header for the specified frame
+ * index.
+ *
+ * @param[in] uf_control
+ * @param[in] frame_index
+ * @param[out] frame_header
+ *
+ * @return SCI_STATUS
+ */
+SCI_STATUS scic_sds_unsolicited_frame_control_get_header(
+ SCIC_SDS_UNSOLICITED_FRAME_CONTROL_T *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;
+}
+
+/**
+ * @brief This method returns the frame buffer for the specified frame
+ * index.
+ *
+ * @param[in] uf_control
+ * @param[in] frame_index
+ * @param[out] frame_buffer
+ *
+ * @return SCI_STATUS
+ */
+SCI_STATUS scic_sds_unsolicited_frame_control_get_buffer(
+ SCIC_SDS_UNSOLICITED_FRAME_CONTROL_T *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;
+}
+
+/**
+ * @brief 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.
+ *
+ * @param[in] uf_control This parameter specifies the UF control object
+ * @param[in] frame_index This parameter specifies the frame index to
+ * attempt to release.
+ *
+ * @return This method returns an indication to the caller as to whether
+ * the unsolicited frame get pointer should be updated.
+ * @retval TRUE This value indicates the unsolicited frame get pointer
+ * should be updated (i.e. write SCU_UFQGP_WRITE).
+ * @retval FALSE This value indicates the get pointer should not be
+ * updated.
+ */
+BOOL scic_sds_unsolicited_frame_control_release_frame(
+ SCIC_SDS_UNSOLICITED_FRAME_CONTROL_T *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 (
+ (
+ (sci_cb_physical_address_lower(
+ uf_control->address_table.array[frame_get]) == 0)
+ && (sci_cb_physical_address_upper(
+ 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.
+ ASSERT(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/sys/dev/isci/scil/scic_sds_unsolicited_frame_control.h b/sys/dev/isci/scil/scic_sds_unsolicited_frame_control.h
new file mode 100644
index 0000000..a05572d
--- /dev/null
+++ b/sys/dev/isci/scil/scic_sds_unsolicited_frame_control.h
@@ -0,0 +1,305 @@
+/*-
+ * 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.
+ *
+ * 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.
+ *
+ * $FreeBSD$
+ */
+/**
+ * @file
+ *
+ * @brief 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_
+
+#ifdef __cplusplus
+extern "C" {
+#endif // __cplusplus
+
+#include <dev/isci/types.h>
+#include <dev/isci/scil/scu_unsolicited_frame.h>
+#include <dev/isci/scil/sci_memory_descriptor_list.h>
+#include <dev/isci/scil/scu_constants.h>
+#include <dev/isci/scil/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.
+ */
+typedef 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.
+ */
+ SCU_UNSOLICITED_FRAME_HEADER_T *header;
+
+ /**
+ * This field points to the frame buffer data.
+ */
+ void *buffer;
+
+} SCIC_SDS_UNSOLICITED_FRAME_T;
+
+/**
+ * @struct SCIC_SDS_UF_HEADER_ARRAY
+ *
+ * This structure contains all of the unsolicited frame header
+ * information.
+ */
+typedef 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.
+ */
+ SCU_UNSOLICITED_FRAME_HEADER_T *array;
+
+ /**
+ * This field specifies the physical address location for the UF
+ * buffer array.
+ */
+ SCI_PHYSICAL_ADDRESS physical_address;
+
+} SCIC_SDS_UF_HEADER_ARRAY_T;
+
+// 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.
+ */
+typedef 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.
+ */
+ SCIC_SDS_UNSOLICITED_FRAME_T array[SCU_UNSOLICITED_FRAME_CONTROL_ARRAY_SIZE];
+
+ /**
+ * This field specifies the physical address location for the UF
+ * buffer array.
+ */
+ SCI_PHYSICAL_ADDRESS physical_address;
+
+} SCIC_SDS_UF_BUFFER_ARRAY_T;
+
+/**
+ * @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.
+ */
+typedef 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.
+ */
+ SCI_PHYSICAL_ADDRESS * array;
+
+ /**
+ * This field specifies the physical address location for the UF
+ * address table.
+ */
+ SCI_PHYSICAL_ADDRESS physical_address;
+
+} SCIC_SDS_UF_ADDRESS_TABLE_ARRAY_T;
+
+/**
+ * @struct SCIC_SDS_UNSOLICITED_FRAME_CONTROL
+ *
+ * This object contains all of the data necessary to handle
+ * unsolicited frames.
+ */
+typedef 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.
+ */
+ SCIC_SDS_UF_HEADER_ARRAY_T headers;
+
+ /**
+ * This field contains all of the unsolicited frame buffer
+ * specific fields.
+ */
+ SCIC_SDS_UF_BUFFER_ARRAY_T buffers;
+
+ /**
+ * This field contains all of the unsolicited frame address table
+ * specific fields.
+ */
+ SCIC_SDS_UF_ADDRESS_TABLE_ARRAY_T address_table;
+
+} SCIC_SDS_UNSOLICITED_FRAME_CONTROL_T;
+
+void scic_sds_unsolicited_frame_control_set_address_table_count(
+ SCIC_SDS_UNSOLICITED_FRAME_CONTROL_T *uf_control
+);
+
+struct SCIC_SDS_CONTROLLER;
+void scic_sds_unsolicited_frame_control_construct(
+ SCIC_SDS_UNSOLICITED_FRAME_CONTROL_T *uf_control,
+ SCI_PHYSICAL_MEMORY_DESCRIPTOR_T *mde,
+ struct SCIC_SDS_CONTROLLER *this_controller
+);
+
+SCI_STATUS scic_sds_unsolicited_frame_control_get_header(
+ SCIC_SDS_UNSOLICITED_FRAME_CONTROL_T *uf_control,
+ U32 frame_index,
+ void **frame_header
+);
+
+SCI_STATUS scic_sds_unsolicited_frame_control_get_buffer(
+ SCIC_SDS_UNSOLICITED_FRAME_CONTROL_T *uf_control,
+ U32 frame_index,
+ void **frame_buffer
+);
+
+BOOL scic_sds_unsolicited_frame_control_release_frame(
+ SCIC_SDS_UNSOLICITED_FRAME_CONTROL_T *uf_control,
+ U32 frame_index
+);
+
+/**
+ * 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(SCI_PHYSICAL_ADDRESS)) \
+ + ((uf_control).buffers.count * sizeof(SCU_UNSOLICITED_FRAME_HEADER_T)) )
+
+#ifdef __cplusplus
+}
+#endif // __cplusplus
+
+#endif // _SCIC_SDS_UNSOLICITED_FRAME_CONTROL_H_
diff --git a/sys/dev/isci/scil/scic_sgpio.h b/sys/dev/isci/scil/scic_sgpio.h
new file mode 100644
index 0000000..4fc5197
--- /dev/null
+++ b/sys/dev/isci/scil/scic_sgpio.h
@@ -0,0 +1,299 @@
+/*-
+ * 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.
+ *
+ * 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.
+ *
+ * $FreeBSD$
+ */
+#ifndef _SCIC_SGPIO_H_
+#define _SCIC_SGPIO_H_
+
+/**
+* @file
+*
+* @brief This file contains all of the interface methods that can be called
+* by an SCI user on an Serialized General Purpose IO (SGPIO) object.
+*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif // __cplusplus
+
+#include <dev/isci/scil/sci_types.h>
+
+//Programmable Blink Pattern Durations
+#define SGPIO_BLINK_DURATION_125 0x0
+#define SGPIO_BLINK_DURATION_250 0x1
+#define SGPIO_BLINK_DURATION_375 0x2
+#define SGPIO_BLINK_DURATION_500 0x3
+#define SGPIO_BLINK_DURATION_625 0x4
+#define SGPIO_BLINK_DURATION_750 0x5
+#define SGPIO_BLINK_DURATION_875 0x6
+#define SGPIO_BLINK_DURATION_1000 0x7
+#define SGPIO_BLINK_DURATION_1250 0x8
+#define SGPIO_BLINK_DURATION_1375 0x9
+#define SGPIO_BLINK_DURATION_1500 0xA
+#define SGPIO_BLINK_DURATION_1625 0xB
+#define SGPIO_BLINK_DURATION_1750 0xC
+#define SGPIO_BLINK_DURATION_1875 0xD
+#define SGPIO_BLINK_DURATION_2000 0xF
+
+#define ENABLE_SGPIO_FUNCTIONALITY 1
+#define DISABLE_SGPIO_FUNCTIONALITY 0
+
+#define SGPIO_HARDWARE_CONTROL 0x00000443
+#define SGPIO_SOFTWARE_CONTROL 0x00000444
+
+#define PHY_0_MASK 0x01
+#define PHY_1_MASK 0x02
+#define PHY_2_MASK 0x04
+#define PHY_3_MASK 0x08
+
+#define SGODSR_INVERT_BIT 0x4
+
+#define SGODSR_ERROR_LED_SHIFT 8
+#define SGODSR_LOCATE_LED_SHIFT 4
+#define SGODSR_ACTIVITY_LED_SHIFT 0
+
+#define SGPIO_BLINK_PATTERN_A 0x1
+#define SGPIO_BLINK_PATTERN_B 0x2
+
+/**
+* @brief This will set the vendor specific code in the SGPIO Vendor Specific Code
+* register that is sent on the sLoad wire at the start of each
+* bit stream.
+*
+* @param[in] SCI_CONTROLLER_HANDLE_T controller
+* @param]in] vendor_specific_sequence - Vendor specific sequence set in the
+* SGVSCR register.
+*
+*/
+void scic_sgpio_set_vendor_code(
+ SCI_CONTROLLER_HANDLE_T controller,
+ U8 vendor_specific_sequence
+);
+
+/**
+* @brief Use this to set both programmable blink patterns A & B in the
+* SGPBR(Programmable Blink Register). Will set identical patterns
+* on both SGPIO units.
+*
+* @param[in] SCI_CONTROLLER_HANDLE_T controller
+* @param[in] pattern_a_high - High(LED on) duration time for pattern A
+* @param[in] pattern_a_low - Low(LED off) duration time for pattern A
+* @param[in] pattern_b_high - High(LED on) duration time for pattern B
+* @param[in] pattern_b_low - Low(LED off) duration time for pattern B
+*
+*/
+void scic_sgpio_set_blink_patterns(
+ SCI_CONTROLLER_HANDLE_T controller,
+ U8 pattern_a_low,
+ U8 pattern_a_high,
+ U8 pattern_b_low,
+ U8 pattern_b_high
+);
+
+
+/**
+* @brief This will set the functionality enable bit in the SGPIO interface
+* control register, when set the bus pins will be used for SGPIO
+* signaling, if not the bus pins are used for direct led control.
+*
+* @param[in] SCI_CONTROLLER_HANDLE_T controller
+* @param[in] BOOL sgpio_mode - indication for SGPIO signaling.
+*
+*/
+void scic_sgpio_set_functionality(
+ SCI_CONTROLLER_HANDLE_T controller,
+ BOOL sgpio_mode
+);
+
+/**
+ * @brief Communicates with hardware to set the blink pattern
+ * of the error, locate, and activity LED's for phys
+ * specified by the phy_mask parameter.
+ * Function intend to be used to LEDs management
+ * in non-inteligent backplanes.
+ *
+ * @param[in] SCI_CONTROLLER_HANDLE_T controller
+ * @param[in] phy_mask - This field is a bit mask that specifies the phys
+ * to be updated.
+ * @param[in] error - If TRUE, apply pattern for the error LED
+ * @param[in] locate - If TRUE, apply pattern for the locate LED
+ * @param[in] activity - If TRUE, apply pattern for the activity LED
+ * @param[in] pattern_selection - One of two patterns (A or B).
+ * "A" and "B" patterns should be previously defined
+ * by scic_sgpio_set_blink_patterns()
+ *
+ * @return none
+ */
+void scic_sgpio_apply_led_blink_pattern(
+ SCI_CONTROLLER_HANDLE_T controller,
+ U32 phy_mask,
+ BOOL error,
+ BOOL locate,
+ BOOL activity,
+ U8 pattern_selection
+);
+
+/**
+ * @brief Communicates with hardware to set the blink pattern
+ * of the error, locate, and activity LED's for all
+ * phys in the port. Function intend to be used to LEDs
+ * management in non-inteligent backplanes.
+ *
+ * @param[in] SCI_CONTROLLER_HANDLE_T controller
+ * @param[in] port_handle - port handle is used to identify SGPIO bay
+ * @param[in] error - If TRUE, apply pattern for the error LED
+ * @param[in] locate - If TRUE, apply pattern for the locate LED
+ * @param[in] activity - If TRUE, apply pattern for the activity LED
+ * @param[in] pattern_selection - One of two patterns (A or B).
+ * "A" and "B" patterns should be previously defined
+ * by scic_sgpio_set_blink_patterns()
+ *
+ * @return none
+ */
+void scic_sgpio_set_led_blink_pattern(
+ SCI_CONTROLLER_HANDLE_T controller,
+ SCI_PORT_HANDLE_T port_handle,
+ BOOL error,
+ BOOL locate,
+ BOOL activity,
+ U8 pattern_selection
+);
+
+/**
+ * @brief Communicates with hardware to set the state of the error, locate,
+ * and activity LED's.
+ *
+ * @param[in] SCI_CONTROLLER_HANDLE_T controller
+ * @param[in] phy_mask - This field is a bit mask that specifies the phys
+ * to be updated.
+ * @param[in] error - State to be set for the error LED
+ * @param[in] locate - State to be set for the locate LED
+ * @param[in] activity - State to be set for the activity LED
+ *
+ * @return none
+ */
+void scic_sgpio_update_led_state(
+ SCI_CONTROLLER_HANDLE_T controller,
+ U32 phy_mask,
+ BOOL error,
+ BOOL locate,
+ BOOL activity
+);
+
+/**
+ * @brief Communicates with hardware to set the state of the error, locate,
+ * and activity LED's for all phys in the port.
+ *
+ * @param[in] SCI_CONTROLLER_HANDLE_T controller
+ * @param[in] port_handle - port handle is used to identify SGPIO bay
+ * @param[in] error - State to be set for the error LED
+ * @param[in] locate - State to be set for the locate LED
+ * @param[in] activity - State to be set for the activity LED
+ *
+ * @return none
+ */
+void scic_sgpio_set_led_state(
+ SCI_CONTROLLER_HANDLE_T controller,
+ SCI_PORT_HANDLE_T port_handle,
+ BOOL error,
+ BOOL locate,
+ BOOL activity
+);
+
+/**
+ * @brief This will set all Activity LED's to hardware controlled
+ *
+ * @param[in] BOOL is_hardware_controlled - indication for the Activity LED's
+ * to be hardware controlled or driver controlled.
+ * @return none
+ */
+void scic_sgpio_set_to_hardware_control(
+ SCI_CONTROLLER_HANDLE_T controller,
+ BOOL is_hardware_controlled
+);
+
+/**
+ * @brief Reads and returns the data-in from the SGPIO port for the specified controller.
+ * Bits 00:02 - Drive 0 input data
+ * Bits 04:06 - Drive 1 input data
+ * Bits 08:10 - Drive 2 input data
+ * Bits 12:14 - Drive 3 input data
+ *
+ * @param[in] SCI_CONTROLLER_HANDLE_T controller
+ * @return U32 - Value read from SGPIO, 0xffffffff indicates hardware not readable
+ */
+U32 scic_sgpio_read(
+ SCI_CONTROLLER_HANDLE_T controller
+);
+
+/**
+ * @brief Initializes the SCU for Hardware SGPIO LED control.
+ *
+ * @param[in] SCI_CONTROLLER_HANDLE_T controller
+ */
+void scic_sgpio_hardware_initialize(
+ SCI_CONTROLLER_HANDLE_T controller
+);
+/**
+* @brief Initializes the SCU for Software SGPIO signaling of LED control.
+*
+* @param[in] SCI_CONTROLLER_HANDLE_T controller
+*/
+void scic_sgpio_initialize(
+ SCI_CONTROLLER_HANDLE_T controller
+);
+
+#ifdef __cplusplus
+}
+#endif // __cplusplus
+
+#endif // _SCIC_SGPIO_H_
diff --git a/sys/dev/isci/scil/scic_task_request.h b/sys/dev/isci/scil/scic_task_request.h
new file mode 100644
index 0000000..41f57fc
--- /dev/null
+++ b/sys/dev/isci/scil/scic_task_request.h
@@ -0,0 +1,181 @@
+/*-
+ * 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.
+ *
+ * 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.
+ *
+ * $FreeBSD$
+ */
+#ifndef _SCIC_TASK_REQUEST_H_
+#define _SCIC_TASK_REQUEST_H_
+
+/**
+ * @file
+ *
+ * @brief This file contains the structures and interface methods that
+ * can be referenced and used by the SCI user for to utilize
+ * task management requests.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif // __cplusplus
+
+#include <dev/isci/scil/sci_types.h>
+#include <dev/isci/scil/sci_status.h>
+
+#if !defined(DISABLE_TASK_MANAGEMENT)
+
+/**
+ * @brief This method simply returns the size required to build an SCI
+ * based task managment request object.
+ *
+ * @return Return the size of the SCIC task request object.
+ */
+U32 scic_task_request_get_object_size(
+ void
+);
+
+/**
+ * @brief 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.
+ *
+ * @note The SCI core implementation will create an association between
+ * the user task request object and the core task request object.
+ *
+ * @param[in] scic_controller the handle to the core controller object
+ * for which to build the task managmement request.
+ * @param[in] 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.
+ * @param[in] 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.
+ * @param[in] 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.
+ * @param[in] scic_task_request_memory This parameter specifies the memory
+ * location to be utilized when building the core request.
+ * @param[out] 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.
+ *
+ * @return Indicate if the controller successfully built the task request.
+ * @retval SCI_SUCCESS This value is returned if the task request was
+ * successfully built.
+ */
+SCI_STATUS scic_task_request_construct(
+ SCI_CONTROLLER_HANDLE_T scic_controller,
+ SCI_REMOTE_DEVICE_HANDLE_T scic_remote_device,
+ U16 io_tag,
+ void * user_task_request_object,
+ void * scic_task_request_memory,
+ SCI_TASK_REQUEST_HANDLE_T * new_scic_task_request_handle
+);
+
+/**
+ * @brief 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.
+ *
+ * @param[out] scic_task_request This parameter specifies the handle
+ * to the core task request object for which to construct
+ * a SATA specific task management request.
+ *
+ * @return Indicate if the controller successfully built the task request.
+ * @retval SCI_SUCCESS This value is returned if the task request was
+ * successfully built.
+ */
+SCI_STATUS scic_task_request_construct_ssp(
+ SCI_TASK_REQUEST_HANDLE_T scic_task_request
+);
+
+/**
+ * @brief 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.
+ *
+ * @param[out] 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.
+ *
+ * @return Indicate if the controller successfully built the task request.
+ * @retval SCI_SUCCESS This value is returned if the task request was
+ * successfully built.
+ */
+SCI_STATUS scic_task_request_construct_sata(
+ SCI_TASK_REQUEST_HANDLE_T scic_task_request_handle
+);
+
+#else // !defined(DISABLE_TASK_MANAGEMENT)
+
+#define scic_task_request_get_object_size() 0
+#define scic_task_request_construct(controller, dev, tag, task, mem, handle) \
+ SCI_FAILURE
+#define scic_task_request_construct_ssp(task) SCI_FAILURE
+#define scic_task_request_construct_sata(task) SCI_FAILURE
+
+#endif // !defined(DISABLE_TASK_MANAGEMENT)
+
+#ifdef __cplusplus
+}
+#endif // __cplusplus
+
+#endif // _SCIC_TASK_REQUEST_H_
+
diff --git a/sys/dev/isci/scil/scic_user_callback.h b/sys/dev/isci/scil/scic_user_callback.h
new file mode 100644
index 0000000..c8f2bdc
--- /dev/null
+++ b/sys/dev/isci/scil/scic_user_callback.h
@@ -0,0 +1,1146 @@
+/*-
+ * 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.
+ *
+ * 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.
+ *
+ * $FreeBSD$
+ */
+#ifndef _SCIC_USER_CALLBACK_H_
+#define _SCIC_USER_CALLBACK_H_
+
+/**
+ * @file
+ *
+ * @brief This file contains all of the interface methods/macros that must
+ * be implemented by an SCI Core user.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif // __cplusplus
+
+#include <dev/isci/scil/sci_types.h>
+#include <dev/isci/scil/sci_status.h>
+#include <dev/isci/scil/sci_controller.h>
+
+/**
+ * @brief This callback method asks the user to create a timer and provide
+ * a handle for this timer for use in further timer interactions.
+ *
+ * @warning 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()).
+ *
+ * @param[in] controller This parameter specifies the controller with
+ * which this timer is to be associated.
+ * @param[in] timer_callback This parameter specifies the callback method
+ * to be invoked whenever the timer expires.
+ * @param[in] 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.
+ *
+ * @return 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(
+ SCI_CONTROLLER_HANDLE_T controller,
+ SCI_TIMER_CALLBACK_T timer_callback,
+ void * cookie
+);
+
+/**
+ * @brief This callback method asks the user to destory the supplied timer.
+ *
+ * @param[in] controller This parameter specifies the controller with
+ * which this timer is to associated.
+ * @param[in] timer This parameter specifies the timer to be destroyed.
+ *
+ * @return none
+ */
+void scic_cb_timer_destroy(
+ SCI_CONTROLLER_HANDLE_T controller,
+ void * timer
+);
+
+/**
+ * @brief This callback method asks the user to start the supplied timer.
+ *
+ * @warning 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.
+ *
+ * @param[in] controller This parameter specifies the controller with
+ * which this timer is to associated.
+ * @param[in] timer This parameter specifies the timer to be started.
+ * @param[in] 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.
+ *
+ * @return none
+ */
+void scic_cb_timer_start(
+ SCI_CONTROLLER_HANDLE_T controller,
+ void * timer,
+ U32 milliseconds
+);
+
+/**
+ * @brief This callback method asks the user to stop the supplied timer.
+ *
+ * @param[in] controller This parameter specifies the controller with
+ * which this timer is to associated.
+ * @param[in] timer This parameter specifies the timer to be stopped.
+ *
+ * @return none
+ */
+void scic_cb_timer_stop(
+ SCI_CONTROLLER_HANDLE_T controller,
+ void * timer
+);
+
+/**
+ * @brief 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.
+ *
+ * @param[in] 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.
+ *
+ * @return none.
+ */
+void scic_cb_stall_execution(
+ U32 microseconds
+);
+
+/**
+ * @brief This user callback will inform the user that the controller has
+ * finished the start process.
+ *
+ * @param[in] controller This parameter specifies the controller that was
+ * started.
+ * @param[in] completion_status This parameter specifies the results of
+ * the start operation. SCI_SUCCESS indicates successful
+ * completion.
+ *
+ * @return none
+ */
+void scic_cb_controller_start_complete(
+ SCI_CONTROLLER_HANDLE_T controller,
+ SCI_STATUS completion_status
+);
+
+/**
+ * @brief This user callback will inform the user that the controller has
+ * finished the stop process.
+ *
+ * @param[in] controller This parameter specifies the controller that was
+ * stopped.
+ * @param[in] completion_status This parameter specifies the results of
+ * the stop operation. SCI_SUCCESS indicates successful
+ * completion.
+ *
+ * @return none
+ */
+void scic_cb_controller_stop_complete(
+ SCI_CONTROLLER_HANDLE_T controller,
+ SCI_STATUS completion_status
+);
+
+/**
+ * @brief This user callback will inform the user that an IO request has
+ * completed.
+ *
+ * @param[in] controller This parameter specifies the controller on
+ * which the IO is completing.
+ * @param[in] remote_device This parameter specifies the remote device on
+ * which this IO request is completing.
+ * @param[in] io_request This parameter specifies the IO request that has
+ * completed.
+ * @param[in] completion_status This parameter specifies the results of
+ * the IO request operation. SCI_SUCCESS indicates successful
+ * completion.
+ *
+ * @return none
+ */
+void scic_cb_io_request_complete(
+ SCI_CONTROLLER_HANDLE_T controller,
+ SCI_REMOTE_DEVICE_HANDLE_T remote_device,
+ SCI_IO_REQUEST_HANDLE_T io_request,
+ SCI_IO_STATUS completion_status
+);
+
+/**
+ * @brief This method simply returns the virtual address associated
+ * with the scsi_io and byte_offset supplied parameters.
+ *
+ * @note This callback is not utilized in the fast path. The expectation
+ * is that this method is utilized for items such as SCSI to ATA
+ * translation for commands like INQUIRY, READ CAPACITY, etc.
+ *
+ * @param[in] 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.
+ * @param[in] byte_offset This parameter specifies the offset into the data
+ * buffers pointed to by the SGL. The byte offset starts at 0
+ * and continues until the last byte pointed to be the last SGL
+ * element.
+ *
+ * @return A virtual address pointer to the location specified by the
+ * parameters.
+ */
+U8 *scic_cb_io_request_get_virtual_address_from_sgl(
+ void * scic_user_io_request,
+ U32 byte_offset
+);
+
+/**
+ * @brief This user callback will inform the user that a task management
+ * request completed.
+ *
+ * @param[in] controller This parameter specifies the controller on
+ * which the task management request is completing.
+ * @param[in] remote_device This parameter specifies the remote device on
+ * which this task management request is completing.
+ * @param[in] task_request This parameter specifies the task management
+ * request that has completed.
+ * @param[in] completion_status This parameter specifies the results of
+ * the IO request operation. SCI_SUCCESS indicates successful
+ * completion.
+ *
+ * @return none
+ */
+void scic_cb_task_request_complete(
+ SCI_CONTROLLER_HANDLE_T controller,
+ SCI_REMOTE_DEVICE_HANDLE_T remote_device,
+ SCI_TASK_REQUEST_HANDLE_T task_request,
+ SCI_TASK_STATUS completion_status
+);
+
+#ifndef SCI_GET_PHYSICAL_ADDRESS_OPTIMIZATION_ENABLED
+/**
+ * @brief This callback method asks the user to provide the physical
+ * address for the supplied virtual address when building an
+ * io request object.
+ *
+ * @param[in] controller This parameter is the core controller object
+ * handle.
+ * @param[in] io_request This parameter is the io request object handle
+ * for which the physical address is being requested.
+ * @param[in] virtual_address This paramter is the virtual address which
+ * is to be returned as a physical address.
+ * @param[out] physical_address The physical address for the supplied virtual
+ * address.
+ *
+ * @return None.
+ */
+void scic_cb_io_request_get_physical_address(
+ SCI_CONTROLLER_HANDLE_T controller,
+ SCI_IO_REQUEST_HANDLE_T io_request,
+ void * virtual_address,
+ SCI_PHYSICAL_ADDRESS * physical_address
+);
+#endif // SCI_GET_PHYSICAL_ADDRESS_OPTIMIZATION_ENABLED
+
+/**
+ * @brief This callback method asks the user to provide the number of
+ * bytes to be transfered as part of this request.
+ *
+ * @param[in] 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.
+ *
+ * @return 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
+);
+
+/**
+ * @brief This callback method asks the user to provide the data direction
+ * for this request.
+ *
+ * @param[in] 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.
+ *
+ * @return 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
+);
+
+#ifdef ENABLE_OSSL_COPY_BUFFER
+/**
+ * @brief This method is presently utilized in the PIO path,
+ * copies from UF buffer to the SGL buffer. This method
+ * can be served for other OS related copies.
+ *
+ * @param[in] 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.
+ * @param[in] source addr. Address of UF buffer.
+ * @param[in] offset. This parameter specifies the offset into the data
+ * buffers pointed to by the SGL. The byte offset starts at 0
+ * and continues until the last byte pointed to be the last SGL
+ * element.
+ * @param[in] length. data length
+ *
+ * @return None
+ */
+void scic_cb_io_request_copy_buffer(
+ void * scic_user_io_request,
+ U8 *source_addr,
+ U32 offset,
+ U32 length
+);
+#endif
+
+#ifndef SCI_SGL_OPTIMIZATION_ENABLED
+/**
+ * @brief 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.
+ *
+ * @param[in] 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.
+ * @param[in] current_sge_address This parameter specifies the address for
+ * the current SGE (i.e. the one that has just processed).
+ * @param[out] next_sge An address specifying the location for the next
+ * scatter gather element to be processed.
+ *
+ * @return 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
+
+/**
+ * @brief This callback method asks the user to provide the contents of the
+ * "address" field in the Scatter-Gather Element.
+ *
+ * @param[in] 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.
+ * @param[in] sge_address This parameter specifies the address for the
+ * SGE from which to retrieve the address field.
+ *
+ * @return A physical address specifying the contents of the SGE's address
+ * field.
+ */
+SCI_PHYSICAL_ADDRESS scic_cb_sge_get_address_field(
+ void * scic_user_io_request,
+ void * sge_address
+);
+
+/**
+ * @brief This callback method asks the user to provide the contents of the
+ * "length" field in the Scatter-Gather Element.
+ *
+ * @param[in] 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.
+ * @param[in] sge_address This parameter specifies the address for the
+ * SGE from which to retrieve the address field.
+ *
+ * @return 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
+);
+
+/**
+ * @brief This callback method asks the user to provide the address for
+ * the command descriptor block (CDB) associated with this IO request.
+ *
+ * @param[in] 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.
+ *
+ * @return This method returns the virtual address of the CDB.
+ */
+void * scic_cb_ssp_io_request_get_cdb_address(
+ void * scic_user_io_request
+);
+
+/**
+ * @brief This callback method asks the user to provide the length of
+ * the command descriptor block (CDB) associated with this IO request.
+ *
+ * @param[in] 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.
+ *
+ * @return This method returns the length of the CDB.
+ */
+U32 scic_cb_ssp_io_request_get_cdb_length(
+ void * scic_user_io_request
+);
+
+/**
+ * @brief This callback method asks the user to provide the Logical Unit (LUN)
+ * associated with this IO request.
+ *
+ * @note 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.
+ *
+ * @param[in] 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.
+ *
+ * @return This method returns the LUN associated with this request.
+ * @todo This should be U64?
+ */
+U32 scic_cb_ssp_io_request_get_lun(
+ void * scic_user_io_request
+);
+
+/**
+ * @brief This callback method asks the user to provide the task attribute
+ * associated with this IO request.
+ *
+ * @note 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.
+ *
+ * @param[in] 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.
+ *
+ * @return 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
+);
+
+/**
+ * @brief This callback method asks the user to provide the command priority
+ * associated with this IO request.
+ *
+ * @note 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.
+ *
+ * @param[in] 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.
+ *
+ * @return 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
+);
+
+/**
+ * @brief 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().
+ *
+ * @param[in] 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.
+ *
+ * @return 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
+);
+
+/**
+ * @brief 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.
+ *
+ * @param[in] 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.
+ *
+ * @return 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
+);
+
+/**
+ * @brief This callback method asks the user to indicate if the IO is initially
+ * constructed or is reconstructed using the recycled memory.
+ *
+ * @param[in] 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.
+ *
+ * @return This method returns TRUE if the request is initial constructed.
+ * This method returns FALSE if the request is constructed using recycled
+ * memory. For many scic user, this method mostly always returns TRUE.
+ */
+BOOL scic_cb_request_is_initial_construction(
+ void * scic_user_io_request
+);
+
+/**
+ * @brief This method returns the Logical Unit to be utilized for this
+ * task management request.
+ *
+ * @note 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.
+ *
+ * @param[in] 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.
+ *
+ * @return This method returns the LUN associated with this request.
+ * @todo This should be U64?
+ */
+U32 scic_cb_ssp_task_request_get_lun(
+ void * scic_user_task_request
+);
+
+/**
+ * @brief This method returns the task management function to be utilized
+ * for this task request.
+ *
+ * @note 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.
+ *
+ * @param[in] 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.
+ *
+ * @return 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
+);
+
+/**
+ * @brief 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.
+ *
+ * @param[in] 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.
+ *
+ * @return 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
+);
+
+/**
+ * @brief This callback method asks the user to provide the virtual
+ * address of the response data buffer for the supplied IO request.
+ *
+ * @param[in] 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.
+ *
+ * @return 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
+);
+
+/**
+ * @brief This callback method asks the user to provide the length of the
+ * response data buffer for the supplied IO request.
+ *
+ * @param[in] 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.
+ *
+ * @return 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
+);
+
+/**
+ * @brief In this method the user is expected to log the supplied
+ * error information. The user must be capable of handling variable
+ * length argument lists and should consider prepending the fact
+ * that this is an error from the core.
+ *
+ * @param[in] logger_object This parameter specifies the logger object
+ * associated with this message.
+ * @param[in] log_object_mask This parameter specifies the log objects
+ * for which this message is being generated.
+ * @param[in] log_message This parameter specifies the message to be logged.
+ *
+ * @return none
+ */
+void scic_cb_logger_log_error(
+ SCI_LOGGER_HANDLE_T logger_object,
+ U32 log_object_mask,
+ char * log_message,
+ ...
+);
+
+
+/**
+ * @brief In this method the user is expected to log the supplied warning
+ * information. The user must be capable of handling variable
+ * length argument lists and should consider prepending the fact
+ * that this is a warning from the core.
+ *
+ * @param[in] logger_object This parameter specifies the logger object
+ * associated with this message.
+ * @param[in] log_object_mask This parameter specifies the log objects
+ * for which this message is being generated.
+ * @param[in] log_message This parameter specifies the message to be logged.
+ *
+ * @return none
+ */
+void scic_cb_logger_log_warning(
+ SCI_LOGGER_HANDLE_T logger_object,
+ U32 log_object_mask,
+ char * log_message,
+ ...
+);
+
+
+/**
+ * @brief In this method the user is expected to log the supplied debug
+ * information. The user must be capable of handling variable
+ * length argument lists and should consider prepending the fact
+ * that this is a debug message from the core.
+ *
+ * @param[in] logger_object This parameter specifies the logger object
+ * associated with this message.
+ * @param[in] log_object_mask This parameter specifies the log objects
+ * for which this message is being generated.
+ * @param[in] log_message This parameter specifies the message to be logged.
+ *
+ * @return none
+ */
+void scic_cb_logger_log_info(
+ SCI_LOGGER_HANDLE_T logger_object,
+ U32 log_object_mask,
+ char * log_message,
+ ...
+);
+
+
+/**
+ * @brief In this method the user is expected to log the supplied function
+ * trace information. The user must be capable of handling variable
+ * length argument lists and should consider prepending the fact
+ * that this is a function trace (i.e. entry/exit) message from the
+ * core.
+ *
+ * @param[in] logger_object This parameter specifies the logger object
+ * associated with this message.
+ * @param[in] log_object_mask This parameter specifies the log objects
+ * for which this message is being generated.
+ * @param[in] log_message This parameter specifies the message to be logged.
+ *
+ * @return none
+ */
+void scic_cb_logger_log_trace(
+ SCI_LOGGER_HANDLE_T logger_object,
+ U32 log_object_mask,
+ char * log_message,
+ ...
+);
+
+
+/**
+ * @brief In this method the user is expected to log the supplied state
+ * transition information. The user must be capable of handling
+ * variable length argument lists and should consider prepending the
+ * fact that this is a warning from the core.
+ *
+ * @param[in] logger_object This parameter specifies the logger object
+ * associated with this message.
+ * @param[in] log_object_mask This parameter specifies the log objects
+ * for which this message is being generated.
+ * @param[in] log_message This parameter specifies the message to be logged.
+ *
+ * @return none
+ */
+void scic_cb_logger_log_states(
+ SCI_LOGGER_HANDLE_T logger_object,
+ U32 log_object_mask,
+ char * log_message,
+ ...
+);
+
+
+/**
+ * @brief In this method the user must return the base address register (BAR)
+ * value for the supplied base address register number.
+ *
+ * @param[in] controller The controller for which to retrieve the bar number.
+ * @param[in] bar_number This parameter depicts the BAR index/number to be read.
+ *
+ * @return Return a pointer value indicating the contents of the BAR.
+ * @retval NULL indicates an invalid BAR index/number was specified.
+ * @retval All other values indicate a valid VIRTUAL address from the BAR.
+ */
+void * scic_cb_pci_get_bar(
+ SCI_CONTROLLER_HANDLE_T controller,
+ U16 bar_number
+);
+
+/**
+ * @brief In this method the user must read from PCI memory via access.
+ * This method is used for access to memory space and IO space.
+ *
+ * @param[in] controller The controller for which to read a DWORD.
+ * @param[in] address This parameter depicts the address from
+ * which to read.
+ *
+ * @return The value being returned from the PCI memory location.
+ *
+ * @todo This PCI memory access calls likely need to be optimized into macro?
+ */
+U32 scic_cb_pci_read_dword(
+ SCI_CONTROLLER_HANDLE_T controller,
+ void * address
+);
+
+/**
+ * @brief In this method the user must write to PCI memory via access.
+ * This method is used for access to memory space and IO space.
+ *
+ * @param[in] controller The controller for which to read a DWORD.
+ * @param[in] address This parameter depicts the address into
+ * which to write.
+ * @param[out] write_value This parameter depicts the value being written
+ * into the PCI memory location.
+ *
+ * @todo This PCI memory access calls likely need to be optimized into macro?
+ */
+void scic_cb_pci_write_dword(
+ SCI_CONTROLLER_HANDLE_T controller,
+ void * address,
+ U32 write_value
+);
+
+/**
+ * @brief This method informs the user when a stop operation on the port
+ * has completed.
+ *
+ * @param[in] controller This parameter represents the controller which
+ * contains the port.
+ * @param[in] port This parameter specifies the SCI port object for which
+ * the callback is being invoked.
+ * @param[in] completion_status This parameter specifies the status for
+ * the operation being completed.
+ *
+ * @return none
+ */
+void scic_cb_port_stop_complete(
+ SCI_CONTROLLER_HANDLE_T controller,
+ SCI_PORT_HANDLE_T port,
+ SCI_STATUS completion_status
+);
+
+/**
+ * @brief 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.
+ *
+ * @param[in] controller This parameter represents the controller which
+ * contains the port.
+ * @param[in] port This parameter specifies the SCI port object for which
+ * the callback is being invoked.
+ * @param[in] completion_status This parameter specifies the status for
+ * the operation being completed.
+ *
+ * @return none
+ */
+void scic_cb_port_hard_reset_complete(
+ SCI_CONTROLLER_HANDLE_T controller,
+ SCI_PORT_HANDLE_T port,
+ SCI_STATUS completion_status
+);
+
+/**
+ * @brief This method informs the user that the port is now in a ready
+ * state and can be utilized to issue IOs.
+ *
+ * @param[in] controller This parameter represents the controller which
+ * contains the port.
+ * @param[in] port This parameter specifies the SCI port object for which
+ * the callback is being invoked.
+ *
+ * @return none
+ */
+void scic_cb_port_ready(
+ SCI_CONTROLLER_HANDLE_T controller,
+ SCI_PORT_HANDLE_T port
+);
+
+/**
+ * @brief 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.
+ *
+ * @param[in] controller This parameter represents the controller which
+ * contains the port.
+ * @param[in] port This parameter specifies the SCI port object for which
+ * the callback is being invoked.
+ * @param[in] reason_code This parameter specifies the reason for the port
+ * not ready callback.
+ *
+ * @return none
+ */
+void scic_cb_port_not_ready(
+ SCI_CONTROLLER_HANDLE_T controller,
+ SCI_PORT_HANDLE_T port,
+ U32 reason_code
+);
+
+/**
+ * @brief 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.
+ *
+ * @param[in] controller This parameter represents the controller which
+ * contains the port.
+ * @param[in] port This parameter specifies the SCI port object for which
+ * the callback is being invoked.
+ * @param[in] phy This parameter specifies the phy that came ready, but the
+ * phy can't be a valid member of the port.
+ *
+ * @return none
+ */
+void scic_cb_port_invalid_link_up(
+ SCI_CONTROLLER_HANDLE_T controller,
+ SCI_PORT_HANDLE_T port,
+ SCI_PHY_HANDLE_T phy
+);
+
+/**
+ * @brief This callback method informs the user that a broadcast change
+ * primitive was received.
+ *
+ * @param[in] controller This parameter represents the controller which
+ * contains the port.
+ * @param[in] 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.
+ * @param[in] phy This parameter specifies the phy on which the primitive
+ * was received.
+ *
+ * @return none
+ */
+void scic_cb_port_bc_change_primitive_recieved(
+ SCI_CONTROLLER_HANDLE_T controller,
+ SCI_PORT_HANDLE_T port,
+ SCI_PHY_HANDLE_T phy
+);
+
+/**
+ * @brief This callback method informs the user that a broadcast SES
+ * primitive was received.
+ *
+ * @param[in] controller This parameter represents the controller which
+ * contains the port.
+ * @param[in] 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.
+ * @param[in] phy This parameter specifies the phy on which the primitive
+ * was received.
+ *
+ * @return none
+ */
+void scic_cb_port_bc_ses_primitive_recieved(
+ SCI_CONTROLLER_HANDLE_T controller,
+ SCI_PORT_HANDLE_T port,
+ SCI_PHY_HANDLE_T phy
+);
+
+/**
+ * @brief This callback method informs the user that a broadcast EXPANDER
+ * primitive was received.
+ *
+ * @param[in] controller This parameter represents the controller which
+ * contains the port.
+ * @param[in] 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.
+ * @param[in] phy This parameter specifies the phy on which the primitive
+ * was received.
+ *
+ * @return none
+ */
+void scic_cb_port_bc_expander_primitive_recieved(
+ SCI_CONTROLLER_HANDLE_T controller,
+ SCI_PORT_HANDLE_T port,
+ SCI_PHY_HANDLE_T phy
+);
+
+/**
+ * @brief This callback method informs the user that a broadcast ASYNCHRONOUS
+ * EVENT (AEN) primitive was received.
+ *
+ * @param[in] controller This parameter represents the controller which
+ * contains the port.
+ * @param[in] 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.
+ * @param[in] phy This parameter specifies the phy on which the primitive
+ * was received.
+ *
+ * @return none
+ */
+void scic_cb_port_bc_aen_primitive_recieved(
+ SCI_CONTROLLER_HANDLE_T controller,
+ SCI_PORT_HANDLE_T port,
+ SCI_PHY_HANDLE_T phy
+);
+
+/**
+ * @brief This callback method informs the user that a phy has become
+ * operational and is capable of communicating with the remote end
+ * point.
+ *
+ * @param[in] controller This parameter represents the controller
+ * associated with the phy.
+ * @param[in] 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
+ * @param[in] phy This parameter specifies the phy object for which the
+ * user callback is being invoked.
+ *
+ * @return none
+ */
+void scic_cb_port_link_up(
+ SCI_CONTROLLER_HANDLE_T controller,
+ SCI_PORT_HANDLE_T port,
+ SCI_PHY_HANDLE_T phy
+);
+
+/**
+ * @brief This callback method informs the user that a phy is no longer
+ * operational and is not capable of communicating with the remote end
+ * point.
+ *
+ * @param[in] controller This parameter represents the controller
+ * associated with the phy.
+ * @param[in] 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
+ * @param[in] phy This parameter specifies the phy object for which the
+ * user callback is being invoked.
+ *
+ * @return none
+ */
+void scic_cb_port_link_down(
+ SCI_CONTROLLER_HANDLE_T controller,
+ SCI_PORT_HANDLE_T port,
+ SCI_PHY_HANDLE_T phy
+);
+
+/**
+ * @brief This user callback method will inform the user that a start
+ * operation has completed.
+ *
+ * @param[in] controller This parameter specifies the core controller
+ * associated with the completion callback.
+ * @param[in] remote_device This parameter specifies the remote device
+ * associated with the completion callback.
+ * @param[in] completion_status This parameter specifies the completion
+ * status for the operation.
+ *
+ * @return none
+ */
+void scic_cb_remote_device_start_complete(
+ SCI_CONTROLLER_HANDLE_T controller,
+ SCI_REMOTE_DEVICE_HANDLE_T remote_device,
+ SCI_STATUS completion_status
+);
+
+/**
+ * @brief This user callback method will inform the user that a stop
+ * operation has completed.
+ *
+ * @param[in] controller This parameter specifies the core controller
+ * associated with the completion callback.
+ * @param[in] remote_device This parameter specifies the remote device
+ * associated with the completion callback.
+ * @param[in] completion_status This parameter specifies the completion
+ * status for the operation.
+ *
+ * @return none
+ */
+void scic_cb_remote_device_stop_complete(
+ SCI_CONTROLLER_HANDLE_T controller,
+ SCI_REMOTE_DEVICE_HANDLE_T remote_device,
+ SCI_STATUS completion_status
+);
+
+/**
+ * @brief This user callback method will inform the user that a remote
+ * device is now capable of handling IO requests.
+ *
+ * @param[in] controller This parameter specifies the core controller
+ * associated with the completion callback.
+ * @param[in] remote_device This parameter specifies the remote device
+ * associated with the callback.
+ *
+ * @return none
+ */
+void scic_cb_remote_device_ready(
+ SCI_CONTROLLER_HANDLE_T controller,
+ SCI_REMOTE_DEVICE_HANDLE_T remote_device
+);
+
+/**
+ * @brief 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).
+ *
+ * @param[in] controller This parameter specifies the core controller
+ * associated with the completion callback.
+ * @param[in] remote_device This parameter specifies the remote device
+ * associated with the callback.
+ * @param[in] reason_code This paramete specifies the reason the remote
+ * device is not ready.
+ *
+ * @return none
+ */
+void scic_cb_remote_device_not_ready(
+ SCI_CONTROLLER_HANDLE_T controller,
+ SCI_REMOTE_DEVICE_HANDLE_T remote_device,
+ U32 reason_code
+);
+
+
+/**
+ * @brief This user callback method will inform the user that this controller
+ * is having unexpected error. The user can choose to reset the controller.
+ * @param[in] controller The controller that is failed at the moment.
+ *
+ * @return none
+ */
+void scic_cb_controller_error(
+ SCI_CONTROLLER_HANDLE_T controller,
+ SCI_CONTROLLER_ERROR error
+);
+
+
+#if !defined(DISABLE_ATAPI)
+/**
+ * @brief This user callback gets from stp packet io's user request
+ * the CDB address.
+ * @param[in] scic_user_io_request
+ *
+ * @return The cdb adress.
+ */
+void * scic_cb_stp_packet_io_request_get_cdb_address(
+ void * scic_user_io_request
+);
+
+/**
+ * @brief This user callback gets from stp packet io's user request
+ * the CDB length.
+ * @param[in] scic_user_io_request
+ *
+ * @return 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)
+
+#ifdef __cplusplus
+}
+#endif // __cplusplus
+
+#endif // _SCIC_USER_CALLBACK_H_
+
diff --git a/sys/dev/isci/scil/scif_config_parameters.h b/sys/dev/isci/scil/scif_config_parameters.h
new file mode 100644
index 0000000..71965fd
--- /dev/null
+++ b/sys/dev/isci/scil/scif_config_parameters.h
@@ -0,0 +1,181 @@
+/*-
+ * 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.
+ *
+ * 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.
+ *
+ * $FreeBSD$
+ */
+#ifndef _SCIF_SAS_USER_PARAMETERS_H_
+#define _SCIF_SAS_USER_PARAMETERS_H_
+
+/**
+ * @file
+ *
+ * @brief This file contains all of the interface methods that can be called
+ * by an SCIF user on a SCIF_SAS_USER_PARAMETERS object.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif // __cplusplus
+
+#include <dev/isci/scil/sci_types.h>
+#include <dev/isci/scil/sci_status.h>
+#include <dev/isci/scil/intel_sas.h>
+
+
+/**
+ * @struct SCIF_SAS_USER_PARAMETERS
+ *
+ * @brief This structure delineates the various user parameters that can be
+ * changed by the framework user.
+ */
+typedef struct SCIF_SAS_USER_PARAMETERS
+{
+ /**
+ * This field indicates if the user would like to have the SATA NCQ
+ * feature enabled for all remote devices.
+ */
+ BOOL is_sata_ncq_enabled;
+
+ /**
+ * This field indicates if the user would like to have the SATA Automatic
+ * Standby Timer feature enabled for all remote devices.
+ */
+ BOOL is_sata_standby_timer_enabled;
+
+ /**
+ * This field indicates if the user would like to have the SATA Non-zero
+ * Buffer Offset feature enabled for all remote devices.
+ */
+ BOOL is_non_zero_buffer_offsets_enabled;
+
+ /**
+ * This field indicates if the user would like to clear affiliation for EA
+ * SATA devices during the controller stop process.
+ */
+ BOOL clear_affiliation_during_controller_stop;
+
+ /**
+ * This field indicates the user's desired NCQ depth for all remote
+ * devices. The maximum legal value for this field is 32.
+ */
+ U16 max_ncq_depth;
+
+ /**
+ * This field indicates the type of reset to be applied to all remote
+ * devices the first time they are discovered.
+ */
+ SCI_SAS_TASK_MGMT_FUNCTION_T reset_type;
+
+ /**
+ * This field indicates the os/user recommends ignoring fua in translation
+ * for perfromance reasons.
+ */
+ BOOL ignore_fua;
+
+} SCIF_SAS_USER_PARAMETERS_T;
+
+/**
+ * @union SCIF_USER_PARAMETERS
+ * @brief This structure/union specifies the various different user
+ * parameter sets available. Each type is specific to a
+ * Serial Attached SCSI implementation of the framework.
+ *
+ */
+typedef union SCIF_USER_PARAMETERS
+{
+ SCIF_SAS_USER_PARAMETERS_T sas;
+
+} SCIF_USER_PARAMETERS_T;
+
+/**
+ * @brief This method allows the user to attempt to change the user
+ * parameters utilized by the controller.
+ *
+ * @param[in] controller This parameter specifies the controller on which
+ * to set the user parameters.
+ * @param[in] user_parameters This parameter specifies the USER_PARAMETERS
+ * object containing the potential new values.
+ *
+ * @return Indicate if the update of the user parameters was successful.
+ * @retval SCI_SUCCESS This value is returned if the operation succeeded.
+ * @retval 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.
+ * @retval SCI_FAILURE_INVALID_PARAMETER_VALUE This value is returned if the
+ * user supplied an invalid reset_type, ncq depth, etc.
+ */
+SCI_STATUS scif_user_parameters_set(
+ SCI_CONTROLLER_HANDLE_T controller,
+ SCIF_USER_PARAMETERS_T * user_parameters
+);
+
+/**
+ * @brief This method allows the user to retrieve the user parameters
+ * utilized by the controller.
+ *
+ * @param[in] controller This parameter specifies the controller on which
+ * to set the user parameters.
+ * @param[in] user_parameters This parameter specifies the USER_PARAMETERS
+ * object into which the framework shall save it's parameters.
+ *
+ * @return none
+ */
+void scif_user_parameters_get(
+ SCI_CONTROLLER_HANDLE_T controller,
+ SCIF_USER_PARAMETERS_T * user_parameters
+);
+
+#ifdef __cplusplus
+}
+#endif // __cplusplus
+
+#endif // _SCIF_SAS_USER_PARAMETERS_H_
+
diff --git a/sys/dev/isci/scil/scif_controller.h b/sys/dev/isci/scil/scif_controller.h
new file mode 100644
index 0000000..61a513f
--- /dev/null
+++ b/sys/dev/isci/scil/scif_controller.h
@@ -0,0 +1,454 @@
+/*-
+ * 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.
+ *
+ * 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.
+ *
+ * $FreeBSD$
+ */
+#ifndef _SCIF_CONTROLLER_H_
+#define _SCIF_CONTROLLER_H_
+
+/**
+ * @file
+ *
+ * @brief This file contains all of the interface methods that can be called
+ * by an SCIF user on a SCIF controller object.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif // __cplusplus
+
+#include <dev/isci/scil/sci_types.h>
+#include <dev/isci/scil/sci_status.h>
+
+
+/**
+ * @brief This method will attempt to construct a framework controller object
+ * utilizing the supplied parameter information.
+ *
+ * @param[in] library This parameter specifies the handle to the framework
+ * library object associated with the controller being constructed.
+ * @param[in] controller This parameter specifies the framework controller to
+ * be constructed.
+ * @param[in] user_object This parameter is a reference to the SCIL users
+ * controller object and will be used to associate with the
+ * framework controller.
+ *
+ * @return Indicate if the controller was successfully constructed or if
+ * it failed in some way.
+ * @retval SCI_SUCCESS This value is returned if the controller was
+ * successfully constructed.
+ * @retval SCI_FAILURE_UNSUPPORTED_INIT_DATA_VERSION This value is returned
+ * if the controller does not support the supplied oem parameter
+ * data version.
+ * @retval SCI_FAILURE_UNSUPPORTED_PORT_CONFIGURATION This value is returned
+ * if the controller doesn't support the port configuration scheme
+ * (APC or MPC).
+ */
+SCI_STATUS scif_controller_construct(
+ SCI_LIBRARY_HANDLE_T library,
+ SCI_CONTROLLER_HANDLE_T controller,
+ void * user_object
+);
+
+/**
+ * @brief This method will initialize the SCI Framework controller object.
+ * This includes initialization of the associated core controller.
+ *
+ * @param[in] controller This parameter specifies the controller to be
+ * initialized.
+ *
+ * @return Indicate if the controller was successfully initialized or if
+ * it failed in some way.
+ * @retval SCI_SUCCESS This value is returned if the controller hardware
+ * was successfully initialized.
+ */
+SCI_STATUS scif_controller_initialize(
+ SCI_CONTROLLER_HANDLE_T controller
+);
+
+/**
+ * @brief This method returns the suggested scif_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.
+ *
+ * @param[in] controller the handle to the controller object for which
+ * to return the suggested start timeout.
+ *
+ * @return This method returns the number of milliseconds for the
+ * suggested start operation timeout.
+ */
+U32 scif_controller_get_suggested_start_timeout(
+ SCI_CONTROLLER_HANDLE_T controller
+);
+
+/**
+ * @brief This method will start the SCIF controller. 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.
+ *
+ * @pre The controller must be in the INITIALIZED or STARTED state.
+ *
+ * @param[in] controller the handle to the controller object to start.
+ * @param[in] timeout This parameter specifies the number of milliseconds
+ * in which the start operation should complete.
+ *
+ * @return Indicate if the controller start method succeeded or failed in
+ * some way.
+ * @retval SCI_SUCCESS if the start operation succeeded.
+ * @retval SCI_WARNING_ALREADY_IN_STATE if the controller is already in
+ * the STARTED state.
+ * @retval SCI_FAILURE_INVALID_STATE if the controller is not either in
+ * the INITIALIZED or STARTED states.
+ * @retval SCI_FAILURE_INVALID_MEMORY_DESCRIPTOR if there are
+ * inconsistent or invalid values in the supplied
+ * SCI_PHYSICAL_MEMORY_DESCRIPTOR array.
+ * @retval SCI_FAILURE_UNSUPPORTED_PORT_CONFIGURATION This value is
+ * returned if the phy to port allocation cannot be supported.
+ *
+ * @see For additional information please refer to: scic_controller_start()
+ */
+SCI_STATUS scif_controller_start(
+ SCI_CONTROLLER_HANDLE_T controller,
+ U32 timeout
+);
+
+/**
+ * @brief This method will stop an individual framework controller object. This
+ * includes quiescing IOs, releasing affiliations, and other shutdown
+ * related operations. 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 framework IO requests are quiesced
+ * and any additional framework operations are halted.
+ *
+ * @pre The controller must be in the STARTED or STOPPED state.
+ *
+ * @param[in] controller the handle to the controller object to stop.
+ * @param[in] timeout This parameter specifies the number of milliseconds
+ * in which the stop operation should complete.
+ *
+ * @return Indicate if the controller stop method succeeded or failed in
+ * some way.
+ * @retval SCI_SUCCESS if the stop operation successfully began.
+ * @retval SCI_WARNING_ALREADY_IN_STATE if the controller is already in
+ * the STOPPED state.
+ * @retval SCI_FAILURE_INVALID_STATE if the controller is not either in
+ * the STARTED or STOPPED states.
+ *
+ * @see For additional information please refer to: scic_controller_stop()
+ */
+SCI_STATUS scif_controller_stop(
+ SCI_CONTROLLER_HANDLE_T controller,
+ U32 timeout
+);
+
+/**
+ * @brief This method will reset the supplied framework controller regardless
+ * of the state of said controller. This operation is considered
+ * destructive. Outstanding IO requests are not aborted or completed
+ * at the actual remote device. However, the framework will
+ * manufacture completion callbacks to the OS driver for the IO
+ * requests.
+ *
+ * @param[in] controller the handle to the controller object to reset.
+ *
+ * @return Indicate if the controller reset method succeeded or failed in
+ * some way.
+ * @retval SCI_SUCCESS if the reset operation successfully started.
+ * @retval SCI_FATAL_ERROR if the controller reset operation is unable to
+ * complete.
+ *
+ * @see For additional information please refer to: scic_controller_reset()
+ */
+SCI_STATUS scif_controller_reset(
+ SCI_CONTROLLER_HANDLE_T controller
+);
+
+/**
+ * @brief This method returns the SCI Core controller handle associated
+ * with this controller.
+ *
+ * @param[in] scif_controller the handle to the controller object for which
+ * to retrieve the core specific controller handle
+ *
+ * @return Return the SCI core controller handle associated with the supplied
+ * framework controller.
+ */
+SCI_CONTROLLER_HANDLE_T scif_controller_get_scic_handle(
+ SCI_CONTROLLER_HANDLE_T scif_controller
+);
+
+/**
+ * @brief This method is called by the SCIF user to send/start a framework
+ * IO request.
+ *
+ * @param[in] controller the handle to the controller object for which
+ * to start an IO request.
+ * @param[in] remote_device the handle to the remote device object for which
+ * to start an IO request.
+ * @param[in] io_request the handle to the io request object to start.
+ * @param[in] 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.
+ * @see scic_controller_allocate_tag() for more information
+ * on allocating a tag.
+ *
+ * @return Indicate if the controller successfully started the IO request.
+ * @retval SCI_IO_SUCCESS if the IO request was successfully started.
+ *
+ * @see For additional information please refer to: scic_controller_start_io()
+ *
+ * @todo Determine the failure situations and return values.
+ */
+SCI_IO_STATUS scif_controller_start_io(
+ SCI_CONTROLLER_HANDLE_T controller,
+ SCI_REMOTE_DEVICE_HANDLE_T remote_device,
+ SCI_IO_REQUEST_HANDLE_T io_request,
+ U16 io_tag
+);
+
+/**
+ * @brief This method is called by the SCIF user to send/start a framework
+ * task management request.
+ *
+ * @param[in] controller the handle to the controller object for which
+ * to start the task management request.
+ * @param[in] remote_device the handle to the remote device object for which
+ * to start the task management request.
+ * @param[in] task_request the handle to the task request object to start.
+ * @param[in] 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.
+ * @see scic_controller_allocate_tag() for more information
+ * on allocating a tag.
+ *
+ * @return Indicate if the controller successfully started the IO request.
+ * @retval SCI_TASK_SUCCESS if the task request was successfully started.
+ *
+ * @see For additional information please refer to: scic_controller_start_task()
+ *
+ * @todo Determine the failure situations and return values.
+ */
+SCI_TASK_STATUS scif_controller_start_task(
+ SCI_CONTROLLER_HANDLE_T controller,
+ SCI_REMOTE_DEVICE_HANDLE_T remote_device,
+ SCI_TASK_REQUEST_HANDLE_T task_request,
+ U16 io_tag
+);
+
+/**
+ * @brief This method is called by the SCI user to complete a previously
+ * started 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).
+ *
+ * @param[in] controller The handle to the controller object for which
+ * to complete the IO request.
+ * @param[in] remote_device The handle to the remote device object for which
+ * to complete the IO request.
+ * @param[in] io_request the handle to the io request object to complete.
+ *
+ * @return Indicate if the controller successfully completed the IO request.
+ * @retval SCI_SUCCESS if the completion process was successful.
+ *
+ * @see For additional information please refer to:
+ * scic_controller_complete_io()
+ */
+SCI_STATUS scif_controller_complete_io(
+ SCI_CONTROLLER_HANDLE_T controller,
+ SCI_REMOTE_DEVICE_HANDLE_T remote_device,
+ SCI_IO_REQUEST_HANDLE_T io_request
+);
+
+/**
+ * @brief This method will perform framework specific completion operations for
+ * a 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).
+ *
+ * @param[in] controller The handle to the controller object for which
+ * to complete the task management request.
+ * @param[in] remote_device The handle to the remote device object for which
+ * to complete the task management request.
+ * @param[in] task_request the handle to the task management request object
+ * to complete.
+ *
+ * @return Indicate if the controller successfully completed the task
+ * management request.
+ * @retval SCI_SUCCESS if the completion process was successful.
+ */
+SCI_STATUS scif_controller_complete_task(
+ SCI_CONTROLLER_HANDLE_T controller,
+ SCI_REMOTE_DEVICE_HANDLE_T remote_device,
+ SCI_TASK_REQUEST_HANDLE_T task_request
+);
+
+/**
+ * @brief This method simply provides the user with a unique handle for a
+ * given SAS/SATA domain index.
+ *
+ * @param[in] controller This parameter represents the handle to the
+ * controller object from which to retrieve a domain (SAS or
+ * SATA) handle.
+ * @param[in] port_index This parameter specifies the domain index in
+ * the controller for which to retrieve the domain handle.
+ * @note 0 <= port_index < maximum number of phys.
+ * @param[out] domain_handle This parameter specifies the retrieved domain
+ * handle to be provided to the caller.
+ *
+ * @return Indicate if the retrieval of the domain handle was successful.
+ * @retval SCI_SUCCESS This value is returned if the retrieval was successful.
+ * @retval SCI_FAILURE_INVALID_PORT This value is returned if the supplied
+ * port index is not invalid.
+ */
+SCI_STATUS scif_controller_get_domain_handle(
+ SCI_CONTROLLER_HANDLE_T controller,
+ U8 port_index,
+ SCI_DOMAIN_HANDLE_T * domain_handle
+);
+
+/**
+ * @brief This method allows the user to configure the SCI Framework
+ * into either a performance mode or a memory savings mode.
+ *
+ * @param[in] controller This parameter represents the handle to the
+ * controller object for which to update the operating
+ * mode.
+ * @param[in] mode This parameter specifies the new mode for the
+ * controller.
+ *
+ * @return Indicate if the user successfully change the operating mode
+ * of the controller.
+ * @retval SCI_SUCCESS The user successfully updated the mode.
+ */
+SCI_STATUS scif_controller_set_mode(
+ SCI_CONTROLLER_HANDLE_T controller,
+ SCI_CONTROLLER_MODE mode
+);
+
+/**
+ * @brief This method simply returns the T10 SCSI to ATA Translation (SAT)
+ * specification version to which this translator is compliant for
+ * supported commands.
+ *
+ * @return An integer value indicating the SAT version to which this
+ * translator complies.
+ */
+U32 scif_controller_get_sat_compliance_version(
+ void
+);
+
+/**
+ * @brief This method simply returns the revision of the T10 SCSI to ATA
+ * Translation (SAT) specification version to which this translator
+ * is compliant for supported commands.
+ *
+ * @return An integer value indicating the revision of the SAT version
+ * to which this translator complies.
+ */
+U32 scif_controller_get_sat_compliance_version_revision(
+ void
+);
+
+/**
+ * @brief This method is called by the SCI user to start internal io.
+ */
+typedef void (*SCI_START_INTERNAL_IO_ROUTINE)(
+ SCI_CONTROLLER_HANDLE_T controller
+);
+
+#if !defined(DISABLE_INTERRUPTS)
+/**
+ * @brief This method allows the user to configure the interrupt coalescence.
+ * Please refer to the comment header for
+ * scic_controller_set_interrupt_coalescence() to find details.
+ */
+SCI_STATUS scif_controller_set_interrupt_coalescence(
+ SCI_CONTROLLER_HANDLE_T controller,
+ U32 coalesce_number,
+ U32 coalesce_timeout
+);
+
+/**
+ * @brief This method retrieves the interrupt coalescence information.
+ * Please refer to the comment header for
+ * scic_controller_get_interrupt_coalescence() to find details.
+ */
+void scif_controller_get_interrupt_coalescence(
+ SCI_CONTROLLER_HANDLE_T controller,
+ U32 * coalesce_number,
+ U32 * coalesce_timeout
+);
+
+#else // !defined(DISABLE_INTERRUPTS)
+
+#define scif_controller_set_interrupt_coalescence(controller, num, timeout) \
+ SCI_FAILURE
+#define scif_controller_get_interrupt_coalescence(controller, num, timeout)
+
+#endif // !defined(DISABLE_INTERRUPTS)
+
+#ifdef __cplusplus
+}
+#endif // __cplusplus
+
+#endif // _SCIF_CONTROLLER_H_
+
diff --git a/sys/dev/isci/scil/scif_domain.h b/sys/dev/isci/scil/scif_domain.h
new file mode 100644
index 0000000..ee639c8
--- /dev/null
+++ b/sys/dev/isci/scil/scif_domain.h
@@ -0,0 +1,185 @@
+/*-
+ * 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.
+ *
+ * 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.
+ *
+ * $FreeBSD$
+ */
+#ifndef _SCIF_DOMAIN_H_
+#define _SCIF_DOMAIN_H_
+
+/**
+ * @file
+ *
+ * @brief This file contains all of the interface methods that can be called
+ * by an SCI Framework user on the SAS/SATA domain object.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif // __cplusplus
+
+#include <dev/isci/scil/sci_types.h>
+#include <dev/isci/scil/sci_status.h>
+#include <dev/isci/scil/intel_sas.h>
+
+
+/**
+ * @brief This method enables the framework user to find the SCI Core Port
+ * object through which the supplied domain is accessed.
+ *
+ * @param[in] domain This parameter specifies the framework domain object
+ * for which to return the corresponding SCI Core port object.
+ *
+ * @return Return a handle to the SCI Core port through which the supplied
+ * domain is accessed.
+ * @retval SCI_INVALID_HANDLE This value is returned if the core port
+ * object can not be retrieved.
+ */
+SCI_PORT_HANDLE_T scif_domain_get_scic_port_handle(
+ SCI_DOMAIN_HANDLE_T domain
+);
+
+/**
+ * @brief This method will find and retreive the device associated with the
+ * supplied SAS address if such a device exists.
+ *
+ * @param[in] domain This parameter specifies the framework domain object
+ * on which to discover devices.
+ * @param[in] sas_address This parameter specifies the SAS address of the
+ * object to locate in this domain.
+ *
+ * @return Indicate if the device was successfully found in the domain.
+ * @retval SCI_INVALID_HANDLE This value is returned if the device is not
+ * found in the domain.
+ * @retval All other values indicate a valid remote device being found.
+ */
+SCI_REMOTE_DEVICE_HANDLE_T scif_domain_get_device_by_sas_address(
+ SCI_DOMAIN_HANDLE_T domain,
+ SCI_SAS_ADDRESS_T * sas_address
+);
+
+/**
+ * @brief This method will attempt to discover the supplied domain.
+ *
+ * @warning This method must be synchronized with the controller completion
+ * handler (see scic_controller_get_handler_methods()). The user
+ * may call this method from within the completion handler in which
+ * case, no synchronization is necessary.
+ *
+ * @note
+ * - IO requests from the OS driver are held off until discovery
+ * of the domain is complete.
+ * - Discovery may perform SSP or STP IO requests to configure
+ * remote devices prior to informing the SCIF User of their
+ * existence via the remote_device_ready user callback.
+ *
+ * @param[in] domain This parameter specifies the framework domain object
+ * on which to discover devices.
+ * @param[in] discover_timeout This parameter specifies the number of
+ * milliseconds in which the domain discovery operation should
+ * complete.
+ * @param[in] device_timeout This parameter specifies the number of
+ * milliseconds in which the device configuration and/or reset
+ * operations should complete. Logically, the device_timeout
+ * parameter should be shorter then the domain_timeout value.
+ * Especially considering the domain could be made up of "n"
+ * different devices.
+ *
+ * @return Indicate if the discover operation started successfully.
+ * @retval SCI_SUCCESS This value is returned if the discover operation
+ * started successfully.
+ * @retval SCI_WARNING_TIMER_CONFLICT This value is returned if the SCI
+ * implementation doesn't support the desired timeout amounts or if
+ * the desired timeout amounts conflict in some manner.
+ */
+SCI_STATUS scif_domain_discover(
+ SCI_DOMAIN_HANDLE_T domain,
+ U32 discover_timeout,
+ U32 device_timeout
+);
+
+#if !defined(DISABLE_SCI_ITERATORS)
+/**
+ * @brief This method gets an iterator for the list of remote devices in the
+ * specified domain.
+ *
+ * @param[in] domain: This parameter specifies the framework domain handle
+ * @param[in] iterator_buffer: This parameters specifies the memory buffer that
+ * will be used to construct the iterator.
+ *
+ * @retval Handle to the remote device list iterator.
+ */
+SCI_ITERATOR_HANDLE_T scif_domain_get_remote_device_iterator(
+ SCI_DOMAIN_HANDLE_T domain,
+ void * iterator_buffer
+);
+#else // !defined(DISABLE_SCI_ITERATORS)
+#define scif_domain_get_remote_device_iterator(the_domain, the_buffer) \
+ SCI_INVALID_HANDLE
+#endif // !defined(DISABLE_SCI_ITERATORS)
+
+/**
+ * @brief This method simply returns a suggest timeout value for discovery.
+ *
+ * @param[in] domain The handle to the domain whose discover activity is to
+ * be started.
+ *
+ * @return The suggested timeout value for domain discover in milli-seconds.
+ */
+U32 scif_domain_get_suggested_discover_timeout(
+ SCI_DOMAIN_HANDLE_T domain
+);
+
+#ifdef __cplusplus
+}
+#endif // __cplusplus
+
+#endif // _SCIF_DOMAIN_H_
+
diff --git a/sys/dev/isci/scil/scif_io_request.h b/sys/dev/isci/scil/scif_io_request.h
new file mode 100644
index 0000000..41647d1
--- /dev/null
+++ b/sys/dev/isci/scil/scif_io_request.h
@@ -0,0 +1,243 @@
+/*-
+ * 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.
+ *
+ * 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.
+ *
+ * $FreeBSD$
+ */
+#ifndef _SCIF_IO_REQUEST_H_
+#define _SCIF_IO_REQUEST_H_
+
+/**
+ * @file
+ *
+ * @brief This file contains the structures and interface methods that
+ * can be referenced and used by the SCI user for the SCI IO request
+ * object.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif // __cplusplus
+
+#include <dev/isci/scil/sci_types.h>
+#include <dev/isci/scil/sci_status.h>
+
+
+/**
+ * @brief This method simply returns the size required to construct an SCI
+ * based IO request object (includes core & framework object size).
+ *
+ * @return Return the size of the SCI IO request object.
+ */
+U32 scif_io_request_get_object_size(
+ void
+);
+
+/**
+* @brief This method simply the number of data bytes transfered for a
+* STP or SSP io request.
+*
+* @param[in] scif_io_request This parameter specifies the framework IO
+* handle to retrieve the number of data bytes transferred.
+*
+* @return Return the number of data bytes transfered by the io request
+*/
+U32 scif_io_request_get_number_of_bytes_transferred(
+ void * scif_io_request
+);
+
+/**
+ * @brief This method is called by the SCIF user to construct an IO request.
+ * This method will construct a SCIC IO request internally. The memory
+ * for the core IO request is passed as a parameter to this method.
+ *
+ * @note The SCI framework implementation will create an association between
+ * the user IO request object and the framework IO request object.
+ *
+ * @param[in] scif_controller the handle to the framework controller object
+ * for which to build an IO request.
+ * @param[in] scif_remote_device This parameter specifies the framework
+ * remote device with which this IO request is to be associated.
+ * @param[in] 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
+ * scif_controller_start_io() method.
+ * @param[in] 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 framework
+ * IO request object.
+ * @param[in] io_request_memory This parameter specifies the memory
+ * to be utilized in the construction of the framework IO request.
+ * @param[in] scif_io_request This parameter specifies the handle to be
+ * utilized for all further interactions with this IO request
+ * object.
+ *
+ * @return Indicate if the controller successfully built the IO request.
+ * @retval SCI_SUCCESS This value is returned if the IO request was
+ * successfully built.
+ */
+SCI_STATUS scif_io_request_construct(
+ SCI_CONTROLLER_HANDLE_T scif_controller,
+ SCI_REMOTE_DEVICE_HANDLE_T scif_remote_device,
+ U16 io_tag,
+ void * user_io_request_object,
+ void * io_request_memory,
+ SCI_IO_REQUEST_HANDLE_T * scif_io_request
+);
+
+/**
+ * @brief This method simply returns the SCI Core object handle that is
+ * associated with the supplied SCI Framework object.
+ *
+ * @param[in] scif_io_request This parameter specifies the framework IO
+ * for which to return the associated core IO request object.
+ *
+ * @return This method returns a handle to the core IO request object
+ * associated with the framework IO request object.
+ * @retval SCI_INVALID_HANDLE This return value indicates that the SCI Core
+ * IO request handle for the supplied framework IO is invalid.
+ */
+SCI_IO_REQUEST_HANDLE_T scif_io_request_get_scic_handle(
+ SCI_IO_REQUEST_HANDLE_T scif_io_request
+);
+
+/**
+ * @brief This method returns the address of the response information unit.
+ * This call is only valid if the completion status for the io request
+ * is SCI_FAILURE_IO_RESPONSE_VALID.
+ *
+ * @param[in] scif_io_request This parameter specifies the framework IO
+ * for which to return the associated core IO request object.
+ *
+ * @return The address for the response information unit.
+ */
+void * scif_io_request_get_response_iu_address(
+ SCI_IO_REQUEST_HANDLE_T scif_io_request
+);
+
+/**
+ * @brief This method will build an Framework SSP Passthrough IO request based
+ * on the user information supplied in the pass-through IO request object.
+ * In case of pass through request construction, the driver creates the
+ * sci core request object and pass that to the framework
+ *
+ * @pre
+ *
+ * @param[in] scif_controller. Not used in the function but kept to maintain uniformity
+ * with other io construct functions
+ * @param[in] scif_remote_device. This parameter is the device.
+ * @param[in] scic_io_request. This parameter is the scic request already constructed
+ * @param[in] user_io_request_object, the user io request
+ * @param[in] io_request_memory, the scif offset in the user_io_request_object.
+ *
+ * @param[out] the contructed scif request. This points to the same location as io_request_memory
+ *
+ * @return Indicate if framework IO request is successfully built.
+ * @retval SCI_SUCCESS This value is returned if the IO request was
+ * successfully built.
+ */
+SCI_STATUS scif_io_request_construct_with_core (
+ SCI_CONTROLLER_HANDLE_T scif_controller,
+ SCI_REMOTE_DEVICE_HANDLE_T scif_remote_device,
+ void * scic_io_request,
+ void * user_io_request_object,
+ void * io_request_memory,
+ SCI_IO_REQUEST_HANDLE_T * scif_io_request
+);
+
+/**
+ * @brief This method will build the basic scif and scic io request object based
+ * on the user information supplied in the pass-through IO request object.
+ * This function will not build the protocol specific part of the request
+ * but set up the memory areas of scif and scic set the association.
+ *
+ * @pre
+ *
+ * @param[in] scif_controller the handle to the framework controller object
+ * for which to build an IO request.
+ * @param[in] scif_remote_device This parameter specifies the framework
+ * remote device with which this IO request is to be associated.
+ * @param[in] 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
+ * scif_controller_start_io() method.
+ * @param[in] 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 framework
+ * IO request object.
+ * @param[in] io_request_memory This parameter specifies the memory
+ * to be utilized in the construction of the framework IO request.
+ * @param[in] scif_io_request This parameter specifies the handle to be
+ * utilized for all further interactions with this IO request
+ * object.
+ *
+ * @return Indicate if the controller successfully built the IO request.
+ * @retval SCI_SUCCESS This value is returned if the IO request was
+ * successfully built.
+ */
+SCI_STATUS scif_request_construct(
+ SCI_CONTROLLER_HANDLE_T scif_controller,
+ SCI_REMOTE_DEVICE_HANDLE_T scif_remote_device,
+ U16 io_tag,
+ void * user_io_request_object,
+ void * io_request_memory,
+ SCI_IO_REQUEST_HANDLE_T * scif_io_request
+);
+
+#ifdef __cplusplus
+}
+#endif // __cplusplus
+
+#endif // _SCIF_IO_REQUEST_H_
+
diff --git a/sys/dev/isci/scil/scif_library.h b/sys/dev/isci/scil/scif_library.h
new file mode 100644
index 0000000..28de43d
--- /dev/null
+++ b/sys/dev/isci/scil/scif_library.h
@@ -0,0 +1,196 @@
+/*-
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 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.
+ *
+ * $FreeBSD$
+ */
+#ifndef _SCIF_LIBRARY_H_
+#define _SCIF_LIBRARY_H_
+
+/**
+ * @file
+ *
+ * @brief This file contains all of the interface methods that can be called
+ * by an SCI Framework user on the library object. The library is
+ * the container of all other objects being managed (i.e. controllers,
+ * target devices, sas ports, etc.) by SCIF.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif // __cplusplus
+
+#include <dev/isci/scil/sci_types.h>
+#include <dev/isci/scil/sci_status.h>
+
+
+/**
+ * @brief This method will contsruct the SCI framework library based on the
+ * supplied parameter information. By default, libraries are
+ * considered "ready" as soon as they are constructed.
+ *
+ * @param[in] library_memory_p a pointer to the memory at which the
+ * library object is located.
+ * @param[in] max_controller_count the maximum number of controllers that
+ * this library can manage.
+ *
+ * @return An opaque library handle to be used by the SCI user for all
+ * subsequent library operations.
+ */
+SCI_LIBRARY_HANDLE_T scif_library_construct(
+ void * library_memory_p,
+ U8 max_controller_count
+);
+
+/**
+ * @brief This method returns the size of the framework library object. The
+ * size of the framework library object includes the associated core
+ * object.
+ *
+ * @param[in] max_controller_count the maximum number of controllers that
+ * this library can manage.
+ *
+ * @return a positive integer value indicating the size (in bytes) of the
+ * library object.
+ */
+U32 scif_library_get_object_size(
+ U8 max_controller_count
+);
+
+/**
+ * @brief This method will allocate the next available framework controller
+ * object that can be managed by this framework library.
+ *
+ * @see For additional information please refer to:
+ * scic_library_allocate_controller()
+ *
+ * @param[in] library the handle to the library object for which to allocate
+ * a controller.
+ * @param[out] new_controller_p This parameter specifies a pointer to the
+ * controller handle that was added to the library.
+ *
+ * @return Indicate if the controller was successfully allocated or if iti
+ * failed in some way.
+ * @retval SCI_SUCCESS if the controller was successfully allocated.
+ * @retval SCI_FAILURE_INSUFFICIENT_RESOURCES if the library has no more
+ * available controller objects to allocate.
+ */
+SCI_STATUS scif_library_allocate_controller(
+ SCI_LIBRARY_HANDLE_T library,
+ SCI_CONTROLLER_HANDLE_T * new_controller_p
+);
+
+/**
+ * @brief This method will attempt to free the supplied controller to the
+ * library.
+ *
+ * @param[in] library the handle to the library object for which to free
+ * a controller.
+ * @param[in] controller the handle to the controller object to be freed
+ * from the library.
+ *
+ * @return Indicate if the controller was successfully freed or if it failed
+ * in some way.
+ * @retval SCI_SUCCESS if the controller was successfully freed.
+ * @retval SCI_FAILURE_CONTROLLER_NOT_FOUND if the supplied controller is
+ * not managed by the supplied library.
+ */
+SCI_STATUS scif_library_free_controller(
+ SCI_LIBRARY_HANDLE_T library,
+ SCI_CONTROLLER_HANDLE_T controller
+);
+
+
+/**
+ * @brief This method returns the SCI Core library handle
+ * associated with this library.
+ *
+ * @param[in] scif_library the handle to the library
+ * object for which to retrieve the core specific
+ * library handle
+ *
+ * @return Return the SCI core library handle associated with
+ * the supplied framework library.
+ */
+SCI_LIBRARY_HANDLE_T scif_library_get_scic_handle(
+ SCI_LIBRARY_HANDLE_T scif_library
+);
+
+
+/**
+ * @brief This method returns the minimum number of timers needed. If the
+ * user supplies timers less then the number specified via this
+ * call, then the user runs the risk of improper operation. This
+ * call includes the minimum number of timers needed by the core.
+ *
+ * @return This method returns a value representing the minimum number of
+ * timers required by this framework implementation
+ */
+U16 scif_library_get_min_timer_count(
+ void
+);
+
+/**
+ * @brief This method returns the maximum number of timers that could
+ * be ever be in use by this component at a given time.
+ *
+ * @return This method returns a value representing the minimum number of
+ * timers required by this framework implementation
+ */
+U16 scif_library_get_max_timer_count(
+ void
+);
+
+#ifdef __cplusplus
+}
+#endif // __cplusplus
+
+#endif // _SCIF_LIBRARY_H_
+
diff --git a/sys/dev/isci/scil/scif_logger.h b/sys/dev/isci/scil/scif_logger.h
new file mode 100644
index 0000000..f9d760c
--- /dev/null
+++ b/sys/dev/isci/scil/scif_logger.h
@@ -0,0 +1,118 @@
+/*-
+ * 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.
+ *
+ * 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.
+ *
+ * $FreeBSD$
+ */
+#ifndef _SCIF_LOGGER_H_
+#define _SCIF_LOGGER_H_
+
+/**
+ * @file
+ *
+ * @brief This file contains all of the SCI Framework specific logger object
+ * constant definitions.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif // __cplusplus
+
+#include <dev/isci/scil/sci_logger.h>
+
+
+/* The following is a list of log objects for which log information can */
+/* be enabled or disabled. */
+
+/** Enables/disables logging specific to the library. */
+#define SCIF_LOG_OBJECT_LIBRARY 0x00000001
+
+/** Enables/disables logging specific to the controller. */
+#define SCIF_LOG_OBJECT_CONTROLLER 0x00000002
+
+/** Enables/disables logging specific to the sas port. */
+#define SCIF_LOG_OBJECT_DOMAIN 0x00000004
+
+/** Enables/disables logging specific to the domain discovery process. */
+#define SCIF_LOG_OBJECT_DOMAIN_DISCOVERY 0x00000008
+
+/** Enables/disables logging specific to the remote devices. */
+#define SCIF_LOG_OBJECT_REMOTE_DEVICE 0x00000010
+
+/** Enables/disables logging specific to remote device configuration. */
+#define SCIF_LOG_OBJECT_REMOTE_DEVICE_CONFIG 0x00000020
+
+/** Enables/disables logging specific to performing task management. */
+#define SCIF_LOG_OBJECT_TASK_MANAGEMENT 0x00000040
+
+/** Enables/disables logging specific to SCSI to SATA command translation. */
+#define SCIF_LOG_OBJECT_COMMAND_TRANSLATION 0x00000080
+
+/** Enables/disables logging specific to SCSI to SATA response translation. */
+#define SCIF_LOG_OBJECT_RESPONSE_TRANSLATION 0x00000100
+
+/** Enables/disables logging specific to framework initialization. */
+#define SCIF_LOG_OBJECT_INITIALIZATION 0x00000200
+
+/** Enables/disables logging specific to framework shutdown. */
+#define SCIF_LOG_OBJECT_SHUTDOWN 0x00000400
+
+/** Enables/disables logging specific to all IO requests. */
+#define SCIF_LOG_OBJECT_IO_REQUEST 0x00000800
+
+/** Enables/disables logging specific to all IO requests. */
+#define SCIF_LOG_OBJECT_CONTROLLER_RESET 0x00001000
+
+#ifdef __cplusplus
+}
+#endif // __cplusplus
+
+#endif // _SCIF_LOGGER_H_
+
diff --git a/sys/dev/isci/scil/scif_overview.h b/sys/dev/isci/scil/scif_overview.h
new file mode 100644
index 0000000..b7132bb
--- /dev/null
+++ b/sys/dev/isci/scil/scif_overview.h
@@ -0,0 +1,116 @@
+/*-
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 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.
+ *
+ * $FreeBSD$
+ */
+#ifndef _SCIF_OVERVIEW_H_
+#define _SCIF_OVERVIEW_H_
+
+/**
+@page framework_page SCI Framework
+
+@section scif_introduction_section Introduction
+
+The SCI Framework component provides SAS and SATA storage specific abstraction
+to any OS driver devoid of this type of functionality. The functionality
+provided by this component is of a higher nature and considered unnecessary
+for some driver environments. Basically, a user should be able to utilize
+the same SCI Framework with different SCI Core implementations, with the
+little to no changes necessary.
+
+@warning In situations where the SCI framework is utilized, users should NOT
+ invoke core methods on core objects for which there are associated
+ framework objects and framework methods. Therefore, if a method is
+ common to both the core and the framework object, do not invoke the
+ core method if utilizing the framework. Some exceptions to this
+ exist and are called out. It is important to mention that methods
+ found only in the core are safe to invoke at times specified per
+ that methods definition.
+
+The following is a list of features found in an SCI Framework implementation:
+
+-# SCI Core management
+-# Port configuration scheme enforcement. There are 2 port configuration
+schemes:
+ -# Automatic Port Configuration (APC). In APC mode the framework will
+ allow for any port configuration based on what is physically connected,
+ assuming the underlying SCI Core also supports the configuration.
+ -# Manual Port Configuration (MPC). In MPC mode the framework expects the
+ user to supply exactly which phys are to be allocated to each specific
+ port. If the discovered direct attached physical connections do not match
+ the user supplied map, then an error is raised and the initialization
+ process is halted.
+-# Domain Discovery
+-# Domain level resets (i.e. bus reset)
+-# Task management processing
+-# Controller Shutdown management (e.g. release STP affiliations, quiesce IOs)
+-# Remote Device Configuration. Potential features:
+ -# SSP: maybe mode selects to set timers or modify DIF settings.
+ -# STP: IDENTIFY_DEVICE, SET FEATURES, etc.
+ -# SMP: CONTROL type requests to set timers.
+-# SAT Translation (Actually contained in SATI component)
+-# SMP Zoning management
+
+@image latex sci_framework.eps "SCI Framework Class Diagram" width=10cm
+
+@note
+For the SCU Driver Standard implementation of the SCI Framework interface the
+following definitions should be used to augment the cardinalities described
+in the previous diagram:
+-# There are exactly 4 scif_domain objects in the scif_controller. This
+ number directly correlates to the number of scic_port objects in the core.
+-# The maximum number of supported controllers in a library is a truly flexible
+ value, but the likely maximum number is 4.
+
+ */
+
+#endif // _SCIF_OVERVIEW_H_
+
diff --git a/sys/dev/isci/scil/scif_remote_device.h b/sys/dev/isci/scil/scif_remote_device.h
new file mode 100644
index 0000000..f67d40d
--- /dev/null
+++ b/sys/dev/isci/scil/scif_remote_device.h
@@ -0,0 +1,295 @@
+/*-
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 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.
+ *
+ * $FreeBSD$
+ */
+#ifndef _SCIF_REMOTE_DEVICE_H_
+#define _SCIF_REMOTE_DEVICE_H_
+
+/**
+ * @file
+ *
+ * @brief This file contains all of the interface methods that can be called
+ * by an SCI Framework user on a remote device object. The
+ * framework remote device object provides management of resets for
+ * the remote device, IO thresholds, potentially NCQ tag management,
+ * etc.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif // __cplusplus
+
+#include <dev/isci/scil/sci_types.h>
+#include <dev/isci/scil/sci_status.h>
+#include <dev/isci/scil/intel_sas.h>
+
+
+/**
+ * This constant is utilized to inform the user that there is no defined
+ * maximum request queue depth associated with a remote device.
+ */
+#define SCIF_REMOTE_DEVICE_NO_MAX_QUEUE_DEPTH 0xFFFF
+
+/**
+ * @brief This method simply returns the maximum memory space needed to
+ * store a remote device object. The value returned includes enough
+ * space for the framework and core device objects.
+ *
+ * @return a positive integer value indicating the size (in bytes) of the
+ * remote device object.
+ */
+U32 scif_remote_device_get_object_size(
+ void
+);
+
+/**
+ * @brief This method performs the construction common to all device object
+ * types in the framework.
+ *
+ * @note
+ * - Remote device objects in the core are a limited resource. Since
+ * the framework construction/destruction methods wrap the core, the
+ * user must ensure that a construct or destruct method is never
+ * invoked when an existing construct or destruct method is ongoing.
+ * This method shall be utilized for discovered direct attached
+ * devices.
+ * - It isn't necessary to call scif_remote_device_destruct() for
+ * device objects that have only called this method for construction.
+ * Once subsequent construction methods have been invoked (e.g.
+ * scif_remote_device_da_construct()), then destruction should occur.
+ *
+ * @param[in] domain This parameter specifies the domain in which this
+ * remote device is contained.
+ * @param[in] remote_device_memory This parameter specifies the memory
+ * location into which this method shall construct the new
+ * framework device object.
+ * @param[out] new_scif_remote_device_handle This parameter specifies the
+ * handle to be used to communicate with the newly constructed
+ * framework remote device.
+ *
+ * @return none
+ */
+void scif_remote_device_construct(
+ SCI_DOMAIN_HANDLE_T domain,
+ void * remote_device_memory,
+ SCI_REMOTE_DEVICE_HANDLE_T * new_scif_remote_device_handle
+);
+
+/**
+ * @brief This method constructs a new framework remote device object. The
+ * remote device object shall remember it's counterpart core device
+ * object as well as the domain in which it is contained.
+ *
+ * @note Remote device objects in the core are a limited resource. Since
+ * the framework construction/destruction methods wrap the core, the
+ * user must ensure that a construct or destruct method is never
+ * invoked when an existing construct or destruct method is ongoing.
+ * This method shall be utilized for discovered direct attached
+ * devices.
+ *
+ * @pre The user must have previously called scif_remote_device_construct()
+ *
+ * @param[in] remote_device This parameter specifies the framework device
+ * for which to perform direct attached specific construction.
+ * @param[in] sas_address This parameter specifies the SAS address of the
+ * remote device object being constructed.
+ * @param[in] protocols This parameter specifies the protocols supported
+ * by the remote device to be constructed.
+ *
+ * @return Indicate if the remote device was successfully constructed.
+ * @retval SCI_SUCCESS This value is returned if the remote device was
+ * successfully constructed.
+ * @retval SCI_FAILURE_DEVICE_EXISTS Returned if the device has already
+ * been constructed.
+ * @retval SCI_FAILURE_INSUFFICIENT_RESOURCES This value is returned if
+ * the core controller associated with the supplied parameters
+ * is unable to support additional remote devices.
+ */
+SCI_STATUS scif_remote_device_da_construct(
+ SCI_REMOTE_DEVICE_HANDLE_T remote_device,
+ SCI_SAS_ADDRESS_T * sas_address,
+ SCI_SAS_IDENTIFY_ADDRESS_FRAME_PROTOCOLS_T * protocols
+);
+
+/**
+ * @brief This method constructs a new framework remote device object. The
+ * remote device object shall remember it's counterpart core device
+ * object as well as the domain in which it is contained.
+ *
+ * @pre The user must have previously called scif_remote_device_construct()
+ *
+ * @note Remote device objects in the core are a limited resource. Since
+ * the framework construction/destruction methods wrap the core, the
+ * user must ensure that a construct or destruct method is never
+ * invoked when an existing construct or destruct method is ongoing.
+ * This method shall be utilized for discovered expander attached
+ * devices.
+ *
+ * @param[in] remote_device This parameter specifies the framework device
+ * for which to perform expander specific construction.
+ * @param[in] containing_device This parameter specifies the remote
+ * device (i.e. an expander) that contains the device being
+ * constructed.
+ * @param[in] smp_response This parameter specifies the SMP_RESPONSE_DISCOVER
+ * associated with the remote device being constructed.
+ *
+ * @return Indicate if the remote device was successfully constructed.
+ * @retval SCI_SUCCESS This value is returned if the remote device was
+ * successfully constructed.
+ * @retval SCI_FAILURE_DEVICE_EXISTS Returned if the device has already
+ * been constructed.
+ * @retval SCI_FAILURE_INSUFFICIENT_RESOURCES This value is returned if
+ * the core controller associated with the supplied parameters
+ * is unable to support additional remote devices.
+ */
+SCI_STATUS scif_remote_device_ea_construct(
+ SCI_REMOTE_DEVICE_HANDLE_T remote_device,
+ SCI_REMOTE_DEVICE_HANDLE_T containing_device,
+ SMP_RESPONSE_DISCOVER_T * smp_response
+);
+
+
+/**
+ * @brief This method is utilized to free up a framework's remote
+ * device object.
+ *
+ * @note Remote device objects in the core are a limited resource. Since
+ * the framework construction/destruction methods wrap the core, the
+ * user must ensure that a construct or destruct method is never
+ * invoked when an existing construct or destruct method is ongoing.
+ *
+ * @param[in] remote_device This parameter specifies the remote device to be
+ * destructed.
+ *
+ * @return The return value shall indicate if the device was successfully
+ * destructed or if some failure occurred.
+ * @retval SCI_STATUS This value is returned if the device is successfully
+ * destructed.
+ * @retval SCI_FAILURE_INVALID_REMOTE_DEVICE This value is returned if the
+ * supplied device isn't valid (e.g. it's already been destructed,
+ * the handle isn't valid, etc.).
+ */
+SCI_STATUS scif_remote_device_destruct(
+ SCI_REMOTE_DEVICE_HANDLE_T remote_device
+);
+
+/**
+ * @brief This method simply returns the SCI Core object handle that is
+ * associated with the supplied SCI Framework object.
+ *
+ * @param[in] remote_device This parameter specifies the framework device
+ * for which to return the associated core remote device.
+ *
+ * @return This method returns a handle to the core remote device object
+ * associated with the framework remote device object.
+ * @retval SCI_INVALID_HANDLE This return value indicates that the SCI Core
+ * remote device handle for the supplied framework device is invalid.
+ */
+SCI_REMOTE_DEVICE_HANDLE_T scif_remote_device_get_scic_handle(
+ SCI_REMOTE_DEVICE_HANDLE_T remote_device
+);
+
+/**
+ * @brief This method returns the maximum queue depth supported for the
+ * supplied target by this SCI Framework impementation.
+ *
+ * @param[in] remote_device This parameter specifies the framework
+ * device for which to return the maximum queue depth.
+ *
+ * @return This method returns a value indicating the maximum number of
+ * IO requests that can be outstanding for the target at any
+ * point in time.
+ * @retval SCIF_REMOTE_DEVICE_NO_MAX_QUEUE_DEPTH This value is returned
+ * when there is no defined maximum queue depth for the target.
+ */
+U16 scif_remote_device_get_max_queue_depth(
+ SCI_REMOTE_DEVICE_HANDLE_T remote_device
+);
+
+/**
+ * @brief This method will return the handle to the parent device of the
+ * remote device.
+ *
+ * @param[in] remote_device This parameter specifies the device for which
+ * to return the parent device.
+ * @param[out] containing_device This parameter specifies the device
+ * handle, from the remote device object, which indicate
+ * the parent device of the supplied remote_device.
+ *
+ * @return none
+ */
+SCI_STATUS scif_remote_device_get_containing_device(
+ SCI_REMOTE_DEVICE_HANDLE_T remote_device,
+ SCI_REMOTE_DEVICE_HANDLE_T * containing_device
+);
+
+/**
+ * @brief This method returns the number of IO currently started
+ * to the supplied target. It does not include task
+ * management requests.
+ *
+ * @param[in] remote_device This parameter specifies the framework
+ * device for which to return the number of started IO.
+ *
+ * @return This method returns a value indicating the number of started
+ * IO requests.
+ */
+U32 scif_remote_device_get_started_io_count(
+ SCI_REMOTE_DEVICE_HANDLE_T remote_device
+);
+
+#ifdef __cplusplus
+}
+#endif // __cplusplus
+
+#endif // _SCIF_REMOTE_DEVICE_H_
+
diff --git a/sys/dev/isci/scil/scif_sas_constants.h b/sys/dev/isci/scil/scif_sas_constants.h
new file mode 100644
index 0000000..88404ef
--- /dev/null
+++ b/sys/dev/isci/scil/scif_sas_constants.h
@@ -0,0 +1,79 @@
+/*-
+ * 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.
+ *
+ * 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.
+ *
+ * $FreeBSD$
+ */
+#ifndef _SCIF_SAS_CONSTANTS_H_
+#define _SCIF_SAS_CONSTANTS_H_
+
+/**
+ * @file
+ *
+ * @brief This file contains the SCU hardware constants.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif // __cplusplus
+
+#include <dev/isci/scil/sci_controller_constants.h>
+
+#if !defined(ENABLE_MINIMUM_MEMORY_MODE)
+#define SCIF_SAS_SMP_PHY_COUNT SCI_MAX_SMP_PHYS
+#else
+#define SCIF_SAS_SMP_PHY_COUNT SCI_MIN_SMP_PHYS
+#endif // !defined(ENABLE_MINIMUM_MEMORY_OPERATION)
+
+#ifdef __cplusplus
+}
+#endif // __cplusplus
+
+#endif // _SCIF_SAS_CONSTANTS_H_
diff --git a/sys/dev/isci/scil/scif_sas_controller.c b/sys/dev/isci/scil/scif_sas_controller.c
new file mode 100644
index 0000000..1f4a66e
--- /dev/null
+++ b/sys/dev/isci/scil/scif_sas_controller.c
@@ -0,0 +1,1249 @@
+/*-
+ * 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.
+ *
+ * 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 <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/**
+ * @file
+ *
+ * @brief This file contains the implementation of the SCIF_SAS_CONTROLLER
+ * object.
+ */
+
+
+#include <dev/isci/scil/sci_status.h>
+#include <dev/isci/scil/sci_util.h>
+#include <dev/isci/scil/sci_controller.h>
+#include <dev/isci/scil/scic_controller.h>
+#include <dev/isci/scil/scic_user_callback.h>
+#include <dev/isci/scil/scif_user_callback.h>
+
+#include <dev/isci/scil/scif_sas_controller.h>
+#include <dev/isci/scil/scif_sas_library.h>
+#include <dev/isci/scil/scif_sas_logger.h>
+
+
+//******************************************************************************
+//* P U B L I C M E T H O D S
+//******************************************************************************
+
+SCI_STATUS scif_controller_construct(
+ SCI_LIBRARY_HANDLE_T library,
+ SCI_CONTROLLER_HANDLE_T controller,
+ void * user_object
+)
+{
+ SCI_STATUS status = SCI_SUCCESS;
+ SCIF_SAS_LIBRARY_T * fw_library = (SCIF_SAS_LIBRARY_T*) library;
+ SCIF_SAS_CONTROLLER_T * fw_controller = (SCIF_SAS_CONTROLLER_T*) controller;
+
+ SCIF_LOG_TRACE((
+ sci_base_object_get_logger(library),
+ SCIF_LOG_OBJECT_CONTROLLER | SCIF_LOG_OBJECT_INITIALIZATION,
+ "scif_controller_construct(0x%x, 0x%x) enter\n",
+ library, controller
+ ));
+
+ // Validate the user supplied parameters.
+ if ((library == SCI_INVALID_HANDLE) || (controller == SCI_INVALID_HANDLE))
+ return SCI_FAILURE_INVALID_PARAMETER_VALUE;
+
+ // Construct the base controller. As part of constructing the base
+ // controller we ask it to also manage the MDL iteration for the Core.
+ sci_base_controller_construct(
+ &fw_controller->parent,
+ sci_base_object_get_logger(fw_library),
+ scif_sas_controller_state_table,
+ fw_controller->mdes,
+ SCIF_SAS_MAX_MEMORY_DESCRIPTORS,
+ sci_controller_get_memory_descriptor_list_handle(fw_controller->core_object)
+ );
+
+ scif_sas_controller_initialize_state_logging(fw_controller);
+
+ sci_object_set_association(fw_controller, user_object);
+
+ status = scic_controller_construct(
+ fw_library->core_object, fw_controller->core_object, fw_controller
+ );
+
+ // If the core controller was successfully constructed, then
+ // finish construction of the framework controller.
+ if (status == SCI_SUCCESS)
+ {
+ // Set the association in the core controller to this framework
+ // controller.
+ sci_object_set_association(
+ (SCI_OBJECT_HANDLE_T) fw_controller->core_object, fw_controller
+ );
+
+ sci_base_state_machine_change_state(
+ &fw_controller->parent.state_machine,
+ SCI_BASE_CONTROLLER_STATE_RESET
+ );
+ }
+
+ return status;
+}
+
+// ---------------------------------------------------------------------------
+
+SCI_STATUS scif_controller_initialize(
+ SCI_CONTROLLER_HANDLE_T controller
+)
+{
+ SCIF_SAS_CONTROLLER_T * fw_controller = (SCIF_SAS_CONTROLLER_T*) controller;
+
+ SCIF_LOG_TRACE((
+ sci_base_object_get_logger(controller),
+ SCIF_LOG_OBJECT_CONTROLLER | SCIF_LOG_OBJECT_INITIALIZATION,
+ "scif_controller_initialize(0x%x) enter\n",
+ controller
+ ));
+
+ // Validate the user supplied parameters.
+ if (controller == SCI_INVALID_HANDLE)
+ return SCI_FAILURE_INVALID_PARAMETER_VALUE;
+
+ return fw_controller->state_handlers->initialize_handler(
+ &fw_controller->parent
+ );
+}
+
+// ---------------------------------------------------------------------------
+
+U32 scif_controller_get_suggested_start_timeout(
+ SCI_CONTROLLER_HANDLE_T controller
+)
+{
+ SCIF_SAS_CONTROLLER_T * fw_controller = (SCIF_SAS_CONTROLLER_T*) controller;
+
+ // Validate the user supplied parameters.
+ if (controller == SCI_INVALID_HANDLE)
+ return 0;
+
+ // Currently we aren't adding any additional time into the suggested
+ // timeout value for the start operation. Simply utilize the core
+ // value.
+ return scic_controller_get_suggested_start_timeout(fw_controller->core_object);
+}
+
+// ---------------------------------------------------------------------------
+
+SCI_STATUS scif_controller_start(
+ SCI_CONTROLLER_HANDLE_T controller,
+ U32 timeout
+)
+{
+ SCIF_SAS_CONTROLLER_T * fw_controller = (SCIF_SAS_CONTROLLER_T*) controller;
+
+ SCIF_LOG_TRACE((
+ sci_base_object_get_logger(controller),
+ SCIF_LOG_OBJECT_CONTROLLER | SCIF_LOG_OBJECT_INITIALIZATION,
+ "scif_controller_start(0x%x, 0x%x) enter\n",
+ controller, timeout
+ ));
+
+ // Validate the user supplied parameters.
+ if (controller == SCI_INVALID_HANDLE)
+ return SCI_FAILURE_INVALID_PARAMETER_VALUE;
+
+ return fw_controller->state_handlers->
+ start_handler(&fw_controller->parent, timeout);
+}
+
+// ---------------------------------------------------------------------------
+
+SCI_STATUS scif_controller_stop(
+ SCI_CONTROLLER_HANDLE_T controller,
+ U32 timeout
+)
+{
+ SCIF_SAS_CONTROLLER_T * fw_controller = (SCIF_SAS_CONTROLLER_T*) controller;
+
+ SCIF_LOG_TRACE((
+ sci_base_object_get_logger(controller),
+ SCIF_LOG_OBJECT_CONTROLLER | SCIF_LOG_OBJECT_SHUTDOWN,
+ "scif_controller_stop(0x%x, 0x%x) enter\n",
+ controller, timeout
+ ));
+
+ // Validate the user supplied parameters.
+ if (controller == SCI_INVALID_HANDLE)
+ return SCI_FAILURE_INVALID_PARAMETER_VALUE;
+
+ return fw_controller->state_handlers->
+ stop_handler(&fw_controller->parent, timeout);
+
+}
+
+// ---------------------------------------------------------------------------
+
+SCI_STATUS scif_controller_reset(
+ SCI_CONTROLLER_HANDLE_T controller
+)
+{
+ SCIF_SAS_CONTROLLER_T * fw_controller = (SCIF_SAS_CONTROLLER_T*) controller;
+
+ SCIF_LOG_TRACE((
+ sci_base_object_get_logger(controller),
+ SCIF_LOG_OBJECT_CONTROLLER | SCIF_LOG_OBJECT_CONTROLLER_RESET,
+ "scif_controller_reset(0x%x) enter\n",
+ controller
+ ));
+
+ // Validate the user supplied parameters.
+ if (controller == SCI_INVALID_HANDLE)
+ return SCI_FAILURE_INVALID_PARAMETER_VALUE;
+
+ return fw_controller->state_handlers->
+ reset_handler(&fw_controller->parent);
+}
+
+// ---------------------------------------------------------------------------
+
+SCI_CONTROLLER_HANDLE_T scif_controller_get_scic_handle(
+ SCI_CONTROLLER_HANDLE_T controller
+)
+{
+ SCIF_SAS_CONTROLLER_T * fw_controller = (SCIF_SAS_CONTROLLER_T*) controller;
+
+ return fw_controller->core_object;
+}
+
+// ---------------------------------------------------------------------------
+
+SCI_IO_STATUS scif_controller_start_io(
+ SCI_CONTROLLER_HANDLE_T controller,
+ SCI_REMOTE_DEVICE_HANDLE_T remote_device,
+ SCI_IO_REQUEST_HANDLE_T io_request,
+ U16 io_tag
+)
+{
+ SCIF_SAS_CONTROLLER_T * fw_controller = (SCIF_SAS_CONTROLLER_T*) controller;
+
+ SCIF_LOG_TRACE((
+ sci_base_object_get_logger(controller),
+ SCIF_LOG_OBJECT_CONTROLLER | SCIF_LOG_OBJECT_IO_REQUEST,
+ "scif_controller_start_io(0x%x, 0x%x, 0x%x, 0x%x) enter\n",
+ controller, remote_device, io_request, io_tag
+ ));
+
+ if (
+ sci_pool_empty(fw_controller->hprq.pool)
+ || scif_sas_controller_sufficient_resource(controller)
+ )
+ {
+ return fw_controller->state_handlers->start_io_handler(
+ (SCI_BASE_CONTROLLER_T*) controller,
+ (SCI_BASE_REMOTE_DEVICE_T*) remote_device,
+ (SCI_BASE_REQUEST_T*) io_request,
+ io_tag
+ );
+ }
+ else
+ return SCI_FAILURE_INSUFFICIENT_RESOURCES;
+}
+
+// ---------------------------------------------------------------------------
+
+SCI_TASK_STATUS scif_controller_start_task(
+ SCI_CONTROLLER_HANDLE_T controller,
+ SCI_REMOTE_DEVICE_HANDLE_T remote_device,
+ SCI_TASK_REQUEST_HANDLE_T task_request,
+ U16 io_tag
+)
+{
+ SCIF_SAS_CONTROLLER_T * fw_controller = (SCIF_SAS_CONTROLLER_T*) controller;
+
+ SCIF_LOG_TRACE((
+ sci_base_object_get_logger(controller),
+ SCIF_LOG_OBJECT_CONTROLLER | SCIF_LOG_OBJECT_TASK_MANAGEMENT,
+ "scif_controller_start_task(0x%x, 0x%x, 0x%x, 0x%x) enter\n",
+ controller, remote_device, task_request, io_tag
+ ));
+
+ // Validate the user supplied parameters.
+ if ( (controller == SCI_INVALID_HANDLE)
+ || (remote_device == SCI_INVALID_HANDLE)
+ || (task_request == SCI_INVALID_HANDLE) )
+ {
+ return SCI_FAILURE_INVALID_PARAMETER_VALUE;
+ }
+
+ if (scif_sas_controller_sufficient_resource(controller))
+ {
+ return fw_controller->state_handlers->start_task_handler(
+ (SCI_BASE_CONTROLLER_T*) controller,
+ (SCI_BASE_REMOTE_DEVICE_T*) remote_device,
+ (SCI_BASE_REQUEST_T*) task_request,
+ io_tag
+ );
+ }
+ else
+ return SCI_FAILURE_INSUFFICIENT_RESOURCES;
+}
+
+// ---------------------------------------------------------------------------
+
+SCI_STATUS scif_controller_complete_io(
+ SCI_CONTROLLER_HANDLE_T controller,
+ SCI_REMOTE_DEVICE_HANDLE_T remote_device,
+ SCI_IO_REQUEST_HANDLE_T io_request
+)
+{
+ SCIF_SAS_CONTROLLER_T * fw_controller = (SCIF_SAS_CONTROLLER_T*) controller;
+
+ SCIF_LOG_TRACE((
+ sci_base_object_get_logger(controller),
+ SCIF_LOG_OBJECT_CONTROLLER | SCIF_LOG_OBJECT_IO_REQUEST,
+ "scif_controller_complete_io(0x%x, 0x%x, 0x%x) enter\n",
+ controller, remote_device, io_request
+ ));
+
+ return fw_controller->state_handlers->complete_io_handler(
+ (SCI_BASE_CONTROLLER_T*) controller,
+ (SCI_BASE_REMOTE_DEVICE_T*) remote_device,
+ (SCI_BASE_REQUEST_T*) io_request
+ );
+}
+
+// ---------------------------------------------------------------------------
+
+SCI_STATUS scif_controller_complete_task(
+ SCI_CONTROLLER_HANDLE_T controller,
+ SCI_REMOTE_DEVICE_HANDLE_T remote_device,
+ SCI_TASK_REQUEST_HANDLE_T task_request
+)
+{
+ SCIF_SAS_CONTROLLER_T * fw_controller = (SCIF_SAS_CONTROLLER_T*) controller;
+
+ SCIF_LOG_TRACE((
+ sci_base_object_get_logger(controller),
+ SCIF_LOG_OBJECT_CONTROLLER | SCIF_LOG_OBJECT_TASK_MANAGEMENT,
+ "scif_controller_complete_task(0x%x, 0x%x, 0x%x) enter\n",
+ controller, remote_device, task_request
+ ));
+
+ // Validate the user supplied parameters.
+ if ( (controller == SCI_INVALID_HANDLE)
+ || (remote_device == SCI_INVALID_HANDLE)
+ || (task_request == SCI_INVALID_HANDLE) )
+ {
+ return SCI_FAILURE_INVALID_PARAMETER_VALUE;
+ }
+
+ return fw_controller->state_handlers->complete_task_handler(
+ (SCI_BASE_CONTROLLER_T*) controller,
+ (SCI_BASE_REMOTE_DEVICE_T*) remote_device,
+ (SCI_BASE_REQUEST_T*) task_request
+ );
+}
+
+// ---------------------------------------------------------------------------
+
+SCI_STATUS scif_controller_get_domain_handle(
+ SCI_CONTROLLER_HANDLE_T controller,
+ U8 port_index,
+ SCI_DOMAIN_HANDLE_T * domain_handle
+)
+{
+ SCIF_SAS_CONTROLLER_T * fw_controller = (SCIF_SAS_CONTROLLER_T*) controller;
+
+ // Validate the user supplied parameters.
+ if (controller == SCI_INVALID_HANDLE)
+ return SCI_FAILURE_INVALID_PARAMETER_VALUE;
+
+ // Retrieve the domain handle if the supplied index is legitimate.
+ if (port_index < SCI_MAX_PORTS)
+ {
+ *domain_handle = &fw_controller->domains[port_index];
+ return SCI_SUCCESS;
+ }
+
+ return SCI_FAILURE_INVALID_PORT;
+}
+
+/**
+ * @brief This method builds the memory descriptor list for this
+ * controller.
+ *
+ * @param[in] fw_controller This parameter specifies the framework
+ * controller object for which to build the MDL.
+ *
+ * @return none
+ */
+void scif_sas_controller_build_mdl(
+ SCIF_SAS_CONTROLLER_T * fw_controller
+)
+{
+ // one internal request for each domain.
+ sci_base_mde_construct(
+ &fw_controller->mdes[SCIF_SAS_MDE_INTERNAL_IO],
+ 4,
+ fw_controller->internal_request_entries *
+ scif_sas_internal_request_get_object_size(),
+ SCI_MDE_ATTRIBUTE_PHYSICALLY_CONTIGUOUS
+ );
+}
+
+// ---------------------------------------------------------------------------
+
+SCI_STATUS scif_controller_set_mode(
+ SCI_CONTROLLER_HANDLE_T controller,
+ SCI_CONTROLLER_MODE mode
+)
+{
+ SCIF_SAS_CONTROLLER_T * fw_controller = (SCIF_SAS_CONTROLLER_T*) controller;
+ SCI_STATUS status = SCI_SUCCESS;
+
+ if (
+ (fw_controller->parent.state_machine.current_state_id
+ == SCI_BASE_CONTROLLER_STATE_INITIALIZING)
+ || (fw_controller->parent.state_machine.current_state_id
+ == SCI_BASE_CONTROLLER_STATE_INITIALIZED)
+ )
+ {
+ switch (mode)
+ {
+ case SCI_MODE_SPEED:
+ fw_controller->internal_request_entries =
+ MIN(fw_controller->internal_request_entries, SCIF_SAS_MAX_INTERNAL_REQUEST_COUNT);
+ scif_sas_controller_build_mdl(fw_controller);
+ break;
+
+ case SCI_MODE_SIZE:
+ fw_controller->internal_request_entries =
+ MIN(fw_controller->internal_request_entries, SCIF_SAS_MIN_INTERNAL_REQUEST_COUNT);
+ scif_sas_controller_build_mdl(fw_controller);
+ break;
+
+ default:
+ status = SCI_FAILURE_INVALID_PARAMETER_VALUE;
+ break;
+ }
+ }
+ else
+ status = SCI_FAILURE_INVALID_STATE;
+
+ if (status != SCI_SUCCESS)
+ {
+ return status;
+ }
+ else
+ {
+ // Currently, the framework doesn't change any configurations for
+ // speed or size modes. Default to speed mode basically.
+ return scic_controller_set_mode(fw_controller->core_object, mode);
+ }
+}
+
+// ---------------------------------------------------------------------------
+
+U32 scif_controller_get_sat_compliance_version(
+ void
+)
+{
+ /// @todo Fix return of SAT compliance version.
+ return 0;
+}
+
+// ---------------------------------------------------------------------------
+
+U32 scif_controller_get_sat_compliance_version_revision(
+ void
+)
+{
+ /// @todo Fix return of SAT compliance revision.
+ return 0;
+}
+
+// ---------------------------------------------------------------------------
+
+SCI_STATUS scif_user_parameters_set(
+ SCI_CONTROLLER_HANDLE_T controller,
+ SCIF_USER_PARAMETERS_T * scif_parms
+)
+{
+ SCIF_SAS_CONTROLLER_T * fw_controller = (SCIF_SAS_CONTROLLER_T*) controller;
+
+ //validate all the registry entries before overwriting the default parameter
+ //values.
+ if (scif_parms->sas.is_sata_ncq_enabled != 1 && scif_parms->sas.is_sata_ncq_enabled != 0)
+ return SCI_FAILURE_INVALID_PARAMETER_VALUE;
+
+ if (scif_parms->sas.max_ncq_depth < 1 && scif_parms->sas.max_ncq_depth > 32)
+ return SCI_FAILURE_INVALID_PARAMETER_VALUE;
+
+ if (scif_parms->sas.is_sata_standby_timer_enabled != 1
+ && scif_parms->sas.is_sata_standby_timer_enabled != 0)
+ return SCI_FAILURE_INVALID_PARAMETER_VALUE;
+
+ if (scif_parms->sas.is_non_zero_buffer_offsets_enabled != 1
+ && scif_parms->sas.is_non_zero_buffer_offsets_enabled != 0)
+ return SCI_FAILURE_INVALID_PARAMETER_VALUE;
+
+ if (scif_parms->sas.reset_type != SCI_SAS_ABORT_TASK
+ && scif_parms->sas.reset_type != SCI_SAS_ABORT_TASK_SET
+ && scif_parms->sas.reset_type != SCI_SAS_CLEAR_TASK_SET
+ && scif_parms->sas.reset_type != SCI_SAS_LOGICAL_UNIT_RESET
+ && scif_parms->sas.reset_type != SCI_SAS_I_T_NEXUS_RESET
+ && scif_parms->sas.reset_type != SCI_SAS_CLEAR_ACA
+ && scif_parms->sas.reset_type != SCI_SAS_QUERY_TASK
+ && scif_parms->sas.reset_type != SCI_SAS_QUERY_TASK_SET
+ && scif_parms->sas.reset_type != SCI_SAS_QUERY_ASYNCHRONOUS_EVENT
+ && scif_parms->sas.reset_type != SCI_SAS_HARD_RESET)
+ return SCI_FAILURE_INVALID_PARAMETER_VALUE;
+
+ if (scif_parms->sas.clear_affiliation_during_controller_stop != 1
+ && scif_parms->sas.clear_affiliation_during_controller_stop !=0)
+ return SCI_FAILURE_INVALID_PARAMETER_VALUE;
+
+ memcpy((&fw_controller->user_parameters), scif_parms, sizeof(*scif_parms));
+
+ // In the future more could be done to prevent setting parameters at the
+ // wrong time, but for now we'll simply set the values even if it is too
+ // late for them to take affect.
+ return SCI_SUCCESS;
+}
+
+// ---------------------------------------------------------------------------
+
+#if !defined(DISABLE_INTERRUPTS)
+
+/**
+ * @brief This routine check each domain of the controller to see if
+ * any domain is overriding interrupt coalescence.
+ *
+ * @param[in] fw_controller frame controller
+ * @param[in] fw_smp_phy The smp phy to be freed.
+ *
+ * @return none
+ */
+static
+BOOL scif_sas_controller_is_overriding_interrupt_coalescence(
+ SCIF_SAS_CONTROLLER_T * fw_controller
+)
+{
+ U8 index;
+
+ for(index = 0; index < SCI_MAX_DOMAINS; index++)
+ {
+ if(fw_controller->domains[index].parent.state_machine.current_state_id ==
+ SCI_BASE_DOMAIN_STATE_DISCOVERING)
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+SCI_STATUS scif_controller_set_interrupt_coalescence(
+ SCI_CONTROLLER_HANDLE_T controller,
+ U32 coalesce_number,
+ U32 coalesce_timeout
+)
+{
+ SCIF_SAS_CONTROLLER_T * fw_controller = (SCIF_SAS_CONTROLLER_T * )controller;
+
+ ///when framework is in the middle of temporarily overriding the interrupt
+ ///coalescence values, user's request of setting interrupt coalescence
+ ///will be saved. As soon as the framework done the temporary overriding,
+ ///it will serve user's request to set new interrupt coalescence.
+ if (scif_sas_controller_is_overriding_interrupt_coalescence(fw_controller))
+ {
+ U32 curr_coalesce_number;
+ U32 curr_coalesce_timeout;
+ SCI_STATUS core_status;
+
+ // save current interrupt coalescence info.
+ scic_controller_get_interrupt_coalescence (
+ fw_controller->core_object, &curr_coalesce_number, &curr_coalesce_timeout);
+
+ //try user's request out in the core, but immediately restore core's
+ //current setting.
+ core_status = scic_controller_set_interrupt_coalescence(
+ fw_controller->core_object, coalesce_number, coalesce_timeout);
+
+ if ( core_status == SCI_SUCCESS )
+ {
+ fw_controller->saved_interrupt_coalesce_number = (U16)coalesce_number;
+ fw_controller->saved_interrupt_coalesce_timeout = coalesce_timeout;
+ }
+
+ //restore current interrupt coalescence.
+ scic_controller_set_interrupt_coalescence(
+ fw_controller->core_object, curr_coalesce_number, curr_coalesce_timeout);
+
+ return core_status;
+ }
+ else
+ {
+ ///If framework is not internally overriding the interrupt coalescence,
+ ///serve user's request immediately by passing the reqeust to core.
+ return scic_controller_set_interrupt_coalescence(
+ fw_controller->core_object, coalesce_number, coalesce_timeout);
+ }
+}
+
+// ---------------------------------------------------------------------------
+
+void scif_controller_get_interrupt_coalescence(
+ SCI_CONTROLLER_HANDLE_T controller,
+ U32 * coalesce_number,
+ U32 * coalesce_timeout
+)
+{
+ SCIF_SAS_CONTROLLER_T * scif_controller = (SCIF_SAS_CONTROLLER_T * )controller;
+
+ scic_controller_get_interrupt_coalescence(
+ scif_controller->core_object, coalesce_number, coalesce_timeout);
+}
+
+/**
+ * @brief This method will save the interrupt coalescence values. If
+ * the interrupt coalescence values have already been saved,
+ * then this method performs no operations.
+ *
+ * @param[in,out] fw_controller This parameter specifies the controller
+ * for which to save the interrupt coalescence values.
+ *
+ * @return none
+ */
+void scif_sas_controller_save_interrupt_coalescence(
+ SCIF_SAS_CONTROLLER_T * fw_controller
+)
+{
+ if ( !scif_sas_controller_is_overriding_interrupt_coalescence(fw_controller))
+ {
+ // Override core's interrupt coalescing settings during SMP
+ // DISCOVER process cause' there is only 1 outstanding SMP
+ // request per domain is allowed.
+ scic_controller_get_interrupt_coalescence(
+ fw_controller->core_object,
+ (U32*)&(fw_controller->saved_interrupt_coalesce_number),
+ &(fw_controller->saved_interrupt_coalesce_timeout)
+ );
+
+ // Temporarily disable the interrupt coalescing.
+ scic_controller_set_interrupt_coalescence(fw_controller->core_object,0,0);
+ }
+}
+
+/**
+ * @brief This method will restore the interrupt coalescence values. If
+ * the interrupt coalescence values have not already been saved,
+ * then this method performs no operations.
+ *
+ * @param[in,out] fw_controller This parameter specifies the controller
+ * for which to restore the interrupt coalescence values.
+ *
+ * @return none
+ */
+void scif_sas_controller_restore_interrupt_coalescence(
+ SCIF_SAS_CONTROLLER_T * fw_controller
+)
+{
+ if ( !scif_sas_controller_is_overriding_interrupt_coalescence(fw_controller))
+ scic_controller_set_interrupt_coalescence(
+ fw_controller->core_object,
+ fw_controller->saved_interrupt_coalesce_number,
+ fw_controller->saved_interrupt_coalesce_timeout
+ );
+}
+
+#endif // !defined(DISABLE_INTERRUPTS)
+
+// ---------------------------------------------------------------------------
+
+void scic_cb_controller_start_complete(
+ SCI_CONTROLLER_HANDLE_T controller,
+ SCI_STATUS completion_status
+)
+{
+ SCIF_SAS_CONTROLLER_T *fw_controller = (SCIF_SAS_CONTROLLER_T*)
+ sci_object_get_association(controller);
+
+ SCIF_LOG_TRACE((
+ sci_base_object_get_logger(controller),
+ SCIF_LOG_OBJECT_CONTROLLER | SCIF_LOG_OBJECT_INITIALIZATION,
+ "scic_cb_controller_start_complete(0x%x, 0x%x) enter\n",
+ controller, completion_status
+ ));
+
+ if (completion_status == SCI_SUCCESS
+ || completion_status == SCI_FAILURE_TIMEOUT)
+ {
+ // Even the initialization of the core controller timed out, framework
+ // controller should still transit to READY state.
+ sci_base_state_machine_change_state(
+ &fw_controller->parent.state_machine,
+ SCI_BASE_CONTROLLER_STATE_READY
+ );
+ }
+
+ scif_cb_controller_start_complete(fw_controller, completion_status);
+}
+
+// ---------------------------------------------------------------------------
+
+void scic_cb_controller_stop_complete(
+ SCI_CONTROLLER_HANDLE_T controller,
+ SCI_STATUS completion_status
+)
+{
+ SCIF_SAS_CONTROLLER_T *fw_controller = (SCIF_SAS_CONTROLLER_T*)
+ sci_object_get_association(controller);
+
+ SCIF_LOG_TRACE((
+ sci_base_object_get_logger(controller),
+ SCIF_LOG_OBJECT_CONTROLLER | SCIF_LOG_OBJECT_SHUTDOWN,
+ "scic_cb_controller_stop_complete(0x%x, 0x%x) enter\n",
+ controller, completion_status
+ ));
+
+ if (completion_status == SCI_SUCCESS)
+ {
+ sci_base_state_machine_change_state(
+ &fw_controller->parent.state_machine,
+ SCI_BASE_CONTROLLER_STATE_STOPPED
+ );
+ }
+ else
+ {
+ sci_base_state_machine_change_state(
+ &fw_controller->parent.state_machine,
+ SCI_BASE_CONTROLLER_STATE_FAILED
+ );
+ }
+
+ scif_cb_controller_stop_complete(fw_controller, completion_status);
+}
+
+
+// ---------------------------------------------------------------------------
+
+void scic_cb_controller_error(
+ SCI_CONTROLLER_HANDLE_T controller,
+ SCI_CONTROLLER_ERROR error
+)
+{
+ SCIF_SAS_CONTROLLER_T *fw_controller = (SCIF_SAS_CONTROLLER_T*)
+ sci_object_get_association(controller);
+
+ fw_controller->parent.error = error;
+
+ SCIF_LOG_TRACE((
+ sci_base_object_get_logger(controller),
+ SCIF_LOG_OBJECT_CONTROLLER | SCIF_LOG_OBJECT_SHUTDOWN,
+ "scic_cb_controller_not_ready(0x%x) enter\n",
+ controller
+ ));
+
+ sci_base_state_machine_change_state(
+ &fw_controller->parent.state_machine,
+ SCI_BASE_CONTROLLER_STATE_FAILED
+ );
+}
+
+//******************************************************************************
+//* P R O T E C T E D M E T H O D S
+//******************************************************************************
+
+/**
+ * @brief This method is utilized to continue an internal IO operation
+ * on the controller. This method is utilized for SAT translated
+ * requests that generate multiple ATA commands in order to fulfill
+ * the original SCSI request.
+ *
+ * @param[in] controller This parameter specifies the controller on which
+ * to continue an internal IO request.
+ * @param[in] remote_device This parameter specifies the remote device
+ * on which to continue an internal IO request.
+ * @param[in] io_request This parameter specifies the IO request to be
+ * continue.
+ *
+ * @return Indicate if the continue operation was successful.
+ * @retval SCI_SUCCESS This value is returned if the operation succeeded.
+ */
+SCI_STATUS scif_sas_controller_continue_io(
+ SCI_CONTROLLER_HANDLE_T controller,
+ SCI_REMOTE_DEVICE_HANDLE_T remote_device,
+ SCI_IO_REQUEST_HANDLE_T io_request
+)
+{
+ SCIF_SAS_CONTROLLER_T * fw_controller = (SCIF_SAS_CONTROLLER_T*) controller;
+
+ return fw_controller->state_handlers->continue_io_handler(
+ (SCI_BASE_CONTROLLER_T*) controller,
+ (SCI_BASE_REMOTE_DEVICE_T*) remote_device,
+ (SCI_BASE_REQUEST_T*) io_request
+ );
+}
+
+/**
+ * @brief This method will attempt to destruct a framework controller.
+ * This includes free any resources retreived from the user (e.g.
+ * timers).
+ *
+ * @param[in] fw_controller This parameter specifies the framework
+ * controller to destructed.
+ *
+ * @return none
+ */
+void scif_sas_controller_destruct(
+ SCIF_SAS_CONTROLLER_T * fw_controller
+)
+{
+ SCIF_LOG_TRACE((
+ sci_base_object_get_logger(fw_controller),
+ SCIF_LOG_OBJECT_CONTROLLER | SCIF_LOG_OBJECT_SHUTDOWN,
+ "scif_sas_controller_destruct(0x%x) enter\n",
+ fw_controller
+ ));
+}
+
+//-----------------------------------------------------------------------------
+// INTERNAL REQUEST RELATED METHODS
+//-----------------------------------------------------------------------------
+
+/**
+ * @brief This routine is to allocate the memory for creating a new internal
+ * request.
+ *
+ * @param[in] scif_controller handle to frame controller
+ *
+ * @return void* address to internal request memory
+ */
+void * scif_sas_controller_allocate_internal_request(
+ SCIF_SAS_CONTROLLER_T * fw_controller
+)
+{
+ POINTER_UINT internal_io_address;
+
+ if( !sci_pool_empty(fw_controller->internal_request_memory_pool) )
+ {
+ sci_pool_get(
+ fw_controller->internal_request_memory_pool, internal_io_address
+ );
+
+ //clean the memory.
+ memset((char*)internal_io_address, 0, scif_sas_internal_request_get_object_size());
+
+ return (void *) internal_io_address;
+ }
+ else
+ return NULL;
+}
+
+/**
+ * @brief This routine is to free the memory for a completed internal request.
+ *
+ * @param[in] scif_controller handle to frame controller
+ * @param[in] fw_internal_io The internal IO to be freed.
+ *
+ * @return none
+ */
+void scif_sas_controller_free_internal_request(
+ SCIF_SAS_CONTROLLER_T * fw_controller,
+ void * fw_internal_request_buffer
+)
+{
+ SCIF_LOG_TRACE((
+ sci_base_object_get_logger(fw_controller),
+ SCIF_LOG_OBJECT_CONTROLLER | SCIF_LOG_OBJECT_IO_REQUEST,
+ "scif_controller_free_internal_request(0x%x, 0x%x) enter\n",
+ fw_controller, fw_internal_request_buffer
+ ));
+
+ //return the memory to to pool.
+ if( !sci_pool_full(fw_controller->internal_request_memory_pool) )
+ {
+ sci_pool_put(
+ fw_controller->internal_request_memory_pool,
+ (POINTER_UINT) fw_internal_request_buffer
+ );
+ }
+}
+
+
+/**
+ * @brief this routine is called by OS' DPC to start io requests from internal
+ * high priority request queue
+ * @param[in] fw_controller The framework controller.
+ *
+ * @return none
+ */
+void scif_sas_controller_start_high_priority_io(
+ SCIF_SAS_CONTROLLER_T * fw_controller
+)
+{
+ POINTER_UINT io_address;
+ SCIF_SAS_IO_REQUEST_T * fw_io;
+ SCI_STATUS status;
+
+ SCIF_LOG_TRACE((
+ sci_base_object_get_logger(fw_controller),
+ SCIF_LOG_OBJECT_CONTROLLER | SCIF_LOG_OBJECT_IO_REQUEST,
+ "scif_controller_start_high_priority_io(0x%x) enter\n",
+ fw_controller
+ ));
+
+ while ( !sci_pool_empty(fw_controller->hprq.pool) )
+ {
+ sci_pool_get(fw_controller->hprq.pool, io_address);
+
+ fw_io = (SCIF_SAS_IO_REQUEST_T *)io_address;
+
+ status = fw_controller->state_handlers->start_high_priority_io_handler(
+ (SCI_BASE_CONTROLLER_T*) fw_controller,
+ (SCI_BASE_REMOTE_DEVICE_T*) fw_io->parent.device,
+ (SCI_BASE_REQUEST_T*) fw_io,
+ SCI_CONTROLLER_INVALID_IO_TAG
+ );
+ }
+}
+
+/**
+ * @brief This method will check how many outstanding IOs currently and number
+ * of IOs in high priority queue, if the overall number exceeds the max_tc,
+ * return FALSE.
+ *
+ * @param[in] fw_controller The framework controller.
+ *
+ * @return BOOL Indicate whether there is sufficient resource to start an IO.
+ * @retvalue TRUE The controller has sufficient resource.
+ * @retvalue FALSE There is not sufficient resource available.
+ */
+BOOL scif_sas_controller_sufficient_resource(
+ SCIF_SAS_CONTROLLER_T *fw_controller
+)
+{
+ SCIF_SAS_DOMAIN_T * fw_domain;
+ U32 domain_index;
+ U32 outstanding_io_count = 0;
+ U32 high_priority_io_count = 0;
+
+ for(domain_index = 0; domain_index < SCI_MAX_DOMAINS; domain_index++)
+ {
+ fw_domain = &fw_controller->domains[domain_index];
+ outstanding_io_count += fw_domain->request_list.element_count;
+ }
+
+ high_priority_io_count = sci_pool_count(fw_controller->hprq.pool);
+
+ if ( (outstanding_io_count + high_priority_io_count) > SCI_MAX_IO_REQUESTS )
+ return FALSE;
+
+ return TRUE;
+}
+
+
+/**
+ * @brief This method is the starting point to complete high prority io for a
+ * controller then down to domain, device.
+ *
+ * @param[in] fw_controller The framework controller
+ * @param[in] remote_device The framework remote device.
+ * @param[in] io_request The high priority io request to be completed.
+ *
+ * @return SCI_STATUS indicate the completion status from framework down to the
+ * core.
+ */
+SCI_STATUS scif_sas_controller_complete_high_priority_io(
+ SCIF_SAS_CONTROLLER_T *fw_controller,
+ SCIF_SAS_REMOTE_DEVICE_T *remote_device,
+ SCIF_SAS_REQUEST_T *io_request
+)
+{
+ SCIF_LOG_TRACE((
+ sci_base_object_get_logger(fw_controller),
+ SCIF_LOG_OBJECT_CONTROLLER | SCIF_LOG_OBJECT_IO_REQUEST,
+ "scif_sas_controller_complete_high_priority_io(0x%x, 0x%x, 0x%x) enter\n",
+ fw_controller, remote_device, io_request
+ ));
+
+ //call controller's new added complete_high_priority_io_handler
+ return fw_controller->state_handlers->complete_high_priority_io_handler(
+ (SCI_BASE_CONTROLLER_T*) fw_controller,
+ (SCI_BASE_REMOTE_DEVICE_T*) remote_device,
+ (SCI_BASE_REQUEST_T*) io_request
+ );
+}
+
+/**
+
+ * @brief This routine is to allocate the memory for creating a smp phy object.
+ *
+ * @param[in] scif_controller handle to frame controller
+ *
+ * @return SCIF_SAS_SMP_PHY_T * An allocated space for smp phy. If failed to allocate,
+ * return NULL.
+ */
+SCIF_SAS_SMP_PHY_T * scif_sas_controller_allocate_smp_phy(
+ SCIF_SAS_CONTROLLER_T * fw_controller
+)
+{
+ SCIF_SAS_SMP_PHY_T * smp_phy;
+
+ SCIF_LOG_TRACE((
+ sci_base_object_get_logger(fw_controller),
+ SCIF_LOG_OBJECT_CONTROLLER,
+ "scif_controller_allocate_smp_phy(0x%x) enter\n",
+ fw_controller
+ ));
+
+ if( !sci_fast_list_is_empty(&fw_controller->smp_phy_memory_list) )
+ {
+ smp_phy = (SCIF_SAS_SMP_PHY_T *)
+ sci_fast_list_remove_head(&fw_controller->smp_phy_memory_list);
+
+ //clean the memory.
+ memset((char*)smp_phy,
+ 0,
+ sizeof(SCIF_SAS_SMP_PHY_T)
+ );
+
+ return smp_phy;
+ }
+ else
+ return NULL;
+}
+
+/**
+ * @brief This routine is to free the memory for a released smp phy.
+ *
+ * @param[in] fw_controller The framework controller, a smp phy is released
+ * to its memory.
+ * @param[in] fw_smp_phy The smp phy to be freed.
+ *
+ * @return none
+ */
+void scif_sas_controller_free_smp_phy(
+ SCIF_SAS_CONTROLLER_T * fw_controller,
+ SCIF_SAS_SMP_PHY_T * smp_phy
+)
+{
+ SCIF_LOG_TRACE((
+ sci_base_object_get_logger(fw_controller),
+ SCIF_LOG_OBJECT_CONTROLLER,
+ "scif_controller_free_smp_phy(0x%x, 0x%x) enter\n",
+ fw_controller, smp_phy
+ ));
+
+ //return the memory to the list.
+ sci_fast_list_insert_tail(
+ &fw_controller->smp_phy_memory_list,
+ &smp_phy->list_element
+ );
+}
+
+
+/**
+ * @brief This method clear affiliation for all the EA SATA devices associated
+ * to this controller.
+ *
+ * @param[in] fw_controller This parameter specifies the framework
+ * controller object for whose remote devices are to be stopped.
+ *
+ * @return This method returns a value indicating if the operation completed.
+ * @retval SCI_COMPLETE This value indicates that all the EA SATA devices'
+ * affiliation was cleared.
+ * @retval SCI_INCOMPLETE This value indicates clear affiliation activity is
+ * yet to be completed.
+ */
+SCI_STATUS scif_sas_controller_clear_affiliation(
+ SCIF_SAS_CONTROLLER_T * fw_controller
+)
+{
+ U8 index;
+ SCI_STATUS status;
+ SCIF_SAS_DOMAIN_T * fw_domain;
+
+ SCIF_LOG_TRACE((
+ sci_base_object_get_logger(fw_controller),
+ SCIF_LOG_OBJECT_CONTROLLER,
+ "scif_sas_controller_clear_affiliation(0x%x) enter\n",
+ fw_controller
+ ));
+
+ index = fw_controller->current_domain_to_clear_affiliation;
+
+ if (index < SCI_MAX_DOMAINS)
+ {
+ fw_domain = &fw_controller->domains[index];
+
+ //Need to stop all the on-going smp activities before clearing affiliation.
+ scif_sas_domain_cancel_smp_activities(fw_domain);
+
+ scif_sas_domain_start_clear_affiliation(fw_domain);
+
+ status = SCI_WARNING_SEQUENCE_INCOMPLETE;
+ }
+ else
+ { //the controller has done clear affiliation work to all its domains.
+ scif_sas_controller_continue_to_stop(fw_controller);
+ status = SCI_SUCCESS;
+ }
+
+ return status;
+}
+
+
+/**
+ * @brief This method sets SCIF user parameters to
+ * default values. Users can override these values utilizing
+ * the sciF_user_parameters_set() methods.
+ *
+ * @param[in] controller This parameter specifies the controller for
+ * which to set the configuration parameters to their
+ * default values.
+ *
+ * @return none
+ */
+void scif_sas_controller_set_default_config_parameters(
+ SCIF_SAS_CONTROLLER_T * this_controller
+)
+{
+ SCIF_USER_PARAMETERS_T * scif_parms = &(this_controller->user_parameters);
+
+ scif_parms->sas.is_sata_ncq_enabled = TRUE;
+ scif_parms->sas.max_ncq_depth = 32;
+ scif_parms->sas.is_sata_standby_timer_enabled = FALSE;
+ scif_parms->sas.is_non_zero_buffer_offsets_enabled = FALSE;
+ scif_parms->sas.reset_type = SCI_SAS_LOGICAL_UNIT_RESET;
+ scif_parms->sas.clear_affiliation_during_controller_stop = TRUE;
+ scif_parms->sas.ignore_fua = FALSE;
+
+}
+
+
+/**
+ * @brief This method releases resource for framework controller and associated
+ * objects.
+ *
+ * @param[in] fw_controller This parameter specifies the framework
+ * controller and associated objects whose resources are to be released.
+ *
+ * @return This method returns a value indicating if the operation succeeded.
+ * @retval SCI_SUCCESS This value indicates that resource release succeeded.
+ * @retval SCI_FAILURE This value indicates certain failure during the process
+ * of resource release.
+ */
+SCI_STATUS scif_sas_controller_release_resource(
+ SCIF_SAS_CONTROLLER_T * fw_controller
+)
+{
+ U8 index;
+ SCIF_SAS_DOMAIN_T * fw_domain;
+
+ SCIF_LOG_TRACE((
+ sci_base_object_get_logger(fw_controller),
+ SCIF_LOG_OBJECT_CONTROLLER,
+ "scif_sas_controller_release_resource(0x%x) enter\n",
+ fw_controller
+ ));
+
+ //currently the only resource to be released is domain's timer.
+ for (index = 0; index < SCI_MAX_DOMAINS; index++)
+ {
+ fw_domain = &fw_controller->domains[index];
+
+ scif_sas_domain_release_resource(fw_controller, fw_domain);
+ }
+
+ return SCI_SUCCESS;
+}
+
+
+#ifdef SCI_LOGGING
+/**
+ * This method will start state transition logging for the framework
+ * controller object.
+ *
+ * @param[in] fw_controller The framework controller object on which to
+ * observe state changes.
+ *
+ * @return none
+ */
+void scif_sas_controller_initialize_state_logging(
+ SCIF_SAS_CONTROLLER_T * fw_controller
+)
+{
+ sci_base_state_machine_logger_initialize(
+ &fw_controller->parent.state_machine_logger,
+ &fw_controller->parent.state_machine,
+ &fw_controller->parent.parent,
+ scif_cb_logger_log_states,
+ "SCIF_SAS_CONTROLLER_T", "base state machine",
+ SCIF_LOG_OBJECT_CONTROLLER
+ );
+}
+
+/**
+ * This method will remove the logging of state transitions from the framework
+ * controller object.
+ *
+ * @param[in] fw_controller The framework controller to change.
+ *
+ * @return none
+ */
+void scif_sas_controller_deinitialize_state_logging(
+ SCIF_SAS_CONTROLLER_T * fw_controller
+)
+{
+ sci_base_state_machine_logger_deinitialize(
+ &fw_controller->parent.state_machine_logger,
+ &fw_controller->parent.state_machine
+ );
+}
+#endif // SCI_LOGGING
diff --git a/sys/dev/isci/scil/scif_sas_controller.h b/sys/dev/isci/scil/scif_sas_controller.h
new file mode 100644
index 0000000..1efd00d
--- /dev/null
+++ b/sys/dev/isci/scil/scif_sas_controller.h
@@ -0,0 +1,308 @@
+/*-
+ * 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.
+ *
+ * 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.
+ *
+ * $FreeBSD$
+ */
+#ifndef _SCIF_SAS_CONTROLLER_H_
+#define _SCIF_SAS_CONTROLLER_H_
+
+/**
+ * @file
+ *
+ * @brief This file contains the protected interface structures, constants,
+ * and methods for the SCIF_SAS_CONTROLLER object.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif // __cplusplus
+
+#include <dev/isci/scil/sci_types.h>
+#include <dev/isci/scil/sci_abstract_list.h>
+#include <dev/isci/scil/sci_controller_constants.h>
+#include <dev/isci/scil/sci_memory_descriptor_list.h>
+#include <dev/isci/scil/sci_base_controller.h>
+#include <dev/isci/scil/scif_controller.h>
+#include <dev/isci/scil/scif_config_parameters.h>
+#include <dev/isci/scil/scif_sas_domain.h>
+#include <dev/isci/scil/scif_sas_io_request.h>
+#include <dev/isci/scil/scif_sas_task_request.h>
+#include <dev/isci/scil/scif_sas_constants.h>
+#include <dev/isci/scil/sci_pool.h>
+#include <dev/isci/scil/scif_sas_internal_io_request.h>
+#include <dev/isci/scil/scif_sas_high_priority_request_queue.h>
+#include <dev/isci/scil/scif_sas_smp_phy.h>
+
+
+// Currently there is only a need for 1 memory descriptor. This descriptor
+// describes the internal IO request memory.
+#define SCIF_SAS_MAX_MEMORY_DESCRIPTORS 1
+
+enum _SCIF_SAS_MAX_MEMORY_DESCRIPTORS
+{
+ SCIF_SAS_MDE_INTERNAL_IO = 0
+
+};
+
+/**
+ * @struct SCIF_SAS_CONTROLLER
+ *
+ * @brief The SCI SAS Framework controller object abstracts storage controller
+ * level behavior for the framework component.
+ */
+typedef struct SCIF_SAS_CONTROLLER
+{
+ /**
+ * The SCI_BASE_CONTROLLER is the parent object for the SCIF_SAS_CONTROLLER
+ * object.
+ */
+ SCI_BASE_CONTROLLER_T parent;
+
+ /**
+ * This field contains the handle for the SCI Core controller object that
+ * is managed by this framework controller.
+ */
+ SCI_CONTROLLER_HANDLE_T core_object;
+
+ /**
+ * This field references the list of state specific handler methods to
+ * be utilized for this controller instance.
+ */
+ SCI_BASE_CONTROLLER_STATE_HANDLER_T * state_handlers;
+
+ /**
+ * This field contains the memory desciptors defining the physical
+ * memory requirements for this controller.
+ */
+ SCI_PHYSICAL_MEMORY_DESCRIPTOR_T mdes[SCIF_SAS_MAX_MEMORY_DESCRIPTORS];
+
+ /**
+ * This field contains the SAS domain objects managed by this controller.
+ */
+ SCIF_SAS_DOMAIN_T domains[SCI_MAX_DOMAINS];
+
+ /**
+ * This field represents the pool of available remote device objects
+ * supported by the controller.
+ */
+ SCI_ABSTRACT_ELEMENT_POOL_T free_remote_device_pool;
+
+ /**
+ * This field contains the maximum number of abstract elements that
+ * can be placed in the pool.
+ */
+ SCI_ABSTRACT_ELEMENT_T remote_device_pool_elements[SCI_MAX_REMOTE_DEVICES];
+
+ /**
+ * This field provides the controller object a scratch area to indicate
+ * status of an ongoing operation.
+ */
+ SCI_STATUS operation_status;
+
+ /**
+ * This field will contain an user specified parameter information
+ * to be utilized by the framework.
+ */
+ SCIF_USER_PARAMETERS_T user_parameters;
+
+ /**
+ * This field records the index for the current domain to clear affiliation
+ * EA SATA remote devices, during the controller stop process.
+ */
+ U8 current_domain_to_clear_affiliation;
+
+ U32 internal_request_entries;
+
+ /**
+ * This field provides a pool to manage the memory resource for all internal
+ * requests.
+ * requests.
+ */
+ SCI_POOL_CREATE(
+ internal_request_memory_pool,
+ POINTER_UINT,
+ SCIF_SAS_MAX_INTERNAL_REQUEST_COUNT
+ );
+
+ /**
+ * This field provides a queue for built internal requests waiting to be
+ * started.
+ */
+ SCIF_SAS_HIGH_PRIORITY_REQUEST_QUEUE_T hprq;
+
+ /**
+ * This represents the number of available SMP phy objects that can
+ * be managed by the framework.
+ */
+ SCIF_SAS_SMP_PHY_T smp_phy_array[SCIF_SAS_SMP_PHY_COUNT];
+
+ /**
+ * This field provides a list to manage the memory resource for all
+ * smp_phy objects.
+ */
+ SCI_FAST_LIST_T smp_phy_memory_list;
+
+#if !defined(DISABLE_INTERRUPTS)
+ /**
+ * This field saves the interrupt coalescing count before changing interrupt
+ * coalescence.
+ */
+ U16 saved_interrupt_coalesce_number;
+
+ /**
+ * This field saves the interrupt coalescing timeout values in micorseconds
+ * before changing interrupt coalescence.
+ */
+ U32 saved_interrupt_coalesce_timeout;
+#endif // !defined(DISABLE_INTERRUPTS)
+
+} SCIF_SAS_CONTROLLER_T;
+
+extern SCI_BASE_STATE_T scif_sas_controller_state_table[];
+extern SCI_BASE_CONTROLLER_STATE_HANDLER_T
+ scif_sas_controller_state_handler_table[];
+
+SCI_STATUS scif_sas_controller_continue_io(
+ SCI_CONTROLLER_HANDLE_T controller,
+ SCI_REMOTE_DEVICE_HANDLE_T remote_device,
+ SCI_IO_REQUEST_HANDLE_T io_request
+);
+
+void scif_sas_controller_destruct(
+ SCIF_SAS_CONTROLLER_T * fw_controller
+);
+
+void * scif_sas_controller_allocate_internal_request(
+ SCIF_SAS_CONTROLLER_T * fw_controller
+);
+
+void scif_sas_controller_free_internal_request(
+ SCIF_SAS_CONTROLLER_T * fw_controller,
+ void * fw_internal_request_buffer
+);
+
+void scif_sas_controller_start_high_priority_io(
+ SCIF_SAS_CONTROLLER_T * fw_controller
+);
+
+BOOL scif_sas_controller_sufficient_resource(
+ SCIF_SAS_CONTROLLER_T *fw_controller
+);
+
+SCI_STATUS scif_sas_controller_complete_high_priority_io(
+ SCIF_SAS_CONTROLLER_T * fw_controller,
+ SCIF_SAS_REMOTE_DEVICE_T * remote_device,
+ SCIF_SAS_REQUEST_T * io_request
+);
+
+SCIF_SAS_SMP_PHY_T * scif_sas_controller_allocate_smp_phy(
+ SCIF_SAS_CONTROLLER_T * fw_controller
+);
+
+void scif_sas_controller_free_smp_phy(
+ SCIF_SAS_CONTROLLER_T * fw_controller,
+ SCIF_SAS_SMP_PHY_T * smp_phy
+);
+
+SCI_STATUS scif_sas_controller_clear_affiliation(
+ SCIF_SAS_CONTROLLER_T * fw_controller
+);
+
+SCI_STATUS scif_sas_controller_continue_to_stop(
+ SCIF_SAS_CONTROLLER_T * fw_controller
+);
+
+void scif_sas_controller_set_default_config_parameters(
+ SCIF_SAS_CONTROLLER_T * this_controller
+);
+
+SCI_STATUS scif_sas_controller_release_resource(
+ SCIF_SAS_CONTROLLER_T * fw_controller
+);
+
+void scif_sas_controller_build_mdl(
+ SCIF_SAS_CONTROLLER_T * fw_controller
+);
+
+#if !defined(DISABLE_INTERRUPTS)
+
+void scif_sas_controller_save_interrupt_coalescence(
+ SCIF_SAS_CONTROLLER_T * fw_controller
+);
+
+void scif_sas_controller_restore_interrupt_coalescence(
+ SCIF_SAS_CONTROLLER_T * fw_controller
+);
+
+#else // !defined(DISABLE_INTERRUPTS)
+#define scif_sas_controller_save_interrupt_coalescence(controller)
+#define scif_sas_controller_restore_interrupt_coalescence(controller)
+#endif // !defined(DISABLE_INTERRUPTS)
+
+#ifdef SCI_LOGGING
+void scif_sas_controller_initialize_state_logging(
+ SCIF_SAS_CONTROLLER_T *this_controller
+);
+
+void scif_sas_controller_deinitialize_state_logging(
+ SCIF_SAS_CONTROLLER_T *this_controller
+);
+#else // SCI_LOGGING
+#define scif_sas_controller_initialize_state_logging(x)
+#define scif_sas_controller_deinitialize_state_logging(x)
+#endif // SCI_LOGGING
+
+#ifdef __cplusplus
+}
+#endif // __cplusplus
+
+#endif // _SCIF_SAS_CONTROLLER_H_
+
diff --git a/sys/dev/isci/scil/scif_sas_controller_state_handlers.c b/sys/dev/isci/scil/scif_sas_controller_state_handlers.c
new file mode 100644
index 0000000..7cf520f
--- /dev/null
+++ b/sys/dev/isci/scil/scif_sas_controller_state_handlers.c
@@ -0,0 +1,1845 @@
+/*-
+ * 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.
+ *
+ * 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 <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/**
+ * @file
+ *
+ * @brief This file contains all of the state handler routines for each
+ * of the controller states defined by the SCI_BASE_CONTROLLER state
+ * machine.
+ */
+
+#include <dev/isci/scil/sci_util.h>
+#include <dev/isci/scil/scic_controller.h>
+#include <dev/isci/scil/scic_port.h>
+#include <dev/isci/scil/scic_remote_device.h>
+#include <dev/isci/scil/scic_io_request.h>
+
+#include <dev/isci/scil/scif_sas_controller.h>
+#include <dev/isci/scil/scif_sas_remote_device.h>
+#include <dev/isci/scil/scif_sas_logger.h>
+#include <dev/isci/scil/scif_sas_smp_remote_device.h>
+
+//******************************************************************************
+//* P R I V A T E M E T H O D S
+//******************************************************************************
+
+/**
+ * @brief This method simply executes the reset operation by entering
+ * the reset state and allowing the state to perform it's work.
+ *
+ * @param[in] fw_controller This parameter specifies the SAS framework
+ * controller for execute the reset.
+ *
+ * @return Indicate the status of the reset operation. Was it successful?
+ * @retval SCI_SUCCESS This value is returned if it was successfully reset.
+ */
+static
+SCI_STATUS scif_sas_controller_execute_reset(
+ SCIF_SAS_CONTROLLER_T * fw_controller
+)
+{
+ SCI_STATUS status;
+
+ SCIF_LOG_TRACE((
+ sci_base_object_get_logger(fw_controller),
+ SCIF_LOG_OBJECT_CONTROLLER | SCIF_LOG_OBJECT_CONTROLLER_RESET,
+ "scif_sas_controller_execute_reset(0x%x) enter\n",
+ fw_controller
+ ));
+
+ //clean the timer to avoid timer leak.
+ scif_sas_controller_release_resource(fw_controller);
+
+ sci_base_state_machine_change_state(
+ &fw_controller->parent.state_machine,
+ SCI_BASE_CONTROLLER_STATE_RESETTING
+ );
+
+ // Retrieve the status for the operations performed during the entrance
+ // to the resetting state were executing successfully.
+ status = fw_controller->operation_status;
+ fw_controller->operation_status = SCI_SUCCESS;
+
+ return status;
+}
+
+/**
+ * @brief This method checks that the memory descriptor list is valid
+ * and hasn't been corrupted in some way by the user.
+ *
+ * @param[in] fw_controller This parameter specifies the framework
+ * controller object for which to validation the MDL.
+ *
+ * @return This method returns a value indicating if the operation succeeded.
+ * @retval SCI_SUCCESS This value indicates that MDL is valid.
+ * @retval SCI_FAILURE_UNSUPPORTED_INFORMATION_FIELD This value indicates
+ * that some portion of the memory descriptor list is invalid.
+ */
+static
+SCI_STATUS scif_sas_controller_validate_mdl(
+ SCIF_SAS_CONTROLLER_T * fw_controller
+)
+{
+ BOOL is_mde_list_valid;
+
+ // Currently there is only a single MDE in the list.
+ is_mde_list_valid = sci_base_mde_is_valid(
+ &fw_controller->mdes[SCIF_SAS_MDE_INTERNAL_IO],
+ 4,
+ fw_controller->internal_request_entries *
+ scif_sas_internal_request_get_object_size(),
+ SCI_MDE_ATTRIBUTE_PHYSICALLY_CONTIGUOUS
+ );
+
+ if (is_mde_list_valid == FALSE)
+ return SCI_FAILURE_UNSUPPORTED_INFORMATION_FIELD;
+
+ return SCI_SUCCESS;
+}
+
+
+/**
+ * @brief This method stops all the domains associated to this
+ * controller.
+ *
+ * @param[in] fw_controller This parameter specifies the framework
+ * controller object for whose remote devices are to be stopped.
+ *
+ * @return This method returns a value indicating if the operation succeeded.
+ * @retval SCI_SUCCESS This value indicates that all the devices are stopped.
+ * @retval SCI_FAILURE This value indicates certain failure during the process
+ * of stopping remote devices.
+ */
+static
+SCI_STATUS scif_sas_controller_stop_domains(
+ SCIF_SAS_CONTROLLER_T * fw_controller
+)
+{
+ U8 index;
+ SCI_STATUS status = SCI_SUCCESS;
+ SCIF_SAS_DOMAIN_T * fw_domain;
+
+ SCIF_LOG_TRACE((
+ sci_base_object_get_logger(fw_controller),
+ SCIF_LOG_OBJECT_CONTROLLER,
+ "scif_sas_controller_stop_domains(0x%x) enter\n",
+ fw_controller
+ ));
+
+ for (index = 0; index < SCI_MAX_DOMAINS && status == SCI_SUCCESS; index++)
+ {
+ fw_domain = &fw_controller->domains[index];
+
+ //Change this domain to STOPPING state. All the remote devices will be
+ //stopped subsquentially.
+ if (fw_domain->parent.state_machine.current_state_id ==
+ SCI_BASE_DOMAIN_STATE_READY
+ || fw_domain->parent.state_machine.current_state_id ==
+ SCI_BASE_DOMAIN_STATE_DISCOVERING)
+ {
+ sci_base_state_machine_change_state(
+ &fw_domain->parent.state_machine, SCI_BASE_DOMAIN_STATE_STOPPING
+ );
+ }
+ }
+
+ return status;
+}
+
+
+/**
+ * @brief This method continue to stop the controller after clear affiliation
+ * is done.
+ *
+ * @param[in] fw_controller This parameter specifies the framework
+ * controller object to be stopped.
+ *
+ * @return This method returns a value indicating if the operation succeeded.
+ * @retval SCI_SUCCESS This value indicates the controller_stop succeeds.
+ * @retval SCI_FAILURE This value indicates certain failure during the process
+ * of stopping controller.
+ */
+SCI_STATUS scif_sas_controller_continue_to_stop(
+ SCIF_SAS_CONTROLLER_T * fw_controller
+)
+{
+ SCI_STATUS status;
+
+ SCIF_LOG_TRACE((
+ sci_base_object_get_logger(fw_controller),
+ SCIF_LOG_OBJECT_CONTROLLER | SCIF_LOG_OBJECT_SHUTDOWN,
+ "scif_sas_controller_continue_to_stop (0x%x).\n",
+ fw_controller
+ ));
+
+ //stop all the domains and their remote devices.
+ status = scif_sas_controller_stop_domains(fw_controller);
+
+ if (status == SCI_SUCCESS)
+ {
+ // Attempt to stop the core controller.
+ status = scic_controller_stop(fw_controller->core_object, 0);
+
+ if (status != SCI_SUCCESS)
+ {
+ SCIF_LOG_ERROR((
+ sci_base_object_get_logger(fw_controller),
+ SCIF_LOG_OBJECT_CONTROLLER | SCIF_LOG_OBJECT_SHUTDOWN,
+ "Controller:0x%x Status:0x%x unable to stop controller.\n",
+ fw_controller, status
+ ));
+
+ sci_base_state_machine_change_state(
+ &fw_controller->parent.state_machine,
+ SCI_BASE_CONTROLLER_STATE_FAILED
+ );
+ }
+ }
+ else
+ {
+ SCIF_LOG_ERROR((
+ sci_base_object_get_logger(fw_controller),
+ SCIF_LOG_OBJECT_CONTROLLER | SCIF_LOG_OBJECT_SHUTDOWN,
+ "Controller:0x%x Status:0x%x unable to stop domains.\n",
+ fw_controller, status
+ ));
+
+ sci_base_state_machine_change_state(
+ &fw_controller->parent.state_machine,
+ SCI_BASE_CONTROLLER_STATE_FAILED
+ );
+ }
+
+ return status;
+}
+
+
+//******************************************************************************
+//* R E S E T H A N D L E R S
+//******************************************************************************
+
+/**
+ * @brief This method provides RESET state specific handling for
+ * when a user attempts to initialize a controller. This is a legal
+ * state in which to attempt an initialize call.
+ *
+ * @param[in] controller This parameter specifies the controller object
+ * on which the user is attempting to perform an initialize
+ * operation.
+ *
+ * @return This method returns an indication of whether the initialize
+ * operation succeeded.
+ * @retval SCI_SUCCESS This value when the initialization completes
+ * successfully.
+ */
+static
+SCI_STATUS scif_sas_controller_reset_initialize_handler(
+ SCI_BASE_CONTROLLER_T * controller
+)
+{
+ SCIF_SAS_CONTROLLER_T * fw_controller = (SCIF_SAS_CONTROLLER_T *)controller;
+ SCI_STATUS status;
+ U32 index;
+
+ SCIF_LOG_TRACE((
+ sci_base_object_get_logger(fw_controller),
+ SCIF_LOG_OBJECT_CONTROLLER | SCIF_LOG_OBJECT_INITIALIZATION,
+ "scif_sas_controller_reset_initialize_handler(0x%x) enter\n",
+ controller
+ ));
+
+ sci_base_state_machine_change_state(
+ &fw_controller->parent.state_machine,
+ SCI_BASE_CONTROLLER_STATE_INITIALIZING
+ );
+
+ scif_sas_controller_build_mdl(fw_controller);
+
+ // Perform any domain object initialization that is necessary.
+ for (index = 0; index < SCI_MAX_DOMAINS; index++)
+ scif_sas_domain_initialize(&fw_controller->domains[index]);
+
+ scif_cb_lock_associate(fw_controller, &fw_controller->hprq.lock);
+
+ // Attempt to initialize the core controller.
+ status = scic_controller_initialize(fw_controller->core_object);
+ if (status == SCI_SUCCESS)
+ {
+ sci_base_state_machine_change_state(
+ &fw_controller->parent.state_machine,
+ SCI_BASE_CONTROLLER_STATE_INITIALIZED
+ );
+ }
+
+ if (status != SCI_SUCCESS)
+ {
+ // Initialization failed, Release resources and do not change state
+ scif_sas_controller_release_resource(fw_controller);
+
+ SCIF_LOG_ERROR((
+ sci_base_object_get_logger(fw_controller),
+ SCIF_LOG_OBJECT_CONTROLLER | SCIF_LOG_OBJECT_INITIALIZATION,
+ "Controller:0x%x Status:0x%x unable to successfully initialize.\n",
+ fw_controller, status
+ ));
+ }
+
+ return status;
+}
+
+//******************************************************************************
+//* I N I T I A L I Z E D H A N D L E R S
+//******************************************************************************
+
+/**
+ * @brief This method provides INITIALIZED state specific handling for
+ * when a user attempts to start a controller.
+ *
+ * @param[in] controller This parameter specifies the controller object
+ * on which the user is attempting to perform a start
+ * operation.
+ * @param[in] timeout This parameter specifies the timeout value (in
+ * milliseconds) to be utilized for this operation.
+ *
+ * @return This method returns an indication of whether the start operation
+ * succeeded.
+ * @retval SCI_SUCCESS This value is returned when the start operation
+ * begins successfully.
+ */
+static
+SCI_STATUS scif_sas_controller_initialized_start_handler(
+ SCI_BASE_CONTROLLER_T * controller,
+ U32 timeout
+)
+{
+ SCI_STATUS status = SCI_SUCCESS;
+ SCIF_SAS_CONTROLLER_T * fw_controller = (SCIF_SAS_CONTROLLER_T *)controller;
+ U16 index = 0;
+
+ SCI_PHYSICAL_MEMORY_DESCRIPTOR_T internal_reqeust_mde =
+ fw_controller->mdes[SCIF_SAS_MDE_INTERNAL_IO];
+
+ void * internal_request_virtual_address = internal_reqeust_mde.virtual_address;
+ POINTER_UINT address = (POINTER_UINT)internal_request_virtual_address;
+
+ SCIF_LOG_TRACE((
+ sci_base_object_get_logger(fw_controller),
+ SCIF_LOG_OBJECT_CONTROLLER | SCIF_LOG_OBJECT_INITIALIZATION,
+ "scif_sas_controller_initialized_start_handler(0x%x, 0x%x) enter\n",
+ controller, timeout
+ ));
+
+ sci_base_state_machine_change_state(
+ &fw_controller->parent.state_machine,
+ SCI_BASE_CONTROLLER_STATE_STARTING
+ );
+
+ status = scif_sas_controller_validate_mdl(fw_controller);
+
+ // initialization work for internal request path. It must be done before
+ // starting domain.
+ if (status == SCI_SUCCESS)
+ {
+ // fill in the sci_pool for internal requests.
+ sci_pool_initialize(fw_controller->internal_request_memory_pool);
+
+ for (index = 0; index < fw_controller->internal_request_entries; index++)
+ {
+ sci_pool_put(fw_controller->internal_request_memory_pool, address);
+
+ address += scif_sas_internal_request_get_object_size();
+ }
+
+ // Using DPC for starting internal IOs, if yes, we need to intialize
+ // DPC here.
+ scif_cb_start_internal_io_task_create(fw_controller);
+ }
+
+ if (status == SCI_SUCCESS)
+ {
+ // Kick-start the domain state machines and, by association, the
+ // core port's.
+
+ // This will ensure we get valid port objects supplied with link up
+ // messages.
+ for (index = 0;
+ (index < SCI_MAX_DOMAINS) && (status == SCI_SUCCESS);
+ index++)
+ {
+ sci_base_state_machine_change_state(
+ &fw_controller->domains[index].parent.state_machine,
+ SCI_BASE_DOMAIN_STATE_STARTING
+ );
+ status = fw_controller->domains[index].operation.status;
+ }
+ }
+
+ // Validate that all the domain state machines began successfully.
+ if (status != SCI_SUCCESS)
+ {
+ SCIF_LOG_ERROR((
+ sci_base_object_get_logger(fw_controller),
+ SCIF_LOG_OBJECT_CONTROLLER | SCIF_LOG_OBJECT_INITIALIZATION,
+ "Controller:0x%x Domain:0x%x Status:0x%x unable to start\n",
+ fw_controller, index, status
+ ));
+
+ return status;
+ }
+
+ // Attempt to start the core controller.
+ status = scic_controller_start(fw_controller->core_object, timeout);
+ if (status != SCI_SUCCESS)
+ {
+ SCIF_LOG_ERROR((
+ sci_base_object_get_logger(fw_controller),
+ SCIF_LOG_OBJECT_CONTROLLER | SCIF_LOG_OBJECT_INITIALIZATION,
+ "Controller:0x%x Status:0x%x unable to start controller.\n",
+ fw_controller, status
+ ));
+
+ sci_base_state_machine_change_state(
+ &fw_controller->parent.state_machine,
+ SCI_BASE_CONTROLLER_STATE_FAILED
+ );
+ }
+
+ return status;
+}
+
+//******************************************************************************
+//* R E A D Y H A N D L E R S
+//******************************************************************************
+
+/**
+ * @brief This method provides READY state specific handling for
+ * when a user attempts to stop a controller.
+ *
+ * @param[in] controller This parameter specifies the controller object
+ * on which the user is attempting to perform a stop
+ * operation.
+ * @param[in] timeout This parameter specifies the timeout value (in
+ * milliseconds) to be utilized for this operation.
+ *
+ * @return This method returns an indication of whether the stop operation
+ * succeeded.
+ * @retval SCI_SUCCESS This value is returned when the stop operation
+ * begins successfully.
+ */
+static
+SCI_STATUS scif_sas_controller_ready_stop_handler(
+ SCI_BASE_CONTROLLER_T * controller,
+ U32 timeout
+)
+{
+ SCIF_SAS_CONTROLLER_T * fw_controller = (SCIF_SAS_CONTROLLER_T *)controller;
+
+ SCIF_LOG_TRACE((
+ sci_base_object_get_logger(fw_controller),
+ SCIF_LOG_OBJECT_CONTROLLER | SCIF_LOG_OBJECT_INITIALIZATION,
+ "scif_sas_controller_ready_stop_handler(0x%x, 0x%x) enter\n",
+ controller, timeout
+ ));
+
+ sci_base_state_machine_change_state(
+ &fw_controller->parent.state_machine,
+ SCI_BASE_CONTROLLER_STATE_STOPPING
+ );
+
+ if (fw_controller->user_parameters.sas.clear_affiliation_during_controller_stop)
+ {
+ fw_controller->current_domain_to_clear_affiliation = 0;
+
+ //clear affiliation first. After the last domain finishes clearing
+ //affiliation, it will call back to controller to continue to stop.
+ scif_sas_controller_clear_affiliation(fw_controller);
+ }
+ else
+ scif_sas_controller_continue_to_stop(fw_controller);
+
+ //Must return SUCCESS at this point.
+ return SCI_SUCCESS;
+}
+
+/**
+ * @brief This method provides READY state specific handling for
+ * when a user attempts to reset a controller.
+ *
+ * @param[in] controller This parameter specifies the controller object
+ * on which the user is attempting to perform a reset
+ * operation.
+ *
+ * @return This method returns an indication of whether the reset operation
+ * succeeded.
+ * @retval SCI_SUCCESS This value is returned when the reset operation
+ * completes successfully.
+ */
+static
+SCI_STATUS scif_sas_controller_ready_reset_handler(
+ SCI_BASE_CONTROLLER_T * controller
+)
+{
+ return scif_sas_controller_execute_reset((SCIF_SAS_CONTROLLER_T*)controller);
+}
+
+/**
+ * @brief This method provides READY state specific handling for
+ * when a user attempts to start an IO request.
+ *
+ * @param[in] controller This parameter specifies the controller object
+ * on which the user is attempting to perform a start IO
+ * operation.
+ * @param[in] remote_device This parameter specifies the remote deivce
+ * object on which the user is attempting to perform a start IO
+ * operation.
+ * @param[in] io_request This parameter specifies the IO request to be
+ * started.
+ * @param[in] io_tag This parameter specifies the optional allocated
+ * IO tag. Please reference scif_controller_start_io() for
+ * more information.
+ *
+ * @return This method returns an indication of whether the start IO
+ * operation succeeded.
+ * @retval SCI_SUCCESS This value is returned when the start IO operation
+ * begins successfully.
+ */
+static
+SCI_STATUS scif_sas_controller_ready_start_io_handler(
+ SCI_BASE_CONTROLLER_T * controller,
+ SCI_BASE_REMOTE_DEVICE_T * remote_device,
+ SCI_BASE_REQUEST_T * io_request,
+ U16 io_tag
+)
+{
+ SCI_STATUS status;
+ SCIF_SAS_IO_REQUEST_T *fw_io = (SCIF_SAS_IO_REQUEST_T*)io_request;
+ SCIF_SAS_CONTROLLER_T *fw_controller = (SCIF_SAS_CONTROLLER_T*)controller;
+ SCIF_SAS_REMOTE_DEVICE_T *fw_device = (SCIF_SAS_REMOTE_DEVICE_T*)
+ remote_device;
+
+ SCIF_LOG_TRACE((
+ sci_base_object_get_logger(fw_controller),
+ SCIF_LOG_OBJECT_CONTROLLER | SCIF_LOG_OBJECT_IO_REQUEST,
+ "scif_sas_controller_ready_start_io_handler(0x%x, 0x%x, 0x%x, 0x%x) enter\n",
+ controller, remote_device, io_request, io_tag
+ ));
+
+ status = fw_device->domain->state_handlers->start_io_handler(
+ &fw_device->domain->parent, remote_device, io_request
+ );
+
+ // Check to see that the other objects in the framework allowed
+ // this IO to be started.
+ if (status == SCI_SUCCESS)
+ {
+ // Ask the core to start processing for this IO request.
+ status = scic_controller_start_io(
+ fw_controller->core_object,
+ fw_device->core_object,
+ fw_io->parent.core_object,
+ io_tag
+ );
+
+ if (status == SCI_SUCCESS)
+ {
+ // We were able to start the core request. As a result,
+ // commit to starting the request for the framework by changing
+ // the state of the IO request.
+ sci_base_state_machine_change_state(
+ &io_request->state_machine, SCI_BASE_REQUEST_STATE_STARTED
+ );
+ }
+ else
+ {
+ // We were unable to start the core IO request. As a result,
+ // back out the start operation for the framework. It's easier to
+ // back out the framework start operation then to backout the core
+ // start IO operation.
+ fw_device->domain->state_handlers->complete_io_handler(
+ &fw_device->domain->parent, remote_device, io_request
+ );
+
+ // Invoke the IO completion handler. For most IOs, this does nothing
+ // since we are still in the constructed state. For NCQ, this will
+ // the return of the NCQ tag back to the remote device free pool.
+ fw_io->parent.state_handlers->complete_handler(io_request);
+
+ SCIF_LOG_WARNING((
+ sci_base_object_get_logger(fw_controller),
+ SCIF_LOG_OBJECT_CONTROLLER,
+ "Controller:0x%x IORequest:0x%x Status:0x%x core IO start failed\n",
+ fw_controller, fw_io, status
+ ));
+ }
+ }
+ else
+ {
+ SCIF_LOG_WARNING((
+ sci_base_object_get_logger(fw_controller),
+ SCIF_LOG_OBJECT_CONTROLLER,
+ "Controller:0x%x IORequest:0x%x Status:0x%x IO start failed\n",
+ fw_controller, fw_io, status
+ ));
+ }
+
+ return status;
+}
+
+/**
+ * @brief This method provides READY state specific handling for
+ * when a user attempts to complete an IO request.
+ *
+ * @param[in] controller This parameter specifies the controller object
+ * on which the user is attempting to perform a complete IO
+ * operation.
+ * @param[in] remote_device This parameter specifies the remote deivce
+ * object on which the user is attempting to perform a start IO
+ * operation.
+ * @param[in] io_request This parameter specifies the IO request to be
+ * started.
+ *
+ * @return This method returns an indication of whether the complete IO
+ * operation succeeded.
+ * @retval SCI_SUCCESS This value is returned when the complete IO operation
+ * begins successfully.
+ */
+static
+SCI_STATUS scif_sas_controller_ready_complete_io_handler(
+ SCI_BASE_CONTROLLER_T * controller,
+ SCI_BASE_REMOTE_DEVICE_T * remote_device,
+ SCI_BASE_REQUEST_T * io_request
+)
+{
+ SCIF_SAS_CONTROLLER_T * fw_controller = (SCIF_SAS_CONTROLLER_T*)
+ controller;
+ SCIF_SAS_REMOTE_DEVICE_T * fw_device = (SCIF_SAS_REMOTE_DEVICE_T*)
+ remote_device;
+ SCIF_SAS_IO_REQUEST_T * fw_io = (SCIF_SAS_IO_REQUEST_T*)
+ io_request;
+ SCI_STATUS status;
+ SCI_STATUS core_status;
+
+ SCIF_LOG_TRACE((
+ sci_base_object_get_logger(fw_controller),
+ SCIF_LOG_OBJECT_CONTROLLER | SCIF_LOG_OBJECT_IO_REQUEST,
+ "scif_sas_controller_ready_complete_io_handler(0x%x, 0x%x, 0x%x) enter\n",
+ controller, remote_device, io_request
+ ));
+
+ fw_io->parent.state_handlers->destruct_handler(&fw_io->parent.parent);
+ status = fw_device->domain->state_handlers->complete_io_handler(
+ &fw_device->domain->parent, remote_device, io_request
+ );
+
+ // Ask the core to finish processing for this IO request.
+ core_status = scic_controller_complete_io(
+ fw_controller->core_object,
+ fw_device->core_object,
+ fw_io->parent.core_object
+ );
+
+ if (status == SCI_SUCCESS)
+ status = core_status;
+
+ if (status != SCI_SUCCESS)
+ {
+ SCIF_LOG_WARNING((
+ sci_base_object_get_logger(fw_controller),
+ SCIF_LOG_OBJECT_CONTROLLER,
+ "Controller:0x%x IORequest:0x%x Status:0x%x CoreStatus:0x%x "
+ "failure to complete IO\n",
+ fw_controller, fw_io, status, core_status
+ ));
+ }
+
+ return status;
+}
+
+
+/**
+ * @brief This method provides READY state specific handling for
+ * when a user attempts to complete a high priority IO request.
+ *
+ * @param[in] controller This parameter specifies the controller object
+ * on which the user is attempting to perform a complete IO
+ * operation.
+ * @param[in] remote_device This parameter specifies the remote deivce
+ * object on which the user is attempting to perform a start IO
+ * operation.
+ * @param[in] io_request This parameter specifies the IO request to be
+ * started.
+ *
+ * @return This method returns an indication of whether the complete IO
+ * operation succeeded.
+ * @retval SCI_SUCCESS This value is returned when the complete IO operation
+ * begins successfully.
+ */
+static
+SCI_STATUS scif_sas_controller_ready_complete_high_priority_io_handler(
+ SCI_BASE_CONTROLLER_T * controller,
+ SCI_BASE_REMOTE_DEVICE_T * remote_device,
+ SCI_BASE_REQUEST_T * io_request
+)
+{
+ SCIF_SAS_CONTROLLER_T * fw_controller = (SCIF_SAS_CONTROLLER_T*)
+ controller;
+ SCIF_SAS_REMOTE_DEVICE_T * fw_device = (SCIF_SAS_REMOTE_DEVICE_T*)
+ remote_device;
+ SCIF_SAS_IO_REQUEST_T * fw_io = (SCIF_SAS_IO_REQUEST_T*)
+ io_request;
+ SCI_IO_STATUS core_completion_status =
+ scic_request_get_sci_status(fw_io->parent.core_object);
+
+ U8 response_data[SCIF_SAS_RESPONSE_DATA_LENGTH];
+
+ SCI_STATUS status;
+ SCI_STATUS core_status;
+
+ SCIF_LOG_TRACE((
+ sci_base_object_get_logger(fw_controller),
+ SCIF_LOG_OBJECT_CONTROLLER | SCIF_LOG_OBJECT_IO_REQUEST,
+ "scif_sas_controller_ready_complete_high_priority_io_handler(0x%x, 0x%x, 0x%x) enter\n",
+ controller, remote_device, io_request
+ ));
+
+ // In high priority path, we ask the core to finish IO request before framework.
+
+ // retrieve and save io response from core now.
+ memcpy(response_data,
+ scic_io_request_get_response_iu_address(fw_io->parent.core_object),
+ SCIF_SAS_RESPONSE_DATA_LENGTH
+ );
+
+ core_status = scic_controller_complete_io(
+ fw_controller->core_object,
+ fw_device->core_object,
+ fw_io->parent.core_object
+ );
+
+ fw_io->parent.state_handlers->destruct_handler(&fw_io->parent.parent);
+ status = fw_device->domain->state_handlers->complete_high_priority_io_handler(
+ &fw_device->domain->parent,
+ remote_device,
+ io_request,
+ (void *)response_data,
+ core_completion_status
+ );
+
+ if (status == SCI_SUCCESS)
+ status = core_status;
+
+ if (status == SCI_SUCCESS)
+ {
+ //issue DPC to start next internal io in high prioriy queue.
+ if( !sci_pool_empty(fw_controller->hprq.pool) )
+ scif_cb_start_internal_io_task_schedule(
+ fw_controller,
+ scif_sas_controller_start_high_priority_io,
+ fw_controller
+ );
+ }
+ else
+ {
+ SCIF_LOG_WARNING((
+ sci_base_object_get_logger(fw_controller),
+ SCIF_LOG_OBJECT_CONTROLLER,
+ "Controller:0x%x IORequest:0x%x Status:0x%x CoreStatus:0x%x "
+ "failure to complete IO\n",
+ fw_controller, fw_io, status, core_status
+ ));
+ }
+
+ return status;
+}
+
+/**
+ * @brief This method provides READY state specific handling for
+ * when a user attempts to continue an IO request.
+ *
+ * @param[in] controller This parameter specifies the controller object
+ * on which the user is attempting to perform a continue IO
+ * operation.
+ * @param[in] remote_device This parameter specifies the remote deivce
+ * object on which the user is attempting to perform a start IO
+ * operation.
+ * @param[in] io_request This parameter specifies the IO request to be
+ * started.
+ *
+ * @return This method returns an indication of whether the continue IO
+ * operation succeeded.
+ * @retval SCI_SUCCESS This value is returned when the continue IO operation
+ * begins successfully.
+ */
+static
+SCI_STATUS scif_sas_controller_ready_continue_io_handler(
+ SCI_BASE_CONTROLLER_T * controller,
+ SCI_BASE_REMOTE_DEVICE_T * remote_device,
+ SCI_BASE_REQUEST_T * io_request
+)
+{
+ SCIF_LOG_TRACE((
+ sci_base_object_get_logger(controller),
+ SCIF_LOG_OBJECT_CONTROLLER | SCIF_LOG_OBJECT_IO_REQUEST,
+ "scif_sas_controller_ready_continue_io_handler(0x%x, 0x%x, 0x%x) enter\n",
+ controller, remote_device, io_request
+ ));
+
+ /// @todo Function unimplemented. fix return code handling.
+ return SCI_FAILURE;
+}
+
+/**
+ * @brief This method provides READY state specific handling for
+ * when a user attempts to start a task request.
+ *
+ * @param[in] controller This parameter specifies the controller object
+ * on which the user is attempting to perform a start task
+ * operation.
+ * @param[in] remote_device This parameter specifies the remote deivce
+ * object on which the user is attempting to perform a start
+ * task operation.
+ * @param[in] task_request This parameter specifies the task management
+ * request to be started.
+ * @param[in] io_tag This parameter specifies the optional allocated
+ * IO tag. Please reference scif_controller_start_task() for
+ * more information.
+ *
+ * @return This method returns an indication of whether the start task
+ * operation succeeded.
+ * @retval SCI_SUCCESS This value is returned when the start task operation
+ * begins successfully.
+ */
+static
+SCI_STATUS scif_sas_controller_ready_start_task_handler(
+ SCI_BASE_CONTROLLER_T * controller,
+ SCI_BASE_REMOTE_DEVICE_T * remote_device,
+ SCI_BASE_REQUEST_T * task_request,
+ U16 io_tag
+)
+{
+ SCIF_SAS_CONTROLLER_T * fw_controller = (SCIF_SAS_CONTROLLER_T*)
+ controller;
+ SCIF_SAS_REMOTE_DEVICE_T * fw_device = (SCIF_SAS_REMOTE_DEVICE_T*)
+ remote_device;
+ SCIF_SAS_TASK_REQUEST_T * fw_task = (SCIF_SAS_TASK_REQUEST_T*)task_request;
+ SCI_STATUS status;
+
+ SCIF_LOG_TRACE((
+ sci_base_object_get_logger(fw_controller),
+ SCIF_LOG_OBJECT_CONTROLLER | SCIF_LOG_OBJECT_TASK_MANAGEMENT,
+ "scif_sas_controller_ready_start_task_handler(0x%x, 0x%x, 0x%x, 0x%x) enter\n",
+ controller, remote_device, task_request, io_tag
+ ));
+
+ status = fw_device->domain->state_handlers->start_task_handler(
+ &fw_device->domain->parent, remote_device, task_request
+ );
+
+ if (status == SCI_SUCCESS)
+ {
+ if (scif_sas_task_request_get_function(fw_task)
+ == SCI_SAS_HARD_RESET)
+ {
+ // Go off to special target reset path. Don't start task to core.
+ scif_sas_remote_device_target_reset(
+ fw_device,
+ (SCIF_SAS_REQUEST_T *)fw_task
+ );
+
+ return SCI_SUCCESS;
+ }
+
+ // Ask the core to start processing for this task request.
+ status = scic_controller_start_task(
+ fw_controller->core_object,
+ fw_device->core_object,
+ fw_task->parent.core_object,
+ io_tag
+ );
+
+ if (status == SCI_SUCCESS)
+ {
+ // We were able to start the core request. As a result,
+ // commit to starting the request for the framework by changing
+ // the state of the task request.
+ fw_task->parent.state_handlers->start_handler(&fw_task->parent.parent);
+ }
+ else
+ {
+ // We were unable to start the core task request. As a result,
+ // back out the start operation for the framework. It's easier to
+ // back out the framework start operation then to backout the core
+ // start task operation.
+ fw_device->domain->state_handlers->complete_task_handler(
+ &fw_device->domain->parent, remote_device, task_request
+ );
+
+ if (status == SCI_SUCCESS)
+ {
+ SCIF_LOG_WARNING((
+ sci_base_object_get_logger(fw_controller),
+ SCIF_LOG_OBJECT_CONTROLLER,
+ "Controller:0x%x TaskRequest:0x%x Status:0x%x core start failed\n",
+ fw_controller, fw_task, status
+ ));
+ }
+ }
+ }
+ else
+ {
+ SCIF_LOG_WARNING((
+ sci_base_object_get_logger(fw_controller),
+ SCIF_LOG_OBJECT_CONTROLLER,
+ "Controller:0x%x TaskRequest:0x%x Status:0x%x Task start failed\n",
+ fw_controller, fw_task, status
+ ));
+ }
+
+ return status;
+}
+
+/**
+ * @brief This method provides READY state specific handling for
+ * when a user attempts to complete a task request.
+ *
+ * @param[in] controller This parameter specifies the controller object
+ * on which the user is attempting to perform a complete task
+ * operation.
+ * @param[in] remote_device This parameter specifies the remote deivce
+ * object on which the user is attempting to perform a start
+ * task operation.
+ * @param[in] task_request This parameter specifies the task management
+ * request to be started.
+ *
+ * @return This method returns an indication of whether the complete task
+ * operation succeeded.
+ * @retval SCI_SUCCESS This value is returned when the complete task operation
+ * begins successfully.
+ */
+static
+SCI_STATUS scif_sas_controller_ready_complete_task_handler(
+ SCI_BASE_CONTROLLER_T * controller,
+ SCI_BASE_REMOTE_DEVICE_T * remote_device,
+ SCI_BASE_REQUEST_T * task_request
+)
+{
+ SCIF_SAS_CONTROLLER_T *fw_controller = (SCIF_SAS_CONTROLLER_T*)controller;
+ SCIF_SAS_REMOTE_DEVICE_T *fw_device = (SCIF_SAS_REMOTE_DEVICE_T*)remote_device;
+ SCIF_SAS_TASK_REQUEST_T *fw_task = (SCIF_SAS_TASK_REQUEST_T*)task_request;
+ SCI_STATUS status;
+ SCI_STATUS core_status;
+
+ SCIF_LOG_TRACE((
+ sci_base_object_get_logger(fw_controller),
+ SCIF_LOG_OBJECT_CONTROLLER | SCIF_LOG_OBJECT_TASK_MANAGEMENT,
+ "scif_sas_controller_ready_complete_task_handler(0x%x, 0x%x, 0x%x) enter\n",
+ controller, remote_device, task_request
+ ));
+
+ status = fw_device->domain->state_handlers->complete_task_handler(
+ &fw_device->domain->parent, remote_device, task_request
+ );
+
+ if (scif_sas_task_request_get_function(fw_task)
+ == SCI_SAS_HARD_RESET)
+ {
+ //No more things to do in the core, since this task is for Target Reset.
+ return status;
+ }
+
+ fw_task->parent.state_handlers->destruct_handler(&fw_task->parent.parent);
+
+ // Ask the core to finish processing for this task request.
+ core_status = scic_controller_complete_task(
+ fw_controller->core_object,
+ fw_device->core_object,
+ fw_task->parent.core_object
+ );
+
+ if (status == SCI_SUCCESS)
+ status = core_status;
+
+ if (status != SCI_SUCCESS)
+ {
+ SCIF_LOG_WARNING((
+ sci_base_object_get_logger(fw_controller),
+ SCIF_LOG_OBJECT_CONTROLLER,
+ "Controller:0x%x TaskRequest:0x%x Status:0x%x CoreStatus:0x%x "
+ "failed to complete\n",
+ fw_controller, fw_task, status, core_status
+ ));
+ }
+
+ return status;
+}
+
+
+
+/**
+ * @brief This method provides common handling for several states
+ * when a user attempts to start an internal request.
+ *
+ * @param[in] controller This parameter specifies the controller object
+ * on which the user is attempting to perform a start IO
+ * operation.
+ * @param[in] remote_device This parameter specifies the remote deivce
+ * object on which the user is attempting to perform a start IO
+ * operation.
+ * @param[in] io_request This parameter specifies the IO request to be
+ * started.
+ * @param[in] io_tag This parameter specifies the optional allocated
+ * IO tag. Please reference scif_controller_start_io() for
+ * more information.
+ *
+ * @return This method returns an indication of whether the start IO
+ * operation succeeded.
+ * @retval SCI_SUCCESS This value is returned when the start IO operation
+ * begins successfully.
+ */
+static
+SCI_STATUS scif_sas_controller_common_start_high_priority_io_handler(
+ SCI_BASE_CONTROLLER_T * controller,
+ SCI_BASE_REMOTE_DEVICE_T * remote_device,
+ SCI_BASE_REQUEST_T * io_request,
+ U16 io_tag
+)
+{
+ SCI_STATUS status;
+ SCIF_SAS_IO_REQUEST_T *fw_io = (SCIF_SAS_IO_REQUEST_T*)io_request;
+ SCIF_SAS_CONTROLLER_T *fw_controller = (SCIF_SAS_CONTROLLER_T*)controller;
+ SCIF_SAS_REMOTE_DEVICE_T *fw_device = (SCIF_SAS_REMOTE_DEVICE_T*)
+ remote_device;
+
+ status = fw_device->domain->state_handlers->start_high_priority_io_handler(
+ &fw_device->domain->parent, remote_device, io_request
+ );
+
+ // Check to see that the other objects in the framework allowed
+ // this IO to be started.
+ if (status == SCI_SUCCESS)
+ {
+ // Ask the core to start processing for this IO request.
+ status = scic_controller_start_io(
+ fw_controller->core_object,
+ fw_device->core_object,
+ fw_io->parent.core_object,
+ io_tag
+ );
+
+ if (status == SCI_SUCCESS)
+ {
+ // We were able to start the core request. As a result,
+ // commit to starting the request for the framework by changing
+ // the state of the IO request.
+ sci_base_state_machine_change_state(
+ &io_request->state_machine, SCI_BASE_REQUEST_STATE_STARTED
+ );
+ }
+ else
+ {
+ // We were unable to start the core IO request. As a result,
+ // back out the start operation for the framework. It's easier to
+ // back out the framework start operation then to backout the core
+ // start IO operation.
+ fw_device->domain->state_handlers->complete_io_handler(
+ &fw_device->domain->parent, remote_device, io_request
+ );
+
+ // Invoke the IO completion handler. For most IOs, this does nothing
+ // since we are still in the constructed state. For NCQ, this will
+ // the return of the NCQ tag back to the remote device free pool.
+ fw_io->parent.state_handlers->complete_handler(io_request);
+
+ SCIF_LOG_WARNING((
+ sci_base_object_get_logger(fw_controller),
+ SCIF_LOG_OBJECT_CONTROLLER,
+ "Controller:0x%x IORequest:0x%x Status:0x%x core IO start failed\n",
+ fw_controller, fw_io, status
+ ));
+ }
+ }
+ else
+ {
+ SCIF_LOG_WARNING((
+ sci_base_object_get_logger(fw_controller),
+ SCIF_LOG_OBJECT_CONTROLLER,
+ "Controller:0x%x IORequest:0x%x Status:0x%x IO start failed\n",
+ fw_controller, fw_io, status
+ ));
+
+ // Invoke the IO completion handler. For most IOs, this does nothing
+ // since we are still in the constructed state. For NCQ, this will
+ // the return of the NCQ tag back to the remote device free pool.
+ fw_io->parent.state_handlers->complete_handler(io_request);
+
+ }
+
+ if (fw_io->parent.is_internal && status != SCI_SUCCESS )
+ {
+ SCIC_TRANSPORT_PROTOCOL protocol =
+ scic_io_request_get_protocol(fw_io->parent.core_object);
+
+ U8 retry_count = fw_io->retry_count;
+
+ scif_sas_internal_io_request_destruct(
+ fw_device->domain->controller,
+ (SCIF_SAS_INTERNAL_IO_REQUEST_T *)fw_io
+ );
+
+ if ( protocol == SCIC_SMP_PROTOCOL )
+ {
+ if (fw_device->protocol_device.smp_device.smp_activity_timer != NULL)
+ {
+ //destroy the smp_activity_timer
+ scif_cb_timer_destroy (
+ fw_controller,
+ fw_device->protocol_device.smp_device.smp_activity_timer
+ );
+
+ fw_device->protocol_device.smp_device.smp_activity_timer = NULL;
+ }
+
+ //we should retry for finite times
+ if ( retry_count < SCIF_SAS_IO_RETRY_LIMIT)
+ {
+ //An internal smp request failed being started, most likely due to remote device
+ //is not in ready state, for example, UPDATING_PORT_WIDTH state. In this case,
+ //we should retry the IO.
+ scif_sas_smp_remote_device_retry_internal_io(
+ (SCIF_SAS_REMOTE_DEVICE_T *)remote_device,
+ retry_count,
+ SMP_REQUEST_RETRY_WAIT_DURATION
+ );
+ }
+ }
+ }
+
+ return status;
+}
+
+
+/**
+ * @brief This method provides READY state specific handling for
+ * when a user attempts to start an internal request. If the high
+ * priority IO is also internal, this method will schedule its timer.
+ *
+ * @param[in] controller This parameter specifies the controller object
+ * on which the user is attempting to perform a start IO
+ * operation.
+ * @param[in] remote_device This parameter specifies the remote deivce
+ * object on which the user is attempting to perform a start IO
+ * operation.
+ * @param[in] io_request This parameter specifies the IO request to be
+ * started.
+ * @param[in] io_tag This parameter specifies the optional allocated
+ * IO tag. Please reference scif_controller_start_io() for
+ * more information.
+ *
+ * @return This method returns an indication of whether the start IO
+ * operation succeeded.
+ * @retval SCI_SUCCESS This value is returned when the start IO operation
+ * begins successfully.
+ */
+static
+SCI_STATUS scif_sas_controller_ready_start_high_priority_io_handler(
+ SCI_BASE_CONTROLLER_T * controller,
+ SCI_BASE_REMOTE_DEVICE_T * remote_device,
+ SCI_BASE_REQUEST_T * io_request,
+ U16 io_tag
+)
+{
+ SCI_STATUS status;
+ SCIF_SAS_IO_REQUEST_T * fw_io = (SCIF_SAS_IO_REQUEST_T *)io_request;
+
+ SCIF_LOG_TRACE((
+ sci_base_object_get_logger(controller),
+ SCIF_LOG_OBJECT_CONTROLLER | SCIF_LOG_OBJECT_IO_REQUEST,
+ "scif_sas_controller_ready_start_high_priority_io_handler(0x%x, 0x%x, 0x%x, 0x%x) enter\n",
+ controller, remote_device, io_request, io_tag
+ ));
+
+ status = scif_sas_controller_common_start_high_priority_io_handler(
+ controller, remote_device, io_request, io_tag);
+
+ if (status == SCI_SUCCESS)
+ {
+ //External io could also be put in high priority queue. i.e. the
+ //smp request for EA Target Reset.
+ if (fw_io->parent.is_internal)
+ {
+ SCIF_SAS_INTERNAL_IO_REQUEST_T * fw_internal_io =
+ (SCIF_SAS_INTERNAL_IO_REQUEST_T *)fw_io;
+
+ //start the timer for internal io
+ scif_cb_timer_start(
+ (SCI_CONTROLLER_HANDLE_T)controller,
+ fw_internal_io->internal_io_timer,
+ SCIF_SAS_INTERNAL_REQUEST_TIMEOUT
+ );
+ }
+ }
+ else
+ {
+ //If failed to start, most likely the device or domain is not in
+ //correct state, and the IO has been cleaned up in controller's start
+ //high priority IO handler. We should just continue to start the next
+ //IO in the HP queue.
+
+ SCIF_LOG_TRACE((
+ sci_base_object_get_logger(controller),
+ SCIF_LOG_OBJECT_CONTROLLER | SCIF_LOG_OBJECT_IO_REQUEST,
+ "scif_controller_start_high_priority_io(0x%x, 0x%x), starting io failed\n",
+ controller, fw_io
+ ));
+ }
+
+ return status;
+}
+
+
+//******************************************************************************
+//* S T O P P I N G H A N D L E R S
+//******************************************************************************
+/**
+ * @brief This method provides STOPPING state specific handling for
+ * when a user attempts to start an internal request. Note that we don't
+ * start the timer for internal IO during controller stopping state.
+ *
+ * @param[in] controller This parameter specifies the controller object
+ * on which the user is attempting to perform a start IO
+ * operation.
+ * @param[in] remote_device This parameter specifies the remote deivce
+ * object on which the user is attempting to perform a start IO
+ * operation.
+ * @param[in] io_request This parameter specifies the IO request to be
+ * started.
+ * @param[in] io_tag This parameter specifies the optional allocated
+ * IO tag. Please reference scif_controller_start_io() for
+ * more information.
+ *
+ * @return This method returns an indication of whether the start IO
+ * operation succeeded.
+ * @retval SCI_SUCCESS This value is returned when the start IO operation
+ * begins successfully.
+ */
+static
+SCI_STATUS scif_sas_controller_stopping_start_high_priority_io_handler(
+ SCI_BASE_CONTROLLER_T * controller,
+ SCI_BASE_REMOTE_DEVICE_T * remote_device,
+ SCI_BASE_REQUEST_T * io_request,
+ U16 io_tag
+)
+{
+ SCIF_LOG_TRACE((
+ sci_base_object_get_logger(controller),
+ SCIF_LOG_OBJECT_CONTROLLER | SCIF_LOG_OBJECT_IO_REQUEST,
+ "scif_sas_controller_stopping_start_high_priority_io_handler(0x%x, 0x%x, 0x%x, 0x%x) enter\n",
+ controller, remote_device, io_request, io_tag
+ ));
+
+ return scif_sas_controller_common_start_high_priority_io_handler(
+ controller, remote_device, io_request, io_tag);
+}
+
+
+//******************************************************************************
+//* S T O P P E D H A N D L E R S
+//******************************************************************************
+
+/**
+ * @brief This method provides STOPPED state specific handling for
+ * when a user attempts to reset a controller.
+ *
+ * @param[in] controller This parameter specifies the controller object
+ * on which the user is attempting to perform a reset
+ * operation.
+ *
+ * @return This method returns an indication of whether the reset operation
+ * succeeded.
+ * @retval SCI_SUCCESS This value is returned when the reset operation
+ * completes successfully.
+ */
+static
+SCI_STATUS scif_sas_controller_stopped_reset_handler(
+ SCI_BASE_CONTROLLER_T * controller
+)
+{
+ return scif_sas_controller_execute_reset((SCIF_SAS_CONTROLLER_T*)controller);
+}
+
+
+//******************************************************************************
+//* F A I L E D H A N D L E R S
+//******************************************************************************
+
+/**
+ * @brief This method provides FAILED state specific handling for
+ * when a user attempts to reset a controller.
+ *
+ * @param[in] controller This parameter specifies the controller object
+ * on which the user is attempting to perform a reset
+ * operation.
+ *
+ * @return This method returns an indication of whether the reset operation
+ * succeeded.
+ * @retval SCI_SUCCESS This value is returned when the reset operation
+ * completes successfully.
+ */
+static
+SCI_STATUS scif_sas_controller_failed_reset_handler(
+ SCI_BASE_CONTROLLER_T * controller
+)
+{
+ return scif_sas_controller_execute_reset((SCIF_SAS_CONTROLLER_T*)controller);
+}
+
+//******************************************************************************
+//* D E F A U L T H A N D L E R S
+//******************************************************************************
+
+/**
+ * @brief This method provides default handling (i.e. returns an error)
+ * when a user attempts to start a controller and a start operation
+ * is not allowed.
+ *
+ * @param[in] controller This parameter specifies the controller object
+ * on which the user is attempting to perform a start operation.
+ * @param[in] timeout This parameter specifies the timeout value (in
+ * milliseconds) to be utilized for this operation.
+ *
+ * @return This method returns an indication that start operations are not
+ * allowed.
+ * @retval SCI_FAILURE_INVALID_STATE This value is always returned.
+ */
+static
+SCI_STATUS scif_sas_controller_default_start_handler(
+ SCI_BASE_CONTROLLER_T * controller,
+ U32 timeout
+)
+{
+ SCIF_LOG_WARNING((
+ sci_base_object_get_logger((SCIF_SAS_CONTROLLER_T *)controller),
+ SCIF_LOG_OBJECT_CONTROLLER,
+ "Controller:0x%x State:0x%x invalid state to start controller.\n",
+ controller,
+ sci_base_state_machine_get_state(
+ &((SCIF_SAS_CONTROLLER_T *)controller)->parent.state_machine)
+ ));
+
+ return SCI_FAILURE_INVALID_STATE;
+}
+
+/**
+ * @brief This method provides default handling (i.e. returns an error)
+ * when a user attempts to stop a controller and a stop operation
+ * is not allowed.
+ *
+ * @param[in] controller This parameter specifies the controller object
+ * on which the user is attempting to perform a stop operation.
+ * @param[in] timeout This parameter specifies the timeout value (in
+ * milliseconds) to be utilized for this operation.
+ *
+ * @return This method returns an indication that stop operations are not
+ * allowed.
+ * @retval SCI_FAILURE_INVALID_STATE This value is always returned.
+ */
+static
+SCI_STATUS scif_sas_controller_default_stop_handler(
+ SCI_BASE_CONTROLLER_T * controller,
+ U32 timeout
+)
+{
+ SCIF_LOG_WARNING((
+ sci_base_object_get_logger((SCIF_SAS_CONTROLLER_T *)controller),
+ SCIF_LOG_OBJECT_CONTROLLER,
+ "Controller:0x%x State:0x%x invalid state to stop controller.\n",
+ controller,
+ sci_base_state_machine_get_state(
+ &((SCIF_SAS_CONTROLLER_T *)controller)->parent.state_machine)
+ ));
+
+ return SCI_FAILURE_INVALID_STATE;
+}
+
+/**
+ * @brief This method provides default handling (i.e. returns an error)
+ * when a user attempts to reset a controller and a reset operation
+ * is not allowed.
+ *
+ * @param[in] controller This parameter specifies the controller object
+ * on which the user is attempting to perform a reset operation.
+ *
+ * @return This method returns an indication that reset operations are not
+ * allowed.
+ * @retval SCI_FAILURE_INVALID_STATE This value is always returned.
+ */
+static
+SCI_STATUS scif_sas_controller_default_reset_handler(
+ SCI_BASE_CONTROLLER_T * controller
+)
+{
+ SCIF_LOG_WARNING((
+ sci_base_object_get_logger((SCIF_SAS_CONTROLLER_T *)controller),
+ SCIF_LOG_OBJECT_CONTROLLER,
+ "Controller:0x%x State:0x%x invalid state to reset controller.\n",
+ controller,
+ sci_base_state_machine_get_state(
+ &((SCIF_SAS_CONTROLLER_T *)controller)->parent.state_machine)
+ ));
+
+ return SCI_FAILURE_INVALID_STATE;
+}
+
+/**
+ * @brief This method provides default handling (i.e. returns an error)
+ * when a user attempts to initialize a controller and an initialize
+ * operation is not allowed.
+ *
+ * @param[in] controller This parameter specifies the controller object
+ * on which the user is attempting to perform an initialize
+ * operation.
+ *
+ * @return This method returns an indication that initialize operations
+ * are not allowed.
+ * @retval SCI_FAILURE_INVALID_STATE This value is always returned.
+ */
+static
+SCI_STATUS scif_sas_controller_default_initialize_handler(
+ SCI_BASE_CONTROLLER_T * controller
+)
+{
+ SCIF_LOG_WARNING((
+ sci_base_object_get_logger((SCIF_SAS_CONTROLLER_T *)controller),
+ SCIF_LOG_OBJECT_CONTROLLER,
+ "Controller:0x%x State:0x%x invalid state to initialize controller.\n",
+ controller,
+ sci_base_state_machine_get_state(
+ &((SCIF_SAS_CONTROLLER_T *)controller)->parent.state_machine)
+ ));
+
+ return SCI_FAILURE_INVALID_STATE;
+}
+
+/**
+ * @brief This method provides default handling (i.e. returns an error)
+ * when a user attempts to start an IO on a controller and a start
+ * IO operation is not allowed.
+ *
+ * @param[in] controller This parameter specifies the controller object
+ * on which the user is attempting to perform a start IO
+ * operation.
+ * @param[in] remote_device This parameter specifies the remote deivce
+ * object on which the user is attempting to perform a start IO
+ * operation.
+ * @param[in] io_request This parameter specifies the IO request to be
+ * started.
+ * @param[in] io_tag This parameter specifies the optional allocated
+ * IO tag. Please reference scif_controller_start_io() for
+ * more information.
+ *
+ * @return This method returns an indication that start IO operations
+ * are not allowed.
+ * @retval SCI_FAILURE_INVALID_STATE This value is always returned.
+ */
+static
+SCI_STATUS scif_sas_controller_default_start_io_handler(
+ SCI_BASE_CONTROLLER_T * controller,
+ SCI_BASE_REMOTE_DEVICE_T * remote_device,
+ SCI_BASE_REQUEST_T * io_request,
+ U16 io_tag
+)
+{
+ SCIF_LOG_WARNING((
+ sci_base_object_get_logger((SCIF_SAS_CONTROLLER_T *)controller),
+ SCIF_LOG_OBJECT_CONTROLLER,
+ "Controller:0x%x State:0x%x invalid state to start IO.\n",
+ controller,
+ sci_base_state_machine_get_state(
+ &((SCIF_SAS_CONTROLLER_T *)controller)->parent.state_machine)
+ ));
+
+ return SCI_FAILURE_INVALID_STATE;
+}
+
+/**
+ * @brief This method provides default handling (i.e. returns an error)
+ * when a user attempts to complete an IO on a controller and a
+ * complete IO operation is not allowed.
+ *
+ * @param[in] controller This parameter specifies the controller object
+ * on which the user is attempting to perform a complete IO
+ * operation.
+ * @param[in] remote_device This parameter specifies the remote deivce
+ * object on which the user is attempting to perform a start IO
+ * operation.
+ * @param[in] io_request This parameter specifies the IO request to be
+ * started.
+ *
+ * @return This method returns an indication that complete IO operations
+ * are not allowed.
+ * @retval SCI_FAILURE_INVALID_STATE This value is always returned.
+ */
+static
+SCI_STATUS scif_sas_controller_default_complete_io_handler(
+ SCI_BASE_CONTROLLER_T * controller,
+ SCI_BASE_REMOTE_DEVICE_T * remote_device,
+ SCI_BASE_REQUEST_T * io_request
+)
+{
+ SCIF_LOG_WARNING((
+ sci_base_object_get_logger((SCIF_SAS_CONTROLLER_T *)controller),
+ SCIF_LOG_OBJECT_CONTROLLER,
+ "Controller:0x%x State:0x%x invalid state to complete IO.\n",
+ controller,
+ sci_base_state_machine_get_state(
+ &((SCIF_SAS_CONTROLLER_T *)controller)->parent.state_machine)
+ ));
+
+ return SCI_FAILURE_INVALID_STATE;
+}
+
+/**
+ * @brief This method provides default handling (i.e. returns an error)
+ * when a user attempts to continue an IO on a controller and a
+ * continue IO operation is not allowed.
+ *
+ * @param[in] controller This parameter specifies the controller object
+ * on which the user is attempting to perform a continue IO
+ * operation.
+ * @param[in] remote_device This parameter specifies the remote deivce
+ * object on which the user is attempting to perform a start IO
+ * operation.
+ * @param[in] io_request This parameter specifies the IO request to be
+ * started.
+ *
+ * @return This method returns an indication that continue IO operations
+ * are not allowed.
+ * @retval SCI_FAILURE_INVALID_STATE This value is always returned.
+ */
+static
+SCI_STATUS scif_sas_controller_default_continue_io_handler(
+ SCI_BASE_CONTROLLER_T * controller,
+ SCI_BASE_REMOTE_DEVICE_T * remote_device,
+ SCI_BASE_REQUEST_T * io_request
+)
+{
+ SCIF_LOG_WARNING((
+ sci_base_object_get_logger((SCIF_SAS_CONTROLLER_T *)controller),
+ SCIF_LOG_OBJECT_CONTROLLER,
+ "Controller:0x%x State:0x%x invalid state to continue IO.\n",
+ controller,
+ sci_base_state_machine_get_state(
+ &((SCIF_SAS_CONTROLLER_T *)controller)->parent.state_machine)
+ ));
+
+ return SCI_FAILURE_INVALID_STATE;
+}
+
+/**
+ * @brief This method provides default handling (i.e. returns an error)
+ * when a user attempts to start a task on a controller and a start
+ * task operation is not allowed.
+ *
+ * @param[in] controller This parameter specifies the controller object
+ * on which the user is attempting to perform a start task
+ * operation.
+ * @param[in] remote_device This parameter specifies the remote deivce
+ * object on which the user is attempting to perform a start
+ * task operation.
+ * @param[in] task_request This parameter specifies the task management
+ * request to be started.
+ * @param[in] io_tag This parameter specifies the optional allocated
+ * IO tag. Please reference scif_controller_start_task() for
+ * more information.
+ *
+ * @return This method returns an indication that start task operations
+ * are not allowed.
+ * @retval SCI_FAILURE_INVALID_STATE This value is always returned.
+ */
+static
+SCI_STATUS scif_sas_controller_default_start_task_handler(
+ SCI_BASE_CONTROLLER_T * controller,
+ SCI_BASE_REMOTE_DEVICE_T * remote_device,
+ SCI_BASE_REQUEST_T * task_request,
+ U16 io_tag
+)
+{
+ SCIF_LOG_WARNING((
+ sci_base_object_get_logger((SCIF_SAS_CONTROLLER_T *)controller),
+ SCIF_LOG_OBJECT_CONTROLLER,
+ "Controller:0x%x State:0x%x invalid state to start task mgmt.\n",
+ controller,
+ sci_base_state_machine_get_state(
+ &((SCIF_SAS_CONTROLLER_T *)controller)->parent.state_machine)
+ ));
+
+ return SCI_FAILURE_INVALID_STATE;
+}
+
+/**
+ * @brief This method provides default handling (i.e. returns an error)
+ * when a user attempts to complete a task on a controller and a
+ * complete task operation is not allowed.
+ *
+ * @param[in] controller This parameter specifies the controller object
+ * on which the user is attempting to perform a complete task
+ * operation.
+ * @param[in] remote_device This parameter specifies the remote deivce
+ * object on which the user is attempting to perform a start
+ * task operation.
+ * @param[in] task_request This parameter specifies the task management
+ * request to be started.
+ *
+ * @return This method returns an indication that complete task operations
+ * are not allowed.
+ * @retval SCI_FAILURE_INVALID_STATE This value is always returned.
+ */
+static
+SCI_STATUS scif_sas_controller_default_complete_task_handler(
+ SCI_BASE_CONTROLLER_T * controller,
+ SCI_BASE_REMOTE_DEVICE_T * remote_device,
+ SCI_BASE_REQUEST_T * task_request
+)
+{
+ SCIF_LOG_WARNING((
+ sci_base_object_get_logger((SCIF_SAS_CONTROLLER_T *)controller),
+ SCIF_LOG_OBJECT_CONTROLLER,
+ "Controller:0x%x State:0x%x invalid state to complete task mgmt.\n",
+ controller,
+ sci_base_state_machine_get_state(
+ &((SCIF_SAS_CONTROLLER_T *)controller)->parent.state_machine)
+ ));
+
+ return SCI_FAILURE_INVALID_STATE;
+}
+
+static
+SCI_STATUS scif_sas_controller_failed_state_start_io_handler(
+ SCI_BASE_CONTROLLER_T * controller,
+ SCI_BASE_REMOTE_DEVICE_T * remote_device,
+ SCI_BASE_REQUEST_T * io_request,
+ U16 io_tag
+)
+{
+ SCIF_LOG_WARNING((
+ sci_base_object_get_logger((SCIF_SAS_CONTROLLER_T *)controller),
+ SCIF_LOG_OBJECT_CONTROLLER,
+ "Controller:0x%x State:0x%x invalid state to start IO.\n",
+ controller,
+ sci_base_state_machine_get_state(
+ &((SCIF_SAS_CONTROLLER_T *)controller)->parent.state_machine)
+ ));
+
+ return SCI_IO_FAILURE;
+}
+
+#define scif_sas_controller_stopping_complete_io_handler \
+ scif_sas_controller_ready_complete_io_handler
+#define scif_sas_controller_stopping_complete_task_handler \
+ scif_sas_controller_ready_complete_task_handler
+#define scif_sas_controller_default_start_high_priority_io_handler \
+ scif_sas_controller_default_start_io_handler
+#define scif_sas_controller_default_complete_high_priority_io_handler \
+ scif_sas_controller_default_complete_io_handler
+#define scif_sas_controller_stopping_complete_high_priority_io_handler \
+ scif_sas_controller_ready_complete_high_priority_io_handler
+
+
+SCI_BASE_CONTROLLER_STATE_HANDLER_T
+ scif_sas_controller_state_handler_table[SCI_BASE_CONTROLLER_MAX_STATES] =
+{
+ // SCI_BASE_CONTROLLER_STATE_INITIAL
+ {
+ scif_sas_controller_default_start_handler,
+ scif_sas_controller_default_stop_handler,
+ scif_sas_controller_default_reset_handler,
+ scif_sas_controller_default_initialize_handler,
+ scif_sas_controller_default_start_io_handler,
+ scif_sas_controller_default_start_high_priority_io_handler,
+ scif_sas_controller_default_complete_io_handler,
+ scif_sas_controller_default_complete_high_priority_io_handler,
+ scif_sas_controller_default_continue_io_handler,
+ scif_sas_controller_default_start_task_handler,
+ scif_sas_controller_default_complete_task_handler
+ },
+ // SCI_BASE_CONTROLLER_STATE_RESET
+ {
+ scif_sas_controller_default_start_handler,
+ scif_sas_controller_default_stop_handler,
+ scif_sas_controller_default_reset_handler,
+ scif_sas_controller_reset_initialize_handler,
+ scif_sas_controller_default_start_io_handler,
+ scif_sas_controller_default_start_high_priority_io_handler,
+ scif_sas_controller_default_complete_io_handler,
+ scif_sas_controller_default_complete_high_priority_io_handler,
+ scif_sas_controller_default_continue_io_handler,
+ scif_sas_controller_default_start_task_handler,
+ scif_sas_controller_default_complete_task_handler
+ },
+ // SCI_BASE_CONTROLLER_STATE_INITIALIZING
+ {
+ scif_sas_controller_default_start_handler,
+ scif_sas_controller_default_stop_handler,
+ scif_sas_controller_default_reset_handler,
+ scif_sas_controller_default_initialize_handler,
+ scif_sas_controller_default_start_io_handler,
+ scif_sas_controller_default_start_high_priority_io_handler,
+ scif_sas_controller_default_complete_io_handler,
+ scif_sas_controller_default_complete_high_priority_io_handler,
+ scif_sas_controller_default_continue_io_handler,
+ scif_sas_controller_default_start_task_handler,
+ scif_sas_controller_default_complete_task_handler
+ },
+ // SCI_BASE_CONTROLLER_STATE_INITIALIZED
+ {
+ scif_sas_controller_initialized_start_handler,
+ scif_sas_controller_default_stop_handler,
+ scif_sas_controller_default_reset_handler,
+ scif_sas_controller_default_initialize_handler,
+ scif_sas_controller_default_start_io_handler,
+ scif_sas_controller_default_start_high_priority_io_handler,
+ scif_sas_controller_default_complete_io_handler,
+ scif_sas_controller_default_complete_high_priority_io_handler,
+ scif_sas_controller_default_continue_io_handler,
+ scif_sas_controller_default_start_task_handler,
+ scif_sas_controller_default_complete_task_handler
+ },
+ // SCI_BASE_CONTROLLER_STATE_STARTING
+ {
+ scif_sas_controller_default_start_handler,
+ scif_sas_controller_default_stop_handler,
+ scif_sas_controller_default_reset_handler,
+ scif_sas_controller_default_initialize_handler,
+ scif_sas_controller_default_start_io_handler,
+ scif_sas_controller_default_start_high_priority_io_handler,
+ scif_sas_controller_default_complete_io_handler,
+ scif_sas_controller_default_complete_high_priority_io_handler,
+ scif_sas_controller_default_continue_io_handler,
+ scif_sas_controller_default_start_task_handler,
+ scif_sas_controller_default_complete_task_handler
+ },
+ // SCI_BASE_CONTROLLER_STATE_READY
+ {
+ scif_sas_controller_default_start_handler,
+ scif_sas_controller_ready_stop_handler,
+ scif_sas_controller_ready_reset_handler,
+ scif_sas_controller_default_initialize_handler,
+ scif_sas_controller_ready_start_io_handler,
+ scif_sas_controller_ready_start_high_priority_io_handler,
+ scif_sas_controller_ready_complete_io_handler,
+ scif_sas_controller_ready_complete_high_priority_io_handler,
+ scif_sas_controller_ready_continue_io_handler,
+ scif_sas_controller_ready_start_task_handler,
+ scif_sas_controller_ready_complete_task_handler
+ },
+ // SCI_BASE_CONTROLLER_STATE_RESETTING
+ {
+ scif_sas_controller_default_start_handler,
+ scif_sas_controller_default_stop_handler,
+ scif_sas_controller_default_reset_handler,
+ scif_sas_controller_default_initialize_handler,
+ scif_sas_controller_default_start_io_handler,
+ scif_sas_controller_default_start_high_priority_io_handler,
+ scif_sas_controller_default_complete_io_handler,
+ scif_sas_controller_default_complete_high_priority_io_handler,
+ scif_sas_controller_default_continue_io_handler,
+ scif_sas_controller_default_start_task_handler,
+ scif_sas_controller_default_complete_task_handler
+ },
+ // SCI_BASE_CONTROLLER_STATE_STOPPING
+ {
+ scif_sas_controller_default_start_handler,
+ scif_sas_controller_default_stop_handler,
+ scif_sas_controller_default_reset_handler,
+ scif_sas_controller_default_initialize_handler,
+ scif_sas_controller_default_start_io_handler,
+ scif_sas_controller_stopping_start_high_priority_io_handler,
+ scif_sas_controller_stopping_complete_io_handler,
+ scif_sas_controller_stopping_complete_high_priority_io_handler,
+ scif_sas_controller_default_continue_io_handler,
+ scif_sas_controller_default_start_task_handler, /**@todo Allow in core?*/
+ scif_sas_controller_stopping_complete_task_handler
+ },
+ // SCI_BASE_CONTROLLER_STATE_STOPPED
+ {
+ scif_sas_controller_default_start_handler,
+ scif_sas_controller_default_stop_handler,
+ scif_sas_controller_stopped_reset_handler,
+ scif_sas_controller_default_initialize_handler,
+ scif_sas_controller_default_start_io_handler,
+ scif_sas_controller_default_start_high_priority_io_handler,
+ scif_sas_controller_default_complete_io_handler,
+ scif_sas_controller_default_complete_high_priority_io_handler,
+ scif_sas_controller_default_continue_io_handler,
+ scif_sas_controller_default_start_task_handler,
+ scif_sas_controller_default_complete_task_handler
+ },
+ // SCI_BASE_CONTROLLER_STATE_FAILED
+ {
+ scif_sas_controller_default_start_handler,
+ scif_sas_controller_default_stop_handler,
+ scif_sas_controller_failed_reset_handler,
+ scif_sas_controller_default_initialize_handler,
+ scif_sas_controller_failed_state_start_io_handler,
+ scif_sas_controller_failed_state_start_io_handler,
+ scif_sas_controller_default_complete_io_handler,
+ scif_sas_controller_default_complete_high_priority_io_handler,
+ scif_sas_controller_default_continue_io_handler,
+ scif_sas_controller_default_start_task_handler,
+ scif_sas_controller_default_complete_task_handler
+ }
+};
+
diff --git a/sys/dev/isci/scil/scif_sas_controller_states.c b/sys/dev/isci/scil/scif_sas_controller_states.c
new file mode 100644
index 0000000..7f280fc
--- /dev/null
+++ b/sys/dev/isci/scil/scif_sas_controller_states.c
@@ -0,0 +1,460 @@
+/*-
+ * 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.
+ *
+ * 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 <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/**
+ * @file
+ *
+ * @brief This file contains all of the entrance and exit methods for each
+ * of the controller states defined by the SCI_BASE_CONTROLLER state
+ * machine.
+ */
+
+#include <dev/isci/scil/scic_controller.h>
+
+#include <dev/isci/scil/scif_sas_logger.h>
+#include <dev/isci/scil/scif_sas_controller.h>
+
+//******************************************************************************
+//* P R O T E C T E D M E T H O D S
+//******************************************************************************
+
+/**
+ * @brief This method implements the actions taken when entering the
+ * INITIAL state.
+ *
+ * @param[in] object This parameter specifies the base object for which
+ * the state transition is occurring. This is cast into a
+ * SCIF_SAS_CONTROLLER object in the method implementation.
+ *
+ * @return none
+ */
+static
+void scif_sas_controller_initial_state_enter(
+ SCI_BASE_OBJECT_T * object
+)
+{
+ SCIF_SAS_CONTROLLER_T * fw_controller = (SCIF_SAS_CONTROLLER_T *)object;
+
+ SET_STATE_HANDLER(
+ fw_controller,
+ scif_sas_controller_state_handler_table,
+ SCI_BASE_CONTROLLER_STATE_INITIAL
+ );
+}
+
+/**
+ * @brief This method implements the actions taken when entering the
+ * RESET state.
+ *
+ * @param[in] object This parameter specifies the base object for which
+ * the state transition is occurring. This is cast into a
+ * SCIF_SAS_CONTROLLER object in the method implementation.
+ *
+ * @return none
+ */
+static
+void scif_sas_controller_reset_state_enter(
+ SCI_BASE_OBJECT_T * object
+)
+{
+ SCIF_SAS_CONTROLLER_T * fw_controller = (SCIF_SAS_CONTROLLER_T *)object;
+ U8 index;
+ U16 smp_phy_index;
+
+ SET_STATE_HANDLER(
+ fw_controller,
+ scif_sas_controller_state_handler_table,
+ SCI_BASE_CONTROLLER_STATE_RESET
+ );
+
+ scif_sas_high_priority_request_queue_construct(
+ &fw_controller->hprq, sci_base_object_get_logger(fw_controller)
+ );
+
+ // Construct the abstract element pool. This pool will store the
+ // references to the framework's remote devices objects.
+ sci_abstract_element_pool_construct(
+ &fw_controller->free_remote_device_pool,
+ fw_controller->remote_device_pool_elements,
+ SCI_MAX_REMOTE_DEVICES
+ );
+
+ // Construct the domain objects.
+ for (index = 0; index < SCI_MAX_DOMAINS; index++)
+ {
+ scif_sas_domain_construct(
+ &fw_controller->domains[index], index, fw_controller
+ );
+ }
+
+ //Initialize SMP PHY MEMORY LIST.
+ sci_fast_list_init(&fw_controller->smp_phy_memory_list);
+
+ for (smp_phy_index = 0;
+ smp_phy_index < SCIF_SAS_SMP_PHY_COUNT;
+ smp_phy_index++)
+ {
+ sci_fast_list_element_init(
+ &fw_controller->smp_phy_array[smp_phy_index],
+ &(fw_controller->smp_phy_array[smp_phy_index].list_element)
+ );
+
+ //insert to owning device's smp phy list.
+ sci_fast_list_insert_tail(
+ (&(fw_controller->smp_phy_memory_list)),
+ (&(fw_controller->smp_phy_array[smp_phy_index].list_element))
+ );
+ }
+
+ scif_sas_controller_set_default_config_parameters(fw_controller);
+
+ fw_controller->internal_request_entries =
+ SCIF_SAS_MAX_INTERNAL_REQUEST_COUNT;
+
+ //@Todo: may need to verify all timers are released. Including domain's
+ //operation timer and all the Internal IO's timer.
+
+ //take care of the lock.
+ scif_cb_lock_disassociate(fw_controller, &fw_controller->hprq.lock);
+}
+
+/**
+ * @brief This method implements the actions taken when entering the
+ * INITIALIZING state.
+ *
+ * @param[in] object This parameter specifies the base object for which
+ * the state transition is occurring. This is cast into a
+ * SCIF_SAS_CONTROLLER object in the method implementation.
+ *
+ * @return none
+ */
+static
+void scif_sas_controller_initializing_state_enter(
+ SCI_BASE_OBJECT_T * object
+)
+{
+ SCIF_SAS_CONTROLLER_T * fw_controller = (SCIF_SAS_CONTROLLER_T *)object;
+
+ SET_STATE_HANDLER(
+ fw_controller,
+ scif_sas_controller_state_handler_table,
+ SCI_BASE_CONTROLLER_STATE_INITIALIZING
+ );
+}
+
+/**
+ * @brief This method implements the actions taken when entering the
+ * INITIALIZED state.
+ *
+ * @param[in] object This parameter specifies the base object for which
+ * the state transition is occurring. This is cast into a
+ * SCIF_SAS_CONTROLLER object in the method implementation.
+ *
+ * @return none
+ */
+static
+void scif_sas_controller_initialized_state_enter(
+ SCI_BASE_OBJECT_T * object
+)
+{
+ SCIF_SAS_CONTROLLER_T * fw_controller = (SCIF_SAS_CONTROLLER_T *)object;
+
+ SET_STATE_HANDLER(
+ fw_controller,
+ scif_sas_controller_state_handler_table,
+ SCI_BASE_CONTROLLER_STATE_INITIALIZED
+ );
+}
+
+/**
+ * @brief This method implements the actions taken when entering the
+ * STARTING state.
+ *
+ * @param[in] object This parameter specifies the base object for which
+ * the state transition is occurring. This is cast into a
+ * SCIF_SAS_CONTROLLER object in the method implementation.
+ *
+ * @return none
+ */
+static
+void scif_sas_controller_starting_state_enter(
+ SCI_BASE_OBJECT_T * object
+)
+{
+ SCIF_SAS_CONTROLLER_T * fw_controller = (SCIF_SAS_CONTROLLER_T *)object;
+
+ SET_STATE_HANDLER(
+ fw_controller,
+ scif_sas_controller_state_handler_table,
+ SCI_BASE_CONTROLLER_STATE_STARTING
+ );
+}
+
+/**
+ * @brief This method implements the actions taken when entering the
+ * READY state.
+ *
+ * @param[in] object This parameter specifies the base object for which
+ * the state transition is occurring. This is cast into a
+ * SCIF_SAS_CONTROLLER object in the method implementation.
+ *
+ * @return none
+ */
+static
+void scif_sas_controller_ready_state_enter(
+ SCI_BASE_OBJECT_T * object
+)
+{
+ SCIF_SAS_CONTROLLER_T * fw_controller = (SCIF_SAS_CONTROLLER_T *)object;
+
+ SET_STATE_HANDLER(
+ fw_controller,
+ scif_sas_controller_state_handler_table,
+ SCI_BASE_CONTROLLER_STATE_READY
+ );
+}
+
+/**
+ * @brief This method implements the actions taken when entering the
+ * STOPPING state.
+ *
+ * @param[in] object This parameter specifies the base object for which
+ * the state transition is occurring. This is cast into a
+ * SCIF_SAS_CONTROLLER object in the method implementation.
+ *
+ * @return none
+ */
+static
+void scif_sas_controller_stopping_state_enter(
+ SCI_BASE_OBJECT_T * object
+)
+{
+ SCIF_SAS_CONTROLLER_T * fw_controller = (SCIF_SAS_CONTROLLER_T *)object;
+
+ SET_STATE_HANDLER(
+ fw_controller,
+ scif_sas_controller_state_handler_table,
+ SCI_BASE_CONTROLLER_STATE_STOPPING
+ );
+}
+
+/**
+ * @brief This method implements the actions taken when entering the
+ * STOPPED state.
+ *
+ * @param[in] object This parameter specifies the base object for which
+ * the state transition is occurring. This is cast into a
+ * SCIF_SAS_CONTROLLER object in the method implementation.
+ *
+ * @return none
+ */
+static
+void scif_sas_controller_stopped_state_enter(
+ SCI_BASE_OBJECT_T * object
+)
+{
+ SCIF_SAS_CONTROLLER_T * fw_controller = (SCIF_SAS_CONTROLLER_T *)object;
+
+ SET_STATE_HANDLER(
+ fw_controller,
+ scif_sas_controller_state_handler_table,
+ SCI_BASE_CONTROLLER_STATE_STOPPED
+ );
+}
+
+/**
+ * @brief This method implements the actions taken when entering the
+ * RESETTING state.
+ *
+ * @param[in] object This parameter specifies the base object for which
+ * the state transition is occurring. This is cast into a
+ * SCIF_SAS_CONTROLLER object in the method implementation.
+ *
+ * @return none
+ */
+static
+void scif_sas_controller_resetting_state_enter(
+ SCI_BASE_OBJECT_T * object
+)
+{
+ SCIF_SAS_CONTROLLER_T * fw_controller = (SCIF_SAS_CONTROLLER_T *)object;
+
+ SET_STATE_HANDLER(
+ fw_controller,
+ scif_sas_controller_state_handler_table,
+ SCI_BASE_CONTROLLER_STATE_RESETTING
+ );
+
+ // Attempt to reset the core controller.
+ fw_controller->operation_status = scic_controller_reset(
+ fw_controller->core_object
+ );
+ if (fw_controller->operation_status == SCI_SUCCESS)
+ {
+ // Reset the framework controller.
+ sci_base_state_machine_change_state(
+ &fw_controller->parent.state_machine,
+ SCI_BASE_CONTROLLER_STATE_RESET
+ );
+ }
+ else
+ {
+ SCIF_LOG_ERROR((
+ sci_base_object_get_logger(fw_controller),
+ SCIF_LOG_OBJECT_CONTROLLER,
+ "Controller: unable to successfully reset controller.\n"
+ ));
+
+ sci_base_state_machine_change_state(
+ &fw_controller->parent.state_machine,
+ SCI_BASE_CONTROLLER_STATE_FAILED
+ );
+ }
+}
+
+/**
+ * @brief This method implements the actions taken when entering the
+ * FAILED state.
+ *
+ * @param[in] object This parameter specifies the base object for which
+ * the state transition is occurring. This is cast into a
+ * SCIF_SAS_CONTROLLER object in the method implementation.
+ *
+ * @return none
+ */
+static
+void scif_sas_controller_failed_state_enter(
+ SCI_BASE_OBJECT_T * object
+)
+{
+ SCIF_SAS_CONTROLLER_T * fw_controller = (SCIF_SAS_CONTROLLER_T *)object;
+
+ SCIF_LOG_ERROR((
+ sci_base_object_get_logger(fw_controller),
+ SCIF_LOG_OBJECT_CONTROLLER,
+ "Controller: entered FAILED state.\n"
+ ));
+
+ SET_STATE_HANDLER(
+ fw_controller,
+ scif_sas_controller_state_handler_table,
+ SCI_BASE_CONTROLLER_STATE_FAILED
+ );
+
+ if (fw_controller->parent.error != SCI_CONTROLLER_FATAL_MEMORY_ERROR)
+ {
+ //clean timers to avoid timer leak.
+ scif_sas_controller_release_resource(fw_controller);
+
+ //notify user.
+ scif_cb_controller_error(fw_controller, fw_controller->parent.error);
+ }
+}
+
+SCI_BASE_STATE_T
+scif_sas_controller_state_table[SCI_BASE_CONTROLLER_MAX_STATES] =
+{
+ {
+ SCI_BASE_CONTROLLER_STATE_INITIAL,
+ scif_sas_controller_initial_state_enter,
+ NULL,
+ },
+ {
+ SCI_BASE_CONTROLLER_STATE_RESET,
+ scif_sas_controller_reset_state_enter,
+ NULL,
+ },
+ {
+ SCI_BASE_CONTROLLER_STATE_INITIALIZING,
+ scif_sas_controller_initializing_state_enter,
+ NULL,
+ },
+ {
+ SCI_BASE_CONTROLLER_STATE_INITIALIZED,
+ scif_sas_controller_initialized_state_enter,
+ NULL,
+ },
+ {
+ SCI_BASE_CONTROLLER_STATE_STARTING,
+ scif_sas_controller_starting_state_enter,
+ NULL,
+ },
+ {
+ SCI_BASE_CONTROLLER_STATE_READY,
+ scif_sas_controller_ready_state_enter,
+ NULL,
+ },
+ {
+ SCI_BASE_CONTROLLER_STATE_RESETTING,
+ scif_sas_controller_resetting_state_enter,
+ NULL,
+ },
+ {
+ SCI_BASE_CONTROLLER_STATE_STOPPING,
+ scif_sas_controller_stopping_state_enter,
+ NULL,
+ },
+ {
+ SCI_BASE_CONTROLLER_STATE_STOPPED,
+ scif_sas_controller_stopped_state_enter,
+ NULL,
+ },
+ {
+ SCI_BASE_CONTROLLER_STATE_FAILED,
+ scif_sas_controller_failed_state_enter,
+ NULL,
+ }
+};
+
diff --git a/sys/dev/isci/scil/scif_sas_design.h b/sys/dev/isci/scil/scif_sas_design.h
new file mode 100644
index 0000000..4bc2825
--- /dev/null
+++ b/sys/dev/isci/scil/scif_sas_design.h
@@ -0,0 +1,348 @@
+/*-
+ * 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.
+ *
+ * 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.
+ *
+ * $FreeBSD$
+ */
+#ifndef _SCIF_SAS_DESIGN_H_
+#define _SCIF_SAS_DESIGN_H_
+
+/**
+@page scif_sas_design_page SCIF SAS High Level Design
+
+<b>Authors:</b>
+- Nathan Marushak
+
+<b>Key Contributors:</b>
+- Richard Boyd
+
+@section scif_sas_scope_and_audience Scope and Audience
+
+This document provides design information relating to the SAS specific
+implementation of the SCI Framework. Driver developers are the primary
+audience for this document. The reader is expected to have an understanding
+of the SCU Software Architecture Specification, the Storage Controller
+Interface Specification, and the SCI Base Design.
+
+@section scif_sas_overview Overview
+
+To begin, it's important to discuss the utilization of state machines in
+the design. State machines are pervasive in this design, because of the
+abilities they provide. A properly implemented state machine allows the
+developer to code for a specific task. The developer is not encumbered
+with needed to handle other situations all in a single function. For
+example, if a specific event can only occur when the object is in a specific
+state, then the event handler is added to handle such an event. Thus, a
+single function is not spliced to handle multiple events under various
+potentially disparate conditions.
+
+Additionally, the SCI Base Design document specifies a number of state
+machines, objects, and methods that are heavily utilized by this design.
+Please refer to Base Design specification for further information.
+
+Many of the framework objects have state machines associated with them.
+As a result, there are a number of state entrance and exit methods as well
+as event handlers for each individual state. This design places all of
+the state entrance and exit methods for a given state machine into a single
+file (e.g. scif_sas_controller_states.c). Furthermore, all of the state
+event handler methods are also placed into a single file (e.g.
+scif_sas_controller_state_handlers.c). This format is reused for each
+object that contains state machine(s).
+
+Some of the SAS framework objects contain sub-state machines. These
+sub-state machines are started upon entrance to the super-state and stopped
+upon exit of the super-state.
+
+All other method, data, constant description information will be found in
+the remaining source file (e.g. scif_sas_controller.c). As a result, please
+be sure to follow the link to that specific object/file definition for
+further information.
+
+@note Currently a large number of function pointers are utilized during the
+course of a normal IO request. Once stability of the driver is achieved,
+performance improvements will be made as needed. This likely will include
+removal of the function pointers from the IO path.
+
+@section scif_sas_use_cases Use Cases
+
+The following use case diagram depicts the high-level user interactions with
+the SAS framework. This diagram does not encompass all use cases implemented
+in the system. The low-level design section will contain detailed use cases
+for each significant object and their associated detailed sequences and/or
+activities. For the purposes of readability, the use cases are not directly
+connected to the associated actor utilizing the use case. Instead naming
+is utilized to different which actor is involved with the use case.
+
+Actors:
+- The Framework user also called the OS Specific Driver initiates activities in
+the Framework.
+- The SCI Core calls back into the Framework as a result of an operation either
+started by the OS Specific Driver or by the Framework itself.
+
+@image latex Use_Case_Diagram__SCIF_SAS__Use_Cases.eps "SCIF SAS OS Use Cases" width=11cm
+@image html Use_Case_Diagram__SCIF_SAS__Use_Cases.jpg "SCIF SAS OS Use Cases"
+
+@section scif_sas_class_hierarchy Class Hierarchy
+
+This section delineates the high-level class organization for the SCIF_SAS
+component. Details concerning each class will be found in the corresponding
+low-level design sections. Furthermore, additional classes not germane to
+the overall architecture of the component will also be defined in these
+low-level design sections.
+
+@image latex Class_Diagram__scif_sas__Class_Diagram.eps "SCIF SAS Class Diagram" width=16cm
+@image html Class_Diagram__scif_sas__Class_Diagram.jpg "SCIF SAS Class Diagram"
+
+For more information on each object appearing in the diagram, please
+reference the subsequent sections.
+
+@section scif_sas_library SCIF SAS Library
+
+First, the SCIF_SAS_LIBRARY object provides an implementation
+for the roles and responsibilities defined in the Storage Controller
+Interface (SCI) specification. It is suggested that the user read the
+storage controller interface specification for background information on
+the library object.
+
+The SCIF_SAS_LIBRARY object is broken down into 2 individual source files
+and one direct header file. These files delineate the methods, members, etc.
+associated with this object. Please reference these files directly for
+further design information:
+- scif_sas_library.h
+- scif_sas_library.c
+
+@section scif_sas_controller SCIF SAS Controller
+
+First, the SCIF_SAS_CONTROLLER object provides an implementation
+for the roles and responsibilities defined in the Storage Controller
+Interface (SCI) specification. It is suggested that the user read the
+storage controller interface specification for background information on
+the controller object.
+
+The SCIF_SAS_CONTROLLER object is broken down into 3 individual source files
+and one direct header file. These files delineate the methods, members, etc.
+associated with this object. Please reference these files directly for
+further design information:
+- scif_sas_controller.h
+- scif_sas_controller.c
+- scif_sas_controller_state_handlers.c
+- scif_sas_controller_states.c
+
+@section scif_sas_domain SCIF SAS Domain
+
+First, the SCIF_SAS_DOMAIN object provides an implementation
+for the roles and responsibilities defined in the Storage Controller
+Interface (SCI) specification. It is suggested that the user read the
+storage controller interface specification for background information on
+the SCIF_SAS_DOMAIN object.
+
+The SCIF_SAS_DOMAIN object is broken down into 3 individual
+source files and one direct header file. These files delineate the
+methods, members, etc. associated with this object. Please reference
+these files directly for
+further design information:
+- scif_sas_domain.h
+- scif_sas_domain.c
+- scif_sas_domain_state_handlers.c
+- scif_sas_domain_states.c
+
+@section scif_sas_remote_device SCIF SAS Remote Device
+
+First, the SCIF_SAS_REMOTE_DEVICE object provides an implementation
+for the roles and responsibilities defined in the Storage Controller
+Interface (SCI) specification. It is suggested that the user read the
+storage controller interface specification for background information on
+the SCIF_SAS_REMOTE_DEVICE object.
+
+The SCIF_SAS_REMOTE_DEVICE object is broken down into 7 individual source files
+and one direct header file. These files delineate the methods, members, etc.
+associated with this object. Methods, data, and functionality specific to a
+particular protocol type (e.g. SMP, STP, etc.) are broken out into their own
+object/file. SSP specific remote device functionality is covered by the base
+classes (common files). Please reference these files directly for further
+design information:
+- scif_sas_remote_device.h
+- scif_sas_smp_remote_device.h
+- scif_sas_stp_remote_device.h
+- scif_sas_remote_device.c
+- scif_sas_remote_device_state_handlers.c
+- scif_sas_remote_device_states.c
+- scif_sas_remote_device_starting_substate_handlers.c
+- scif_sas_remote_device_starting_substates.c
+- scif_sas_remote_device_ready_substate_handlers.c
+- scif_sas_remote_device_ready_substates.c
+- scif_sas_smp_remote_device.c
+- scif_sas_stp_remote_device.c
+
+The SCIF_SAS_REMOTE_DEVICE object has sub-state machines defined for
+the READY and STARTING super-states. For more information on the
+super-state machine please refer to SCI_BASE_REMOTE_DEVICE_STATES
+in the SCI Base design document.
+
+In the SCIF_SAS_REMOTE_DEVICE_STARTING_SUBSTATES sub-state machine,
+the remote device currently has to wait for the core to
+return an indication that the remote device has successfully started
+and become ready. If all goes well, then the remote device will
+transition into the READY state.
+
+For more information on the starting sub-state machine states please refer
+to the scif_sas_remote_device.h::_SCIF_SAS_REMOTE_DEVICE_STARTING_SUBSTATES
+enumeration.
+
+@image latex State_Machine_Diagram__STARTING_SUB-STATE__STARTING_SUB-STATE.eps "SCIF SAS Remote Device Starting Sub-state Machine Diagram" width=16cm
+@image html State_Machine_Diagram__STARTING_SUB-STATE__STARTING_SUB-STATE.jpg "SCIF SAS Remote Device Starting Sub-state Machine Diagram"
+
+In the SCIF_SAS_REMOTE_DEVICE_READY_SUBSTATES sub-state machine,
+the remote device currently only allows new host IO requests during the
+OPERATIONAL state. In the TASK MANAGEMENT state only new task management
+requests are allowed.
+
+For more information on the ready sub-state machine states please refer
+to the scif_sas_remote_device.h::_SCIF_SAS_REMOTE_DEVICE_READY_SUBSTATES
+enumeration.
+
+@image latex State_Machine_Diagram__READY_SUB-STATE__READY_SUB-STATE.eps "SCIF SAS Remote Device Ready Sub-state Machine Diagram" width=16cm
+@image html State_Machine_Diagram__READY_SUB-STATE__READY_SUB-STATE.jpg "SCIF SAS Remote Device Ready Sub-state Machine Diagram"
+
+@section scif_sas_request SCIF SAS Request
+
+The SCIF_SAS_REQUEST object provide common functionality for the
+SCIF_SAS_IO_REQUEST and the SCIF_SAS_TASK_REQUEST objects. This object
+does not directly map to an SCI defined object, but its children do. For
+additional information, you may reference the SCIF_SAS_IO_REQUEST or
+SCIF_SAS_TASK_REQUEST objects.
+
+The SCIF_SAS_REQUEST object is broken down into 1 individual source file
+and one direct header file. These files delineate the methods, members, etc.
+associated with this object. Please reference these files directly for
+further design information:
+- scif_sas_request.h
+- scif_sas_request.c
+
+@section scif_sas_io_request SCIF SAS IO Request
+
+First, the SCIF_SAS_IO_REQUEST object provides an implementation
+for the roles and responsibilities defined in the Storage Controller
+Interface (SCI) specification. It is suggested that the user read the
+storage controller interface specification for background information on
+the SCIF_SAS_IO_REQUEST object.
+
+The SCIF_SAS_IO_REQUEST object is broken down into 3 individual
+source files and one direct header file. These files delineate the
+methods, members, etc. associated with this object. Please reference
+these files directly for further design information:
+- scif_sas_io_request.h
+- scif_sas_smp_io_request.h
+- scif_sas_stp_io_request.h
+- scif_sas_sati_binding.h
+- scif_sas_io_request.c
+- scif_sas_io_request_state_handlers.c
+- scif_sas_io_request_states.c
+- scif_sas_smp_io_request.c
+- scif_sas_stp_io_request.c
+
+@section scif_sas_task_request SCIF SAS Task Request
+
+First, the SCIF_SAS_TASK_REQUEST object provides an implementation
+for the roles and responsibilities defined in the Storage Controller
+Interface (SCI) specification. It is suggested that the user read the
+storage controller interface specification for background information on
+the SCIF_SAS_TASK_REQUEST object.
+
+The SCIF_SAS_TASK_REQUEST object is broken down into 3 individual
+source files and one direct header file. These files delineate the
+methods, members, etc. associated with this object. Please reference
+these files directly for further design information:
+- scif_sas_task_request.h
+- scif_sas_stp_task_request.h
+- scif_sas_task_request.c
+- scif_sas_task_request_state_handlers.c
+- scif_sas_task_request_states.c
+- scif_sas_stp_task_request.c
+
+@section scif_sas_internal_io_request SCIF SAS INTERNAL IO Request
+
+The SCIF_SAS_INTERNAL_IO_REQUEST object fulfills the SCI's need to create
+and send out the internal io request. These internal io requests could be
+smp request for expander device discover process, or stp request for NCQ
+error handling. Internal IOs consume the reserved internal io space in
+scif_sas_controller. When an internal IO is constructed, it is put into an
+internal high priority queue. A defferred task (start_internal_io_task) will be
+scheduled at the end of every completion process. The task looks up the high
+priority queue and starts each internal io in the queue. There is one exception
+that start_internal_io_task is scheduled immediately when the first internal io
+is constructed. A retry mechanism is also provided for internal io. When an
+internal io response is decoded, if the decoding indicates a retry is needed,
+the internal io will be retried.
+
+Please refer to these files directly for further design information:
+- scif_sas_internal_io_request.h
+- scif_sas_internal_io_request.c
+- scif_sas_controller.h
+
+@section scif_sas_smp_remote_device SCIF SAS SMP REMOTE DEVICE
+
+The SCIF SAS SMP REMOTE DEVICE object represents the expander device and fulfills
+its SMP discover activities. The discover procedure includes a initial discover
+phase and a follwoing SATA spinup_hold release phase, if there are expander attached
+SATA device is discovered and in spinup_hold conditon. The SCIF SAS SMP REMOTE DEVICE
+object also fulfills expander attached device Target Reset (Phy Control) activity.
+
+@image latex Discover Process.eps "SMP Discover Activity Diagram" width=10cm
+@image html Discover Process.jpg "SMP Discover Activity Diagram"
+
+Please refer to these files directly for further design information:
+- scif_sas_smp_remote_device.h
+- scif_sas_smp_remote_device.c
+- scif_sas_smp_request.h
+- scif_sas_smp_request.c
+*/
+
+#endif // _SCIF_SAS_DESIGN_H_
diff --git a/sys/dev/isci/scil/scif_sas_domain.c b/sys/dev/isci/scil/scif_sas_domain.c
new file mode 100644
index 0000000..8e79277
--- /dev/null
+++ b/sys/dev/isci/scil/scif_sas_domain.c
@@ -0,0 +1,1536 @@
+/*-
+ * 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.
+ *
+ * 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 <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/**
+ * @file
+ *
+ * @brief This file contains the implementation of the SCIF_SAS_DOMAIN
+ * object.
+ */
+
+#include <dev/isci/scil/intel_sas.h>
+#include <dev/isci/scil/sci_fast_list.h>
+#include <dev/isci/scil/scic_controller.h>
+#include <dev/isci/scil/scic_port.h>
+#include <dev/isci/scil/scic_remote_device.h>
+#include <dev/isci/scil/scic_io_request.h>
+#include <dev/isci/scil/scic_user_callback.h>
+#include <dev/isci/scil/scif_user_callback.h>
+#include <dev/isci/scil/sci_abstract_list.h>
+#include <dev/isci/scil/sci_base_iterator.h>
+
+#include <dev/isci/scil/scif_sas_logger.h>
+#include <dev/isci/scil/scif_sas_domain.h>
+#include <dev/isci/scil/scif_sas_controller.h>
+#include <dev/isci/scil/scif_sas_remote_device.h>
+#include <dev/isci/scil/scif_sas_smp_remote_device.h>
+#include <dev/isci/scil/sci_util.h>
+
+//******************************************************************************
+//* P R I V A T E M E T H O D S
+//******************************************************************************
+
+/**
+ * @brief This method will attempt to handle an operation timeout (i.e.
+ * discovery or reset).
+ *
+ * @param[in] cookie This parameter specifies the domain in which the
+ * timeout occurred.
+ *
+ * @return none
+ */
+static
+void scif_sas_domain_operation_timeout_handler(
+ void * cookie
+)
+{
+ SCIF_SAS_DOMAIN_T * fw_domain = (SCIF_SAS_DOMAIN_T*) cookie;
+ U32 state;
+
+ state = sci_base_state_machine_get_state(&fw_domain->parent.state_machine);
+
+ // Based upon the state of the domain, we know whether we were in the
+ // process of performing discovery or a reset.
+ if (state == SCI_BASE_DOMAIN_STATE_DISCOVERING)
+ {
+ SCIF_LOG_WARNING((
+ sci_base_object_get_logger(fw_domain),
+ SCIF_LOG_OBJECT_DOMAIN,
+ "Domain:0x%x State:0x%x DISCOVER timeout!\n",
+ fw_domain, state
+ ));
+
+ fw_domain->operation.status = SCI_FAILURE_TIMEOUT;
+
+ //search all the smp devices in the domain and cancel their activities
+ //if there is any outstanding activity remained. The smp devices will terminate
+ //all the started internal IOs.
+ scif_sas_domain_cancel_smp_activities(fw_domain);
+
+ scif_sas_domain_continue_discover(fw_domain);
+ }
+ else
+ {
+ SCIF_LOG_ERROR((
+ sci_base_object_get_logger(fw_domain),
+ SCIF_LOG_OBJECT_DOMAIN,
+ "Domain:0x%x State:0x%x operation timeout in invalid state\n",
+ fw_domain, state
+ ));
+ }
+}
+
+//******************************************************************************
+//* P U B L I C M E T H O D S
+//******************************************************************************
+
+SCI_PORT_HANDLE_T scif_domain_get_scic_port_handle(
+ SCI_DOMAIN_HANDLE_T domain
+)
+{
+ SCIF_SAS_DOMAIN_T * fw_domain = (SCIF_SAS_DOMAIN_T*) domain;
+
+ if ( (fw_domain != NULL) && (fw_domain->core_object != SCI_INVALID_HANDLE) )
+ return fw_domain->core_object;
+
+ SCIF_LOG_WARNING((
+ sci_base_object_get_logger(fw_domain),
+ SCIF_LOG_OBJECT_DOMAIN,
+ "Domain:0x%x no associated core port found\n",
+ fw_domain
+ ));
+
+ return SCI_INVALID_HANDLE;
+}
+
+// ---------------------------------------------------------------------------
+
+SCI_REMOTE_DEVICE_HANDLE_T scif_domain_get_device_by_sas_address(
+ SCI_DOMAIN_HANDLE_T domain,
+ SCI_SAS_ADDRESS_T * sas_address
+)
+{
+ SCIF_SAS_DOMAIN_T * fw_domain = (SCIF_SAS_DOMAIN_T*) domain;
+ SCI_ABSTRACT_ELEMENT_T * element = sci_abstract_list_get_front(
+ &fw_domain->remote_device_list
+ );
+ SCIF_SAS_REMOTE_DEVICE_T * fw_device;
+ SCI_SAS_ADDRESS_T fw_device_address;
+
+ SCIF_LOG_TRACE((
+ sci_base_object_get_logger(domain),
+ SCIF_LOG_OBJECT_DOMAIN,
+ "scif_domain_get_device_by_sas_address(0x%x, 0x%x) enter\n",
+ domain, sas_address
+ ));
+
+ // Search the abstract list to see if there is a remote device with the
+ // same SAS address.
+ while (element != NULL)
+ {
+ fw_device = (SCIF_SAS_REMOTE_DEVICE_T*)
+ sci_abstract_list_get_object(element);
+
+ scic_remote_device_get_sas_address(
+ fw_device->core_object, &fw_device_address
+ );
+
+ // Check to see if this is the device for which we are searching.
+ if ( (fw_device_address.low == sas_address->low)
+ && (fw_device_address.high == sas_address->high) )
+ {
+ return fw_device;
+ }
+
+ element = sci_abstract_list_get_next(element);
+ }
+
+ return SCI_INVALID_HANDLE;
+}
+
+// ---------------------------------------------------------------------------
+
+#if !defined(DISABLE_SCI_ITERATORS)
+
+SCI_ITERATOR_HANDLE_T scif_domain_get_remote_device_iterator(
+ SCI_DOMAIN_HANDLE_T domain,
+ void * iterator_buffer
+)
+{
+ SCI_ITERATOR_HANDLE_T iterator = (SCI_ITERATOR_HANDLE_T *)iterator_buffer;
+
+ sci_base_iterator_construct(
+ iterator, &((SCIF_SAS_DOMAIN_T*) domain)->remote_device_list
+ );
+
+
+ return iterator;
+}
+
+#endif // !defined(DISABLE_SCI_ITERATORS)
+
+// ---------------------------------------------------------------------------
+
+SCI_STATUS scif_domain_discover(
+ SCI_DOMAIN_HANDLE_T domain,
+ U32 discover_timeout,
+ U32 device_timeout
+)
+{
+ SCIF_SAS_DOMAIN_T * fw_domain = (SCIF_SAS_DOMAIN_T*) domain;
+ SCI_STATUS status = SCI_SUCCESS;
+ SCI_STATUS op_status = SCI_SUCCESS;
+
+ SCIF_LOG_TRACE((
+ sci_base_object_get_logger(domain),
+ SCIF_LOG_OBJECT_DOMAIN | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
+ "scif_domain_discover(0x%x, 0x%x, 0x%x) enter\n",
+ domain, discover_timeout, device_timeout
+ ));
+
+ // Check to make sure the size of the domain doesn't cause potential issues
+ // with the remote device timer and the domain timer.
+ if ((device_timeout * sci_abstract_list_size(&fw_domain->remote_device_list))
+ > discover_timeout)
+ status = SCI_WARNING_TIMER_CONFLICT;
+
+ op_status = fw_domain->state_handlers->discover_handler(
+ &fw_domain->parent, discover_timeout, device_timeout
+ );
+
+ // The status of the discover operation takes priority.
+ if ( (status == SCI_SUCCESS)
+ || (status != SCI_SUCCESS && op_status != SCI_SUCCESS) )
+ {
+ status = op_status;
+ }
+
+ return status;
+}
+
+// ---------------------------------------------------------------------------
+
+U32 scif_domain_get_suggested_discover_timeout(
+ SCI_DOMAIN_HANDLE_T domain
+)
+{
+ U32 suggested_timeout = SCIF_DOMAIN_DISCOVER_TIMEOUT; //milli-seconds
+ return suggested_timeout;
+}
+
+// ---------------------------------------------------------------------------
+
+void scic_cb_port_stop_complete(
+ SCI_CONTROLLER_HANDLE_T controller,
+ SCI_PORT_HANDLE_T port,
+ SCI_STATUS completion_status
+)
+{
+ SCIF_LOG_TRACE((
+ sci_base_object_get_logger((SCIF_SAS_DOMAIN_T*)sci_object_get_association(port)),
+ SCIF_LOG_OBJECT_DOMAIN,
+ "scic_cb_port_stop_complete(0x%x, 0x%x, 0x%x) enter\n",
+ controller, port, completion_status
+ ));
+}
+
+// ---------------------------------------------------------------------------
+
+void scic_cb_port_ready(
+ SCI_CONTROLLER_HANDLE_T controller,
+ SCI_PORT_HANDLE_T port
+)
+{
+ SCIF_SAS_DOMAIN_T * fw_domain = (SCIF_SAS_DOMAIN_T*)
+ sci_object_get_association(port);
+
+ SCIF_LOG_TRACE((
+ sci_base_object_get_logger(fw_domain),
+ SCIF_LOG_OBJECT_DOMAIN,
+ "scic_cb_port_ready(0x%x, 0x%x) enter\n",
+ controller, port
+ ));
+
+ // The controller supplied with the port should match the controller
+ // saved in the domain.
+ ASSERT(sci_object_get_association(controller) == fw_domain->controller);
+
+ fw_domain->is_port_ready = TRUE;
+
+ fw_domain->state_handlers->port_ready_handler(&fw_domain->parent);
+}
+
+// ---------------------------------------------------------------------------
+
+void scic_cb_port_not_ready(
+ SCI_CONTROLLER_HANDLE_T controller,
+ SCI_PORT_HANDLE_T port,
+ U32 reason_code
+)
+{
+ SCIF_SAS_DOMAIN_T * fw_domain = (SCIF_SAS_DOMAIN_T*)
+ sci_object_get_association(port);
+
+ SCIF_LOG_TRACE((
+ sci_base_object_get_logger(fw_domain),
+ SCIF_LOG_OBJECT_DOMAIN,
+ "scic_cb_port_not_ready(0x%x, 0x%x) enter\n",
+ controller, port
+ ));
+
+ // The controller supplied with the port should match the controller
+ // saved in the domain.
+ ASSERT(sci_object_get_association(controller) == fw_domain->controller);
+
+ // There is no need to take action on the port reconfiguring since it is
+ // just a change of the port width.
+ if (reason_code != SCIC_PORT_NOT_READY_RECONFIGURING)
+ {
+ fw_domain->is_port_ready = FALSE;
+
+ fw_domain->state_handlers->port_not_ready_handler(
+ &fw_domain->parent, reason_code);
+ }
+}
+
+// ---------------------------------------------------------------------------
+
+void scic_cb_port_hard_reset_complete(
+ SCI_CONTROLLER_HANDLE_T controller,
+ SCI_PORT_HANDLE_T port,
+ SCI_STATUS completion_status
+)
+{
+ SCIF_SAS_DOMAIN_T * fw_domain = (SCIF_SAS_DOMAIN_T*)
+ sci_object_get_association(port);
+ SCIF_SAS_REMOTE_DEVICE_T * fw_device;
+ SCI_FAST_LIST_ELEMENT_T * element = fw_domain->request_list.list_head;
+ SCIF_SAS_TASK_REQUEST_T * task_request = NULL;
+
+ SCIF_LOG_TRACE((
+ sci_base_object_get_logger(fw_domain),
+ SCIF_LOG_OBJECT_DOMAIN,
+ "scic_cb_port_hard_reset_complete(0x%x, 0x%x, 0x%x) enter\n",
+ controller, port, completion_status
+ ));
+
+ while (element != NULL)
+ {
+ task_request = (SCIF_SAS_TASK_REQUEST_T*) sci_fast_list_get_object(element);
+ element = sci_fast_list_get_next(element);
+
+ if (scif_sas_task_request_get_function(task_request)
+ == SCI_SAS_HARD_RESET)
+ {
+ fw_device = task_request->parent.device;
+
+ if (fw_device->domain == fw_domain)
+ {
+ scic_remote_device_reset_complete(fw_device->core_object);
+
+ scif_cb_task_request_complete(
+ sci_object_get_association(controller),
+ fw_device,
+ task_request,
+ (SCI_TASK_STATUS) completion_status
+ );
+
+ break;
+ }
+ }
+ }
+}
+
+// ---------------------------------------------------------------------------
+
+void scic_cb_port_bc_change_primitive_recieved(
+ SCI_CONTROLLER_HANDLE_T controller,
+ SCI_PORT_HANDLE_T port,
+ SCI_PHY_HANDLE_T phy
+)
+{
+ SCIF_SAS_DOMAIN_T * fw_domain = (SCIF_SAS_DOMAIN_T*)
+ sci_object_get_association(port);
+
+ SCIF_SAS_CONTROLLER_T * fw_controller = (SCIF_SAS_CONTROLLER_T *)
+ sci_object_get_association(controller);
+
+ SCIF_LOG_TRACE((
+ sci_base_object_get_logger(fw_domain),
+ SCIF_LOG_OBJECT_DOMAIN | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
+ "scic_cb_port_bc_change_primitive_recieved(0x%x, 0x%x, 0x%x) enter\n",
+ controller, port, phy
+ ));
+
+ if (fw_domain->broadcast_change_count == 0)
+ { // Enable the BCN detection only if the bcn_count is zero. If bcn_count is
+ // not zero at this time, we won't enable BCN detection since all non-zero
+ // BCN_count means same to us. Furthermore, we avoid BCN storm by not
+ // always enabling the BCN_detection.
+ scic_port_enable_broadcast_change_notification(fw_domain->core_object);
+ }
+
+ fw_domain->broadcast_change_count++;
+
+ //if there is smp device on this domain that is in the middle of discover
+ //process or smp target reset, don't notify the driver layer.
+ if( ! scif_sas_domain_is_in_smp_activity(fw_domain) )
+ // Notify the user that there is, potentially, a change to the domain.
+ scif_cb_domain_change_notification(fw_controller, fw_domain);
+}
+
+// ---------------------------------------------------------------------------
+
+void scic_cb_port_bc_ses_primitive_recieved(
+ SCI_CONTROLLER_HANDLE_T controller,
+ SCI_PORT_HANDLE_T port,
+ SCI_PHY_HANDLE_T phy
+)
+{
+ SCIF_LOG_TRACE((
+ sci_base_object_get_logger(sci_object_get_association(port)),
+ SCIF_LOG_OBJECT_DOMAIN,
+ "scic_cb_port_bc_ses_primitive_received(0x%x, 0x%x, 0x%x) enter\n",
+ controller, port, phy
+ ));
+}
+
+// ---------------------------------------------------------------------------
+
+void scic_cb_port_bc_expander_primitive_recieved(
+ SCI_CONTROLLER_HANDLE_T controller,
+ SCI_PORT_HANDLE_T port,
+ SCI_PHY_HANDLE_T phy
+)
+{
+ SCIF_LOG_TRACE((
+ sci_base_object_get_logger(sci_object_get_association(port)),
+ SCIF_LOG_OBJECT_DOMAIN,
+ "scic_cb_port_bc_expander_primitive_received(0x%x, 0x%x, 0x%x) enter\n",
+ controller, port, phy
+ ));
+}
+
+// ---------------------------------------------------------------------------
+
+void scic_cb_port_bc_aen_primitive_recieved(
+ SCI_CONTROLLER_HANDLE_T controller,
+ SCI_PORT_HANDLE_T port,
+ SCI_PHY_HANDLE_T phy
+)
+{
+ SCIF_LOG_TRACE((
+ sci_base_object_get_logger(sci_object_get_association(port)),
+ SCIF_LOG_OBJECT_DOMAIN,
+ "scic_cb_port_bc_aen_primitive_received(0x%x, 0x%x, 0x%x) enter\n",
+ controller, port, phy
+ ));
+}
+
+// ---------------------------------------------------------------------------
+
+void scic_cb_port_link_up(
+ SCI_CONTROLLER_HANDLE_T controller,
+ SCI_PORT_HANDLE_T port,
+ SCI_PHY_HANDLE_T phy
+)
+{
+ SCIF_SAS_DOMAIN_T * fw_domain = (SCIF_SAS_DOMAIN_T*)
+ sci_object_get_association(port);
+
+ SCIF_LOG_TRACE((
+ sci_base_object_get_logger(sci_object_get_association(port)),
+ SCIF_LOG_OBJECT_DOMAIN,
+ "scic_cb_port_link_up(0x%x, 0x%x, 0x%x) enter\n",
+ controller, port, phy
+ ));
+
+ scif_sas_domain_update_device_port_width(fw_domain, port);
+}
+
+// ---------------------------------------------------------------------------
+
+void scic_cb_port_link_down(
+ SCI_CONTROLLER_HANDLE_T controller,
+ SCI_PORT_HANDLE_T port,
+ SCI_PHY_HANDLE_T phy
+)
+{
+ SCIF_SAS_DOMAIN_T * fw_domain = (SCIF_SAS_DOMAIN_T*)
+ sci_object_get_association(port);
+
+ SCIF_LOG_TRACE((
+ sci_base_object_get_logger(sci_object_get_association(port)),
+ SCIF_LOG_OBJECT_DOMAIN,
+ "scic_cb_port_link_down(0x%x, 0x%x, 0x%x) enter\n",
+ controller, port, phy
+ ));
+
+ scif_sas_domain_update_device_port_width(fw_domain, port);
+}
+
+//******************************************************************************
+//* P R O T E C T E D M E T H O D S
+//******************************************************************************
+
+/**
+ * @brief This method constructs the framework's SAS domain object. During
+ * the construction process a linkage to the corresponding core port
+ * object.
+ *
+ * @param[in] domain This parameter specifies the domain object to be
+ * constructed.
+ * @param[in] domain_id This parameter specifies the ID for the domain
+ * object.
+ * @param[in] fw_controller This parameter specifies the controller managing
+ * the domain being constructed.
+ *
+ * @return none
+ */
+void scif_sas_domain_construct(
+ SCIF_SAS_DOMAIN_T * fw_domain,
+ U8 domain_id,
+ SCIF_SAS_CONTROLLER_T * fw_controller
+)
+{
+ SCIF_LOG_TRACE((
+ sci_base_object_get_logger(fw_controller),
+ SCIF_LOG_OBJECT_DOMAIN | SCIF_LOG_OBJECT_INITIALIZATION,
+ "scif_sas_domain_construct(0x%x, 0x%x, 0x%x) enter\n",
+ fw_domain, domain_id, fw_controller
+ ));
+
+ sci_base_domain_construct(
+ &fw_domain->parent,
+ sci_base_object_get_logger(fw_controller),
+ scif_sas_domain_state_table
+ );
+
+ scif_sas_domain_initialize_state_logging(fw_domain);
+
+ sci_abstract_list_construct(
+ &fw_domain->remote_device_list, &fw_controller->free_remote_device_pool
+ );
+
+ // Retrieve the core's port object that directly corresponds to this
+ // domain.
+ scic_controller_get_port_handle(
+ fw_controller->core_object, domain_id, &fw_domain->core_object
+ );
+
+ // Set the association in the core port to this framework domain object.
+ sci_object_set_association(
+ (SCI_OBJECT_HANDLE_T) fw_domain->core_object, fw_domain
+ );
+
+ sci_fast_list_init(&fw_domain->request_list);
+
+ fw_domain->operation.timer = NULL;
+
+ fw_domain->is_port_ready = FALSE;
+ fw_domain->device_start_count = 0;
+ fw_domain->controller = fw_controller;
+ fw_domain->operation.status = SCI_SUCCESS;
+ fw_domain->is_config_route_table_needed = FALSE;
+}
+
+/**
+ * @brief This method will terminate the requests outstanding in the core
+ * based on the supplied criteria.
+ * - if the all three parameters are specified then only the single
+ * SCIF_SAS_REQUEST object is terminated.
+ * - if only the SCIF_SAS_DOMAIN and SCIF_SAS_REMOTE_DEVICE are
+ * specified, then all SCIF_SAS_REQUEST objects outstanding at
+ * the device are terminated. The one exclusion to this rule is
+ * that the fw_requestor is not terminated.
+ * - if only the SCIF_SAS_DOMAIN object is specified, then all
+ * SCIF_SAS_REQUEST objects outstanding in the domain are
+ * terminated.
+ *
+ * @param[in] fw_domain This parameter specifies the domain in which to
+ * terminate requests.
+ * @param[in] fw_device This parameter specifies the remote device in
+ * which to terminate requests. This parameter can be NULL
+ * as long as the fw_request parameter is NULL. It is a
+ * required parameter if the fw_request parameter is not NULL.
+ * @param[in] fw_request This parameter specifies the request object to
+ * be terminated. This parameter can be NULL.
+ * @param[in] fw_requestor This parameter specifies the task management
+ * request that is responsible for the termination of requests.
+ *
+ * @return none
+ */
+void scif_sas_domain_terminate_requests(
+ SCIF_SAS_DOMAIN_T * fw_domain,
+ SCIF_SAS_REMOTE_DEVICE_T * fw_device,
+ SCIF_SAS_REQUEST_T * fw_request,
+ SCIF_SAS_TASK_REQUEST_T * fw_requestor
+)
+{
+ SCIF_LOG_TRACE((
+ sci_base_object_get_logger(fw_domain),
+ SCIF_LOG_OBJECT_DOMAIN | SCIF_LOG_OBJECT_TASK_MANAGEMENT,
+ "scif_sas_domain_terminate_requests(0x%x, 0x%x, 0x%x, 0x%x) enter\n",
+ fw_domain, fw_device, fw_request, fw_requestor
+ ));
+
+ if (fw_request != NULL)
+ {
+ fw_request->terminate_requestor = fw_requestor;
+ fw_request->state_handlers->abort_handler(&fw_request->parent);
+ }
+ else
+ {
+ SCI_FAST_LIST_ELEMENT_T * element = fw_domain->request_list.list_head;
+ SCIF_SAS_REQUEST_T * request = NULL;
+
+ // Cycle through the fast list of IO requests. Terminate each
+ // oustanding requests that matches the criteria supplied by the
+ // caller.
+ while (element != NULL)
+ {
+ request = (SCIF_SAS_REQUEST_T*) sci_fast_list_get_object(element);
+ // The current element may be deleted from the list becasue of
+ // IO completion so advance to the next element early
+ element = sci_fast_list_get_next(element);
+
+ // Ensure we pass the supplied criteria before terminating the
+ // request.
+ if (
+ (fw_device == NULL)
+ || (
+ (request->device == fw_device)
+ && (fw_requestor != (SCIF_SAS_TASK_REQUEST_T*) request)
+ )
+ )
+ {
+ if (
+ (request->is_waiting_for_abort_task_set == FALSE) ||
+ (request->terminate_requestor == NULL)
+ )
+ {
+ request->terminate_requestor = fw_requestor;
+ request->state_handlers->abort_handler(&request->parent);
+ }
+ }
+ }
+ }
+}
+
+/**
+ * @brief This method searches the domain object to find a
+ * SCIF_SAS_REQUEST object associated with the supplied IO tag.
+ *
+ * @param[in] fw_domain This parameter specifies the domain in which to
+ * to find the request object.
+ * @param[in] io_tag This parameter specifies the IO tag value for which
+ * to locate the corresponding request.
+ *
+ * @return This method returns a pointer to the SCIF_SAS_REQUEST object
+ * associated with the supplied IO tag.
+ * @retval NULL This value is returned if the IO tag does not resolve to
+ * a request.
+ */
+SCIF_SAS_REQUEST_T * scif_sas_domain_get_request_by_io_tag(
+ SCIF_SAS_DOMAIN_T * fw_domain,
+ U16 io_tag
+)
+{
+ SCI_FAST_LIST_ELEMENT_T * element = fw_domain->request_list.list_head;
+ SCIF_SAS_IO_REQUEST_T * io_request = NULL;
+
+ SCIF_LOG_TRACE((
+ sci_base_object_get_logger(fw_domain),
+ SCIF_LOG_OBJECT_DOMAIN | SCIF_LOG_OBJECT_TASK_MANAGEMENT,
+ "scif_sas_domain_get_request_by_io_tag(0x%x, 0x%x) enter\n",
+ fw_domain, io_tag
+ ));
+
+ while (element != NULL)
+ {
+ io_request = (SCIF_SAS_IO_REQUEST_T*) sci_fast_list_get_object(element);
+
+ // Check to see if we located the request with an identical IO tag.
+ if (scic_io_request_get_io_tag(io_request->parent.core_object) == io_tag)
+ return &io_request->parent;
+
+ element = sci_fast_list_get_next(element);
+ }
+
+ return NULL;
+}
+
+/**
+ * @brief This method performs domain object initialization to be done
+ * when the scif_controller_initialize() method is invoked.
+ * This includes operation timeout creation.
+ *
+ * @param[in] fw_domain This parameter specifies the domain object for
+ * which to perform initialization.
+ *
+ * @return none
+ */
+void scif_sas_domain_initialize(
+ SCIF_SAS_DOMAIN_T * fw_domain
+)
+{
+ SCIF_LOG_TRACE((
+ sci_base_object_get_logger(fw_domain),
+ SCIF_LOG_OBJECT_DOMAIN | SCIF_LOG_OBJECT_INITIALIZATION,
+ "scif_sas_domain_initialize(0x%x) enter\n",
+ fw_domain
+ ));
+
+ // Create the timer for each domain. It is too early in the process
+ // to allocate this during construction since the user didn't have
+ // a chance to set it's association.
+ if (fw_domain->operation.timer == 0)
+ {
+ fw_domain->operation.timer = scif_cb_timer_create(
+ fw_domain->controller,
+ scif_sas_domain_operation_timeout_handler,
+ fw_domain
+ );
+ }
+}
+
+/**
+ * @brief This method performs domain object handling for core remote
+ * device start complete notifications. Core remote device starts
+ * and start completes are only done during discovery. This could
+ * ultimately be wrapped into a handler method on the domain (they
+ * actually already exist). This method will decrement the number
+ * of device start operations ongoing and attempt to determine if
+ * discovery is complete.
+ *
+ * @param[in] fw_domain This parameter specifies the domain object for
+ * which to perform initialization.
+ *
+ * @return none
+ */
+void scif_sas_domain_remote_device_start_complete(
+ SCIF_SAS_DOMAIN_T * fw_domain,
+ SCIF_SAS_REMOTE_DEVICE_T * fw_device
+)
+{
+ SMP_DISCOVER_RESPONSE_PROTOCOLS_T dev_protocols;
+
+ SCIF_LOG_TRACE((
+ sci_base_object_get_logger(fw_domain),
+ SCIF_LOG_OBJECT_DOMAIN | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
+ "scif_sas_domain_remote_device_start_complete(0x%x, 0x%x) enter\n",
+ fw_domain, fw_device
+ ));
+
+ // If a device is being started/start completed, then we must be
+ // during discovery.
+ ASSERT(fw_domain->parent.state_machine.current_state_id
+ == SCI_BASE_DOMAIN_STATE_DISCOVERING);
+
+ scic_remote_device_get_protocols(fw_device->core_object, &dev_protocols);
+
+ // Decrement the number of devices being started and check to see
+ // if all have finished being started or failed as the case may be.
+ fw_domain->device_start_in_progress_count--;
+
+ if ( dev_protocols.u.bits.attached_smp_target )
+ {
+ if ( fw_device->containing_device == NULL )
+ //kick off the smp discover process if this expander is direct attached.
+ scif_sas_smp_remote_device_start_discover(fw_device);
+ else
+ //mark this device, the discover process of this device will start after
+ //its containing smp device finish discover.
+ fw_device->protocol_device.smp_device.scheduled_activity =
+ SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_DISCOVER;
+ }
+ else
+ {
+ fw_domain->state_handlers->device_start_complete_handler(
+ &fw_domain->parent, &fw_device->parent
+ );
+ }
+}
+
+
+/**
+ * @brief This methods check each smp device in this domain. If there is at
+ * least one smp device in discover or target reset activity, this
+ * domain is considered in smp activity. Note this routine is not
+ * called on fast IO path.
+ *
+ * @param[in] fw_domain The framework domain object
+ *
+ * @return BOOL value to indicate whether a domain is in SMP activity.
+ */
+BOOL scif_sas_domain_is_in_smp_activity(
+ SCIF_SAS_DOMAIN_T * fw_domain
+)
+{
+ SCI_ABSTRACT_ELEMENT_T * current_element =
+ sci_abstract_list_get_front(&fw_domain->remote_device_list);
+
+ SCIF_SAS_REMOTE_DEVICE_T * current_device;
+
+ while ( current_element != NULL )
+ {
+ SMP_DISCOVER_RESPONSE_PROTOCOLS_T dev_protocols;
+
+ current_device = (SCIF_SAS_REMOTE_DEVICE_T *)
+ sci_abstract_list_get_object(current_element);
+
+ scic_remote_device_get_protocols(current_device->core_object,
+ &dev_protocols
+ );
+
+ if (dev_protocols.u.bits.attached_smp_target &&
+ scif_sas_smp_remote_device_is_in_activity(current_device))
+ return TRUE;
+
+ current_element =
+ sci_abstract_list_get_next(current_element);
+ }
+
+ return FALSE;
+}
+
+
+/**
+ * @brief This methods finds a expander attached device by searching the domain's
+ * device list using connected expander device and expander phy id.
+ *
+ * @param[in] fw_domain The framework domain object
+ * @param[in] parent_device The expander device the target device attaches to.
+ * @param[in] expander_phy_id The expander phy id that the target device owns.
+ *
+ * @return found remote device or a NULL value if no device found.
+ */
+SCIF_SAS_REMOTE_DEVICE_T * scif_sas_domain_get_device_by_containing_device(
+ SCIF_SAS_DOMAIN_T * fw_domain,
+ SCIF_SAS_REMOTE_DEVICE_T * containing_device,
+ U8 expander_phy_id
+)
+{
+ SCIF_SAS_REMOTE_DEVICE_T * fw_device;
+ SCI_ABSTRACT_ELEMENT_T * element = sci_abstract_list_get_front(
+ &fw_domain->remote_device_list
+ );
+
+ //parent device must not be NULL.
+ ASSERT(containing_device != NULL);
+
+ // Search the abstract list to see if there is a remote device meets the
+ // search condition.
+ while (element != NULL)
+ {
+ fw_device = (SCIF_SAS_REMOTE_DEVICE_T*)
+ sci_abstract_list_get_object(element);
+
+ // Check to see if this is the device for which we are searching.
+ if (
+ (fw_device->containing_device == containing_device)
+ && (fw_device->expander_phy_identifier == expander_phy_id)
+ )
+ {
+ return fw_device;
+ }
+
+ element = sci_abstract_list_get_next(element);
+ }
+
+ return SCI_INVALID_HANDLE;
+}
+
+
+/**
+ * @brief This methods finds the first device that is in STOPPED state and its
+ * connection_rate is still in SPINUP_HOLD(value 3).
+ *
+ * @param[in] fw_domain The framework domain object
+ *
+ * @return SCIF_SAS_REMOTE_DEVICE_T The device that is in SPINUP_HOLD or NULL.
+ */
+SCIF_SAS_REMOTE_DEVICE_T * scif_sas_domain_find_device_in_spinup_hold(
+ SCIF_SAS_DOMAIN_T * fw_domain
+)
+{
+ SCI_ABSTRACT_ELEMENT_T * current_element;
+ SCIF_SAS_REMOTE_DEVICE_T * current_device;
+
+ SCIF_LOG_TRACE((
+ sci_base_object_get_logger(fw_domain),
+ SCIF_LOG_OBJECT_DOMAIN,
+ "scif_sas_domain_find_device_in_spinup_hold(0x%x) enter\n",
+ fw_domain
+ ));
+
+ //search throught domain's device list to find the first sata device on spinup_hold
+ current_element = sci_abstract_list_get_front(&fw_domain->remote_device_list);
+ while (current_element != NULL )
+ {
+ current_device = (SCIF_SAS_REMOTE_DEVICE_T *)
+ sci_abstract_list_get_object(current_element);
+
+ //We must get the next element before we remove the current
+ //device. Or else, we will get wrong next_element, since the erased
+ //element has been put into free pool.
+ current_element = sci_abstract_list_get_next(current_element);
+
+ if ( sci_base_state_machine_get_state(&current_device->parent.state_machine) ==
+ SCI_BASE_REMOTE_DEVICE_STATE_STOPPED
+ && scic_remote_device_get_connection_rate(current_device->core_object) ==
+ SCI_SATA_SPINUP_HOLD )
+ {
+ return current_device;
+ }
+ }
+
+ return NULL;
+}
+
+
+/**
+ * @brief This methods finds the first device that has specific activity scheduled.
+ *
+ * @param[in] fw_domain The framework domain object
+ * @param[in] smp_activity A specified smp activity. The valid range is [1,5].
+ *
+ * @return SCIF_SAS_REMOTE_DEVICE_T The device that has specified smp activity scheduled.
+ */
+SCIF_SAS_REMOTE_DEVICE_T * scif_sas_domain_find_device_has_scheduled_activity(
+ SCIF_SAS_DOMAIN_T * fw_domain,
+ U8 smp_activity
+)
+{
+ SCI_ABSTRACT_ELEMENT_T * current_element =
+ sci_abstract_list_get_front(&fw_domain->remote_device_list);
+
+ SCIF_SAS_REMOTE_DEVICE_T * current_device;
+ SMP_DISCOVER_RESPONSE_PROTOCOLS_T dev_protocols;
+
+ //config route table activity has higher priority than discover activity.
+ while ( current_element != NULL )
+ {
+ current_device = (SCIF_SAS_REMOTE_DEVICE_T *)
+ sci_abstract_list_get_object(current_element);
+
+ scic_remote_device_get_protocols(current_device->core_object,
+ &dev_protocols);
+
+ current_element =
+ sci_abstract_list_get_next(current_element);
+
+ if ( dev_protocols.u.bits.attached_smp_target
+ && current_device->protocol_device.smp_device.scheduled_activity ==
+ smp_activity)
+ {
+ return current_device;
+ }
+ }
+
+ return NULL;
+}
+
+
+/**
+ * @brief This methods finds the smp device that has is_config_route_table_scheduled
+ * flag set to TRUE, and start config route table on it. If there is no
+ * smp device scheduled to config route table, find the smp device has
+ * is_discover_scheduled and start the smp discover process on them.
+ *
+ * @param[in] fw_domain The framework domain that to start smp discover process.
+ *
+ * @return NONE
+ */
+void scif_sas_domain_start_smp_activity(
+ SCIF_SAS_DOMAIN_T * fw_domain
+)
+{
+ SCIF_SAS_REMOTE_DEVICE_T * device_has_scheduled_activity = NULL;
+
+ //first, find device that has config route table activity scheduled.
+ //config route table activity has higher priority than Discover.
+ device_has_scheduled_activity =
+ scif_sas_domain_find_device_has_scheduled_activity(
+ fw_domain,
+ SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_CONFIG_ROUTE_TABLE
+ );
+
+ if (device_has_scheduled_activity != NULL)
+ {
+ scif_sas_smp_remote_device_configure_route_table(device_has_scheduled_activity);
+ device_has_scheduled_activity->protocol_device.smp_device.scheduled_activity =
+ SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_NONE;
+ return;
+ }
+
+ //if no device has config route table activity scheduled, search again, find
+ //device has discover activity scheduled.
+ device_has_scheduled_activity =
+ scif_sas_domain_find_device_has_scheduled_activity(
+ fw_domain,
+ SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_DISCOVER
+ );
+
+ if (device_has_scheduled_activity != NULL)
+ scif_sas_smp_remote_device_start_discover(device_has_scheduled_activity);
+}
+
+
+/**
+ * @brief This method starts domain's smp discover process from the top level expander.
+ *
+ * @param[in] fw_domain The framework domain that to start smp discover process.
+ @ @param[in] top_expander The top level expander device to start smp discover process.
+ *
+ * @return None
+ */
+void scif_sas_domain_start_smp_discover(
+ SCIF_SAS_DOMAIN_T * fw_domain,
+ SCIF_SAS_REMOTE_DEVICE_T * top_expander
+)
+{
+ SCI_ABSTRACT_ELEMENT_T * current_element =
+ sci_abstract_list_get_front(&fw_domain->remote_device_list);
+
+ SCIF_SAS_REMOTE_DEVICE_T * current_device;
+
+ // something changed behind expander
+ // mark all the device behind expander to be NOT
+ // is_currently_discovered.
+ while ( current_element != NULL )
+ {
+ current_device = (SCIF_SAS_REMOTE_DEVICE_T *)
+ sci_abstract_list_get_object(current_element);
+
+ current_device->is_currently_discovered = FALSE;
+
+ //reset all the devices' port witdh except the top expander.
+ if (current_device->containing_device != NULL)
+ current_device->device_port_width = 1;
+
+ current_element = sci_abstract_list_get_next(current_element);
+ }
+
+ //expander device itself should be set to is_currently_discovered.
+ top_expander->is_currently_discovered = TRUE;
+
+ //kick off the smp discover process.
+ scif_sas_smp_remote_device_start_discover(top_expander);
+}
+
+
+/**
+ * @brief This method continues domain's smp discover process and
+ * may transit to READY state if all smp activities are done.
+ *
+ * @param[in] fw_domain The framework domain that to start smp discover process.
+ *
+ * @return None
+ */
+void scif_sas_domain_continue_discover(
+ SCIF_SAS_DOMAIN_T * fw_domain
+)
+{
+ SCIF_LOG_TRACE((
+ sci_base_object_get_logger(fw_domain),
+ SCIF_LOG_OBJECT_DOMAIN | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
+ "scif_sas_domain_continue_discover(0x%x) enter\n",
+ fw_domain
+ ));
+
+ if ( fw_domain->device_start_in_progress_count == 0
+ && !scif_sas_domain_is_in_smp_activity(fw_domain) )
+ {
+ //domain scrub the remote device list to see if there is a need
+ //to start smp discover on expander device. There may be no
+ //need to start any smp discover.
+ scif_sas_domain_start_smp_activity(fw_domain);
+
+ //In domain discovery timeout case, we cancel all
+ //the smp activities, and terminate all the smp requests, then
+ //this routine is called. But the smp request may not done
+ //terminated. We want to guard the domain trasitting to READY
+ //by checking outstanding smp request count. If there is outstanding
+ //smp request, the domain will not transit to READY. Later when
+ //the smp request is terminated at smp remote device, this routine
+ //will be called then the domain will transit to READY state.
+ if ( ! scif_sas_domain_is_in_smp_activity(fw_domain)
+ && scif_sas_domain_get_smp_request_count(fw_domain) == 0)
+ {
+ //before domain transit to READY state, domain has some clean up
+ //work to do, such like update domain's remote devcie list.
+ scif_sas_domain_finish_discover(fw_domain);
+ }
+ }
+}
+
+
+/**
+ * @brief This method finishes domain's smp discover process and
+ * update domain's remote device list.
+ *
+ * @param[in] fw_domain The framework domain that's to finish smp discover process.
+ *
+ * @return None
+ */
+void scif_sas_domain_finish_discover(
+ SCIF_SAS_DOMAIN_T * fw_domain
+)
+{
+ SCIF_SAS_REMOTE_DEVICE_T * current_device = NULL;
+ SCI_ABSTRACT_ELEMENT_T * current_element = NULL;
+
+ SCIF_LOG_TRACE((
+ sci_base_object_get_logger(fw_domain),
+ SCIF_LOG_OBJECT_DOMAIN | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
+ "scif_sas_domain_finish_discover(0x%x) enter\n",
+ fw_domain
+ ));
+
+ //need to scrub all the devices behind the expander. Check each
+ //device's discover_status. if the is_currently_discovered is FALSE, means
+ //the device is not been rediscovered. this device needs to be removed.
+ current_element = sci_abstract_list_get_front(&fw_domain->remote_device_list);
+ while (current_element != NULL )
+ {
+ current_device = (SCIF_SAS_REMOTE_DEVICE_T *)
+ sci_abstract_list_get_object(current_element);
+
+ //We must get the next element before we remove the current
+ //device. Or else, we will get wrong next_element, since the erased
+ //element has been put into free pool.
+ current_element = sci_abstract_list_get_next(current_element);
+
+ if ( current_device->is_currently_discovered == FALSE )
+ {
+ // Notify the framework user of the device removal.
+ scif_cb_domain_device_removed(
+ fw_domain->controller, fw_domain, current_device
+ );
+ }
+ }
+
+ sci_base_state_machine_change_state(
+ &fw_domain->parent.state_machine, SCI_BASE_DOMAIN_STATE_READY
+ );
+}
+
+
+
+/**
+ * @brief This method remove an expander device and its child devices, in order to
+ * deal with a detected illeagal phy connection.
+ *
+ * @param[in] fw_domain The domain that a expander belongs to.
+ * @param[in] fw_device The expander device to be removed.
+ *
+ * @return none.
+ */
+void scif_sas_domain_remove_expander_device(
+ SCIF_SAS_DOMAIN_T * fw_domain,
+ SCIF_SAS_REMOTE_DEVICE_T * fw_device
+)
+{
+ SCIF_SAS_SMP_REMOTE_DEVICE_T * smp_remote_device =
+ &fw_device->protocol_device.smp_device;
+
+ SCI_FAST_LIST_ELEMENT_T * element = smp_remote_device->smp_phy_list.list_head;
+ SCIF_SAS_SMP_PHY_T * curr_smp_phy = NULL;
+ SCIF_SAS_REMOTE_DEVICE_T * current_device = NULL;
+
+ while (element != NULL)
+ {
+ curr_smp_phy = (SCIF_SAS_SMP_PHY_T*) sci_fast_list_get_object(element);
+ element = sci_fast_list_get_next(element);
+
+ if ( curr_smp_phy->attached_device_type != SMP_NO_DEVICE_ATTACHED
+ && curr_smp_phy->u.end_device != NULL )
+ {
+ if (curr_smp_phy->attached_device_type == SMP_END_DEVICE_ONLY)
+ current_device = curr_smp_phy->u.end_device;
+ else
+ current_device = curr_smp_phy->u.attached_phy->owning_device;
+
+ scif_cb_domain_device_removed(fw_domain->controller, fw_domain, current_device);
+ }
+ }
+
+ //remove device itself
+ scif_cb_domain_device_removed(fw_domain->controller, fw_domain, fw_device);
+}
+
+
+/**
+ * @brief This method searches the whole domain and finds all the smp devices to
+ * cancel their smp activities if there is any.
+ *
+ * @param[in] fw_domain The domain that its smp activities are to be canceled.
+ *
+ * @return none.
+ */
+void scif_sas_domain_cancel_smp_activities(
+ SCIF_SAS_DOMAIN_T * fw_domain
+)
+{
+ SCI_ABSTRACT_ELEMENT_T * current_element =
+ sci_abstract_list_get_front(&fw_domain->remote_device_list);
+
+ SCIF_SAS_REMOTE_DEVICE_T * current_device;
+
+ //purge all the outstanding internal IOs in HPQ.
+ scif_sas_high_priority_request_queue_purge_domain(
+ &fw_domain->controller->hprq, fw_domain
+ );
+
+ while ( current_element != NULL )
+ {
+ SMP_DISCOVER_RESPONSE_PROTOCOLS_T dev_protocols;
+
+ current_device = (SCIF_SAS_REMOTE_DEVICE_T *)
+ sci_abstract_list_get_object(current_element);
+
+ scic_remote_device_get_protocols(current_device->core_object,
+ &dev_protocols
+ );
+
+ if (dev_protocols.u.bits.attached_smp_target)
+ {
+ scif_sas_smp_remote_device_cancel_smp_activity(current_device);
+ }
+
+ current_element =
+ sci_abstract_list_get_next(current_element);
+ }
+}
+
+
+/**
+ * @brief This method searches the domain's request list and counts outstanding
+ * smp IOs.
+ *
+ * @param[in] fw_domain The domain that its request list is to be searched.
+ *
+ * @return U8 The possible return value of this routine is 0 or 1.
+ */
+U8 scif_sas_domain_get_smp_request_count(
+ SCIF_SAS_DOMAIN_T * fw_domain
+)
+{
+ SCI_FAST_LIST_ELEMENT_T * element = fw_domain->request_list.list_head;
+ SCIF_SAS_REQUEST_T * request = NULL;
+ U8 count = 0;
+ SCIC_TRANSPORT_PROTOCOL protocol;
+
+ // Cycle through the fast list of IO requests. Terminate each
+ // oustanding requests that matches the criteria supplied by the
+ // caller.
+ while (element != NULL)
+ {
+ request = (SCIF_SAS_REQUEST_T*) sci_fast_list_get_object(element);
+ // The current element may be deleted from the list becasue of
+ // IO completion so advance to the next element early
+ element = sci_fast_list_get_next(element);
+
+ protocol = scic_io_request_get_protocol(request->core_object);
+
+ if ( protocol == SCIC_SMP_PROTOCOL)
+ count++;
+ }
+
+ return count;
+}
+
+
+/**
+ * @brief This method start clear affiliation activities for smp devices in
+ * this domain.
+ *
+ * @param[in] fw_domain The domain that its smp devices are scheduled to clear
+ * affiliation for all the EA SATA devices.
+ *
+ * @return none.
+ */
+void scif_sas_domain_start_clear_affiliation(
+ SCIF_SAS_DOMAIN_T * fw_domain
+)
+{
+ scif_sas_domain_schedule_clear_affiliation(fw_domain);
+ scif_sas_domain_continue_clear_affiliation(fw_domain);
+}
+
+
+/**
+ * @brief This method schedule clear affiliation activities for smp devices in
+ * this domain.
+ *
+ * @param[in] fw_domain The domain that its smp devices are scheduled to clear
+ * affiliation for all the EA SATA devices.
+ *
+ * @return none.
+ */
+void scif_sas_domain_schedule_clear_affiliation(
+ SCIF_SAS_DOMAIN_T * fw_domain
+)
+{
+ SCI_ABSTRACT_ELEMENT_T * current_element =
+ sci_abstract_list_get_front(&fw_domain->remote_device_list);
+
+ SCIF_SAS_REMOTE_DEVICE_T * current_device;
+ SMP_DISCOVER_RESPONSE_PROTOCOLS_T dev_protocols;
+
+ //config route table activity has higher priority than discover activity.
+ while ( current_element != NULL )
+ {
+ current_device = (SCIF_SAS_REMOTE_DEVICE_T *)
+ sci_abstract_list_get_object(current_element);
+
+ scic_remote_device_get_protocols(current_device->core_object,
+ &dev_protocols);
+
+ current_element =
+ sci_abstract_list_get_next(current_element);
+
+ if ( dev_protocols.u.bits.attached_smp_target )
+ {
+ current_device->protocol_device.smp_device.scheduled_activity =
+ SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_CLEAR_AFFILIATION;
+ }
+ }
+}
+
+
+/**
+ * @brief This method carries clear affiliation activities for a smp devices in
+ * this domain during controller stop process.
+ *
+ * @param[in] fw_domain The domain that its smp devices are to clear
+ * affiliation for all the EA SATA devices.
+ *
+ * @return none.
+ */
+void scif_sas_domain_continue_clear_affiliation(
+ SCIF_SAS_DOMAIN_T * fw_domain
+)
+{
+ SCIF_SAS_REMOTE_DEVICE_T * smp_device =
+ scif_sas_domain_find_device_has_scheduled_activity(
+ fw_domain,
+ SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_CLEAR_AFFILIATION
+ );
+
+ if (smp_device != NULL)
+ scif_sas_smp_remote_device_start_clear_affiliation(smp_device);
+ else
+ {
+ //This domain has done clear affiliation.
+ SCIF_SAS_CONTROLLER_T * fw_controller = fw_domain->controller;
+ fw_controller->current_domain_to_clear_affiliation++;
+
+ //let controller continue to clear affiliation on other domains.
+ scif_sas_controller_clear_affiliation(fw_domain->controller);
+ }
+}
+
+
+/**
+ * @brief This method releases resource for a framework domain.
+ *
+ * @param[in] fw_controller This parameter specifies the framework
+ * controller, its associated domain's resources are to be released.
+ * @param[in] fw_domain This parameter specifies the framework
+ * domain whose resources are to be released.
+ */
+void scif_sas_domain_release_resource(
+ SCIF_SAS_CONTROLLER_T * fw_controller,
+ SCIF_SAS_DOMAIN_T * fw_domain
+)
+{
+ if (fw_domain->operation.timer != NULL)
+ {
+ scif_cb_timer_destroy(fw_controller, fw_domain->operation.timer);
+ fw_domain->operation.timer = NULL;
+ }
+}
+
+
+/**
+ * @brief This method finds the a EA device that has target reset scheduled.
+ *
+ * @param[in] fw_domain The framework domain object
+ *
+ * @return SCIF_SAS_REMOTE_DEVICE_T The EA device that has target reset scheduled.
+ */
+SCIF_SAS_REMOTE_DEVICE_T * scif_sas_domain_find_next_ea_target_reset(
+ SCIF_SAS_DOMAIN_T * fw_domain
+)
+{
+ SCI_ABSTRACT_ELEMENT_T * current_element;
+ SCIF_SAS_REMOTE_DEVICE_T * current_device;
+
+ SCIF_LOG_TRACE((
+ sci_base_object_get_logger(fw_domain),
+ SCIF_LOG_OBJECT_DOMAIN,
+ "scif_sas_domain_find_next_ea_target_reset(0x%x) enter\n",
+ fw_domain
+ ));
+
+ //search throught domain's device list to find the first sata device on spinup_hold
+ current_element = sci_abstract_list_get_front(&fw_domain->remote_device_list);
+ while (current_element != NULL )
+ {
+ current_device = (SCIF_SAS_REMOTE_DEVICE_T *)
+ sci_abstract_list_get_object(current_element);
+
+ current_element = sci_abstract_list_get_next(current_element);
+
+ if ( current_device->ea_target_reset_request_scheduled != NULL )
+ {
+ return current_device;
+ }
+ }
+
+ return NULL;
+}
+
+#if !defined(DISABLE_WIDE_PORTED_TARGETS)
+/**
+ * @brief This method update the direct attached device port width.
+ *
+ * @param[in] fw_domain The framework domain object
+ * @param[in] port The associated port object which recently has link up/down
+ * event happened.
+ *
+ * @return none
+ */
+void scif_sas_domain_update_device_port_width(
+ SCIF_SAS_DOMAIN_T * fw_domain,
+ SCI_PORT_HANDLE_T port
+)
+{
+ SCIF_SAS_REMOTE_DEVICE_T * fw_device;
+ SCIC_PORT_PROPERTIES_T properties;
+ U8 new_port_width = 0;
+
+ SCIF_LOG_TRACE((
+ sci_base_object_get_logger(fw_domain),
+ SCIF_LOG_OBJECT_DOMAIN,
+ "scif_sas_domain_update_device_port_width(0x%x, 0x%x) enter\n",
+ fw_domain, port
+ ));
+
+ scic_port_get_properties(port, &properties);
+
+ fw_device = (SCIF_SAS_REMOTE_DEVICE_T *)
+ scif_domain_get_device_by_sas_address(
+ fw_domain, &properties.remote.sas_address
+ );
+
+ // If the device already existed in the domain, it is a wide port SSP target,
+ // we need to update its port width.
+ if (fw_device != SCI_INVALID_HANDLE)
+ {
+ SMP_DISCOVER_RESPONSE_PROTOCOLS_T dev_protocols;
+ scic_remote_device_get_protocols(fw_device->core_object, &dev_protocols);
+
+ if (dev_protocols.u.bits.attached_ssp_target)
+ {
+ //Get accurate port width from port's phy mask for a DA device.
+ SCI_GET_BITS_SET_COUNT(properties.phy_mask, new_port_width);
+
+ scif_sas_remote_device_update_port_width(fw_device, new_port_width);
+ }
+ }
+}
+#endif //#if !defined(DISABLE_WIDE_PORTED_TARGETS)
+
+
+#ifdef SCI_LOGGING
+/**
+ * This method will turn on logging of domain state changes.
+ *
+ * @param[in] fw_domain The domain for which the state logging is to be turned
+ * on.
+ */
+void scif_sas_domain_initialize_state_logging(
+ SCIF_SAS_DOMAIN_T *fw_domain
+)
+{
+ sci_base_state_machine_logger_initialize(
+ &fw_domain->parent.state_machine_logger,
+ &fw_domain->parent.state_machine,
+ &fw_domain->parent.parent,
+ scif_cb_logger_log_states,
+ "SCIF_SAS_DOMAIN_T", "base state machine",
+ SCIF_LOG_OBJECT_DOMAIN
+ );
+}
+
+/**
+ * This method will turn off logging of domain state changes.
+ *
+ * @param[in] fw_domain The domain for which the state logging is to be turned
+ * off.
+ */
+void scif_sas_domain_deinitialize_state_logging(
+ SCIF_SAS_DOMAIN_T *fw_domain
+)
+{
+ sci_base_state_machine_logger_deinitialize(
+ &fw_domain->parent.state_machine_logger,
+ &fw_domain->parent.state_machine
+ );
+}
+#endif
diff --git a/sys/dev/isci/scil/scif_sas_domain.h b/sys/dev/isci/scil/scif_sas_domain.h
new file mode 100644
index 0000000..9fbd338
--- /dev/null
+++ b/sys/dev/isci/scil/scif_sas_domain.h
@@ -0,0 +1,328 @@
+/*-
+ * 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.
+ *
+ * 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.
+ *
+ * $FreeBSD$
+ */
+#ifndef _SCIF_SAS_DOMAIN_H_
+#define _SCIF_SAS_DOMAIN_H_
+
+/**
+ * @file
+ *
+ * @brief This file contains the protected interface structures, constants,
+ * and methods for the SCIF_SAS_DOMAIN object.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif // __cplusplus
+
+#include <dev/isci/scil/sci_abstract_list.h>
+#include <dev/isci/scil/sci_fast_list.h>
+#include <dev/isci/scil/scif_domain.h>
+
+#include <dev/isci/scil/sci_base_domain.h>
+#include <dev/isci/scil/scif_sas_request.h>
+#include <dev/isci/scil/scif_sas_task_request.h>
+#include <dev/isci/scil/scif_sas_remote_device.h>
+
+
+extern SCI_BASE_DOMAIN_STATE_HANDLER_T scif_sas_domain_state_handler_table[];
+extern SCI_BASE_STATE_T scif_sas_domain_state_table[];
+
+#define PORT_HARD_RESET_TIMEOUT 1000 //1000 miliseconds
+
+#define SCIF_DOMAIN_DISCOVER_TIMEOUT 20000 // miliseconds
+
+/**
+ * @struct SCIF_SAS_DOMAIN
+ *
+ * @brief The SCI SAS Framework domain object abstracts the SAS domain
+ * level behavior for the framework component. Additionally,
+ * it provides a higher level of abstraction for the core port
+ * object. There is a 1:1 correspondance between core ports and
+ * framework domain objects. Essentially, each core port provides
+ * the access to the remote devices in the domain.
+ */
+typedef struct SCIF_SAS_DOMAIN
+{
+ /**
+ * The SCI_BASE_DOMAIN is the parent object for the SCIF_SAS_DOMAIN
+ * object.
+ */
+ SCI_BASE_DOMAIN_T parent;
+
+ /**
+ * This field contains the handle for the SCI Core port object that
+ * is managed by this framework domain object.
+ */
+ SCI_PORT_HANDLE_T core_object;
+
+ /**
+ * This field specifies the controller containing this domain object.
+ */
+ struct SCIF_SAS_CONTROLLER * controller;
+
+ /**
+ * This field references the list of state specific handler methods to
+ * be utilized for this domain instance.
+ */
+ SCI_BASE_DOMAIN_STATE_HANDLER_T * state_handlers;
+
+ /**
+ * This field contains references to all of the devices contained in
+ * this domain.
+ */
+ SCI_ABSTRACT_LIST_T remote_device_list;
+
+ /**
+ * This field contains the list of all outstanding request (IO or
+ * management) in this domain.
+ */
+ SCI_FAST_LIST_T request_list;
+
+ /**
+ * This field indicates whether the core port object is in a ready state
+ * or not.
+ */
+ BOOL is_port_ready;
+
+ /**
+ * This field indicates the number of remote devices that have been
+ * started in this domain.
+ */
+ U32 device_start_count;
+
+ /**
+ * This field indicates the number of remote devices that are currently
+ * in the process of becoming ready. This field is utilized to gate
+ * the transition back to the READY state for the domain.
+ */
+ U32 device_start_in_progress_count;
+
+ /**
+ * This field records how many broadcast change primitve are
+ * received and not processed yet.
+ */
+ U32 broadcast_change_count;
+
+ /**
+ * This fields indicates whether the expanders in this domain need to
+ * have there config route table configured by our driver. For expample,
+ * if we found the top level expander is a self-configuring expander and
+ * it is able to config others, all the expanders in this domain don't
+ * need to configure route table.
+ */
+ BOOL is_config_route_table_needed;
+
+ struct
+ {
+ /**
+ * This field provides the domain object a scratch area to indicate
+ * status of an ongoing operation.
+ */
+ SCI_STATUS status;
+
+ /**
+ * This is the timer handle that is utilized to time the discovery
+ * or domain reset operations.
+ */
+ void * timer;
+
+ /**
+ * This field specifies the timeout value, in milliseconds, for the
+ * entire operation (discovery or reset).
+ */
+ U32 timeout;
+
+ /**
+ * This field specifies the timeout value, in milliseconds, for a
+ * single device.
+ */
+ U32 device_timeout;
+
+ } operation;
+
+} SCIF_SAS_DOMAIN_T;
+
+void scif_sas_domain_construct(
+ SCIF_SAS_DOMAIN_T * fw_domain,
+ U8 domain_id,
+ struct SCIF_SAS_CONTROLLER * fw_controller
+);
+
+void scif_sas_domain_terminate_requests(
+ SCIF_SAS_DOMAIN_T * fw_domain,
+ SCIF_SAS_REMOTE_DEVICE_T * fw_device,
+ SCIF_SAS_REQUEST_T * fw_request,
+ SCIF_SAS_TASK_REQUEST_T * fw_requestor
+);
+
+SCIF_SAS_REQUEST_T * scif_sas_domain_get_request_by_io_tag(
+ SCIF_SAS_DOMAIN_T * fw_domain,
+ U16 io_tag
+);
+
+void scif_sas_domain_transition_to_stopped_state(
+ SCIF_SAS_DOMAIN_T * fw_domain
+);
+
+void scif_sas_domain_initialize(
+ SCIF_SAS_DOMAIN_T * fw_domain
+);
+
+void scif_sas_domain_remote_device_start_complete(
+ SCIF_SAS_DOMAIN_T * fw_domain,
+ SCIF_SAS_REMOTE_DEVICE_T * fw_device
+);
+
+BOOL scif_sas_domain_is_in_smp_activity(
+ SCIF_SAS_DOMAIN_T * fw_domain
+);
+
+SCIF_SAS_REMOTE_DEVICE_T * scif_sas_domain_get_device_by_containing_device(
+ SCIF_SAS_DOMAIN_T * fw_domain,
+ SCIF_SAS_REMOTE_DEVICE_T * containing_device,
+ U8 expander_phy_id
+);
+
+SCIF_SAS_REMOTE_DEVICE_T * scif_sas_domain_find_device_in_spinup_hold(
+ SCIF_SAS_DOMAIN_T * fw_domain
+);
+
+SCIF_SAS_REMOTE_DEVICE_T * scif_sas_domain_find_device_has_scheduled_activity(
+ SCIF_SAS_DOMAIN_T * fw_domain,
+ U8 smp_activity
+);
+
+void scif_sas_domain_start_smp_activity(
+ SCIF_SAS_DOMAIN_T * fw_domain
+);
+
+void scif_sas_domain_remove_expander_device(
+ SCIF_SAS_DOMAIN_T * fw_domain,
+ SCIF_SAS_REMOTE_DEVICE_T * fw_device
+);
+
+void scif_sas_domain_start_smp_discover(
+ SCIF_SAS_DOMAIN_T * fw_domain,
+ SCIF_SAS_REMOTE_DEVICE_T * top_expander
+);
+
+void scif_sas_domain_continue_discover(
+ SCIF_SAS_DOMAIN_T * fw_domain
+);
+
+void scif_sas_domain_finish_discover(
+ SCIF_SAS_DOMAIN_T * fw_domain
+);
+
+void scif_sas_domain_transition_to_discovering_state(
+ SCIF_SAS_DOMAIN_T * fw_domain
+);
+
+void scif_sas_domain_cancel_smp_activities(
+ SCIF_SAS_DOMAIN_T * fw_domain
+);
+
+U8 scif_sas_domain_get_smp_request_count(
+ SCIF_SAS_DOMAIN_T * fw_domain
+);
+
+void scif_sas_domain_schedule_clear_affiliation(
+ SCIF_SAS_DOMAIN_T * fw_domain
+);
+
+void scif_sas_domain_start_clear_affiliation(
+ SCIF_SAS_DOMAIN_T * fw_domain
+);
+
+void scif_sas_domain_continue_clear_affiliation(
+ SCIF_SAS_DOMAIN_T * fw_domain
+);
+
+void scif_sas_domain_release_resource(
+ struct SCIF_SAS_CONTROLLER * fw_controller,
+ SCIF_SAS_DOMAIN_T * fw_domain
+);
+
+SCIF_SAS_REMOTE_DEVICE_T * scif_sas_domain_find_next_ea_target_reset(
+ SCIF_SAS_DOMAIN_T * fw_domain
+);
+
+#if !defined(DISABLE_WIDE_PORTED_TARGETS)
+void scif_sas_domain_update_device_port_width(
+ SCIF_SAS_DOMAIN_T * fw_domain,
+ SCI_PORT_HANDLE_T port
+);
+#else //!defined(DISABLE_WIDE_PORTED_TARGETS)
+#define scif_sas_domain_update_device_port_width(domain, port)
+#endif //!defined(DISABLE_WIDE_PORTED_TARGETS)
+
+#ifdef SCI_LOGGING
+void scif_sas_domain_initialize_state_logging(
+ SCIF_SAS_DOMAIN_T *fw_domain
+);
+
+void scif_sas_domain_deinitialize_state_logging(
+ SCIF_SAS_DOMAIN_T *fw_domain
+);
+#else // SCI_LOGGING
+#define scif_sas_domain_initialize_state_logging(x)
+#define scif_sas_domain_deinitialize_state_logging(x)
+#endif // SCI_LOGGING
+
+#ifdef __cplusplus
+}
+#endif // __cplusplus
+
+#endif // _SCIF_SAS_DOMAIN_H_
+
diff --git a/sys/dev/isci/scil/scif_sas_domain_state_handlers.c b/sys/dev/isci/scil/scif_sas_domain_state_handlers.c
new file mode 100644
index 0000000..42b75fc
--- /dev/null
+++ b/sys/dev/isci/scil/scif_sas_domain_state_handlers.c
@@ -0,0 +1,1630 @@
+/*-
+ * 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.
+ *
+ * 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 <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/**
+ * @file
+ *
+ * @brief This file contains all of the state handler routines for each
+ * of the domain states defined by the SCI_BASE_DOMAIN state
+ * machine.
+ * @note
+ * - The discover method must be synchronized with the
+ * controller's completion handler. The OS specific driver
+ * component is responsible for ensuring this occurs. If the
+ * discovery method is called from within the call
+ * tree of the completion routine, then no action is necessary.
+ */
+
+
+#include <dev/isci/scil/scic_port.h>
+#include <dev/isci/scil/scic_io_request.h>
+#include <dev/isci/scil/scif_sas_logger.h>
+#include <dev/isci/scil/scif_sas_domain.h>
+
+//******************************************************************************
+//* P R O T E C T E D M E T H O D S
+//******************************************************************************
+
+//******************************************************************************
+//* S T A R T I N G H A N D L E R S
+//******************************************************************************
+
+static
+SCI_STATUS scif_sas_domain_starting_port_ready_handler(
+ SCI_BASE_DOMAIN_T * domain
+)
+{
+ SCIF_LOG_TRACE((
+ sci_base_object_get_logger(domain),
+ SCIF_LOG_OBJECT_DOMAIN | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
+ "scif_sas_domain_starting_port_ready_handler(0x%x) enter\n",
+ domain
+ ));
+
+ // The domain was previously completely stopped. Now that the port is
+ // ready we can transition the domain to the ready state.
+ sci_base_state_machine_change_state(
+ &domain->state_machine, SCI_BASE_DOMAIN_STATE_READY
+ );
+
+ return SCI_SUCCESS;
+}
+
+//******************************************************************************
+//* R E A D Y H A N D L E R S
+//******************************************************************************
+
+/**
+ * @brief This method provides READY state specific handling for
+ * when a user attempts to discover a domain.
+ *
+ * @param[in] domain This parameter specifies the domain object
+ * on which the user is attempting to perform a discover
+ * operation.
+ *
+ * @return This method returns an indication of whether the discover operation
+ * succeeded.
+ * @retval SCI_SUCCESSS This value is returned when the discover operation
+ * begins successfully.
+ */
+static
+SCI_STATUS scif_sas_domain_ready_discover_handler(
+ SCI_BASE_DOMAIN_T * domain,
+ U32 op_timeout,
+ U32 device_timeout
+)
+{
+ SCIF_SAS_DOMAIN_T * fw_domain = (SCIF_SAS_DOMAIN_T *)domain;
+
+ SCIF_LOG_TRACE((
+ sci_base_object_get_logger(domain),
+ SCIF_LOG_OBJECT_DOMAIN | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
+ "scif_sas_domain_ready_discover_handler(0x%x, 0x%x, 0x%x) enter\n",
+ domain, op_timeout, device_timeout
+ ));
+
+ fw_domain->operation.timeout = op_timeout;
+ fw_domain->operation.device_timeout = device_timeout;
+ fw_domain->operation.status = SCI_SUCCESS;
+
+ scif_cb_timer_start(
+ fw_domain->controller,
+ fw_domain->operation.timer,
+ fw_domain->operation.timeout
+ );
+
+ scif_sas_domain_transition_to_discovering_state(fw_domain);
+
+ return fw_domain->operation.status;
+}
+
+/**
+ * @brief This method provides READY state processing for reception of a
+ * port NOT ready notification from the core.
+ *
+ * @param[in] domain This parameter specifies the domain object
+ * on which the core port has just come ready.
+ *
+ * @return
+ */
+static
+SCI_STATUS scif_sas_domain_ready_port_not_ready_handler(
+ SCI_BASE_DOMAIN_T * domain,
+ U32 reason_code
+)
+{
+ SCIF_LOG_TRACE((
+ sci_base_object_get_logger(domain),
+ SCIF_LOG_OBJECT_DOMAIN | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
+ "scif_sas_domain_ready_port_not_ready_handler(0x%x, 0x%x) enter\n",
+ domain,
+ reason_code
+ ));
+
+ if (reason_code != SCIC_PORT_NOT_READY_HARD_RESET_REQUESTED)
+ {
+ // Change to the STOPPING state to cause existing request
+ // completions to be terminated and devices removed.
+ sci_base_state_machine_change_state(
+ &domain->state_machine, SCI_BASE_DOMAIN_STATE_STOPPING
+ );
+ }
+
+ return SCI_SUCCESS;
+}
+
+/**
+ * @brief This method provides READY state specific handling for
+ * when a user attempts to start an IO request.
+ *
+ * @param[in] domain This parameter specifies the domain object
+ * on which the user is attempting to perform a start IO
+ * operation.
+ * @param[in] remote_device This parameter specifies the remote device
+ * object on which the user is attempting to perform a start IO
+ * operation.
+ * @param[in] io_request This parameter specifies the io request that is
+ * being started.
+ *
+ * @return This method returns an indication of whether the start IO
+ * operation succeeded.
+ * @retval SCI_SUCCESS This value is returned when the start IO operation
+ * begins successfully.
+ */
+static
+SCI_STATUS scif_sas_domain_ready_start_io_handler(
+ SCI_BASE_DOMAIN_T * domain,
+ SCI_BASE_REMOTE_DEVICE_T * remote_device,
+ SCI_BASE_REQUEST_T * io_request
+)
+{
+ SCIF_SAS_DOMAIN_T * fw_domain = (SCIF_SAS_DOMAIN_T*) domain;
+ SCIF_SAS_REMOTE_DEVICE_T * fw_device = (SCIF_SAS_REMOTE_DEVICE_T*)
+ remote_device;
+ SCIF_SAS_REQUEST_T * fw_request = (SCIF_SAS_REQUEST_T*) io_request;
+ SCI_STATUS status;
+
+ SCIF_LOG_TRACE((
+ sci_base_object_get_logger(domain),
+ SCIF_LOG_OBJECT_DOMAIN | SCIF_LOG_OBJECT_IO_REQUEST,
+ "scif_sas_domain_ready_start_io_handler(0x%x, 0x%x, 0x%x) enter\n",
+ domain, remote_device, io_request
+ ));
+
+ status = fw_device->state_handlers->parent.start_io_handler(
+ &fw_device->parent, &fw_request->parent
+ );
+
+ if (status == SCI_SUCCESS)
+ {
+ // Add the IO to the list of outstanding requests on the domain.
+ sci_fast_list_insert_tail(
+ &fw_domain->request_list, &fw_request->list_element
+ );
+ }
+
+ return status;
+}
+
+/**
+ * @brief This method provides READY state specific handling for
+ * when a user attempts to complete an IO request.
+ *
+ * @param[in] domain This parameter specifies the domain object
+ * on which the user is attempting to perform a complete IO
+ * operation.
+ * @param[in] remote_device This parameter specifies the remote device
+ * object on which the user is attempting to perform a complete
+ * IO operation.
+ * @param[in] io_request This parameter specifies the io request that is
+ * being completed.
+ *
+ * @return This method returns an indication of whether the complete IO
+ * operation succeeded.
+ * @retval SCI_SUCCESS This value is returned when the complete IO operation
+ * is successful.
+ */
+static
+SCI_STATUS scif_sas_domain_ready_complete_io_handler(
+ SCI_BASE_DOMAIN_T * domain,
+ SCI_BASE_REMOTE_DEVICE_T * remote_device,
+ SCI_BASE_REQUEST_T * io_request
+)
+{
+ SCIF_SAS_REMOTE_DEVICE_T * fw_device = (SCIF_SAS_REMOTE_DEVICE_T*)
+ remote_device;
+ SCIF_SAS_REQUEST_T * fw_request= (SCIF_SAS_REQUEST_T*) io_request;
+
+ SCIF_LOG_TRACE((
+ sci_base_object_get_logger(domain),
+ SCIF_LOG_OBJECT_DOMAIN | SCIF_LOG_OBJECT_IO_REQUEST,
+ "scif_sas_domain_ready_complete_io_handler(0x%x, 0x%x, 0x%x) enter\n",
+ domain, remote_device, io_request
+ ));
+
+ // Remove the IO from the list of outstanding requests on the domain.
+ sci_fast_list_remove_element(&fw_request->list_element);
+
+ return fw_device->state_handlers->parent.complete_io_handler(
+ &fw_device->parent, &fw_request->parent
+ );
+}
+
+/**
+ * @brief This method provides READY state specific handling for
+ * when a user attempts to continue an IO request.
+ *
+ * @param[in] domain This parameter specifies the domain object
+ * on which the user is attempting to perform a continue IO
+ * operation.
+ * @param[in] remote_device This parameter specifies the remote device
+ * object on which the user is attempting to perform a start IO
+ * operation.
+ * @param[in] io_request This parameter specifies the io request that is
+ * being started.
+ *
+ * @return This method returns an indication of whether the continue IO
+ * operation succeeded.
+ * @retval SCI_SUCCESS This value is returned when the continue IO operation
+ * begins successfully.
+ */
+static
+SCI_STATUS scif_sas_domain_ready_continue_io_handler(
+ SCI_BASE_DOMAIN_T * domain,
+ SCI_BASE_REMOTE_DEVICE_T * remote_device,
+ SCI_BASE_REQUEST_T * io_request
+)
+{
+ SCIF_LOG_TRACE((
+ sci_base_object_get_logger(domain),
+ SCIF_LOG_OBJECT_DOMAIN | SCIF_LOG_OBJECT_IO_REQUEST,
+ "scif_sas_domain_ready_continue_io_handler(0x%x, 0x%x, 0x%x) enter\n",
+ domain, remote_device, io_request
+ ));
+
+ /// @todo fix return code handling.
+ return SCI_FAILURE;
+}
+
+/**
+ * @brief This method provides READY state specific handling for
+ * when a user attempts to start a task request.
+ *
+ * @param[in] domain This parameter specifies the domain object
+ * on which the user is attempting to perform a start task
+ * operation.
+ * @param[in] remote_device This parameter specifies the remote device
+ * object on which the user is attempting to perform a start IO
+ * operation.
+ * @param[in] task_request This parameter specifies the task request that
+ * is being started.
+ *
+ * @return This method returns an indication of whether the start task
+ * operation succeeded.
+ * @retval SCI_SUCCESS This value is returned when the start task operation
+ * begins successfully.
+ */
+static
+SCI_STATUS scif_sas_domain_ready_start_task_handler(
+ SCI_BASE_DOMAIN_T * domain,
+ SCI_BASE_REMOTE_DEVICE_T * remote_device,
+ SCI_BASE_REQUEST_T * task_request
+)
+{
+ SCIF_SAS_DOMAIN_T * fw_domain = (SCIF_SAS_DOMAIN_T*) domain;
+ SCIF_SAS_REMOTE_DEVICE_T * fw_device = (SCIF_SAS_REMOTE_DEVICE_T*)
+ remote_device;
+ SCIF_SAS_REQUEST_T * fw_request = (SCIF_SAS_REQUEST_T*) task_request;
+ SCI_STATUS status;
+
+ SCIF_LOG_TRACE((
+ sci_base_object_get_logger(domain),
+ SCIF_LOG_OBJECT_DOMAIN | SCIF_LOG_OBJECT_TASK_MANAGEMENT,
+ "scif_sas_domain_ready_start_task_handler(0x%x, 0x%x, 0x%x) enter\n",
+ domain, remote_device, task_request
+ ));
+
+ status = fw_device->state_handlers->parent.start_task_handler(
+ &fw_device->parent, &fw_request->parent
+ );
+
+ if (status == SCI_SUCCESS)
+ {
+ // Add the task to the list of outstanding requests on the domain.
+ sci_fast_list_insert_tail(
+ &fw_domain->request_list, &fw_request->list_element
+ );
+ }
+
+ return status;
+}
+
+/**
+ * @brief This method provides READY state specific handling for
+ * when a user attempts to complete a task request.
+ *
+ * @param[in] domain This parameter specifies the domain object
+ * on which the user is attempting to perform a complete task
+ * operation.
+ * @param[in] remote_device This parameter specifies the remote device
+ * object on which the user is attempting to perform a start IO
+ * operation.
+ * @param[in] task_request This parameter specifies the task request that
+ * is being started.
+ *
+ * @return This method returns an indication of whether the complete task
+ * operation succeeded.
+ * @retval SCI_SUCCESS This value is returned when the complete task operation
+ * begins successfully.
+ */
+static
+SCI_STATUS scif_sas_domain_ready_complete_task_handler(
+ SCI_BASE_DOMAIN_T * domain,
+ SCI_BASE_REMOTE_DEVICE_T * remote_device,
+ SCI_BASE_REQUEST_T * task_request
+)
+{
+ SCIF_SAS_REMOTE_DEVICE_T * fw_device = (SCIF_SAS_REMOTE_DEVICE_T*)
+ remote_device;
+ SCIF_SAS_REQUEST_T * fw_request = (SCIF_SAS_REQUEST_T*) task_request;
+
+ SCIF_LOG_TRACE((
+ sci_base_object_get_logger(domain),
+ SCIF_LOG_OBJECT_DOMAIN | SCIF_LOG_OBJECT_TASK_MANAGEMENT,
+ "scif_sas_domain_ready_complete_task_handler(0x%x, 0x%x, 0x%x) enter\n",
+ domain, remote_device, task_request
+ ));
+
+ // Remove the IO from the list of outstanding requests on the domain.
+ sci_fast_list_remove_element(&fw_request->list_element);
+
+ return fw_device->state_handlers->parent.complete_task_handler(
+ &fw_device->parent, &fw_request->parent
+ );
+}
+
+
+/**
+ * @brief This method provides READY state specific handling for when a user
+ * attempts to start a high priority IO request.
+ *
+ * @param[in] domain This parameter specifies the domain object
+ * on which the user is attempting to perform a start high priority
+ * IO operation (which is exclusively for Phy Control hard reset).
+ * @param[in] remote_device This parameter specifies the remote device
+ * object on which the user is attempting to perform a start
+ * high priority IO operation.
+ * @param[in] io_request This parameter specifies the io request that is
+ * being started.
+ *
+ * @return This method returns an indication of whether the start IO
+ * operation succeeded.
+ * @retval SCI_SUCCESS This value is returned when the start IO operation
+ * begins successfully.
+ */
+static
+SCI_STATUS scif_sas_domain_ready_start_high_priority_io_handler(
+ SCI_BASE_DOMAIN_T * domain,
+ SCI_BASE_REMOTE_DEVICE_T * remote_device,
+ SCI_BASE_REQUEST_T * io_request
+)
+{
+ SCIF_SAS_DOMAIN_T * fw_domain = (SCIF_SAS_DOMAIN_T*) domain;
+ SCIF_SAS_REMOTE_DEVICE_T * fw_device = (SCIF_SAS_REMOTE_DEVICE_T*)
+ remote_device;
+ SCIF_SAS_REQUEST_T * fw_request = (SCIF_SAS_REQUEST_T*) io_request;
+ SCI_STATUS status;
+
+ SCIF_LOG_TRACE((
+ sci_base_object_get_logger(domain),
+ SCIF_LOG_OBJECT_DOMAIN | SCIF_LOG_OBJECT_IO_REQUEST,
+ "scif_sas_domain_ready_start_high_priority_request_handler(0x%x, 0x%x, 0x%x) enter\n",
+ domain, remote_device, io_request
+ ));
+
+ status = fw_device->state_handlers->start_high_priority_io_handler(
+ &fw_device->parent, &fw_request->parent
+ );
+
+ if (status == SCI_SUCCESS)
+ {
+ // Add the IO to the list of outstanding requests on the domain.
+
+ // When domain is in READY state, this high priority io is likely
+ // a smp Phy Control or Discover request sent to parent device of
+ // a target device, which is to be Target Reset. This high priority
+ // IO's probably has already been added to the domain's list as a
+ // SCIF_SAS_TASK_REQUEST. We need to check if it is already on the
+ // list.
+
+ if ( ! sci_fast_list_is_on_this_list(
+ &fw_domain->request_list, &fw_request->list_element))
+
+ sci_fast_list_insert_tail(
+ &fw_domain->request_list, &fw_request->list_element
+ );
+ }
+
+ return status;
+}
+
+
+/**
+ * @brief This method provides READY state specific handling for
+ * when a user attempts to complete an high priroity IO request.
+ *
+ * @param[in] domain This parameter specifies the domain object
+ * on which the user is attempting to perform a complete high
+ * priority IO operation (which is exclusively for Phy Control
+ * hard reset).
+ * @param[in] remote_device This parameter specifies the remote device
+ * object on which the user is attempting to perform a complete
+ * IO operation.
+ * @param[in] io_request This parameter specifies the io request that is
+ * being completed.
+ *
+ * @return This method returns an indication of whether the complete IO
+ * operation succeeded.
+ * @retval SCI_SUCCESS This value is returned when the complete IO operation
+ * is successful.
+ */
+static
+SCI_STATUS scif_sas_domain_ready_complete_high_priority_io_handler(
+ SCI_BASE_DOMAIN_T * domain,
+ SCI_BASE_REMOTE_DEVICE_T * remote_device,
+ SCI_BASE_REQUEST_T * io_request,
+ void * response_data,
+ SCI_IO_STATUS completion_status
+)
+{
+ SCIF_SAS_REMOTE_DEVICE_T * fw_device = (SCIF_SAS_REMOTE_DEVICE_T*)
+ remote_device;
+ SCIF_SAS_REQUEST_T * fw_request= (SCIF_SAS_REQUEST_T*) io_request;
+
+ SCIC_TRANSPORT_PROTOCOL protocol;
+
+ SCIF_LOG_TRACE((
+ sci_base_object_get_logger(domain),
+ SCIF_LOG_OBJECT_DOMAIN | SCIF_LOG_OBJECT_IO_REQUEST,
+ "scif_sas_domain_ready_complete_high_priority_io_handler(0x%x, 0x%x, 0x%x, 0x%x) enter\n",
+ domain, remote_device, io_request, response_data
+ ));
+
+ protocol = scic_io_request_get_protocol(fw_request->core_object);
+
+ // If the request is an SMP HARD/LINK RESET request, then the request
+ // came through the task management path (partially). As a result,
+ // the accounting for the request is managed in the task request
+ // completion path. Thus, only change the domain request counter if
+ // the request is not an SMP target reset of some sort.
+ if (
+ (protocol != SCIC_SMP_PROTOCOL)
+ || (fw_device->protocol_device.smp_device.current_activity !=
+ SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_TARGET_RESET)
+ )
+ {
+ sci_fast_list_remove_element(&fw_request->list_element);
+ }
+
+ return fw_device->state_handlers->complete_high_priority_io_handler(
+ &fw_device->parent, &fw_request->parent, response_data, completion_status
+ );
+}
+
+//******************************************************************************
+//* S T O P P I N G H A N D L E R S
+//******************************************************************************
+
+static
+SCI_STATUS scif_sas_domain_stopping_device_stop_complete_handler(
+ SCI_BASE_DOMAIN_T * domain,
+ SCI_BASE_REMOTE_DEVICE_T * remote_device
+)
+{
+ SCIF_SAS_DOMAIN_T * fw_domain = (SCIF_SAS_DOMAIN_T *) domain;
+
+ SCIF_LOG_TRACE((
+ sci_base_object_get_logger(domain),
+ SCIF_LOG_OBJECT_DOMAIN,
+ "scif_sas_domain_stopping_device_stop_complete_handler(0x%x, 0x%x) enter\n",
+ domain, remote_device
+ ));
+
+ // Attempt to transition to the stopped state.
+ scif_sas_domain_transition_to_stopped_state(fw_domain);
+
+ return SCI_SUCCESS;
+}
+
+/**
+ * @brief This method provides STOPPING state specific handling for
+ * when a user attempts to complete an IO request.
+ *
+ * @param[in] domain This parameter specifies the domain object
+ * on which the user is attempting to perform a complete IO
+ * operation.
+ * @param[in] remote_device This parameter specifies the remote device
+ * object on which the user is attempting to perform a complete
+ * IO operation.
+ * @param[in] io_request This parameter specifies the io request that is
+ * being completed.
+ *
+ * @return This method returns an indication of whether the complete IO
+ * operation succeeded.
+ * @retval SCI_SUCCESS This value is returned when the complete IO operation
+ * is successful.
+ */
+static
+SCI_STATUS scif_sas_domain_stopping_complete_io_handler(
+ SCI_BASE_DOMAIN_T * domain,
+ SCI_BASE_REMOTE_DEVICE_T * remote_device,
+ SCI_BASE_REQUEST_T * io_request
+)
+{
+ SCIF_SAS_DOMAIN_T * fw_domain = (SCIF_SAS_DOMAIN_T *) domain;
+ SCI_STATUS status;
+
+ SCIF_LOG_TRACE((
+ sci_base_object_get_logger(domain),
+ SCIF_LOG_OBJECT_DOMAIN | SCIF_LOG_OBJECT_IO_REQUEST,
+ "scif_sas_domain_stopping_complete_io_handler(0x%x, 0x%x, 0x%x) enter\n",
+ domain, remote_device, io_request
+ ));
+
+ status = scif_sas_domain_ready_complete_io_handler(
+ domain, remote_device, io_request
+ );
+
+ // Attempt to transition to the stopped state.
+ scif_sas_domain_transition_to_stopped_state(fw_domain);
+
+ return status;
+}
+
+
+/**
+ * @brief This method provides STOPPING state specific handling for
+ * when a user attempts to complete an IO request.
+ *
+ * @param[in] domain This parameter specifies the domain object
+ * on which the user is attempting to perform a complete IO
+ * operation.
+ * @param[in] remote_device This parameter specifies the remote device
+ * object on which the user is attempting to perform a complete
+ * IO operation.
+ * @param[in] io_request This parameter specifies the io request that is
+ * being completed.
+ *
+ * @return This method returns an indication of whether the complete IO
+ * operation succeeded.
+ * @retval SCI_SUCCESS This value is returned when the complete IO operation
+ * is successful.
+ */
+static
+SCI_STATUS scif_sas_domain_stopping_complete_high_priority_io_handler(
+ SCI_BASE_DOMAIN_T * domain,
+ SCI_BASE_REMOTE_DEVICE_T * remote_device,
+ SCI_BASE_REQUEST_T * io_request,
+ void * response_data,
+ SCI_IO_STATUS completion_status
+)
+{
+ SCIF_SAS_DOMAIN_T * fw_domain = (SCIF_SAS_DOMAIN_T *) domain;
+ SCI_STATUS status;
+
+ SCIF_LOG_TRACE((
+ sci_base_object_get_logger(domain),
+ SCIF_LOG_OBJECT_DOMAIN | SCIF_LOG_OBJECT_IO_REQUEST,
+ "scif_sas_domain_stopping_complete_io_handler(0x%x, 0x%x, 0x%x) enter\n",
+ domain, remote_device, io_request
+ ));
+
+ status = scif_sas_domain_ready_complete_high_priority_io_handler(
+ domain, remote_device, io_request, response_data, completion_status
+ );
+
+ // Attempt to transition to the stopped state.
+ scif_sas_domain_transition_to_stopped_state(fw_domain);
+
+ return status;
+}
+
+
+/**
+ * @brief This method provides STOPPING state specific handling for
+ * when a user attempts to complete a task request.
+ *
+ * @param[in] domain This parameter specifies the domain object
+ * on which the user is attempting to perform a complete task
+ * operation.
+ *
+ * @return This method returns an indication of whether the complete task
+ * operation succeeded.
+ * @retval SCI_SUCCESS This value is returned when the complete task operation
+ * begins successfully.
+ */
+static
+SCI_STATUS scif_sas_domain_stopping_complete_task_handler(
+ SCI_BASE_DOMAIN_T * domain,
+ SCI_BASE_REMOTE_DEVICE_T * remote_device,
+ SCI_BASE_REQUEST_T * task_request
+)
+{
+ SCIF_SAS_DOMAIN_T * fw_domain = (SCIF_SAS_DOMAIN_T *) domain;
+ SCI_STATUS status;
+
+ SCIF_LOG_TRACE((
+ sci_base_object_get_logger(domain),
+ SCIF_LOG_OBJECT_DOMAIN | SCIF_LOG_OBJECT_TASK_MANAGEMENT,
+ "scif_sas_domain_stopping_complete_task_handler(0x%x, 0x%x, 0x%x) enter\n",
+ domain, remote_device, task_request
+ ));
+
+ status = scif_sas_domain_ready_complete_task_handler(
+ domain, remote_device, task_request
+ );
+
+ // Attempt to transition to the stopped state.
+ scif_sas_domain_transition_to_stopped_state(fw_domain);
+
+ return SCI_SUCCESS;
+}
+
+//******************************************************************************
+//* D I S C O V E R I N G H A N D L E R S
+//******************************************************************************
+
+/**
+ * @brief This method provides DISCOVERING state specific processing for
+ * reception of a port NOT ready notification from the core. A port
+ * NOT ready notification forces the discovery operation to complete
+ * in error. Additionally, all IOs are aborted and devices removed.
+ *
+ * @param[in] domain This parameter specifies the domain object
+ * for which the core port is no longer ready.
+ *
+ * @return
+ */
+static
+SCI_STATUS scif_sas_domain_discovering_port_not_ready_handler(
+ SCI_BASE_DOMAIN_T * domain,
+ U32 reason_code
+)
+{
+ SCIF_LOG_TRACE((
+ sci_base_object_get_logger(domain),
+ SCIF_LOG_OBJECT_DOMAIN | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
+ "scif_sas_domain_discovering_port_not_ready_handler(0x%x, 0x%x) enter\n",
+ domain,
+ reason_code
+ ));
+
+ // Change to the STOPPING state to cause existing request
+ // completions to be terminated and devices removed.
+ sci_base_state_machine_change_state(
+ &domain->state_machine, SCI_BASE_DOMAIN_STATE_STOPPING
+ );
+
+ return SCI_SUCCESS;
+}
+
+static
+SCI_STATUS scif_sas_domain_discovering_device_start_complete_handler(
+ SCI_BASE_DOMAIN_T * domain,
+ SCI_BASE_REMOTE_DEVICE_T * remote_device
+)
+{
+ SCIF_SAS_DOMAIN_T * fw_domain = (SCIF_SAS_DOMAIN_T *)domain;
+
+ SCIF_LOG_TRACE((
+ sci_base_object_get_logger(domain),
+ SCIF_LOG_OBJECT_DOMAIN | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
+ "scif_sas_domain_discovering_device_start_complete_handler(0x%x) enter\n",
+ domain, remote_device
+ ));
+
+ //domain will decide what's next step.
+ scif_sas_domain_continue_discover(fw_domain);
+
+ return SCI_SUCCESS;
+}
+
+// ---------------------------------------------------------------------------
+
+static
+SCI_STATUS scif_sas_domain_discovering_device_stop_complete_handler(
+ SCI_BASE_DOMAIN_T * domain,
+ SCI_BASE_REMOTE_DEVICE_T * remote_device
+)
+{
+ SCIF_LOG_TRACE((
+ sci_base_object_get_logger(domain),
+ SCIF_LOG_OBJECT_DOMAIN | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
+ "scif_sas_domain_discovering_device_stop_complete_handler(0x%x) enter\n",
+ domain, remote_device
+ ));
+
+ return SCI_FAILURE;
+}
+
+
+/**
+ * @brief This method provides DISCOVERING state specific handling for when a user
+ * attempts to start a high priority IO request.
+ *
+ * @param[in] domain This parameter specifies the domain object
+ * on which the user is attempting to perform a start IO
+ * operation.
+ * @param[in] remote_device This parameter specifies the remote device
+ * object on which the user is attempting to perform a start IO
+ * operation.
+ * @param[in] io_request This parameter specifies the io request that is
+ * being started.
+ *
+ * @return This method returns an indication of whether the start IO
+ * operation succeeded.
+ * @retval SCI_SUCCESS This value is returned when the start IO operation
+ * begins successfully.
+ */
+static
+SCI_STATUS scif_sas_domain_discovering_start_high_priority_io_handler(
+ SCI_BASE_DOMAIN_T * domain,
+ SCI_BASE_REMOTE_DEVICE_T * remote_device,
+ SCI_BASE_REQUEST_T * io_request
+)
+{
+ SCIF_SAS_DOMAIN_T * fw_domain = (SCIF_SAS_DOMAIN_T*) domain;
+ SCIF_SAS_REMOTE_DEVICE_T * fw_device = (SCIF_SAS_REMOTE_DEVICE_T*)
+ remote_device;
+ SCIF_SAS_REQUEST_T * fw_request = (SCIF_SAS_REQUEST_T*) io_request;
+ SCI_STATUS status;
+
+ SCIF_LOG_TRACE((
+ sci_base_object_get_logger(domain),
+ SCIF_LOG_OBJECT_DOMAIN | SCIF_LOG_OBJECT_IO_REQUEST,
+ "scif_sas_domain_discovery_start_high_priority_request_handler(0x%x, 0x%x, 0x%x) enter\n",
+ domain, remote_device, io_request
+ ));
+
+ status = fw_device->state_handlers->start_high_priority_io_handler(
+ &fw_device->parent, &fw_request->parent
+ );
+
+ if (status == SCI_SUCCESS)
+ {
+ // Add the IO to the list of outstanding requests on the domain.
+
+ // It is possible this high priority IO's has already been added to
+ // the domain's list as a SCIF_SAS_TASK_REQUEST. We need to check
+ // if it is already on the list.
+ if ( ! sci_fast_list_is_on_this_list(
+ &fw_domain->request_list, &fw_request->list_element))
+
+ sci_fast_list_insert_tail(
+ &fw_domain->request_list, &fw_request->list_element
+ );
+ }
+
+ return status;
+}
+
+
+/**
+ * @brief This method provides DISCOVERING state specific handling for
+ * when a user attempts to complete an IO request. User IOs are
+ * allowed to be completed during discovery.
+ *
+ * @param[in] domain This parameter specifies the domain object
+ * on which the user is attempting to perform a complete IO
+ * operation.
+ * @param[in] remote_device This parameter specifies the remote device
+ * object on which the user is attempting to perform a complete
+ * IO operation.
+ * @param[in] io_request This parameter specifies the io request that is
+ * being completed.
+ *
+ * @return This method returns an indication of whether the complete IO
+ * operation succeeded.
+ * @retval SCI_SUCCESS This value is returned when the complete IO operation
+ * is successful.
+ */
+static
+SCI_STATUS scif_sas_domain_discovering_complete_io_handler(
+ SCI_BASE_DOMAIN_T * domain,
+ SCI_BASE_REMOTE_DEVICE_T * remote_device,
+ SCI_BASE_REQUEST_T * io_request
+)
+{
+ SCIF_LOG_TRACE((
+ sci_base_object_get_logger(domain),
+ SCIF_LOG_OBJECT_DOMAIN | SCIF_LOG_OBJECT_IO_REQUEST,
+ "scif_sas_domain_discovering_complete_io_handler(0x%x, 0x%x, 0x%x) enter\n",
+ domain, remote_device, io_request
+ ));
+
+ return scif_sas_domain_ready_complete_io_handler(
+ domain, remote_device, io_request
+ );
+}
+
+/**
+ * @brief This method provides DISCOVERING state specific handling for
+ * when a user attempts to complete an high priroity IO request. User
+ * IOs are allowed to be completed during discovery.
+ *
+ * @param[in] domain This parameter specifies the domain object
+ * on which the user is attempting to perform a complete IO
+ * operation.
+ * @param[in] remote_device This parameter specifies the remote device
+ * object on which the user is attempting to perform a complete
+ * IO operation.
+ * @param[in] io_request This parameter specifies the io request that is
+ * being completed.
+ *
+ * @return This method returns an indication of whether the complete IO
+ * operation succeeded.
+ * @retval SCI_SUCCESS This value is returned when the complete IO operation
+ * is successful.
+ */
+static
+SCI_STATUS scif_sas_domain_discovering_complete_high_priority_io_handler(
+ SCI_BASE_DOMAIN_T * domain,
+ SCI_BASE_REMOTE_DEVICE_T * remote_device,
+ SCI_BASE_REQUEST_T * io_request,
+ void * response_data,
+ SCI_IO_STATUS completion_status
+)
+{
+ SCIF_SAS_REMOTE_DEVICE_T * fw_device = (SCIF_SAS_REMOTE_DEVICE_T*)
+ remote_device;
+ SCIF_SAS_REQUEST_T * fw_request= (SCIF_SAS_REQUEST_T*) io_request;
+
+ SCIC_TRANSPORT_PROTOCOL protocol;
+
+ SCIF_LOG_TRACE((
+ sci_base_object_get_logger(domain),
+ SCIF_LOG_OBJECT_DOMAIN | SCIF_LOG_OBJECT_IO_REQUEST,
+ "scif_sas_domain_discovering_complete_high_priority_io_handler(0x%x, 0x%x, 0x%x, 0x%x) enter\n",
+ domain, remote_device, io_request, response_data
+ ));
+
+ protocol = scic_io_request_get_protocol(fw_request->core_object);
+
+ // Remove the IO from the list of outstanding requests on the domain.
+
+ // If the request is an SMP HARD/LINK RESET request, then the request
+ // came through the task management path (partially). As a result,
+ // the accounting for the request is managed in the task request
+ // completion path. Thus, only change the domain request counter if
+ // the request is not an SMP target reset of some sort.
+ if (
+ (protocol != SCIC_SMP_PROTOCOL)
+ || (fw_device->protocol_device.smp_device.current_activity !=
+ SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_TARGET_RESET)
+ )
+ {
+ sci_fast_list_remove_element(&fw_request->list_element);
+ }
+
+ return fw_device->state_handlers->complete_high_priority_io_handler(
+ &fw_device->parent, &fw_request->parent, response_data, completion_status
+ );
+}
+
+
+/**
+ * @brief This method provides DISCOVERING state specific handling for
+ * when the framework attempts to complete an IO request. Internal
+ * Framework IOs allowed to be continued during discovery.
+ *
+ * @param[in] domain This parameter specifies the domain object
+ * on which the user is attempting to perform a continue IO
+ * operation.
+ * @param[in] remote_device This parameter specifies the remote device
+ * object on which the user is attempting to perform a continue
+ * IO operation.
+ * @param[in] io_request This parameter specifies the io request that is
+ * being continued.
+ *
+ * @return This method returns an indication of whether the continue IO
+ * operation succeeded.
+ * @retval SCI_SUCCESS This value is returned when the continue IO operation
+ * is successful.
+ */
+static
+SCI_STATUS scif_sas_domain_discovering_continue_io_handler(
+ SCI_BASE_DOMAIN_T * domain,
+ SCI_BASE_REMOTE_DEVICE_T * remote_device,
+ SCI_BASE_REQUEST_T * io_request
+)
+{
+ SCIF_LOG_TRACE((
+ sci_base_object_get_logger(domain),
+ SCIF_LOG_OBJECT_DOMAIN | SCIF_LOG_OBJECT_IO_REQUEST,
+ "scif_sas_domain_discovering_continue_io_handler(0x%x, 0x%x, 0x%x) enter\n",
+ domain, remote_device, io_request
+ ));
+
+ /// @todo fix return code handling.
+ return SCI_FAILURE;
+}
+
+
+/**
+ * @brief This method provides handling when a user attempts to start
+ * a task on a domain in DISCOVER state, only hard reset is allowed.
+ *
+ * @param[in] domain This parameter specifies the domain object
+ * on which the user is attempting to perform a start task
+ * operation.
+ * @param[in] remote_device This parameter specifies the remote device
+ * object on which the user is attempting to perform a start IO
+ * operation.
+ * @param[in] task_request This parameter specifies the task request that
+ * is being started.
+ *
+ * @return This method returns a status of start task operations
+ * @retval SCI_FAILURE_INVALID_STATE This value is returned for any tasks,
+ * except for HARD RESET.
+ */
+static
+SCI_STATUS scif_sas_domain_discovering_start_task_handler(
+ SCI_BASE_DOMAIN_T * domain,
+ SCI_BASE_REMOTE_DEVICE_T * remote_device,
+ SCI_BASE_REQUEST_T * task_request
+)
+{
+ SCIF_SAS_REMOTE_DEVICE_T * fw_device = (SCIF_SAS_REMOTE_DEVICE_T*)
+ remote_device;
+ SCIF_SAS_TASK_REQUEST_T * fw_task = (SCIF_SAS_TASK_REQUEST_T*)task_request;
+
+ //Only let target reset go through.
+ if (scif_sas_task_request_get_function(fw_task)
+ == SCI_SAS_HARD_RESET)
+ {
+ //If the domain is in the middle of smp DISCOVER process,
+ //interrupt it. After target reset is done, resume the smp DISCOVERY.
+ scif_sas_domain_cancel_smp_activities(fw_device->domain);
+
+ return scif_sas_domain_ready_start_task_handler(domain, remote_device, task_request);
+ }
+ else{
+ SCIF_LOG_WARNING((
+ sci_base_object_get_logger(domain),
+ SCIF_LOG_OBJECT_DOMAIN,
+ "Domain:0x%x Device:0x%x State:0x%x start task message invalid\n",
+ domain, remote_device,
+ sci_base_state_machine_get_state(&domain->state_machine)
+ ));
+
+ return SCI_FAILURE_INVALID_STATE;
+ }
+}
+
+
+/**
+ * @brief This method provides DISCOVERING state specific handling for
+ * when a user attempts to complete a task request. User task
+ * management requests are allowed to be completed during discovery.
+ *
+ * @param[in] domain This parameter specifies the domain object
+ * on which the user is attempting to perform a complete IO
+ * operation.
+ * @param[in] remote_device This parameter specifies the remote device
+ * object on which the user is attempting to perform a complete
+ * IO operation.
+ * @param[in] task_request This parameter specifies the task request that
+ * is being completed.
+ *
+ * @return This method returns an indication of whether the complete task
+ * management operation succeeded.
+ * @retval SCI_SUCCESS This value is returned when the complete task request
+ * is successful.
+ */
+static
+SCI_STATUS scif_sas_domain_discovering_complete_task_handler(
+ SCI_BASE_DOMAIN_T * domain,
+ SCI_BASE_REMOTE_DEVICE_T * remote_device,
+ SCI_BASE_REQUEST_T * task_request
+)
+{
+ SCI_STATUS status;
+
+ SCIF_LOG_TRACE((
+ sci_base_object_get_logger(domain),
+ SCIF_LOG_OBJECT_DOMAIN | SCIF_LOG_OBJECT_TASK_MANAGEMENT,
+ "scif_sas_domain_discovering_complete_task_handler(0x%x, 0x%x, 0x%x) enter\n",
+ domain, remote_device, task_request
+ ));
+
+ status = scif_sas_domain_ready_complete_task_handler(
+ domain, remote_device, task_request
+ );
+
+ return status;
+}
+
+//******************************************************************************
+//* D E F A U L T H A N D L E R S
+//******************************************************************************
+
+/**
+ * @brief This method provides default handling (i.e. returns an error)
+ * when a user attempts to discover a domain and a discovery
+ * operation is not allowed.
+ *
+ * @param[in] domain This parameter specifies the domain object
+ * on which the user is attempting to perform an discover
+ * operation.
+ * @param[in] op_timeout This parameter specifies the timeout
+ * (in milliseconds) for the entire discovery operation.
+ * This timeout value should be some multiple of the
+ * individual device_timeout value.
+ * @param[in] device_timeout This parameter specifies the timeout
+ * (in milliseconds) for an individual device being discovered
+ * and configured during this operation.
+ *
+ * @return This method returns an indication that discovery operations
+ * are not allowed.
+ * @retval SCI_FAILURE_INVALID_STATE This value is always returned.
+ */
+static
+SCI_STATUS scif_sas_domain_default_discover_handler(
+ SCI_BASE_DOMAIN_T * domain,
+ U32 op_timeout,
+ U32 device_timeout
+)
+{
+ SCIF_LOG_WARNING((
+ sci_base_object_get_logger((SCIF_SAS_DOMAIN_T *)domain),
+ SCIF_LOG_OBJECT_DOMAIN | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
+ "Domain:0x%x State:0x%x requested to discover in invalid state\n",
+ domain,
+ sci_base_state_machine_get_state(&domain->state_machine)
+ ));
+
+ return SCI_FAILURE_INVALID_STATE;
+}
+
+/**
+ * @brief This method provides default processing for reception of a port
+ * ready notification from the core.
+ *
+ * @param[in] domain This parameter specifies the domain object
+ * on which the core port has just come ready.
+ *
+ * @return
+ */
+static
+SCI_STATUS scif_sas_domain_default_port_ready_handler(
+ SCI_BASE_DOMAIN_T * domain
+)
+{
+ SCIF_LOG_INFO((
+ sci_base_object_get_logger(domain),
+ SCIF_LOG_OBJECT_DOMAIN,
+ "Domain:0x%x State:0x%x port now ready\n",
+ domain,
+ sci_base_state_machine_get_state(&domain->state_machine)
+ ));
+
+ return SCI_SUCCESS;
+}
+
+/**
+ * @brief This method provides default processing for reception of a port
+ * NOT ready notification from the core.
+ *
+ * @param[in] domain This parameter specifies the domain object
+ * on which the core port has just come ready.
+ *
+ * @return
+ */
+static
+SCI_STATUS scif_sas_domain_default_port_not_ready_handler(
+ SCI_BASE_DOMAIN_T * domain,
+ U32 reason_code
+)
+{
+ SCIF_LOG_WARNING((
+ sci_base_object_get_logger(domain),
+ SCIF_LOG_OBJECT_DOMAIN,
+ "Domain:0x%x State:0x%x Port Not Ready 0x%x in invalid state\n",
+ domain,
+ sci_base_state_machine_get_state(&domain->state_machine),
+ reason_code
+ ));
+
+ return SCI_FAILURE_INVALID_STATE;
+}
+
+/**
+ * @brief This method provides default handling (i.e. returns an error)
+ * when a user attempts to start an IO on a domain and a start
+ * IO operation is not allowed.
+ *
+ * @param[in] domain This parameter specifies the domain object
+ * on which the user is attempting to perform a start IO
+ * operation.
+ * @param[in] remote_device This parameter specifies the remote device
+ * object on which the user is attempting to perform a start IO
+ * operation.
+ * @param[in] io_request This parameter specifies the io request that is
+ * being started.
+ *
+ * @return This method returns an indication that start IO operations
+ * are not allowed.
+ * @retval SCI_FAILURE_INVALID_STATE This value is always returned.
+ */
+static
+SCI_STATUS scif_sas_domain_default_start_io_handler(
+ SCI_BASE_DOMAIN_T * domain,
+ SCI_BASE_REMOTE_DEVICE_T * remote_device,
+ SCI_BASE_REQUEST_T * io_request
+)
+{
+ SCIF_LOG_WARNING((
+ sci_base_object_get_logger(domain),
+ SCIF_LOG_OBJECT_DOMAIN,
+ "Domain:0x%x Device:0x%x State:0x%x start IO message invalid\n",
+ domain, remote_device,
+ sci_base_state_machine_get_state(&domain->state_machine)
+ ));
+
+ return SCI_FAILURE_INVALID_STATE;
+}
+
+/**
+ * @brief This method provides default handling (i.e. returns an error)
+ * when a user attempts to complete an IO on a domain and a
+ * complete IO operation is not allowed.
+ *
+ * @param[in] domain This parameter specifies the domain object
+ * on which the user is attempting to perform a complete IO
+ * operation.
+ * @param[in] remote_device This parameter specifies the remote device
+ * object on which the user is attempting to perform a complete IO
+ * operation.
+ * @param[in] io_request This parameter specifies the io request that is
+ * being completed.
+ *
+ * @return This method returns an indication that complete IO operations
+ * are not allowed.
+ * @retval SCI_FAILURE_INVALID_STATE This value is always returned.
+ */
+static
+SCI_STATUS scif_sas_domain_default_complete_io_handler(
+ SCI_BASE_DOMAIN_T * domain,
+ SCI_BASE_REMOTE_DEVICE_T * remote_device,
+ SCI_BASE_REQUEST_T * io_request
+)
+{
+ SCIF_LOG_WARNING((
+ sci_base_object_get_logger(domain),
+ SCIF_LOG_OBJECT_DOMAIN,
+ "Domain:0x%x Device:0x%x State:0x%x complete IO message invalid\n",
+ domain, remote_device,
+ sci_base_state_machine_get_state(&domain->state_machine)
+ ));
+
+ return SCI_FAILURE_INVALID_STATE;
+}
+
+
+/**
+ * @brief This method provides default handling (i.e. returns an error)
+ * when a user attempts to complete an IO on a domain and a
+ * complete IO operation is not allowed.
+ *
+ * @param[in] domain This parameter specifies the domain object
+ * on which the user is attempting to perform a complete IO
+ * operation.
+ * @param[in] remote_device This parameter specifies the remote device
+ * object on which the user is attempting to perform a complete IO
+ * operation.
+ * @param[in] io_request This parameter specifies the io request that is
+ * being completed.
+ *
+ * @return This method returns an indication that complete IO operations
+ * are not allowed.
+ * @retval SCI_FAILURE_INVALID_STATE This value is always returned.
+ */
+static
+SCI_STATUS scif_sas_domain_default_complete_high_priority_io_handler(
+ SCI_BASE_DOMAIN_T * domain,
+ SCI_BASE_REMOTE_DEVICE_T * remote_device,
+ SCI_BASE_REQUEST_T * io_request,
+ void * response_data,
+ SCI_IO_STATUS completion_status
+)
+{
+ SCIF_LOG_WARNING((
+ sci_base_object_get_logger(domain),
+ SCIF_LOG_OBJECT_DOMAIN,
+ "Domain:0x%x Device:0x%x State:0x%x complete IO message invalid\n",
+ domain, remote_device,
+ sci_base_state_machine_get_state(&domain->state_machine)
+ ));
+
+ return SCI_FAILURE_INVALID_STATE;
+}
+
+/**
+ * @brief This method provides default handling (i.e. returns an error)
+ * when a user attempts to continue an IO on a domain and a
+ * continue IO operation is not allowed.
+ *
+ * @param[in] domain This parameter specifies the domain object
+ * on which the user is attempting to perform a continue IO
+ * operation.
+ * @param[in] remote_device This parameter specifies the remote device
+ * object on which the user is attempting to perform a start IO
+ * operation.
+ * @param[in] io_request This parameter specifies the io request that is
+ * being started.
+ *
+ * @return This method returns an indication that continue IO operations
+ * are not allowed.
+ * @retval SCI_FAILURE_INVALID_STATE This value is always returned.
+ */
+static
+SCI_STATUS scif_sas_domain_default_continue_io_handler(
+ SCI_BASE_DOMAIN_T * domain,
+ SCI_BASE_REMOTE_DEVICE_T * remote_device,
+ SCI_BASE_REQUEST_T * io_request
+)
+{
+ SCIF_LOG_WARNING((
+ sci_base_object_get_logger(domain),
+ SCIF_LOG_OBJECT_DOMAIN,
+ "Domain:0x%x Device:0x%x State:0x%x contineu IO message invalid\n",
+ domain, remote_device,
+ sci_base_state_machine_get_state(&domain->state_machine)
+ ));
+
+ return SCI_FAILURE_INVALID_STATE;
+}
+
+/**
+ * @brief This method provides default handling (i.e. returns an error)
+ * when a user attempts to start a task on a domain and a start
+ * task operation is not allowed.
+ *
+ * @param[in] domain This parameter specifies the domain object
+ * on which the user is attempting to perform a start task
+ * operation.
+ * @param[in] remote_device This parameter specifies the remote device
+ * object on which the user is attempting to perform a start IO
+ * operation.
+ * @param[in] task_request This parameter specifies the task request that
+ * is being started.
+ *
+ * @return This method returns an indication that start task operations
+ * are not allowed.
+ * @retval SCI_FAILURE_INVALID_STATE This value is always returned.
+ */
+static
+SCI_STATUS scif_sas_domain_default_start_task_handler(
+ SCI_BASE_DOMAIN_T * domain,
+ SCI_BASE_REMOTE_DEVICE_T * remote_device,
+ SCI_BASE_REQUEST_T * task_request
+)
+{
+ SCIF_LOG_WARNING((
+ sci_base_object_get_logger(domain),
+ SCIF_LOG_OBJECT_DOMAIN,
+ "Domain:0x%x Device:0x%x State:0x%x start task message invalid\n",
+ domain, remote_device,
+ sci_base_state_machine_get_state(&domain->state_machine)
+ ));
+
+ return SCI_FAILURE_INVALID_STATE;
+}
+
+/**
+ * @brief This method provides default handling (i.e. returns an error)
+ * when a user attempts to complete a task on a domain and a
+ * complete task operation is not allowed.
+ *
+ * @param[in] domain This parameter specifies the domain object
+ * on which the user is attempting to perform a complete task
+ * operation.
+ * @param[in] remote_device This parameter specifies the remote device
+ * object on which the user is attempting to perform a start IO
+ * operation.
+ * @param[in] task_request This parameter specifies the task request that
+ * is being started.
+ *
+ * @return This method returns an indication that complete task operations
+ * are not allowed.
+ * @retval SCI_FAILURE_INVALID_STATE This value is always returned.
+ */
+static
+SCI_STATUS scif_sas_domain_default_complete_task_handler(
+ SCI_BASE_DOMAIN_T * domain,
+ SCI_BASE_REMOTE_DEVICE_T * remote_device,
+ SCI_BASE_REQUEST_T * task_request
+)
+{
+ SCIF_LOG_WARNING((
+ sci_base_object_get_logger(domain),
+ SCIF_LOG_OBJECT_DOMAIN,
+ "Domain:0x%x Device:0x%x State:0x%x complete task message invalid\n",
+ domain, remote_device,
+ sci_base_state_machine_get_state(&domain->state_machine)
+ ));
+
+ return SCI_FAILURE_INVALID_STATE;
+}
+
+/**
+ * @brief This method provides default handling (i.e. returns an error)
+ * when a remote device start operation completes in a state.
+ *
+ * @param[in] domain This parameter specifies the domain object
+ * on which the remote device start operation is completing.
+ * @param[in] remote_device This parameter specifies the remote device
+ * for which the start operation is completing.
+ *
+ * @return This method returns an indication that start operation
+ * completion is not allowed.
+ * @retval SCI_FAILURE_INVALID_STATE This value is always returned.
+ */
+static
+SCI_STATUS scif_sas_domain_default_device_start_complete_handler(
+ SCI_BASE_DOMAIN_T * domain,
+ SCI_BASE_REMOTE_DEVICE_T * remote_device
+)
+{
+ SCIF_LOG_WARNING((
+ sci_base_object_get_logger(domain),
+ SCIF_LOG_OBJECT_DOMAIN,
+ "Domain:0x%x Device:0x%x State:0x%x device stop complete message invalid\n",
+ domain, remote_device,
+ sci_base_state_machine_get_state(&domain->state_machine)
+ ));
+
+ return SCI_FAILURE_INVALID_STATE;
+}
+
+/**
+ * @brief This method provides default handling (i.e. returns an error)
+ * when a remote device stop operation completes in a state.
+ *
+ * @param[in] domain This parameter specifies the domain object
+ * on which the remote device stop operation is completing.
+ * @param[in] remote_device This parameter specifies the remote device
+ * for which the stop operation is completing.
+ *
+ * @return This method returns an indication that stop operation
+ * completion is not allowed.
+ * @retval SCI_FAILURE_INVALID_STATE This value is always returned.
+ */
+static
+SCI_STATUS scif_sas_domain_default_device_stop_complete_handler(
+ SCI_BASE_DOMAIN_T * domain,
+ SCI_BASE_REMOTE_DEVICE_T * remote_device
+)
+{
+ SCIF_LOG_WARNING((
+ sci_base_object_get_logger(domain),
+ SCIF_LOG_OBJECT_DOMAIN,
+ "Domain:0x%x Device:0x%x State:0x%x device stop complete message invalid\n",
+ domain, remote_device,
+ sci_base_state_machine_get_state(&domain->state_machine)
+ ));
+
+ return SCI_FAILURE_INVALID_STATE;
+}
+
+/**
+ * @brief This method provides default handling (i.e. returns an error)
+ * when sci user try to destruct a remote device of this domain.
+ *
+ * @param[in] domain This parameter specifies the domain object
+ * on which the remote device is to be destructed.
+ * @param[in] remote_device This parameter specifies the remote device
+ * to be destructed.
+ *
+ * @return This method returns an indication that device destruction
+ * is not allowed.
+ * @retval SCI_FAILURE_INVALID_STATE This value is always returned.
+ */
+static
+SCI_STATUS scif_sas_domain_default_device_destruct_handler(
+ SCI_BASE_DOMAIN_T * domain,
+ SCI_BASE_REMOTE_DEVICE_T * remote_device
+)
+{
+ SCIF_LOG_WARNING((
+ sci_base_object_get_logger(domain),
+ SCIF_LOG_OBJECT_DOMAIN,
+ "Domain:0x%x Device:0x%x State:0x%x device destruct in invalid state\n",
+ domain, remote_device,
+ sci_base_state_machine_get_state(&domain->state_machine)
+ ));
+
+ return SCI_FAILURE_INVALID_STATE;
+}
+
+
+/**
+ * @brief This method provides handling when sci user destruct a remote
+ * device of this domain in discovering state. Mainly the device
+ * is removed from domain's remote_device_list.
+ *
+ * @param[in] domain This parameter specifies the domain object
+ * on which the remote device is to be destructed.
+ * @param[in] remote_device This parameter specifies the remote device
+ * to be destructed.
+ *
+ * @return This method returns a status of the device destruction.
+ * @retval SCI_SUCCESS This value is returned when a remote device is
+ * successfully removed from domain.
+ */
+static
+SCI_STATUS scif_sas_domain_discovering_device_destruct_handler(
+ SCI_BASE_DOMAIN_T * domain,
+ SCI_BASE_REMOTE_DEVICE_T * remote_device
+)
+{
+ SCIF_SAS_DOMAIN_T * fw_domain = (SCIF_SAS_DOMAIN_T *)domain;
+
+ SCIF_LOG_WARNING((
+ sci_base_object_get_logger(domain),
+ SCIF_LOG_OBJECT_DOMAIN,
+ "Domain:0x%x Device:0x%x State:0x%x device destruct in domain DISCOVERING state\n",
+ domain, remote_device,
+ sci_base_state_machine_get_state(&domain->state_machine)
+ ));
+
+ //remove the remote device from domain's remote_device_list
+ sci_abstract_list_erase(
+ &(fw_domain->remote_device_list),
+ remote_device
+ );
+
+ return SCI_SUCCESS;
+}
+
+
+#define scif_sas_domain_stopped_discover_handler \
+ scif_sas_domain_ready_discover_handler
+
+#define scif_sas_domain_default_start_high_priority_io_handler \
+ scif_sas_domain_default_start_io_handler
+
+
+SCI_BASE_DOMAIN_STATE_HANDLER_T
+ scif_sas_domain_state_handler_table[SCI_BASE_DOMAIN_MAX_STATES] =
+{
+ // SCI_BASE_DOMAIN_STATE_INITIAL
+ {
+ scif_sas_domain_default_discover_handler,
+ scif_sas_domain_default_port_ready_handler,
+ scif_sas_domain_default_port_not_ready_handler,
+ scif_sas_domain_default_device_start_complete_handler,
+ scif_sas_domain_default_device_stop_complete_handler,
+ scif_sas_domain_default_device_destruct_handler,
+ scif_sas_domain_default_start_io_handler,
+ scif_sas_domain_default_start_high_priority_io_handler,
+ scif_sas_domain_default_complete_io_handler,
+ scif_sas_domain_default_complete_high_priority_io_handler,
+ scif_sas_domain_default_continue_io_handler,
+ scif_sas_domain_default_start_task_handler,
+ scif_sas_domain_default_complete_task_handler
+ },
+ // SCI_BASE_DOMAIN_STATE_STARTING
+ {
+ scif_sas_domain_default_discover_handler,
+ scif_sas_domain_starting_port_ready_handler,
+ scif_sas_domain_default_port_not_ready_handler,
+ scif_sas_domain_default_device_start_complete_handler,
+ scif_sas_domain_default_device_stop_complete_handler,
+ scif_sas_domain_default_device_destruct_handler,
+ scif_sas_domain_default_start_io_handler,
+ scif_sas_domain_default_start_high_priority_io_handler,
+ scif_sas_domain_default_complete_io_handler,
+ scif_sas_domain_default_complete_high_priority_io_handler,
+ scif_sas_domain_default_continue_io_handler,
+ scif_sas_domain_default_start_task_handler,
+ scif_sas_domain_default_complete_task_handler
+ },
+ // SCI_BASE_DOMAIN_STATE_READY
+ {
+ scif_sas_domain_ready_discover_handler,
+ scif_sas_domain_default_port_ready_handler,
+ scif_sas_domain_ready_port_not_ready_handler,
+ scif_sas_domain_default_device_start_complete_handler,
+ scif_sas_domain_default_device_stop_complete_handler,
+ scif_sas_domain_default_device_destruct_handler,
+ scif_sas_domain_ready_start_io_handler,
+ scif_sas_domain_ready_start_high_priority_io_handler,
+ scif_sas_domain_ready_complete_io_handler,
+ scif_sas_domain_ready_complete_high_priority_io_handler,
+ scif_sas_domain_ready_continue_io_handler,
+ scif_sas_domain_ready_start_task_handler,
+ scif_sas_domain_ready_complete_task_handler
+ },
+ // SCI_BASE_DOMAIN_STATE_STOPPING
+ {
+ scif_sas_domain_default_discover_handler,
+ scif_sas_domain_default_port_ready_handler,
+ scif_sas_domain_default_port_not_ready_handler,
+ scif_sas_domain_default_device_start_complete_handler,
+ scif_sas_domain_stopping_device_stop_complete_handler,
+ scif_sas_domain_default_device_destruct_handler,
+ scif_sas_domain_default_start_io_handler,
+ scif_sas_domain_default_start_high_priority_io_handler,
+ scif_sas_domain_stopping_complete_io_handler,
+ scif_sas_domain_stopping_complete_high_priority_io_handler,
+ scif_sas_domain_default_continue_io_handler,
+ scif_sas_domain_default_start_task_handler,
+ scif_sas_domain_stopping_complete_task_handler
+ },
+ // SCI_BASE_DOMAIN_STATE_STOPPED
+ {
+ scif_sas_domain_stopped_discover_handler,
+ scif_sas_domain_default_port_ready_handler,
+ scif_sas_domain_default_port_not_ready_handler,
+ scif_sas_domain_default_device_start_complete_handler,
+ scif_sas_domain_default_device_stop_complete_handler,
+ scif_sas_domain_default_device_destruct_handler,
+ scif_sas_domain_default_start_io_handler,
+ scif_sas_domain_default_start_high_priority_io_handler,
+ scif_sas_domain_default_complete_io_handler,
+ scif_sas_domain_default_complete_high_priority_io_handler,
+ scif_sas_domain_default_continue_io_handler,
+ scif_sas_domain_default_start_task_handler,
+ scif_sas_domain_default_complete_task_handler
+ },
+ // SCI_BASE_DOMAIN_STATE_DISCOVERING
+ {
+ scif_sas_domain_default_discover_handler,
+ scif_sas_domain_default_port_ready_handler,
+ scif_sas_domain_discovering_port_not_ready_handler,
+ scif_sas_domain_discovering_device_start_complete_handler,
+ scif_sas_domain_discovering_device_stop_complete_handler,
+ scif_sas_domain_discovering_device_destruct_handler, //
+ scif_sas_domain_default_start_io_handler,
+ scif_sas_domain_discovering_start_high_priority_io_handler,
+ scif_sas_domain_discovering_complete_io_handler,
+ scif_sas_domain_discovering_complete_high_priority_io_handler, //
+ scif_sas_domain_discovering_continue_io_handler,
+ scif_sas_domain_discovering_start_task_handler,
+ scif_sas_domain_discovering_complete_task_handler
+ }
+};
+
diff --git a/sys/dev/isci/scil/scif_sas_domain_states.c b/sys/dev/isci/scil/scif_sas_domain_states.c
new file mode 100644
index 0000000..803c26a
--- /dev/null
+++ b/sys/dev/isci/scil/scif_sas_domain_states.c
@@ -0,0 +1,612 @@
+/*-
+ * 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.
+ *
+ * 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 <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/**
+ * @file
+ *
+ * @brief This file contains all of the entrance and exit methods for each
+ * of the domain states defined by the SCI_BASE_DOMAIN state
+ * machine.
+ */
+
+#include <dev/isci/scil/intel_sas.h>
+#include <dev/isci/scil/scic_port.h>
+
+#include <dev/isci/scil/scif_sas_logger.h>
+#include <dev/isci/scil/scif_sas_domain.h>
+#include <dev/isci/scil/scif_sas_controller.h>
+#include <dev/isci/scil/scic_controller.h>
+
+//******************************************************************************
+//* P R O T E C T E D M E T H O D S
+//******************************************************************************
+
+/**
+ * @brief This method will attempt to transition to the stopped state.
+ * The transition will only occur if the criteria for transition is
+ * met (i.e. all IOs are complete and all devices are stopped).
+ *
+ * @param[in] fw_domain This parameter specifies the domain in which to
+ * to attempt to perform the transition.
+ *
+ * @return none
+ */
+void scif_sas_domain_transition_to_stopped_state(
+ SCIF_SAS_DOMAIN_T * fw_domain
+)
+{
+ SCIF_LOG_TRACE((
+ sci_base_object_get_logger(fw_domain),
+ SCIF_LOG_OBJECT_DOMAIN | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
+ "scif_sas_domain_transition_to_stopped_state(0x%x) enter\n",
+ fw_domain
+ ));
+
+ // If IOs are quiesced, and all remote devices are stopped,
+ // then transition directly to the STOPPED state.
+ if ( (fw_domain->request_list.element_count == 0)
+ && (fw_domain->device_start_count == 0) )
+ {
+ SCIF_LOG_INFO((
+ sci_base_object_get_logger(fw_domain),
+ SCIF_LOG_OBJECT_DOMAIN | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
+ "Domain:0x%x immediate transition to STOPPED\n",
+ fw_domain
+ ));
+
+ sci_base_state_machine_change_state(
+ &fw_domain->parent.state_machine, SCI_BASE_DOMAIN_STATE_STOPPED
+ );
+ }
+}
+
+
+/**
+ * @brief This method is called upon entrance to all states where the
+ * previous state may have been the DISCOVERING state.
+ * We issue the scif_cb_domain_discovery_complete() notification
+ * from this method, assuming pre-requisites are met, as opposed
+ * to in the exit handler of the DISCOVERING state, so that the
+ * appropriate state handlers are in place should the user decide
+ * to call scif_domain_discover() again.
+ *
+ * @param[in] fw_domain This parameter specifies the domain for which
+ * the state transition has occurred.
+ *
+ * @return none
+ */
+static
+void scif_sas_domain_transition_from_discovering_state(
+ SCIF_SAS_DOMAIN_T * fw_domain
+)
+{
+ SCIF_LOG_TRACE((
+ sci_base_object_get_logger(fw_domain),
+ SCIF_LOG_OBJECT_DOMAIN | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
+ "scif_sas_domain_transition_from_discovering_state(0x%x) enter\n",
+ fw_domain
+ ));
+
+ if (fw_domain->parent.state_machine.previous_state_id
+ == SCI_BASE_DOMAIN_STATE_DISCOVERING)
+ {
+ scif_sas_controller_restore_interrupt_coalescence(fw_domain->controller);
+
+ scif_cb_timer_stop(fw_domain->controller, fw_domain->operation.timer);
+
+ scif_cb_domain_discovery_complete(
+ fw_domain->controller, fw_domain, fw_domain->operation.status
+ );
+ }
+}
+
+
+/**
+ * @brief This method is called upon entrance to DISCOVERING state. Right before
+ * transitioning to DISCOVERING state, we temporarily change interrupt
+ * coalescence scheme.
+ *
+ * @param[in] fw_domain This parameter specifies the domain for which
+ * the state transition has occurred.
+ *
+ * @return none
+ */
+void scif_sas_domain_transition_to_discovering_state(
+ SCIF_SAS_DOMAIN_T * fw_domain
+)
+{
+ scif_sas_controller_save_interrupt_coalescence(fw_domain->controller);
+
+ sci_base_state_machine_change_state(
+ &fw_domain->parent.state_machine, SCI_BASE_DOMAIN_STATE_DISCOVERING
+ );
+}
+
+
+/**
+ * @brief This method implements the actions taken when entering the
+ * INITIAL state.
+ *
+ * @param[in] object This parameter specifies the base object for which
+ * the state transition is occurring. This is cast into a
+ * SCIF_SAS_DOMAIN object in the method implementation.
+ *
+ * @return none
+ */
+static
+void scif_sas_domain_initial_state_enter(
+ SCI_BASE_OBJECT_T * object
+)
+{
+ SCIF_SAS_DOMAIN_T * fw_domain = (SCIF_SAS_DOMAIN_T *)object;
+
+ SET_STATE_HANDLER(
+ fw_domain,
+ scif_sas_domain_state_handler_table,
+ SCI_BASE_DOMAIN_STATE_INITIAL
+ );
+
+ SCIF_LOG_TRACE((
+ sci_base_object_get_logger(fw_domain),
+ SCIF_LOG_OBJECT_DOMAIN,
+ "scif_sas_domain_initial_state_enter(0x%x) enter\n",
+ fw_domain
+ ));
+}
+
+/**
+ * @brief This method implements the actions taken when entering the
+ * STARTING state. This includes setting the state handlers and
+ * checking to see if the core port has already become READY.
+ *
+ * @param[in] object This parameter specifies the base object for which
+ * the state transition is occurring. This is cast into a
+ * SCIF_SAS_DOMAIN object in the method implementation.
+ *
+ * @return none
+ */
+static
+void scif_sas_domain_starting_state_enter(
+ SCI_BASE_OBJECT_T * object
+)
+{
+ SCIF_SAS_DOMAIN_T * fw_domain = (SCIF_SAS_DOMAIN_T *)object;
+
+ SET_STATE_HANDLER(
+ fw_domain,
+ scif_sas_domain_state_handler_table,
+ SCI_BASE_DOMAIN_STATE_STARTING
+ );
+
+ SCIF_LOG_TRACE((
+ sci_base_object_get_logger(fw_domain),
+ SCIF_LOG_OBJECT_DOMAIN | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
+ "scif_sas_domain_starting_state_enter(0x%x) enter\n",
+ fw_domain
+ ));
+
+ scif_sas_domain_transition_from_discovering_state(fw_domain);
+
+ // If we entered the STARTING state and the core port is actually ready,
+ // then directly transition into the READY state. This can occur
+ // if we were in the middle of discovery when the port failed
+ // (causing a transition to STOPPING), then before reaching STOPPED
+ // the port becomes ready again.
+ if (fw_domain->is_port_ready == TRUE)
+ {
+ sci_base_state_machine_change_state(
+ &fw_domain->parent.state_machine, SCI_BASE_DOMAIN_STATE_READY
+ );
+ }
+}
+
+/**
+ * @brief This method implements the actions taken when entering the
+ * READY state. If the transition into this state came from:
+ * - the STARTING state, then alert the user via a
+ * scif_cb_domain_change_notification() that the domain
+ * has at least 1 device ready for discovery.
+ * - the DISCOVERING state, then alert the user that
+ * discovery is complete via the
+ * scif_cb_domain_discovery_complete() notification that
+ * discovery is finished.
+ *
+ * @param[in] object This parameter specifies the base object for which
+ * the state transition is occurring. This is cast into a
+ * SCIF_SAS_DOMAIN object in the method implementation.
+ *
+ * @return none
+ */
+static
+void scif_sas_domain_ready_state_enter(
+ SCI_BASE_OBJECT_T * object
+)
+{
+ SCIF_SAS_DOMAIN_T * fw_domain = (SCIF_SAS_DOMAIN_T *)object;
+
+ SET_STATE_HANDLER(
+ fw_domain,
+ scif_sas_domain_state_handler_table,
+ SCI_BASE_DOMAIN_STATE_READY
+ );
+
+ SCIF_LOG_TRACE((
+ sci_base_object_get_logger(fw_domain),
+ SCIF_LOG_OBJECT_DOMAIN | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
+ "scif_sas_domain_ready_state_enter(0x%x) enter\n",
+ fw_domain
+ ));
+
+ if (fw_domain->parent.state_machine.previous_state_id
+ == SCI_BASE_DOMAIN_STATE_STARTING)
+ {
+ scif_cb_domain_ready(fw_domain->controller, fw_domain);
+
+ // Only indicate the domain change notification if the previous
+ // state was the STARTING state. We issue the notification here
+ // as opposed to exit of the STARTING state so that the appropriate
+ // state handlers are in place should the user call
+ // scif_domain_discover() from scif_cb_domain_change_notification()
+ scif_cb_domain_change_notification(fw_domain->controller, fw_domain);
+ }
+ else if (fw_domain->parent.state_machine.previous_state_id
+ == SCI_BASE_DOMAIN_STATE_DISCOVERING)
+ {
+ //if domain discovery timed out, we will NOT go back to discover even
+ //the broadcast change count is not zero. Instead we finish the discovery
+ //back to user. User can check the operation status and decide to
+ //retry discover all over again.
+ if (fw_domain->operation.status == SCI_FAILURE_TIMEOUT)
+ fw_domain->broadcast_change_count = 0;
+
+ // Check the broadcast change count to determine if discovery
+ // is indeed complete.
+ if (fw_domain->broadcast_change_count == 0)
+ {
+ scif_sas_domain_transition_from_discovering_state(fw_domain);
+ scif_cb_domain_ready(fw_domain->controller, fw_domain);
+ }
+ else
+ {
+ // The broadcast change count indicates something my have
+ // changed in the domain, while a discovery was ongoing.
+ // Thus, we should start discovery over again.
+ sci_base_state_machine_change_state(
+ &fw_domain->parent.state_machine, SCI_BASE_DOMAIN_STATE_DISCOVERING
+ );
+ }
+
+ // Enable the BCN because underneath hardware may disabled any further
+ // BCN.
+ scic_port_enable_broadcast_change_notification(fw_domain->core_object);
+ }
+}
+
+/**
+ * @brief This method implements the actions taken when exiting the
+ * READY state.
+ *
+ * @param[in] object This parameter specifies the base object for which
+ * the state transition is occurring. This is cast into a
+ * SCIF_SAS_DOMAIN object in the method implementation.
+ *
+ * @return none
+ */
+static
+void scif_sas_domain_ready_state_exit(
+ SCI_BASE_OBJECT_T * object
+)
+{
+ SCIF_SAS_DOMAIN_T * fw_domain = (SCIF_SAS_DOMAIN_T *)object;
+
+ SCIF_LOG_TRACE((
+ sci_base_object_get_logger(fw_domain),
+ SCIF_LOG_OBJECT_DOMAIN | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
+ "scif_sas_domain_ready_state_exit(0x%x) enter\n",
+ fw_domain
+ ));
+
+ scif_cb_domain_not_ready(fw_domain->controller, fw_domain);
+}
+
+/**
+ * @brief This method implements the actions taken when entering the
+ * STOPPING state.
+ *
+ * @param[in] object This parameter specifies the base object for which
+ * the state transition is occurring. This is cast into a
+ * SCIF_SAS_DOMAIN object in the method implementation.
+ *
+ * @return none
+ */
+static
+void scif_sas_domain_stopping_state_enter(
+ SCI_BASE_OBJECT_T * object
+)
+{
+ SCIF_SAS_REMOTE_DEVICE_T * fw_device;
+ SCIF_SAS_DOMAIN_T * fw_domain = (SCIF_SAS_DOMAIN_T *)object;
+ SCI_ABSTRACT_ELEMENT_T * element = sci_abstract_list_get_front(
+ &fw_domain->remote_device_list
+ );
+
+ SET_STATE_HANDLER(
+ fw_domain,
+ scif_sas_domain_state_handler_table,
+ SCI_BASE_DOMAIN_STATE_STOPPING
+ );
+
+ // This must be invoked after the state handlers are set to ensure
+ // appropriate processing will occur if the user attempts to perform
+ // additional actions.
+ scif_sas_domain_transition_from_discovering_state(fw_domain);
+
+ SCIF_LOG_TRACE((
+ sci_base_object_get_logger(fw_domain),
+ SCIF_LOG_OBJECT_DOMAIN | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
+ "scif_sas_domain_stopping_state_enter(0x%x) enter\n",
+ fw_domain
+ ));
+
+ scif_sas_high_priority_request_queue_purge_domain(
+ &fw_domain->controller->hprq, fw_domain
+ );
+
+ // Search the domain's list of devices and put them all in the STOPPING
+ // state.
+ while (element != NULL)
+ {
+ fw_device = (SCIF_SAS_REMOTE_DEVICE_T*)
+ sci_abstract_list_get_object(element);
+
+ // This method will stop the core device. The core will terminate
+ // all IO requests currently outstanding.
+ fw_device->state_handlers->parent.stop_handler(&fw_device->parent);
+
+ element = sci_abstract_list_get_next(element);
+ }
+
+ // Attempt to transition to the stopped state.
+ scif_sas_domain_transition_to_stopped_state(fw_domain);
+}
+
+/**
+ * @brief This method implements the actions taken when entering the
+ * STOPPED state.
+ *
+ * @param[in] object This parameter specifies the base object for which
+ * the state transition is occurring. This is cast into a
+ * SCIF_SAS_DOMAIN object in the method implementation.
+ *
+ * @return none
+ */
+static
+void scif_sas_domain_stopped_state_enter(
+ SCI_BASE_OBJECT_T * object
+)
+{
+ SCIF_SAS_DOMAIN_T * fw_domain = (SCIF_SAS_DOMAIN_T *)object;
+
+ SET_STATE_HANDLER(
+ fw_domain,
+ scif_sas_domain_state_handler_table,
+ SCI_BASE_DOMAIN_STATE_STOPPED
+ );
+
+ SCIF_LOG_TRACE((
+ sci_base_object_get_logger(fw_domain),
+ SCIF_LOG_OBJECT_DOMAIN | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
+ "scif_sas_domain_stopped_state_enter(0x%x) enter\n",
+ fw_domain
+ ));
+
+ // A hot unplug of the direct attached device has occurred. Thus,
+ // notify the user. Note, if the controller is not in READY state,
+ // mostly likely the controller is in STOPPING or STOPPED state,
+ // meaning the controller is in the process of stopping, we should
+ // not call back to user in the middle of controller stopping.
+ if(fw_domain->controller->parent.state_machine.current_state_id
+ == SCI_BASE_CONTROLLER_STATE_READY)
+ scif_cb_domain_change_notification(fw_domain->controller, fw_domain);
+}
+
+/**
+ * @brief This method implements the actions taken when entering the
+ * DISCOVERING state. This includes determining from which
+ * state we entered. If we entered from stopping that some sort
+ * of hot-remove of the port occurred. In the hot-remove case
+ * all devices should be in the STOPPED state already and, as
+ * a result, are removed from the domain with a notification sent
+ * to the framework user.
+ *
+ * @note This method currently only handles hot-insert/hot-remove of
+ * direct attached SSP devices.
+ *
+ * @param[in] object This parameter specifies the base object for which
+ * the state transition is occurring. This is cast into a
+ * SCIF_SAS_DOMAIN object in the method implementation.
+ *
+ * @return none
+ */
+static
+void scif_sas_domain_discovering_state_enter(
+ SCI_BASE_OBJECT_T * object
+)
+{
+ SCIF_SAS_DOMAIN_T * fw_domain = (SCIF_SAS_DOMAIN_T *)object;
+
+ SET_STATE_HANDLER(
+ fw_domain,
+ scif_sas_domain_state_handler_table,
+ SCI_BASE_DOMAIN_STATE_DISCOVERING
+ );
+
+ SCIF_LOG_TRACE((
+ sci_base_object_get_logger(fw_domain),
+ SCIF_LOG_OBJECT_DOMAIN | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
+ "scif_sas_domain_discovering_state_enter(0x%x) enter\n",
+ fw_domain
+ ));
+
+ fw_domain->broadcast_change_count = 0;
+
+ // Did the domain just go through a port not ready action? If it did,
+ // then we will be entering from the STOPPED state.
+ if (fw_domain->parent.state_machine.previous_state_id
+ != SCI_BASE_DOMAIN_STATE_STOPPED)
+ {
+ SCIF_SAS_REMOTE_DEVICE_T * remote_device;
+ SCIC_PORT_PROPERTIES_T properties;
+
+ scic_port_get_properties(fw_domain->core_object, &properties);
+
+ // If the device has not yet been added to the domain, then
+ // inform the user that the device is new.
+ remote_device = (SCIF_SAS_REMOTE_DEVICE_T *)
+ scif_domain_get_device_by_sas_address(
+ fw_domain, &properties.remote.sas_address
+ );
+ if (remote_device == SCI_INVALID_HANDLE)
+ {
+ // simply notify the user of the new DA device and be done
+ // with discovery.
+ scif_cb_domain_da_device_added(
+ fw_domain->controller,
+ fw_domain,
+ &properties.remote.sas_address,
+ &properties.remote.protocols
+ );
+ }
+ else
+ {
+ if(properties.remote.protocols.u.bits.smp_target)
+ //kick off the smp discover process.
+ scif_sas_domain_start_smp_discover(fw_domain, remote_device);
+ }
+ }
+ else //entered from STOPPED state.
+ {
+ SCI_ABSTRACT_ELEMENT_T * current_element =
+ sci_abstract_list_get_front(&(fw_domain->remote_device_list) );
+
+ SCIF_SAS_REMOTE_DEVICE_T * fw_device;
+
+ while (current_element != NULL)
+ {
+ fw_device = (SCIF_SAS_REMOTE_DEVICE_T *)
+ sci_abstract_list_get_object(current_element);
+
+ ASSERT(fw_device->parent.state_machine.current_state_id
+ == SCI_BASE_REMOTE_DEVICE_STATE_STOPPED);
+
+ current_element =
+ sci_abstract_list_get_next(current_element);
+
+ SCIF_LOG_INFO((
+ sci_base_object_get_logger(fw_domain),
+ SCIF_LOG_OBJECT_DOMAIN | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
+ "Controller:0x%x Domain:0x%x Device:0x%x removed\n",
+ fw_domain->controller, fw_domain, fw_device
+ ));
+
+ // Notify the framework user of the device removal.
+ scif_cb_domain_device_removed(
+ fw_domain->controller, fw_domain, fw_device
+ );
+ }
+
+ ASSERT(fw_domain->request_list.element_count == 0);
+ ASSERT(sci_abstract_list_size(&fw_domain->remote_device_list) == 0);
+
+ sci_base_state_machine_change_state(
+ &fw_domain->parent.state_machine, SCI_BASE_DOMAIN_STATE_STARTING
+ );
+ }
+}
+
+SCI_BASE_STATE_T scif_sas_domain_state_table[SCI_BASE_DOMAIN_MAX_STATES] =
+{
+ {
+ SCI_BASE_DOMAIN_STATE_INITIAL,
+ scif_sas_domain_initial_state_enter,
+ NULL,
+ },
+ {
+ SCI_BASE_DOMAIN_STATE_STARTING,
+ scif_sas_domain_starting_state_enter,
+ NULL,
+ },
+ {
+ SCI_BASE_DOMAIN_STATE_READY,
+ scif_sas_domain_ready_state_enter,
+ scif_sas_domain_ready_state_exit,
+ },
+ {
+ SCI_BASE_DOMAIN_STATE_STOPPING,
+ scif_sas_domain_stopping_state_enter,
+ NULL,
+ },
+ {
+ SCI_BASE_DOMAIN_STATE_STOPPED,
+ scif_sas_domain_stopped_state_enter,
+ NULL,
+ },
+ {
+ SCI_BASE_DOMAIN_STATE_DISCOVERING,
+ scif_sas_domain_discovering_state_enter,
+ NULL,
+ }
+};
+
diff --git a/sys/dev/isci/scil/scif_sas_high_priority_request_queue.c b/sys/dev/isci/scil/scif_sas_high_priority_request_queue.c
new file mode 100644
index 0000000..a9aada7
--- /dev/null
+++ b/sys/dev/isci/scil/scif_sas_high_priority_request_queue.c
@@ -0,0 +1,161 @@
+/*-
+ * 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.
+ *
+ * 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 <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/**
+ * @file
+ *
+ * @brief This file contains all of method implementations specific to
+ * the high priority request queue (HPRQ). See the
+ * scif_sas_high_priority_request_queue.h file for additional
+ * information.
+ */
+
+#include <dev/isci/scil/scif_sas_high_priority_request_queue.h>
+
+#include <dev/isci/scil/scif_sas_logger.h>
+#include <dev/isci/scil/scif_sas_io_request.h>
+#include <dev/isci/scil/scif_sas_controller.h>
+
+/**
+ * @brief This method initializes the fields of the HPRQ. It should be
+ * called during the construction of the object containing or
+ * utilizing it (i.e. SCIF_SAS_CONTROLLER).
+ *
+ * @param[in] fw_hprq This parameter specific the high priority request
+ * queue object being constructed.
+ *
+ * @return none
+ */
+void scif_sas_high_priority_request_queue_construct(
+ SCIF_SAS_HIGH_PRIORITY_REQUEST_QUEUE_T * fw_hprq,
+ SCI_BASE_LOGGER_T * logger
+)
+{
+ SCIF_LOG_TRACE((
+ logger,
+ SCIF_LOG_OBJECT_CONTROLLER | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
+ "scif_sas_high_priority_request_queue_construct(0x%x,0x%x) enter\n",
+ fw_hprq, logger
+ ));
+
+ sci_base_object_construct((SCI_BASE_OBJECT_T*) &fw_hprq->lock, logger);
+ fw_hprq->lock.level = SCI_LOCK_LEVEL_NONE;
+
+ sci_pool_initialize(fw_hprq->pool);
+}
+
+/**
+ * @brief This method will ensure all internal requests destined for
+ * devices contained in the supplied domain are properly removed
+ * from the high priority request queue.
+ *
+ * @param[in] fw_hprq This parameter specifies the high priority request
+ * queue object for which to attempt to remove elements.
+ * @param[in] fw_domain This parameter specifies the domain for which to
+ * remove all high priority requests.
+ *
+ * @return none
+ */
+void scif_sas_high_priority_request_queue_purge_domain(
+ SCIF_SAS_HIGH_PRIORITY_REQUEST_QUEUE_T * fw_hprq,
+ SCIF_SAS_DOMAIN_T * fw_domain
+)
+{
+ SCIF_SAS_IO_REQUEST_T * fw_io;
+ POINTER_UINT io_address;
+ U32 index;
+ U32 element_count;
+
+ SCIF_LOG_TRACE((
+ sci_base_object_get_logger(&fw_hprq->lock),
+ SCIF_LOG_OBJECT_CONTROLLER | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
+ "scif_sas_high_priority_request_queue_purge_domain(0x%x,0x%x) enter\n",
+ fw_hprq, fw_domain
+ ));
+
+ element_count = sci_pool_count(fw_hprq->pool);
+
+ scif_cb_lock_acquire(fw_domain->controller, &fw_hprq->lock);
+
+ for (index = 0; index < element_count; index++)
+ {
+ sci_pool_get(fw_hprq->pool, io_address);
+
+ fw_io = (SCIF_SAS_IO_REQUEST_T*) io_address;
+
+ // If the high priority request is not intended for this domain,
+ // then it can be left in the pool.
+ if (fw_io->parent.device->domain != fw_domain)
+ {
+ sci_pool_put(fw_hprq->pool, io_address);
+ }
+ else
+ {
+ if (fw_io->parent.is_internal)
+ {
+ SCIF_SAS_INTERNAL_IO_REQUEST_T * fw_internal_io =
+ (SCIF_SAS_INTERNAL_IO_REQUEST_T *)fw_io;
+
+ // The request was intended for a device in the domain. Put it
+ // back in the pool of freely available internal request memory
+ // objects. The internal IO's timer is to be destoyed.
+ scif_sas_internal_io_request_destruct(fw_domain->controller, fw_internal_io);
+ }
+ }
+ }
+
+ scif_cb_lock_release(fw_domain->controller, &fw_hprq->lock);
+}
+
diff --git a/sys/dev/isci/scil/scif_sas_high_priority_request_queue.h b/sys/dev/isci/scil/scif_sas_high_priority_request_queue.h
new file mode 100644
index 0000000..4512850
--- /dev/null
+++ b/sys/dev/isci/scil/scif_sas_high_priority_request_queue.h
@@ -0,0 +1,123 @@
+/*-
+ * 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.
+ *
+ * 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.
+ *
+ * $FreeBSD$
+ */
+#ifndef _SCIF_SAS_HIGH_PRIORITY_REQUEST_QUEUE_H_
+#define _SCIF_SAS_HIGH_PRIORITY_REQUEST_QUEUE_H_
+
+/**
+ * @file
+ *
+ * @brief This file contains all of method prototypes and type
+ * definitions specific to the high priority request queue (HPRQ).
+ * The HPRQ is the mechanism through which internal requests or
+ * other important requests created by the framework are stored.
+ * The HPRQ is checked during the scif_controller_start_io() path
+ * and is given precedence over user supplied IO requests.
+ * Additionally, when requests are created there is an attempt to
+ * start them quickly.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif // __cplusplus
+
+#include <dev/isci/scil/sci_types.h>
+#include <dev/isci/scil/sci_base_object.h>
+#include <dev/isci/scil/sci_pool.h>
+#include <dev/isci/scil/scif_sas_domain.h>
+#include <dev/isci/scil/scif_sas_internal_io_request.h>
+
+typedef struct SCIF_SAS_LOCK
+{
+ SCI_BASE_OBJECT_T parent;
+
+ SCI_LOCK_LEVEL level;
+
+} SCIF_SAS_LOCK_T;
+
+/**
+ * @struct SCIF_SAS_HIGH_PRIORITY_REQUEST_QUEUE_T
+ *
+ * @brief This structure depicts the fields contain in the high
+ * priority request queue (HPRQ) object. The HPRQ is used
+ * to store IO or task requests that need to be completed
+ * in short order.
+ */
+typedef struct SCIF_SAS_HIGH_PRIORITY_REQUEST_QUEUE
+{
+ /**
+ * This field specifies the necessary lock information (e.g. level)
+ * that must be taken before items are added or removed from the
+ * queue.
+ */
+ SCIF_SAS_LOCK_T lock;
+
+ SCI_POOL_CREATE(pool, POINTER_UINT, SCIF_SAS_MAX_INTERNAL_REQUEST_COUNT);
+
+} SCIF_SAS_HIGH_PRIORITY_REQUEST_QUEUE_T;
+
+void scif_sas_high_priority_request_queue_construct(
+ SCIF_SAS_HIGH_PRIORITY_REQUEST_QUEUE_T * fw_hprq,
+ SCI_BASE_LOGGER_T * logger
+);
+
+void scif_sas_high_priority_request_queue_purge_domain(
+ SCIF_SAS_HIGH_PRIORITY_REQUEST_QUEUE_T * fw_hprq,
+ SCIF_SAS_DOMAIN_T * fw_domain
+);
+
+#ifdef __cplusplus
+}
+#endif // __cplusplus
+
+#endif // _SCIF_SAS_HIGH_PRIORITY_REQUEST_QUEUE_H_
diff --git a/sys/dev/isci/scil/scif_sas_internal_io_request.c b/sys/dev/isci/scil/scif_sas_internal_io_request.c
new file mode 100644
index 0000000..9d98190
--- /dev/null
+++ b/sys/dev/isci/scil/scif_sas_internal_io_request.c
@@ -0,0 +1,282 @@
+/*-
+ * 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.
+ *
+ * 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 <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/**
+ * @file
+ *
+ * @brief This file contains the implementation of the
+ * SCIF_SAS_INTERNAL_IO_REQUEST object.
+ */
+
+
+#include <dev/isci/scil/scic_io_request.h>
+#include <dev/isci/scil/scic_remote_device.h>
+#include <dev/isci/scil/scic_user_callback.h>
+#include <dev/isci/scil/scic_controller.h>
+#include <dev/isci/scil/scic_task_request.h>
+#include <dev/isci/scil/scif_user_callback.h>
+
+#include <dev/isci/scil/scif_sas_controller.h>
+#include <dev/isci/scil/scif_sas_domain.h>
+#include <dev/isci/scil/scif_sas_remote_device.h>
+#include <dev/isci/scil/scif_sas_io_request.h>
+#include <dev/isci/scil/scif_sas_internal_io_request.h>
+#include <dev/isci/scil/scif_sas_task_request.h>
+#include <dev/isci/scil/scif_sas_stp_io_request.h>
+#include <dev/isci/scil/scif_sas_logger.h>
+#include <dev/isci/scil/scif_sas_smp_io_request.h>
+#include <dev/isci/scil/sci_util.h>
+
+//******************************************************************************
+//* P U B L I C M E T H O D S
+//******************************************************************************
+
+/**
+ * @brief this routine return all memory needed for an internal request, both
+ * framework and core request.
+ *
+ * @return U32 size of all memory needed for an internal request
+ */
+U32 scif_sas_internal_request_get_object_size(
+ void
+)
+{
+ return MAX(
+ (sizeof(SCIF_SAS_INTERNAL_IO_REQUEST_T) + scic_io_request_get_object_size()),
+ (sizeof(SCIF_SAS_TASK_REQUEST_T) + scic_task_request_get_object_size())
+ );
+}
+
+
+/**
+ * @brief This method constructs an internal smp request.
+ *
+ * @param[in] fw_controller The framework controller
+ * @param[in] fw_device The smp device that the internal io targets to.
+ * @param[in] internal_io_memory The memory space for the internal io.
+ * @param[in] io_tag The io tag for the internl io to be constructed.
+ * @param[in] smp_command A pointer to the smp request data structure according
+ * to SAS protocol.
+ *
+ * @return Indicate if the internal io was successfully constructed.
+ * @retval SCI_SUCCESS This value is returned if the internal io was
+ * successfully constructed.
+ * @retval SCI_FAILURE This value is returned if the internal io was failed to
+ * be constructed.
+ */
+SCI_STATUS scif_sas_internal_io_request_construct_smp(
+ SCIF_SAS_CONTROLLER_T * fw_controller,
+ SCIF_SAS_REMOTE_DEVICE_T * fw_device,
+ void * internal_io_memory,
+ U16 io_tag,
+ SMP_REQUEST_T * smp_command
+)
+{
+ SCIF_SAS_INTERNAL_IO_REQUEST_T * fw_internal_io =
+ (SCIF_SAS_INTERNAL_IO_REQUEST_T*)internal_io_memory;
+
+ SCIF_SAS_IO_REQUEST_T * fw_io =
+ (SCIF_SAS_IO_REQUEST_T*)internal_io_memory;
+
+ SCI_STATUS status;
+
+ //call common smp request construct routine.
+ status = scif_sas_io_request_construct_smp(
+ fw_controller,
+ fw_device,
+ internal_io_memory,
+ (char *)internal_io_memory + sizeof(SCIF_SAS_INTERNAL_IO_REQUEST_T),
+ SCI_CONTROLLER_INVALID_IO_TAG,
+ smp_command,
+ NULL //there is no associated user io object.
+ );
+
+ //Codes below are all internal io related.
+ if (status == SCI_SUCCESS)
+ {
+ //set the is_internal flag
+ fw_io->parent.is_internal = TRUE;
+
+ if (fw_internal_io->internal_io_timer == NULL)
+ {
+ //create the timer for this internal request.
+ fw_internal_io->internal_io_timer =
+ scif_cb_timer_create(
+ (SCI_CONTROLLER_HANDLE_T *)fw_controller,
+ scif_sas_internal_io_request_timeout_handler,
+ (void*)fw_io
+ );
+ }
+ else
+ {
+ ASSERT (0);
+ }
+
+ //insert into high priority queue
+ if ( !sci_pool_full(fw_controller->hprq.pool) )
+ {
+ sci_pool_put(
+ fw_controller->hprq.pool, (POINTER_UINT) internal_io_memory
+ );
+ }
+ else
+ {
+ SCIF_LOG_ERROR((
+ sci_base_object_get_logger(fw_controller),
+ SCIF_LOG_OBJECT_CONTROLLER | SCIF_LOG_OBJECT_REMOTE_DEVICE,
+ "scif_sas_internal_io_request_construct_smp, high priority queue full!\n"
+ ));
+
+ scif_sas_internal_io_request_destruct(fw_controller, fw_internal_io);
+
+ //return failure status.
+ return SCI_FAILURE_INSUFFICIENT_RESOURCES;
+ }
+ }
+
+ return status;
+}
+
+
+/**
+ * @brief This method constructs an internal smp request.
+ * @param[in] fw_io
+ *
+ * @return SCI_STATUS
+ */
+SCI_STATUS scif_sas_internal_io_request_construct_stp(
+ SCIF_SAS_INTERNAL_IO_REQUEST_T * fw_io
+)
+{
+ //TBD
+ return SCI_SUCCESS;
+}
+
+
+/**
+ * @brief This method handles the timeout situation for an internal io.
+ *
+ * @param[in] fw_internal_io The timed out IO.
+ *
+ * @return none
+ */
+void scif_sas_internal_io_request_timeout_handler(
+ void * fw_internal_io
+)
+{
+ SCIF_SAS_REQUEST_T * fw_request = (SCIF_SAS_REQUEST_T *)fw_internal_io;
+
+ SCIF_LOG_TRACE((
+ sci_base_object_get_logger(fw_request),
+ SCIF_LOG_OBJECT_IO_REQUEST,
+ "scif_sas_internal_io_request_timeout_handler(0x%x) enter\n",
+ fw_internal_io
+ ));
+
+ fw_request->state_handlers->abort_handler(&fw_request->parent);
+}
+
+
+/**
+ * @brief This methods takes care of completion of an internal request about its
+ * "internal" related feature, including the memory recycling and timer.
+ *
+ * @param[in] fw_controller The framework controller object.
+ * @param[in] fw_internal_io The internal io to be completed.
+ * @param[in] completion_status the completeion status by core and framework so
+ * far.
+ *
+ * @return none
+ */
+void scif_sas_internal_io_request_complete(
+ SCIF_SAS_CONTROLLER_T * fw_controller,
+ SCIF_SAS_INTERNAL_IO_REQUEST_T * fw_internal_io,
+ SCI_STATUS completion_status
+)
+{
+ SCIF_LOG_TRACE((
+ sci_base_object_get_logger(fw_controller),
+ SCIF_LOG_OBJECT_IO_REQUEST,
+ "scif_sas_internal_io_request_complete(0x%x, 0x%x, 0x%x) enter\n",
+ fw_controller, fw_internal_io, completion_status
+ ));
+
+ scif_cb_timer_stop(fw_controller, fw_internal_io->internal_io_timer);
+ scif_sas_internal_io_request_destruct(fw_controller, fw_internal_io);
+}
+
+
+/**
+ * @brief This methods takes care of destruction of an internal request about its
+ * "internal" related feature, including the memory recycling and timer.
+ *
+ * @param[in] fw_controller The framework controller object.
+ * @param[in] fw_internal_io The internal io to be completed.
+ *
+ * @return none
+ */
+void scif_sas_internal_io_request_destruct(
+ SCIF_SAS_CONTROLLER_T * fw_controller,
+ SCIF_SAS_INTERNAL_IO_REQUEST_T * fw_internal_io
+)
+{
+ if (fw_internal_io->internal_io_timer != NULL)
+ {
+ scif_cb_timer_destroy(fw_controller, fw_internal_io->internal_io_timer);
+ fw_internal_io->internal_io_timer = NULL;
+ }
+ scif_sas_controller_free_internal_request(fw_controller, fw_internal_io);
+}
+
diff --git a/sys/dev/isci/scil/scif_sas_internal_io_request.h b/sys/dev/isci/scil/scif_sas_internal_io_request.h
new file mode 100644
index 0000000..411e46f
--- /dev/null
+++ b/sys/dev/isci/scil/scif_sas_internal_io_request.h
@@ -0,0 +1,157 @@
+/*-
+ * 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.
+ *
+ * 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.
+ *
+ * $FreeBSD$
+ */
+#ifndef _SCIF_SAS_INTERNAL_REQUEST_H_
+#define _SCIF_SAS_INTERNAL_REQUEST_H_
+
+/**
+ * @file
+ *
+ * @brief This file contains the protected interface structures, constants,
+ * and methods for the SCIF_SAS_INTERNAL_REQUEST object.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif // __cplusplus
+
+
+#include <dev/isci/scil/scif_io_request.h>
+#include <dev/isci/scil/sci_base_request.h>
+#include <dev/isci/scil/scif_sas_request.h>
+#include <dev/isci/scil/scif_sas_io_request.h>
+#include <dev/isci/scil/scif_sas_remote_device.h>
+#include <dev/isci/scil/intel_sas.h>
+#include <dev/isci/scil/sci_controller_constants.h>
+
+struct SCIF_SAS_CONTROLLER;
+
+/**
+ * This constant dictates the maximum number of internal framework
+ * IO request objects. These objects are used for internal SMP requests
+ * and for NCQ error handling.
+ */
+#define SCIF_SAS_MAX_INTERNAL_REQUEST_COUNT (SCI_MAX_DOMAINS*4)
+
+/**
+ * This constant dictates the minimum number of internal framework
+ * IO request objects when size-constrained.
+ */
+#define SCIF_SAS_MIN_INTERNAL_REQUEST_COUNT (SCI_MAX_DOMAINS)
+
+/*
+ * This constant indicates the timeout value of an internal IO request
+ * in mili-seconds.
+ */
+#define SCIF_SAS_INTERNAL_REQUEST_TIMEOUT 3000
+
+/**
+ * @struct SCIF_SAS_INTERNAL_IO_REQUEST
+ *
+ * @brief The SCIF_SAS_INTERNAL_IO_REQUEST object represents the internal SAS
+ * IO request behavior for the framework component.
+ */
+typedef struct SCIF_SAS_INTERNAL_IO_REQUEST
+{
+ /**
+ * The SCIF_SAS_IO_REQUEST is the parent object for the
+ * SCIF_SAS_INTERNAL_IO_REQUEST object.
+ */
+ SCIF_SAS_IO_REQUEST_T parent;
+
+ /**
+ * This field will be utilized only by internal IO to handle timeout
+ * situation.
+ */
+ void * internal_io_timer;
+
+}SCIF_SAS_INTERNAL_IO_REQUEST_T;
+
+
+U32 scif_sas_internal_request_get_object_size(
+ void
+);
+
+SCI_STATUS scif_sas_internal_io_request_construct_smp(
+ struct SCIF_SAS_CONTROLLER * fw_controller,
+ SCIF_SAS_REMOTE_DEVICE_T * fw_remote_device,
+ void * internal_io_memory,
+ U16 io_tag,
+ SMP_REQUEST_T * smp_command
+);
+
+SCI_STATUS scif_sas_internal_io_request_construct_stp(
+ SCIF_SAS_INTERNAL_IO_REQUEST_T * fw_io
+);
+
+void scif_sas_internal_io_request_timeout_handler(
+ void * fw_io
+);
+
+void scif_sas_internal_io_request_complete(
+ struct SCIF_SAS_CONTROLLER * fw_controller,
+ SCIF_SAS_INTERNAL_IO_REQUEST_T * fw_io,
+ SCI_STATUS completion_status
+);
+
+void scif_sas_internal_io_request_destruct(
+ struct SCIF_SAS_CONTROLLER * fw_controller,
+ SCIF_SAS_INTERNAL_IO_REQUEST_T * fw_internal_io
+);
+
+#ifdef __cplusplus
+}
+#endif // __cplusplus
+
+#endif // _SCIF_SAS_IO_REQUEST_H_
+
diff --git a/sys/dev/isci/scil/scif_sas_io_request.c b/sys/dev/isci/scil/scif_sas_io_request.c
new file mode 100644
index 0000000..82a907c
--- /dev/null
+++ b/sys/dev/isci/scil/scif_sas_io_request.c
@@ -0,0 +1,820 @@
+/*-
+ * 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.
+ *
+ * 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 <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/**
+ * @file
+ *
+ * @brief This file contains the implementation of the SCIF_SAS_IO_REQUEST
+ * object.
+ */
+
+
+#include <dev/isci/scil/scic_io_request.h>
+#include <dev/isci/scil/scic_remote_device.h>
+#include <dev/isci/scil/scic_user_callback.h>
+#include <dev/isci/scil/scic_controller.h>
+#include <dev/isci/scil/scif_user_callback.h>
+
+#include <dev/isci/scil/scif_sas_controller.h>
+#include <dev/isci/scil/scif_sas_domain.h>
+#include <dev/isci/scil/scif_sas_remote_device.h>
+#include <dev/isci/scil/scif_sas_io_request.h>
+#include <dev/isci/scil/scif_sas_task_request.h>
+#include <dev/isci/scil/scif_sas_stp_io_request.h>
+#include <dev/isci/scil/scif_sas_logger.h>
+#include <dev/isci/scil/scif_sas_smp_io_request.h>
+#include <dev/isci/scil/sci_fast_list.h>
+#include <dev/isci/scil/sati.h>
+#include <dev/isci/scil/intel_sat.h>
+#include <dev/isci/scil/sati_translator_sequence.h>
+
+/**
+ * @brief This method represents common functionality for the
+ * scif_io_request_construct() and scif_sas_io_request_continue()
+ * methods.
+ *
+ * @return This method returns an indication as to whether the
+ * construction succeeded.
+ */
+static
+SCI_STATUS scif_sas_io_request_construct(
+ SCIF_SAS_REMOTE_DEVICE_T * fw_device,
+ SCIF_SAS_IO_REQUEST_T * fw_io,
+ U16 io_tag,
+ void * user_io_request_object,
+ SCI_IO_REQUEST_HANDLE_T * scif_io_request,
+ BOOL is_initial_construction
+)
+{
+ SCI_STATUS status;
+ SMP_DISCOVER_RESPONSE_PROTOCOLS_T dev_protocols;
+
+ scic_remote_device_get_protocols(fw_device->core_object, &dev_protocols);
+
+ //Currently, all the io requests sent to smp target are internal.
+ //so we fail all the external io toward to it.
+ //Todo: is there a better way to handle external io to smp target?
+ if (dev_protocols.u.bits.attached_smp_target)
+ return SCI_FAILURE_INVALID_REMOTE_DEVICE;
+
+ SCIF_LOG_TRACE((
+ sci_base_object_get_logger(fw_device),
+ SCIF_LOG_OBJECT_IO_REQUEST,
+ "scif_sas_io_request_construct(0x%x,0x%x,0x%x,0x%x,0x%x,0x%x) enter\n",
+ fw_device, fw_io, io_tag, user_io_request_object, scif_io_request,
+ is_initial_construction
+ ));
+
+ // Initialize the users handle to the framework IO request.
+ *scif_io_request = fw_io;
+
+ // Construct the parent object first in order to ensure logging can
+ // function.
+ scif_sas_request_construct(
+ &fw_io->parent,
+ fw_device,
+ sci_base_object_get_logger(fw_device),
+ scif_sas_io_request_state_table
+ );
+
+ status = scic_io_request_construct(
+ fw_device->domain->controller->core_object,
+ fw_device->core_object,
+ io_tag,
+ fw_io,
+ ((U8 *)fw_io) + sizeof(SCIF_SAS_IO_REQUEST_T),
+ &fw_io->parent.core_object
+ );
+
+ if (status == SCI_SUCCESS)
+ {
+ // These associations must be set early for the core io request
+ // object construction to complete correctly as there will be
+ // callbacks into the user driver framework during core construction
+ sci_object_set_association(fw_io, user_io_request_object);
+ sci_object_set_association(fw_io->parent.core_object, fw_io);
+
+ // Perform protocol specific core IO request construction.
+ if (dev_protocols.u.bits.attached_ssp_target)
+ status = scic_io_request_construct_basic_ssp(fw_io->parent.core_object);
+ else if (dev_protocols.u.bits.attached_stp_target)
+ {
+ if (is_initial_construction == TRUE)
+ sati_sequence_construct(&fw_io->parent.stp.sequence);
+
+#if !defined(DISABLE_ATAPI)
+ if (!scic_remote_device_is_atapi(fw_device->core_object))
+ {
+#endif
+ status = scif_sas_stp_io_request_construct(fw_io);
+
+#if !defined(DISABLE_ATAPI)
+ }
+ else
+ status = scif_sas_stp_packet_io_request_construct(fw_io);
+#endif
+ }
+
+ sci_base_state_machine_logger_initialize(
+ &fw_io->parent.parent.state_machine_logger,
+ &fw_io->parent.parent.state_machine,
+ &fw_io->parent.parent.parent,
+ scif_cb_logger_log_states,
+ "SCIF_IO_REQUEST_T", "base_state_machine",
+ SCIF_LOG_OBJECT_IO_REQUEST
+ );
+ }
+
+ return status;
+}
+
+//******************************************************************************
+//* P U B L I C M E T H O D S
+//******************************************************************************
+
+U32 scif_io_request_get_object_size(
+ void
+)
+{
+ return (sizeof(SCIF_SAS_IO_REQUEST_T) + scic_io_request_get_object_size());
+}
+
+// ----------------------------------------------------------------------------
+U32 scif_io_request_get_number_of_bytes_transferred(
+ SCI_IO_REQUEST_HANDLE_T scif_io_request
+)
+{
+ SCIF_SAS_IO_REQUEST_T * fw_request = (SCIF_SAS_IO_REQUEST_T*) scif_io_request;
+
+ if(scic_io_request_get_protocol(scif_io_request_get_scic_handle(scif_io_request))
+ == SCIC_STP_PROTOCOL)
+ {
+ U16 sati_data_bytes_set =
+ sati_get_number_data_bytes_set(&(fw_request->parent.stp.sequence));
+
+ if (sati_data_bytes_set != 0)
+ return sati_data_bytes_set;
+ else
+ {
+#if !defined(DISABLE_ATAPI)
+ U8 sat_protocol = fw_request->parent.stp.sequence.protocol;
+ if ( sat_protocol & SAT_PROTOCOL_PACKET)
+ return
+ scif_sas_stp_packet_io_request_get_number_of_bytes_transferred(fw_request);
+ else
+#endif
+ return scic_io_request_get_number_of_bytes_transferred(
+ scif_io_request_get_scic_handle(scif_io_request));
+ }
+ }
+ else
+ {
+ return scic_io_request_get_number_of_bytes_transferred(
+ scif_io_request_get_scic_handle(scif_io_request));
+ }
+}
+
+// ---------------------------------------------------------------------------
+
+SCI_STATUS scif_io_request_construct(
+ SCI_CONTROLLER_HANDLE_T scif_controller,
+ SCI_REMOTE_DEVICE_HANDLE_T scif_remote_device,
+ U16 io_tag,
+ void * user_io_request_object,
+ void * io_request_memory,
+ SCI_IO_REQUEST_HANDLE_T * scif_io_request
+)
+{
+ SCIF_SAS_IO_REQUEST_T * fw_io = (SCIF_SAS_IO_REQUEST_T*)
+ io_request_memory;
+ SCIF_SAS_REMOTE_DEVICE_T * fw_device = (SCIF_SAS_REMOTE_DEVICE_T*)
+ scif_remote_device;
+
+ return scif_sas_io_request_construct(
+ fw_device,
+ fw_io,
+ io_tag,
+ user_io_request_object,
+ scif_io_request,
+ TRUE
+ );
+}
+
+// ---------------------------------------------------------------------------
+
+SCI_STATUS scif_request_construct(
+ SCI_CONTROLLER_HANDLE_T scif_controller,
+ SCI_REMOTE_DEVICE_HANDLE_T scif_remote_device,
+ U16 io_tag,
+ void * user_io_request_object,
+ void * io_request_memory,
+ SCI_IO_REQUEST_HANDLE_T * scif_io_request
+)
+{
+ SCIF_SAS_IO_REQUEST_T * fw_io = (SCIF_SAS_IO_REQUEST_T*)
+ io_request_memory;
+ SCIF_SAS_REMOTE_DEVICE_T * fw_device = (SCIF_SAS_REMOTE_DEVICE_T*)
+ scif_remote_device;
+ SCI_STATUS status;
+
+ SCIF_LOG_TRACE((
+ sci_base_object_get_logger(fw_device),
+ SCIF_LOG_OBJECT_IO_REQUEST,
+ "scif_io_request_construct(0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x) enter\n",
+ scif_controller, scif_remote_device, io_tag, user_io_request_object,
+ io_request_memory, scif_io_request
+ ));
+
+ // Step 1: Create the scif io request.
+ // Initialize the users handle to the framework IO request.
+ *scif_io_request = fw_io;
+
+ // Construct the parent object first in order to ensure logging can
+ // function.
+ scif_sas_request_construct(
+ &fw_io->parent,
+ fw_device,
+ sci_base_object_get_logger(fw_device),
+ scif_sas_io_request_state_table
+ );
+
+ status = scic_io_request_construct(
+ (void *) ((SCIF_SAS_CONTROLLER_T *)scif_controller)->core_object,
+ (void *) fw_device->core_object,
+ io_tag,
+ fw_io,
+ (U8 *)io_request_memory + sizeof(SCIF_SAS_IO_REQUEST_T),
+ &fw_io->parent.core_object
+ );
+
+ if (status == SCI_SUCCESS)
+ {
+ // These associations must be set early for the core io request
+ // object construction to complete correctly as there will be
+ // callbacks into the user driver framework during core construction
+ sci_object_set_association(fw_io, user_io_request_object);
+ sci_object_set_association(fw_io->parent.core_object, fw_io);
+
+ sci_base_state_machine_logger_initialize(
+ &fw_io->parent.parent.state_machine_logger,
+ &fw_io->parent.parent.state_machine,
+ &fw_io->parent.parent.parent,
+ scif_cb_logger_log_states,
+ "SCIF_IO_REQUEST_T", "base_state_machine",
+ SCIF_LOG_OBJECT_IO_REQUEST
+ );
+ }
+
+ return status;
+}
+
+// ----------------------------------------------------------------------------
+
+SCI_STATUS scif_io_request_construct_with_core (
+ SCI_CONTROLLER_HANDLE_T scif_controller,
+ SCI_REMOTE_DEVICE_HANDLE_T scif_remote_device,
+ void * scic_io_request,
+ void * user_io_request_object,
+ void * io_request_memory,
+ SCI_IO_REQUEST_HANDLE_T * scif_io_request
+)
+{
+ SCIF_SAS_IO_REQUEST_T * fw_io = (SCIF_SAS_IO_REQUEST_T*)
+ io_request_memory;
+ SCIF_SAS_REMOTE_DEVICE_T * fw_device = (SCIF_SAS_REMOTE_DEVICE_T*)
+ scif_remote_device;
+ SCI_STATUS status = SCI_SUCCESS;
+
+ SCIF_LOG_TRACE((
+ sci_base_object_get_logger(fw_device),
+ SCIF_LOG_OBJECT_IO_REQUEST,
+ "scif_io_request_construct_pass_through(0x%x, 0x%x, 0x%x, 0x%x) enter\n",
+ scif_remote_device, user_io_request_object,
+ io_request_memory, scif_io_request
+ ));
+
+ // Initialize the users handle to the framework IO request.
+ *scif_io_request = fw_io;
+
+ // Construct the parent object first in order to ensure logging can
+ // function.
+ scif_sas_request_construct(
+ &fw_io->parent,
+ fw_device,
+ sci_base_object_get_logger(fw_device),
+ scif_sas_io_request_state_table
+ );
+
+ fw_io->parent.core_object = scic_io_request;
+
+ //set association
+ sci_object_set_association(fw_io, user_io_request_object);
+ sci_object_set_association(fw_io->parent.core_object, fw_io);
+
+
+ sci_base_state_machine_logger_initialize(
+ &fw_io->parent.parent.state_machine_logger,
+ &fw_io->parent.parent.state_machine,
+ &fw_io->parent.parent.parent,
+ scif_cb_logger_log_states,
+ "SCIF_IO_REQUEST_T", "base_state_machine",
+ SCIF_LOG_OBJECT_IO_REQUEST
+ );
+
+ return status;
+}
+
+// ---------------------------------------------------------------------------
+
+void * scif_io_request_get_response_iu_address(
+ SCI_IO_REQUEST_HANDLE_T scif_io_request
+)
+{
+ SCIF_SAS_IO_REQUEST_T * fw_io = (SCIF_SAS_IO_REQUEST_T*)scif_io_request;
+
+ return (scic_io_request_get_response_iu_address(fw_io->parent.core_object ));
+}
+
+// ---------------------------------------------------------------------------
+
+SCI_IO_REQUEST_HANDLE_T scif_io_request_get_scic_handle(
+ SCI_IO_REQUEST_HANDLE_T scif_io_request
+)
+{
+ SCIF_SAS_IO_REQUEST_T * fw_io = (SCIF_SAS_IO_REQUEST_T*) scif_io_request;
+ return fw_io->parent.core_object;
+}
+
+// ---------------------------------------------------------------------------
+
+void scic_cb_io_request_complete(
+ SCI_CONTROLLER_HANDLE_T controller,
+ SCI_REMOTE_DEVICE_HANDLE_T remote_device,
+ SCI_IO_REQUEST_HANDLE_T io_request,
+ SCI_IO_STATUS completion_status
+)
+{
+ SCI_STATUS status;
+ SCIF_SAS_CONTROLLER_T * fw_controller = (SCIF_SAS_CONTROLLER_T*)
+ sci_object_get_association(controller);
+ SCIF_SAS_REMOTE_DEVICE_T * fw_device = (SCIF_SAS_REMOTE_DEVICE_T*)
+ sci_object_get_association(remote_device);
+ SCIF_SAS_REQUEST_T * fw_request = (SCIF_SAS_REQUEST_T*)
+ sci_object_get_association(io_request);
+
+ SCIF_LOG_TRACE((
+ sci_base_object_get_logger(controller),
+ SCIF_LOG_OBJECT_IO_REQUEST,
+ "scic_cb_io_request_complete(0x%x, 0x%x, 0x%x, 0x%x) enter\n",
+ controller, remote_device, io_request, completion_status
+ ));
+
+ // Invoke the common completion handler routine.
+ // A non-successful return indicates we are not in a correct state to
+ // receive a completion notification for this request.
+ status = fw_request->state_handlers->complete_handler(&fw_request->parent);
+
+ // If the status indicates the completion handler was successful, then
+ // allow protocol specific completion processing to occur.
+ if (status == SCI_SUCCESS)
+ {
+ if (fw_request->protocol_complete_handler != NULL)
+ {
+ status = fw_request->protocol_complete_handler(
+ fw_controller, fw_device, fw_request, (SCI_STATUS *)&completion_status
+ );
+ }
+
+ // If this isn't an internal framework IO request, then simply pass the
+ // notification up to the SCIF user.
+ if ( status == SCI_SUCCESS )
+ {
+ if (fw_request->is_high_priority == FALSE)
+ {
+ if (fw_request->is_waiting_for_abort_task_set == FALSE)
+ {
+ scif_cb_io_request_complete(
+ fw_controller, fw_device, fw_request, completion_status);
+ }
+ else
+ {
+ // do nothing - will complete the I/O when the abort task
+ // set completes
+ }
+ }
+ else
+ scif_sas_controller_complete_high_priority_io(
+ fw_controller, fw_device, fw_request);
+ }
+ else if ( status == SCI_WARNING_SEQUENCE_INCOMPLETE )
+ {
+ scif_sas_io_request_continue(fw_controller, fw_device, fw_request);
+ }
+ }
+}
+
+// ---------------------------------------------------------------------------
+
+U32 scic_cb_io_request_get_transfer_length(
+ void * scic_user_io_request
+)
+{
+ SCIF_SAS_IO_REQUEST_T * fw_io = (SCIF_SAS_IO_REQUEST_T*)
+ scic_user_io_request;
+
+ return (scif_cb_io_request_get_transfer_length(
+ fw_io->parent.parent.parent.associated_object
+ ));
+}
+
+// ---------------------------------------------------------------------------
+
+SCI_IO_REQUEST_DATA_DIRECTION scic_cb_io_request_get_data_direction(
+ void * scic_user_io_request
+)
+{
+ SCIF_SAS_IO_REQUEST_T * fw_io = (SCIF_SAS_IO_REQUEST_T*)
+ scic_user_io_request;
+
+ return (scif_cb_io_request_get_data_direction(
+ fw_io->parent.parent.parent.associated_object
+ ));
+}
+
+// ---------------------------------------------------------------------------
+#ifndef SCI_SGL_OPTIMIZATION_ENABLED
+void scic_cb_io_request_get_next_sge(
+ void * scic_user_io_request,
+ void * current_sge_address,
+ void **next_sge
+)
+{
+ SCIF_SAS_IO_REQUEST_T * fw_io = (SCIF_SAS_IO_REQUEST_T*)
+ scic_user_io_request;
+
+ scif_cb_io_request_get_next_sge(
+ fw_io->parent.parent.parent.associated_object,
+ current_sge_address,
+ next_sge
+ );
+}
+#endif
+
+// ---------------------------------------------------------------------------
+
+SCI_PHYSICAL_ADDRESS scic_cb_sge_get_address_field(
+ void * scic_user_io_request,
+ void * sge_address
+)
+{
+ SCIF_SAS_IO_REQUEST_T * fw_io = (SCIF_SAS_IO_REQUEST_T*)
+ scic_user_io_request;
+ return scif_cb_sge_get_address_field(
+ fw_io->parent.parent.parent.associated_object, sge_address
+ );
+}
+
+// ---------------------------------------------------------------------------
+
+U32 scic_cb_sge_get_length_field(
+ void * scic_user_io_request,
+ void * sge_address
+)
+{
+ SCIF_SAS_IO_REQUEST_T * fw_io = (SCIF_SAS_IO_REQUEST_T*)
+ scic_user_io_request;
+
+ return scif_cb_sge_get_length_field(
+ fw_io->parent.parent.parent.associated_object,
+ sge_address
+ );
+}
+
+// ---------------------------------------------------------------------------
+
+void * scic_cb_ssp_io_request_get_cdb_address(
+ void * scic_user_io_request
+)
+{
+ SCIF_SAS_IO_REQUEST_T * fw_io = (SCIF_SAS_IO_REQUEST_T*)
+ scic_user_io_request;
+
+ return scif_cb_io_request_get_cdb_address(
+ fw_io->parent.parent.parent.associated_object
+ );
+}
+
+// ---------------------------------------------------------------------------
+
+U32 scic_cb_ssp_io_request_get_cdb_length(
+ void * scic_user_io_request
+)
+{
+ SCIF_SAS_IO_REQUEST_T * fw_io = (SCIF_SAS_IO_REQUEST_T*)
+ scic_user_io_request;
+
+ return scif_cb_io_request_get_cdb_length(
+ fw_io->parent.parent.parent.associated_object
+ );
+}
+
+// ---------------------------------------------------------------------------
+
+#if !defined(DISABLE_ATAPI)
+void * scic_cb_stp_packet_io_request_get_cdb_address(
+ void * scic_user_io_request
+)
+{
+ SCIF_SAS_REQUEST_T * fw_request = (SCIF_SAS_REQUEST_T*)scic_user_io_request;
+
+ SATI_TRANSLATOR_SEQUENCE_T * sati_sequence = &fw_request->stp.sequence;
+
+ if (sati_sequence->state != SATI_SEQUENCE_STATE_INCOMPLETE)
+ return scif_cb_io_request_get_cdb_address(
+ fw_request->parent.parent.associated_object
+ );
+ else
+ return
+ &(sati_sequence->command_specific_data.sati_atapi_data.request_sense_cdb);
+}
+#endif
+
+// ---------------------------------------------------------------------------
+
+#if !defined(DISABLE_ATAPI)
+U32 scic_cb_stp_packet_io_request_get_cdb_length(
+ void * scic_user_io_request
+)
+{
+ SCIF_SAS_REQUEST_T * fw_request = (SCIF_SAS_REQUEST_T*)
+ scic_user_io_request;
+
+ SATI_TRANSLATOR_SEQUENCE_T * sati_sequence = &fw_request->stp.sequence;
+
+ if (sati_sequence->state != SATI_SEQUENCE_STATE_INCOMPLETE)
+ return scif_cb_io_request_get_cdb_length(
+ fw_request->parent.parent.associated_object
+ );
+ else
+ return SATI_ATAPI_REQUEST_SENSE_CDB_LENGTH;
+}
+#endif
+
+// ---------------------------------------------------------------------------
+
+U32 scic_cb_ssp_io_request_get_lun(
+ void * scic_user_io_request
+)
+{
+ SCIF_SAS_IO_REQUEST_T * fw_io = (SCIF_SAS_IO_REQUEST_T*)
+ scic_user_io_request;
+
+ return scif_cb_io_request_get_lun(
+ fw_io->parent.parent.parent.associated_object
+ );
+}
+
+// ---------------------------------------------------------------------------
+
+U32 scic_cb_ssp_io_request_get_task_attribute(
+ void * scic_user_io_request
+)
+{
+ SCIF_SAS_IO_REQUEST_T * fw_io = (SCIF_SAS_IO_REQUEST_T*)
+ scic_user_io_request;
+
+ return scif_cb_io_request_get_task_attribute(
+ fw_io->parent.parent.parent.associated_object
+ );
+}
+
+// ---------------------------------------------------------------------------
+
+U32 scic_cb_ssp_io_request_get_command_priority(
+ void * scic_user_io_request
+)
+{
+ SCIF_SAS_IO_REQUEST_T * fw_io = (SCIF_SAS_IO_REQUEST_T*)
+ scic_user_io_request;
+
+ return scif_cb_io_request_get_command_priority(
+ fw_io->parent.parent.parent.associated_object
+ );
+}
+
+// ---------------------------------------------------------------------------
+
+BOOL scic_cb_request_is_initial_construction(
+ void * scic_user_io_request
+)
+{
+ SCIF_SAS_REQUEST_T * fw_request = (SCIF_SAS_REQUEST_T*)
+ scic_user_io_request;
+ SCIF_SAS_REMOTE_DEVICE_T* fw_device = fw_request->device;
+
+ SMP_DISCOVER_RESPONSE_PROTOCOLS_T dev_protocols;
+ scic_remote_device_get_protocols(fw_device->core_object, &dev_protocols);
+
+ if (dev_protocols.u.bits.attached_stp_target
+ && fw_request->stp.sequence.state == SATI_SEQUENCE_STATE_INCOMPLETE)
+ return FALSE;
+
+ return TRUE;
+}
+
+
+//******************************************************************************
+//* P R O T E C T E D M E T H O D S
+//******************************************************************************
+/**
+ * @brief This method constructs an scif sas smp request.
+ *
+ * @param[in] fw_controller The framework controller
+ * @param[in] fw_device The smp device that the smp request targets to.
+ * @param[in] fw_io_memory The memory space for the smp request.
+ * @param[in] core_io_memory The memory space for the core request.
+ * @param[in] io_tag The io tag for the internl io to be constructed.
+ * @param[in] smp_command A pointer to the smp request data structure according
+ * to SAS protocol.
+ *
+ * @return Indicate if the internal io was successfully constructed.
+ * @retval SCI_SUCCESS This value is returned if the internal io was
+ * successfully constructed.
+ * @retval SCI_FAILURE This value is returned if the internal io was failed to
+ * be constructed.
+ */
+SCI_STATUS scif_sas_io_request_construct_smp(
+ SCIF_SAS_CONTROLLER_T * fw_controller,
+ SCIF_SAS_REMOTE_DEVICE_T * fw_device,
+ void * fw_io_memory,
+ void * core_io_memory,
+ U16 io_tag,
+ SMP_REQUEST_T * smp_command,
+ void * user_request_object
+)
+{
+ SCIF_SAS_IO_REQUEST_T * fw_io =
+ (SCIF_SAS_IO_REQUEST_T*)fw_io_memory;
+
+ SCI_STATUS status = SCI_SUCCESS;
+
+ SCIF_LOG_TRACE((
+ sci_base_object_get_logger(fw_device),
+ SCIF_LOG_OBJECT_IO_REQUEST,
+ "scif_sas_io_request_construct_smp(0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x) enter\n",
+ fw_controller,
+ fw_device,
+ fw_io_memory,
+ core_io_memory,
+ io_tag,
+ smp_command,
+ user_request_object
+ ));
+
+ // Construct the parent object first in order to ensure logging can
+ // function.
+ scif_sas_request_construct(
+ &fw_io->parent,
+ fw_device,
+ sci_base_object_get_logger(fw_controller),
+ scif_sas_io_request_state_table
+ );
+
+ status = scic_io_request_construct(
+ fw_device->domain->controller->core_object,
+ fw_device->core_object,
+ io_tag,
+ (void*)fw_io,
+ (U8 *)core_io_memory,
+ &fw_io->parent.core_object
+ );
+
+ if (status == SCI_SUCCESS)
+ {
+ //set object association.
+ sci_object_set_association(fw_io, user_request_object);
+ sci_object_set_association(fw_io->parent.core_object, fw_io);
+
+ scif_sas_smp_request_construct(&fw_io->parent, smp_command);
+
+ fw_io->parent.is_high_priority = TRUE;
+
+ sci_base_state_machine_logger_initialize(
+ &fw_io->parent.parent.state_machine_logger,
+ &fw_io->parent.parent.state_machine,
+ &fw_io->parent.parent.parent,
+ scif_cb_logger_log_states,
+ "SCIF_IO_REQUEST_T", "base_state_machine",
+ SCIF_LOG_OBJECT_IO_REQUEST
+ );
+ }
+
+ return status;
+}
+
+
+/**
+ * @brief This method continues a scif sas request.
+ *
+ * @param[in] fw_controller The framework controller
+ * @param[in] fw_device The device that the IO request targets to.
+ * @param[in] fw_request The IO request to be continued.
+ *
+ * @return Indicate if the internal io was successfully constructed.
+ * @retval SCI_SUCCESS This value is returned if the internal io was
+ * successfully continued.
+ * @retval SCI_FAILURE This value is returned if the io was failed to
+ * be continued.
+ */
+SCI_STATUS scif_sas_io_request_continue(
+ SCIF_SAS_CONTROLLER_T * fw_controller,
+ SCIF_SAS_REMOTE_DEVICE_T * fw_device,
+ SCIF_SAS_REQUEST_T * fw_request
+)
+{
+ SCI_IO_REQUEST_HANDLE_T dummy_handle;
+
+ SCIF_LOG_TRACE((
+ sci_base_object_get_logger(fw_request),
+ SCIF_LOG_OBJECT_IO_REQUEST,
+ "scif_sas_io_request_continue(0x%x, 0x%x, 0x%x) enter\n",
+ fw_controller,
+ fw_device,
+ fw_request
+ ));
+
+ //complete this io request in framework and core.
+ scif_controller_complete_io(fw_controller, fw_device, fw_request);
+
+ //construct next command in the sequence using the same memory. We pass
+ //a dummy pointer to let the framework user keep the pointer to this IO
+ //request untouched.
+ scif_sas_io_request_construct(
+ fw_device,
+ (SCIF_SAS_IO_REQUEST_T*)fw_request,
+ SCI_CONTROLLER_INVALID_IO_TAG,
+ (void *)sci_object_get_association(fw_request),
+ &dummy_handle,
+ FALSE
+ );
+
+ //start the new constructed IO.
+ return scif_controller_start_io(
+ (SCI_CONTROLLER_HANDLE_T) fw_controller,
+ (SCI_REMOTE_DEVICE_HANDLE_T) fw_device,
+ (SCI_IO_REQUEST_HANDLE_T) fw_request,
+ SCI_CONTROLLER_INVALID_IO_TAG
+ );
+}
diff --git a/sys/dev/isci/scil/scif_sas_io_request.h b/sys/dev/isci/scil/scif_sas_io_request.h
new file mode 100644
index 0000000..f09f9fe
--- /dev/null
+++ b/sys/dev/isci/scil/scif_sas_io_request.h
@@ -0,0 +1,152 @@
+/*-
+ * 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.
+ *
+ * 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.
+ *
+ * $FreeBSD$
+ */
+#ifndef _SCIF_SAS_IO_REQUEST_H_
+#define _SCIF_SAS_IO_REQUEST_H_
+
+/**
+ * @file
+ *
+ * @brief This file contains the protected interface structures, constants,
+ * and methods for the SCIF_SAS_IO_REQUEST object.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif // __cplusplus
+
+#include <dev/isci/scil/scif_io_request.h>
+#include <dev/isci/scil/sci_base_request.h>
+#include <dev/isci/scil/scif_sas_request.h>
+#include <dev/isci/scil/scif_sas_stp_io_request.h>
+#include <dev/isci/scil/intel_sas.h>
+
+
+struct SCIF_SAS_CONTROLLER;
+struct SCIF_SAS_REMOTE_DEVICE;
+
+//Note 0xFF is the maximum possible value to IO_RETRY_LIMIT since the io_retry_count in
+//SCIF_SAS_IO_REQUEST is in type of U8.
+#define SCIF_SAS_IO_RETRY_LIMIT 0xFF
+
+/**
+ * @struct SCIF_SAS_IO_REQUEST
+ *
+ * @brief The SCI SAS Framework IO request object abstracts the SAS IO
+ * level behavior for the framework component. Additionally,
+ * it provides a higher level of abstraction for the core IO request
+ * object.
+ */
+typedef struct SCIF_SAS_IO_REQUEST
+{
+ /**
+ * The SCI_BASE_REQUEST is the parent object for the
+ * SCIF_SAS_IO_REQUEST object.
+ */
+ SCIF_SAS_REQUEST_T parent;
+
+ /**
+ * This field specifies the number of bytes to be utilized for this
+ * IO request. This field is utilized during internal IO requests.
+ */
+ U32 transfer_length;
+
+ /**
+ * This field keeps track of how many times an io got retried.
+ */
+ U8 retry_count;
+
+} SCIF_SAS_IO_REQUEST_T;
+
+extern SCI_BASE_STATE_T scif_sas_io_request_state_table[];
+extern SCI_BASE_REQUEST_STATE_HANDLER_T
+ scif_sas_io_request_state_handler_table[];
+
+SCI_STATUS scif_sas_io_request_constructed_start_handler(
+ SCI_BASE_REQUEST_T * io_request
+);
+
+SCI_STATUS scif_sas_io_request_constructed_abort_handler(
+ SCI_BASE_REQUEST_T * io_request
+);
+
+SCI_STATUS scif_sas_io_request_default_complete_handler(
+ SCI_BASE_REQUEST_T * io_request
+);
+
+SCI_STATUS scif_sas_io_request_default_destruct_handler(
+ SCI_BASE_REQUEST_T * io_request
+);
+
+SCI_STATUS scif_sas_io_request_construct_smp(
+ struct SCIF_SAS_CONTROLLER * fw_controller,
+ struct SCIF_SAS_REMOTE_DEVICE * fw_device,
+ void * fw_io_memory,
+ void * core_io_memory,
+ U16 io_tag,
+ SMP_REQUEST_T * smp_command,
+ void * user_request_object
+);
+
+SCI_STATUS scif_sas_io_request_continue(
+ struct SCIF_SAS_CONTROLLER * fw_controller,
+ struct SCIF_SAS_REMOTE_DEVICE * fw_device,
+ SCIF_SAS_REQUEST_T * fw_request
+);
+
+#ifdef __cplusplus
+}
+#endif // __cplusplus
+
+#endif // _SCIF_SAS_IO_REQUEST_H_
+
diff --git a/sys/dev/isci/scil/scif_sas_io_request_state_handlers.c b/sys/dev/isci/scil/scif_sas_io_request_state_handlers.c
new file mode 100644
index 0000000..303ea85
--- /dev/null
+++ b/sys/dev/isci/scil/scif_sas_io_request_state_handlers.c
@@ -0,0 +1,417 @@
+/*-
+ * 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.
+ *
+ * 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 <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/**
+ * @file
+ *
+ * @brief This file contains all of the method implementations pertaining
+ * to the framework io request state handler methods.
+ */
+
+#include <dev/isci/scil/scic_controller.h>
+#include <dev/isci/scil/scif_sas_logger.h>
+#include <dev/isci/scil/scif_sas_io_request.h>
+#include <dev/isci/scil/scif_sas_remote_device.h>
+#include <dev/isci/scil/scif_sas_domain.h>
+#include <dev/isci/scil/scif_sas_controller.h>
+
+//******************************************************************************
+//* C O N S T R U C T E D H A N D L E R S
+//******************************************************************************
+
+/**
+ * @brief This method provides CONSTRUCTED state specific handling for
+ * when the user attempts to start the supplied IO request.
+ *
+ * @param[in] io_request This parameter specifies the IO request object
+ * to be started.
+ *
+ * @return This method returns a value indicating if the IO request was
+ * successfully started or not.
+ * @retval SCI_SUCCESS This return value indicates successful starting
+ * of the IO request.
+ */
+SCI_STATUS scif_sas_io_request_constructed_start_handler(
+ SCI_BASE_REQUEST_T * io_request
+)
+{
+ return SCI_SUCCESS;
+}
+
+/**
+ * @brief This method provides CONSTRUCTED state specific handling for
+ * when the user attempts to abort the supplied IO request.
+ *
+ * @param[in] io_request This parameter specifies the IO request object
+ * to be aborted.
+ *
+ * @return This method returns a value indicating if the IO request was
+ * successfully aborted or not.
+ * @retval SCI_SUCCESS This return value indicates successful aborting
+ * of the IO request.
+ */
+SCI_STATUS scif_sas_io_request_constructed_abort_handler(
+ SCI_BASE_REQUEST_T * io_request
+)
+{
+ sci_base_state_machine_change_state(
+ &io_request->state_machine, SCI_BASE_REQUEST_STATE_COMPLETED
+ );
+
+ return SCI_SUCCESS;
+}
+
+//******************************************************************************
+//* S T A R T E D H A N D L E R S
+//******************************************************************************
+
+/**
+ * @brief This method provides STARTED state specific handling for
+ * when the user attempts to abort the supplied IO request.
+ *
+ * @param[in] io_request This parameter specifies the IO request object
+ * to be aborted.
+ *
+ * @return This method returns a value indicating if the aborting the
+ * IO request was successfully started.
+ * @retval SCI_SUCCESS This return value indicates that the abort process
+ * began successfully.
+ */
+static
+SCI_STATUS scif_sas_io_request_started_abort_handler(
+ SCI_BASE_REQUEST_T * io_request
+)
+{
+ SCIF_SAS_REQUEST_T * fw_request = (SCIF_SAS_REQUEST_T *) io_request;
+
+ sci_base_state_machine_change_state(
+ &io_request->state_machine, SCI_BASE_REQUEST_STATE_ABORTING
+ );
+
+ return fw_request->status;
+}
+
+/**
+ * @brief This method provides STARTED state specific handling for
+ * when the user attempts to complete the supplied IO request.
+ *
+ * @param[in] io_request This parameter specifies the IO request object
+ * to be completed.
+ *
+ * @return This method returns a value indicating if the completion of the
+ * IO request was successful.
+ * @retval SCI_SUCCESS This return value indicates that the completion process
+ * was successful.
+ */
+static
+SCI_STATUS scif_sas_io_request_started_complete_handler(
+ SCI_BASE_REQUEST_T * io_request
+)
+{
+ sci_base_state_machine_change_state(
+ &io_request->state_machine, SCI_BASE_REQUEST_STATE_COMPLETED
+ );
+
+ return SCI_SUCCESS;
+}
+
+//******************************************************************************
+//* C O M P L E T E D H A N D L E R S
+//******************************************************************************
+
+/**
+ * @brief This method provides COMPLETED state specific handling for
+ * when the user attempts to destruct the supplied IO request.
+ *
+ * @param[in] io_request This parameter specifies the IO request object
+ * to be destructed.
+ *
+ * @return This method returns a value indicating if the destruct
+ * operation was successful.
+ * @retval SCI_SUCCESS This return value indicates that the destruct
+ * was successful.
+ */
+static
+SCI_STATUS scif_sas_io_request_completed_destruct_handler(
+ SCI_BASE_REQUEST_T * io_request
+)
+{
+ sci_base_state_machine_change_state(
+ &io_request->state_machine, SCI_BASE_REQUEST_STATE_FINAL
+ );
+
+ sci_base_state_machine_logger_deinitialize(
+ &io_request->state_machine_logger,
+ &io_request->state_machine
+ );
+
+ return SCI_SUCCESS;
+}
+
+//******************************************************************************
+//* A B O R T I N G H A N D L E R S
+//******************************************************************************
+
+/**
+ * @brief This method provides ABORTING state specific handlering for when the
+ * user attempts to abort the supplied IO request.
+ *
+ * @param[in] io_request This parameter specifies the IO request object
+ * to be completed.
+ *
+ * @return This method returns a value indicating if the completion
+ * operation was successful.
+ * @retval SCI_SUCCESS This return value indicates that the abort operation
+ * was successful.
+ */
+static
+SCI_STATUS scif_sas_io_request_aborting_abort_handler(
+ SCI_BASE_REQUEST_T * io_request
+)
+{
+ SCIF_SAS_IO_REQUEST_T * fw_request = (SCIF_SAS_IO_REQUEST_T *) io_request;
+
+ return scic_controller_terminate_request(
+ fw_request->parent.device->domain->controller->core_object,
+ fw_request->parent.device->core_object,
+ fw_request->parent.core_object
+ );
+}
+
+/**
+ * @brief This method provides ABORTING state specific handling for
+ * when the user attempts to complete the supplied IO request.
+ *
+ * @param[in] io_request This parameter specifies the IO request object
+ * to be completed.
+ *
+ * @return This method returns a value indicating if the completion
+ * operation was successful.
+ * @retval SCI_SUCCESS This return value indicates that the completion
+ * was successful.
+ */
+static
+SCI_STATUS scif_sas_io_request_aborting_complete_handler(
+ SCI_BASE_REQUEST_T * io_request
+)
+{
+ sci_base_state_machine_change_state(
+ &io_request->state_machine, SCI_BASE_REQUEST_STATE_COMPLETED
+ );
+
+ return SCI_SUCCESS;
+}
+
+//******************************************************************************
+//* D E F A U L T H A N D L E R S
+//******************************************************************************
+
+/**
+ * @brief This method provides DEFAULT handling for when the user
+ * attempts to start the supplied IO request.
+ *
+ * @param[in] io_request This parameter specifies the IO request object
+ * to be started.
+ *
+ * @return This method returns an indication that the start operation is
+ * not allowed.
+ * @retval SCI_FAILURE_INVALID_STATE This value is always returned.
+ */
+static
+SCI_STATUS scif_sas_io_request_default_start_handler(
+ SCI_BASE_REQUEST_T * io_request
+)
+{
+ SCIF_LOG_ERROR((
+ sci_base_object_get_logger((SCIF_SAS_IO_REQUEST_T *) io_request),
+ SCIF_LOG_OBJECT_IO_REQUEST,
+ "IoRequest:0x%x State:0x%x invalid state to start\n",
+ io_request,
+ sci_base_state_machine_get_state(
+ &((SCIF_SAS_IO_REQUEST_T *) io_request)->parent.parent.state_machine)
+ ));
+
+ return SCI_FAILURE_INVALID_STATE;
+}
+
+/**
+ * @brief This method provides DEFAULT handling for when the user
+ * attempts to abort the supplied IO request.
+ *
+ * @param[in] io_request This parameter specifies the IO request object
+ * to be aborted.
+ *
+ * @return This method returns an indication that the abort operation is
+ * not allowed.
+ * @retval SCI_FAILURE_INVALID_STATE This value is always returned.
+ */
+static
+SCI_STATUS scif_sas_io_request_default_abort_handler(
+ SCI_BASE_REQUEST_T * io_request
+)
+{
+ SCIF_LOG_ERROR((
+ sci_base_object_get_logger((SCIF_SAS_IO_REQUEST_T *) io_request),
+ SCIF_LOG_OBJECT_IO_REQUEST,
+ "IoRequest:0x%x State:0x%x invalid state to abort\n",
+ io_request,
+ sci_base_state_machine_get_state(
+ &((SCIF_SAS_IO_REQUEST_T *) io_request)->parent.parent.state_machine)
+ ));
+
+ return SCI_FAILURE_INVALID_STATE;
+}
+
+/**
+ * @brief This method provides DEFAULT handling for when the user
+ * attempts to complete the supplied IO request.
+ *
+ * @param[in] io_request This parameter specifies the IO request object
+ * to be completed.
+ *
+ * @return This method returns an indication that complete operation is
+ * not allowed.
+ * @retval SCI_FAILURE_INVALID_STATE This value is always returned.
+ */
+SCI_STATUS scif_sas_io_request_default_complete_handler(
+ SCI_BASE_REQUEST_T * io_request
+)
+{
+ SCIF_LOG_ERROR((
+ sci_base_object_get_logger((SCIF_SAS_IO_REQUEST_T *) io_request),
+ SCIF_LOG_OBJECT_IO_REQUEST,
+ "IoRequest:0x%x State:0x%x invalid state to complete\n",
+ io_request,
+ sci_base_state_machine_get_state(
+ &((SCIF_SAS_IO_REQUEST_T *) io_request)->parent.parent.state_machine)
+ ));
+
+ return SCI_FAILURE_INVALID_STATE;
+}
+
+/**
+ * @brief This method provides DEFAULT handling for when the user
+ * attempts to destruct the supplied IO request.
+ *
+ * @param[in] io_request This parameter specifies the IO request object
+ * to be destructed.
+ *
+ * @return This method returns an indication that destruct operation is
+ * not allowed.
+ * @retval SCI_FAILURE_INVALID_STATE This value is always returned.
+ */
+SCI_STATUS scif_sas_io_request_default_destruct_handler(
+ SCI_BASE_REQUEST_T * io_request
+)
+{
+ SCIF_LOG_ERROR((
+ sci_base_object_get_logger((SCIF_SAS_IO_REQUEST_T *) io_request),
+ SCIF_LOG_OBJECT_IO_REQUEST,
+ "IoRequest:0x%x State:0x%x invalid state to destruct.\n",
+ io_request,
+ sci_base_state_machine_get_state(
+ &((SCIF_SAS_IO_REQUEST_T *) io_request)->parent.parent.state_machine)
+ ));
+
+ return SCI_FAILURE_INVALID_STATE;
+}
+
+
+SCI_BASE_REQUEST_STATE_HANDLER_T scif_sas_io_request_state_handler_table[] =
+{
+ // SCI_BASE_REQUEST_STATE_INITIAL
+ {
+ scif_sas_io_request_default_start_handler,
+ scif_sas_io_request_default_abort_handler,
+ scif_sas_io_request_default_complete_handler,
+ scif_sas_io_request_default_destruct_handler
+ },
+ // SCI_BASE_REQUEST_STATE_CONSTRUCTED
+ {
+ scif_sas_io_request_constructed_start_handler,
+ scif_sas_io_request_constructed_abort_handler,
+ scif_sas_io_request_default_complete_handler,
+ scif_sas_io_request_default_destruct_handler
+ },
+ // SCI_BASE_REQUEST_STATE_STARTED
+ {
+ scif_sas_io_request_default_start_handler,
+ scif_sas_io_request_started_abort_handler,
+ scif_sas_io_request_started_complete_handler,
+ scif_sas_io_request_default_destruct_handler
+ },
+ // SCI_BASE_REQUEST_STATE_COMPLETED
+ {
+ scif_sas_io_request_default_start_handler,
+ scif_sas_io_request_default_abort_handler,
+ scif_sas_io_request_default_complete_handler,
+ scif_sas_io_request_completed_destruct_handler
+ },
+ // SCI_BASE_REQUEST_STATE_ABORTING
+ {
+ scif_sas_io_request_default_start_handler,
+ scif_sas_io_request_aborting_abort_handler,
+ scif_sas_io_request_aborting_complete_handler,
+ scif_sas_io_request_default_destruct_handler
+ },
+ // SCI_BASE_REQUEST_STATE_FINAL
+ {
+ scif_sas_io_request_default_start_handler,
+ scif_sas_io_request_default_abort_handler,
+ scif_sas_io_request_default_complete_handler,
+ scif_sas_io_request_default_destruct_handler
+ },
+};
+
diff --git a/sys/dev/isci/scil/scif_sas_io_request_states.c b/sys/dev/isci/scil/scif_sas_io_request_states.c
new file mode 100644
index 0000000..0ae3ca2
--- /dev/null
+++ b/sys/dev/isci/scil/scif_sas_io_request_states.c
@@ -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.
+ *
+ * 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 <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/**
+ * @file
+ *
+ * @brief This file contains all of the SCIF_SAS_IO_REQUEST object
+ * state entrance and exit method implementations.
+ */
+
+#include <dev/isci/scil/scic_controller.h>
+
+#include <dev/isci/scil/scif_sas_io_request.h>
+#include <dev/isci/scil/scif_sas_domain.h>
+#include <dev/isci/scil/scif_sas_controller.h>
+#include <dev/isci/scil/scif_sas_logger.h>
+
+//******************************************************************************
+//* P R O T E C T E D M E T H O D S
+//******************************************************************************
+
+/**
+ * @brief This method implements the actions taken when entering the
+ * INITIAL state.
+ *
+ * @param[in] object This parameter specifies the base object for which
+ * the state transition is occurring. This is cast into a
+ * SCIF_SAS_IO_REQUEST object in the method implementation.
+ *
+ * @return none
+ */
+static
+void scif_sas_io_request_initial_state_enter(
+ SCI_BASE_OBJECT_T *object
+)
+{
+ SCIF_SAS_IO_REQUEST_T * fw_io = (SCIF_SAS_IO_REQUEST_T *)object;
+
+ SET_STATE_HANDLER(
+ &fw_io->parent,
+ scif_sas_io_request_state_handler_table,
+ SCI_BASE_REQUEST_STATE_INITIAL
+ );
+
+ // Initial state is a transitional state to the constructed state
+ sci_base_state_machine_change_state(
+ &fw_io->parent.parent.state_machine, SCI_BASE_REQUEST_STATE_CONSTRUCTED
+ );
+}
+
+/**
+ * @brief This method implements the actions taken when entering the
+ * CONSTRUCTED state.
+ *
+ * @param[in] object This parameter specifies the base object for which
+ * the state transition is occurring. This is cast into a
+ * SCIF_SAS_IO_REQUEST object in the method implementation.
+ *
+ * @return none
+ */
+static
+void scif_sas_io_request_constructed_state_enter(
+ SCI_BASE_OBJECT_T *object
+)
+{
+ SCIF_SAS_IO_REQUEST_T * fw_io = (SCIF_SAS_IO_REQUEST_T *)object;
+
+ SET_STATE_HANDLER(
+ &fw_io->parent,
+ scif_sas_io_request_state_handler_table,
+ SCI_BASE_REQUEST_STATE_CONSTRUCTED
+ );
+}
+
+/**
+ * @brief This method implements the actions taken when entering the
+ * STARTED state.
+ *
+ * @param[in] object This parameter specifies the base object for which
+ * the state transition is occurring. This is cast into a
+ * SCIF_SAS_IO_REQUEST object in the method implementation.
+ *
+ * @return none
+ */
+static
+void scif_sas_io_request_started_state_enter(
+ SCI_BASE_OBJECT_T *object
+)
+{
+ SCIF_SAS_IO_REQUEST_T * fw_io = (SCIF_SAS_IO_REQUEST_T *)object;
+
+ SET_STATE_HANDLER(
+ &fw_io->parent,
+ scif_sas_io_request_state_handler_table,
+ SCI_BASE_REQUEST_STATE_STARTED
+ );
+}
+
+/**
+ * @brief This method implements the actions taken when entering the
+ * COMPLETED state.
+ *
+ * @param[in] object This parameter specifies the base object for which
+ * the state transition is occurring. This is cast into a
+ * SCIF_SAS_IO_REQUEST object in the method implementation.
+ *
+ * @return none
+ */
+static
+void scif_sas_io_request_completed_state_enter(
+ SCI_BASE_OBJECT_T *object
+)
+{
+ SCIF_SAS_IO_REQUEST_T * fw_io = (SCIF_SAS_IO_REQUEST_T *)object;
+
+ SET_STATE_HANDLER(
+ &fw_io->parent,
+ scif_sas_io_request_state_handler_table,
+ SCI_BASE_REQUEST_STATE_COMPLETED
+ );
+}
+
+/**
+ * @brief This method implements the actions taken when entering the
+ * ABORTING state.
+ *
+ * @param[in] object This parameter specifies the base object for which
+ * the state transition is occurring. This is cast into a
+ * SCIF_SAS_IO_REQUEST object in the method implementation.
+ *
+ * @return none
+ */
+static
+void scif_sas_io_request_aborting_state_enter(
+ SCI_BASE_OBJECT_T *object
+)
+{
+ SCIF_SAS_IO_REQUEST_T * fw_io = (SCIF_SAS_IO_REQUEST_T *)object;
+
+ SCIF_LOG_WARNING((
+ sci_base_object_get_logger(fw_io),
+ SCIF_LOG_OBJECT_IO_REQUEST | SCIF_LOG_OBJECT_TASK_MANAGEMENT,
+ "Domain:0x%x Device:0x%x IORequest:0x%x terminating\n",
+ fw_io->parent.device->domain, fw_io->parent.device, fw_io
+ ));
+
+ SET_STATE_HANDLER(
+ &fw_io->parent,
+ scif_sas_io_request_state_handler_table,
+ SCI_BASE_REQUEST_STATE_ABORTING
+ );
+
+ fw_io->parent.status = scif_sas_request_terminate_start(
+ &fw_io->parent, fw_io->parent.core_object
+ );
+}
+
+/**
+ * @brief This method implements the actions taken when exiting the
+ * ABORTING state.
+ *
+ * @param[in] object This parameter specifies the base object for which
+ * the state transition is occurring. This is cast into a
+ * SCIF_SAS_IO_REQUEST object in the method implementation.
+ *
+ * @return none
+ */
+static
+void scif_sas_io_request_aborting_state_exit(
+ SCI_BASE_OBJECT_T *object
+)
+{
+ SCIF_SAS_REQUEST_T * fw_request = (SCIF_SAS_REQUEST_T *)object;
+ scif_sas_request_terminate_complete(fw_request);
+}
+
+/**
+ * @brief This method implements the actions taken when entering the
+ * FINAL state.
+ *
+ * @param[in] object This parameter specifies the base object for which
+ * the state transition is occurring. This is cast into a
+ * SCIF_SAS_IO_REQUEST object in the method implementation.
+ *
+ * @return none
+ */
+static
+void scif_sas_io_request_final_state_enter(
+ SCI_BASE_OBJECT_T *object
+)
+{
+ SCIF_SAS_IO_REQUEST_T * fw_io = (SCIF_SAS_IO_REQUEST_T *)object;
+
+ SET_STATE_HANDLER(
+ &fw_io->parent,
+ scif_sas_io_request_state_handler_table,
+ SCI_BASE_REQUEST_STATE_FINAL
+ );
+}
+
+SCI_BASE_STATE_T scif_sas_io_request_state_table[SCI_BASE_REQUEST_MAX_STATES] =
+{
+ {
+ SCI_BASE_REQUEST_STATE_INITIAL,
+ scif_sas_io_request_initial_state_enter,
+ NULL
+ },
+ {
+ SCI_BASE_REQUEST_STATE_CONSTRUCTED,
+ scif_sas_io_request_constructed_state_enter,
+ NULL
+ },
+ {
+ SCI_BASE_REQUEST_STATE_STARTED,
+ scif_sas_io_request_started_state_enter,
+ NULL
+ },
+ {
+ SCI_BASE_REQUEST_STATE_COMPLETED,
+ scif_sas_io_request_completed_state_enter,
+ NULL
+ },
+ {
+ SCI_BASE_REQUEST_STATE_ABORTING,
+ scif_sas_io_request_aborting_state_enter,
+ scif_sas_io_request_aborting_state_exit
+ },
+ {
+ SCI_BASE_REQUEST_STATE_FINAL,
+ scif_sas_io_request_final_state_enter,
+ NULL
+ },
+};
+
diff --git a/sys/dev/isci/scil/scif_sas_library.c b/sys/dev/isci/scil/scif_sas_library.c
new file mode 100644
index 0000000..5521d6f
--- /dev/null
+++ b/sys/dev/isci/scil/scif_sas_library.c
@@ -0,0 +1,270 @@
+/*-
+ * 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.
+ *
+ * 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 <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/**
+ * @file
+ *
+ * @brief This file contains all of the method implementations for the
+ * SCIF_SAS_LIBRARY object.
+ */
+
+
+#include <dev/isci/scil/scic_library.h>
+#include <dev/isci/scil/sci_pool.h>
+
+#include <dev/isci/scil/scif_sas_library.h>
+#include <dev/isci/scil/scif_sas_logger.h>
+#include <dev/isci/scil/scif_sas_controller.h>
+
+
+/**
+ * This macro simply calculates the size of the framework library. This
+ * includes the memory for each controller object.
+ */
+#define SCIF_LIBRARY_SIZE(max_controllers) \
+( \
+ sizeof(SCIF_SAS_LIBRARY_T) + \
+ (sizeof(SCIF_SAS_CONTROLLER_T) * (max_controllers)) \
+)
+
+
+//******************************************************************************
+//* P U B L I C M E T H O D S
+//******************************************************************************
+
+
+U32 scif_library_get_object_size(
+ U8 max_controller_count
+)
+{
+ return ( SCIF_LIBRARY_SIZE(max_controller_count) +
+ scic_library_get_object_size(max_controller_count) );
+}
+
+// ---------------------------------------------------------------------------
+
+SCI_LIBRARY_HANDLE_T scif_library_construct(
+ void * library_memory,
+ U8 max_controller_count
+)
+{
+ SCI_STATUS status;
+ SCIF_SAS_LIBRARY_T * fw_library = (SCIF_SAS_LIBRARY_T *) library_memory;
+
+ // Just clear out the memory of the structure to be safe.
+ memset(fw_library, 0, scif_library_get_object_size(max_controller_count));
+
+ // Invoke the parent object constructor.
+ SCI_BASE_LIBRARY_CONSTRUCT(fw_library,
+ &fw_library->parent,
+ max_controller_count,
+ struct SCIF_SAS_CONTROLLER,
+ status);
+
+ // The memory for the framework controller objects start immediately
+ // after the library object.
+ fw_library->controllers = (SCIF_SAS_CONTROLLER_T*)
+ ((U8*)library_memory + sizeof(SCIF_SAS_LIBRARY_T));
+
+ // Construct the core library.
+ fw_library->core_object = scic_library_construct(
+ (U8 *)library_memory +
+ SCIF_LIBRARY_SIZE(max_controller_count),
+ max_controller_count
+ );
+
+ // Ensure construction completed successfully for the core.
+ if (fw_library->core_object != SCI_INVALID_HANDLE)
+ {
+ // Set the association in the core library to this framework library.
+ sci_object_set_association(
+ (SCI_OBJECT_HANDLE_T) fw_library->core_object,
+ (void *) fw_library
+ );
+
+ return fw_library;
+ }
+
+ return SCI_INVALID_HANDLE;
+}
+
+// ---------------------------------------------------------------------------
+
+SCI_STATUS scif_library_allocate_controller(
+ SCI_LIBRARY_HANDLE_T library,
+ SCI_CONTROLLER_HANDLE_T * new_controller
+)
+{
+ SCI_STATUS status;
+
+ // Ensure the user supplied a valid library handle.
+ if (library != SCI_INVALID_HANDLE)
+ {
+ SCIF_SAS_LIBRARY_T * fw_library = (SCIF_SAS_LIBRARY_T *) library;
+
+ // Allocate the framework library.
+ SCI_BASE_LIBRARY_ALLOCATE_CONTROLLER(fw_library, new_controller, &status);
+ if (status == SCI_SUCCESS)
+ {
+ SCIF_SAS_CONTROLLER_T * fw_controller;
+
+ // Allocate the core controller and save the handle in the framework
+ // controller object.
+ fw_controller = (SCIF_SAS_CONTROLLER_T*) *new_controller;
+
+ // Just clear out the memory of the structure to be safe.
+ memset(fw_controller, 0, sizeof(SCIF_SAS_CONTROLLER_T));
+
+ status = scic_library_allocate_controller(
+ fw_library->core_object, &(fw_controller->core_object)
+ );
+
+ // Free the framework controller if the core controller allocation
+ // failed.
+ if (status != SCI_SUCCESS)
+ scif_library_free_controller(library, fw_controller);
+ }
+
+ if (status != SCI_SUCCESS)
+ {
+ SCIF_LOG_WARNING((
+ sci_base_object_get_logger(fw_library),
+ SCIF_LOG_OBJECT_LIBRARY,
+ "Library:0x%x Status:0x%x controller allocation failed\n",
+ fw_library, status
+ ));
+ }
+ }
+ else
+ status = SCI_FAILURE_INVALID_PARAMETER_VALUE;
+
+ return status;
+}
+
+// ---------------------------------------------------------------------------
+
+SCI_STATUS scif_library_free_controller(
+ SCI_LIBRARY_HANDLE_T library,
+ SCI_CONTROLLER_HANDLE_T controller
+)
+{
+ SCI_STATUS status;
+
+ if ( (library != SCI_INVALID_HANDLE) && (controller != SCI_INVALID_HANDLE) )
+ {
+ SCI_STATUS core_status;
+ SCIF_SAS_LIBRARY_T * fw_library = (SCIF_SAS_LIBRARY_T*) library;
+ SCIF_SAS_CONTROLLER_T * fw_controller = (SCIF_SAS_CONTROLLER_T*) controller;
+
+ core_status = scic_library_free_controller(
+ fw_library->core_object, fw_controller->core_object
+ );
+
+ scif_sas_controller_destruct(fw_controller);
+
+ SCI_BASE_LIBRARY_FREE_CONTROLLER(
+ (SCIF_SAS_LIBRARY_T *) library,
+ controller,
+ SCIF_SAS_CONTROLLER_T,
+ &status
+ );
+
+ if ( (status == SCI_SUCCESS) && (core_status != SCI_SUCCESS) )
+ status = core_status;
+
+ if (status != SCI_SUCCESS)
+ {
+ SCIF_LOG_WARNING((
+ sci_base_object_get_logger(fw_library),
+ SCIF_LOG_OBJECT_LIBRARY,
+ "Library:0x%x Controller:0x%x Status:0x%x free controller failed\n",
+ fw_library, fw_controller, status
+ ));
+ }
+ }
+ else
+ status = SCI_FAILURE_INVALID_PARAMETER_VALUE;
+
+ return status;
+}
+
+// ---------------------------------------------------------------------------
+
+SCI_LIBRARY_HANDLE_T scif_library_get_scic_handle(
+ SCI_LIBRARY_HANDLE_T scif_library
+)
+{
+ SCIF_SAS_LIBRARY_T * fw_library = (SCIF_SAS_LIBRARY_T*) scif_library;
+
+ return fw_library->core_object;
+}
+
+// ---------------------------------------------------------------------------
+
+#define SCIF_SAS_LIBRARY_MAX_TIMERS 32
+
+U16 scif_library_get_max_timer_count(
+ void
+)
+{
+ /// @todo Need to calculate the exact maximum number of timers needed.
+ return SCIF_SAS_LIBRARY_MAX_TIMERS + scic_library_get_max_timer_count();
+}
+
+//******************************************************************************
+//* P R O T E C T E D M E T H O D S
+//******************************************************************************
+
+
diff --git a/sys/dev/isci/scil/scif_sas_library.h b/sys/dev/isci/scil/scif_sas_library.h
new file mode 100644
index 0000000..63c1ca2
--- /dev/null
+++ b/sys/dev/isci/scil/scif_sas_library.h
@@ -0,0 +1,105 @@
+/*-
+ * 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.
+ *
+ * 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.
+ *
+ * $FreeBSD$
+ */
+#ifndef _SCIF_SAS_LIBRARY_H_
+#define _SCIF_SAS_LIBRARY_H_
+
+/**
+ * @file
+ *
+ * @brief This file contains the protected interface structures, constants,
+ * and methods for the SCIF_SAS_LIBRARY object.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif // __cplusplus
+
+#include <dev/isci/scil/sci_base_library.h>
+#include <dev/isci/scil/scif_library.h>
+
+
+/**
+ * @struct SCIF_SAS_LIBRARY
+ *
+ * @brief The SCI SAS Framework library object acts as the root of the
+ * containment hierarchy for all framework objects.
+ */
+typedef struct SCIF_SAS_LIBRARY
+{
+ /**
+ * The SCI_BASE_LIBRARY is the parent object for the SCIF_SAS_LIBRARY
+ * object.
+ */
+ SCI_BASE_LIBRARY_T parent;
+
+ /**
+ * This field contains the handle for the SCI Core library object that
+ * is managed by the framework.
+ */
+ SCI_LIBRARY_HANDLE_T core_object;
+
+ /**
+ * This field provides the library a reference to the controller objects
+ * being managed by this library.
+ */
+ struct SCIF_SAS_CONTROLLER * controllers;
+
+} SCIF_SAS_LIBRARY_T;
+
+#ifdef __cplusplus
+}
+#endif // __cplusplus
+
+#endif // _SCIF_SAS_LIBRARY_H_
+
diff --git a/sys/dev/isci/scil/scif_sas_logger.h b/sys/dev/isci/scil/scif_sas_logger.h
new file mode 100644
index 0000000..d2bdabc
--- /dev/null
+++ b/sys/dev/isci/scil/scif_sas_logger.h
@@ -0,0 +1,94 @@
+/*-
+ * 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.
+ *
+ * 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.
+ *
+ * $FreeBSD$
+ */
+#ifndef _SCIF_SAS_LOGGER_H_
+#define _SCIF_SAS_LOGGER_H_
+
+/**
+ * @file
+ *
+ * @brief This file contains all of the SCI SAS Framework specific logger
+ * object methods.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif // __cplusplus
+
+#include <dev/isci/scil/scif_logger.h>
+#include <dev/isci/scil/scif_user_callback.h>
+
+#if defined (SCI_LOGGING)
+
+#define SCIF_LOG_ERROR(x) scif_cb_logger_log_error x
+#define SCIF_LOG_WARNING(x) scif_cb_logger_log_warning x
+#define SCIF_LOG_INFO(x) scif_cb_logger_log_info x
+#define SCIF_LOG_TRACE(x) scif_cb_logger_log_trace x
+#define SCIF_LOG_STATES(x) scif_cb_logger_log_states x
+
+#else // defined (SCI_LOGGING)
+
+#define SCIF_LOG_ERROR(x)
+#define SCIF_LOG_WARNING(x)
+#define SCIF_LOG_INFO(x)
+#define SCIF_LOG_TRACE(x)
+#define SCIF_LOG_STATES(x)
+
+#endif // defined (SCI_LOGGING)
+
+#ifdef __cplusplus
+}
+#endif // __cplusplus
+
+#endif // _SCIF_SAS_LOGGER_H_
+
diff --git a/sys/dev/isci/scil/scif_sas_remote_device.c b/sys/dev/isci/scil/scif_sas_remote_device.c
new file mode 100644
index 0000000..7088b38
--- /dev/null
+++ b/sys/dev/isci/scil/scif_sas_remote_device.c
@@ -0,0 +1,794 @@
+/*-
+ * 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.
+ *
+ * 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 <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/**
+ * @file
+ *
+ * @brief This file contains the implementation of the SCIF_SAS_REMOTE_DEVICE
+ * object.
+ */
+
+
+#include <dev/isci/scil/scic_remote_device.h>
+#include <dev/isci/scil/scic_port.h>
+#include <dev/isci/scil/scic_user_callback.h>
+
+#include <dev/isci/scil/scif_sas_logger.h>
+#include <dev/isci/scil/scif_sas_remote_device.h>
+#include <dev/isci/scil/scif_sas_stp_remote_device.h>
+#include <dev/isci/scil/scif_sas_domain.h>
+#include <dev/isci/scil/scif_sas_controller.h>
+#include <dev/isci/scil/sci_controller.h>
+#include <dev/isci/scil/sci_util.h>
+
+
+//******************************************************************************
+//* P U B L I C M E T H O D S
+//******************************************************************************
+
+U32 scif_remote_device_get_object_size(
+ void
+)
+{
+ return ( sizeof(SCIF_SAS_REMOTE_DEVICE_T)
+ + scic_remote_device_get_object_size() );
+}
+
+// ---------------------------------------------------------------------------
+
+void scif_remote_device_construct(
+ SCI_DOMAIN_HANDLE_T domain,
+ void * remote_device_memory,
+ SCI_REMOTE_DEVICE_HANDLE_T * new_scif_remote_device_handle
+)
+{
+ SCIF_SAS_DOMAIN_T * fw_domain = (SCIF_SAS_DOMAIN_T *) domain;
+ SCIF_SAS_REMOTE_DEVICE_T * fw_device = (SCIF_SAS_REMOTE_DEVICE_T *)
+ remote_device_memory;
+
+ SCIF_LOG_TRACE((
+ sci_base_object_get_logger(fw_domain),
+ SCIF_LOG_OBJECT_REMOTE_DEVICE,
+ "scif_remote_device_construct(0x%x, 0x%x, 0x%x) enter\n",
+ domain, remote_device_memory, new_scif_remote_device_handle
+ ));
+
+ memset(remote_device_memory, 0, sizeof(SCIF_SAS_REMOTE_DEVICE_T));
+
+ // The user's handle to the remote device evaluates to the memory
+ // address where the remote device object is stored.
+ *new_scif_remote_device_handle = remote_device_memory;
+
+ fw_device->domain = fw_domain;
+ fw_device->destruct_when_stopped = FALSE;
+ //fw_device->parent.is_failed = FALSE;
+ fw_device->operation_status = SCI_SUCCESS;
+ fw_device->request_count = 0;
+ fw_device->task_request_count = 0;
+ fw_device->is_currently_discovered = TRUE;
+ fw_device->containing_device = NULL;
+ fw_device->device_port_width = 1;
+ fw_device->expander_phy_identifier = 0;
+ fw_device->destination_state =
+ SCIF_SAS_REMOTE_DEVICE_DESTINATION_STATE_UNSPECIFIED;
+ fw_device->ea_target_reset_request_scheduled = NULL;
+
+ // Construct the base object first in order to ensure logging can
+ // function.
+ sci_base_remote_device_construct(
+ &fw_device->parent,
+ sci_base_object_get_logger(fw_domain),
+ scif_sas_remote_device_state_table
+ );
+
+ sci_base_state_machine_construct(
+ &fw_device->starting_substate_machine,
+ &fw_device->parent.parent,
+ scif_sas_remote_device_starting_substate_table,
+ SCIF_SAS_REMOTE_DEVICE_STARTING_SUBSTATE_AWAIT_COMPLETE
+ );
+
+ sci_base_state_machine_construct(
+ &fw_device->ready_substate_machine,
+ &fw_device->parent.parent,
+ scif_sas_remote_device_ready_substate_table,
+ SCIF_SAS_REMOTE_DEVICE_READY_SUBSTATE_OPERATIONAL
+ );
+
+ scif_sas_remote_device_initialize_state_logging(fw_device);
+
+ scic_remote_device_construct(
+ fw_domain->core_object,
+ ((U8*) remote_device_memory) + sizeof(SCIF_SAS_REMOTE_DEVICE_T),
+ &fw_device->core_object
+ );
+
+ // Set the association in the core object, so that we are able to
+ // determine our framework remote device object from the core remote
+ // device.
+ sci_object_set_association(fw_device->core_object, fw_device);
+}
+
+// ---------------------------------------------------------------------------
+
+SCI_STATUS scif_remote_device_da_construct(
+ SCI_REMOTE_DEVICE_HANDLE_T remote_device,
+ SCI_SAS_ADDRESS_T * sas_address,
+ SCI_SAS_IDENTIFY_ADDRESS_FRAME_PROTOCOLS_T * protocols
+)
+{
+ SCI_STATUS status = SCI_SUCCESS;
+ SCIF_SAS_REMOTE_DEVICE_T * fw_device = (SCIF_SAS_REMOTE_DEVICE_T *)
+ remote_device;
+
+ SCIF_LOG_TRACE((
+ sci_base_object_get_logger(fw_device),
+ SCIF_LOG_OBJECT_REMOTE_DEVICE,
+ "scif_remote_device_da_construct(0x%x, 0x%x, 0x%x) enter\n",
+ remote_device, sas_address, protocols
+ ));
+
+ // Make sure the device hasn't already been constructed and added
+ // to the domain.
+ if (scif_domain_get_device_by_sas_address(fw_device->domain, sas_address)
+ == SCI_INVALID_HANDLE)
+ {
+ SCIC_PORT_PROPERTIES_T properties;
+
+ scic_port_get_properties(fw_device->domain->core_object, &properties);
+
+ // Check to see if this is the direct attached device.
+ if ( (sas_address->low == properties.remote.sas_address.low)
+ && (sas_address->high == properties.remote.sas_address.high) )
+ {
+ //Get accurate port width from port's phy mask for a DA device.
+ SCI_GET_BITS_SET_COUNT(properties.phy_mask, fw_device->device_port_width);
+
+ status = scic_remote_device_da_construct(fw_device->core_object);
+ }
+ else
+ // Don't allow the user to construct a direct attached device
+ // if it's not a direct attached device.
+ status = SCI_FAILURE_UNSUPPORTED_PROTOCOL;
+ }
+ else
+ status = SCI_FAILURE_DEVICE_EXISTS;
+
+ if (status == SCI_SUCCESS)
+ {
+ // Add the device to the domain list.
+ sci_abstract_list_pushback(
+ &fw_device->domain->remote_device_list, fw_device
+ );
+
+ // If a SATA/STP device is connected, then construct it.
+ if (protocols->u.bits.stp_target)
+ scif_sas_stp_remote_device_construct(fw_device);
+ else if (protocols->u.bits.smp_target)
+ scif_sas_smp_remote_device_construct(fw_device);
+
+ SCIF_LOG_INFO((
+ sci_base_object_get_logger(fw_device),
+ SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
+ "Domain:0x%x SasAddress:0x%x,0x%x remote device constructed\n",
+ fw_device->domain, sas_address->low, sas_address->high
+ ));
+
+ status = fw_device->state_handlers->parent.start_handler(
+ &fw_device->parent
+ );
+ }
+ else
+ {
+ SCIF_LOG_WARNING((
+ sci_base_object_get_logger(fw_device),
+ SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
+ "Domain:0x%x SasAddress:0x%x,0x%x Status:0x%x remote device construct failure\n",
+ fw_device->domain, sas_address->low, sas_address->high, status
+ ));
+ }
+
+ return status;
+}
+
+// ---------------------------------------------------------------------------
+
+SCI_STATUS scif_remote_device_ea_construct(
+ SCI_REMOTE_DEVICE_HANDLE_T remote_device,
+ SCI_REMOTE_DEVICE_HANDLE_T containing_device,
+ SMP_RESPONSE_DISCOVER_T * smp_response
+)
+{
+ SCI_SAS_ADDRESS_T * sas_address;
+ SCI_STATUS status = SCI_SUCCESS;
+ SCIF_SAS_REMOTE_DEVICE_T * fw_device = (SCIF_SAS_REMOTE_DEVICE_T *)
+ remote_device;
+ SCIF_SAS_REMOTE_DEVICE_T * fw_smp_device = (SCIF_SAS_REMOTE_DEVICE_T *)
+ containing_device;
+
+ fw_device->containing_device = fw_smp_device;
+ fw_device->expander_phy_identifier =
+ fw_smp_device->protocol_device.smp_device.current_activity_phy_index;
+
+ sas_address = &smp_response->attached_sas_address;
+
+ SCIF_LOG_TRACE((
+ sci_base_object_get_logger(fw_device),
+ SCIF_LOG_OBJECT_REMOTE_DEVICE,
+ "scif_remote_device_ea_construct(0x%x, 0x%x) enter\n",
+ remote_device, smp_response
+ ));
+
+ // Make sure the device hasn't already been constructed and added
+ // to the domain.
+ if (scif_domain_get_device_by_sas_address(fw_device->domain, sas_address)
+ == SCI_INVALID_HANDLE)
+ {
+ //for sata device, we need another routine. likely
+ //scif_remote_device_ea_sata_construct.
+ status = scic_remote_device_ea_construct(fw_device->core_object, smp_response);
+ }
+ else
+ status = SCI_FAILURE_DEVICE_EXISTS;
+
+ if (status == SCI_SUCCESS)
+ {
+ // Add the device to the domain list.
+ sci_abstract_list_pushback(
+ &fw_device->domain->remote_device_list, fw_device
+ );
+
+ if (smp_response->protocols.u.bits.attached_smp_target)
+ scif_sas_smp_remote_device_construct(fw_device);
+ else if (smp_response->protocols.u.bits.attached_stp_target)
+ scif_sas_stp_remote_device_construct(fw_device);
+
+ SCIF_LOG_INFO((
+ sci_base_object_get_logger(fw_device),
+ SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
+ "Domain:0x%x SasAddress:0x%x,0x%x remote device constructed\n",
+ fw_device->domain, sas_address->low, sas_address->high
+ ));
+
+ //only start the device if the device is not a SATA disk on SPINUP_HOLD state.
+ if ( scic_remote_device_get_connection_rate(fw_device->core_object) !=
+ SCI_SATA_SPINUP_HOLD )
+ {
+ status = fw_device->state_handlers->parent.start_handler(
+ &fw_device->parent
+ );
+ }
+ }
+ else
+ {
+ SCIF_LOG_WARNING((
+ sci_base_object_get_logger(fw_device),
+ SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
+ "Domain:0x%x SasAddress:0x%x,0x%x Status:0x%x remote device construct failure\n",
+ fw_device->domain, sas_address->low, sas_address->high, status
+ ));
+ }
+
+ return status;
+}
+
+// ---------------------------------------------------------------------------
+
+SCI_STATUS scif_remote_device_destruct(
+ SCI_REMOTE_DEVICE_HANDLE_T remote_device
+)
+{
+ SCIF_SAS_REMOTE_DEVICE_T * fw_device = (SCIF_SAS_REMOTE_DEVICE_T*)
+ remote_device;
+
+ SCIF_LOG_TRACE((
+ sci_base_object_get_logger(fw_device),
+ SCIF_LOG_OBJECT_REMOTE_DEVICE,
+ "scif_remote_device_destruct(0x%x) enter\n",
+ remote_device
+ ));
+
+ //remove the device from domain's remote_device_list
+ fw_device->domain->state_handlers->device_destruct_handler(
+ &fw_device->domain->parent, &fw_device->parent
+ );
+
+ // The destruct process may not complete immediately, since the core
+ // remote device likely needs to be stopped first. However, the user
+ // is not given a callback notification for destruction.
+ return fw_device->state_handlers->parent.destruct_handler(
+ &fw_device->parent
+ );
+}
+
+// ---------------------------------------------------------------------------
+
+SCI_REMOTE_DEVICE_HANDLE_T scif_remote_device_get_scic_handle(
+ SCI_REMOTE_DEVICE_HANDLE_T scif_remote_device
+)
+{
+ SCIF_SAS_REMOTE_DEVICE_T * fw_device = (SCIF_SAS_REMOTE_DEVICE_T*)
+ scif_remote_device;
+
+ if ( (fw_device != NULL) && (fw_device->core_object != SCI_INVALID_HANDLE) )
+ return fw_device->core_object;
+
+ SCIF_LOG_WARNING((
+ sci_base_object_get_logger(fw_device),
+ SCIF_LOG_OBJECT_REMOTE_DEVICE,
+ "RemoteDevice:0x%x no associated core device found\n",
+ fw_device
+ ));
+
+ return SCI_INVALID_HANDLE;
+}
+
+// ---------------------------------------------------------------------------
+
+void scic_cb_remote_device_start_complete(
+ SCI_CONTROLLER_HANDLE_T controller,
+ SCI_REMOTE_DEVICE_HANDLE_T remote_device,
+ SCI_STATUS completion_status
+)
+{
+ SCIF_SAS_REMOTE_DEVICE_T * fw_device = (SCIF_SAS_REMOTE_DEVICE_T*)
+ sci_object_get_association(remote_device);
+
+ SCIF_LOG_TRACE((
+ sci_base_object_get_logger(fw_device),
+ SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_REMOTE_DEVICE_CONFIG,
+ "scic_cb_remote_device_start_complete(0x%x, 0x%x, 0x%x) enter\n",
+ controller, remote_device, completion_status
+ ));
+
+ fw_device->state_handlers->start_complete_handler(
+ fw_device, completion_status
+ );
+}
+
+// ---------------------------------------------------------------------------
+
+void scic_cb_remote_device_stop_complete(
+ SCI_CONTROLLER_HANDLE_T controller,
+ SCI_REMOTE_DEVICE_HANDLE_T remote_device,
+ SCI_STATUS completion_status
+)
+{
+ SCIF_SAS_REMOTE_DEVICE_T * fw_device = (SCIF_SAS_REMOTE_DEVICE_T*)
+ sci_object_get_association(remote_device);
+
+ SCIF_LOG_TRACE((
+ sci_base_object_get_logger(fw_device),
+ SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_REMOTE_DEVICE_CONFIG,
+ "scic_cb_remote_device_stop_complete(0x%x, 0x%x, 0x%x) enter\n",
+ controller, remote_device, completion_status
+ ));
+
+ fw_device->state_handlers->stop_complete_handler(
+ fw_device, completion_status
+ );
+}
+
+// ---------------------------------------------------------------------------
+
+void scic_cb_remote_device_ready(
+ SCI_CONTROLLER_HANDLE_T controller,
+ SCI_REMOTE_DEVICE_HANDLE_T remote_device
+)
+{
+ SCIF_SAS_REMOTE_DEVICE_T * fw_device = (SCIF_SAS_REMOTE_DEVICE_T*)
+ sci_object_get_association(remote_device);
+
+ fw_device->state_handlers->ready_handler(fw_device);
+}
+
+// ---------------------------------------------------------------------------
+
+void scic_cb_remote_device_not_ready(
+ SCI_CONTROLLER_HANDLE_T controller,
+ SCI_REMOTE_DEVICE_HANDLE_T remote_device,
+ U32 reason_code
+)
+{
+ SCIF_SAS_REMOTE_DEVICE_T * fw_device = (SCIF_SAS_REMOTE_DEVICE_T*)
+ sci_object_get_association(remote_device);
+
+ fw_device->state_handlers->not_ready_handler(fw_device,reason_code);
+}
+
+// ---------------------------------------------------------------------------
+
+U16 scif_remote_device_get_max_queue_depth(
+ SCI_REMOTE_DEVICE_HANDLE_T remote_device
+)
+{
+ SCIF_SAS_REMOTE_DEVICE_T * fw_device = (SCIF_SAS_REMOTE_DEVICE_T*)
+ remote_device;
+ SMP_DISCOVER_RESPONSE_PROTOCOLS_T protocols;
+
+ scic_remote_device_get_protocols(fw_device->core_object, &protocols);
+
+ // If the target is a SATA/STP target, then determine the queue depth
+ // for either NCQ or for UDMA.
+ if (protocols.u.bits.attached_stp_target)
+ {
+ if (fw_device->protocol_device.stp_device.sati_device.capabilities
+ & SATI_DEVICE_CAP_NCQ_SUPPORTED_ENABLE)
+ {
+ return fw_device->protocol_device.stp_device.sati_device.ncq_depth;
+ }
+ else
+ {
+ // At the moment, we only allow a single UDMA request to be queued.
+ return 1;
+ }
+ }
+
+ // For SSP devices return a no maximum queue depth supported.
+ return SCIF_REMOTE_DEVICE_NO_MAX_QUEUE_DEPTH;
+}
+
+// ---------------------------------------------------------------------------
+
+SCI_STATUS scif_remote_device_get_containing_device(
+ SCI_REMOTE_DEVICE_HANDLE_T remote_device,
+ SCI_REMOTE_DEVICE_HANDLE_T * containing_device
+)
+{
+ SCI_STATUS status = SCI_FAILURE;
+ SCIF_SAS_REMOTE_DEVICE_T * this_device = (SCIF_SAS_REMOTE_DEVICE_T *)
+ remote_device;
+
+ if ( (this_device != NULL) && (containing_device != NULL) )
+ {
+ *containing_device = (SCI_REMOTE_DEVICE_HANDLE_T)(this_device->containing_device);
+ if (*containing_device != NULL)
+ {
+ status = SCI_SUCCESS;
+ }
+ }
+
+ return status;
+}
+
+// ---------------------------------------------------------------------------
+
+U32 scif_remote_device_get_started_io_count(
+ SCI_REMOTE_DEVICE_HANDLE_T remote_device
+)
+{
+ SCIF_SAS_REMOTE_DEVICE_T * this_device = (SCIF_SAS_REMOTE_DEVICE_T *)
+ remote_device;
+
+ return this_device->request_count - this_device->task_request_count;
+}
+//******************************************************************************
+//* P R O T E C T E D M E T H O D S
+//******************************************************************************
+
+/*
+void scif_sas_remote_device_failure(
+ SCIF_SAS_REMOTE_DEVICE_T * fw_device
+)
+{
+ fw_device->parent.is_failed = TRUE;
+ sci_base_state_machine_change_state(
+ &fw_device->parent.state_machine, SCI_BASE_REMOTE_DEVICE_STATE_STOPPING
+ );
+}
+*/
+
+
+/**
+ * @brief This method retrieves info from Report Phy Sata response and
+ * save the additional data for a SATA remote device, if necessary.
+ *
+ * @param[in] report_phy_sata_response SMP Report Phy Sata response
+ *
+ * @return none
+ */
+void scif_sas_remote_device_save_report_phy_sata_information(
+ SMP_RESPONSE_REPORT_PHY_SATA_T * report_phy_sata_response
+)
+{
+ //do nothing currently. Later, if needed, we will search the existed
+ //remote device by stp_sas_address, then save more information for
+ //that device off the report_phy_sata_response. This assumes the
+ //stp_sas_address from report_phy_sata response is the same sas address
+ //from discover response.
+
+ return;
+}
+
+/**
+ * @brief This method does target reset for DA or EA remote device.
+ *
+ * @param[in] fw_controller, the controller object the target device belongs
+ * to.
+ * @param[in] fw_device, the target device to be hard reset.
+ * @param[in] fw_request, the scif task request object that asked for this
+ * target reset.
+ */
+void scif_sas_remote_device_target_reset(
+ SCIF_SAS_REMOTE_DEVICE_T * fw_device,
+ SCIF_SAS_REQUEST_T * fw_request
+)
+{
+ SCIF_LOG_INFO((
+ sci_base_object_get_logger(fw_device),
+ SCIF_LOG_OBJECT_REMOTE_DEVICE,
+ "scif_sas_remote_device_target_reset! fw_device:0x%x fw_request:0x%x\n",
+ fw_device, fw_request
+ ));
+
+ if (fw_device->containing_device == NULL)
+ {
+ SCI_PORT_HANDLE_T port;
+
+ port = scif_domain_get_scic_port_handle(fw_device->domain);
+
+ //Direct attached device target reset.
+ //calling core to do port reset. The fw_request will not be used here.
+ scic_port_hard_reset(
+ port,
+ scic_remote_device_get_suggested_reset_timeout(fw_device->core_object)
+ );
+ }
+ else
+ { //Expander attached device target reset.
+
+ if ( fw_device->containing_device->protocol_device.smp_device.current_activity
+ == SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_TARGET_RESET )
+ {
+ //The containing expander is in the middle of target resetting other of its
+ //remote disks. Flag this remote device to be target reset later.
+ SCIF_LOG_INFO((
+ sci_base_object_get_logger(fw_device),
+ SCIF_LOG_OBJECT_REMOTE_DEVICE,
+ "scif_sas_remote_device_target_reset DELAYED! fw_device:0x%x fw_request:0x%x\n",
+ fw_device, fw_request
+ ));
+
+ fw_device->ea_target_reset_request_scheduled = fw_request;
+ return;
+ }
+
+ //set current_activity and current_smp_request to expander device.
+ scif_sas_smp_remote_device_start_target_reset(
+ fw_device->containing_device, fw_device, fw_request);
+ }
+
+ scic_remote_device_reset(fw_device->core_object);
+}
+
+
+/**
+ * @brief This method completes target reset for DA or EA remote device.
+ *
+ * @param[in] fw_device, the target device to be hard reset.
+ * @param[in] fw_request, the scif task request object that asked for this
+ * target reset.
+ * @param[in] completion_status
+ */
+void scif_sas_remote_device_target_reset_complete(
+ SCIF_SAS_REMOTE_DEVICE_T * fw_device,
+ SCIF_SAS_REQUEST_T * fw_request,
+ SCI_STATUS completion_status
+)
+{
+ SCIF_LOG_INFO((
+ sci_base_object_get_logger(fw_device),
+ SCIF_LOG_OBJECT_REMOTE_DEVICE,
+ "scif_sas_remote_device_target_reset_complete! "
+ "fw_device:0x%x fw_request:0x%x completion_status 0x%x\n",
+ fw_device, fw_request, completion_status
+ ));
+
+ scif_cb_task_request_complete(
+ fw_device->domain->controller,
+ fw_device,
+ fw_request,
+ (SCI_TASK_STATUS) completion_status
+ );
+
+ scic_remote_device_reset_complete(fw_device->core_object);
+
+ //For expander attached device done target reset.
+ if (fw_device->containing_device != NULL)
+ {
+ //search for all the devices in the domain to find other remote devices
+ //needs to be target reset.
+ SCIF_SAS_REMOTE_DEVICE_T * next_device;
+
+ scif_sas_smp_remote_device_clear(fw_device->containing_device);
+
+ if( (next_device = scif_sas_domain_find_next_ea_target_reset(fw_device->domain))
+ != NULL )
+ {
+ scif_sas_smp_remote_device_start_target_reset(
+ next_device->containing_device,
+ next_device,
+ next_device->ea_target_reset_request_scheduled
+ );
+
+ next_device->ea_target_reset_request_scheduled = NULL;
+ }
+ else
+ {
+ //if the domain is in the DISCOVER state, we should resume the DISCOVER.
+ if (fw_device->domain->parent.state_machine.current_state_id ==
+ SCI_BASE_DOMAIN_STATE_DISCOVERING)
+ {
+ SCIF_SAS_REMOTE_DEVICE_T * top_expander = fw_device->containing_device;
+
+ while(top_expander->containing_device != NULL)
+ top_expander = top_expander->containing_device;
+
+ scif_sas_domain_start_smp_discover(fw_device->domain, top_expander);
+ }
+ else
+ {
+ //Tell driver to kick off Discover process. If the domain is already
+ //in Discovery state, this discovery requst will not be carried on.
+ scif_cb_domain_change_notification(
+ fw_device->domain->controller, fw_device->domain );
+ }
+ }
+ }
+ else
+ {
+ //Tell driver to kick off Discover process. If the domain is already
+ //in Discovery state, this discovery requst will not be carried on.
+ scif_cb_domain_change_notification(
+ fw_device->domain->controller, fw_device->domain );
+ }
+}
+
+#if !defined(DISABLE_WIDE_PORTED_TARGETS)
+SCI_STATUS scif_sas_remote_device_update_port_width(
+ SCIF_SAS_REMOTE_DEVICE_T * fw_device,
+ U8 new_port_width
+)
+{
+ SCIF_LOG_INFO((
+ sci_base_object_get_logger(fw_device),
+ SCIF_LOG_OBJECT_REMOTE_DEVICE,
+ "scif_sas_remote_device_update_port_width (0x%x, 0x%x) enter\n",
+ fw_device, new_port_width
+ ));
+
+ fw_device->device_port_width = new_port_width;
+
+ //Don't Start a new update of port width if a device is already in
+ //UPDATING PORT WIDTH state.
+ if (fw_device->parent.state_machine.current_state_id == SCI_BASE_REMOTE_DEVICE_STATE_READY)
+ {
+ if (fw_device->device_port_width != 0)
+ {
+ //Change state to UPDATING_PORT_WIDTH
+ sci_base_state_machine_change_state(
+ &fw_device->parent.state_machine,
+ SCI_BASE_REMOTE_DEVICE_STATE_UPDATING_PORT_WIDTH
+ );
+ }
+
+ return SCI_SUCCESS;
+ }
+ else if (fw_device->parent.state_machine.current_state_id ==
+ SCI_BASE_REMOTE_DEVICE_STATE_STARTING)
+ {
+ fw_device->destination_state =
+ SCIF_SAS_REMOTE_DEVICE_DESTINATION_STATE_UPDATING_PORT_WIDTH;
+ }
+
+ return SCI_FAILURE_INVALID_STATE;
+}
+#endif //#if !defined(DISABLE_WIDE_PORTED_TARGETS)
+
+
+#ifdef SCI_LOGGING
+void scif_sas_remote_device_initialize_state_logging(
+ SCIF_SAS_REMOTE_DEVICE_T * remote_device
+)
+{
+ sci_base_state_machine_logger_initialize(
+ &remote_device->parent.state_machine_logger,
+ &remote_device->parent.state_machine,
+ &remote_device->parent.parent,
+ scif_cb_logger_log_states,
+ "SCIF_SAS_REMOTE_DEVICE_T", "base_state_machine",
+ SCIF_LOG_OBJECT_REMOTE_DEVICE
+ );
+
+ sci_base_state_machine_logger_initialize(
+ &remote_device->starting_substate_machine_logger,
+ &remote_device->starting_substate_machine,
+ &remote_device->parent.parent,
+ scif_cb_logger_log_states,
+ "SCIF_SAS_REMOTE_DEVICE_T", "starting substate machine",
+ SCIF_LOG_OBJECT_REMOTE_DEVICE
+ );
+
+ sci_base_state_machine_logger_initialize(
+ &remote_device->ready_substate_machine_logger,
+ &remote_device->ready_substate_machine,
+ &remote_device->parent.parent,
+ scif_cb_logger_log_states,
+ "SCIF_SAS_REMOTE_DEVICE_T", "ready substate machine",
+ SCIF_LOG_OBJECT_REMOTE_DEVICE
+ );
+}
+
+void scif_sas_remote_device_deinitialize_state_logging(
+ SCIF_SAS_REMOTE_DEVICE_T * remote_device
+)
+{
+ sci_base_state_machine_logger_deinitialize(
+ &remote_device->parent.state_machine_logger,
+ &remote_device->parent.state_machine
+ );
+
+ sci_base_state_machine_logger_deinitialize(
+ &remote_device->starting_substate_machine_logger,
+ &remote_device->starting_substate_machine
+ );
+
+ sci_base_state_machine_logger_deinitialize(
+ &remote_device->ready_substate_machine_logger,
+ &remote_device->ready_substate_machine
+ );
+}
+#endif // SCI_LOGGING
+
diff --git a/sys/dev/isci/scil/scif_sas_remote_device.h b/sys/dev/isci/scil/scif_sas_remote_device.h
new file mode 100644
index 0000000..91ad2ed
--- /dev/null
+++ b/sys/dev/isci/scil/scif_sas_remote_device.h
@@ -0,0 +1,502 @@
+/*-
+ * 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.
+ *
+ * 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.
+ *
+ * $FreeBSD$
+ */
+#ifndef _SCIF_SAS_REMOTE_DEVICE_H_
+#define _SCIF_SAS_REMOTE_DEVICE_H_
+
+/**
+ * @file
+ *
+ * @brief This file contains the protected interface structures, constants,
+ * and methods for the SCIF_SAS_REMOTE_DEVICE object.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif // __cplusplus
+
+#include <dev/isci/scil/scif_remote_device.h>
+
+#include <dev/isci/scil/sci_base_remote_device.h>
+#include <dev/isci/scil/sci_base_request.h>
+#include <dev/isci/scil/sci_base_state_machine_logger.h>
+#include <dev/isci/scil/scif_sas_stp_remote_device.h>
+#include <dev/isci/scil/scif_sas_smp_remote_device.h>
+
+
+struct SCIF_SAS_DOMAIN;
+struct SCIF_SAS_REMOTE_DEVICE;
+struct SCIF_SAS_REQUEST;
+
+/**
+ * This constant indicates the number of milliseconds to wait for the core
+ * to start/stop it's remote device object.
+ */
+#define SCIF_SAS_REMOTE_DEVICE_CORE_OP_TIMEOUT 1000
+
+/**
+ * @enum _SCIF_SAS_REMOTE_DEVICE_STARTING_SUBSTATES
+ *
+ * @brief This enumeration depicts all the substates for the remote device's
+ * starting substate machine.
+ */
+typedef enum _SCIF_SAS_REMOTE_DEVICE_STARTING_SUBSTATES
+{
+ /**
+ * This state indicates that the framework is waiting for the core to
+ * issue a scic_cb_remote_device_start_complete() notification.
+ */
+ SCIF_SAS_REMOTE_DEVICE_STARTING_SUBSTATE_AWAIT_COMPLETE,
+
+ /**
+ * This state indicates that the core has received the core's
+ * scic_cb_remote_device_start_complete() notification.
+ */
+ SCIF_SAS_REMOTE_DEVICE_STARTING_SUBSTATE_AWAIT_READY,
+
+ SCIF_SAS_REMOTE_DEVICE_STARTING_SUBSTATE_MAX_STATES
+
+} SCIF_SAS_REMOTE_DEVICE_STARTING_SUBSTATES;
+
+/**
+ * @enum _SCIF_SAS_REMOTE_DEVICE_READY_SUBSTATES
+ *
+ * @brief This enumeration depicts all of the substates for the remote
+ * device READY substate machine.
+ */
+typedef enum _SCIF_SAS_REMOTE_DEVICE_READY_SUBSTATES
+{
+ /**
+ * The Operational sub-state indicates that the remote device object
+ * is capable of receiving and handling all request types.
+ */
+ SCIF_SAS_REMOTE_DEVICE_READY_SUBSTATE_OPERATIONAL,
+
+ /**
+ * This substate indicates that core remote device is not ready.
+ * As a result, no new IO or Task Management requests are allowed.
+ */
+ SCIF_SAS_REMOTE_DEVICE_READY_SUBSTATE_SUSPENDED,
+
+ /**
+ * This substate indicates that task management to this device is
+ * ongoing and new IO requests are not allowed.
+ */
+ SCIF_SAS_REMOTE_DEVICE_READY_SUBSTATE_TASK_MGMT,
+
+ /**
+ * This substate indicates that core remote device is not ready due
+ * to an NCQ error. As a result, no new IO requests are allowed.
+ */
+ SCIF_SAS_REMOTE_DEVICE_READY_SUBSTATE_NCQ_ERROR,
+
+ SCIF_SAS_REMOTE_DEVICE_READY_SUBSTATE_MAX_STATES
+
+} SCIF_SAS_REMOTE_DEVICE_READY_SUBSTATES;
+
+struct SCIF_SAS_REMOTE_DEVICE;
+typedef void (*SCIF_SAS_REMOTE_DEVICE_COMPLETION_HANDLER_T)(
+ struct SCIF_SAS_REMOTE_DEVICE *,
+ SCI_STATUS
+);
+
+typedef void (*SCIF_SAS_REMOTE_DEVICE_HANDLER_T)(
+ struct SCIF_SAS_REMOTE_DEVICE *
+);
+
+typedef void (*SCIF_SAS_REMOTE_DEVICE_NOT_READY_HANDLER_T)(
+ struct SCIF_SAS_REMOTE_DEVICE *,
+ U32
+);
+
+/**
+ * @struct SCIF_SAS_REMOTE_DEVICE_STATE_HANDLER
+ *
+ * @brief This structure defines the state handler methods for states and
+ * substates applicable for the framework remote device object.
+ */
+typedef struct SCIF_SAS_REMOTE_DEVICE_STATE_HANDLER
+{
+ SCI_BASE_REMOTE_DEVICE_STATE_HANDLER_T parent;
+ SCIF_SAS_REMOTE_DEVICE_COMPLETION_HANDLER_T start_complete_handler;
+ SCIF_SAS_REMOTE_DEVICE_COMPLETION_HANDLER_T stop_complete_handler;
+ SCIF_SAS_REMOTE_DEVICE_HANDLER_T ready_handler;
+ SCIF_SAS_REMOTE_DEVICE_NOT_READY_HANDLER_T not_ready_handler;
+ SCI_BASE_REMOTE_DEVICE_REQUEST_HANDLER_T start_high_priority_io_handler;
+ SCI_BASE_REMOTE_DEVICE_HIGH_PRIORITY_REQUEST_COMPLETE_HANDLER_T complete_high_priority_io_handler;
+} SCIF_SAS_REMOTE_DEVICE_STATE_HANDLER_T;
+
+/**
+ * @struct SCIF_SAS_REMOTE_DEVICE
+ *
+ * @brief The SCI SAS Framework remote device object abstracts the SAS remote
+ * device level behavior for the framework component. Additionally,
+ * it provides a higher level of abstraction for the core remote
+ * device object.
+ */
+typedef struct SCIF_SAS_REMOTE_DEVICE
+{
+ /**
+ * The SCI_BASE_REMOTE_DEVICE is the parent object for the
+ * SCIF_SAS_REMOTE_DEVICE object.
+ */
+ SCI_BASE_REMOTE_DEVICE_T parent;
+
+ /**
+ * This field contains the handle for the SCI Core remote device object
+ * that is managed by this framework controller.
+ */
+ SCI_REMOTE_DEVICE_HANDLE_T core_object;
+
+ /**
+ * This field references the list of state specific handler methods to
+ * be utilized for this remote device instance.
+ */
+ SCIF_SAS_REMOTE_DEVICE_STATE_HANDLER_T * state_handlers;
+
+ /**
+ * This field specifies the state machine utilized to manage the
+ * starting remote device substate machine.
+ */
+ SCI_BASE_STATE_MACHINE_T starting_substate_machine;
+
+ /**
+ * This field specifies the state machine utilized to manage the
+ * starting remote device substate machine.
+ */
+ SCI_BASE_STATE_MACHINE_T ready_substate_machine;
+
+ union
+ {
+ /**
+ * This field specifies the information specific to SATA/STP device
+ * instances. This field is not utilized for SSP/SMP.
+ */
+ SCIF_SAS_STP_REMOTE_DEVICE_T stp_device;
+
+ /**
+ * This field specifies the information specific to SMP device instances.
+ * This field is not utilized for SSP/SATA/STP.
+ */
+ SCIF_SAS_SMP_REMOTE_DEVICE_T smp_device;
+
+ }protocol_device;
+
+ /**
+ * This field indicates the domain object containing this remote device.
+ */
+ struct SCIF_SAS_DOMAIN * domain;
+
+ /**
+ * This field counts the number of requests (IO and task management)
+ * that are currently outstanding for this device.
+ */
+ U32 request_count;
+
+ /**
+ * This field counts the number of only task management request that are
+ * currently outstanding for this device.
+ */
+ U32 task_request_count;
+
+ /**
+ * This field is utilize to store the status value of various operations
+ * the can be executed on this remote device instance.
+ */
+ SCI_STATUS operation_status;
+
+ /**
+ * This field is utilize to indicate that the remote device should be
+ * destructed when it finally reaches the stopped state. This will
+ * include destructing the core remote device as well.
+ */
+ BOOL destruct_when_stopped;
+
+ /**
+ * This field marks a device state of being discovered or not, majorly used
+ * during re-discover procedure.
+ */
+ BOOL is_currently_discovered;
+
+ /**
+ * This filed stores the expander device this device connected to, only if this
+ * device is behind expander. So this field also served as a flag to tell if a
+ * device is a EA one.
+ */
+ struct SCIF_SAS_REMOTE_DEVICE * containing_device;
+
+ /**
+ * This field stores the expander phy identifier for an expander attached
+ * device. This field is only used by expander attached device.
+ */
+ U8 expander_phy_identifier;
+
+ /**
+ * This field stores the port width for a device. Most devices are narrow port
+ * device, their port width is 1. If a device is a wide port device, their
+ * port width is larger than 1.
+ */
+ U8 device_port_width;
+
+ /**
+ * This field stores the destination state for a remote device in UPDATING
+ * PORT WIDTH state. The possible destination states for a remote device in
+ * UPDATING_PORT_WIDTH state are READY or STOPPING.
+ */
+ U16 destination_state;
+
+ /**
+ * This field stores the scheduled/delayed EA target reset request.
+ */
+ struct SCIF_SAS_REQUEST * ea_target_reset_request_scheduled;
+
+ #ifdef SCI_LOGGING
+ /**
+ * This field is the observer of the base state machine for this device
+ * object.
+ */
+ SCI_BASE_OBSERVER_T base_state_machine_observer;
+
+ /**
+ * This field is the state machine logger of the startig substate machine for
+ * this device object.
+ */
+ SCI_BASE_STATE_MACHINE_LOGGER_T starting_substate_machine_logger;
+
+ /**
+ * This field is the state machine logger of the ready substate machine for
+ * this device object.
+ */
+ SCI_BASE_STATE_MACHINE_LOGGER_T ready_substate_machine_logger;
+ #endif // SCI_LOGGING
+
+} SCIF_SAS_REMOTE_DEVICE_T;
+
+extern SCI_BASE_STATE_T scif_sas_remote_device_state_table[];
+extern SCIF_SAS_REMOTE_DEVICE_STATE_HANDLER_T
+ scif_sas_remote_device_state_handler_table[];
+
+extern SCI_BASE_STATE_T scif_sas_remote_device_starting_substate_table[];
+extern SCIF_SAS_REMOTE_DEVICE_STATE_HANDLER_T
+ scif_sas_remote_device_starting_substate_handler_table[];
+
+extern SCI_BASE_STATE_T scif_sas_remote_device_ready_substate_table[];
+extern SCIF_SAS_REMOTE_DEVICE_STATE_HANDLER_T
+ scif_sas_remote_device_ready_substate_handler_table[];
+
+/**
+ * @enum
+ *
+ * This enumeration is used to define the end destination state for the
+ * framework remote device.
+ */
+enum SCIF_SAS_REMOTE_DEVICE_DESTINATION_STATE
+{
+ SCIF_SAS_REMOTE_DEVICE_DESTINATION_STATE_UNSPECIFIED,
+ SCIF_SAS_REMOTE_DEVICE_DESTINATION_STATE_READY,
+ SCIF_SAS_REMOTE_DEVICE_DESTINATION_STATE_STOPPING,
+ SCIF_SAS_REMOTE_DEVICE_DESTINATION_STATE_UPDATING_PORT_WIDTH
+};
+
+//******************************************************************************
+//* P R O T E C T E D M E T H O D S
+//******************************************************************************
+void scif_sas_remote_device_save_report_phy_sata_information(
+ SMP_RESPONSE_REPORT_PHY_SATA_T * report_phy_sata_response
+);
+
+void scif_sas_remote_device_target_reset(
+ SCIF_SAS_REMOTE_DEVICE_T * fw_device,
+ struct SCIF_SAS_REQUEST * fw_request
+);
+
+void scif_sas_remote_device_target_reset_complete(
+ SCIF_SAS_REMOTE_DEVICE_T * fw_device,
+ struct SCIF_SAS_REQUEST * fw_request,
+ SCI_STATUS completion_status
+);
+
+#ifdef SCI_LOGGING
+void scif_sas_remote_device_initialize_state_logging(
+ SCIF_SAS_REMOTE_DEVICE_T * remote_device
+);
+
+void scif_sas_remote_device_deinitialize_state_logging(
+ SCIF_SAS_REMOTE_DEVICE_T * remote_device
+);
+#else // SCI_LOGGING
+#define scif_sas_remote_device_initialize_state_logging(x)
+#define scif_sas_remote_device_deinitialize_state_logging(x)
+#endif // SCI_LOGGING
+
+//******************************************************************************
+//* R E A D Y O P E R A T I O N A L S T A T E H A N D L E R S
+//******************************************************************************
+
+SCI_STATUS scif_sas_remote_device_ready_operational_complete_io_handler(
+ SCI_BASE_REMOTE_DEVICE_T * remote_device,
+ SCI_BASE_REQUEST_T * io_request
+);
+
+SCI_STATUS scif_sas_remote_device_ready_operational_complete_task_handler(
+ SCI_BASE_REMOTE_DEVICE_T * remote_device,
+ SCI_BASE_REQUEST_T * task_request
+);
+
+SCI_STATUS scif_sas_remote_device_ready_task_management_complete_task_handler(
+ SCI_BASE_REMOTE_DEVICE_T * remote_device,
+ SCI_BASE_REQUEST_T * task_request
+);
+
+//******************************************************************************
+//* D E F A U L T S T A T E H A N D L E R S
+//******************************************************************************
+
+SCI_STATUS scif_sas_remote_device_default_start_handler(
+ SCI_BASE_REMOTE_DEVICE_T * remote_device
+);
+
+SCI_STATUS scif_sas_remote_device_default_stop_handler(
+ SCI_BASE_REMOTE_DEVICE_T * remote_device
+);
+
+SCI_STATUS scif_sas_remote_device_default_reset_handler(
+ SCI_BASE_REMOTE_DEVICE_T * remote_device
+);
+
+SCI_STATUS scif_sas_remote_device_default_reset_complete_handler(
+ SCI_BASE_REMOTE_DEVICE_T * remote_device
+);
+
+SCI_STATUS scif_sas_remote_device_default_start_io_handler(
+ SCI_BASE_REMOTE_DEVICE_T * remote_device,
+ SCI_BASE_REQUEST_T * io_request
+);
+
+void scif_sas_remote_device_default_start_complete_handler(
+ SCIF_SAS_REMOTE_DEVICE_T * fw_device,
+ SCI_STATUS completion_status
+);
+
+void scif_sas_remote_device_default_stop_complete_handler(
+ SCIF_SAS_REMOTE_DEVICE_T * fw_device,
+ SCI_STATUS completion_status
+);
+
+SCI_STATUS scif_sas_remote_device_default_destruct_handler(
+ SCI_BASE_REMOTE_DEVICE_T * remote_device
+);
+
+SCI_STATUS scif_sas_remote_device_default_complete_io_handler(
+ SCI_BASE_REMOTE_DEVICE_T * remote_device,
+ SCI_BASE_REQUEST_T * io_request
+);
+
+SCI_STATUS scif_sas_remote_device_default_complete_high_priority_io_handler(
+ SCI_BASE_REMOTE_DEVICE_T * remote_device,
+ SCI_BASE_REQUEST_T * io_request,
+ void * response_data,
+ SCI_IO_STATUS completion_status
+);
+
+SCI_STATUS scif_sas_remote_device_default_continue_io_handler(
+ SCI_BASE_REMOTE_DEVICE_T * remote_device,
+ SCI_BASE_REQUEST_T * io_request
+);
+
+SCI_STATUS scif_sas_remote_device_default_start_task_handler(
+ SCI_BASE_REMOTE_DEVICE_T * remote_device,
+ SCI_BASE_REQUEST_T * task_request
+);
+
+SCI_STATUS scif_sas_remote_device_default_complete_task_handler(
+ SCI_BASE_REMOTE_DEVICE_T * remote_device,
+ SCI_BASE_REQUEST_T * task_request
+);
+
+void scif_sas_remote_device_default_ready_handler(
+ SCIF_SAS_REMOTE_DEVICE_T * fw_device
+);
+
+void scif_sas_remote_device_default_not_ready_handler(
+ SCIF_SAS_REMOTE_DEVICE_T * fw_device,
+ U32 reason_code
+);
+
+SCI_STATUS scif_sas_remote_device_ready_task_management_start_high_priority_io_handler(
+ SCI_BASE_REMOTE_DEVICE_T * remote_device,
+ SCI_BASE_REQUEST_T * io_request
+);
+
+SCI_STATUS scif_sas_remote_device_ready_task_management_complete_high_priority_io_handler(
+ SCI_BASE_REMOTE_DEVICE_T * remote_device,
+ SCI_BASE_REQUEST_T * io_request,
+ void * response_data,
+ SCI_IO_STATUS completion_status
+);
+
+#if !defined(DISABLE_WIDE_PORTED_TARGETS)
+SCI_STATUS scif_sas_remote_device_update_port_width(
+ SCIF_SAS_REMOTE_DEVICE_T * fw_device,
+ U8 new_port_width
+);
+#else // !defined(DISABLE_WIDE_PORTED_TARGETS)
+#define scif_sas_remote_device_update_port_width(device) SCI_FAILURE
+#endif //#if !defined(DISABLE_WIDE_PORTED_TARGETS)
+
+#ifdef __cplusplus
+}
+#endif // __cplusplus
+
+#endif // _SCIF_SAS_REMOTE_DEVICE_H_
+
diff --git a/sys/dev/isci/scil/scif_sas_remote_device_ready_substate_handlers.c b/sys/dev/isci/scil/scif_sas_remote_device_ready_substate_handlers.c
new file mode 100644
index 0000000..4471434
--- /dev/null
+++ b/sys/dev/isci/scil/scif_sas_remote_device_ready_substate_handlers.c
@@ -0,0 +1,779 @@
+/*-
+ * 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.
+ *
+ * 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 <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/**
+ * @file
+ *
+ * @brief This file contains all of the method implementations pertaining
+ * to the framework remote device READY sub-state handler methods.
+ */
+
+#include <dev/isci/scil/scic_remote_device.h>
+#include <dev/isci/scil/scic_io_request.h>
+
+#include <dev/isci/scil/scif_sas_logger.h>
+#include <dev/isci/scil/scif_sas_remote_device.h>
+#include <dev/isci/scil/scif_sas_domain.h>
+#include <dev/isci/scil/scif_sas_task_request.h>
+#include <dev/isci/scil/scif_sas_io_request.h>
+#include <dev/isci/scil/scif_sas_internal_io_request.h>
+#include <dev/isci/scil/scif_sas_controller.h>
+#include <dev/isci/scil/sci_abstract_list.h>
+#include <dev/isci/scil/intel_sat.h>
+#include <dev/isci/scil/sci_controller.h>
+
+//******************************************************************************
+//* P R I V A T E M E T H O D S
+//******************************************************************************
+
+/**
+ * @brief This method implements the behavior common to starting a task mgmt
+ * request. It will change the ready substate to task management.
+ *
+ * @param[in] fw_device This parameter specifies the remote device for
+ * which to complete a request.
+ * @param[in] fw_task This parameter specifies the task management
+ * request being started.
+ *
+ * @return This method returns a value indicating the status of the
+ * start operation.
+ */
+static
+SCI_STATUS scif_sas_remote_device_start_task_request(
+ SCIF_SAS_REMOTE_DEVICE_T * fw_device,
+ SCIF_SAS_TASK_REQUEST_T * fw_task
+)
+{
+ // Transition into the TASK MGMT substate if not already in it.
+ if (fw_device->ready_substate_machine.current_state_id
+ != SCIF_SAS_REMOTE_DEVICE_READY_SUBSTATE_TASK_MGMT)
+ {
+ sci_base_state_machine_change_state(
+ &fw_device->ready_substate_machine,
+ SCIF_SAS_REMOTE_DEVICE_READY_SUBSTATE_TASK_MGMT
+ );
+ }
+
+ fw_device->request_count++;
+ fw_device->task_request_count++;
+
+ return SCI_SUCCESS;
+}
+
+//******************************************************************************
+//* R E A D Y O P E R A T I O N A L H A N D L E R S
+//******************************************************************************
+
+/**
+ * @brief This method provides OPERATIONAL sub-state specific handling for
+ * when the core remote device object issues a device not ready
+ * notification.
+ *
+ * @param[in] remote_device This parameter specifies the remote device
+ * object for which the notification occurred.
+ *
+ * @return none.
+ */
+static
+void scif_sas_remote_device_ready_operational_not_ready_handler(
+ SCIF_SAS_REMOTE_DEVICE_T * fw_device,
+ U32 reason_code
+)
+{
+ if (reason_code == SCIC_REMOTE_DEVICE_NOT_READY_SATA_SDB_ERROR_FIS_RECEIVED)
+ {
+ sci_base_state_machine_change_state(
+ &fw_device->ready_substate_machine,
+ SCIF_SAS_REMOTE_DEVICE_READY_SUBSTATE_NCQ_ERROR
+ );
+ }
+ else
+ {
+ // Even though we are in the OPERATIONAL state, the core remote device is not
+ // ready. As a result, we process user requests/events as if we were
+ // stopping the framework remote device.
+ sci_base_state_machine_change_state(
+ &fw_device->ready_substate_machine,
+ SCIF_SAS_REMOTE_DEVICE_READY_SUBSTATE_SUSPENDED
+ );
+ }
+}
+
+/**
+ * @brief This method provides TASK MGMT sub-state specific handling for when
+ * the core remote device object issues a device not ready notification.
+ *
+ * @param[in] remote_device This parameter specifies the remote device
+ * object for which the notification occurred.
+ *
+ * @return none.
+ */
+static
+void scif_sas_remote_device_ready_task_management_not_ready_handler(
+ SCIF_SAS_REMOTE_DEVICE_T * fw_device,
+ U32 reason_code
+)
+{
+ //do nothing. Don't need to go to suspended substate.
+}
+
+/**
+ * @brief This method provides OPERATIONAL sub-state specific handling for
+ * when the remote device is being stopped by the framework.
+ *
+ * @param[in] remote_device This parameter specifies the remote device
+ * object for which the stop operation is being requested.
+ *
+ * @return This method returns an indication as to whether the failure
+ * operation completed successfully.
+ */
+static
+SCI_STATUS scif_sas_remote_device_ready_operational_stop_handler(
+ SCI_BASE_REMOTE_DEVICE_T * remote_device
+)
+{
+ SCIF_SAS_REMOTE_DEVICE_T * fw_device = (SCIF_SAS_REMOTE_DEVICE_T *)
+ remote_device;
+
+ sci_base_state_machine_change_state(
+ &fw_device->parent.state_machine, SCI_BASE_REMOTE_DEVICE_STATE_STOPPING
+ );
+
+ return fw_device->operation_status;
+}
+
+/**
+ * @brief This method provides OPERATIONAL sub-state specific handling for
+ * when the user attempts to destruct the remote device. In
+ * the READY state the framework must first stop the device
+ * before destructing it.
+ *
+ * @param[in] remote_device This parameter specifies the remote device
+ * object for which the framework is attempting to start.
+ *
+ * @return This method returns an indication as to whether the destruct
+ * operation completed successfully.
+ */
+static
+SCI_STATUS scif_sas_remote_device_ready_operational_destruct_handler(
+ SCI_BASE_REMOTE_DEVICE_T * remote_device
+)
+{
+ SCIF_SAS_REMOTE_DEVICE_T * fw_device = (SCIF_SAS_REMOTE_DEVICE_T *)
+ remote_device;
+
+ fw_device->destruct_when_stopped = TRUE;
+
+ return (fw_device->state_handlers->parent.stop_handler(&fw_device->parent));
+}
+
+/**
+ * @brief This method provides OPERATIONAL sub-state specific handling for
+ * when the remote device undergoes a failure condition.
+ *
+ * @param[in] remote_device This parameter specifies the remote device
+ * object for which the failure condition occurred.
+ *
+ * @return This method returns an indication as to whether the failure
+ * operation completed successfully.
+ */
+static
+SCI_STATUS scif_sas_remote_device_ready_operational_fail_handler(
+ SCI_BASE_REMOTE_DEVICE_T * remote_device
+)
+{
+ SCIF_SAS_REMOTE_DEVICE_T * fw_device = (SCIF_SAS_REMOTE_DEVICE_T *)
+ remote_device;
+
+ SCIF_LOG_WARNING((
+ sci_base_object_get_logger(fw_device),
+ SCIF_LOG_OBJECT_REMOTE_DEVICE,
+ "RemoteDevice:0x%x ready device failed\n",
+ fw_device
+ ));
+
+ sci_base_state_machine_change_state(
+ &fw_device->parent.state_machine, SCI_BASE_REMOTE_DEVICE_STATE_FAILED
+ );
+
+ /// @todo Fix the return code handling.
+ return SCI_FAILURE;
+}
+
+/**
+ * @brief This method provides OPERATIONAL sub-state specific handling for
+ * when a user attempts to start an IO request on a remote
+ * device.
+ *
+ * @param[in] remote_device This parameter specifies the remote device
+ * object on which the user is attempting to perform a start
+ * IO operation.
+ * @param[in] io_request This parameter specifies the IO request to be
+ * started.
+ *
+ * @return This method returns an indication as to whether the IO request
+ * started successfully.
+ */
+static
+SCI_STATUS scif_sas_remote_device_ready_operational_start_io_handler(
+ SCI_BASE_REMOTE_DEVICE_T * remote_device,
+ SCI_BASE_REQUEST_T * io_request
+)
+{
+ SCIF_SAS_REMOTE_DEVICE_T * fw_device = (SCIF_SAS_REMOTE_DEVICE_T*)
+ remote_device;
+ SCIF_SAS_IO_REQUEST_T * fw_io = (SCIF_SAS_IO_REQUEST_T*) io_request;
+ SCI_STATUS status;
+
+ status = fw_io->parent.state_handlers->start_handler(&fw_io->parent.parent);
+
+ if (status == SCI_SUCCESS)
+ {
+ fw_device->request_count++;
+ }
+
+ return status;
+}
+
+/**
+ * @brief This method provides OPERATIONAL sub-state specific handling for
+ * when a user attempts to start an IO request on a remote
+ * device.
+ *
+ * @param[in] remote_device This parameter specifies the remote device
+ * object on which the user is attempting to perform a complete
+ * IO operation.
+ * @param[in] io_request This parameter specifies the IO request to
+ * be completed.
+ *
+ * @return This method returns an indication as to whether the IO request
+ * completed successfully.
+ */
+SCI_STATUS scif_sas_remote_device_ready_operational_complete_io_handler(
+ SCI_BASE_REMOTE_DEVICE_T * remote_device,
+ SCI_BASE_REQUEST_T * io_request
+)
+{
+ SCIF_SAS_REMOTE_DEVICE_T * fw_device = (SCIF_SAS_REMOTE_DEVICE_T*)
+ remote_device;
+ fw_device->request_count--;
+ return SCI_SUCCESS;
+}
+
+
+/**
+ * @brief This method provides OPERATIONAL sub-state specific handling for
+ * when a user attempts to start an IO request on a remote
+ * device.
+ *
+ * @param[in] remote_device This parameter specifies the remote device
+ * object on which the user is attempting to perform a complete
+ * IO operation.
+ * @param[in] io_request This parameter specifies the IO request to
+ * be completed.
+ *
+ * @return This method returns an indication as to whether the IO request
+ * completed successfully.
+ */
+static
+SCI_STATUS scif_sas_remote_device_ready_operational_complete_high_priority_io_handler(
+ SCI_BASE_REMOTE_DEVICE_T * remote_device,
+ SCI_BASE_REQUEST_T * io_request,
+ void * response_data,
+ SCI_IO_STATUS completion_status
+)
+{
+ SCIF_LOG_WARNING((
+ sci_base_object_get_logger((SCIF_SAS_REMOTE_DEVICE_T *)remote_device),
+ SCIF_LOG_OBJECT_REMOTE_DEVICE,
+ "RemoteDevice:0x%x State:0x%x invalid state to complete high priority IO\n",
+ remote_device,
+ sci_base_state_machine_get_state(
+ &((SCIF_SAS_REMOTE_DEVICE_T *)remote_device)->parent.state_machine)
+ ));
+
+ return SCI_FAILURE_INVALID_STATE;
+}
+
+
+/**
+ * @brief This method provides OPERATIONAL sub-state specific handling for when
+ * the framework attempts to continue an IO request on a remote
+ * device.
+ *
+ * @param[in] remote_device This parameter specifies the remote device
+ * object on which the user is attempting to perform a continue
+ * IO operation.
+ * @param[in] io_request This parameter specifies the IO request to
+ * be continued.
+ *
+ * @return This method returns an indication as to whether the IO request
+ * completed successfully.
+ */
+static
+SCI_STATUS scif_sas_remote_device_ready_operational_continue_io_handler(
+ SCI_BASE_REMOTE_DEVICE_T * remote_device,
+ SCI_BASE_REQUEST_T * io_request
+)
+{
+ /// @todo Fix the return code handling.
+ return SCI_FAILURE;
+}
+
+/**
+ * @brief This method provides OPERATIONAL sub-state specific handling for
+ * when a user attempts to start a task management request on
+ * a remote device. This includes terminating all of the affected
+ * ongoing IO requests (i.e. aborting them in the silicon) and then
+ * issuing the task management request to the silicon.
+ *
+ * @param[in] remote_device This parameter specifies the remote device
+ * object on which the user is attempting to perform a start
+ * task operation.
+ * @param[in] task_request This parameter specifies the task management
+ * request to be started.
+ *
+ * @return This method returns an indication as to whether the task
+ * management request started successfully.
+ */
+static
+SCI_STATUS scif_sas_remote_device_ready_operational_start_task_handler(
+ SCI_BASE_REMOTE_DEVICE_T * remote_device,
+ SCI_BASE_REQUEST_T * task_request
+)
+{
+ SCI_STATUS status = SCI_FAILURE;
+ SCIF_SAS_REMOTE_DEVICE_T * fw_device = (SCIF_SAS_REMOTE_DEVICE_T*)
+ remote_device;
+ SCIF_SAS_TASK_REQUEST_T * fw_task = (SCIF_SAS_TASK_REQUEST_T*)
+ task_request;
+ U8 task_function =
+ scif_sas_task_request_get_function(fw_task);
+
+ SMP_DISCOVER_RESPONSE_PROTOCOLS_T dev_protocols;
+
+ scic_remote_device_get_protocols(fw_device->core_object, &dev_protocols);
+ if ( dev_protocols.u.bits.attached_ssp_target
+ || dev_protocols.u.bits.attached_stp_target)
+ {
+ // //NOTE: For STP/SATA targets we currently terminate all requests for
+ // any type of task management.
+ if ( (task_function == SCI_SAS_ABORT_TASK_SET)
+ || (task_function == SCI_SAS_CLEAR_TASK_SET)
+ || (task_function == SCI_SAS_LOGICAL_UNIT_RESET)
+ || (task_function == SCI_SAS_I_T_NEXUS_RESET)
+ || (task_function == SCI_SAS_HARD_RESET) )
+ {
+ // Terminate all of the requests in the silicon for this device.
+ scif_sas_domain_terminate_requests(
+ fw_device->domain, fw_device, NULL, fw_task
+ );
+
+ status = scif_sas_remote_device_start_task_request(fw_device, fw_task);
+ }
+ else if ( (task_function == SCI_SAS_CLEAR_ACA)
+ || (task_function == SCI_SAS_QUERY_TASK)
+ || (task_function == SCI_SAS_QUERY_TASK_SET)
+ || (task_function == SCI_SAS_QUERY_ASYNCHRONOUS_EVENT) )
+ {
+ ASSERT(!dev_protocols.u.bits.attached_stp_target);
+ status = scif_sas_remote_device_start_task_request(fw_device, fw_task);
+ }
+ else if (task_function == SCI_SAS_ABORT_TASK)
+ {
+ SCIF_SAS_REQUEST_T * fw_request
+ = scif_sas_domain_get_request_by_io_tag(
+ fw_device->domain, fw_task->io_tag_to_manage
+ );
+
+ // Determine if the request being aborted was found.
+ if (fw_request != NULL)
+ {
+ scif_sas_domain_terminate_requests(
+ fw_device->domain, fw_device, fw_request, fw_task
+ );
+
+ status = scif_sas_remote_device_start_task_request(
+ fw_device, fw_task
+ );
+ }
+ else
+ status = SCI_FAILURE_INVALID_IO_TAG;
+ }
+ }
+ else
+ status = SCI_FAILURE_UNSUPPORTED_PROTOCOL;
+
+ if (status != SCI_SUCCESS)
+ {
+ SCIF_LOG_ERROR((
+ sci_base_object_get_logger(fw_device),
+ SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_TASK_MANAGEMENT,
+ "Controller:0x%x TaskRequest:0x%x Status:0x%x start task failure\n",
+ fw_device, fw_task, status
+ ));
+ }
+
+ return status;
+}
+
+/**
+ * @brief This method provides OPERATIONAL sub-state specific handling for
+ * when a user attempts to complete a task management request on
+ * a remote device.
+ *
+ * @param[in] remote_device This parameter specifies the remote device object
+ * on which the user is attempting to perform a complete task
+ * operation.
+ * @param[in] task_request This parameter specifies the task management
+ * request to be completed.
+ *
+ * @return This method returns an indication as to whether the task
+ * management request succeeded.
+ */
+SCI_STATUS scif_sas_remote_device_ready_operational_complete_task_handler(
+ SCI_BASE_REMOTE_DEVICE_T * remote_device,
+ SCI_BASE_REQUEST_T * task_request
+)
+{
+ SCIF_SAS_REMOTE_DEVICE_T * fw_device = (SCIF_SAS_REMOTE_DEVICE_T*)
+ remote_device;
+ fw_device->request_count--;
+ fw_device->task_request_count--;
+
+ return SCI_SUCCESS;
+}
+
+/**
+ * @brief This method provides OPERATIONAL sub-state specific handling for
+ * when a user attempts to start a high priority IO request on a remote
+ * device.
+ *
+ * @param[in] remote_device This parameter specifies the remote device
+ * object on which the user is attempting to perform a start
+ * IO operation.
+ * @param[in] io_request This parameter specifies the IO request to be
+ * started.
+ *
+ * @return This method returns an indication as to whether the IO request
+ * started successfully.
+ */
+static
+SCI_STATUS scif_sas_remote_device_ready_operational_start_high_priority_io_handler(
+ SCI_BASE_REMOTE_DEVICE_T * remote_device,
+ SCI_BASE_REQUEST_T * io_request
+)
+{
+ SCIF_SAS_REMOTE_DEVICE_T * fw_device = (SCIF_SAS_REMOTE_DEVICE_T*)
+ remote_device;
+ SCIF_SAS_IO_REQUEST_T * fw_io = (SCIF_SAS_IO_REQUEST_T*) io_request;
+
+ SMP_DISCOVER_RESPONSE_PROTOCOLS_T dev_protocols;
+
+ scic_remote_device_get_protocols(fw_device->core_object, &dev_protocols);
+
+ if (dev_protocols.u.bits.attached_smp_target)
+ {
+ //transit to task management state for smp request phase.
+ if (fw_device->ready_substate_machine.current_state_id
+ != SCIF_SAS_REMOTE_DEVICE_READY_SUBSTATE_TASK_MGMT)
+ {
+ sci_base_state_machine_change_state(
+ &fw_device->ready_substate_machine,
+ SCIF_SAS_REMOTE_DEVICE_READY_SUBSTATE_TASK_MGMT
+ );
+ }
+ }
+
+ fw_device->request_count++;
+
+ return fw_io->parent.state_handlers->start_handler(&fw_io->parent.parent);
+}
+
+
+/**
+ * @brief This method provides TASK MANAGEMENT sub-state specific handling for
+ * when a user attempts to complete a task management request on
+ * a remote device.
+ *
+ * @param[in] remote_device This parameter specifies the remote device object
+ * on which the user is attempting to perform a complete task
+ * operation.
+ * @param[in] task_request This parameter specifies the task management
+ * request to be completed.
+ *
+ * @return This method returns an indication as to whether the task
+ * management request succeeded.
+ */
+SCI_STATUS scif_sas_remote_device_ready_task_management_complete_task_handler(
+ SCI_BASE_REMOTE_DEVICE_T * remote_device,
+ SCI_BASE_REQUEST_T * task_request
+)
+{
+ SCIF_SAS_REMOTE_DEVICE_T * fw_device = (SCIF_SAS_REMOTE_DEVICE_T*)
+ remote_device;
+
+ SCIF_SAS_TASK_REQUEST_T * fw_task = (SCIF_SAS_TASK_REQUEST_T *)
+ task_request;
+
+ fw_device->request_count--;
+ fw_device->task_request_count--;
+
+ // All existing task management requests and all of the IO requests
+ // affectected by the task management request must complete before
+ // the remote device can transition back into the READY / OPERATIONAL
+ // state.
+ if ( (fw_device->task_request_count == 0)
+ && (fw_task->affected_request_count == 0) )
+ {
+ sci_base_state_machine_change_state(
+ &fw_device->ready_substate_machine,
+ SCIF_SAS_REMOTE_DEVICE_READY_SUBSTATE_OPERATIONAL
+ );
+ }
+
+ return SCI_SUCCESS;
+}
+
+/**
+ * @brief This method provides SUSPENDED sub-state specific handling for
+ * when the core remote device object issues a device ready
+ * notification. This effectively causes the framework remote
+ * device to transition back into the OPERATIONAL state.
+ *
+ * @param[in] remote_device This parameter specifies the remote device
+ * object for which the notification occurred.
+ *
+ * @return none.
+ */
+static
+void scif_sas_remote_device_ready_suspended_ready_handler(
+ SCIF_SAS_REMOTE_DEVICE_T * fw_device
+)
+{
+ sci_base_state_machine_change_state(
+ &fw_device->ready_substate_machine,
+ SCIF_SAS_REMOTE_DEVICE_READY_SUBSTATE_OPERATIONAL
+ );
+}
+
+
+/**
+ * @brief This handler is currently solely used by smp remote device for
+ * discovering.
+ *
+ * @param[in] remote_device This parameter specifies the remote device
+ * object on which the user is attempting to perform a complete high
+ * priority IO operation.
+ * @param[in] io_request This parameter specifies the high priority IO request
+ * to be completed.
+ *
+ * @return SCI_STATUS indicate whether the io complete successfully.
+ */
+SCI_STATUS
+scif_sas_remote_device_ready_task_management_complete_high_priority_io_handler(
+ SCI_BASE_REMOTE_DEVICE_T * remote_device,
+ SCI_BASE_REQUEST_T * io_request,
+ void * response_data,
+ SCI_IO_STATUS completion_status
+)
+{
+ SCIF_SAS_REMOTE_DEVICE_T * fw_device = (SCIF_SAS_REMOTE_DEVICE_T*)
+ remote_device;
+ SCIF_SAS_REQUEST_T * fw_request = (SCIF_SAS_REQUEST_T*) io_request;
+ SCI_STATUS status = SCI_SUCCESS;
+ SCIC_TRANSPORT_PROTOCOL protocol;
+
+ SCIF_LOG_TRACE((
+ sci_base_object_get_logger(remote_device),
+ SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_IO_REQUEST,
+ "scif_sas_remote_device_ready_task_management_complete_high_priority_io_handler(0x%x, 0x%x, 0x%x, 0x%x) enter\n",
+ remote_device, io_request, response_data, completion_status
+ ));
+
+ fw_device->request_count--;
+
+ // we are back to ready operational sub state here.
+ sci_base_state_machine_change_state(
+ &fw_device->ready_substate_machine,
+ SCIF_SAS_REMOTE_DEVICE_READY_SUBSTATE_OPERATIONAL
+ );
+
+ protocol = scic_io_request_get_protocol(fw_request->core_object);
+
+ // If this request was an SMP initiator request we created, then
+ // decode the response.
+ if (protocol == SCIC_SMP_PROTOCOL)
+ {
+ if (completion_status != SCI_IO_FAILURE_TERMINATED)
+ {
+ status = scif_sas_smp_remote_device_decode_smp_response(
+ fw_device, fw_request, response_data, completion_status
+ );
+ }
+ else
+ scif_sas_smp_remote_device_terminated_request_handler(fw_device, fw_request);
+ }
+ else
+ {
+ // Currently, there are only internal SMP requests. So, default work
+ // is simply to clean up the internal request.
+ if (fw_request->is_internal == TRUE)
+ {
+ scif_sas_internal_io_request_complete(
+ fw_device->domain->controller,
+ (SCIF_SAS_INTERNAL_IO_REQUEST_T *)fw_request,
+ SCI_SUCCESS
+ );
+ }
+ }
+
+ return status;
+}
+
+
+SCIF_SAS_REMOTE_DEVICE_STATE_HANDLER_T
+scif_sas_remote_device_ready_substate_handler_table[] =
+{
+ // SCIF_SAS_REMOTE_DEVICE_READY_SUBSTATE_OPERATIONAL
+ {
+ {
+ scif_sas_remote_device_default_start_handler,
+ scif_sas_remote_device_ready_operational_stop_handler,
+ scif_sas_remote_device_ready_operational_fail_handler,
+ scif_sas_remote_device_ready_operational_destruct_handler,
+ scif_sas_remote_device_default_reset_handler,
+ scif_sas_remote_device_default_reset_complete_handler,
+ scif_sas_remote_device_ready_operational_start_io_handler,
+ scif_sas_remote_device_ready_operational_complete_io_handler,
+ scif_sas_remote_device_ready_operational_continue_io_handler,
+ scif_sas_remote_device_ready_operational_start_task_handler,
+ scif_sas_remote_device_ready_operational_complete_task_handler
+ },
+ scif_sas_remote_device_default_start_complete_handler,
+ scif_sas_remote_device_default_stop_complete_handler,
+ scif_sas_remote_device_default_ready_handler,
+ scif_sas_remote_device_ready_operational_not_ready_handler,
+ scif_sas_remote_device_ready_operational_start_high_priority_io_handler, //
+ scif_sas_remote_device_ready_operational_complete_high_priority_io_handler
+ },
+ // SCIF_SAS_REMOTE_DEVICE_READY_SUBSTATE_SUSPENDED
+ {
+ {
+ scif_sas_remote_device_default_start_handler,
+ scif_sas_remote_device_ready_operational_stop_handler,
+ scif_sas_remote_device_ready_operational_fail_handler,
+ scif_sas_remote_device_ready_operational_destruct_handler,
+ scif_sas_remote_device_default_reset_handler,
+ scif_sas_remote_device_default_reset_complete_handler,
+ scif_sas_remote_device_default_start_io_handler,
+ scif_sas_remote_device_ready_operational_complete_io_handler,
+ scif_sas_remote_device_default_continue_io_handler,
+ scif_sas_remote_device_ready_operational_start_task_handler,
+ scif_sas_remote_device_ready_operational_complete_task_handler
+ },
+ scif_sas_remote_device_default_start_complete_handler,
+ scif_sas_remote_device_default_stop_complete_handler,
+ scif_sas_remote_device_ready_suspended_ready_handler,
+ scif_sas_remote_device_default_not_ready_handler,
+ scif_sas_remote_device_default_start_io_handler,
+ scif_sas_remote_device_ready_operational_complete_high_priority_io_handler
+ },
+ // SCIF_SAS_REMOTE_DEVICE_READY_SUBSTATE_TASK_MGMT
+ {
+ {
+ scif_sas_remote_device_default_start_handler,
+ scif_sas_remote_device_ready_operational_stop_handler,
+ scif_sas_remote_device_ready_operational_fail_handler,
+ scif_sas_remote_device_ready_operational_destruct_handler,
+ scif_sas_remote_device_default_reset_handler,
+ scif_sas_remote_device_default_reset_complete_handler,
+ scif_sas_remote_device_default_start_io_handler,
+ scif_sas_remote_device_ready_operational_complete_io_handler,
+ scif_sas_remote_device_ready_operational_continue_io_handler,
+ scif_sas_remote_device_ready_operational_start_task_handler,
+ scif_sas_remote_device_ready_task_management_complete_task_handler
+ },
+ scif_sas_remote_device_default_start_complete_handler,
+ scif_sas_remote_device_default_stop_complete_handler,
+ scif_sas_remote_device_default_ready_handler,
+ scif_sas_remote_device_ready_task_management_not_ready_handler,
+ scif_sas_remote_device_ready_operational_start_high_priority_io_handler,
+ scif_sas_remote_device_ready_task_management_complete_high_priority_io_handler
+ },
+ // SCIF_SAS_REMOTE_DEVICE_READY_SUBSTATE_NCQ_ERROR
+ {
+ {
+ scif_sas_remote_device_default_start_handler,
+ scif_sas_remote_device_ready_operational_stop_handler,
+ scif_sas_remote_device_ready_operational_fail_handler,
+ scif_sas_remote_device_ready_operational_destruct_handler,
+ scif_sas_remote_device_default_reset_handler,
+ scif_sas_remote_device_default_reset_complete_handler,
+ scif_sas_remote_device_default_start_io_handler,
+ scif_sas_remote_device_ready_operational_complete_io_handler,
+ scif_sas_remote_device_default_continue_io_handler,
+ scif_sas_remote_device_ready_operational_start_task_handler,
+ scif_sas_remote_device_ready_operational_complete_task_handler
+ },
+ scif_sas_remote_device_default_start_complete_handler,
+ scif_sas_remote_device_default_stop_complete_handler,
+ scif_sas_remote_device_ready_suspended_ready_handler,
+ scif_sas_remote_device_default_not_ready_handler,
+ scif_sas_remote_device_default_start_io_handler,
+ scif_sas_remote_device_ready_operational_complete_high_priority_io_handler
+ },
+};
+
diff --git a/sys/dev/isci/scil/scif_sas_remote_device_ready_substates.c b/sys/dev/isci/scil/scif_sas_remote_device_ready_substates.c
new file mode 100644
index 0000000..2240be8
--- /dev/null
+++ b/sys/dev/isci/scil/scif_sas_remote_device_ready_substates.c
@@ -0,0 +1,290 @@
+/*-
+ * 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.
+ *
+ * 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 <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/**
+ * @file
+ *
+ * @brief This file contains the entrance and exit methods for the ready
+ * sub-state machine states (OPERATIONAL, TASK_MGMT).
+ */
+
+#include <dev/isci/scil/scif_sas_remote_device.h>
+#include <dev/isci/scil/scif_sas_domain.h>
+#include <dev/isci/scil/scif_sas_logger.h>
+#include <dev/isci/scil/scif_sas_internal_io_request.h>
+#include <dev/isci/scil/scif_sas_controller.h>
+#include <dev/isci/scil/sci_controller.h>
+
+//******************************************************************************
+//* P R O T E C T E D M E T H O D S
+//******************************************************************************
+
+/**
+ * @brief This method implements the actions taken when entering the
+ * READY OPERATIONAL substate. This includes setting the state
+ * handler methods and issuing a scif_cb_remote_device_ready()
+ * notification to the user.
+ *
+ * @param[in] object This parameter specifies the base object for which
+ * the state transition is occurring. This is cast into a
+ * SCIF_SAS_REMOTE_DEVICE object in the method implementation.
+ *
+ * @return none
+ */
+static
+void scif_sas_remote_device_ready_operational_substate_enter(
+ SCI_BASE_OBJECT_T *object
+)
+{
+ SCIF_SAS_REMOTE_DEVICE_T * fw_device = (SCIF_SAS_REMOTE_DEVICE_T *)object;
+
+ SET_STATE_HANDLER(
+ fw_device,
+ scif_sas_remote_device_ready_substate_handler_table,
+ SCIF_SAS_REMOTE_DEVICE_READY_SUBSTATE_OPERATIONAL
+ );
+
+ SCIF_LOG_INFO((
+ sci_base_object_get_logger(fw_device),
+ SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_REMOTE_DEVICE_CONFIG,
+ "Domain:0x%x Device:0x%x device ready\n",
+ fw_device->domain, fw_device
+ ));
+
+ // Notify the user that the device has become ready.
+ scif_cb_remote_device_ready(
+ fw_device->domain->controller, fw_device->domain, fw_device
+ );
+}
+
+/**
+ * @brief This method implements the actions taken when exiting the
+ * READY OPERATIONAL substate. This method issues a
+ * scif_cb_remote_device_not_ready() notification to the framework
+ * user.
+ *
+ * @param[in] object This parameter specifies the base object for which
+ * the state transition is occurring. This is cast into a
+ * SCIF_SAS_REMOTE_DEVICE object in the method implementation.
+ *
+ * @return none
+ */
+static
+void scif_sas_remote_device_ready_operational_substate_exit(
+ SCI_BASE_OBJECT_T *object
+)
+{
+ SCIF_SAS_REMOTE_DEVICE_T * fw_device = (SCIF_SAS_REMOTE_DEVICE_T *)object;
+
+ // Notify the user that the device has become ready.
+ scif_cb_remote_device_not_ready(
+ fw_device->domain->controller, fw_device->domain, fw_device
+ );
+}
+
+/**
+ * @brief This method implements the actions taken when entering the
+ * READY SUSPENDED substate. This includes setting the state
+ * handler methods.
+ *
+ * @param[in] object This parameter specifies the base object for which
+ * the state transition is occurring. This is cast into a
+ * SCIF_SAS_REMOTE_DEVICE object in the method implementation.
+ *
+ * @return none
+ */
+static
+void scif_sas_remote_device_ready_suspended_substate_enter(
+ SCI_BASE_OBJECT_T *object
+)
+{
+ SCIF_SAS_REMOTE_DEVICE_T * fw_device = (SCIF_SAS_REMOTE_DEVICE_T *)object;
+
+ SET_STATE_HANDLER(
+ fw_device,
+ scif_sas_remote_device_ready_substate_handler_table,
+ SCIF_SAS_REMOTE_DEVICE_READY_SUBSTATE_SUSPENDED
+ );
+}
+
+/**
+ * @brief This method implements the actions taken when entering the
+ * READY TASK MGMT substate. This includes setting the state
+ * handler methods.
+ *
+ * @param[in] object This parameter specifies the base object for which
+ * the state transition is occurring. This is cast into a
+ * SCIF_SAS_REMOTE_DEVICE object in the method implementation.
+ *
+ * @return none
+ */
+static
+void scif_sas_remote_device_ready_taskmgmt_substate_enter(
+ SCI_BASE_OBJECT_T *object
+)
+{
+ SCIF_SAS_REMOTE_DEVICE_T * fw_device = (SCIF_SAS_REMOTE_DEVICE_T *)object;
+
+ SET_STATE_HANDLER(
+ fw_device,
+ scif_sas_remote_device_ready_substate_handler_table,
+ SCIF_SAS_REMOTE_DEVICE_READY_SUBSTATE_TASK_MGMT
+ );
+}
+
+/**
+* @brief This method implements the actions taken when entering the
+* READY NCQ ERROR substate. This includes setting the state
+* handler methods.
+*
+* @param[in] object This parameter specifies the base object for which
+* the state transition is occurring. This is cast into a
+* SCIF_SAS_REMOTE_DEVICE object in the method implementation.
+*
+* @return none
+*/
+static
+void scif_sas_remote_device_ready_ncq_error_substate_enter(
+ SCI_BASE_OBJECT_T *object
+)
+{
+ SCIF_SAS_REMOTE_DEVICE_T * fw_device = (SCIF_SAS_REMOTE_DEVICE_T *)object;
+ SCI_STATUS status = SCI_SUCCESS;
+ SCI_TASK_REQUEST_HANDLE_T handle;
+ SCIF_SAS_CONTROLLER_T * fw_controller = fw_device->domain->controller;
+ SCIF_SAS_TASK_REQUEST_T * fw_task_request;
+ SCIF_SAS_REQUEST_T * fw_request;
+ void * internal_task_memory;
+ SCIF_SAS_DOMAIN_T * fw_domain = fw_device->domain;
+ SCI_FAST_LIST_ELEMENT_T * pending_request_element;
+ SCIF_SAS_REQUEST_T * pending_request = NULL;
+
+ SET_STATE_HANDLER(
+ fw_device,
+ scif_sas_remote_device_ready_substate_handler_table,
+ SCIF_SAS_REMOTE_DEVICE_READY_SUBSTATE_NCQ_ERROR
+ );
+
+ internal_task_memory = scif_sas_controller_allocate_internal_request(fw_controller);
+ ASSERT(internal_task_memory != NULL);
+
+ fw_task_request = (SCIF_SAS_TASK_REQUEST_T*)internal_task_memory;
+
+ fw_request = &fw_task_request->parent;
+
+ //construct the scif io request
+ status = scif_sas_internal_task_request_construct(
+ fw_controller,
+ fw_device,
+ SCI_CONTROLLER_INVALID_IO_TAG,
+ (void *)fw_task_request,
+ &handle,
+ SCI_SAS_ABORT_TASK_SET
+ );
+
+ pending_request_element = fw_domain->request_list.list_head;
+
+ // Cycle through the fast list of IO requests. Mark each request
+ // pending to this remote device so that they are not completed
+ // to the operating system when the request is terminated, but
+ // rather when the abort task set completes.
+ while (pending_request_element != NULL)
+ {
+ pending_request =
+ (SCIF_SAS_REQUEST_T*) sci_fast_list_get_object(pending_request_element);
+
+ // The current element may be deleted from the list becasue of
+ // IO completion so advance to the next element early
+ pending_request_element = sci_fast_list_get_next(pending_request_element);
+
+ if (pending_request->device == fw_device)
+ {
+ pending_request->is_waiting_for_abort_task_set = TRUE;
+ }
+ }
+
+ status = scif_controller_start_task(
+ fw_controller,
+ fw_device,
+ fw_request,
+ SCI_CONTROLLER_INVALID_IO_TAG
+ );
+}
+
+SCI_BASE_STATE_T scif_sas_remote_device_ready_substate_table
+[SCIF_SAS_REMOTE_DEVICE_READY_SUBSTATE_MAX_STATES] =
+{
+ {
+ SCIF_SAS_REMOTE_DEVICE_READY_SUBSTATE_OPERATIONAL,
+ scif_sas_remote_device_ready_operational_substate_enter,
+ scif_sas_remote_device_ready_operational_substate_exit
+ },
+ {
+ SCIF_SAS_REMOTE_DEVICE_READY_SUBSTATE_SUSPENDED,
+ scif_sas_remote_device_ready_suspended_substate_enter,
+ NULL
+ },
+ {
+ SCIF_SAS_REMOTE_DEVICE_READY_SUBSTATE_TASK_MGMT,
+ scif_sas_remote_device_ready_taskmgmt_substate_enter,
+ NULL
+ },
+ {
+ SCIF_SAS_REMOTE_DEVICE_READY_SUBSTATE_NCQ_ERROR,
+ scif_sas_remote_device_ready_ncq_error_substate_enter,
+ NULL
+ }
+};
+
diff --git a/sys/dev/isci/scil/scif_sas_remote_device_starting_substate_handlers.c b/sys/dev/isci/scil/scif_sas_remote_device_starting_substate_handlers.c
new file mode 100644
index 0000000..ec06125
--- /dev/null
+++ b/sys/dev/isci/scil/scif_sas_remote_device_starting_substate_handlers.c
@@ -0,0 +1,317 @@
+/*-
+ * 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.
+ *
+ * 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 <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/**
+ * @file
+ *
+ * @brief This file contains all of the method implementations pertaining
+ * to the framework remote device STARTING sub-state handler methods.
+ * The STARTING sub-state machine is responsible for ensuring that
+ * all initialization and configuration for a particular remote
+ * device is complete before transitioning to the READY state
+ * (i.e. before allowing normal host IO).
+ */
+
+#include <dev/isci/scil/scic_remote_device.h>
+
+#include <dev/isci/scil/scif_sas_logger.h>
+#include <dev/isci/scil/scif_sas_remote_device.h>
+#include <dev/isci/scil/scif_sas_domain.h>
+#include <dev/isci/scil/scif_sas_task_request.h>
+
+//******************************************************************************
+//* G E N E R A L S T O P H A N D L E R S
+//******************************************************************************
+
+/**
+ * @brief This method provides startig sub-state specific handling for
+ * when the remote device is requested to stop. This will occur
+ * when there is a link failure during the starting operation.
+ *
+ * @param[in] remote_device This parameter specifies the remote device
+ * object for which the failure condition occurred.
+ *
+ * @return This method returns an indication as to whether the failure
+ * operation completed successfully.
+ */
+static
+SCI_STATUS
+scif_sas_remote_device_starting_state_general_stop_handler(
+ SCI_BASE_REMOTE_DEVICE_T * remote_device
+)
+{
+ SCIF_SAS_REMOTE_DEVICE_T * fw_device = (SCIF_SAS_REMOTE_DEVICE_T *)
+ remote_device;
+
+ SCIF_LOG_INFO((
+ sci_base_object_get_logger(fw_device),
+ SCIF_LOG_OBJECT_REMOTE_DEVICE,
+ "RemoteDevice:0x%x starting device requested to stop\n",
+ fw_device
+ ));
+
+ fw_device->domain->device_start_in_progress_count--;
+
+ sci_base_state_machine_change_state(
+ &fw_device->parent.state_machine, SCI_BASE_REMOTE_DEVICE_STATE_STOPPING
+ );
+
+ return SCI_SUCCESS;
+}
+
+//******************************************************************************
+//* A W A I T C O M P L E T E H A N D L E R S
+//******************************************************************************
+
+/**
+ * @brief This method provides AWAIT START COMPLETE sub-state specific
+ * handling for when the remote device undergoes a failure
+ * condition.
+ *
+ * @param[in] remote_device This parameter specifies the remote device
+ * object for which the failure condition occurred.
+ *
+ * @return This method returns an indication as to whether the failure
+ * operation completed successfully.
+ */
+static
+SCI_STATUS scif_sas_remote_device_starting_await_complete_fail_handler(
+ SCI_BASE_REMOTE_DEVICE_T * remote_device
+)
+{
+ SCIF_SAS_REMOTE_DEVICE_T * fw_device = (SCIF_SAS_REMOTE_DEVICE_T *)
+ remote_device;
+
+ SCIF_LOG_WARNING((
+ sci_base_object_get_logger(fw_device),
+ SCIF_LOG_OBJECT_REMOTE_DEVICE,
+ "RemoteDevice:0x%x starting device failed, start complete not received\n",
+ fw_device
+ ));
+
+ sci_base_state_machine_change_state(
+ &fw_device->parent.state_machine, SCI_BASE_REMOTE_DEVICE_STATE_FAILED
+ );
+
+ return SCI_SUCCESS;
+}
+
+/**
+ * @brief This method provides AWAIT COMPLETE state specific handling for
+ * when the core remote device object issues a device not ready
+ * notification. In the AWAIT COMPLETE state we do not inform
+ * the framework user of the state change of the device, since the
+ * user is unaware of the remote device start process.
+ *
+ * @param[in] remote_device This parameter specifies the remote device
+ * object for which the notification occurred.
+ *
+ * @return none.
+ */
+static
+void scif_sas_remote_device_starting_await_complete_not_ready_handler(
+ SCIF_SAS_REMOTE_DEVICE_T * fw_device,
+ U32 reason_code
+)
+{
+}
+
+/**
+ * @brief This method provides AWAIT START COMPLETE sub-state specific
+ * handling for when the core provides a start complete notification
+ * for the remote device. If the start completion status indicates
+ * a successful start, then the device is transitioned into the
+ * READY state. All other status cause a transition to the
+ * FAILED state and a scif_cb_controller_error() notification
+ * message to the framework user.
+ *
+ * @param[in] fw_device This parameter specifies the remote device
+ * object for which the notification has occurred.
+ *
+ * @return none.
+ */
+static
+void scif_sas_remote_device_starting_await_complete_start_complete_handler(
+ SCIF_SAS_REMOTE_DEVICE_T * fw_device,
+ SCI_STATUS completion_status
+)
+{
+ if (completion_status == SCI_SUCCESS)
+ {
+ /** @todo need to add support for resetting the device first. This can
+ wait until 1.3. */
+ /** @todo Update to comprehend situations (i.e. SATA) where config is
+ needed. */
+
+ sci_base_state_machine_change_state(
+ &fw_device->starting_substate_machine,
+ SCIF_SAS_REMOTE_DEVICE_STARTING_SUBSTATE_AWAIT_READY
+ );
+ }
+ else
+ {
+ SCIF_LOG_WARNING((
+ sci_base_object_get_logger(fw_device),
+ SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_REMOTE_DEVICE_CONFIG,
+ "Device:0x%x Status:0x%x failed to start core device\n",
+ fw_device
+ ));
+
+ sci_base_state_machine_change_state(
+ &fw_device->parent.state_machine,
+ SCI_BASE_REMOTE_DEVICE_STATE_FAILED
+ );
+
+ // Something is seriously wrong. Starting the core remote device
+ // shouldn't fail in anyway in this state.
+ scif_cb_controller_error(fw_device->domain->controller,
+ SCI_CONTROLLER_REMOTE_DEVICE_ERROR);
+ }
+}
+
+//******************************************************************************
+//* C O M P L E T E H A N D L E R S
+//******************************************************************************
+
+/**
+ * @brief This method provides STARTING AWAIT READY sub-state specific
+ * handling for when the core provides a device ready notification
+ * for the remote device. This essentially, causes a transition
+ * of the framework remote device into the READY state.
+ *
+ * @param[in] fw_device This parameter specifies the remote device
+ * object for which the notification has occurred.
+ *
+ * @return none.
+ */
+static
+void scif_sas_remote_device_starting_await_ready_ready_handler(
+ SCIF_SAS_REMOTE_DEVICE_T * fw_device
+)
+{
+#if !defined(DISABLE_WIDE_PORTED_TARGETS)
+ if (fw_device->destination_state ==
+ SCIF_SAS_REMOTE_DEVICE_DESTINATION_STATE_UPDATING_PORT_WIDTH)
+ {
+ {
+ sci_base_state_machine_change_state(
+ &fw_device->parent.state_machine,
+ SCI_BASE_REMOTE_DEVICE_STATE_UPDATING_PORT_WIDTH
+ );
+ }
+ }
+ else
+#endif
+ {
+ sci_base_state_machine_change_state(
+ &fw_device->parent.state_machine, SCI_BASE_REMOTE_DEVICE_STATE_READY
+ );
+ }
+
+#if !defined(DISABLE_WIDE_PORTED_TARGETS)
+ scif_sas_domain_remote_device_start_complete(fw_device->domain,fw_device);
+#endif
+}
+
+
+SCIF_SAS_REMOTE_DEVICE_STATE_HANDLER_T
+scif_sas_remote_device_starting_substate_handler_table[] =
+{
+ // SCIF_SAS_REMOTE_DEVICE_STARTING_SUBSTATE_AWAIT_COMPLETE
+ {
+ {
+ scif_sas_remote_device_default_start_handler,
+ scif_sas_remote_device_starting_state_general_stop_handler,
+ scif_sas_remote_device_starting_await_complete_fail_handler,
+ scif_sas_remote_device_default_destruct_handler,
+ scif_sas_remote_device_default_reset_handler,
+ scif_sas_remote_device_default_reset_complete_handler,
+ scif_sas_remote_device_default_start_io_handler,
+ scif_sas_remote_device_default_complete_io_handler,
+ scif_sas_remote_device_default_continue_io_handler,
+ scif_sas_remote_device_default_start_task_handler,
+ scif_sas_remote_device_default_complete_task_handler
+ },
+ scif_sas_remote_device_starting_await_complete_start_complete_handler,
+ scif_sas_remote_device_default_stop_complete_handler,
+ scif_sas_remote_device_default_ready_handler,
+ scif_sas_remote_device_starting_await_complete_not_ready_handler,
+ scif_sas_remote_device_default_start_io_handler,
+ scif_sas_remote_device_default_complete_high_priority_io_handler
+ },
+ // SCIF_SAS_REMOTE_DEVICE_STARTING_SUBSTATE_AWAIT_READY
+ {
+ {
+ scif_sas_remote_device_default_start_handler,
+ scif_sas_remote_device_starting_state_general_stop_handler,
+ scif_sas_remote_device_starting_await_complete_fail_handler,
+ scif_sas_remote_device_default_destruct_handler,
+ scif_sas_remote_device_default_reset_handler,
+ scif_sas_remote_device_default_reset_complete_handler,
+ scif_sas_remote_device_default_start_io_handler,
+ scif_sas_remote_device_default_complete_io_handler,
+ scif_sas_remote_device_default_continue_io_handler,
+ scif_sas_remote_device_default_start_task_handler,
+ scif_sas_remote_device_default_complete_task_handler
+ },
+ scif_sas_remote_device_default_start_complete_handler,
+ scif_sas_remote_device_default_stop_complete_handler,
+ scif_sas_remote_device_starting_await_ready_ready_handler,
+ scif_sas_remote_device_default_not_ready_handler,
+ scif_sas_remote_device_default_start_io_handler,
+ scif_sas_remote_device_default_complete_high_priority_io_handler
+ }
+};
+
diff --git a/sys/dev/isci/scil/scif_sas_remote_device_starting_substates.c b/sys/dev/isci/scil/scif_sas_remote_device_starting_substates.c
new file mode 100644
index 0000000..4639fd3
--- /dev/null
+++ b/sys/dev/isci/scil/scif_sas_remote_device_starting_substates.c
@@ -0,0 +1,143 @@
+/*-
+ * 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.
+ *
+ * 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 <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/**
+ * @file
+ *
+ * @brief This file contains the entrance and exit methods for the starting
+ * sub-state machine states (AWAIT COMPELTE). The starting sub-state
+ * machine manages the steps necessary to initialize and configure
+ * a remote device.
+ */
+
+#include <dev/isci/scil/scif_sas_remote_device.h>
+#include <dev/isci/scil/scif_sas_domain.h>
+#include <dev/isci/scil/scif_sas_logger.h>
+
+
+//******************************************************************************
+//* P R O T E C T E D M E T H O D S
+//******************************************************************************
+
+/**
+ * @brief This method implements the actions taken when entering the
+ * STARTING AWAIT COMPLETE substate. This includes setting the
+ * state handler methods.
+ *
+ * @param[in] object This parameter specifies the base object for which
+ * the state transition is occurring. This is cast into a
+ * SCIF_SAS_REMOTE_DEVICE object in the method implementation.
+ *
+ * @return none
+ */
+static
+void scif_sas_remote_device_starting_await_complete_substate_enter(
+ SCI_BASE_OBJECT_T *object
+)
+{
+ SCIF_SAS_REMOTE_DEVICE_T * fw_device = (SCIF_SAS_REMOTE_DEVICE_T *)object;
+
+ SET_STATE_HANDLER(
+ fw_device,
+ scif_sas_remote_device_starting_substate_handler_table,
+ SCIF_SAS_REMOTE_DEVICE_STARTING_SUBSTATE_AWAIT_COMPLETE
+ );
+
+ fw_device->domain->device_start_in_progress_count++;
+ fw_device->domain->device_start_count++;
+}
+
+/**
+ * @brief This method implements the actions taken when entering the
+ * STARTING COMPLETE substate. This includes setting the
+ * state handler methods.
+ *
+ * @param[in] object This parameter specifies the base object for which
+ * the state transition is occurring. This is cast into a
+ * SCIF_SAS_REMOTE_DEVICE object in the method implementation.
+ *
+ * @return none
+ */
+static
+void scif_sas_remote_device_starting_complete_substate_enter(
+ SCI_BASE_OBJECT_T *object
+)
+{
+ SCIF_SAS_REMOTE_DEVICE_T * fw_device = (SCIF_SAS_REMOTE_DEVICE_T *)object;
+
+ SET_STATE_HANDLER(
+ fw_device,
+ scif_sas_remote_device_starting_substate_handler_table,
+ SCIF_SAS_REMOTE_DEVICE_STARTING_SUBSTATE_AWAIT_READY
+ );
+}
+
+
+SCI_BASE_STATE_T
+scif_sas_remote_device_starting_substate_table
+[SCIF_SAS_REMOTE_DEVICE_STARTING_SUBSTATE_MAX_STATES] =
+{
+ {
+ SCIF_SAS_REMOTE_DEVICE_STARTING_SUBSTATE_AWAIT_COMPLETE,
+ scif_sas_remote_device_starting_await_complete_substate_enter,
+ NULL
+ },
+ {
+ SCIF_SAS_REMOTE_DEVICE_STARTING_SUBSTATE_AWAIT_READY,
+ scif_sas_remote_device_starting_complete_substate_enter,
+ NULL
+ }
+};
+
diff --git a/sys/dev/isci/scil/scif_sas_remote_device_state_handlers.c b/sys/dev/isci/scil/scif_sas_remote_device_state_handlers.c
new file mode 100644
index 0000000..2a3b9bd
--- /dev/null
+++ b/sys/dev/isci/scil/scif_sas_remote_device_state_handlers.c
@@ -0,0 +1,1161 @@
+/*-
+ * 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.
+ *
+ * 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 <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/**
+ * @file
+ *
+ * @brief This file contains all of the method implementations pertaining
+ * to the framework remote device state handler methods.
+ */
+
+#include <dev/isci/scil/scic_remote_device.h>
+
+#include <dev/isci/scil/scif_sas_logger.h>
+#include <dev/isci/scil/scif_sas_remote_device.h>
+#include <dev/isci/scil/scif_sas_domain.h>
+#include <dev/isci/scil/scif_sas_task_request.h>
+#include <dev/isci/scil/scif_sas_internal_io_request.h>
+
+//******************************************************************************
+//* S T O P P E D H A N D L E R S
+//******************************************************************************
+
+/**
+ * @brief This method provides STOPPED state specific handling for
+ * when the framework attempts to start the remote device. This
+ * method attempts to transition the state machine into the
+ * STARTING state. If this is unsuccessful, then there is a direct
+ * transition into the FAILED state.
+ *
+ * @param[in] remote_device This parameter specifies the remote device
+ * object for which the framework is attempting to start.
+ *
+ * @return This method returns an indication as to whether the start
+ * operating began successfully.
+ */
+static
+SCI_STATUS scif_sas_remote_device_stopped_start_handler(
+ SCI_BASE_REMOTE_DEVICE_T * remote_device
+)
+{
+ SCIF_SAS_REMOTE_DEVICE_T * fw_device = (SCIF_SAS_REMOTE_DEVICE_T *)
+ remote_device;
+
+ sci_base_state_machine_change_state(
+ &fw_device->parent.state_machine, SCI_BASE_REMOTE_DEVICE_STATE_STARTING
+ );
+
+ // Check to see if the state transition occurred without issue.
+ if (sci_base_state_machine_get_state(&fw_device->parent.state_machine)
+ == SCI_BASE_REMOTE_DEVICE_STATE_FAILED)
+ {
+ SCIF_LOG_WARNING((
+ sci_base_object_get_logger(fw_device),
+ SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
+ "Domain:0x%x Device:0x%x Status:0x%x failed to start\n",
+ fw_device->domain, fw_device, fw_device->operation_status
+ ));
+ }
+
+ return fw_device->operation_status;
+}
+
+/**
+ * @brief This method provides STOPPED state specific handling for
+ * when the user attempts to destruct the remote device.
+ *
+ * @param[in] remote_device This parameter specifies the remote device
+ * object for which the framework is attempting to start.
+ *
+ * @return This method returns an indication as to whether the destruct
+ * operation completed successfully.
+ */
+static
+SCI_STATUS scif_sas_remote_device_stopped_destruct_handler(
+ SCI_BASE_REMOTE_DEVICE_T * remote_device
+)
+{
+ SCI_STATUS status;
+ SCIF_SAS_REMOTE_DEVICE_T * fw_device = (SCIF_SAS_REMOTE_DEVICE_T *)
+ remote_device;
+
+ SMP_DISCOVER_RESPONSE_PROTOCOLS_T dev_protocols;
+ scic_remote_device_get_protocols(fw_device->core_object, &dev_protocols);
+
+ //For smp device, need to clear its smp phy list first.
+ if(dev_protocols.u.bits.attached_smp_target)
+ scif_sas_smp_remote_device_removed(fw_device);
+
+ status = scic_remote_device_destruct(fw_device->core_object);
+ if (status == SCI_SUCCESS)
+ {
+ sci_base_state_machine_change_state(
+ &fw_device->parent.state_machine, SCI_BASE_REMOTE_DEVICE_STATE_FINAL
+ );
+
+ scif_sas_remote_device_deinitialize_state_logging(fw_device);
+ }
+ else
+ {
+ SCIF_LOG_ERROR((
+ sci_base_object_get_logger(fw_device),
+ SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_REMOTE_DEVICE_CONFIG,
+ "Device:0x%x Status:0x%x failed to destruct core device\n",
+ fw_device
+ ));
+ }
+
+ return status;
+}
+
+//******************************************************************************
+//* S T O P P I N G H A N D L E R S
+//******************************************************************************
+
+/**
+ * @brief This method provides STOPPING state specific handling for
+ * when the core remote device object issues a stop completion
+ * notification.
+ *
+ * @note There is no need to ensure all IO/Task requests are complete
+ * before transitioning to the STOPPED state. The SCI Core will
+ * ensure this is accomplished.
+ *
+ * @param[in] remote_device This parameter specifies the remote device
+ * object for which the completion occurred.
+ * @param[in] completion_status This parameter specifies the status
+ * of the completion operation.
+ *
+ * @return none.
+ */
+static
+void scif_sas_remote_device_stopping_stop_complete_handler(
+ SCIF_SAS_REMOTE_DEVICE_T * fw_device,
+ SCI_STATUS completion_status
+)
+{
+ // Transition directly to the STOPPED state since the core ensures
+ // all IO/Tasks are complete.
+ sci_base_state_machine_change_state(
+ &fw_device->parent.state_machine,
+ SCI_BASE_REMOTE_DEVICE_STATE_STOPPED
+ );
+
+ if (completion_status != SCI_SUCCESS)
+ {
+ SCIF_LOG_ERROR((
+ sci_base_object_get_logger(fw_device),
+ SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_REMOTE_DEVICE_CONFIG,
+ "Device:0x%x Status:0x%x failed to stop core device\n",
+ fw_device, completion_status
+ ));
+
+ // Something is seriously wrong. Stopping the core remote device
+ // shouldn't fail in anyway.
+ scif_cb_controller_error(fw_device->domain->controller,
+ SCI_CONTROLLER_REMOTE_DEVICE_ERROR);
+ }
+}
+
+/**
+ * @brief This method provides STOPPING state handling for high priority
+ * IO requests, when the framework attempts to complete a high
+ * priority request.
+ *
+ * @param[in] remote_device This parameter specifies the remote device
+ * object for which to complete the high priority IO.
+ * @param[in] io_request This parameter specifies the IO request to be
+ * completed.
+ * @param[in] response_data This parameter is ignored, since the device
+ * is in the stopping state.
+ *
+ * @return This method always returns success.
+ */
+static
+SCI_STATUS scif_sas_remote_device_stopping_complete_high_priority_io_handler(
+ SCI_BASE_REMOTE_DEVICE_T * remote_device,
+ SCI_BASE_REQUEST_T * io_request,
+ void * response_data,
+ SCI_IO_STATUS completion_status
+)
+{
+ SCIF_SAS_REMOTE_DEVICE_T * fw_device = (SCIF_SAS_REMOTE_DEVICE_T *)
+ remote_device;
+ SCIF_SAS_REQUEST_T * fw_request = (SCIF_SAS_REQUEST_T *) io_request;
+
+ SCIF_LOG_TRACE((
+ sci_base_object_get_logger(remote_device),
+ SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_IO_REQUEST,
+ "scif_sas_remote_device_stopping_complete_high_priority_io_handler(0x%x,0x%x,0x%x) enter\n",
+ remote_device, io_request, response_data
+ ));
+
+ fw_device->request_count--;
+
+ if (fw_request->is_internal == TRUE)
+ {
+ scif_sas_internal_io_request_complete(
+ fw_device->domain->controller,
+ (SCIF_SAS_INTERNAL_IO_REQUEST_T *) io_request,
+ SCI_SUCCESS
+ );
+ }
+
+ return SCI_SUCCESS;
+}
+
+//******************************************************************************
+//* F A I L E D H A N D L E R S
+//******************************************************************************
+
+/**
+ * @brief This method provides FAILED state specific handling for
+ * when the remote device is being stopped by the framework.
+ *
+ * @param[in] remote_device This parameter specifies the remote device
+ * object for which the stop operation is being requested.
+ *
+ * @return This method returns an indication as to whether the failure
+ * operation completed successfully.
+ */
+static
+SCI_STATUS scif_sas_remote_device_failed_stop_handler(
+ SCI_BASE_REMOTE_DEVICE_T * remote_device
+)
+{
+ SCIF_SAS_REMOTE_DEVICE_T * fw_device = (SCIF_SAS_REMOTE_DEVICE_T *)
+ remote_device;
+
+ SCIF_LOG_WARNING((
+ sci_base_object_get_logger(fw_device),
+ SCIF_LOG_OBJECT_REMOTE_DEVICE,
+ "RemoteDevice:0x%x stopping failed device\n",
+ fw_device
+ ));
+
+ sci_base_state_machine_change_state(
+ &fw_device->parent.state_machine, SCI_BASE_REMOTE_DEVICE_STATE_STOPPING
+ );
+
+ /// @todo Fix the return code handling.
+ return SCI_FAILURE;
+}
+
+//******************************************************************************
+//* D E F A U L T H A N D L E R S
+//******************************************************************************
+
+/**
+ * @brief This method provides default handling (i.e. returns an error);
+ * when a user attempts to start a remote device and a start operation
+ * is not allowed.
+ *
+ * @param[in] remote_device This parameter specifies the remote device object
+ * on which the user is attempting to perform a start operation.
+ *
+ * @return This method returns an indication that start operations are not
+ * allowed.
+ * @retval SCI_FAILURE_INVALID_STATE This value is always returned.
+ */
+SCI_STATUS scif_sas_remote_device_default_start_handler(
+ SCI_BASE_REMOTE_DEVICE_T * remote_device
+)
+{
+ SCIF_LOG_WARNING((
+ sci_base_object_get_logger((SCIF_SAS_REMOTE_DEVICE_T *)remote_device),
+ SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_REMOTE_DEVICE_CONFIG,
+ "RemoteDevice:0x%x State:0x%x invalid state to start\n",
+ remote_device,
+ sci_base_state_machine_get_state(
+ &((SCIF_SAS_REMOTE_DEVICE_T *)remote_device)->parent.state_machine)
+ ));
+
+ return SCI_FAILURE_INVALID_STATE;
+}
+
+/**
+ * @brief This method provides default handling (i.e. returns an error);
+ * when a user attempts to stop a remote device and a stop operation
+ * is not allowed.
+ *
+ * @param[in] remote_device This parameter specifies the remote device object
+ * on which the user is attempting to perform a stop operation.
+ *
+ * @return This method returns an indication that stop operations are not
+ * allowed.
+ * @retval SCI_FAILURE_INVALID_STATE This value is always returned.
+ */
+SCI_STATUS scif_sas_remote_device_default_stop_handler(
+ SCI_BASE_REMOTE_DEVICE_T * remote_device
+)
+{
+ SCIF_LOG_WARNING((
+ sci_base_object_get_logger((SCIF_SAS_REMOTE_DEVICE_T *)remote_device),
+ SCIF_LOG_OBJECT_REMOTE_DEVICE,
+ "RemoteDevice:0x%x State:0x%x invalid state to stop\n",
+ remote_device,
+ sci_base_state_machine_get_state(
+ &((SCIF_SAS_REMOTE_DEVICE_T *)remote_device)->parent.state_machine)
+ ));
+
+ return SCI_FAILURE_INVALID_STATE;
+}
+
+/**
+ * @brief This method provides default handling (i.e. returns an error);
+ * when there is an attempt to fail a remote device from an invalid
+ * state.
+ *
+ * @param[in] remote_device This parameter specifies the remote device
+ * object on which there is an attempt to fail the device.
+ *
+ * @return This method returns an indication that the fail transition is not
+ * allowed.
+ * @retval SCI_FAILURE_INVALID_STATE This value is always returned.
+ */
+static
+SCI_STATUS scif_sas_remote_device_default_fail_handler(
+ SCI_BASE_REMOTE_DEVICE_T * remote_device
+)
+{
+ SCIF_LOG_WARNING((
+ sci_base_object_get_logger((SCIF_SAS_REMOTE_DEVICE_T *)remote_device),
+ SCIF_LOG_OBJECT_REMOTE_DEVICE,
+ "RemoteDevice:0x%x State:0x%x invalid state to fail device\n",
+ remote_device,
+ sci_base_state_machine_get_state(
+ &((SCIF_SAS_REMOTE_DEVICE_T *)remote_device)->parent.state_machine)
+ ));
+
+ return SCI_FAILURE_INVALID_STATE;
+}
+
+/**
+ * @brief This method provides default handling (i.e. returns an error);
+ * when there is an attempt to destruct a remote device from an
+ * invalid state.
+ *
+ * @param[in] remote_device This parameter specifies the remote device
+ * object on which there is an attempt to fail the device.
+ *
+ * @return This method returns an indication that the fail transition is not
+ * allowed.
+ * @retval SCI_FAILURE_INVALID_STATE This value is always returned.
+ */
+SCI_STATUS scif_sas_remote_device_default_destruct_handler(
+ SCI_BASE_REMOTE_DEVICE_T * remote_device
+)
+{
+ SCIF_LOG_WARNING((
+ sci_base_object_get_logger((SCIF_SAS_REMOTE_DEVICE_T *)remote_device),
+ SCIF_LOG_OBJECT_REMOTE_DEVICE,
+ "RemoteDevice:0x%x State:0x%x invalid state to destruct.\n",
+ remote_device,
+ sci_base_state_machine_get_state(
+ &((SCIF_SAS_REMOTE_DEVICE_T *)remote_device)->parent.state_machine)
+ ));
+
+ return SCI_FAILURE_INVALID_STATE;
+}
+
+/**
+ * @brief This method provides default handling (i.e. returns an error);
+ * when there is an attempt to reset a remote device from an invalid
+ * state.
+ *
+ * @param[in] remote_device This parameter specifies the remote device
+ * object on which there is an attempt to fail the device.
+ *
+ * @return This method returns an indication that the fail transition is not
+ * allowed.
+ * @retval SCI_FAILURE_INVALID_STATE This value is always returned.
+ */
+SCI_STATUS scif_sas_remote_device_default_reset_handler(
+ SCI_BASE_REMOTE_DEVICE_T * remote_device
+)
+{
+ SCIF_LOG_WARNING((
+ sci_base_object_get_logger((SCIF_SAS_REMOTE_DEVICE_T *)remote_device),
+ SCIF_LOG_OBJECT_REMOTE_DEVICE,
+ "RemoteDevice:0x%x State:0x%x invalid state to reset.\n",
+ remote_device,
+ sci_base_state_machine_get_state(
+ &((SCIF_SAS_REMOTE_DEVICE_T *)remote_device)->parent.state_machine)
+ ));
+
+ return SCI_FAILURE_INVALID_STATE;
+}
+
+/**
+ * @brief This method provides default handling (i.e. returns an error);
+ * when there is an attempt to complete a reset to the remote device
+ * from an invalid state.
+ *
+ * @param[in] remote_device This parameter specifies the remote device
+ * object on which there is an attempt to fail the device.
+ *
+ * @return This method returns an indication that the fail transition is not
+ * allowed.
+ * @retval SCI_FAILURE_INVALID_STATE This value is always returned.
+ */
+SCI_STATUS scif_sas_remote_device_default_reset_complete_handler(
+ SCI_BASE_REMOTE_DEVICE_T * remote_device
+)
+{
+ SCIF_LOG_WARNING((
+ sci_base_object_get_logger((SCIF_SAS_REMOTE_DEVICE_T *)remote_device),
+ SCIF_LOG_OBJECT_REMOTE_DEVICE,
+ "RemoteDevice:0x%x State:0x%x invalid state to complete reset.\n",
+ remote_device,
+ sci_base_state_machine_get_state(
+ &((SCIF_SAS_REMOTE_DEVICE_T *)remote_device)->parent.state_machine)
+ ));
+
+ return SCI_FAILURE_INVALID_STATE;
+}
+
+/**
+ * @brief This method provides default handling (i.e. returns an error);
+ * when a user attempts to start an IO on a remote device and a start
+ * IO operation is not allowed.
+ *
+ * @param[in] remote_device This parameter specifies the remote device
+ * object on which the user is attempting to perform a start IO
+ * operation.
+ * @param[in] io_request This parameter specifies the IO request to be
+ * started.
+ *
+ * @return This method returns an indication that start IO operations
+ * are not allowed.
+ * @retval SCI_FAILURE_INVALID_STATE This value is always returned.
+ */
+SCI_STATUS scif_sas_remote_device_default_start_io_handler(
+ SCI_BASE_REMOTE_DEVICE_T * remote_device,
+ SCI_BASE_REQUEST_T * io_request
+)
+{
+ SCIF_LOG_WARNING((
+ sci_base_object_get_logger((SCIF_SAS_REMOTE_DEVICE_T *)remote_device),
+ SCIF_LOG_OBJECT_REMOTE_DEVICE,
+ "RemoteDevice:0x%x State:0x%x invalid state to start IO.\n",
+ remote_device,
+ sci_base_state_machine_get_state(
+ &((SCIF_SAS_REMOTE_DEVICE_T *)remote_device)->parent.state_machine)
+ ));
+
+ return SCI_FAILURE_INVALID_STATE;
+}
+
+/**
+ * @brief This method provides default handling (i.e. returns an error);
+ * when a user attempts to complete an IO on a remote device and a
+ * complete IO operation is not allowed.
+ *
+ * @param[in] remote_device This parameter specifies the remote device
+ * object on which the user is attempting to perform a complete
+ * IO operation.
+ * @param[in] io_request This parameter specifies the IO request to be
+ * completed.
+ *
+ * @return This method returns an indication that complete IO operations
+ * are not allowed.
+ * @retval SCI_FAILURE_INVALID_STATE This value is always returned.
+ */
+SCI_STATUS scif_sas_remote_device_default_complete_io_handler(
+ SCI_BASE_REMOTE_DEVICE_T * remote_device,
+ SCI_BASE_REQUEST_T * io_request
+)
+{
+ SCIF_LOG_WARNING((
+ sci_base_object_get_logger((SCIF_SAS_REMOTE_DEVICE_T *)remote_device),
+ SCIF_LOG_OBJECT_REMOTE_DEVICE,
+ "RemoteDevice:0x%x State:0x%x invalid state to complete IO\n",
+ remote_device,
+ sci_base_state_machine_get_state(
+ &((SCIF_SAS_REMOTE_DEVICE_T *)remote_device)->parent.state_machine)
+ ));
+
+ return SCI_FAILURE_INVALID_STATE;
+}
+
+
+/**
+ * @brief This method provides default handling (i.e. returns an error);
+ * when a user attempts to complete an IO on a remote device and a
+ * complete IO operation is not allowed.
+ *
+ * @param[in] remote_device This parameter specifies the remote device
+ * object on which the user is attempting to perform a start IO
+ * operation.
+ * @param[in] io_request This parameter specifies the IO request to be
+ * started.
+ *
+ * @return This method returns an indication that complete IO operations
+ * are not allowed.
+ * @retval SCI_FAILURE_INVALID_STATE This value is always returned.
+ */
+SCI_STATUS scif_sas_remote_device_default_complete_high_priority_io_handler(
+ SCI_BASE_REMOTE_DEVICE_T * remote_device,
+ SCI_BASE_REQUEST_T * io_request,
+ void * response_data,
+ SCI_IO_STATUS completion_status
+)
+{
+ SCIF_LOG_WARNING((
+ sci_base_object_get_logger((SCIF_SAS_REMOTE_DEVICE_T *)remote_device),
+ SCIF_LOG_OBJECT_REMOTE_DEVICE,
+ "RemoteDevice:0x%x State:0x%x invalid state to complete high priority IO\n",
+ remote_device,
+ sci_base_state_machine_get_state(
+ &((SCIF_SAS_REMOTE_DEVICE_T *)remote_device)->parent.state_machine)
+ ));
+
+ return SCI_FAILURE_INVALID_STATE;
+}
+
+
+/**
+ * @brief This method provides default handling (i.e. returns an error);
+ * when a user attempts to continue an IO on a remote device and a
+ * continue IO operation is not allowed.
+ *
+ * @param[in] remote_device This parameter specifies the remote device
+ * object on which the user is attempting to perform a start IO
+ * operation.
+ * @param[in] io_request This parameter specifies the IO request to be
+ * started.
+ *
+ * @return This method returns an indication that continue IO operations
+ * are not allowed.
+ * @retval SCI_FAILURE_INVALID_STATE This value is always returned.
+ */
+SCI_STATUS scif_sas_remote_device_default_continue_io_handler(
+ SCI_BASE_REMOTE_DEVICE_T * remote_device,
+ SCI_BASE_REQUEST_T * io_request
+)
+{
+ SCIF_LOG_WARNING((
+ sci_base_object_get_logger((SCIF_SAS_REMOTE_DEVICE_T *)remote_device),
+ SCIF_LOG_OBJECT_REMOTE_DEVICE,
+ "RemoteDevice:0x%x State:0x%x invalid state to continue IO\n",
+ remote_device,
+ sci_base_state_machine_get_state(
+ &((SCIF_SAS_REMOTE_DEVICE_T *)remote_device)->parent.state_machine)
+ ));
+
+ return SCI_FAILURE_INVALID_STATE;
+}
+
+/**
+ * @brief This method provides default handling (i.e. returns an error);
+ * when a user attempts to start a task on a remote device and a
+ * start task operation is not allowed.
+ *
+ * @param[in] remote_device This parameter specifies the remote device
+ * object on which the user is attempting to perform a start
+ * task operation.
+ * @param[in] task_request This parameter specifies the task management
+ * request to be started.
+ *
+ * @return This method returns an indication that start task operations
+ * are not allowed.
+ * @retval SCI_FAILURE_INVALID_STATE This value is always returned.
+ */
+SCI_STATUS scif_sas_remote_device_default_start_task_handler(
+ SCI_BASE_REMOTE_DEVICE_T * remote_device,
+ SCI_BASE_REQUEST_T * task_request
+)
+{
+ SCIF_LOG_WARNING((
+ sci_base_object_get_logger((SCIF_SAS_REMOTE_DEVICE_T *)remote_device),
+ SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_TASK_MANAGEMENT,
+ "RemoteDevice:0x%x State:0x%x invalid state to start task\n",
+ remote_device,
+ sci_base_state_machine_get_state(
+ &((SCIF_SAS_REMOTE_DEVICE_T *)remote_device)->parent.state_machine)
+ ));
+
+ return SCI_FAILURE_INVALID_STATE;
+}
+
+/**
+ * @brief This method provides default handling (i.e. returns an error);
+ * when a user attempts to complete a task on a remote device and a
+ * complete task operation is not allowed.
+ *
+ * @param[in] remote_device This parameter specifies the remote device object
+ * on which the user is attempting to perform a complete task
+ * operation.
+ * @param[in] task_request This parameter specifies the task management
+ * request to be completed.
+ *
+ * @return This method returns an indication that complete task operations
+ * are not allowed.
+ * @retval SCI_FAILURE_INVALID_STATE This value is always returned.
+ */
+SCI_STATUS scif_sas_remote_device_default_complete_task_handler(
+ SCI_BASE_REMOTE_DEVICE_T * remote_device,
+ SCI_BASE_REQUEST_T * task_request
+)
+{
+ SCIF_LOG_WARNING((
+ sci_base_object_get_logger((SCIF_SAS_REMOTE_DEVICE_T *)remote_device),
+ SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_TASK_MANAGEMENT,
+ "RemoteDevice:0x%x State:0x%x invalid state to complete task\n",
+ remote_device,
+ sci_base_state_machine_get_state(
+ &((SCIF_SAS_REMOTE_DEVICE_T *)remote_device)->parent.state_machine)
+ ));
+
+ return SCI_FAILURE_INVALID_STATE;
+}
+
+/**
+ * @brief This method provides default handling (i.e. returns an error);
+ * for when the core issues a start completion notification and
+ * such a notification isn't supported.
+ *
+ * @param[in] remote_device This parameter specifies the remote device object
+ * for which the completion notification has occured.
+ * @param[in] completion_status This parameter specifies the status
+ * of the completion operation.
+ *
+ * @return none.
+ */
+void scif_sas_remote_device_default_start_complete_handler(
+ SCIF_SAS_REMOTE_DEVICE_T * fw_device,
+ SCI_STATUS completion_status
+)
+{
+ SCIF_LOG_WARNING((
+ sci_base_object_get_logger(fw_device),
+ SCIF_LOG_OBJECT_REMOTE_DEVICE,
+ "RemoteDevice:0x%x State:0x%x invalid state to start complete\n",
+ fw_device,
+ sci_base_state_machine_get_state(&fw_device->parent.state_machine)
+ ));
+}
+
+/**
+ * @brief This method provides default handling (i.e. returns an error);
+ * for when the core issues a stop completion notification and
+ * such a notification isn't supported.
+ *
+ * @param[in] remote_device This parameter specifies the remote device object
+ * for which the completion notification has occured.
+ * @param[in] completion_status This parameter specifies the status
+ * of the completion operation.
+ *
+ * @return none.
+ */
+void scif_sas_remote_device_default_stop_complete_handler(
+ SCIF_SAS_REMOTE_DEVICE_T * fw_device,
+ SCI_STATUS completion_status
+)
+{
+ SCIF_LOG_WARNING((
+ sci_base_object_get_logger(fw_device),
+ SCIF_LOG_OBJECT_REMOTE_DEVICE,
+ "RemoteDevice:0x%x State:0x%x invalid state to stop complete\n",
+ fw_device,
+ sci_base_state_machine_get_state(&fw_device->parent.state_machine)
+ ));
+}
+
+/**
+ * @brief This method provides default handling (i.e. returns an error);
+ * for when the core issues a ready notification and such a
+ * notification isn't supported.
+ *
+ * @param[in] remote_device This parameter specifies the remote device object
+ * for which the notification has occured.
+ *
+ * @return none.
+ */
+void scif_sas_remote_device_default_ready_handler(
+ SCIF_SAS_REMOTE_DEVICE_T * fw_device
+)
+{
+ SCIF_LOG_WARNING((
+ sci_base_object_get_logger(fw_device),
+ SCIF_LOG_OBJECT_REMOTE_DEVICE,
+ "RemoteDevice:0x%x State:0x%x invalid state to handle ready\n",
+ fw_device,
+ sci_base_state_machine_get_state(&fw_device->parent.state_machine)
+ ));
+}
+
+/**
+ * @brief This method provides default handling (i.e. returns an error);
+ * for when the core issues a not ready notification and such a
+ * notification isn't supported.
+ *
+ * @param[in] remote_device This parameter specifies the remote device object
+ * for which the notification has occured.
+ *
+ * @return none.
+ */
+void scif_sas_remote_device_default_not_ready_handler(
+ SCIF_SAS_REMOTE_DEVICE_T * fw_device,
+ U32 reason_code
+)
+{
+ SCIF_LOG_WARNING((
+ sci_base_object_get_logger(fw_device),
+ SCIF_LOG_OBJECT_REMOTE_DEVICE,
+ "RemoteDevice:0x%x State:0x%x invalid state to handle not ready\n",
+ fw_device,
+ sci_base_state_machine_get_state(&fw_device->parent.state_machine)
+ ));
+}
+
+#if !defined(DISABLE_WIDE_PORTED_TARGETS)
+/**
+ * @brief This method provides handling of device start complete duing
+ * UPDATING_PORT_WIDTH state.
+ *
+ * @param[in] remote_device This parameter specifies the remote device object
+ * which is start complete.
+ *
+ * @return none.
+ */
+static
+SCI_STATUS scif_sas_remote_device_updating_port_width_state_complete_io_handler(
+ SCI_BASE_REMOTE_DEVICE_T * remote_device,
+ SCI_BASE_REQUEST_T * io_request
+)
+{
+ SCIF_SAS_REMOTE_DEVICE_T * fw_device = (SCIF_SAS_REMOTE_DEVICE_T*)
+ remote_device;
+ fw_device->request_count--;
+
+ //If the request count is zero, go ahead to update the RNC.
+ if (fw_device->request_count == 0 )
+ {
+ if (fw_device->destination_state == SCIF_SAS_REMOTE_DEVICE_DESTINATION_STATE_STOPPING)
+ {
+ //if the destination state of this device change to STOPPING, no matter
+ //whether we need to update the port width, just make the device
+ //go to the STOPPING state, the device will be removed anyway.
+ sci_base_state_machine_change_state(
+ &fw_device->parent.state_machine,
+ SCI_BASE_REMOTE_DEVICE_STATE_STOPPING
+ );
+ }
+ else
+ {
+ //stop the device, upon the stop complete callback, start the device again
+ //with the updated port width.
+ scic_remote_device_stop(
+ fw_device->core_object, SCIF_SAS_REMOTE_DEVICE_CORE_OP_TIMEOUT);
+ }
+ }
+
+ return SCI_SUCCESS;
+}
+
+
+/**
+ * @brief This method provides handling of device start complete duing
+ * UPDATING_PORT_WIDTH state.
+ *
+ * @param[in] remote_device This parameter specifies the remote device object
+ * which is start complete.
+ *
+ * @return none.
+ */
+static
+void scif_sas_remote_device_updating_port_width_state_start_complete_handler(
+ SCIF_SAS_REMOTE_DEVICE_T * fw_device,
+ SCI_STATUS completion_status
+)
+{
+ SCIF_LOG_INFO((
+ sci_base_object_get_logger(fw_device),
+ SCIF_LOG_OBJECT_REMOTE_DEVICE,
+ "RemoteDevice:0x%x updating port width state start complete handler\n",
+ fw_device,
+ sci_base_state_machine_get_state(&fw_device->parent.state_machine)
+ ));
+
+ if ( fw_device->destination_state
+ == SCIF_SAS_REMOTE_DEVICE_DESTINATION_STATE_STOPPING )
+ {
+ //if the destination state of this device change to STOPPING, no matter
+ //whether we need to update the port width again, just make the device
+ //go to the STOPPING state.
+ sci_base_state_machine_change_state(
+ &fw_device->parent.state_machine,
+ SCI_BASE_REMOTE_DEVICE_STATE_STOPPING
+ );
+ }
+ else if ( scic_remote_device_get_port_width(fw_device->core_object)
+ != fw_device->device_port_width
+ && fw_device->device_port_width != 0)
+ {
+ scic_remote_device_stop(
+ fw_device->core_object,
+ SCIF_SAS_REMOTE_DEVICE_CORE_OP_TIMEOUT
+ );
+ }
+ else
+ {
+ //Port width updating succeeds. Transfer to destination state.
+ sci_base_state_machine_change_state(
+ &fw_device->parent.state_machine,
+ SCI_BASE_REMOTE_DEVICE_STATE_READY
+ );
+ }
+}
+
+/**
+ * @brief This method provides handling of device stop complete duing
+ * UPDATING_PORT_WIDTH state.
+ *
+ * @param[in] remote_device This parameter specifies the remote device object
+ * which is stop complete.
+ *
+ * @return none.
+ */
+static
+void scif_sas_remote_device_updating_port_width_state_stop_complete_handler(
+ SCIF_SAS_REMOTE_DEVICE_T * fw_device,
+ SCI_STATUS completion_status
+)
+{
+ SCIF_LOG_INFO((
+ sci_base_object_get_logger(fw_device),
+ SCIF_LOG_OBJECT_REMOTE_DEVICE,
+ "RemoteDevice:0x%x updating port width state stop complete handler\n",
+ fw_device,
+ sci_base_state_machine_get_state(&fw_device->parent.state_machine)
+ ));
+
+ if ( fw_device->destination_state
+ == SCIF_SAS_REMOTE_DEVICE_DESTINATION_STATE_STOPPING )
+ {
+ //Device directly transits to STOPPED STATE from UPDATING_PORT_WIDTH state,
+ fw_device->domain->device_start_count--;
+
+ //if the destination state of this device change to STOPPING, no matter
+ //whether we need to update the port width again, just make the device
+ //go to the STOPPED state.
+ sci_base_state_machine_change_state(
+ &fw_device->parent.state_machine,
+ SCI_BASE_REMOTE_DEVICE_STATE_STOPPED
+ );
+ }
+ else
+ {
+ scic_remote_device_set_port_width(
+ fw_device->core_object,
+ fw_device->device_port_width
+ );
+
+ //Device stop complete, means the RNC has been destructed. Now we need to
+ //start core device so the RNC with updated port width will be posted.
+ scic_remote_device_start(
+ fw_device->core_object, SCIF_SAS_REMOTE_DEVICE_CORE_OP_TIMEOUT);
+ }
+}
+
+/**
+ * @brief This method provides handling (i.e. returns an error);
+ * when a user attempts to stop a remote device during the updating
+ * port width state, it will record the destination state for this
+ * device to be STOPPING, instead of usually READY state.
+ *
+ * @param[in] remote_device This parameter specifies the remote device object
+ * on which the user is attempting to perform a stop operation.
+ *
+ * @return This method always return SCI_SUCCESS.
+ */
+static
+SCI_STATUS scif_sas_remote_device_updating_port_width_state_stop_handler(
+ SCI_BASE_REMOTE_DEVICE_T * remote_device
+)
+{
+ SCIF_SAS_REMOTE_DEVICE_T * fw_device =
+ (SCIF_SAS_REMOTE_DEVICE_T *)remote_device;
+
+ SCIF_LOG_INFO((
+ sci_base_object_get_logger(fw_device),
+ SCIF_LOG_OBJECT_REMOTE_DEVICE,
+ "RemoteDevice:0x%x updating port width state stop handler\n",
+ fw_device,
+ sci_base_state_machine_get_state(&fw_device->parent.state_machine)
+ ));
+
+ //Can't stop the device right now. Remember the pending stopping request.
+ //When exit the UPDATING_PORT_WIDTH state, we will check this variable
+ //to decide which state to go.
+ fw_device->destination_state =
+ SCIF_SAS_REMOTE_DEVICE_DESTINATION_STATE_STOPPING;
+
+ return SCI_SUCCESS;
+}
+
+#endif //#if !defined(DISABLE_WIDE_PORTED_TARGETS)
+
+#define scif_sas_remote_device_stopping_complete_io_handler \
+ scif_sas_remote_device_ready_operational_complete_io_handler
+#define scif_sas_remote_device_stopping_complete_task_handler \
+ scif_sas_remote_device_ready_operational_complete_task_handler
+
+SCIF_SAS_REMOTE_DEVICE_STATE_HANDLER_T
+scif_sas_remote_device_state_handler_table[SCI_BASE_REMOTE_DEVICE_MAX_STATES] =
+{
+ // SCI_BASE_REMOTE_DEVICE_STATE_INITIAL
+ {
+ {
+ scif_sas_remote_device_default_start_handler,
+ scif_sas_remote_device_default_stop_handler,
+ scif_sas_remote_device_default_fail_handler,
+ scif_sas_remote_device_default_destruct_handler,
+ scif_sas_remote_device_default_reset_handler,
+ scif_sas_remote_device_default_reset_complete_handler,
+ scif_sas_remote_device_default_start_io_handler,
+ scif_sas_remote_device_default_complete_io_handler,
+ scif_sas_remote_device_default_continue_io_handler,
+ scif_sas_remote_device_default_start_task_handler,
+ scif_sas_remote_device_default_complete_task_handler
+ },
+ scif_sas_remote_device_default_start_complete_handler,
+ scif_sas_remote_device_default_stop_complete_handler,
+ scif_sas_remote_device_default_ready_handler,
+ scif_sas_remote_device_default_not_ready_handler,
+ scif_sas_remote_device_default_start_io_handler,
+ scif_sas_remote_device_default_complete_high_priority_io_handler
+ },
+ // SCI_BASE_REMOTE_DEVICE_STATE_STOPPED
+ {
+ {
+ scif_sas_remote_device_stopped_start_handler,
+ scif_sas_remote_device_default_stop_handler,
+ scif_sas_remote_device_default_fail_handler,
+ scif_sas_remote_device_stopped_destruct_handler,
+ scif_sas_remote_device_default_reset_handler,
+ scif_sas_remote_device_default_reset_complete_handler,
+ scif_sas_remote_device_default_start_io_handler,
+ scif_sas_remote_device_default_complete_io_handler,
+ scif_sas_remote_device_default_continue_io_handler,
+ scif_sas_remote_device_default_start_task_handler,
+ scif_sas_remote_device_default_complete_task_handler
+ },
+ scif_sas_remote_device_default_start_complete_handler,
+ scif_sas_remote_device_default_stop_complete_handler,
+ scif_sas_remote_device_default_ready_handler,
+ scif_sas_remote_device_default_not_ready_handler,
+ scif_sas_remote_device_default_start_io_handler,
+ scif_sas_remote_device_default_complete_high_priority_io_handler
+ },
+ // SCI_BASE_REMOTE_DEVICE_STATE_STARTING
+ {
+ {
+ scif_sas_remote_device_default_start_handler,
+ scif_sas_remote_device_default_stop_handler,
+ scif_sas_remote_device_default_fail_handler,
+ scif_sas_remote_device_default_destruct_handler,
+ scif_sas_remote_device_default_reset_handler,
+ scif_sas_remote_device_default_reset_complete_handler,
+ scif_sas_remote_device_default_start_io_handler,
+ scif_sas_remote_device_default_complete_io_handler,
+ scif_sas_remote_device_default_continue_io_handler,
+ scif_sas_remote_device_default_start_task_handler,
+ scif_sas_remote_device_default_complete_task_handler
+ },
+ scif_sas_remote_device_default_start_complete_handler,
+ scif_sas_remote_device_default_stop_complete_handler,
+ scif_sas_remote_device_default_ready_handler,
+ scif_sas_remote_device_default_not_ready_handler,
+ scif_sas_remote_device_default_start_io_handler,
+ scif_sas_remote_device_default_complete_high_priority_io_handler
+ },
+ // SCI_BASE_REMOTE_DEVICE_STATE_READY - see substate handlers
+ {
+ {
+ scif_sas_remote_device_default_start_handler,
+ scif_sas_remote_device_default_stop_handler,
+ scif_sas_remote_device_default_fail_handler,
+ scif_sas_remote_device_default_destruct_handler,
+ scif_sas_remote_device_default_reset_handler,
+ scif_sas_remote_device_default_reset_complete_handler,
+ scif_sas_remote_device_default_start_io_handler,
+ scif_sas_remote_device_default_complete_io_handler,
+ scif_sas_remote_device_default_continue_io_handler,
+ scif_sas_remote_device_default_start_task_handler,
+ scif_sas_remote_device_default_complete_task_handler
+ },
+ scif_sas_remote_device_default_start_complete_handler,
+ scif_sas_remote_device_default_stop_complete_handler,
+ scif_sas_remote_device_default_ready_handler,
+ scif_sas_remote_device_default_not_ready_handler,
+ scif_sas_remote_device_default_start_io_handler,
+ scif_sas_remote_device_default_complete_high_priority_io_handler
+ },
+ // SCI_BASE_REMOTE_DEVICE_STATE_STOPPING
+ {
+ {
+ scif_sas_remote_device_default_start_handler,
+ scif_sas_remote_device_default_stop_handler,
+ scif_sas_remote_device_default_fail_handler,
+ scif_sas_remote_device_default_destruct_handler,
+ scif_sas_remote_device_default_reset_handler,
+ scif_sas_remote_device_default_reset_complete_handler,
+ scif_sas_remote_device_default_start_io_handler,
+ scif_sas_remote_device_stopping_complete_io_handler,
+ scif_sas_remote_device_default_continue_io_handler,
+ scif_sas_remote_device_default_start_task_handler,
+ scif_sas_remote_device_stopping_complete_task_handler
+ },
+ scif_sas_remote_device_default_start_complete_handler,
+ scif_sas_remote_device_stopping_stop_complete_handler,
+ scif_sas_remote_device_default_ready_handler,
+ scif_sas_remote_device_default_not_ready_handler,
+ scif_sas_remote_device_default_start_io_handler,
+ scif_sas_remote_device_stopping_complete_high_priority_io_handler
+ },
+ // SCI_BASE_REMOTE_DEVICE_STATE_FAILED
+ {
+ {
+ scif_sas_remote_device_default_start_handler,
+ scif_sas_remote_device_failed_stop_handler,
+ scif_sas_remote_device_default_fail_handler,
+ scif_sas_remote_device_default_destruct_handler,
+ scif_sas_remote_device_default_reset_handler,
+ scif_sas_remote_device_default_reset_complete_handler,
+ scif_sas_remote_device_default_start_io_handler,
+ scif_sas_remote_device_default_complete_io_handler,
+ scif_sas_remote_device_default_continue_io_handler,
+ scif_sas_remote_device_default_start_task_handler,
+ scif_sas_remote_device_default_complete_task_handler
+ },
+ scif_sas_remote_device_default_start_complete_handler,
+ scif_sas_remote_device_default_stop_complete_handler,
+ scif_sas_remote_device_default_ready_handler,
+ scif_sas_remote_device_default_not_ready_handler,
+ scif_sas_remote_device_default_start_io_handler,
+ scif_sas_remote_device_default_complete_high_priority_io_handler
+ },
+ // SCI_BASE_REMOTE_DEVICE_STATE_RESETTING - is unused by framework
+ {
+ {
+ scif_sas_remote_device_default_start_handler,
+ scif_sas_remote_device_default_stop_handler,
+ scif_sas_remote_device_default_fail_handler,
+ scif_sas_remote_device_default_destruct_handler,
+ scif_sas_remote_device_default_reset_handler,
+ scif_sas_remote_device_default_reset_complete_handler,
+ scif_sas_remote_device_default_start_io_handler,
+ scif_sas_remote_device_default_complete_io_handler,
+ scif_sas_remote_device_default_continue_io_handler,
+ scif_sas_remote_device_default_start_task_handler,
+ scif_sas_remote_device_default_complete_task_handler
+ },
+ scif_sas_remote_device_default_start_complete_handler,
+ scif_sas_remote_device_default_stop_complete_handler,
+ scif_sas_remote_device_default_ready_handler,
+ scif_sas_remote_device_default_not_ready_handler,
+ scif_sas_remote_device_default_start_io_handler,
+ scif_sas_remote_device_default_complete_high_priority_io_handler
+ },
+#if !defined(DISABLE_WIDE_PORTED_TARGETS)
+ // SCI_BASE_REMOTE_DEVICE_STATE_UPDATING_PORT_WIDTH
+ {
+ {
+ scif_sas_remote_device_default_start_handler,
+ scif_sas_remote_device_updating_port_width_state_stop_handler,
+ scif_sas_remote_device_default_fail_handler,
+ scif_sas_remote_device_default_destruct_handler,
+ scif_sas_remote_device_default_reset_handler,
+ scif_sas_remote_device_default_reset_complete_handler,
+ scif_sas_remote_device_default_start_io_handler,
+ scif_sas_remote_device_updating_port_width_state_complete_io_handler,
+ scif_sas_remote_device_default_continue_io_handler,
+ scif_sas_remote_device_default_start_task_handler,
+ scif_sas_remote_device_default_complete_task_handler
+ },
+ scif_sas_remote_device_updating_port_width_state_start_complete_handler,
+ scif_sas_remote_device_updating_port_width_state_stop_complete_handler,
+ scif_sas_remote_device_default_ready_handler,
+ scif_sas_remote_device_default_not_ready_handler,
+ scif_sas_remote_device_default_start_io_handler,
+ scif_sas_remote_device_default_complete_high_priority_io_handler
+ },
+#endif
+ // SCI_BASE_REMOTE_DEVICE_STATE_FINAL
+ {
+ {
+ scif_sas_remote_device_default_start_handler,
+ scif_sas_remote_device_default_stop_handler,
+ scif_sas_remote_device_default_fail_handler,
+ scif_sas_remote_device_default_destruct_handler,
+ scif_sas_remote_device_default_reset_handler,
+ scif_sas_remote_device_default_reset_complete_handler,
+ scif_sas_remote_device_default_start_io_handler,
+ scif_sas_remote_device_default_complete_io_handler,
+ scif_sas_remote_device_default_continue_io_handler,
+ scif_sas_remote_device_default_start_task_handler,
+ scif_sas_remote_device_default_complete_task_handler
+ },
+ scif_sas_remote_device_default_start_complete_handler,
+ scif_sas_remote_device_default_stop_complete_handler,
+ scif_sas_remote_device_default_ready_handler,
+ scif_sas_remote_device_default_not_ready_handler,
+ scif_sas_remote_device_default_start_io_handler,
+ scif_sas_remote_device_default_complete_high_priority_io_handler
+ }
+};
+
diff --git a/sys/dev/isci/scil/scif_sas_remote_device_states.c b/sys/dev/isci/scil/scif_sas_remote_device_states.c
new file mode 100644
index 0000000..fda6db1
--- /dev/null
+++ b/sys/dev/isci/scil/scif_sas_remote_device_states.c
@@ -0,0 +1,549 @@
+/*-
+ * 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.
+ *
+ * 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 <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/**
+ * @file
+ *
+ * @brief
+ */
+
+#include <dev/isci/scil/scic_remote_device.h>
+
+#include <dev/isci/scil/scif_sas_remote_device.h>
+#include <dev/isci/scil/scif_sas_domain.h>
+#include <dev/isci/scil/scif_sas_logger.h>
+
+
+/**
+ * This constant indicates the number of milliseconds to wait for the core
+ * to start/stop it's remote device object.
+ */
+//#define SCIF_SAS_REMOTE_DEVICE_CORE_OP_TIMEOUT 1000
+
+//******************************************************************************
+//* P R O T E C T E D M E T H O D S
+//******************************************************************************
+
+/**
+ * @brief This method implements the actions taken when entering the
+ * INITIAL state. This basically, causes an immediate transition
+ * into the STOPPED state.
+ *
+ * @param[in] object This parameter specifies the base object for which
+ * the state transition is occurring. This is cast into a
+ * SCIF_SAS_REMOTE_DEVICE object in the method implementation.
+ *
+ * @return none
+ */
+static
+void scif_sas_remote_device_initial_state_enter(
+ SCI_BASE_OBJECT_T *object
+)
+{
+ SCIF_SAS_REMOTE_DEVICE_T * fw_device = (SCIF_SAS_REMOTE_DEVICE_T *)object;
+
+ SET_STATE_HANDLER(
+ fw_device,
+ scif_sas_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(
+ &fw_device->parent.state_machine,
+ SCI_BASE_REMOTE_DEVICE_STATE_STOPPED
+ );
+}
+
+/**
+ * @brief This method implements the actions taken when entering the
+ * STOPPED state. This method updates the domains count of started
+ * devices and will invoke the destruct method if this entrance into
+ * the STOPPED state was due to a scif_remote_device_destruct()
+ * call by the user.
+ *
+ * @param[in] object This parameter specifies the base object for which
+ * the state transition is occurring. This is cast into a
+ * SCIF_SAS_REMOTE_DEVICE object in the method implementation.
+ *
+ * @return none
+ */
+static
+void scif_sas_remote_device_stopped_state_enter(
+ SCI_BASE_OBJECT_T *object
+)
+{
+ SCIF_SAS_REMOTE_DEVICE_T * fw_device = (SCIF_SAS_REMOTE_DEVICE_T *)object;
+
+ SET_STATE_HANDLER(
+ fw_device,
+ scif_sas_remote_device_state_handler_table,
+ SCI_BASE_REMOTE_DEVICE_STATE_STOPPED
+ );
+
+ // There should be no outstanding requests for this device in the
+ // stopped state.
+ ASSERT(fw_device->request_count == 0);
+
+ // If we are entering the stopped state as a result of a destruct
+ // request, then let's perform the actual destruct operation now.
+ if (fw_device->destruct_when_stopped == TRUE)
+ fw_device->operation_status
+ = fw_device->state_handlers->parent.destruct_handler(
+ &fw_device->parent
+ );
+
+ /// @todo What should we do if this call fails?
+ fw_device->domain->state_handlers->device_stop_complete_handler(
+ &fw_device->domain->parent, &fw_device->parent
+ );
+}
+
+/**
+ * @brief This method implements the actions taken when entering the
+ * STARTING state. This method will attempt to start the core
+ * remote device and will kick-start the starting sub-state machine
+ * if no errors are encountered.
+ *
+ * @param[in] object This parameter specifies the base object for which
+ * the state transition is occurring. This is cast into a
+ * SCIF_SAS_REMOTE_DEVICE object in the method implementation.
+ *
+ * @return none
+ */
+static
+void scif_sas_remote_device_starting_state_enter(
+ SCI_BASE_OBJECT_T *object
+)
+{
+ SCIF_SAS_REMOTE_DEVICE_T * fw_device = (SCIF_SAS_REMOTE_DEVICE_T *)object;
+
+ SET_STATE_HANDLER(
+ fw_device,
+ scif_sas_remote_device_state_handler_table,
+ SCI_BASE_REMOTE_DEVICE_STATE_STARTING
+ );
+
+ SCIF_LOG_INFO((
+ sci_base_object_get_logger(fw_device),
+ SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_REMOTE_DEVICE_CONFIG,
+ "RemoteDevice:0x%x starting/configuring\n",
+ fw_device
+ ));
+
+ fw_device->destination_state =
+ SCIF_SAS_REMOTE_DEVICE_DESTINATION_STATE_READY;
+
+ sci_base_state_machine_start(&fw_device->starting_substate_machine);
+
+ fw_device->operation_status = scic_remote_device_start(
+ fw_device->core_object,
+ SCIF_SAS_REMOTE_DEVICE_CORE_OP_TIMEOUT
+ );
+
+ if (fw_device->operation_status != SCI_SUCCESS)
+ {
+ fw_device->state_handlers->parent.fail_handler(&fw_device->parent);
+
+ // Something is seriously wrong. Starting the core remote device
+ // shouldn't fail in anyway in this state.
+ scif_cb_controller_error(fw_device->domain->controller,
+ SCI_CONTROLLER_REMOTE_DEVICE_ERROR);
+ }
+}
+
+/**
+ * @brief This method implements the actions taken when exiting the
+ * STARTING state. Currently this method simply stops the
+ * sub-state machine.
+ *
+ * @param[in] object This parameter specifies the base object for which
+ * the state transition is occurring. This is cast into a
+ * SCIF_SAS_REMOTE_DEVICE object in the method implementation.
+ *
+ * @return none
+ */
+static
+void scif_sas_remote_device_starting_state_exit(
+ SCI_BASE_OBJECT_T *object
+)
+{
+ SCIF_SAS_REMOTE_DEVICE_T * fw_device = (SCIF_SAS_REMOTE_DEVICE_T *)object;
+
+ fw_device->destination_state =
+ SCIF_SAS_REMOTE_DEVICE_DESTINATION_STATE_UNSPECIFIED;
+
+ // Transition immediately into the operational sub-state.
+ sci_base_state_machine_stop(&fw_device->starting_substate_machine);
+}
+
+/**
+ * @brief This method implements the actions taken when entering the
+ * READY state. Currently this method simply starts the
+ * sub-state machine.
+ *
+ * @param[in] object This parameter specifies the base object for which
+ * the state transition is occurring. This is cast into a
+ * SCIF_SAS_REMOTE_DEVICE object in the method implementation.
+ *
+ * @return none
+ */
+static
+void scif_sas_remote_device_ready_state_enter(
+ SCI_BASE_OBJECT_T *object
+)
+{
+ SCIF_SAS_REMOTE_DEVICE_T * fw_device = (SCIF_SAS_REMOTE_DEVICE_T *)object;
+
+ // Transition immediately into the operational sub-state.
+ sci_base_state_machine_start(&fw_device->ready_substate_machine);
+
+#if defined(DISABLE_WIDE_PORTED_TARGETS)
+ scif_sas_domain_remote_device_start_complete(fw_device->domain,fw_device);
+#endif
+}
+
+/**
+ * @brief This method implements the actions taken when exiting the
+ * READY state. Currently this method simply stops the
+ * sub-state machine.
+ *
+ * @param[in] object This parameter specifies the base object for which
+ * the state transition is occurring. This is cast into a
+ * SCIF_SAS_REMOTE_DEVICE object in the method implementation.
+ *
+ * @return none
+ */
+static
+void scif_sas_remote_device_ready_state_exit(
+ SCI_BASE_OBJECT_T *object
+)
+{
+ SCIF_SAS_REMOTE_DEVICE_T * fw_device = (SCIF_SAS_REMOTE_DEVICE_T *)object;
+
+ // Transition immediately into the operational sub-state.
+ sci_base_state_machine_stop(&fw_device->ready_substate_machine);
+}
+
+/**
+ * @brief This method implements the actions taken when entering the
+ * STOPPING state. This includes: stopping the core remote device
+ * and handling any errors that may occur.
+ *
+ * @param[in] object This parameter specifies the base object for which
+ * the state transition is occurring. This is cast into a
+ * SCIF_SAS_REMOTE_DEVICE object in the method implementation.
+ *
+ * @return none
+ */
+static
+void scif_sas_remote_device_stopping_state_enter(
+ SCI_BASE_OBJECT_T *object
+)
+{
+ SCIF_SAS_REMOTE_DEVICE_T * fw_device = (SCIF_SAS_REMOTE_DEVICE_T *)object;
+
+ SET_STATE_HANDLER(
+ fw_device,
+ scif_sas_remote_device_state_handler_table,
+ SCI_BASE_REMOTE_DEVICE_STATE_STOPPING
+ );
+
+ fw_device->operation_status = scic_remote_device_stop(
+ fw_device->core_object,
+ SCIF_SAS_REMOTE_DEVICE_CORE_OP_TIMEOUT
+ );
+
+ // If there was a failure, then transition directly to the stopped state.
+ if (fw_device->operation_status != SCI_SUCCESS)
+ {
+ /**
+ * @todo We may want to consider adding handling to reset the
+ * structure data for the framework and core devices here
+ * in order to help aid recovery.
+ */
+
+ fw_device->state_handlers->stop_complete_handler(
+ fw_device, fw_device->operation_status
+ );
+ }
+}
+
+/**
+ * @brief This method implements the actions taken when exiting the
+ * STOPPING state.
+ *
+ * @param[in] object This parameter specifies the base object for which
+ * the state transition is occurring. This is cast into a
+ * SCIF_SAS_REMOTE_DEVICE object in the method implementation.
+ *
+ * @return none
+ */
+static
+void scif_sas_remote_device_stopping_state_exit(
+ SCI_BASE_OBJECT_T *object
+)
+{
+ SCIF_SAS_REMOTE_DEVICE_T * fw_device = (SCIF_SAS_REMOTE_DEVICE_T *)object;
+
+ // Let the domain know that the device has stopped
+ fw_device->domain->device_start_count--;
+}
+
+/**
+ * @brief This method implements the actions taken when entering the
+ * FAILED state. This includes setting the state handler methods
+ * and issuing a scif_cb_remote_device_failed() notification to
+ * the user.
+ *
+ * @param[in] object This parameter specifies the base object for which
+ * the state transition is occurring. This is cast into a
+ * SCIF_SAS_REMOTE_DEVICE object in the method implementation.
+ *
+ * @return none
+ */
+static
+void scif_sas_remote_device_failed_state_enter(
+ SCI_BASE_OBJECT_T *object
+)
+{
+ SCIF_SAS_REMOTE_DEVICE_T * fw_device = (SCIF_SAS_REMOTE_DEVICE_T *)object;
+
+ SET_STATE_HANDLER(
+ fw_device,
+ scif_sas_remote_device_state_handler_table,
+ SCI_BASE_REMOTE_DEVICE_STATE_FAILED
+ );
+
+ SCIF_LOG_INFO((
+ sci_base_object_get_logger(fw_device),
+ SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_REMOTE_DEVICE_CONFIG,
+ "Domain:0x%x Device:0x%x Status:0x%x device failed\n",
+ fw_device->domain, fw_device, fw_device->operation_status
+ ));
+
+ // Notify the user that the device has failed.
+ scif_cb_remote_device_failed(
+ fw_device->domain->controller,
+ fw_device->domain,
+ fw_device,
+ fw_device->operation_status
+ );
+
+ // Only call start_complete for the remote device if the device failed
+ // from the STARTING state.
+ if (fw_device->parent.state_machine.previous_state_id
+ == SCI_BASE_REMOTE_DEVICE_STATE_STARTING)
+ scif_sas_domain_remote_device_start_complete(fw_device->domain,fw_device);
+}
+
+/**
+ * @brief This method implements the actions taken when entering the RESETTING
+ * state.
+ *
+ * @param[in] object This parameter specifies the base object for which
+ * the state transition is occurring. This is cast into a
+ * SCIF_SAS_REMOTE_DEVICE object in the method implementation.
+ *
+ * @return none
+ */
+static
+void scif_sas_remote_device_resetting_state_enter(
+ SCI_BASE_OBJECT_T *object
+)
+{
+}
+
+#if !defined(DISABLE_WIDE_PORTED_TARGETS)
+/**
+ * @brief This method implements the actions taken when entering the UPDATING
+ * PORT WIDTH state.
+ *
+ * @param[in] object This parameter specifies the base object for which
+ * the state transition is occurring. This is cast into a
+ * SCIF_SAS_REMOTE_DEVICE object in the method implementation.
+ *
+ * @return none
+ */
+static
+void scif_sas_remote_device_updating_port_width_state_enter(
+ SCI_BASE_OBJECT_T *object
+)
+{
+ SCIF_SAS_REMOTE_DEVICE_T * fw_device = (SCIF_SAS_REMOTE_DEVICE_T *)object;
+
+ SET_STATE_HANDLER(
+ fw_device,
+ scif_sas_remote_device_state_handler_table,
+ SCI_BASE_REMOTE_DEVICE_STATE_UPDATING_PORT_WIDTH
+ );
+
+ fw_device->destination_state = SCIF_SAS_REMOTE_DEVICE_DESTINATION_STATE_READY;
+
+ //If the request count is zero, go ahead to update the RNC.
+ //If not, don't do anything for now. The IO complete handler of this state
+ //will update the RNC whenever the request count goes down to zero.
+ if (fw_device->request_count == 0)
+ {
+ //stop the device, upon the stop complete callback, start the device again
+ //with the updated port width.
+ scic_remote_device_stop(
+ fw_device->core_object, SCIF_SAS_REMOTE_DEVICE_CORE_OP_TIMEOUT);
+ }
+}
+
+
+/**
+ * @brief This method implements the actions taken when exiting the
+ * STOPPING state.
+ *
+ * @param[in] object This parameter specifies the base object for which
+ * the state transition is occurring. This is cast into a
+ * SCIF_SAS_REMOTE_DEVICE object in the method implementation.
+ *
+ * @return none
+ */
+static
+void scif_sas_remote_device_updating_port_width_state_exit(
+ SCI_BASE_OBJECT_T *object
+)
+{
+ SCIF_SAS_REMOTE_DEVICE_T * fw_device = (SCIF_SAS_REMOTE_DEVICE_T *)object;
+
+ fw_device->destination_state =
+ SCIF_SAS_REMOTE_DEVICE_DESTINATION_STATE_UNSPECIFIED;
+}
+
+
+#endif //#if !defined(DISABLE_WIDE_PORTED_TARGETS)
+
+/**
+ * @brief This method implements the actions taken when entering the
+ * FINAL state. This includes setting the FINAL state handler
+ * methods.
+ *
+ * @param[in] object This parameter specifies the base object for which
+ * the state transition is occurring. This is cast into a
+ * SCIF_SAS_REMOTE_DEVICE object in the method implementation.
+ *
+ * @return none
+ */
+static
+void scif_sas_remote_device_final_state_enter(
+ SCI_BASE_OBJECT_T *object
+)
+{
+ SCIF_SAS_REMOTE_DEVICE_T * fw_device = (SCIF_SAS_REMOTE_DEVICE_T *)object;
+
+ SET_STATE_HANDLER(
+ fw_device,
+ scif_sas_remote_device_state_handler_table,
+ SCI_BASE_REMOTE_DEVICE_STATE_FINAL
+ );
+}
+
+
+SCI_BASE_STATE_T
+ scif_sas_remote_device_state_table[SCI_BASE_REMOTE_DEVICE_MAX_STATES] =
+{
+ {
+ SCI_BASE_REMOTE_DEVICE_STATE_INITIAL,
+ scif_sas_remote_device_initial_state_enter,
+ NULL
+ },
+ {
+ SCI_BASE_REMOTE_DEVICE_STATE_STOPPED,
+ scif_sas_remote_device_stopped_state_enter,
+ NULL
+ },
+ {
+ SCI_BASE_REMOTE_DEVICE_STATE_STARTING,
+ scif_sas_remote_device_starting_state_enter,
+ scif_sas_remote_device_starting_state_exit
+ },
+ {
+ SCI_BASE_REMOTE_DEVICE_STATE_READY,
+ scif_sas_remote_device_ready_state_enter,
+ scif_sas_remote_device_ready_state_exit
+ },
+ {
+ SCI_BASE_REMOTE_DEVICE_STATE_STOPPING,
+ scif_sas_remote_device_stopping_state_enter,
+ scif_sas_remote_device_stopping_state_exit
+ },
+ {
+ SCI_BASE_REMOTE_DEVICE_STATE_FAILED,
+ scif_sas_remote_device_failed_state_enter,
+ NULL
+ },
+ {
+ SCI_BASE_REMOTE_DEVICE_STATE_RESETTING,
+ scif_sas_remote_device_resetting_state_enter,
+ NULL
+ },
+#if !defined(DISABLE_WIDE_PORTED_TARGETS)
+ {
+ SCI_BASE_REMOTE_DEVICE_STATE_UPDATING_PORT_WIDTH,
+ scif_sas_remote_device_updating_port_width_state_enter,
+ scif_sas_remote_device_updating_port_width_state_exit
+ },
+#endif //#if !defined(DISABLE_WIDE_PORTED_TARGETS)
+ {
+ SCI_BASE_REMOTE_DEVICE_STATE_FINAL,
+ scif_sas_remote_device_final_state_enter,
+ NULL
+ },
+};
+
diff --git a/sys/dev/isci/scil/scif_sas_request.c b/sys/dev/isci/scil/scif_sas_request.c
new file mode 100644
index 0000000..9c7d62e
--- /dev/null
+++ b/sys/dev/isci/scil/scif_sas_request.c
@@ -0,0 +1,183 @@
+/*-
+ * 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.
+ *
+ * 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 <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/**
+ * @file
+ *
+ * @brief This file contains the implementation of the SCIF_SAS_REQUEST
+ * object. The SCIF_SAS_REQUEST object provides data and methods
+ * that are common to both IO requests and task management requests.
+ */
+
+
+#include <dev/isci/scil/scic_controller.h>
+
+#include <dev/isci/scil/scif_sas_request.h>
+#include <dev/isci/scil/scif_sas_task_request.h>
+#include <dev/isci/scil/scif_sas_controller.h>
+#include <dev/isci/scil/scif_sas_domain.h>
+#include <dev/isci/scil/scif_sas_remote_device.h>
+
+#include <dev/isci/scil/scif_sas_logger.h>
+
+//******************************************************************************
+//* P R O T E C T E D M E T H O D S
+//******************************************************************************
+
+/**
+ * @brief This method constructs the SCIF_SAS_REQUEST object.
+ *
+ * @param[in] fw_request This parameter specifies the request object to
+ * be constructed.
+ * @param[in] fw_device This parameter specifies the remote device object
+ * to which this request is destined.
+ * @param[in] logger This parameter specifies the logger associated with
+ * this base request object.
+ * @param[in] state_table This parameter specifies the table of state
+ * definitions to be utilized for the request state machine.
+ *
+ * @return none
+ */
+void scif_sas_request_construct(
+ SCIF_SAS_REQUEST_T * fw_request,
+ SCIF_SAS_REMOTE_DEVICE_T * fw_device,
+ SCI_BASE_LOGGER_T * logger,
+ SCI_BASE_STATE_T * state_table
+)
+{
+ sci_base_request_construct(&fw_request->parent, logger, state_table);
+
+ SCIF_LOG_TRACE((
+ sci_base_object_get_logger(fw_request),
+ SCIF_LOG_OBJECT_TASK_MANAGEMENT,
+ "scif_sas_request_construct(0x%x, 0x%x, 0x%x, 0x%x) enter\n",
+ fw_request, fw_device, logger, state_table
+ ));
+
+ fw_request->device = fw_device;
+ fw_request->is_internal = FALSE;
+ fw_request->lun = 0;
+ fw_request->terminate_requestor = NULL;
+ fw_request->protocol_complete_handler = NULL;
+ fw_request->is_high_priority = FALSE;
+ fw_request->is_waiting_for_abort_task_set = FALSE;
+
+ sci_fast_list_element_init(fw_request, &fw_request->list_element);
+}
+
+/**
+ * @brief This method will request the SCI core to terminate the supplied
+ * request.
+ *
+ * @param[in] fw_request This parameter specifies the request to be terminated.
+ * @param[in] core_request This parameter specifies the core request (IO or
+ * task) to be terminated.
+ *
+ * @return This method returns the status of the core termination operation.
+ */
+SCI_STATUS scif_sas_request_terminate_start(
+ SCIF_SAS_REQUEST_T * fw_request,
+ SCI_IO_REQUEST_HANDLE_T core_request
+)
+{
+ SCIF_LOG_TRACE((
+ sci_base_object_get_logger(fw_request),
+ SCIF_LOG_OBJECT_TASK_MANAGEMENT,
+ "scif_sas_request_terminate_start(0x%x) enter\n",
+ fw_request
+ ));
+
+ // Only increment the affected request count if this request is being
+ // terminated at the behest of a task management request.
+ if (fw_request->terminate_requestor != NULL)
+ fw_request->terminate_requestor->affected_request_count++;
+
+ return scic_controller_terminate_request(
+ fw_request->device->domain->controller->core_object,
+ fw_request->device->core_object,
+ core_request
+ );
+}
+
+/**
+ * @brief This method will perform termination completion processing for
+ * the supplied request. This includes updated the affected
+ * request count, if a task management request is what generated
+ * this termination. Also, this method will attempt to transition
+ * to the READY OPERATIONAL state if this represents the last
+ * affected request.
+ *
+ * @param[in] fw_request This parameter specifies the request for which to
+ * perform termination completion processing.
+ *
+ * @return none
+ */
+void scif_sas_request_terminate_complete(
+ SCIF_SAS_REQUEST_T * fw_request
+)
+{
+ SCIF_LOG_TRACE((
+ sci_base_object_get_logger(fw_request),
+ SCIF_LOG_OBJECT_TASK_MANAGEMENT,
+ "scif_sas_request_terminate_complete(0x%x) enter\n",
+ fw_request
+ ));
+
+ // For requests that were terminated due to a task management request,
+ // check to see if the task management request has completed.
+ if (fw_request->terminate_requestor != NULL)
+ scif_sas_task_request_operation_complete(fw_request->terminate_requestor);
+}
+
diff --git a/sys/dev/isci/scil/scif_sas_request.h b/sys/dev/isci/scil/scif_sas_request.h
new file mode 100644
index 0000000..0dc41e3
--- /dev/null
+++ b/sys/dev/isci/scil/scif_sas_request.h
@@ -0,0 +1,221 @@
+/*-
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 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.
+ *
+ * $FreeBSD$
+ */
+#ifndef _SCIF_SAS_REQUEST_H_
+#define _SCIF_SAS_REQUEST_H_
+
+/**
+ * @file
+ *
+ * @brief This file contains the protected interface structures, constants,
+ * and methods for the SCIF_SAS_REQUEST object. This object provides
+ * the common data and behavior to SAS IO and task management
+ * request types.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif // __cplusplus
+
+#include <dev/isci/scil/sati_translator_sequence.h>
+#include <dev/isci/scil/sci_types.h>
+#include <dev/isci/scil/sci_status.h>
+#include <dev/isci/scil/sci_fast_list.h>
+#include <dev/isci/scil/sci_base_request.h>
+
+#define SCIF_SAS_RESPONSE_DATA_LENGTH 120
+
+struct SCIF_SAS_CONTROLLER;
+struct SCIF_SAS_REMOTE_DEVICE;
+struct SCIF_SAS_TASK_REQUEST;
+struct SCIF_SAS_REQUEST;
+
+typedef SCI_STATUS (*SCIF_SAS_REQUEST_COMPLETION_HANDLER_T)(
+ struct SCIF_SAS_CONTROLLER *,
+ struct SCIF_SAS_REMOTE_DEVICE *,
+ struct SCIF_SAS_REQUEST *,
+ SCI_STATUS *
+);
+
+/**
+ * @struct SCIF_SAS_STP_REQUEST
+ *
+ * @brief This structure contains all of the data specific to performing
+ * SATA/STP IO and TASK requests.
+ */
+typedef struct SCIF_SAS_STP_REQUEST
+{
+ /**
+ * This field contains the translation information utilized by SATI.
+ * For more information on this field please refer to
+ * SATI_TRANSLATOR_SEQUENCE.
+ */
+ SATI_TRANSLATOR_SEQUENCE_T sequence;
+
+ /**
+ * This field contains the ncq tag being utilized by this IO request.
+ * The NCQ tag value must be less than or equal to 31 (0 <= tag <= 31).
+ */
+ U8 ncq_tag;
+
+} SCIF_SAS_STP_REQUEST_T;
+
+/**
+ * @struct SCIF_SAS_REQUEST
+ *
+ * @brief The SCIF_SAS_REQUEST object abstracts the common SAS
+ * IO & task management data and behavior for the framework component.
+ */
+typedef struct SCIF_SAS_REQUEST
+{
+ /**
+ * All SAS request types (IO or Task management) have the SCI base
+ * request as their parent object.
+ */
+ SCI_BASE_REQUEST_T parent;
+
+ /**
+ * This field references the list of state specific handler methods to
+ * be utilized for this request instance.
+ */
+ SCI_BASE_REQUEST_STATE_HANDLER_T * state_handlers;
+
+ SCIF_SAS_REQUEST_COMPLETION_HANDLER_T protocol_complete_handler;
+
+ /**
+ * This field is utilized to communicate state information relating
+ * to this IO request and it's state transitions.
+ */
+ SCI_STATUS status;
+
+ /**
+ * This field represents the remote device object to which this IO
+ * request is destined.
+ */
+ struct SCIF_SAS_REMOTE_DEVICE * device;
+
+ /**
+ * This field references the request object that has asked that this
+ * request be terminated.
+ */
+ struct SCIF_SAS_TASK_REQUEST * terminate_requestor;
+
+ /**
+ * This field provides list specific information that enables a request
+ * to be placed in a list.
+ */
+ SCI_FAST_LIST_ELEMENT_T list_element;
+
+ /**
+ * This field indicates if the current request is one internally
+ * generated by the framework or if it is a user IO/task request.
+ */
+ BOOL is_internal;
+
+ /**
+ * This field indicates the current request is a high priority one.
+ * An internal request is always high priority. But an external request
+ * could be high priority.
+ */
+ BOOL is_high_priority;
+
+ /**
+ * This field indicates the current request should not be completed
+ * until a pending abort task set request is completed. For NCQ errors,
+ * it will allow waiting until the read log ext data is returned to
+ * to determine how to fail/abort the pending ios.
+ */
+ BOOL is_waiting_for_abort_task_set;
+
+ /**
+ * This field indicates the logical unit (LUN) for the request.
+ * This field is utilized during internal IO requests.
+ */
+ U32 lun;
+
+ /**
+ * This field specifies sata specific data for the reqeust object.
+ * This data is only valid for SATA requests.
+ */
+ SCIF_SAS_STP_REQUEST_T stp;
+
+ /**
+ * This field contains the handle for the SCI Core request object that is
+ * managed by this framework request.
+ */
+ SCI_IO_REQUEST_HANDLE_T core_object;
+
+} SCIF_SAS_REQUEST_T;
+
+void scif_sas_request_construct(
+ SCIF_SAS_REQUEST_T * fw_request,
+ struct SCIF_SAS_REMOTE_DEVICE * fw_device,
+ SCI_BASE_LOGGER_T * logger,
+ SCI_BASE_STATE_T * state_table
+);
+
+SCI_STATUS scif_sas_request_terminate_start(
+ SCIF_SAS_REQUEST_T * fw_request,
+ SCI_IO_REQUEST_HANDLE_T core_request
+);
+
+void scif_sas_request_terminate_complete(
+ SCIF_SAS_REQUEST_T * fw_request
+);
+
+#ifdef __cplusplus
+}
+#endif // __cplusplus
+
+#endif // _SCIF_SAS_REQUEST_H_
+
diff --git a/sys/dev/isci/scil/scif_sas_sati_binding.h b/sys/dev/isci/scil/scif_sas_sati_binding.h
new file mode 100644
index 0000000..99c9433
--- /dev/null
+++ b/sys/dev/isci/scil/scif_sas_sati_binding.h
@@ -0,0 +1,253 @@
+/*-
+ * 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.
+ *
+ * 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.
+ *
+ * $FreeBSD$
+ */
+#ifndef _SCIF_SAS_SATI_BINDING_H_
+#define _SCIF_SAS_SATI_BINDING_H_
+
+/**
+ * @file
+ *
+ * @brief This file contains the SATI (SCSI to ATA Translation Implementation)
+ * callback implementations that can be implemented by the SCI
+ * Framework (or core in some cases).
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif // __cplusplus
+
+#include <dev/isci/scil/scif_user_callback.h>
+#include <dev/isci/scil/scif_io_request.h>
+#include <dev/isci/scil/scif_remote_device.h>
+#include <dev/isci/scil/scic_user_callback.h>
+#include <dev/isci/scil/scic_io_request.h>
+#include <dev/isci/scil/scic_remote_device.h>
+//#include <dev/isci/scil/scic_sds_request.h>
+//#include <dev/isci/scil/scu_task_context.h>
+#include <dev/isci/scil/sci_object.h>
+#include <dev/isci/scil/scif_sas_request.h>
+#include <dev/isci/scil/sci_base_memory_descriptor_list.h>
+#include <dev/isci/scil/scif_sas_stp_remote_device.h>
+#include <dev/isci/scil/scif_sas_remote_device.h>
+#include <dev/isci/scil/scif_sas_domain.h>
+#include <dev/isci/scil/scif_sas_controller.h>
+#include <dev/isci/scil/scic_sds_request.h>
+#include <dev/isci/sci_environment.h>
+
+// SATI callbacks fulfilled by the framework user.
+
+#define sati_cb_get_data_byte(scsi_io, byte_offset, value) \
+{ \
+ U8 * virtual_address = scif_cb_io_request_get_virtual_address_from_sgl( \
+ sci_object_get_association(scsi_io),(byte_offset)\
+ ); \
+ *(value) = *(virtual_address); \
+}
+
+#define sati_cb_set_data_byte(scsi_io, byte_offset, value) \
+{ \
+ U8 * virtual_address = scif_cb_io_request_get_virtual_address_from_sgl( \
+ sci_object_get_association(scsi_io),(byte_offset)\
+ ); \
+ *(virtual_address) = value; \
+}
+
+#define sati_cb_get_cdb_address(scsi_io) \
+ scif_cb_io_request_get_cdb_address(sci_object_get_association(scsi_io))
+
+#define sati_cb_get_cdb_length(scsi_io) \
+ scif_cb_io_request_get_cdb_length(sci_object_get_association(scsi_io))
+
+#define sati_cb_get_data_direction(scsi_io, sati_data_direction) \
+{ \
+ SCI_IO_REQUEST_DATA_DIRECTION sci_data_direction = \
+ scif_cb_io_request_get_data_direction( \
+ sci_object_get_association(scsi_io) \
+ ); \
+ if (sci_data_direction == SCI_IO_REQUEST_DATA_IN) \
+ *(sati_data_direction) = SATI_DATA_DIRECTION_IN; \
+ else if (sci_data_direction == SCI_IO_REQUEST_DATA_OUT) \
+ *(sati_data_direction) = SATI_DATA_DIRECTION_OUT; \
+ else if (sci_data_direction == SCI_IO_REQUEST_NO_DATA) \
+ *(sati_data_direction) = SATI_DATA_DIRECTION_NONE; \
+}
+
+#define sati_cb_get_lun(scsi_io) \
+ scif_cb_io_request_get_lun(sci_object_get_association(scsi_io))
+
+// SATI callbacks fulfilled by the framework.
+
+/**
+ * This method implements the functionality necessary to fulfill the
+ * SCSI-to-ATA Translation requirements. It ensures that the SAS
+ * address for the remote device associated with the supplied IO
+ * is written into the sas_address parameter.
+ * For more information on the parameters utilized in this method,
+ * please refer to sati_cb_device_get_sas_address().
+ */
+#define sati_cb_device_get_sas_address(scsi_io, sas_address) \
+{ \
+ SCIF_SAS_REQUEST_T* fw_request = (SCIF_SAS_REQUEST_T*)scsi_io; \
+ SCI_REMOTE_DEVICE_HANDLE_T scic_device \
+ = scif_remote_device_get_scic_handle(fw_request->device); \
+ scic_remote_device_get_sas_address(scic_device, sas_address); \
+}
+
+#define sati_cb_device_get_request_by_ncq_tag(scsi_io, ncq_tag, matching_req) \
+{ \
+ SCIF_SAS_REQUEST_T* fw_request = (SCIF_SAS_REQUEST_T*)scsi_io; \
+ SCIF_SAS_REMOTE_DEVICE_T* fw_device = fw_request->device; \
+ matching_req = scif_sas_stp_remote_device_get_request_by_ncq_tag(fw_device, ncq_tag); \
+}
+
+#define sati_cb_io_request_complete(scsi_io, completion_status) \
+{ \
+ SCIF_SAS_REQUEST_T* fw_request = (SCIF_SAS_REQUEST_T*)scsi_io; \
+ SCIF_SAS_REMOTE_DEVICE_T* fw_device = fw_request->device; \
+ SCIF_SAS_DOMAIN_T* fw_domain = fw_device->domain; \
+ SCIF_SAS_CONTROLLER_T* fw_controller = fw_domain->controller; \
+ scif_cb_io_request_complete( \
+ fw_controller, fw_device, fw_request, completion_status \
+ ); \
+}
+
+#define sati_cb_get_response_iu_address scif_io_request_get_response_iu_address
+#define sati_cb_get_task_function scic_cb_ssp_task_request_get_function
+
+#define sati_cb_get_ata_data_address(the_ata_io) \
+ scic_io_request_get_rx_frame( \
+ scif_io_request_get_scic_handle((the_ata_io)), 0 \
+ )
+
+#define sati_cb_get_h2d_register_fis_address(the_ata_io) \
+ (U8*) scic_stp_io_request_get_h2d_reg_address( \
+ scif_io_request_get_scic_handle((the_ata_io)) \
+ )
+
+#define sati_cb_get_d2h_register_fis_address(the_ata_io) \
+ (U8*) scic_stp_io_request_get_d2h_reg_address( \
+ scif_io_request_get_scic_handle((the_ata_io)) \
+ )
+
+#define sati_cb_allocate_dma_buffer(scsi_io, length, virt_address, phys_address_low, phys_address_high) \
+{ \
+ SCIF_SAS_REQUEST_T* fw_request = (SCIF_SAS_REQUEST_T*)scsi_io; \
+ SCI_PHYSICAL_MEMORY_DESCRIPTOR_T mde; \
+ SCI_PHYSICAL_ADDRESS phys_addr; \
+ mde.virtual_address = NULL; \
+ sci_cb_make_physical_address(mde.physical_address, 0, 0); \
+ sci_base_mde_construct( \
+ &mde, 4, length, SCI_MDE_ATTRIBUTE_PHYSICALLY_CONTIGUOUS \
+ ); \
+ scif_cb_controller_allocate_memory( \
+ fw_request->device->domain->controller, &mde \
+ ); \
+ scic_cb_io_request_get_physical_address(fw_request->device->domain->controller, \
+ NULL, \
+ mde.virtual_address, \
+ &phys_addr); \
+ *(virt_address) = mde.virtual_address; \
+ *(phys_address_low) = sci_cb_physical_address_lower(phys_addr); \
+ *(phys_address_high) = sci_cb_physical_address_upper(phys_addr); \
+}
+
+#define sati_cb_free_dma_buffer(scsi_io, virt_address) \
+{ \
+ SCIF_SAS_REQUEST_T* fw_request = (SCIF_SAS_REQUEST_T*)scsi_io; \
+ SCI_PHYSICAL_MEMORY_DESCRIPTOR_T mde; \
+ mde.virtual_address = virt_address; \
+ sci_cb_make_physical_address(mde.physical_address, 0, 0); \
+ sci_base_mde_construct( \
+ &mde, 4, 0, SCI_MDE_ATTRIBUTE_PHYSICALLY_CONTIGUOUS \
+ ); \
+ scif_cb_controller_free_memory( \
+ fw_request->device->domain->controller, &mde \
+ ); \
+}
+
+#define sati_cb_sgl_next_sge(scsi_io, ata_io, current_sge, next_sge) \
+{ \
+ /* For now just 2 SGEs are supported. */ \
+ SCIC_SDS_REQUEST_T *scic_request; \
+ SCU_SGL_ELEMENT_PAIR_T *sgl_pair; \
+ scic_request = scif_io_request_get_scic_handle((scsi_io)); \
+ sgl_pair = scic_sds_request_get_sgl_element_pair(scic_request, 0); \
+ \
+ if ((current_sge) == NULL) \
+ { \
+ *(next_sge) = &(sgl_pair->A); \
+ } \
+ else \
+ { \
+ *(next_sge) = &(sgl_pair->B); \
+ } \
+}
+
+#define sati_cb_sge_write(current_sge, phys_address_low, phys_address_high, byte_length) \
+{ \
+ SCU_SGL_ELEMENT_T * scu_sge = (SCU_SGL_ELEMENT_T*) (current_sge); \
+ scu_sge->address_upper = (phys_address_high); \
+ scu_sge->address_lower = (phys_address_low); \
+ scu_sge->length = (byte_length); \
+ scu_sge->address_modifier = 0; \
+}
+
+#define sati_cb_do_translate_response(request) \
+ (request)->stp.sequence.is_translate_response_required
+
+#ifdef __cplusplus
+}
+#endif // __cplusplus
+
+#endif // _SCIF_SAS_SATI_BINDING_H_
+
diff --git a/sys/dev/isci/scil/scif_sas_smp_activity_clear_affiliation.c b/sys/dev/isci/scil/scif_sas_smp_activity_clear_affiliation.c
new file mode 100644
index 0000000..998e147
--- /dev/null
+++ b/sys/dev/isci/scil/scif_sas_smp_activity_clear_affiliation.c
@@ -0,0 +1,252 @@
+/*-
+ * 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.
+ *
+ * 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 <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/**
+ * @file
+ *
+ * @brief This file contains the methods for the SCIF_SAS_SMP_REMMOTE object's
+ * clear affiliation activity.
+ */
+#include <dev/isci/scil/sci_controller.h>
+#include <dev/isci/scil/scif_sas_controller.h>
+#include <dev/isci/scil/scif_sas_remote_device.h>
+#include <dev/isci/scil/scif_sas_logger.h>
+
+#include <dev/isci/scil/scif_sas_smp_remote_device.h>
+#include <dev/isci/scil/scif_sas_smp_io_request.h>
+#include <dev/isci/scil/intel_sas.h>
+#include <dev/isci/scil/scic_io_request.h>
+#include <dev/isci/scil/scic_remote_device.h>
+#include <dev/isci/scil/scif_sas_smp_phy.h>
+
+//******************************************************************************
+//* P R I V A T E M E T H O D S
+//******************************************************************************
+
+/**
+ * @brief This method finds the next smp phy (from the anchor_phy) that link to
+ * a SATA end device.
+ *
+ * @param[in] fw_device the framework SMP device that is clearing affiliation for
+ * its remote SATA devices'
+ *
+ * @return SCIF_SAS_SMP_PHY_T a smp phy, to which clear affiliation phy control command
+ * is to be sent.
+ */
+static
+SCIF_SAS_SMP_PHY_T * scif_sas_smp_remote_device_find_next_smp_phy_link_to_sata(
+ SCIF_SAS_SMP_PHY_T * anchor_phy
+)
+{
+ SCI_FAST_LIST_ELEMENT_T * element = &anchor_phy->list_element;
+ SCIF_SAS_SMP_PHY_T * curr_smp_phy = NULL;
+
+ while (element != NULL)
+ {
+ curr_smp_phy = (SCIF_SAS_SMP_PHY_T*) sci_fast_list_get_object(element);
+ element = sci_fast_list_get_next(element);
+
+ if (curr_smp_phy->attached_device_type == SMP_END_DEVICE_ONLY
+ && curr_smp_phy->u.end_device != NULL)
+ {
+ SMP_DISCOVER_RESPONSE_PROTOCOLS_T dev_protocols;
+ scic_remote_device_get_protocols(
+ curr_smp_phy->u.end_device->core_object, &dev_protocols);
+
+ if (dev_protocols.u.bits.attached_stp_target)
+ return curr_smp_phy;
+ }
+ }
+
+ return NULL;
+}
+
+//******************************************************************************
+//* P U B L I C M E T H O D S
+//******************************************************************************
+
+/**
+ * @brief This method starts the clear affiliation activity for a
+ * smp device's remote SATA devices.
+ *
+ * @param[in] fw_device the framework SMP device that is clearing affiliation for
+ * its remote SATA devices.
+ *
+ * @return none
+ */
+void scif_sas_smp_remote_device_start_clear_affiliation(
+ SCIF_SAS_REMOTE_DEVICE_T * fw_device
+)
+{
+ SCIF_SAS_SMP_REMOTE_DEVICE_T * smp_device =
+ &fw_device->protocol_device.smp_device;
+
+ SCIF_SAS_SMP_PHY_T * phy_to_clear_affiliation = NULL;
+
+ if (smp_device->smp_phy_list.list_head != NULL)
+ {
+ phy_to_clear_affiliation =
+ scif_sas_smp_remote_device_find_next_smp_phy_link_to_sata(
+ (SCIF_SAS_SMP_PHY_T *)smp_device->smp_phy_list.list_head->object
+ );
+ }
+
+ if (phy_to_clear_affiliation != NULL)
+ {
+ smp_device->curr_clear_affiliation_phy = phy_to_clear_affiliation;
+
+ //set current activity
+ fw_device->protocol_device.smp_device.current_activity =
+ SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_CLEAR_AFFILIATION;
+
+ //Set current_smp_request to PHY CONTROL.
+ fw_device->protocol_device.smp_device.current_smp_request =
+ SMP_FUNCTION_PHY_CONTROL;
+
+ //reset discover_to_start flag.
+ fw_device->protocol_device.smp_device.scheduled_activity =
+ SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_NONE;
+
+ //build PHY Control (clear affiliation) to the phy.
+ scif_sas_smp_request_construct_phy_control(
+ fw_device->domain->controller,
+ fw_device,
+ PHY_OPERATION_CLEAR_AFFILIATION,
+ phy_to_clear_affiliation->phy_identifier,
+ NULL,
+ NULL
+ );
+
+ //issue DPC to start this request.
+ scif_cb_start_internal_io_task_schedule(
+ fw_device->domain->controller,
+ scif_sas_controller_start_high_priority_io,
+ fw_device->domain->controller
+ );
+ }
+ else
+ scif_sas_smp_remote_device_finish_clear_affiliation(fw_device);
+}
+
+
+/**
+ * @brief This method continues the clear affiliation activity for a
+ * smp device's remote SATA devices.
+ *
+ * @param[in] fw_device the framework SMP device that is clearing affiliation for
+ * its remote SATA devices.
+ *
+ * @return none
+ */
+void scif_sas_smp_remote_device_continue_clear_affiliation(
+ SCIF_SAS_REMOTE_DEVICE_T * fw_device
+)
+{
+ SCIF_SAS_SMP_REMOTE_DEVICE_T * smp_device =
+ &fw_device->protocol_device.smp_device;
+
+ //search from next immediate smp phy.
+ SCIF_SAS_SMP_PHY_T * phy_to_clear_affiliation = NULL;
+
+ if (smp_device->curr_clear_affiliation_phy->list_element.next != NULL)
+ {
+ phy_to_clear_affiliation =
+ scif_sas_smp_remote_device_find_next_smp_phy_link_to_sata(
+ smp_device->curr_clear_affiliation_phy->list_element.next->object
+ );
+ }
+
+ if (phy_to_clear_affiliation != NULL)
+ {
+ smp_device->curr_clear_affiliation_phy = phy_to_clear_affiliation;
+
+ //build PHY Control (clear affiliation) to the phy.
+ scif_sas_smp_request_construct_phy_control(
+ fw_device->domain->controller,
+ fw_device,
+ PHY_OPERATION_CLEAR_AFFILIATION,
+ phy_to_clear_affiliation->phy_identifier,
+ NULL,
+ NULL
+ );
+ }
+ else
+ scif_sas_smp_remote_device_finish_clear_affiliation(fw_device);
+}
+
+
+/**
+ * @brief This method finishes the clear affiliation activity for a
+ * smp device's remote SATA devices. It then notify the domain it fihishes
+ * the clear affiliation activity.
+ *
+ * @param[in] fw_device the framework SMP device that is clearing affiliation for
+ * its remote SATA devices.
+ *
+ * @return none
+ */
+void scif_sas_smp_remote_device_finish_clear_affiliation(
+ SCIF_SAS_REMOTE_DEVICE_T * fw_device
+)
+{
+ SCIF_SAS_DOMAIN_T * fw_domain = fw_device->domain;
+
+ scif_sas_smp_remote_device_clear(fw_device);
+
+ //let domain continue to clear affiliation on other smp devices.
+ scif_sas_domain_continue_clear_affiliation(fw_domain);
+}
+
+
diff --git a/sys/dev/isci/scil/scif_sas_smp_io_request.c b/sys/dev/isci/scil/scif_sas_smp_io_request.c
new file mode 100644
index 0000000..9a05232
--- /dev/null
+++ b/sys/dev/isci/scil/scif_sas_smp_io_request.c
@@ -0,0 +1,600 @@
+/*-
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 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 <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/**
+ * @file
+ *
+ * @brief This file contains the method implementations for the
+ * SCIF_SAS_SMP_IO_REQUEST object. The contents will implement SMP
+ * specific functionality.
+ */
+
+#include <dev/isci/scil/scif_sas_smp_io_request.h>
+#include <dev/isci/scil/scif_sas_logger.h>
+#include <dev/isci/scil/scif_sas_controller.h>
+#include <dev/isci/scil/sci_controller.h>
+
+#include <dev/isci/scil/sci_status.h>
+#include <dev/isci/scil/scic_io_request.h>
+#include <dev/isci/scil/scic_user_callback.h>
+
+#include <dev/isci/scil/intel_sas.h>
+
+/**
+ * @brief This routine is to fill in the space given by core the SMP command
+ * frame. Then it calls core's construction.
+ *
+ * @param[in] fw_io The smp io request to be constructed.
+ * @param[in] smp_command The SMP request filled according to SAS spec.
+ *
+ * @return none
+ */
+void scif_sas_smp_request_construct(
+ SCIF_SAS_REQUEST_T * fw_request,
+ SMP_REQUEST_T * smp_command
+)
+{
+ void * command_iu_address =
+ scic_io_request_get_command_iu_address(fw_request->core_object);
+
+ //copy the smp_command to the address;
+ memcpy( (char*) command_iu_address,
+ smp_command,
+ sizeof(SMP_REQUEST_T)
+ );
+
+ scic_io_request_construct_smp(fw_request->core_object);
+
+ fw_request->protocol_complete_handler
+ = NULL;
+}
+
+/**
+ * @brief This method will perform all of the construction common to all
+ * SMP requests (e.g. filling in the frame type, zero-out memory,
+ * etc.).
+ *
+ * @param[out] smp_request This parameter specifies the SMP request
+ * structure containing the SMP request to be sent to the
+ * SMP target.
+ * @param[in] smp_function This parameter specifies the SMP function to
+ * sent.
+ * @param[in] smp_response_length This parameter specifies the length of
+ * the response (in DWORDs) that will be returned for this
+ * SMP request.
+ * @param[in] smp_request_length This parameter specifies the length of
+ * the request (in DWORDs) that will be sent.
+ */
+static
+void scif_sas_smp_protocol_request_construct(
+ SMP_REQUEST_T * smp_request,
+ U8 smp_function,
+ U8 smp_response_length,
+ U8 smp_request_length
+)
+{
+ memset((char*)smp_request, 0, sizeof(SMP_REQUEST_T));
+
+ smp_request->header.smp_frame_type = SMP_FRAME_TYPE_REQUEST;
+ smp_request->header.function = smp_function;
+ smp_request->header.allocated_response_length = smp_response_length;
+ smp_request->header.request_length = smp_request_length;
+}
+
+
+/**
+ * @brief This method will allocate the internal IO request object and
+ * construct its contents based upon the supplied SMP request.
+ *
+ * @param[in] fw_controller This parameter specifies the controller object
+ * from which to allocate the internal IO request.
+ * @param[in] fw_device This parameter specifies the remote device for
+ * which the internal IO request is destined.
+ * @param[in] smp_request This parameter specifies the SMP request contents
+ * to be sent to the SMP target.
+ *
+ * @return void * The address of built scif sas smp request.
+ */
+static
+void * scif_sas_smp_request_build(
+ SCIF_SAS_CONTROLLER_T * fw_controller,
+ SCIF_SAS_REMOTE_DEVICE_T * fw_device,
+ SMP_REQUEST_T * smp_request,
+ void * external_request_object,
+ void * external_memory
+)
+{
+ if (external_memory != NULL && external_request_object != NULL)
+ {
+ scif_sas_io_request_construct_smp(
+ fw_controller,
+ fw_device,
+ external_memory,
+ (char *)external_memory + sizeof(SCIF_SAS_IO_REQUEST_T),
+ SCI_CONTROLLER_INVALID_IO_TAG,
+ smp_request,
+ external_request_object
+ );
+
+ return external_memory;
+ }
+ else
+ {
+ void * internal_io_memory;
+ internal_io_memory = scif_sas_controller_allocate_internal_request(fw_controller);
+ ASSERT(internal_io_memory != NULL);
+
+ if (internal_io_memory != NULL)
+ {
+ //construct, only when we got valid io memory.
+ scif_sas_internal_io_request_construct_smp(
+ fw_controller,
+ fw_device,
+ internal_io_memory,
+ SCI_CONTROLLER_INVALID_IO_TAG,
+ smp_request
+ );
+ }
+ else
+ {
+ SCIF_LOG_ERROR((
+ sci_base_object_get_logger(fw_controller),
+ SCIF_LOG_OBJECT_IO_REQUEST,
+ "scif_sas_smp_request_build, no memory available!\n"
+ ));
+ }
+
+ return internal_io_memory;
+ }
+}
+
+/**
+ * @brief construct a smp Report Genernal command to the fw_device.
+ *
+ * @param[in] fw_controller The framework controller object.
+ * @param[in] fw_device the framework device that the REPORT GENERAL command
+ * targets to.
+ *
+ * @return void * address to the built scif sas smp request.
+ */
+void * scif_sas_smp_request_construct_report_general(
+ SCIF_SAS_CONTROLLER_T * fw_controller,
+ SCIF_SAS_REMOTE_DEVICE_T * fw_device
+)
+{
+ SMP_REQUEST_T smp_report_general;
+
+ // Build the REPORT GENERAL request.
+ scif_sas_smp_protocol_request_construct(
+ &smp_report_general,
+ SMP_FUNCTION_REPORT_GENERAL,
+ sizeof(SMP_RESPONSE_REPORT_GENERAL_T) / sizeof(U32),
+ 0
+ );
+
+ smp_report_general.request.report_general.crc = 0;
+
+ SCIF_LOG_INFO((
+ sci_base_object_get_logger(fw_device),
+ SCIF_LOG_OBJECT_IO_REQUEST | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
+ "SMP REPORT GENERAL - Device:0x%x\n",
+ fw_device
+ ));
+
+ return scif_sas_smp_request_build(
+ fw_controller, fw_device, &smp_report_general, NULL, NULL);
+}
+
+/**
+ * @brief construct a SMP Report Manufacturer Info request to the fw_device.
+ *
+ * @param[in] fw_controller The framework controller object.
+ * @param[in] fw_device the framework device that the REPORT MANUFACTURER
+ * INFO targets to.
+ *
+ * @return void * address to the built scif sas smp request.
+ */
+void * scif_sas_smp_request_construct_report_manufacturer_info(
+ SCIF_SAS_CONTROLLER_T * fw_controller,
+ SCIF_SAS_REMOTE_DEVICE_T * fw_device
+)
+{
+ SMP_REQUEST_T smp_report_manufacturer_info;
+
+ scif_sas_smp_protocol_request_construct(
+ &smp_report_manufacturer_info,
+ SMP_FUNCTION_REPORT_MANUFACTURER_INFORMATION,
+ sizeof(SMP_RESPONSE_REPORT_MANUFACTURER_INFORMATION_T) / sizeof(U32),
+ 0
+ );
+
+ smp_report_manufacturer_info.request.report_general.crc = 0;
+
+ SCIF_LOG_INFO((
+ sci_base_object_get_logger(fw_device),
+ SCIF_LOG_OBJECT_IO_REQUEST | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
+ "SMP REPORT MANUFACTURER_INFO - Device:0x%x\n",
+ fw_device
+ ));
+
+ return scif_sas_smp_request_build(
+ fw_controller, fw_device, &smp_report_manufacturer_info, NULL, NULL
+ );
+}
+
+/**
+ * @brief construct a smp Discover command to the fw_device.
+ * @param[in] fw_controller The framework controller object.
+ * @param[in] fw_device the framework smp device that DISCOVER command targets
+ * to.
+ * @param[in] phy_identifier The phy index the DISCOVER command targets to.
+ *
+ * @return void * address to the built scif sas smp request.
+ */
+void * scif_sas_smp_request_construct_discover(
+ SCIF_SAS_CONTROLLER_T * fw_controller,
+ SCIF_SAS_REMOTE_DEVICE_T * fw_device,
+ U8 phy_identifier,
+ void * external_request_object,
+ void * external_memory
+)
+{
+ SMP_REQUEST_T smp_discover;
+
+ scif_sas_smp_protocol_request_construct(
+ &smp_discover,
+ SMP_FUNCTION_DISCOVER,
+ sizeof(SMP_RESPONSE_DISCOVER_T) / sizeof(U32),
+ sizeof(SMP_REQUEST_PHY_IDENTIFIER_T) / sizeof(U32)
+ );
+
+ smp_discover.request.discover.phy_identifier = phy_identifier;
+
+ SCIF_LOG_INFO((
+ sci_base_object_get_logger(fw_device),
+ SCIF_LOG_OBJECT_IO_REQUEST | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
+ "SMP DISCOVER - Device:0x%x PhyId:0x%x\n",
+ fw_device, phy_identifier
+ ));
+
+ return scif_sas_smp_request_build(
+ fw_controller, fw_device, &smp_discover,
+ external_request_object, external_memory
+ );
+}
+
+
+/**
+ * @brief construct a smp REPORT PHY SATA command to the fw_device.
+ * @param[in] fw_controller The framework controller object.
+ * @param[in] fw_device the framework smp device that DISCOVER command targets
+ * to.
+ * @param[in] phy_identifier The phy index the DISCOVER command targets to.
+ *
+ * @return void * address to the built scif sas smp request.
+ */
+void * scif_sas_smp_request_construct_report_phy_sata(
+ SCIF_SAS_CONTROLLER_T * fw_controller,
+ SCIF_SAS_REMOTE_DEVICE_T * fw_device,
+ U8 phy_identifier
+)
+{
+ SMP_REQUEST_T report_phy_sata;
+
+ scif_sas_smp_protocol_request_construct(
+ &report_phy_sata,
+ SMP_FUNCTION_REPORT_PHY_SATA,
+ sizeof(SMP_RESPONSE_REPORT_PHY_SATA_T) / sizeof(U32),
+ sizeof(SMP_REQUEST_PHY_IDENTIFIER_T) / sizeof(U32)
+ );
+
+ report_phy_sata.request.report_phy_sata.phy_identifier = phy_identifier;
+
+ SCIF_LOG_INFO((
+ sci_base_object_get_logger(fw_device),
+ SCIF_LOG_OBJECT_IO_REQUEST | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
+ "SMP REPORT PHY SATA - Device:0x%x PhyId:0x%x\n",
+ fw_device, phy_identifier
+ ));
+
+ return scif_sas_smp_request_build(
+ fw_controller, fw_device, &report_phy_sata, NULL, NULL);
+}
+
+
+/**
+ * @brief construct a smp REPORT PHY SATA command to the fw_device.
+ * @param[in] fw_controller The framework controller object.
+ * @param[in] fw_device the framework smp device that PHY CONTROL command
+ * targets to.
+ * @param[in] phy_identifier The phy index the DISCOVER command targets to.
+ *
+ * @return void * address to the built scif sas smp request.
+ */
+void * scif_sas_smp_request_construct_phy_control(
+ SCIF_SAS_CONTROLLER_T * fw_controller,
+ SCIF_SAS_REMOTE_DEVICE_T * fw_device,
+ U8 phy_operation,
+ U8 phy_identifier,
+ void * external_request_object,
+ void * external_memory
+)
+{
+ SMP_REQUEST_T phy_control;
+
+ scif_sas_smp_protocol_request_construct(
+ &phy_control,
+ SMP_FUNCTION_PHY_CONTROL,
+ 0,
+ sizeof(SMP_REQUEST_PHY_CONTROL_T) / sizeof(U32)
+ );
+
+ phy_control.request.phy_control.phy_operation = phy_operation;
+ phy_control.request.phy_control.phy_identifier = phy_identifier;
+
+ return scif_sas_smp_request_build(
+ fw_controller, fw_device, &phy_control,
+ external_request_object, external_memory
+ );
+}
+
+
+/**
+ * @brief construct a smp CONFIG ROUTE INFO command to the fw_device.
+ *
+ * @param[in] fw_controller The framework controller object.
+ * @param[in] fw_device the framework smp device that PHY CONTROL command
+ * targets to.
+ * @param[in] phy_id The phy, whose route entry at route_index is to be configured.
+ * @param[in] route_index The index of a phy's route entry that is to be configured.
+ * @param[in] destination_sas_address A sas address for an route table entry
+ *
+ * @return void * address to the built scif sas smp request.
+ */
+void * scif_sas_smp_request_construct_config_route_info(
+ struct SCIF_SAS_CONTROLLER * fw_controller,
+ struct SCIF_SAS_REMOTE_DEVICE * fw_device,
+ U8 phy_id,
+ U16 route_index,
+ SCI_SAS_ADDRESS_T destination_sas_address,
+ BOOL disable_expander_route_entry
+)
+{
+ SMP_REQUEST_T config_route_info;
+
+ scif_sas_smp_protocol_request_construct(
+ &config_route_info,
+ SMP_FUNCTION_CONFIGURE_ROUTE_INFORMATION,
+ 0,
+ sizeof(SMP_REQUEST_CONFIGURE_ROUTE_INFORMATION_T) / sizeof(U32)
+ );
+
+ config_route_info.request.configure_route_information.phy_identifier = phy_id;
+ config_route_info.request.configure_route_information.expander_route_index_high =
+ ((route_index & 0xff00) >> 8);
+ config_route_info.request.configure_route_information.expander_route_index =
+ route_index & 0xff;
+ config_route_info.request.configure_route_information.routed_sas_address[0] =
+ destination_sas_address.high;
+ config_route_info.request.configure_route_information.routed_sas_address[1] =
+ destination_sas_address.low;
+
+ if (disable_expander_route_entry == TRUE)
+ config_route_info.request.configure_route_information.disable_route_entry = 1;
+
+ return scif_sas_smp_request_build(
+ fw_controller, fw_device, &config_route_info,
+ NULL, NULL
+ );
+}
+
+/**
+ * @brief This method retry the internal smp request.
+ *
+ * @param[in] fw_device This parameter specifies the remote device for
+ * which the internal IO request is destined.
+ * @param[in] retry_count This parameter specifies how many times the
+ * old smp request has been retried.
+ *
+ * @return none.
+ */
+SCI_STATUS scif_sas_smp_internal_request_retry(
+ SCIF_SAS_REMOTE_DEVICE_T * fw_device
+)
+{
+ SCIF_SAS_CONTROLLER_T * fw_controller;
+ SCIF_SAS_IO_REQUEST_T * new_io;
+ void * new_request_memory = NULL;
+ U8 retry_count = fw_device->protocol_device.smp_device.io_retry_count;
+
+ SCIF_LOG_TRACE((
+ sci_base_object_get_logger(fw_device),
+ SCIF_LOG_OBJECT_IO_REQUEST | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
+ "scif_sas_smp_internal_request_retry(0x%x, 0x%x) time %d!\n",
+ fw_device, retry_count
+ ));
+
+ fw_controller = fw_device->domain->controller;
+
+ switch (fw_device->protocol_device.smp_device.current_smp_request)
+ {
+ case SMP_FUNCTION_REPORT_GENERAL:
+ new_request_memory = scif_sas_smp_request_construct_report_general(
+ fw_controller, fw_device
+ );
+ break;
+
+ case SMP_FUNCTION_DISCOVER:
+ //We are retrying an internal io. So we are going to allocate
+ //a new memory from internal io memory pool.
+ new_request_memory = scif_sas_smp_request_construct_discover(
+ fw_controller, fw_device,
+ fw_device->protocol_device.smp_device.current_activity_phy_index,
+ NULL, NULL
+ );
+
+ break;
+
+ case SMP_FUNCTION_REPORT_PHY_SATA:
+ new_request_memory = scif_sas_smp_request_construct_report_phy_sata(
+ fw_controller, fw_device,
+ fw_device->protocol_device.smp_device.current_activity_phy_index
+ );
+ break;
+
+ default:
+ //unsupported case, TBD
+ break;
+ } //end of switch
+
+ if (new_request_memory != NULL)
+ {
+ //set the retry count to new built smp request.
+ new_io = (SCIF_SAS_IO_REQUEST_T *) new_request_memory;
+ new_io->retry_count = ++retry_count;
+
+ //need to schedule the DPC here.
+ scif_cb_start_internal_io_task_schedule(
+ fw_controller,
+ scif_sas_controller_start_high_priority_io,
+ fw_controller
+ );
+
+ return SCI_SUCCESS;
+ }
+ else
+ return SCI_FAILURE_INSUFFICIENT_RESOURCES;
+
+}
+
+/**
+ * @brief This method retry the external smp request.
+ *
+ * @param[in] fw_device This parameter specifies the remote device for
+ * which the internal IO request is destined.
+ * @param[in] old_internal_io This parameter specifies the old smp request to be
+ * retried.
+ *
+ * @return none.
+ */
+SCI_STATUS scif_sas_smp_external_request_retry(
+ SCIF_SAS_IO_REQUEST_T * old_io
+)
+{
+ SCIF_SAS_REMOTE_DEVICE_T * fw_device = old_io->parent.device;
+ SCIF_SAS_CONTROLLER_T * fw_controller;
+ SCIF_SAS_IO_REQUEST_T * new_io;
+ void * new_request_memory = NULL;
+ U8 retry_count = old_io->retry_count;
+
+ SCIF_LOG_TRACE((
+ sci_base_object_get_logger(fw_device),
+ SCIF_LOG_OBJECT_IO_REQUEST | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
+ "scif_sas_smp_external_request_retry(0x%x) time %d!\n",
+ old_io
+ ));
+
+ fw_controller = fw_device->domain->controller;
+
+ // Before we construct new io using the same memory, we need to
+ // remove the IO from the list of outstanding requests on the domain
+ // so that we don't damage the domain's fast list of request.
+ sci_fast_list_remove_element(&old_io->parent.list_element);
+
+ switch (fw_device->protocol_device.smp_device.current_smp_request)
+ {
+ case SMP_FUNCTION_DISCOVER:
+ //we are retrying an external io, we are going to reuse the
+ //old io's memory. new_request_memory is same as old_io.
+ new_request_memory = scif_sas_smp_request_construct_discover(
+ fw_controller, fw_device,
+ fw_device->protocol_device.smp_device.current_activity_phy_index,
+ (void *)sci_object_get_association(old_io),
+ (void *)old_io
+ );
+
+ break;
+
+ case SMP_FUNCTION_PHY_CONTROL:
+ //Phy Control command always uses external io memory.
+ new_request_memory = scif_sas_smp_request_construct_phy_control(
+ fw_controller, fw_device, PHY_OPERATION_HARD_RESET,
+ fw_device->protocol_device.smp_device.current_activity_phy_index,
+ (void *)sci_object_get_association(old_io),
+ (void *)old_io
+ );
+
+ break;
+
+ default:
+ //unsupported case, TBD
+ break;
+ } //end of switch
+
+ //set the retry count to new built smp request.
+ new_io = (SCIF_SAS_IO_REQUEST_T *) new_request_memory;
+ new_io->retry_count = ++retry_count;
+
+ //put into the high priority queue.
+ sci_pool_put(fw_controller->hprq.pool, (POINTER_UINT) new_request_memory);
+
+ //schedule the DPC to start new io.
+ scif_cb_start_internal_io_task_schedule(
+ fw_controller, scif_sas_controller_start_high_priority_io, fw_controller
+ );
+
+ return SCI_SUCCESS;
+}
+
diff --git a/sys/dev/isci/scil/scif_sas_smp_io_request.h b/sys/dev/isci/scil/scif_sas_smp_io_request.h
new file mode 100644
index 0000000..6497cb8
--- /dev/null
+++ b/sys/dev/isci/scil/scif_sas_smp_io_request.h
@@ -0,0 +1,138 @@
+/*-
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 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.
+ *
+ * $FreeBSD$
+ */
+#ifndef _SCIF_SAS_SMP_REQUEST_H_
+#define _SCIF_SAS_SMP_REQUEST_H_
+
+/**
+ * @file
+ *
+ * @brief This file contains the protected interface structures, constants,
+ * and methods for the SCIF_SAS_SMP_REQUEST object.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif // __cplusplus
+
+#include <dev/isci/scil/intel_sas.h>
+#include <dev/isci/scil/sci_types.h>
+#include <dev/isci/scil/sci_status.h>
+#include <dev/isci/scil/sci_base_request.h>
+
+struct SCIF_SAS_REQUEST;
+struct SCIF_SAS_IO_REQUEST;
+struct SCIF_SAS_CONTROLLER;
+struct SCIF_SAS_REMOTE_DEVICE;
+struct SCIF_SAS_INTERNAL_IO_REQUEST;
+
+void scif_sas_smp_request_construct(
+ struct SCIF_SAS_REQUEST * fw_io,
+ SMP_REQUEST_T * smp_command
+);
+
+void * scif_sas_smp_request_construct_report_general(
+ struct SCIF_SAS_CONTROLLER * fw_controller,
+ struct SCIF_SAS_REMOTE_DEVICE * fw_device
+);
+
+void * scif_sas_smp_request_construct_report_manufacturer_info(
+ struct SCIF_SAS_CONTROLLER * fw_controller,
+ struct SCIF_SAS_REMOTE_DEVICE * fw_device
+);
+
+void * scif_sas_smp_request_construct_discover(
+ struct SCIF_SAS_CONTROLLER * fw_controller,
+ struct SCIF_SAS_REMOTE_DEVICE * fw_device,
+ U8 phy_identifier,
+ void * external_request_object,
+ void * external_memory
+);
+
+void * scif_sas_smp_request_construct_report_phy_sata(
+ struct SCIF_SAS_CONTROLLER * fw_controller,
+ struct SCIF_SAS_REMOTE_DEVICE * fw_device,
+ U8 phy_identifier
+);
+
+void * scif_sas_smp_request_construct_phy_control(
+ struct SCIF_SAS_CONTROLLER * fw_controller,
+ struct SCIF_SAS_REMOTE_DEVICE * fw_device,
+ U8 phy_operation,
+ U8 phy_identifier,
+ void * external_request_object,
+ void * external_memory
+);
+
+void * scif_sas_smp_request_construct_config_route_info(
+ struct SCIF_SAS_CONTROLLER * fw_controller,
+ struct SCIF_SAS_REMOTE_DEVICE * fw_device,
+ U8 phy_id,
+ U16 route_index,
+ SCI_SAS_ADDRESS_T destination_sas_Address,
+ BOOL disable_expander_route_entry
+);
+
+SCI_STATUS scif_sas_smp_internal_request_retry(
+ struct SCIF_SAS_REMOTE_DEVICE * fw_device
+);
+
+SCI_STATUS scif_sas_smp_external_request_retry(
+ struct SCIF_SAS_IO_REQUEST * old_io
+);
+
+#ifdef __cplusplus
+}
+#endif // __cplusplus
+
+#endif
diff --git a/sys/dev/isci/scil/scif_sas_smp_phy.c b/sys/dev/isci/scil/scif_sas_smp_phy.c
new file mode 100644
index 0000000..ad3a041
--- /dev/null
+++ b/sys/dev/isci/scil/scif_sas_smp_phy.c
@@ -0,0 +1,335 @@
+/*-
+ * 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.
+ *
+ * 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 <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/**
+ * @file
+ *
+ * @brief This file contains the implementation of the SCIF_SAS_SMP_PHY
+ * object.
+ */
+
+#include <dev/isci/scil/scif_sas_controller.h>
+#include <dev/isci/scil/scif_sas_smp_phy.h>
+#include <dev/isci/scil/scif_sas_smp_remote_device.h>
+
+//******************************************************************************
+//*
+//* P U B L I C M E T H O D S
+//*
+//******************************************************************************
+
+/**
+ * @brief This routine constructs a smp phy object for an expander phy and insert
+ * to owning expander device's smp_phy_list.
+ * @param[in] this_smp_phy The memory space to store a phy
+ * @param[in] owning_device The smp remote device that owns this smp phy.
+ * @param[in] expander_phy_id The expander phy id for this_smp_phy.
+ * @return None
+ */
+void scif_sas_smp_phy_construct(
+ SCIF_SAS_SMP_PHY_T * this_smp_phy,
+ SCIF_SAS_REMOTE_DEVICE_T * owning_device,
+ U8 expander_phy_id
+)
+{
+ memset(this_smp_phy, 0, sizeof(SCIF_SAS_SMP_PHY_T));
+
+ this_smp_phy->phy_identifier = expander_phy_id;
+ this_smp_phy->owning_device = owning_device;
+
+ sci_fast_list_element_init((this_smp_phy), (&this_smp_phy->list_element));
+
+ //insert to owning device's smp phy list.
+ sci_fast_list_insert_tail(
+ (&owning_device->protocol_device.smp_device.smp_phy_list),
+ (&this_smp_phy->list_element)
+ );
+}
+
+/**
+ * @brief This routine destructs a smp phy object for an expander phy and free the smp
+ * phy to controller's smp phy memory.
+ * @param[in] this_smp_phy The smp phy to be destructed.
+ *
+ * @return None
+ */
+void scif_sas_smp_phy_destruct(
+ SCIF_SAS_SMP_PHY_T * this_smp_phy
+)
+{
+ SCIF_SAS_REMOTE_DEVICE_T * owning_device = this_smp_phy->owning_device;
+ SCIF_SAS_CONTROLLER_T * fw_controller = owning_device->domain->controller;
+
+ if ( ( this_smp_phy->attached_device_type == SMP_EDGE_EXPANDER_DEVICE
+ || this_smp_phy->attached_device_type == SMP_FANOUT_EXPANDER_DEVICE)
+ && this_smp_phy->u.attached_phy != NULL )
+ {
+ //update the counterpart phy from the other smp phy list.
+ this_smp_phy->u.attached_phy->attached_device_type = SMP_NO_DEVICE_ATTACHED;
+ this_smp_phy->u.attached_phy->u.attached_phy = NULL;
+ }
+
+ //remove curr_smp_phy
+ sci_fast_list_remove_element(&this_smp_phy->list_element);
+ scif_sas_controller_free_smp_phy(fw_controller, this_smp_phy);
+}
+
+
+/**
+ * @brief This routine save a smp phy information based on discover response.
+ *
+ * @param[in] this_smp_phy The memory space to store a phy
+ * @param[in] attached_device A possible direct attached device to this phy.
+ *
+ * @param[in] discover_response The smp DISCOVER response for this_smp_phy.
+ * @return None
+ */
+void scif_sas_smp_phy_save_information(
+ SCIF_SAS_SMP_PHY_T * this_smp_phy,
+ SCIF_SAS_REMOTE_DEVICE_T * attached_device,
+ SMP_RESPONSE_DISCOVER_T * discover_response
+)
+{
+ ASSERT (this_smp_phy->owning_device != NULL);
+ ASSERT (this_smp_phy->phy_identifier == discover_response->phy_identifier);
+
+ this_smp_phy->attached_device_type = (U8)discover_response->u2.sas1_1.attached_device_type;
+ this_smp_phy->routing_attribute = (U8)discover_response->routing_attribute;
+ this_smp_phy->attached_sas_address = discover_response->attached_sas_address;
+ this_smp_phy->config_route_table_index_anchor = 0;
+
+ if (this_smp_phy->attached_device_type != SMP_EDGE_EXPANDER_DEVICE
+ && this_smp_phy->attached_device_type != SMP_FANOUT_EXPANDER_DEVICE)
+ {
+ //note, end_device field could be an end device, or a NULL value, but can't be expander device.
+ this_smp_phy->u.end_device = attached_device;
+ }
+ else
+ {
+ //if attached device type is expander, we will set u.attached_phy later when the
+ //the attached expander finish its discover on attached_phy.
+ ;
+ }
+}
+
+/**
+ * @brief This routine constructs a smp phy object for an expander phy.
+ * @param[in] this_smp_phy The memory space to store a phy
+ * @param[in] owning_device The smp remote device that owns this smp phy.
+ * @param[in] discover_response The smp DISCOVER response for this_smp_phy.
+ *
+ * @return Whether a smp phy has an attached phy and the pair of phy are set
+ * set to each other as attached phy successfully.
+ */
+SCI_STATUS scif_sas_smp_phy_set_attached_phy(
+ SCIF_SAS_SMP_PHY_T * this_smp_phy,
+ U8 attached_phy_identifier,
+ SCIF_SAS_REMOTE_DEVICE_T * attached_remote_device
+)
+{
+ //find the attached phy from its owning device by attached_phy_id.
+ SCIF_SAS_SMP_PHY_T * attached_smp_phy =
+ (SCIF_SAS_SMP_PHY_T *)scif_sas_smp_remote_device_find_smp_phy_by_id(
+ attached_phy_identifier,
+ &attached_remote_device->protocol_device.smp_device);
+
+ if (attached_smp_phy != NULL)
+ {
+ this_smp_phy->u.attached_phy = attached_smp_phy;
+ attached_smp_phy->u.attached_phy = this_smp_phy;
+
+ return SCI_SUCCESS;
+ }
+
+ return SCI_FAILURE;
+}
+
+
+/**
+ * @brief This method verify the routing attributes of a phy connection per
+ * specification.
+ *
+ * @param[in] this_smp_phy One smp phy belongs to a smp phy connection.
+ * @param[in] attached_smp_phy One smp phy belongs to a smp phy connection.
+ *
+ * @return Whether routing attributes of a phy connection is legal.
+ * @retval SCI_SUCCESS indicates a good phy connection.
+ * SCI_FAILURE indicates a illegal phy connection.
+ */
+SCI_STATUS scif_sas_smp_phy_verify_routing_attribute(
+ SCIF_SAS_SMP_PHY_T * this_smp_phy,
+ SCIF_SAS_SMP_PHY_T * attached_smp_phy
+)
+{
+ SCI_STATUS status = SCI_SUCCESS;
+
+ //expander phy with direct routing attribute can only connect to
+ //phy with direct routing attribute.
+ if ( this_smp_phy->routing_attribute == DIRECT_ROUTING_ATTRIBUTE
+ || attached_smp_phy->routing_attribute == DIRECT_ROUTING_ATTRIBUTE )
+ {
+ if ( (this_smp_phy->routing_attribute | attached_smp_phy->routing_attribute)
+ != DIRECT_ROUTING_ATTRIBUTE )
+ status = SCI_FAILURE;
+ }
+
+ if (this_smp_phy->routing_attribute == TABLE_ROUTING_ATTRIBUTE
+ && attached_smp_phy->routing_attribute == TABLE_ROUTING_ATTRIBUTE)
+ {
+ if ( ! this_smp_phy->owning_device->protocol_device.smp_device.is_table_to_table_supported
+ || !attached_smp_phy->owning_device->protocol_device.smp_device.is_table_to_table_supported )
+ status = SCI_FAILURE;
+ }
+
+ return status;
+}
+
+
+/**
+ * @brief This method find The next smp phy that is in the smp phy list and
+ * resides in the same wide port as this_smp_phy.
+ *
+ * @param[in] this_smp_phy The smp phy whose neighbor phy that is in the same
+ * same wide port is to be find.
+ *
+ * @return The next smp phy that is in the smp phy list and resides in the same
+ * wide port as this_smp_phy.
+ */
+SCIF_SAS_SMP_PHY_T * scif_sas_smp_phy_find_next_phy_in_wide_port(
+ SCIF_SAS_SMP_PHY_T * this_smp_phy
+)
+{
+ SCI_FAST_LIST_ELEMENT_T * next_phy_element = sci_fast_list_get_next(
+ &(this_smp_phy->list_element) );
+
+ SCIF_SAS_SMP_PHY_T * next_phy;
+
+ while (next_phy_element != NULL)
+ {
+ next_phy = (SCIF_SAS_SMP_PHY_T *)sci_fast_list_get_object(next_phy_element);
+
+ next_phy_element = sci_fast_list_get_next( &(next_phy->list_element));
+
+ if (next_phy->attached_sas_address.high == this_smp_phy->attached_sas_address.high
+ &&next_phy->attached_sas_address.low == this_smp_phy->attached_sas_address.low)
+ return next_phy;
+ }
+
+ return NULL;
+}
+
+
+/**
+ * @brief This method find the smp phy that resides in the middle of the same
+ * wide port as this_smp_phy.
+ *
+ * @param[in] this_smp_phy The smp phy who is the lowest order phy in a wide
+ * port .
+ *
+ * @return The next smp phy that is in the smp phy list and resides in the same
+ * wide port as this_smp_phy.
+ */
+SCIF_SAS_SMP_PHY_T * scif_sas_smp_phy_find_middle_phy_in_wide_port(
+ SCIF_SAS_SMP_PHY_T * this_smp_phy
+)
+{
+ SCIF_SAS_SMP_PHY_T * next_phy =
+ scif_sas_smp_phy_find_next_phy_in_wide_port(this_smp_phy);
+ SCIF_SAS_SMP_PHY_T * middle_phy = this_smp_phy;
+
+ //currently we assume a wide port could not be wider than X4. so the
+ //second phy is always the correct answer for x2, x3 or x4 wide port.
+ //For a narrow port, phy0 is the middle phy.
+ if (next_phy != NULL)
+ {
+ middle_phy = next_phy;
+ next_phy =
+ scif_sas_smp_phy_find_next_phy_in_wide_port(next_phy);
+ }
+
+ if (next_phy != NULL)
+ middle_phy = next_phy;
+
+ return middle_phy;
+}
+
+
+/**
+ * @brief This method find the smp phy that is the hishest order phy
+ * in the same wide port as this_smp_phy.
+ *
+ * @param[in] this_smp_phy The smp phy who is the lowest order phy in a wide
+ * port.
+ *
+ * @return The next smp phy that is in the smp phy list and resides in the same
+ * wide port as this_smp_phy.
+ */
+SCIF_SAS_SMP_PHY_T * scif_sas_smp_phy_find_highest_phy_in_wide_port(
+ SCIF_SAS_SMP_PHY_T * this_smp_phy
+)
+{
+ SCIF_SAS_SMP_PHY_T * next_phy =
+ scif_sas_smp_phy_find_next_phy_in_wide_port(this_smp_phy);
+ SCIF_SAS_SMP_PHY_T * highest_phy = this_smp_phy;
+
+ while(next_phy != NULL )
+ {
+ highest_phy = next_phy;
+ next_phy =
+ scif_sas_smp_phy_find_next_phy_in_wide_port(next_phy);
+ }
+
+ return highest_phy;
+}
diff --git a/sys/dev/isci/scil/scif_sas_smp_phy.h b/sys/dev/isci/scil/scif_sas_smp_phy.h
new file mode 100644
index 0000000..703d0be
--- /dev/null
+++ b/sys/dev/isci/scil/scif_sas_smp_phy.h
@@ -0,0 +1,186 @@
+/*-
+ * 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.
+ *
+ * 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.
+ *
+ * $FreeBSD$
+ */
+#ifndef _SCIF_SAS_SMP_PHY_H_
+#define _SCIF_SAS_SMP_PHY_H_
+
+/**
+ * @file
+ *
+ * @brief This file contains the protected interface structures, constants,
+ * and methods for the SCIF_SAS_SMP_PHY object.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif // __cplusplus
+
+#include <dev/isci/scil/scif_sas_remote_device.h>
+#include <dev/isci/scil/sci_fast_list.h>
+
+struct SCIF_SAS_CONTROLLER;
+struct SCIF_SAS_SMP_PHY;
+struct SCIF_SAS_REMOTE_DEVICE;
+
+/**
+ * @struct SCIF_SAS_SMP_PHY
+ *
+ * @brief This structure stores data for a smp phy of a smp device (expander).
+ */
+typedef struct SCIF_SAS_SMP_PHY
+{
+ /**
+ * A smp phy can either connect to a end device or another smp phy,
+ * This two conditions are mutual exclusive.
+ */
+ union{
+ /**
+ * The attached smp phy. This field has valid meaning when
+ * attached_device_type is expander.
+ */
+ struct SCIF_SAS_SMP_PHY * attached_phy;
+
+ /**
+ * The attached end device. This field has valid meaning when
+ * attached_device_type is end_device.
+ */
+ struct SCIF_SAS_REMOTE_DEVICE * end_device;
+ } u;
+
+ /**
+ * This field records the owning expander device this smp phy belongs to.
+ */
+ struct SCIF_SAS_REMOTE_DEVICE * owning_device;
+
+ /**
+ * The list element of this smp phy for the smp phy list of the ownig expander.
+ */
+ SCI_FAST_LIST_ELEMENT_T list_element;
+
+ /**
+ * This field records the attached sas address, retrieved from a DISCOVER
+ * response. Zero value is valid.
+ */
+ SCI_SAS_ADDRESS_T attached_sas_address;
+
+ /**
+ * This field records the attached device type, retrieved from a DISCOVER
+ * response.
+ */
+ U8 attached_device_type;
+
+ /**
+ * This field records the routing attribute, retrieved from a DISCOVER
+ * response.
+ */
+ U8 routing_attribute;
+
+ /**
+ * This field records the phy identifier of this smp phy, retrieved from a
+ * DISCOVER response.
+ */
+ U8 phy_identifier;
+
+ /**
+ * this field stores the last route index for previous round of config
+ * route table activity on a smp phy within one DISCOVER process.
+ */
+ U16 config_route_table_index_anchor;
+
+}SCIF_SAS_SMP_PHY_T;
+
+
+void scif_sas_smp_phy_construct(
+ SCIF_SAS_SMP_PHY_T * this_smp_phy,
+ struct SCIF_SAS_REMOTE_DEVICE * owning_device,
+ U8 expander_phy_id
+);
+
+void scif_sas_smp_phy_destruct(
+ SCIF_SAS_SMP_PHY_T * this_smp_phy
+);
+
+void scif_sas_smp_phy_save_information(
+ SCIF_SAS_SMP_PHY_T * this_smp_phy,
+ struct SCIF_SAS_REMOTE_DEVICE * attached_device,
+ SMP_RESPONSE_DISCOVER_T * discover_response
+);
+
+SCI_STATUS scif_sas_smp_phy_set_attached_phy(
+ SCIF_SAS_SMP_PHY_T * this_smp_phy,
+ U8 attached_phy_identifier,
+ struct SCIF_SAS_REMOTE_DEVICE * attached_remote_device
+);
+
+SCI_STATUS scif_sas_smp_phy_verify_routing_attribute(
+ SCIF_SAS_SMP_PHY_T * this_smp_phy,
+ SCIF_SAS_SMP_PHY_T * attached_smp_phy
+);
+
+SCIF_SAS_SMP_PHY_T * scif_sas_smp_phy_find_next_phy_in_wide_port(
+ SCIF_SAS_SMP_PHY_T * this_smp_phy
+);
+
+SCIF_SAS_SMP_PHY_T * scif_sas_smp_phy_find_middle_phy_in_wide_port(
+ SCIF_SAS_SMP_PHY_T * this_smp_phy
+);
+
+SCIF_SAS_SMP_PHY_T * scif_sas_smp_phy_find_highest_phy_in_wide_port(
+ SCIF_SAS_SMP_PHY_T * this_smp_phy
+);
+
+#ifdef __cplusplus
+}
+#endif // __cplusplus
+
+#endif // _SCIF_SAS_SMP_PHY_H_
diff --git a/sys/dev/isci/scil/scif_sas_smp_remote_device.c b/sys/dev/isci/scil/scif_sas_smp_remote_device.c
new file mode 100644
index 0000000..6df955a
--- /dev/null
+++ b/sys/dev/isci/scil/scif_sas_smp_remote_device.c
@@ -0,0 +1,2632 @@
+/*-
+ * 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.
+ *
+ * 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 <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/**
+ * @file
+ *
+ * @brief This file contains the methods for the SCIF_SAS_SMP_REMOTE_DEVICE object.
+ */
+#include <dev/isci/scil/sci_controller.h>
+#include <dev/isci/scil/scif_sas_controller.h>
+#include <dev/isci/scil/scif_sas_remote_device.h>
+#include <dev/isci/scil/scif_sas_logger.h>
+
+#include <dev/isci/scil/scif_sas_smp_remote_device.h>
+#include <dev/isci/scil/scif_sas_smp_io_request.h>
+#include <dev/isci/scil/intel_sas.h>
+#include <dev/isci/scil/scic_io_request.h>
+#include <dev/isci/scil/scic_remote_device.h>
+#include <dev/isci/scil/scif_sas_smp_phy.h>
+
+
+/**
+ * @brief This method resets all fields for a smp remote device. This is a
+ * private method.
+ *
+ * @param[in] fw_device the framework SMP device that is being
+ * constructed.
+ *
+ * @return none
+ */
+void scif_sas_smp_remote_device_clear(
+ SCIF_SAS_REMOTE_DEVICE_T * fw_device
+)
+{
+ //reset all fields in smp_device, indicate that the smp device is not
+ //in discovery process.
+ fw_device->protocol_device.smp_device.current_activity =
+ SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_NONE;
+
+ fw_device->protocol_device.smp_device.current_smp_request =
+ NOT_IN_SMP_ACTIVITY;
+
+ fw_device->protocol_device.smp_device.current_activity_phy_index = 0;
+
+ fw_device->protocol_device.smp_device.curr_config_route_index = 0;
+
+ fw_device->protocol_device.smp_device.config_route_smp_phy_anchor = NULL;
+
+ fw_device->protocol_device.smp_device.is_route_table_cleaned = FALSE;
+
+ fw_device->protocol_device.smp_device.curr_config_route_destination_smp_phy = NULL;
+
+ fw_device->protocol_device.smp_device.scheduled_activity =
+ SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_NONE;
+
+ fw_device->protocol_device.smp_device.io_retry_count = 0;
+
+ fw_device->protocol_device.smp_device.curr_clear_affiliation_phy = NULL;
+
+ if (fw_device->protocol_device.smp_device.smp_activity_timer != NULL)
+ {
+ //stop the timer
+ scif_cb_timer_stop(
+ fw_device->domain->controller,
+ fw_device->protocol_device.smp_device.smp_activity_timer
+ );
+
+ //destroy the timer
+ scif_cb_timer_destroy(
+ fw_device->domain->controller,
+ fw_device->protocol_device.smp_device.smp_activity_timer
+ );
+
+ fw_device->protocol_device.smp_device.smp_activity_timer = NULL;
+ }
+}
+
+
+/**
+ * @brief This method intializes a smp remote device.
+ *
+ * @param[in] fw_device the framework SMP device that is being
+ * constructed.
+ *
+ * @return none
+ */
+void scif_sas_smp_remote_device_construct(
+ SCIF_SAS_REMOTE_DEVICE_T * fw_device
+)
+{
+ SCIF_LOG_TRACE((
+ sci_base_object_get_logger(fw_device),
+ SCIF_LOG_OBJECT_REMOTE_DEVICE,
+ "scif_sas_smp_remote_device_construct(0x%x) enter\n",
+ fw_device
+ ));
+
+ fw_device->protocol_device.smp_device.number_of_phys = 0;
+ fw_device->protocol_device.smp_device.expander_route_indexes = 0;
+ fw_device->protocol_device.smp_device.is_table_to_table_supported = FALSE;
+ fw_device->protocol_device.smp_device.is_externally_configurable = FALSE;
+ fw_device->protocol_device.smp_device.is_able_to_config_others = FALSE;
+
+ sci_fast_list_init(&fw_device->protocol_device.smp_device.smp_phy_list);
+
+ scif_sas_smp_remote_device_clear(fw_device);
+}
+
+
+/**
+ * @brief This method decodes a smp response to this smp device and then
+ * continue the smp discover process.
+ *
+ * @param[in] fw_device The framework device that a SMP response targets to.
+ * @param[in] fw_request The pointer to an smp request whose response
+ * is to be decoded.
+ * @param[in] response_data The response data passed in.
+ *
+ * @return none
+ */
+SCI_STATUS scif_sas_smp_remote_device_decode_smp_response(
+ SCIF_SAS_REMOTE_DEVICE_T * fw_device,
+ SCIF_SAS_REQUEST_T * fw_request,
+ void * response_data,
+ SCI_IO_STATUS completion_status
+)
+{
+ SMP_RESPONSE_T * smp_response = (SMP_RESPONSE_T *)response_data;
+ SCI_STATUS status = SCI_FAILURE_UNSUPPORTED_INFORMATION_TYPE;
+
+ if (fw_device->protocol_device.smp_device.smp_activity_timer != NULL)
+ {
+ //if there is a timer being used, recycle it now. Since we may
+ //use the timer for other purpose next.
+ scif_cb_timer_destroy(
+ fw_device->domain->controller,
+ fw_device->protocol_device.smp_device.smp_activity_timer
+ );
+
+ fw_device->protocol_device.smp_device.smp_activity_timer = NULL;
+ }
+
+ //if Core set the status of this io to be RETRY_REQUIRED, we should
+ //retry the IO without even decode the response.
+ if (completion_status == SCI_FAILURE_RETRY_REQUIRED)
+ {
+ scif_sas_smp_remote_device_continue_current_activity(
+ fw_device, fw_request, SCI_FAILURE_RETRY_REQUIRED
+ );
+
+ return SCI_FAILURE_RETRY_REQUIRED;
+ }
+
+ //check the current smp request, decide what's next smp request to issue.
+ switch (fw_device->protocol_device.smp_device.current_smp_request)
+ {
+ case SMP_FUNCTION_REPORT_GENERAL:
+ {
+ //interpret REPORT GENERAL response.
+ status = scif_sas_smp_remote_device_decode_report_general_response(
+ fw_device, smp_response
+ );
+
+ break;
+ }
+
+ case SMP_FUNCTION_REPORT_MANUFACTURER_INFORMATION:
+ {
+ // No need to perform any parsing. Just want to see
+ // the information in a trace if necessary.
+ status = SCI_SUCCESS;
+ break;
+ }
+
+ case SMP_FUNCTION_DISCOVER:
+ {
+ if (fw_device->protocol_device.smp_device.current_activity ==
+ SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_DISCOVER)
+ {
+ //decode discover response
+ status = scif_sas_smp_remote_device_decode_initial_discover_response(
+ fw_device, smp_response
+ );
+ }
+ else if (fw_device->protocol_device.smp_device.current_activity ==
+ SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_TARGET_RESET)
+ {
+ //decode discover response as a polling result for a remote device
+ //target reset.
+ status =
+ scif_sas_smp_remote_device_decode_target_reset_discover_response(
+ fw_device, smp_response
+ );
+ }
+ else if (fw_device->protocol_device.smp_device.current_activity ==
+ SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_SATA_SPINUP_HOLD_RELEASE)
+ {
+ //decode discover response
+ status =
+ scif_sas_smp_remote_device_decode_spinup_hold_release_discover_response(
+ fw_device, smp_response
+ );
+ }
+ else
+ ASSERT(0);
+ break;
+ }
+
+ case SMP_FUNCTION_REPORT_PHY_SATA:
+ {
+ //decode the report phy sata response.
+ status = scif_sas_smp_remote_device_decode_report_phy_sata_response(
+ fw_device, smp_response
+ );
+
+ break;
+ }
+
+ case SMP_FUNCTION_PHY_CONTROL:
+ {
+ if (fw_device->protocol_device.smp_device.current_activity ==
+ SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_DISCOVER)
+ {
+ //decode the phy control response.
+ status = scif_sas_smp_remote_device_decode_discover_phy_control_response(
+ fw_device, smp_response
+ );
+ }
+ else if (fw_device->protocol_device.smp_device.current_activity ==
+ SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_TARGET_RESET)
+ {
+ //decode discover response as a polling result for a remote device
+ //target reset.
+ status = scif_sas_smp_remote_device_decode_target_reset_phy_control_response(
+ fw_device, smp_response
+ );
+ }
+ else if (fw_device->protocol_device.smp_device.current_activity ==
+ SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_CLEAR_AFFILIATION)
+ {
+ //currently don't care about the status.
+ status = SCI_SUCCESS;
+ }
+ else
+ ASSERT(0);
+ break;
+ }
+
+ case SMP_FUNCTION_CONFIGURE_ROUTE_INFORMATION:
+ {
+ //Note, currently we don't expect any abnormal status from config route info response,
+ //but there is a possibility that we exceed the maximum route index. We will take care
+ //of errors later.
+ status = scif_sas_smp_remote_device_decode_config_route_info_response(
+ fw_device, smp_response
+ );
+ break;
+ }
+
+ default:
+ //unsupported case, TBD
+ status = SCI_FAILURE_UNSUPPORTED_INFORMATION_TYPE;
+ break;
+ } //end of switch
+
+ //Continue current activity based on response's decoding status.
+ scif_sas_smp_remote_device_continue_current_activity(
+ fw_device, fw_request, status
+ );
+
+ return status;
+}
+
+
+/**
+ * @brief This method decodes a smp Report Genernal response to this smp device
+ * and then continue the smp discover process.
+ *
+ * @param[in] fw_device The framework device that the REPORT GENERAL command
+ * targets to.
+ * @param[in] report_general_response The pointer to a report general response
+ *
+ * @return none
+ */
+SCI_STATUS scif_sas_smp_remote_device_decode_report_general_response(
+ SCIF_SAS_REMOTE_DEVICE_T * fw_device,
+ SMP_RESPONSE_T * smp_response
+)
+{
+ SMP_RESPONSE_REPORT_GENERAL_T * report_general_response =
+ &smp_response->response.report_general;
+
+ SMP_RESPONSE_HEADER_T * response_header = &smp_response->header;
+
+ SCIF_LOG_TRACE((
+ sci_base_object_get_logger(fw_device),
+ SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
+ "scif_sas_smp_remote_device_decode_report_general_response(0x%x, 0x%x) enter\n",
+ fw_device, smp_response
+ ));
+
+ if (response_header->function_result != SMP_RESULT_FUNCTION_ACCEPTED)
+ {
+ /// @todo: more decoding work needed when the function_result is not
+ /// SMP_RESULT_FUNCTION_ACCEPTED. Retry might be the option for some
+ /// function result.
+ SCIF_LOG_ERROR((
+ sci_base_object_get_logger(fw_device),
+ SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
+ "Report General function result(0x%x)\n",
+ response_header->function_result
+ ));
+
+ return SCI_FAILURE;
+ }
+
+ //get info from report general response.
+ fw_device->protocol_device.smp_device.number_of_phys =
+ (U8)report_general_response->number_of_phys;
+
+ //currently there is byte swap issue in U16 data.
+ fw_device->protocol_device.smp_device.expander_route_indexes =
+ ((report_general_response->expander_route_indexes & 0xff) << 8) |
+ ((report_general_response->expander_route_indexes & 0xff00) >> 8);
+
+ fw_device->protocol_device.smp_device.is_table_to_table_supported =
+ (BOOL)report_general_response->table_to_table_supported;
+
+ fw_device->protocol_device.smp_device.is_externally_configurable =
+ (BOOL)report_general_response->configurable_route_table;
+
+ fw_device->protocol_device.smp_device.is_able_to_config_others =
+ (BOOL)report_general_response->configures_others;
+
+ //If the top level expander of a domain is able to configure others,
+ //no config route table is needed in the domain. Or else,
+ //we'll let all the externally configurable expanders in the damain
+ //configure route table.
+ if (fw_device->containing_device == NULL
+ && ! fw_device->protocol_device.smp_device.is_able_to_config_others)
+ fw_device->domain->is_config_route_table_needed = TRUE;
+
+ //knowing number of phys this expander has, we can allocate all the smp phys for
+ //this expander now if it is not done already.
+ if (fw_device->protocol_device.smp_device.smp_phy_list.element_count == 0)
+ scif_sas_smp_remote_device_populate_smp_phy_list(fw_device);
+
+ if (report_general_response->configuring)
+ return SCI_FAILURE_RETRY_REQUIRED;
+
+ return SCI_SUCCESS;
+}
+
+
+/**
+ * @brief This method decodes a smp Discover response to this smp device
+ * and then continue the smp discover process. This is only ever
+ * called for the very first discover stage during a given domain
+ * discovery process.
+ *
+ * @param[in] fw_device The framework device that the DISCOVER command
+ * targets to.
+ * @param[in] discover_response The pointer to a DISCOVER response
+ *
+ * @return none
+ */
+SCI_STATUS scif_sas_smp_remote_device_decode_initial_discover_response(
+ SCIF_SAS_REMOTE_DEVICE_T * fw_device,
+ SMP_RESPONSE_T * smp_response
+)
+{
+ SCIF_SAS_DOMAIN_T * fw_domain = fw_device->domain;
+ SCI_SAS_ADDRESS_T attached_device_address;
+ SCIF_SAS_REMOTE_DEVICE_T * attached_remote_device;
+ SMP_RESPONSE_DISCOVER_T * discover_response =
+ &smp_response->response.discover;
+ SMP_RESPONSE_HEADER_T * response_header = &smp_response->header;
+
+ SCIF_LOG_TRACE((
+ sci_base_object_get_logger(fw_device),
+ SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
+ "scif_sas_smp_remote_device_decode_initial_discover_response(0x%x, 0x%x) enter\n",
+ fw_device, smp_response
+ ));
+
+ if (response_header->function_result == SMP_RESULT_PHY_VACANT)
+ {
+ return SCI_SUCCESS;
+ }
+ else if (response_header->function_result != SMP_RESULT_FUNCTION_ACCEPTED)
+ {
+ /// @todo: more decoding work needed when the function_result is not
+ /// SMP_RESULT_FUNCTION_ACCEPTED. Retry might be the option for some
+ /// function result.
+ SCIF_LOG_ERROR((
+ sci_base_object_get_logger(fw_device),
+ SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
+ "Discover function result(0x%x)\n",
+ response_header->function_result
+ ));
+
+ return SCI_FAILURE;
+ }
+
+ //only if there is target device attached. We don't add device that is
+ //initiator only.
+ if ( ( discover_response->u2.sas1_1.attached_device_type
+ != SMP_NO_DEVICE_ATTACHED )
+ && ( discover_response->protocols.u.bits.attached_ssp_target
+ || discover_response->protocols.u.bits.attached_stp_target
+ || discover_response->protocols.u.bits.attached_smp_target
+ || discover_response->protocols.u.bits.attached_sata_device ) )
+ {
+ attached_device_address = discover_response->attached_sas_address;
+
+ attached_remote_device = (SCIF_SAS_REMOTE_DEVICE_T *)
+ scif_domain_get_device_by_sas_address(
+ fw_domain, &attached_device_address
+ );
+
+ //need to check if the device already existed in the domian.
+ if (attached_remote_device != SCI_INVALID_HANDLE)
+ {
+#if !defined(DISABLE_WIDE_PORTED_TARGETS)
+ if ( attached_remote_device->is_currently_discovered == TRUE
+ && attached_remote_device != fw_device->containing_device )
+ {
+ //a downstream wide port target is found.
+ attached_remote_device->device_port_width++;
+ }
+ else
+#endif //#if !defined(DISABLE_WIDE_PORTED_TARGETS)
+ {
+ //The device already existed. Mark the device as discovered.
+ attached_remote_device->is_currently_discovered = TRUE;
+ }
+
+#if !defined(DISABLE_WIDE_PORTED_TARGETS)
+ if (attached_remote_device->device_port_width !=
+ scic_remote_device_get_port_width(attached_remote_device->core_object)
+ && discover_response->protocols.u.bits.attached_ssp_target
+ )
+ {
+ scif_sas_remote_device_update_port_width(
+ attached_remote_device, attached_remote_device->device_port_width);
+ }
+#endif //#if !defined(DISABLE_WIDE_PORTED_TARGETS)
+
+ if ( discover_response->protocols.u.bits.attached_smp_target
+ && attached_remote_device != fw_device->containing_device)
+ {
+ //another expander device is discovered. Its own smp discover will starts after
+ //this discover finishes.
+ attached_remote_device->protocol_device.smp_device.scheduled_activity =
+ SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_DISCOVER;
+ }
+ }
+ else
+ {
+ //report the discovery of a disk for all types of end device.
+ scif_cb_domain_ea_device_added(
+ fw_domain->controller, fw_domain, fw_device, discover_response
+ );
+
+ //get info from discover response to see what we found. And do
+ //extra work according to end device's protocol type.
+ if ( discover_response->protocols.u.bits.attached_ssp_target
+ || discover_response->protocols.u.bits.attached_smp_target)
+ {
+ //for SSP or SMP target, no extra work.
+ ;
+ }
+ else if ( (discover_response->protocols.u.bits.attached_stp_target)
+ || (discover_response->protocols.u.bits.attached_sata_device) )
+ {
+ // We treat a SATA Device bit the same as an attached STP
+ // target.
+ discover_response->protocols.u.bits.attached_stp_target = 1;
+
+ //kick off REPORT PHY SATA to the same phy.
+ fw_device->protocol_device.smp_device.current_smp_request =
+ SMP_FUNCTION_REPORT_PHY_SATA;
+ }
+ }
+ }
+ else if( (discover_response->u2.sas1_1.negotiated_physical_link_rate == SCI_SATA_SPINUP_HOLD
+ || discover_response->u4.sas2.negotiated_physical_link_rate == SCI_SATA_SPINUP_HOLD)
+ &&(discover_response->protocols.u.bits.attached_stp_target
+ || discover_response->protocols.u.bits.attached_sata_device)
+ )
+ {
+ attached_remote_device = scif_sas_domain_get_device_by_containing_device(
+ fw_domain,
+ fw_device,
+ discover_response->phy_identifier
+ );
+
+ if (attached_remote_device != SCI_INVALID_HANDLE)
+ {
+ //Here, the only reason a device already existed in domain but
+ //the initial discover rersponse shows it in SPINUP_HOLD, is that
+ //a device has been removed and coming back in SPINUP_HOLD before
+ //we detected. The possibility of this situation is very very rare.
+ //we need to remove the device then add it back using the new
+ //discover response.
+ scif_cb_domain_device_removed(
+ fw_domain->controller, fw_domain, attached_remote_device
+ );
+ }
+
+ discover_response->protocols.u.bits.attached_stp_target = 1;
+
+ //still report ea_device_added(). But this device will not be
+ //started during scif_remote_device_ea_construct().
+ scif_cb_domain_ea_device_added(
+ fw_domain->controller, fw_domain, fw_device, discover_response
+ );
+
+ //need to send Phy Control (RESET) to release the phy from spinup hold
+ //condition.
+ fw_device->protocol_device.smp_device.current_smp_request =
+ SMP_FUNCTION_PHY_CONTROL;
+ }
+
+ //update the smp phy info based on this DISCOVER response.
+ return scif_sas_smp_remote_device_save_smp_phy_info(
+ fw_device, discover_response);
+}
+
+
+/**
+ * @brief This method decodes a smp Report Phy Sata response to this
+ * smp device and then continue the smp discover process.
+ *
+ * @param[in] fw_device The framework device that the REPORT PHY SATA
+ * command targets to.
+ * @param[in] report_phy_sata_response The pointer to a REPORT PHY
+ * SATA response
+ *
+ * @return none
+ */
+SCI_STATUS scif_sas_smp_remote_device_decode_report_phy_sata_response(
+ SCIF_SAS_REMOTE_DEVICE_T * fw_device,
+ SMP_RESPONSE_T * smp_response
+)
+{
+ SMP_RESPONSE_REPORT_PHY_SATA_T * report_phy_sata_response =
+ &smp_response->response.report_phy_sata;
+
+ SMP_RESPONSE_HEADER_T * response_header = &smp_response->header;
+
+ SCIF_LOG_TRACE((
+ sci_base_object_get_logger(fw_device),
+ SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
+ "scif_sas_smp_remote_device_decode_report_phy_sata_response(0x%x, 0x%x) enter\n",
+ fw_device, smp_response
+ ));
+
+ if (response_header->function_result != SMP_RESULT_FUNCTION_ACCEPTED)
+ {
+ /// @todo: more decoding work needed when the function_result is not
+ /// SMP_RESULT_FUNCTION_ACCEPTED. Retry might be the option for some
+ /// function result.
+ SCIF_LOG_ERROR((
+ sci_base_object_get_logger(fw_device),
+ SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
+ "Report Phy Sata function result(0x%x)\n",
+ response_header->function_result
+ ));
+
+ return SCI_FAILURE;
+ }
+
+ scif_sas_remote_device_save_report_phy_sata_information(
+ report_phy_sata_response
+ );
+
+ // continue the discover process.
+ fw_device->protocol_device.smp_device.current_smp_request =
+ SMP_FUNCTION_DISCOVER;
+
+ return SCI_SUCCESS;
+}
+
+
+/**
+ * @brief This method decodes a smp Phy Control response to this smp device and
+ * then continue the smp TARGET RESET process.
+ *
+ * @param[in] fw_device The framework device that the Phy Control command
+ * targets to.
+ * @param[in] smp_response The pointer to a Phy Control response
+ * @param[in] fw_io The scif IO request that associates to this smp response.
+ *
+ * @return none
+ */
+SCI_STATUS scif_sas_smp_remote_device_decode_target_reset_phy_control_response(
+ SCIF_SAS_REMOTE_DEVICE_T * fw_device,
+ SMP_RESPONSE_T * smp_response
+)
+{
+ SMP_RESPONSE_HEADER_T * response_header = &smp_response->header;
+
+ SCI_STATUS status = SCI_SUCCESS;
+
+ SCIF_LOG_TRACE((
+ sci_base_object_get_logger(fw_device),
+ SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
+ "scif_sas_smp_remote_device_decode_target_reset_phy_control_response(0x%x, 0x%x) enter\n",
+ fw_device, smp_response
+ ));
+
+ if (response_header->function_result != SMP_RESULT_FUNCTION_ACCEPTED)
+ {
+ /// @todo: more decoding work needed when the function_result is not
+ /// SMP_RESULT_FUNCTION_ACCEPTED. Retry might be the option for some
+ /// function result.
+ SCIF_LOG_ERROR((
+ sci_base_object_get_logger(fw_device),
+ SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
+ "Phy Control function unaccepted result(0x%x)\n",
+ response_header->function_result
+ ));
+
+ status = SCI_FAILURE_RETRY_REQUIRED;
+ }
+
+ // phy Control succeeded.
+ return status;
+}
+
+/**
+ * @brief This method decodes a smp Phy Control response to this smp device and
+ * then continue the smp DISCOVER process.
+ *
+ * @param[in] fw_device The framework device that the Phy Control command
+ * targets to.
+ * @param[in] smp_response The pointer to a Phy Control response
+ *
+ * @return Almost always SCI_SUCCESS
+ */
+SCI_STATUS scif_sas_smp_remote_device_decode_discover_phy_control_response(
+ SCIF_SAS_REMOTE_DEVICE_T * fw_device,
+ SMP_RESPONSE_T * smp_response
+)
+{
+ SMP_RESPONSE_HEADER_T * response_header = &smp_response->header;
+
+ SCI_STATUS status = SCI_SUCCESS;
+
+ SCIF_LOG_TRACE((
+ sci_base_object_get_logger(fw_device),
+ SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
+ "scif_sas_smp_remote_device_decode_discover_phy_control_response(0x%x, 0x%x) enter\n",
+ fw_device, smp_response
+ ));
+
+ if (response_header->function_result != SMP_RESULT_FUNCTION_ACCEPTED)
+ {
+ /// @todo: more decoding work needed when the function_result is not
+ /// SMP_RESULT_FUNCTION_ACCEPTED. Retry might be the option for some
+ /// function result.
+ SCIF_LOG_ERROR((
+ sci_base_object_get_logger(fw_device),
+ SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
+ "Phy Control function unaccepted result(0x%x)\n",
+ response_header->function_result
+ ));
+
+ return SCI_FAILURE_RETRY_REQUIRED;
+ }
+
+ // continue the discover process.
+ fw_device->protocol_device.smp_device.current_smp_request =
+ SMP_FUNCTION_DISCOVER;
+
+ // phy Control succeeded.
+ return status;
+}
+
+
+/**
+ * @brief This method decodes a smp Discover response to this smp device
+ * and then continue the smp discover process.
+ *
+ * @param[in] fw_device The framework device that the DISCOVER command
+ * targets to.
+ * @param[in] discover_response The pointer to a DISCOVER response
+ *
+ * @return none
+ */
+SCI_STATUS scif_sas_smp_remote_device_decode_target_reset_discover_response(
+ SCIF_SAS_REMOTE_DEVICE_T * fw_device,
+ SMP_RESPONSE_T * smp_response
+)
+{
+ SCIF_SAS_DOMAIN_T * fw_domain;
+ SCI_SAS_ADDRESS_T attached_device_address;
+ SCIF_SAS_REMOTE_DEVICE_T * attached_remote_device;
+ SMP_RESPONSE_DISCOVER_T * discover_response =
+ &smp_response->response.discover;
+
+ SMP_RESPONSE_HEADER_T * response_header = &smp_response->header;
+
+ SCIF_LOG_TRACE((
+ sci_base_object_get_logger(fw_device),
+ SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
+ "scif_sas_smp_remote_device_decode_target_reset_discover_response(0x%x, 0x%x) enter\n",
+ fw_device, smp_response
+ ));
+
+ if (response_header->function_result != SMP_RESULT_FUNCTION_ACCEPTED)
+ {
+ /// @todo: more decoding work needed when the function_result is not
+ /// SMP_RESULT_FUNCTION_ACCEPTED. Retry might be the option for some
+ /// function result.
+ SCIF_LOG_ERROR((
+ sci_base_object_get_logger(fw_device),
+ SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
+ "Discover function result(0x%x)\n",
+ response_header->function_result
+ ));
+
+ return SCI_FAILURE_RETRY_REQUIRED;
+ }
+
+ //only if there is device attached.
+ if ( discover_response->u2.sas1_1.attached_device_type != SMP_NO_DEVICE_ATTACHED )
+ {
+ fw_domain = fw_device->domain;
+ attached_device_address = discover_response->attached_sas_address;
+
+ attached_remote_device = (SCIF_SAS_REMOTE_DEVICE_T *)
+ scif_domain_get_device_by_sas_address(
+ fw_domain, &attached_device_address
+ );
+
+ // the device should have already existed in the domian.
+ ASSERT (attached_remote_device != SCI_INVALID_HANDLE);
+ return SCI_SUCCESS;
+ }
+ else
+ return SCI_FAILURE_RETRY_REQUIRED;
+}
+
+/**
+ * @brief This method decodes a smp Discover response to this smp device
+ * for SPINUP_HOLD_RELEASE activity. If a DISCOVER response says
+ * SATA DEVICE ATTACHED and has a valid NPL value, we call fw_device's
+ * start_handler(). But if a DISCOVER response still shows SPINUP
+ * in NPL state, we need to return retry_required status
+ *
+ * @param[in] fw_device The framework device that the DISCOVER command
+ * targets to.
+ * @param[in] discover_response The pointer to a DISCOVER response
+ *
+ * @return SCI_SUCCESS
+ * SCI_FAILURE_RETRY_REQUIRED
+ */
+SCI_STATUS scif_sas_smp_remote_device_decode_spinup_hold_release_discover_response(
+ SCIF_SAS_REMOTE_DEVICE_T * fw_device,
+ SMP_RESPONSE_T * smp_response
+)
+{
+ SMP_RESPONSE_DISCOVER_T * discover_response = &smp_response->response.discover;
+
+ SMP_RESPONSE_HEADER_T * response_header = &smp_response->header;
+
+ SCIF_LOG_TRACE((
+ sci_base_object_get_logger(fw_device),
+ SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
+ "scif_sas_smp_remote_device_decode_spinup_hold_release_discover_response(0x%x, 0x%x) enter\n",
+ fw_device, smp_response
+ ));
+
+ if (response_header->function_result != SMP_RESULT_FUNCTION_ACCEPTED)
+ {
+ /// @todo: more decoding work needed when the function_result is not
+ /// SMP_RESULT_FUNCTION_ACCEPTED. Retry might be the option for some
+ /// function result.
+ SCIF_LOG_ERROR((
+ sci_base_object_get_logger(fw_device),
+ SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
+ "Discover function result(0x%x)\n",
+ response_header->function_result
+ ));
+
+ return SCI_FAILURE;
+ }
+
+ if ( discover_response->u2.sas1_1.attached_device_type != SMP_NO_DEVICE_ATTACHED )
+ {
+ if (discover_response->u2.sas1_1.negotiated_physical_link_rate != SCI_SATA_SPINUP_HOLD
+ && discover_response->u4.sas2.negotiated_physical_link_rate != SCI_SATA_SPINUP_HOLD
+ && ( discover_response->protocols.u.bits.attached_stp_target
+ ||discover_response->protocols.u.bits.attached_sata_device )
+ )
+ {
+ SCIF_SAS_REMOTE_DEVICE_T * target_device =
+ scif_sas_domain_get_device_by_containing_device(
+ fw_device->domain,
+ fw_device,
+ fw_device->protocol_device.smp_device.current_activity_phy_index
+ );
+
+ //Need to update the device's connection rate. Its connection rate was SPINIP_HOLD.
+ scic_remote_device_set_max_connection_rate(
+ target_device->core_object,
+ discover_response->u2.sas1_1.negotiated_physical_link_rate
+ );
+
+ //Need to update the smp phy info too.
+ scif_sas_smp_remote_device_save_smp_phy_info(
+ fw_device, discover_response);
+
+ //This device has already constructed, only need to call start_handler
+ //of this device here.
+ return target_device->state_handlers->parent.start_handler(
+ &target_device->parent );
+ }
+ else
+ return SCI_FAILURE_RETRY_REQUIRED;
+ }
+ else
+ return SCI_FAILURE_RETRY_REQUIRED;
+}
+
+
+/**
+ * @brief This method decodes a smp CONFIG ROUTE INFO response to this smp
+ * device and then continue to config route table.
+ *
+ * @param[in] fw_device The framework device that the CONFIG ROUTE INFO command
+ * targets to.
+ * @param[in] smp_response The pointer to a CONFIG ROUTE INFO response
+ *
+ * @return none
+ */
+SCI_STATUS scif_sas_smp_remote_device_decode_config_route_info_response(
+ SCIF_SAS_REMOTE_DEVICE_T * fw_device,
+ SMP_RESPONSE_T * smp_response
+)
+{
+ SMP_RESPONSE_HEADER_T * response_header = &smp_response->header;
+
+ SCIF_LOG_TRACE((
+ sci_base_object_get_logger(fw_device),
+ SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
+ "scif_sas_smp_remote_device_decode_config_route_info_response(0x%x, 0x%x) enter\n",
+ fw_device, smp_response
+ ));
+
+ if (response_header->function_result == SMP_RESULT_INDEX_DOES_NOT_EXIST)
+ {
+ //case of exceeding max route index. We need to remove the devices that are not
+ //able to be edit to route table. The destination config route smp phy
+ //is used to remove devices.
+ scif_sas_smp_remote_device_cancel_config_route_table_activity(fw_device);
+
+ return SCI_FAILURE_EXCEED_MAX_ROUTE_INDEX;
+ }
+ else if (response_header->function_result != SMP_RESULT_FUNCTION_ACCEPTED)
+ {
+ /// @todo: more decoding work needed when the function_result is not
+ /// SMP_RESULT_FUNCTION_ACCEPTED. Retry might be the option for some
+ /// function result.
+ SCIF_LOG_ERROR((
+ sci_base_object_get_logger(fw_device),
+ SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
+ "Discover function result(0x%x)\n",
+ response_header->function_result
+ ));
+
+ return SCI_FAILURE;
+ }
+
+ return SCI_SUCCESS;
+}
+
+
+/**
+ * @brief This method starts the smp Discover process for an expander by
+ * sending Report General request.
+ *
+ * @param[in] fw_device The framework smp device that a command
+ * targets to.
+ *
+ * @return none
+ */
+void scif_sas_smp_remote_device_start_discover(
+ SCIF_SAS_REMOTE_DEVICE_T * fw_device
+)
+{
+ SCIF_SAS_CONTROLLER_T * fw_controller = fw_device->domain->controller;
+
+ SCIF_LOG_TRACE((
+ sci_base_object_get_logger(fw_device),
+ SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
+ "scif_sas_smp_remote_device_start_discover(0x%x) enter\n",
+ fw_device
+ ));
+
+ //For safety, clear the device again, there may be some config route table
+ //related info are not cleared yet.
+ scif_sas_smp_remote_device_clear(fw_device);
+
+ //set current activity
+ fw_device->protocol_device.smp_device.current_activity =
+ SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_DISCOVER;
+
+ //Set current_smp_request to REPORT GENERAL.
+ fw_device->protocol_device.smp_device.current_smp_request =
+ SMP_FUNCTION_REPORT_GENERAL;
+
+ //reset discover_to_start flag.
+ fw_device->protocol_device.smp_device.scheduled_activity =
+ SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_NONE;
+
+ //build the first smp request Report Genernal.
+ scif_sas_smp_request_construct_report_general(fw_controller, fw_device);
+
+ //issue DPC to start this request.
+ scif_cb_start_internal_io_task_schedule(
+ fw_controller,
+ scif_sas_controller_start_high_priority_io,
+ fw_controller
+ );
+}
+
+
+/**
+ * @brief This method continues the smp Discover process.
+ *
+ * @param[in] fw_device The framework smp device that a DISCOVER command
+ * targets to.
+ * @param[in] fw_request The pointer to an smp request whose response
+ * has been decoded.
+ * @param[in] status The decoding status of the smp request's response
+ *
+ * @return none
+ */
+void scif_sas_smp_remote_device_continue_current_activity(
+ SCIF_SAS_REMOTE_DEVICE_T * fw_device,
+ SCIF_SAS_REQUEST_T * fw_request,
+ SCI_STATUS status
+)
+{
+ SCIF_SAS_IO_REQUEST_T * fw_io = (SCIF_SAS_IO_REQUEST_T *)fw_request;
+ // save the retry count.
+ U8 io_retry_count = fw_io->retry_count;
+
+ if (fw_request->is_internal)
+ {
+ // Complete this internal io request now. We want to free this io before
+ // we create another SMP request, which is going to happen soon.
+ scif_sas_internal_io_request_complete(
+ fw_device->domain->controller,
+ (SCIF_SAS_INTERNAL_IO_REQUEST_T *)fw_request,
+ SCI_SUCCESS
+ );
+ }
+
+ if (fw_device->protocol_device.smp_device.current_activity ==
+ SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_DISCOVER)
+ {
+ if (status == SCI_SUCCESS)
+ { //continue the discover process.
+ scif_sas_smp_remote_device_continue_discover(fw_device);
+ }
+ else if (status == SCI_FAILURE_RETRY_REQUIRED)
+ {
+ //Retry the smp request. Since we are in the middle of Discover
+ //process, all the smp requests are internal. A new smp request
+ //will be created for retry.
+ U32 retry_wait_duration = (SCIF_DOMAIN_DISCOVER_TIMEOUT / 2) / SCIF_SAS_IO_RETRY_LIMIT;
+
+ if (io_retry_count < SCIF_SAS_IO_RETRY_LIMIT)
+ scif_sas_smp_remote_device_retry_internal_io (
+ fw_device, io_retry_count, retry_wait_duration);
+ else
+ scif_sas_smp_remote_device_fail_discover(fw_device);
+ }
+ else if (status == SCI_FAILURE_ILLEGAL_ROUTING_ATTRIBUTE_CONFIGURATION)
+ {
+ //remove this expander device and its child devices. No need to
+ //continue the discover on this device.
+ scif_sas_domain_remove_expander_device(fw_device->domain, fw_device);
+
+ //continue the domain's smp discover.
+ scif_sas_domain_continue_discover(fw_device->domain);
+ }
+ else
+ { //terminate the discover process.
+ scif_sas_smp_remote_device_fail_discover(fw_device);
+ }
+ }
+ else if (fw_device->protocol_device.smp_device.current_activity ==
+ SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_TARGET_RESET)
+ {
+ if (status == SCI_SUCCESS)
+ { //continue the target reset process.
+ scif_sas_smp_remote_device_continue_target_reset(
+ fw_device, fw_request);
+ }
+ else if (status == SCI_FAILURE_RETRY_REQUIRED)
+ {
+ //Retry the same smp request. Since we are in the middle of Target
+ //reset process, all the smp requests are using external resource.
+ //We will use the exactly same memory to retry.
+ if (io_retry_count < SCIF_SAS_IO_RETRY_LIMIT)
+ {
+ if (fw_device->protocol_device.smp_device.smp_activity_timer == NULL)
+ {
+ //create the timer to wait before retry.
+ fw_device->protocol_device.smp_device.smp_activity_timer =
+ scif_cb_timer_create(
+ (SCI_CONTROLLER_HANDLE_T *)fw_device->domain->controller,
+ (SCI_TIMER_CALLBACK_T)scif_sas_smp_external_request_retry,
+ (void*)fw_request
+ );
+ }
+ else
+ {
+ ASSERT(0);
+ }
+
+ //start the timer to wait
+ scif_cb_timer_start(
+ (SCI_CONTROLLER_HANDLE_T)fw_device->domain->controller,
+ fw_device->protocol_device.smp_device.smp_activity_timer,
+ SMP_REQUEST_RETRY_WAIT_DURATION //20 miliseconds
+ );
+ }
+ else
+ scif_sas_smp_remote_device_fail_target_reset(fw_device, fw_request);
+ }
+ else
+ //terminate the discover process.
+ scif_sas_smp_remote_device_fail_target_reset(fw_device, fw_request);
+ }
+ else if (fw_device->protocol_device.smp_device.current_activity ==
+ SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_SATA_SPINUP_HOLD_RELEASE)
+ {
+ SCIF_SAS_REMOTE_DEVICE_T * target_device =
+ scif_sas_domain_get_device_by_containing_device(
+ fw_device->domain,
+ fw_device,
+ fw_device->protocol_device.smp_device.current_activity_phy_index
+ );
+
+ if (status == SCI_SUCCESS)
+ {
+ //move on to next round of SPINUP_HOLD_REALSE activity.
+ scif_sas_smp_remote_device_sata_spinup_hold_release(fw_device);
+ }
+ else if (status == SCI_FAILURE_RETRY_REQUIRED)
+ {
+ U32 delay =
+ (scic_remote_device_get_suggested_reset_timeout(target_device->core_object) /
+ SCIF_SAS_IO_RETRY_LIMIT);
+
+ //Retry the smp request. Since we are in the middle of Discover
+ //process, all the smp requests are internal. A new smp request
+ //will be created for retry.
+ if (io_retry_count < SCIF_SAS_IO_RETRY_LIMIT)
+ {
+ scif_sas_smp_remote_device_retry_internal_io(
+ fw_device, io_retry_count, delay);
+ }
+ else //give up on this target device.
+ {
+ scif_sas_smp_remote_device_fail_target_spinup_hold_release(
+ fw_device , target_device);
+ }
+ }
+ else //give up on this target device.
+ scif_sas_smp_remote_device_fail_target_spinup_hold_release(
+ fw_device, target_device);
+ }
+ else if (fw_device->protocol_device.smp_device.current_activity ==
+ SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_CONFIG_ROUTE_TABLE)
+ {
+ SCI_FAST_LIST_ELEMENT_T * next_phy_element = sci_fast_list_get_next(
+ &(fw_device->protocol_device.smp_device.curr_config_route_destination_smp_phy->list_element) );
+
+ SCI_FAST_LIST_T * destination_smp_phy_list =
+ fw_device->protocol_device.smp_device.curr_config_route_destination_smp_phy->list_element.owning_list;
+
+ SCIF_SAS_SMP_PHY_T * next_phy_in_wide_port = NULL;
+
+ if (next_phy_element != NULL
+ && status != SCI_FAILURE_EXCEED_MAX_ROUTE_INDEX)
+ {
+ fw_device->protocol_device.smp_device.curr_config_route_index++;
+
+ fw_device->protocol_device.smp_device.curr_config_route_destination_smp_phy =
+ (SCIF_SAS_SMP_PHY_T *)sci_fast_list_get_object(next_phy_element);
+
+ // Update the anchor for config route index.
+ fw_device->protocol_device.smp_device.config_route_smp_phy_anchor->config_route_table_index_anchor =
+ fw_device->protocol_device.smp_device.curr_config_route_index;
+
+ scif_sas_smp_remote_device_configure_route_table(fw_device);
+ }
+ else if ( scif_sas_smp_remote_device_get_config_route_table_method(fw_device)
+ == SCIF_SAS_CONFIG_ROUTE_TABLE_ALL_PHYS
+ && (next_phy_in_wide_port = scif_sas_smp_phy_find_next_phy_in_wide_port(
+ fw_device->protocol_device.smp_device.config_route_smp_phy_anchor)
+ )!= NULL
+ )
+ {
+ //config the other phy in the same wide port
+ fw_device->protocol_device.smp_device.config_route_smp_phy_anchor =
+ next_phy_in_wide_port;
+
+ fw_device->protocol_device.smp_device.current_activity_phy_index =
+ fw_device->protocol_device.smp_device.config_route_smp_phy_anchor->phy_identifier;
+
+ fw_device->protocol_device.smp_device.curr_config_route_destination_smp_phy =
+ sci_fast_list_get_head(destination_smp_phy_list);
+
+ if (fw_device->protocol_device.smp_device.config_route_smp_phy_anchor->config_route_table_index_anchor != 0)
+ fw_device->protocol_device.smp_device.curr_config_route_index =
+ fw_device->protocol_device.smp_device.config_route_smp_phy_anchor->config_route_table_index_anchor + 1;
+ else
+ fw_device->protocol_device.smp_device.curr_config_route_index = 0;
+
+ scif_sas_smp_remote_device_configure_route_table(fw_device);
+ }
+ else if ( fw_device->protocol_device.smp_device.is_route_table_cleaned == FALSE)
+ {
+ fw_device->protocol_device.smp_device.current_activity =
+ SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_CLEAN_ROUTE_TABLE;
+
+ scif_sas_smp_remote_device_clean_route_table(fw_device);
+ }
+ else
+ {
+ //set this device's activity to NON.
+ fw_device->protocol_device.smp_device.current_activity =
+ SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_NONE;
+
+ //we need to notify domain that this device finished config route table, domain
+ //may pick up other activities (i.e. Discover) for other expanders.
+ scif_sas_domain_continue_discover(fw_device->domain);
+ }
+ }
+ else if (fw_device->protocol_device.smp_device.current_activity ==
+ SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_CLEAN_ROUTE_TABLE)
+ {
+ scif_sas_smp_remote_device_clean_route_table(fw_device);
+ }
+ else if (fw_device->protocol_device.smp_device.current_activity ==
+ SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_CLEAR_AFFILIATION)
+ {
+ scif_sas_smp_remote_device_continue_clear_affiliation(fw_device);
+ }
+}
+
+
+/**
+ * @brief This method continues the smp Discover process.
+ *
+ * @param[in] fw_device The framework smp device that a DISCOVER command
+ * targets to.
+ *
+ * @return none
+ */
+void scif_sas_smp_remote_device_continue_discover(
+ SCIF_SAS_REMOTE_DEVICE_T * fw_device
+)
+{
+ SCIF_SAS_DOMAIN_T * fw_domain = fw_device->domain;
+
+ SCIF_LOG_TRACE((
+ sci_base_object_get_logger(fw_device),
+ SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
+ "scif_sas_smp_remote_device_continue_discover(0x%x) enter\n",
+ fw_device
+ ));
+
+ switch (fw_device->protocol_device.smp_device.current_smp_request)
+ {
+ case SMP_FUNCTION_REPORT_GENERAL:
+ // send the REPORT MANUFACTURER_INFO request
+ fw_device->protocol_device.smp_device.current_smp_request =
+ SMP_FUNCTION_REPORT_MANUFACTURER_INFORMATION;
+
+ scif_sas_smp_request_construct_report_manufacturer_info(
+ fw_domain->controller, fw_device
+ );
+
+ break;
+
+ case SMP_FUNCTION_REPORT_MANUFACTURER_INFORMATION:
+ //send the first SMP DISCOVER request.
+ fw_device->protocol_device.smp_device.current_activity_phy_index = 0;
+ fw_device->protocol_device.smp_device.current_smp_request =
+ SMP_FUNCTION_DISCOVER;
+
+ scif_sas_smp_request_construct_discover(
+ fw_domain->controller,
+ fw_device,
+ fw_device->protocol_device.smp_device.current_activity_phy_index,
+ NULL, NULL
+ );
+ break;
+
+
+ case SMP_FUNCTION_DISCOVER:
+ fw_device->protocol_device.smp_device.current_activity_phy_index++;
+
+ if ( (fw_device->protocol_device.smp_device.current_activity_phy_index <
+ fw_device->protocol_device.smp_device.number_of_phys) )
+ {
+ scif_sas_smp_request_construct_discover(
+ fw_domain->controller,
+ fw_device,
+ fw_device->protocol_device.smp_device.current_activity_phy_index,
+ NULL, NULL
+ );
+ }
+ else
+ scif_sas_smp_remote_device_finish_initial_discover(fw_device);
+ break;
+
+
+ case SMP_FUNCTION_REPORT_PHY_SATA:
+ scif_sas_smp_request_construct_report_phy_sata(
+ fw_device->domain->controller,
+ fw_device,
+ fw_device->protocol_device.smp_device.current_activity_phy_index
+ );
+
+ break;
+
+
+ case SMP_FUNCTION_PHY_CONTROL:
+ scif_sas_smp_request_construct_phy_control(
+ fw_device->domain->controller,
+ fw_device,
+ PHY_OPERATION_HARD_RESET,
+ fw_device->protocol_device.smp_device.current_activity_phy_index,
+ NULL,
+ NULL
+ );
+
+ break;
+
+ default:
+ break;
+ }
+}
+
+/**
+ * @brief This method finishes the initial smp DISCOVER process. There
+ * may be a spinup_hold release phase following of initial discover,
+ * depending on whether there are SATA device in the domain
+ * in SATA_SPINUP_HOLD condition.
+ *
+ * @param[in] fw_device The framework smp device that finishes all the
+ * DISCOVER requests.
+ *
+ * @return none
+ */
+void scif_sas_smp_remote_device_finish_initial_discover(
+ SCIF_SAS_REMOTE_DEVICE_T * fw_device
+)
+{
+ SCIF_SAS_REMOTE_DEVICE_T * device_in_sata_spinup_hold =
+ scif_sas_domain_find_device_in_spinup_hold(fw_device->domain);
+
+ SCIF_LOG_TRACE((
+ sci_base_object_get_logger(fw_device),
+ SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
+ "scif_sas_smp_remote_device_finish_initial_discover(0x%x) enter\n",
+ fw_device
+ ));
+
+ if ( device_in_sata_spinup_hold != NULL )
+ {
+ //call the common private routine to reset all fields of this smp device.
+ scif_sas_smp_remote_device_clear(fw_device);
+
+ //Move on to next activity SPINUP_HOLD_RELEASE
+ fw_device->protocol_device.smp_device.current_activity =
+ SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_SATA_SPINUP_HOLD_RELEASE;
+
+ //create the timer to delay a little bit before going to
+ //sata spinup hold release activity.
+ if (fw_device->protocol_device.smp_device.smp_activity_timer == NULL)
+ {
+ fw_device->protocol_device.smp_device.smp_activity_timer =
+ scif_cb_timer_create(
+ (SCI_CONTROLLER_HANDLE_T *)fw_device->domain->controller,
+ (SCI_TIMER_CALLBACK_T)scif_sas_smp_remote_device_sata_spinup_hold_release,
+ (void*)fw_device
+ );
+ }
+ else
+ {
+ ASSERT (0);
+ }
+
+ scif_cb_timer_start(
+ (SCI_CONTROLLER_HANDLE_T)fw_device->domain->controller,
+ fw_device->protocol_device.smp_device.smp_activity_timer,
+ SMP_SPINUP_HOLD_RELEASE_WAIT_DURATION
+ );
+ }
+ else
+ scif_sas_smp_remote_device_finish_discover(fw_device);
+}
+
+
+/**
+ * @brief This method finishes the smp DISCOVER process.
+ *
+ * @param[in] fw_device The framework smp device that finishes all the
+ * DISCOVER requests.
+ *
+ * @return none
+ */
+void scif_sas_smp_remote_device_finish_discover(
+ SCIF_SAS_REMOTE_DEVICE_T * fw_device
+)
+{
+ SCIF_SAS_DOMAIN_T * fw_domain = fw_device->domain;
+
+ SCIF_LOG_TRACE((
+ sci_base_object_get_logger(fw_device),
+ SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
+ "scif_sas_smp_remote_device_finish_discover(0x%x) enter\n",
+ fw_device
+ ));
+
+ if ( fw_domain->is_config_route_table_needed
+ && fw_device->protocol_device.smp_device.smp_phy_list.list_head != NULL)
+ scif_sas_smp_remote_device_configure_upstream_expander_route_info(fw_device);
+
+ //call the common private routine to reset all fields of this smp device.
+ scif_sas_smp_remote_device_clear(fw_device);
+
+#ifdef SCI_SMP_PHY_LIST_DEBUG_PRINT
+ scif_sas_smp_remote_device_print_smp_phy_list(fw_device);
+#endif
+
+ //notify domain this smp device's discover finishes, it's up to domain
+ //to continue the discover process in a bigger scope.
+ scif_sas_domain_continue_discover(fw_domain);
+}
+
+
+/**
+ * @brief This method continues the smp Target Reset (Phy Control) process.
+ *
+ * @param[in] fw_device The framework smp device that a smp reset targets to.
+ *
+ * @return none
+ */
+void scif_sas_smp_remote_device_continue_target_reset(
+ SCIF_SAS_REMOTE_DEVICE_T * fw_device,
+ SCIF_SAS_REQUEST_T * fw_request
+)
+{
+ SCIF_SAS_CONTROLLER_T * fw_controller = fw_device->domain->controller;
+ SCIF_SAS_REMOTE_DEVICE_T * target_device =
+ scif_sas_domain_get_device_by_containing_device(
+ fw_device->domain,
+ fw_device,
+ fw_device->protocol_device.smp_device.current_activity_phy_index
+ );
+
+ SCIF_LOG_TRACE((
+ sci_base_object_get_logger(fw_device),
+ SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
+ "scif_sas_smp_remote_device_continue_target_reset(0x%x, 0x%x) enter\n",
+ fw_device, fw_request
+ ));
+
+ if (fw_device->protocol_device.smp_device.current_smp_request ==
+ SMP_FUNCTION_PHY_CONTROL)
+ {
+ //query the core remote device to get suggested reset timeout value
+ //then scale down by factor of 8 to get the duration of the pause
+ //before sending out Discover command to poll.
+ U32 delay =
+ (scic_remote_device_get_suggested_reset_timeout(target_device->core_object)/8);
+
+ //create the timer to send Discover command polling target device's
+ //coming back.
+ if (fw_device->protocol_device.smp_device.smp_activity_timer == NULL)
+ {
+ fw_device->protocol_device.smp_device.smp_activity_timer =
+ scif_cb_timer_create(
+ (SCI_CONTROLLER_HANDLE_T *)fw_controller,
+ (SCI_TIMER_CALLBACK_T)scif_sas_smp_remote_device_target_reset_poll,
+ (void*)fw_request
+ );
+ }
+ else
+ {
+ ASSERT(0);
+ }
+
+ //start the timer
+ scif_cb_timer_start(
+ (SCI_CONTROLLER_HANDLE_T)fw_controller,
+ fw_device->protocol_device.smp_device.smp_activity_timer,
+ delay
+ );
+ }
+ else if (fw_device->protocol_device.smp_device.current_smp_request ==
+ SMP_FUNCTION_DISCOVER)
+ {
+ //tell target reset successful
+ scif_sas_remote_device_target_reset_complete(
+ target_device, fw_request, SCI_SUCCESS);
+ }
+}
+
+/**
+ * @brief This routine is invoked by timer or when 2 BCN are received
+ * after Phy Control command. This routine will construct a
+ * Discover command to the same expander phy to poll the target
+ * device's coming back. This new request is then put into
+ * high priority queue and will be started by a DPC soon.
+ *
+ * @param[in] fw_request The scif request for smp activities.
+ */
+void scif_sas_smp_remote_device_target_reset_poll(
+ SCIF_SAS_REQUEST_T * fw_request
+)
+{
+ SCIF_SAS_REMOTE_DEVICE_T * fw_device = fw_request->device;
+ SCIF_SAS_CONTROLLER_T * fw_controller = fw_device->domain->controller;
+ void * new_command_handle;
+
+ SCIF_LOG_TRACE((
+ sci_base_object_get_logger(fw_device),
+ SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
+ "scif_sas_smp_remote_device_target_reset_poll(0x%x) enter\n",
+ fw_request
+ ));
+
+ // Before we construct new io using the same memory, we need to
+ // remove the IO from the list of outstanding requests on the domain
+ // so that we don't damage the domain's fast list of request.
+ sci_fast_list_remove_element(&fw_request->list_element);
+
+ fw_device->protocol_device.smp_device.current_smp_request =
+ SMP_FUNCTION_DISCOVER;
+
+ //sent smp discover request to poll on remote device's coming back.
+ //construct Discover command using the same memory as fw_request.
+ new_command_handle = scif_sas_smp_request_construct_discover(
+ fw_device->domain->controller,
+ fw_device,
+ fw_device->protocol_device.smp_device.current_activity_phy_index,
+ (void *)sci_object_get_association(fw_request),
+ (void *)fw_request
+ );
+
+ //put into the high priority queue.
+ sci_pool_put(fw_controller->hprq.pool, (POINTER_UINT) new_command_handle);
+
+ //schedule the DPC to start new Discover command.
+ scif_cb_start_internal_io_task_schedule(
+ fw_controller, scif_sas_controller_start_high_priority_io, fw_controller
+ );
+}
+
+
+/**
+ * @brief This method fails discover process.
+ *
+ * @param[in] fw_device The framework smp device that failed at current
+ * activity.
+ *
+ * @return none
+ */
+void scif_sas_smp_remote_device_fail_discover(
+ SCIF_SAS_REMOTE_DEVICE_T * fw_device
+)
+{
+ SCIF_LOG_TRACE((
+ sci_base_object_get_logger(fw_device),
+ SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
+ "scif_sas_smp_remote_device_fail_discover(0x%x) enter\n",
+ fw_device
+ ));
+
+ switch (fw_device->protocol_device.smp_device.current_smp_request)
+ {
+ case SMP_FUNCTION_REPORT_GENERAL:
+ case SMP_FUNCTION_REPORT_MANUFACTURER_INFORMATION:
+ scif_sas_smp_remote_device_finish_discover(fw_device);
+ break;
+
+ case SMP_FUNCTION_DISCOVER:
+ case SMP_FUNCTION_REPORT_PHY_SATA:
+ //Retry limit reached, we will continue to send DISCOVER to next phy.
+ fw_device->protocol_device.smp_device.current_smp_request =
+ SMP_FUNCTION_DISCOVER;
+
+ scif_sas_smp_remote_device_continue_discover(fw_device);
+ break;
+
+ default:
+ break;
+ }
+}
+
+
+/**
+ * @brief This method fails Target Reset.
+ *
+ * @param[in] fw_device The framework smp device that failed at current
+ * activity.
+ * @param[in] fw_request The smp request created for target reset
+ * using external resource.
+ *
+ * @return none
+ */
+void scif_sas_smp_remote_device_fail_target_reset(
+ SCIF_SAS_REMOTE_DEVICE_T * fw_device,
+ SCIF_SAS_REQUEST_T * fw_request
+)
+{
+ SCIF_SAS_REMOTE_DEVICE_T * target_device =
+ scif_sas_domain_get_device_by_containing_device(
+ fw_device->domain,
+ fw_device,
+ fw_device->protocol_device.smp_device.current_activity_phy_index
+ );
+
+ SCIF_LOG_TRACE((
+ sci_base_object_get_logger(fw_device),
+ SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
+ "scif_sas_smp_remote_device_fail_target_reset(0x%x, 0x%x, 0x%x) enter\n",
+ fw_device, target_device, fw_request
+ ));
+
+ //tell target reset failed
+ scif_sas_remote_device_target_reset_complete(
+ target_device, fw_request, SCI_FAILURE);
+}
+
+/**
+ * @brief This method init or continue the SATA SPINUP_HOLD RELEASE activity.
+ * This function searches domain's device list, find a device in STOPPED STATE
+ * and its connection_rate is SPINIP, then send DISCOVER command to its expander
+ * phy id to poll. But if searching the domain's device list for SATA devices on
+ * SPINUP_HOLD finds no device, the activity SPINUP_HOLD_RELEASE is finished.
+ * We then call fw_domain->device_start_complete_handler() for this smp-device.
+ *
+ * @param[in] fw_device The framework smp device that is on SATA SPINUP_HOLD_RELEASE
+ * activity.
+ *
+ * @return none
+ */
+void scif_sas_smp_remote_device_sata_spinup_hold_release(
+ SCIF_SAS_REMOTE_DEVICE_T * fw_device
+)
+{
+ SCIF_SAS_DOMAIN_T * fw_domain = fw_device->domain;
+ SCIF_SAS_CONTROLLER_T * fw_controller = fw_domain->controller;
+ SCIF_SAS_REMOTE_DEVICE_T * device_to_poll = NULL;
+
+ SCIF_LOG_TRACE((
+ sci_base_object_get_logger(fw_device),
+ SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
+ "scif_sas_smp_remote_device_sata_spinup_hold_release(0x%x) enter\n",
+ fw_device
+ ));
+
+ //search throught domain's device list to find a sata device on spinup_hold
+ //state to poll.
+ device_to_poll = scif_sas_domain_find_device_in_spinup_hold(fw_domain);
+
+ if (device_to_poll != NULL)
+ {
+ //send DISCOVER command to this device's expaner phy.
+ fw_device->protocol_device.smp_device.current_smp_request =
+ SMP_FUNCTION_DISCOVER;
+
+ fw_device->protocol_device.smp_device.current_activity_phy_index =
+ device_to_poll->expander_phy_identifier;
+
+ scif_sas_smp_request_construct_discover(
+ fw_domain->controller,
+ fw_device,
+ fw_device->protocol_device.smp_device.current_activity_phy_index,
+ NULL, NULL
+ );
+
+ //schedule the DPC to start new Discover command.
+ scif_cb_start_internal_io_task_schedule(
+ fw_controller, scif_sas_controller_start_high_priority_io, fw_controller
+ );
+ }
+ else //SATA SPINUP HOLD RELEASE activity is done.
+ scif_sas_smp_remote_device_finish_discover (fw_device);
+}
+
+
+/**
+ * @brief This method fail an action of SATA SPINUP_HOLD RELEASE on a single EA
+ * SATA device. It will remove a remote_device object for a sata device
+ * that fails to come out of spinup_hold.
+ *
+ * @param[in] fw_device The framework smp device that is on SATA SPINUP_HOLD_RELEASE
+ * activity.
+ * @param[in] target_device The expander attached device failed being brought out
+ * of SPINUP_HOLD state.
+ *
+ * @return none
+ */
+void scif_sas_smp_remote_device_fail_target_spinup_hold_release(
+ SCIF_SAS_REMOTE_DEVICE_T * fw_device,
+ SCIF_SAS_REMOTE_DEVICE_T * target_device
+)
+{
+ SCIF_SAS_DOMAIN_T * fw_domain = fw_device->domain;
+
+ SCIF_LOG_TRACE((
+ sci_base_object_get_logger(fw_device),
+ SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
+ "scif_sas_smp_remote_device_fail_target_spinup_hold_release(0x%x, 0x%x) enter\n",
+ fw_device, target_device
+ ));
+
+ //need to remove the device, since we have to give up on spinup_hold_release
+ //activity on this device.
+ scif_cb_domain_device_removed(
+ fw_domain->controller, fw_domain, target_device
+ );
+
+ //move on to next round of SPINUP_HOLD_REALSE activity.
+ scif_sas_smp_remote_device_sata_spinup_hold_release(fw_device);
+}
+
+
+/**
+ * @brief This method retry only internal IO for the smp device.
+ *
+ * @param[in] fw_device The framework smp device that has an smp request to retry.
+ * @param[in] io_retry_count current count for times the IO being retried.
+ * @param[in] delay The time delay before the io gets retried.
+ *
+ * @return none
+ */
+void scif_sas_smp_remote_device_retry_internal_io(
+ SCIF_SAS_REMOTE_DEVICE_T * fw_device,
+ U8 io_retry_count,
+ U32 delay
+)
+{
+ SCIF_LOG_TRACE((
+ sci_base_object_get_logger(fw_device),
+ SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
+ "scif_sas_smp_remote_device_retry_internal_io(0x%x, 0x%x, 0x%x) enter\n",
+ fw_device, io_retry_count, delay
+ ));
+
+ fw_device->protocol_device.smp_device.io_retry_count =
+ io_retry_count;
+
+ //create the timer for poll target device's coming back.
+ if (fw_device->protocol_device.smp_device.smp_activity_timer == NULL)
+ {
+ fw_device->protocol_device.smp_device.smp_activity_timer =
+ scif_cb_timer_create(
+ (SCI_CONTROLLER_HANDLE_T *)fw_device->domain->controller,
+ (SCI_TIMER_CALLBACK_T)scif_sas_smp_internal_request_retry,
+ (void*)fw_device
+ );
+ }
+ else
+ {
+ ASSERT(0);
+ }
+ //start the timer for a purpose of waiting.
+ scif_cb_timer_start(
+ (SCI_CONTROLLER_HANDLE_T)fw_device->domain->controller,
+ fw_device->protocol_device.smp_device.smp_activity_timer,
+ delay
+ );
+}
+
+
+/**
+ * @brief This method indicates whether an expander device is in Discover
+ * process.
+ *
+ * @param[in] fw_device The framework smp device.
+ *
+ * @return Whether an expander device is in the middle of discovery process.
+ */
+BOOL scif_sas_smp_remote_device_is_in_activity(
+ SCIF_SAS_REMOTE_DEVICE_T * fw_device
+)
+{
+ return(fw_device->protocol_device.smp_device.current_activity
+ != SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_NONE);
+}
+
+/**
+ * @brief This method search through the smp phy list of an expander to
+ * find a smp phy by its phy id of the expander.
+ *
+ * @param[in] phy_identifier The search criteria.
+ * @param[in] smp_remote_device The expander that owns the smp phy list.
+ *
+ * @return The found smp phy or a NULL pointer to indicate no smp phy is found.
+ */
+SCIF_SAS_SMP_PHY_T * scif_sas_smp_remote_device_find_smp_phy_by_id(
+ U8 phy_identifier,
+ SCIF_SAS_SMP_REMOTE_DEVICE_T * smp_remote_device
+)
+{
+ SCI_FAST_LIST_ELEMENT_T * element = smp_remote_device->smp_phy_list.list_head;
+ SCIF_SAS_SMP_PHY_T * curr_smp_phy = NULL;
+
+ while (element != NULL)
+ {
+ curr_smp_phy = (SCIF_SAS_SMP_PHY_T*) sci_fast_list_get_object(element);
+ element = sci_fast_list_get_next(element);
+
+ if (curr_smp_phy->phy_identifier == phy_identifier)
+ return curr_smp_phy;
+ }
+
+ return NULL;
+}
+
+/**
+ * @brief This method takes care of removing smp phy list of a smp devcie, which is
+ * about to be removed.
+ *
+ * @param[in] fw_device The expander device that is about to be removed.
+ *
+ * @return none.
+ */
+void scif_sas_smp_remote_device_removed(
+ SCIF_SAS_REMOTE_DEVICE_T * this_device
+)
+{
+ SCIF_SAS_SMP_REMOTE_DEVICE_T * smp_remote_device =
+ &this_device->protocol_device.smp_device;
+
+ SCI_FAST_LIST_ELEMENT_T * element = smp_remote_device->smp_phy_list.list_head;
+ SCIF_SAS_SMP_PHY_T * curr_smp_phy = NULL;
+
+ SCIF_LOG_TRACE((
+ sci_base_object_get_logger(this_device),
+ SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
+ "scif_sas_smp_remote_device_removed(0x%x) enter\n",
+ this_device
+ ));
+
+ //remove all the smp phys in this device's smp_phy_list, and the conterpart smp phys
+ //in phy connections.
+ while (element != NULL)
+ {
+ curr_smp_phy = (SCIF_SAS_SMP_PHY_T*) sci_fast_list_get_object(element);
+ element = sci_fast_list_get_next(element);
+
+ scif_sas_smp_phy_destruct(curr_smp_phy);
+ }
+
+ this_device->protocol_device.smp_device.number_of_phys = 0;
+ this_device->protocol_device.smp_device.expander_route_indexes = 0;
+ this_device->protocol_device.smp_device.is_table_to_table_supported = FALSE;
+ this_device->protocol_device.smp_device.is_externally_configurable = FALSE;
+ this_device->protocol_device.smp_device.is_able_to_config_others = FALSE;
+
+ scif_sas_smp_remote_device_clear(this_device);
+}
+
+
+/**
+ * @brief This method takes care of terminated smp request to a smp device. The
+ * terminated smp request is most likely timeout and being aborted. A timeout
+ * maybe due to OPEN REJECT (NO DESTINATION).
+ *
+ * @param[in] fw_device The expander device that a timed out smp request towards to.
+ * @param[in] fw_request A failed smp request that is terminated by scic.
+ *
+ * @return none.
+ */
+void scif_sas_smp_remote_device_terminated_request_handler(
+ SCIF_SAS_REMOTE_DEVICE_T * fw_device,
+ SCIF_SAS_REQUEST_T * fw_request
+)
+{
+ SCIF_LOG_TRACE((
+ sci_base_object_get_logger(fw_device),
+ SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
+ "scif_sas_smp_remote_device_terminated_request_handler(0x%x, 0x%x) enter\n",
+ fw_device, fw_request
+ ));
+
+ scif_sas_smp_remote_device_decode_smp_response(
+ fw_device, fw_request, NULL, SCI_FAILURE_RETRY_REQUIRED
+ );
+}
+
+
+/**
+ * @brief This method allocates and populates the smp phy list of a expander device.
+ *
+ * @param[in] fw_device The expander device, whose smp phy list is to be populated after
+ * getting REPORT GENERAL response.
+ *
+ * @return none.
+ */
+void scif_sas_smp_remote_device_populate_smp_phy_list(
+ SCIF_SAS_REMOTE_DEVICE_T * fw_device
+)
+{
+ SCIF_SAS_SMP_PHY_T * this_smp_phy = NULL;
+ U8 expander_phy_id = 0;
+
+ SCIF_LOG_TRACE((
+ sci_base_object_get_logger(fw_device),
+ SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
+ "scif_sas_smp_remote_device_populate_smp_phy_list(0x%x) enter\n",
+ fw_device
+ ));
+
+ for ( expander_phy_id = 0;
+ expander_phy_id < fw_device->protocol_device.smp_device.number_of_phys;
+ expander_phy_id++ )
+ {
+ this_smp_phy =
+ scif_sas_controller_allocate_smp_phy(fw_device->domain->controller);
+
+ ASSERT( this_smp_phy != NULL );
+
+ if ( this_smp_phy != NULL )
+ scif_sas_smp_phy_construct(this_smp_phy, fw_device, expander_phy_id);
+ }
+}
+
+
+/**
+ * @brief This method updates a smp phy of a expander device based on DISCOVER response.
+ *
+ * @param[in] fw_device The expander device, one of whose smp phys is to be updated.
+ * @param[in] discover_response The smp DISCOVER response.
+ *
+ * @return SCI_STATUS If a smp phy pair between expanders has invalid routing attribute,
+ * return SCI_FAILURE_ILLEGAL_ROUTING_ATTRIBUTE_CONFIGURATION, otherwise,
+ * return SCI_SUCCESS
+ */
+SCI_STATUS scif_sas_smp_remote_device_save_smp_phy_info(
+ SCIF_SAS_REMOTE_DEVICE_T * fw_device,
+ SMP_RESPONSE_DISCOVER_T * discover_response
+)
+{
+ SCI_STATUS status = SCI_SUCCESS;
+ SCIF_SAS_SMP_PHY_T * smp_phy = NULL;
+ SCIF_SAS_REMOTE_DEVICE_T * attached_device = NULL;
+
+ SCIF_LOG_TRACE((
+ sci_base_object_get_logger(fw_device),
+ SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
+ "scif_sas_smp_remote_device_save_smp_phy_info(0x%x, 0x%x) enter\n",
+ fw_device, discover_response
+ ));
+
+ smp_phy = scif_sas_smp_remote_device_find_smp_phy_by_id(
+ discover_response->phy_identifier,
+ &fw_device->protocol_device.smp_device
+ );
+
+ ASSERT( smp_phy != NULL );
+
+ //Note, attached_device could be NULL, not all the smp phy have to connected to a device.
+ attached_device = (SCIF_SAS_REMOTE_DEVICE_T *)
+ scif_domain_get_device_by_sas_address(
+ fw_device->domain, &discover_response->attached_sas_address);
+
+ if (smp_phy != NULL)
+ {
+ scif_sas_smp_phy_save_information(
+ smp_phy, attached_device, discover_response);
+ }
+
+ //handle the special case of smp phys between expanders.
+ if ( discover_response->protocols.u.bits.attached_smp_target )
+ {
+ //this fw_device is a child expander, just found its parent expander.
+ //And there is no smp_phy constructed yet, record this phy connection.
+ if ( attached_device != NULL
+ && attached_device == fw_device->containing_device )
+ {
+ //record the smp phy info, for this phy connects to a upstream smp device.
+ //the connection of a pair of smp phys are completed.
+ status = scif_sas_smp_phy_set_attached_phy(
+ smp_phy,
+ discover_response->attached_phy_identifier,
+ attached_device
+ );
+
+ if (status == SCI_SUCCESS)
+ {
+ //check the routing attribute for this phy and its containing device's
+ //expander_phy_routing_attribute.
+ if ( scif_sas_smp_phy_verify_routing_attribute(
+ smp_phy, smp_phy->u.attached_phy) != SCI_SUCCESS )
+ return SCI_FAILURE_ILLEGAL_ROUTING_ATTRIBUTE_CONFIGURATION;
+ }
+ }
+ }
+
+ return status;
+}
+
+#ifdef SCI_SMP_PHY_LIST_DEBUG_PRINT
+void scif_sas_smp_remote_device_print_smp_phy_list(
+ SCIF_SAS_REMOTE_DEVICE_T * fw_device
+)
+{
+ SCIF_SAS_SMP_REMOTE_DEVICE_T * smp_remote_device = &fw_device->protocol_device.smp_device;
+ SCI_FAST_LIST_ELEMENT_T * element = smp_remote_device->smp_phy_list.list_head;
+ SCIF_SAS_SMP_PHY_T * curr_smp_phy = NULL;
+
+ SCIF_LOG_ERROR((
+ sci_base_object_get_logger(fw_device),
+ SCIF_LOG_OBJECT_REMOTE_DEVICE,
+ "==========EXPANDER DEVICE (0x%x) smp phy list========== \n",
+ fw_device
+ ));
+
+ while (element != NULL)
+ {
+ curr_smp_phy = (SCIF_SAS_SMP_PHY_T*) sci_fast_list_get_object(element);
+ element = sci_fast_list_get_next(element);
+
+ //print every thing about a smp phy
+ SCIF_LOG_ERROR((
+ sci_base_object_get_logger(fw_device),
+ SCIF_LOG_OBJECT_REMOTE_DEVICE,
+ "SMP_PHY_%d (0x%x), attached device(0x%x), attached_sas_address(%x%x) attached_device_type(%d), routing_attribute(%d)\n",
+ curr_smp_phy->phy_identifier, curr_smp_phy,
+ curr_smp_phy->u.end_device,
+ curr_smp_phy->attached_sas_address.high, curr_smp_phy->attached_sas_address.low,
+ curr_smp_phy->attached_device_type,
+ curr_smp_phy->routing_attribute
+ ));
+ }
+}
+#endif
+
+
+/**
+ * @brief This method configure upstream expander(s)' (if there is any) route info.
+ *
+ * @param[in] this_device The expander device that is currently in discover process.
+ *
+ * @return none.
+ */
+void scif_sas_smp_remote_device_configure_upstream_expander_route_info(
+ SCIF_SAS_REMOTE_DEVICE_T * this_device
+)
+{
+ SCIF_SAS_REMOTE_DEVICE_T * curr_child_expander = this_device;
+ SCIF_SAS_REMOTE_DEVICE_T * curr_parent_expander =
+ scif_sas_remote_device_find_upstream_expander(this_device);
+
+ SCIF_SAS_REMOTE_DEVICE_T * curr_config_route_info_expander = NULL;
+
+ SCIF_LOG_TRACE((
+ sci_base_object_get_logger(this_device),
+ SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
+ "scif_sas_smp_remote_device_configure_upstream_expander_route_info(0x%x) enter\n",
+ this_device
+ ));
+
+ //traverse back to find root device.
+ while(curr_parent_expander != NULL )
+ {
+ //must set destination_smp_phy outside of find_upstream_expander() using the device
+ //that is just about to finish the discovery.
+ curr_parent_expander->protocol_device.smp_device.curr_config_route_destination_smp_phy =
+ (SCIF_SAS_SMP_PHY_T*)sci_fast_list_get_object(
+ this_device->protocol_device.smp_device.smp_phy_list.list_head);
+
+ curr_child_expander = curr_parent_expander;
+ curr_parent_expander = scif_sas_remote_device_find_upstream_expander(curr_child_expander);
+ }
+
+ //found the root device: curr_child_expander. configure it and its downstream expander(s) till
+ //this_device or a self-configuring expander that configures others;
+ curr_config_route_info_expander = curr_child_expander;
+
+ while ( curr_config_route_info_expander != NULL
+ && curr_config_route_info_expander != this_device
+ && curr_config_route_info_expander->protocol_device.smp_device.scheduled_activity
+ == SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_NONE
+ )
+ {
+ if (curr_config_route_info_expander->protocol_device.smp_device.is_externally_configurable)
+ {
+ SCIF_SAS_SMP_PHY_T * phy_being_config =
+ curr_config_route_info_expander->protocol_device.smp_device.config_route_smp_phy_anchor;
+
+ curr_config_route_info_expander->protocol_device.smp_device.curr_config_route_index =
+ phy_being_config->config_route_table_index_anchor;
+
+ if (curr_config_route_info_expander->protocol_device.smp_device.curr_config_route_index != 0)
+ curr_config_route_info_expander->protocol_device.smp_device.curr_config_route_index++;
+
+ curr_config_route_info_expander->protocol_device.smp_device.scheduled_activity =
+ SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_CONFIG_ROUTE_TABLE;
+
+ //Find a downstream expander that has curr_config_route_destination_smp_phy.owning device
+ //same as curr_config_route_info_expander.
+ curr_config_route_info_expander = scif_sas_remote_device_find_downstream_expander(
+ curr_config_route_info_expander);
+ }
+ else if (curr_config_route_info_expander->protocol_device.smp_device.is_able_to_config_others)
+ {
+ //no need to config route table to this expander and its children.
+ //find its downstream expander and clear the planned config route table activity.
+ SCIF_SAS_REMOTE_DEVICE_T * curr_downstream_expander =
+ scif_sas_remote_device_find_downstream_expander(
+ curr_config_route_info_expander);
+
+ scif_sas_smp_remote_device_clear(curr_config_route_info_expander);
+
+ while ( curr_downstream_expander != NULL
+ && curr_downstream_expander != this_device )
+ {
+ scif_sas_smp_remote_device_clear(curr_downstream_expander);
+ curr_downstream_expander =
+ scif_sas_remote_device_find_downstream_expander(
+ curr_config_route_info_expander);
+ }
+
+ break;
+ }
+ else
+ {
+ // current expander is a self-configuring expander, which is not externally
+ // configurable, and doesn't config others. we need to simply skip this expander.
+ curr_config_route_info_expander = scif_sas_remote_device_find_downstream_expander(
+ curr_config_route_info_expander);
+ }
+ }
+}
+
+/**
+ * @brief This method finds the immediate upstream expander of a given expander device.
+ *
+ * @param[in] this_device The given expander device, whose upstream expander is to be found.
+ *
+ * @return The immediate upstream expander. Or a NULL pointer if this_device is root already.
+ */
+SCIF_SAS_REMOTE_DEVICE_T * scif_sas_remote_device_find_upstream_expander(
+ SCIF_SAS_REMOTE_DEVICE_T * this_device
+)
+{
+ SCIF_SAS_SMP_REMOTE_DEVICE_T * smp_remote_device =
+ &this_device->protocol_device.smp_device;
+
+ SCIF_SAS_REMOTE_DEVICE_T * upstream_expander = NULL;
+
+ SCI_FAST_LIST_ELEMENT_T * element = smp_remote_device->smp_phy_list.list_head;
+ SCIF_SAS_SMP_PHY_T * curr_smp_phy = NULL;
+
+ SCIF_LOG_TRACE((
+ sci_base_object_get_logger(this_device),
+ SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
+ "scif_sas_smp_remote_device_configure_upstream_expander_route_info(0x%x) enter\n",
+ this_device
+ ));
+
+ while (element != NULL)
+ {
+ curr_smp_phy = (SCIF_SAS_SMP_PHY_T*) sci_fast_list_get_object(element);
+ element = sci_fast_list_get_next(element);
+
+ if ( curr_smp_phy->routing_attribute == SUBTRACTIVE_ROUTING_ATTRIBUTE
+ && ( curr_smp_phy->attached_device_type == SMP_EDGE_EXPANDER_DEVICE
+ || curr_smp_phy->attached_device_type == SMP_FANOUT_EXPANDER_DEVICE)
+ && curr_smp_phy->u.attached_phy != NULL
+ && curr_smp_phy->u.attached_phy->routing_attribute == TABLE_ROUTING_ATTRIBUTE )
+ {
+ //set the current_activity and current_config_route_index for that
+ //upstream expander.
+ upstream_expander = curr_smp_phy->u.attached_phy->owning_device;
+
+ upstream_expander->protocol_device.smp_device.current_smp_request =
+ SMP_FUNCTION_CONFIGURE_ROUTE_INFORMATION;
+
+ //if the upstream_expander's config route table method is config phy0 only or
+ //config all phys, the current activity phy is found.
+ upstream_expander->protocol_device.smp_device.config_route_smp_phy_anchor =
+ scif_sas_smp_remote_device_find_smp_phy_by_id(
+ curr_smp_phy->u.attached_phy->phy_identifier,
+ &(curr_smp_phy->u.attached_phy->owning_device->protocol_device.smp_device)
+ );
+
+ //if the upstream_expander's config route table method is config middle phy only
+ //config highest phy only, the current activity phy needs a update.
+ if ( scif_sas_smp_remote_device_get_config_route_table_method(upstream_expander)
+ == SCIF_SAS_CONFIG_ROUTE_TABLE_MIDDLE_PHY_ONLY )
+ {
+ upstream_expander->protocol_device.smp_device.config_route_smp_phy_anchor =
+ scif_sas_smp_phy_find_middle_phy_in_wide_port (
+ upstream_expander->protocol_device.smp_device.config_route_smp_phy_anchor
+ );
+ }
+ else if ( scif_sas_smp_remote_device_get_config_route_table_method(upstream_expander)
+ == SCIF_SAS_CONFIG_ROUTE_TABLE_HIGHEST_PHY_ONLY )
+ {
+ upstream_expander->protocol_device.smp_device.config_route_smp_phy_anchor =
+ scif_sas_smp_phy_find_highest_phy_in_wide_port (
+ upstream_expander->protocol_device.smp_device.config_route_smp_phy_anchor
+ );
+ }
+
+ upstream_expander->protocol_device.smp_device.current_activity_phy_index =
+ upstream_expander->protocol_device.smp_device.config_route_smp_phy_anchor->phy_identifier;
+
+ return upstream_expander;
+ }
+ }
+
+ return NULL;
+}
+
+
+/**
+ * @brief This method finds the immediate downstream expander of a given expander device.
+ *
+ * @param[in] this_device The given expander device, whose downstream expander is to be found.
+ *
+ * @return The immediate downstream expander. Or a NULL pointer if there is none.
+ */
+SCIF_SAS_REMOTE_DEVICE_T * scif_sas_remote_device_find_downstream_expander(
+ SCIF_SAS_REMOTE_DEVICE_T * this_device
+)
+{
+ SCIF_SAS_SMP_REMOTE_DEVICE_T * this_smp_remote_device =
+ &this_device->protocol_device.smp_device;
+
+ SCIF_SAS_REMOTE_DEVICE_T * downstream_expander = NULL;
+
+ SCI_FAST_LIST_ELEMENT_T * element = this_smp_remote_device->smp_phy_list.list_head;
+ SCIF_SAS_SMP_PHY_T * curr_smp_phy = NULL;
+
+ SCIF_LOG_TRACE((
+ sci_base_object_get_logger(this_device),
+ SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
+ "scif_sas_remote_device_find_downstream_expander(0x%x) enter\n",
+ this_device
+ ));
+
+ while (element != NULL)
+ {
+ curr_smp_phy = (SCIF_SAS_SMP_PHY_T*) sci_fast_list_get_object(element);
+ element = sci_fast_list_get_next(element);
+
+ if ( curr_smp_phy->routing_attribute == TABLE_ROUTING_ATTRIBUTE
+ && curr_smp_phy->attached_device_type == SMP_EDGE_EXPANDER_DEVICE
+ && curr_smp_phy->u.attached_phy != NULL)
+ {
+ //set the current_activity and current_config_route_index for that
+ //upstream expander.
+ downstream_expander = curr_smp_phy->u.attached_phy->owning_device;
+
+ if ( downstream_expander->protocol_device.smp_device.curr_config_route_destination_smp_phy != NULL
+ && downstream_expander->protocol_device.smp_device.curr_config_route_destination_smp_phy->owning_device ==
+ this_smp_remote_device->curr_config_route_destination_smp_phy->owning_device )
+ return downstream_expander;
+ }
+ }
+
+ return NULL;
+}
+
+
+/**
+ * @brief This method follows route table optimization rule to check if a destination_device
+ * should be recorded in the device_being_config's route table
+ *
+ * @param[in] device_being_config The upstream expander device, whose route table is being configured.
+ * @param[in] destination_smp_phy A smp phy whose attached device is potentially to be
+ * recorded in route table.
+ *
+ * @return BOOL This method returns TRUE if a destination_device should be recorded in route table.
+ * This method returns FALSE if a destination_device need not to be recorded
+ * in route table.
+ */
+BOOL scif_sas_smp_remote_device_do_config_route_info(
+ SCIF_SAS_REMOTE_DEVICE_T * device_being_config,
+ SCIF_SAS_SMP_PHY_T * destination_smp_phy
+)
+{
+ SCI_SAS_ADDRESS_T device_being_config_sas_address;
+
+ SCIF_LOG_TRACE((
+ sci_base_object_get_logger(device_being_config),
+ SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
+ "scif_sas_smp_remote_device_do_config_route_info(0x%x, 0x%x) enter\n",
+ device_being_config, destination_smp_phy
+ ));
+
+ scic_remote_device_get_sas_address(
+ device_being_config->core_object, &device_being_config_sas_address
+ );
+
+ //refer to SAS-2 spec 4.8.3, rule (b)
+ if ((destination_smp_phy->attached_sas_address.low == 0
+ && destination_smp_phy->attached_sas_address.high == 0)
+ && (destination_smp_phy->attached_device_type == SMP_NO_DEVICE_ATTACHED))
+ {
+ return FALSE;
+ }
+
+ //refer to SAS-2 spec 4.8.3, rule (c), self-referencing.
+ if (destination_smp_phy->attached_sas_address.high ==
+ device_being_config_sas_address.high
+ && destination_smp_phy->attached_sas_address.low ==
+ device_being_config_sas_address.low)
+ {
+ return FALSE;
+ }
+
+ //There will be no cases that falling into rule (a), (d), (e) to be excluded,
+ //based on our current mechanism of cofig route table.
+
+ return TRUE;
+}
+
+
+/**
+ * @brief This method configures device_being_config's route table for all the enclosed devices in
+ * a downstream smp device, destination_device.
+ *
+ * @param[in] device_being_config The upstream expander device, whose route table is being configured.
+ *
+ * @return None
+ */
+void scif_sas_smp_remote_device_configure_route_table(
+ SCIF_SAS_REMOTE_DEVICE_T * device_being_config
+)
+{
+ //go through the smp phy list of this_device.
+ SCI_FAST_LIST_ELEMENT_T * element =
+ &(device_being_config->protocol_device.smp_device.curr_config_route_destination_smp_phy->list_element);
+ SCIF_SAS_SMP_PHY_T * curr_smp_phy = NULL;
+
+ SCIF_LOG_TRACE((
+ sci_base_object_get_logger(device_being_config),
+ SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
+ "scif_sas_smp_remote_device_configure_route_table(0x%x) enter\n",
+ device_being_config
+ ));
+
+ device_being_config->protocol_device.smp_device.current_activity =
+ SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_CONFIG_ROUTE_TABLE;
+
+ while (element != NULL)
+ {
+ curr_smp_phy = (SCIF_SAS_SMP_PHY_T*) sci_fast_list_get_object(element);
+ element = sci_fast_list_get_next(element);
+
+ //check if this phy needs to be added to the expander's route table.
+ if (scif_sas_smp_remote_device_do_config_route_info(
+ device_being_config, curr_smp_phy) == TRUE )
+ {
+ SCIF_SAS_SMP_REMOTE_DEVICE_T * smp_remote_device =
+ &device_being_config->protocol_device.smp_device;
+
+ smp_remote_device->curr_config_route_destination_smp_phy =
+ curr_smp_phy;
+
+ //Then config this_device's route table entry at the phy and next route_index.
+ //send config_route_info using curr_smp_phy.phy_identifier and sas_address.
+ scif_sas_smp_request_construct_config_route_info(
+ device_being_config->domain->controller,
+ device_being_config,
+ smp_remote_device->current_activity_phy_index,
+ smp_remote_device->curr_config_route_index,
+ curr_smp_phy->attached_sas_address,
+ FALSE
+ );
+
+ //schedule the DPC.
+ scif_cb_start_internal_io_task_schedule(
+ device_being_config->domain->controller,
+ scif_sas_controller_start_high_priority_io,
+ device_being_config->domain->controller
+ );
+
+ //stop here, we need to wait for config route info's response then send
+ //the next one.
+ break;
+ }
+ }
+}
+
+
+/**
+ * @brief This method walks through an expander's route table to clean table
+ * attribute phys' route entries. This routine finds one table entry
+ * to clean and will be called repeatly till it finishes cleanning the
+ * whole table.
+ *
+ * @param[in] fw_device The expander device, whose route table entry is to be cleaned.
+ *
+ * @return None.
+ */
+void scif_sas_smp_remote_device_clean_route_table(
+ SCIF_SAS_REMOTE_DEVICE_T * fw_device
+)
+{
+ SCIF_SAS_SMP_PHY_T * smp_phy_being_config =
+ scif_sas_smp_remote_device_find_smp_phy_by_id(
+ fw_device->protocol_device.smp_device.current_activity_phy_index,
+ &(fw_device->protocol_device.smp_device)
+ );
+
+ SCIF_LOG_TRACE((
+ sci_base_object_get_logger(fw_device),
+ SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
+ "scif_sas_smp_remote_device_clean_route_table(0x%x) enter\n",
+ fw_device
+ ));
+
+ //from anchors, start to clean all the other route table entries.
+ fw_device->protocol_device.smp_device.curr_config_route_index++;
+
+ if ( fw_device->protocol_device.smp_device.curr_config_route_index >=
+ fw_device->protocol_device.smp_device.expander_route_indexes )
+ {
+ fw_device->protocol_device.smp_device.curr_config_route_index = 0;
+
+ do //find next table attribute PHY.
+ {
+ fw_device->protocol_device.smp_device.current_activity_phy_index++;
+ if (fw_device->protocol_device.smp_device.current_activity_phy_index ==
+ fw_device->protocol_device.smp_device.number_of_phys)
+ fw_device->protocol_device.smp_device.current_activity_phy_index=0;
+
+ //phy_index changed, so update the smp_phy_being_config.
+ smp_phy_being_config =
+ scif_sas_smp_remote_device_find_smp_phy_by_id(
+ fw_device->protocol_device.smp_device.current_activity_phy_index,
+ &(fw_device->protocol_device.smp_device)
+ );
+ } while( smp_phy_being_config->routing_attribute != TABLE_ROUTING_ATTRIBUTE );
+
+ if ( smp_phy_being_config->phy_identifier !=
+ fw_device->protocol_device.smp_device.config_route_smp_phy_anchor->phy_identifier)
+ {
+ if (smp_phy_being_config->config_route_table_index_anchor != 0)
+ fw_device->protocol_device.smp_device.curr_config_route_index =
+ smp_phy_being_config->config_route_table_index_anchor + 1;
+ else
+ fw_device->protocol_device.smp_device.curr_config_route_index = 0;
+ }
+ }
+
+ if ( !(fw_device->protocol_device.smp_device.current_activity_phy_index ==
+ fw_device->protocol_device.smp_device.config_route_smp_phy_anchor->phy_identifier
+ && fw_device->protocol_device.smp_device.curr_config_route_index == 0)
+ )
+ {
+ //clean this route entry.
+ scif_sas_smp_remote_device_clean_route_table_entry(fw_device);
+ }
+ else
+ {
+ fw_device->protocol_device.smp_device.is_route_table_cleaned = TRUE;
+
+ //set this device's activity to NON.
+ fw_device->protocol_device.smp_device.current_activity =
+ SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_NONE;
+
+ //we need to notify domain that this device finished config route table, domain
+ //may pick up other activities (i.e. Discover) for other expanders.
+ scif_sas_domain_continue_discover(fw_device->domain);
+ }
+}
+
+/**
+ * @brief This method cleans a device's route table antry.
+ *
+ * @param[in] fw_device The expander device, whose route table entry is to be cleaned.
+ *
+ * @return None.
+ */
+void scif_sas_smp_remote_device_clean_route_table_entry(
+ SCIF_SAS_REMOTE_DEVICE_T * fw_device
+)
+{
+ SCI_SAS_ADDRESS_T empty_sas_address;
+ SCIF_SAS_SMP_REMOTE_DEVICE_T * smp_remote_device =
+ &(fw_device->protocol_device.smp_device);
+
+ SCIF_LOG_TRACE((
+ sci_base_object_get_logger(fw_device),
+ SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
+ "scif_sas_smp_remote_device_clean_route_table(0x%x) enter\n",
+ fw_device
+ ));
+
+ empty_sas_address.high = 0;
+ empty_sas_address.low = 0;
+
+ scif_sas_smp_request_construct_config_route_info(
+ fw_device->domain->controller,
+ fw_device,
+ smp_remote_device->current_activity_phy_index,
+ smp_remote_device->curr_config_route_index,
+ empty_sas_address,
+ TRUE
+ );
+
+ //schedule the DPC.
+ scif_cb_start_internal_io_task_schedule(
+ fw_device->domain->controller,
+ scif_sas_controller_start_high_priority_io,
+ fw_device->domain->controller
+ );
+}
+
+
+/**
+ * @brief This method handles the case of exceeding route index when config route table
+ * for a device, by removing the attached device of current config route
+ * destination smp phy and the rest of smp phys in the same smp phy list.
+ *
+ * @param[in] fw_device The expander device, whose route table to be edited but failed
+ * with a SMP function result of INDEX DOES NOT EXIST.
+ *
+ * @return None.
+ */
+void scif_sas_smp_remote_device_cancel_config_route_table_activity(
+ SCIF_SAS_REMOTE_DEVICE_T * fw_device
+)
+{
+ //go through the rest of the smp phy list of destination device.
+ SCI_FAST_LIST_ELEMENT_T * element =
+ &(fw_device->protocol_device.smp_device.curr_config_route_destination_smp_phy->list_element);
+ SCIF_SAS_SMP_PHY_T * curr_smp_phy = NULL;
+ SCIF_SAS_REMOTE_DEVICE_T * curr_attached_device = NULL;
+
+ SCIF_LOG_TRACE((
+ sci_base_object_get_logger(fw_device),
+ SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
+ "scif_sas_smp_remote_device_cancel_config_route_table_activity(0x%x) enter\n",
+ fw_device
+ ));
+
+ while (element != NULL)
+ {
+ curr_smp_phy = (SCIF_SAS_SMP_PHY_T*) sci_fast_list_get_object(element);
+ element = sci_fast_list_get_next(element);
+
+ //check if this phy needs to be added to the expander's route table but can't due to
+ //exceeding max route index.
+ if (scif_sas_smp_remote_device_do_config_route_info(
+ fw_device, curr_smp_phy) == TRUE )
+ {
+ //set the is_currently_discovered to FALSE for attached device. Then when
+ //domain finish discover, domain will remove this device.
+ curr_attached_device = (SCIF_SAS_REMOTE_DEVICE_T *)
+ scif_domain_get_device_by_sas_address(
+ fw_device->domain, &(curr_smp_phy->attached_sas_address));
+
+ if (curr_attached_device != NULL)
+ curr_attached_device->is_currently_discovered = FALSE;
+ }
+ }
+}
+
+
+/**
+ * @brief This method cancel current activity and terminate the outstanding internal IO
+ * if there is one.
+ *
+ * @param[in] fw_device The expander device, whose smp activity is to be canceled.
+ *
+ * @return None.
+ */
+void scif_sas_smp_remote_device_cancel_smp_activity(
+ SCIF_SAS_REMOTE_DEVICE_T * fw_device
+)
+{
+ SCIF_LOG_TRACE((
+ sci_base_object_get_logger(fw_device),
+ SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
+ "scif_sas_smp_remote_device_cancel_smp_activity(0x%x) enter\n",
+ fw_device
+ ));
+
+ //Terminate all of the requests in the silicon for this device.
+ scif_sas_domain_terminate_requests(
+ fw_device->domain, fw_device, NULL, NULL
+ );
+
+ if (fw_device->protocol_device.smp_device.current_activity ==
+ SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_CONFIG_ROUTE_TABLE)
+ scif_sas_smp_remote_device_cancel_config_route_table_activity(fw_device);
+
+ //Clear the device to stop the smp sctivity.
+ scif_sas_smp_remote_device_clear(fw_device);
+}
+
+
+/**
+ * @brief This method tells the way to configure route table for a expander. The
+ * possible ways are: configure phy 0's route table, configure middle
+ * phy's route table, configure highest order phy's route table,
+ * configure all phys.
+ *
+ * @param[in] fw_device The expander device, whose config route table method is
+ * to be chosen.
+ *
+ * @return one in 4 possible options.
+ */
+U8 scif_sas_smp_remote_device_get_config_route_table_method(
+ SCIF_SAS_REMOTE_DEVICE_T * fw_device
+)
+{
+ U8 config_route_table_method;
+
+ //config_route_table_method = SCIF_SAS_CONFIG_ROUTE_TABLE_MIDDLE_PHY_ONLY;
+ config_route_table_method = SCIF_SAS_CONFIG_ROUTE_TABLE_ALL_PHYS;
+
+ return config_route_table_method;
+}
+
+
+/**
+ * @brief This method starts the EA target reset process by constructing
+ * and starting a PHY CONTROL (hard reset) smp request.
+ *
+ * @param[in] expander_device The expander device, to which a PHY Control smp command is
+ * sent.
+ * @param[in] target_device The expander attahced target device, to which the target reset
+ * request is sent.
+ * @param[in] fw_request The target reset task request.
+ *
+ * @return none
+ */
+void scif_sas_smp_remote_device_start_target_reset(
+ SCIF_SAS_REMOTE_DEVICE_T * expander_device,
+ SCIF_SAS_REMOTE_DEVICE_T * target_device,
+ SCIF_SAS_REQUEST_T * fw_request
+)
+{
+ SCIF_SAS_CONTROLLER_T * fw_controller = expander_device->domain->controller;
+
+ //set current_activity and current_smp_request to expander device.
+ expander_device->protocol_device.smp_device.current_activity =
+ SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_TARGET_RESET;
+ expander_device->protocol_device.smp_device.current_smp_request =
+ SMP_FUNCTION_PHY_CONTROL;
+ expander_device->protocol_device.smp_device.current_activity_phy_index =
+ target_device->expander_phy_identifier;
+
+ //A Phy Control smp request has been constructed towards parent device.
+ //Walk the high priority io path.
+ fw_controller->state_handlers->start_high_priority_io_handler(
+ (SCI_BASE_CONTROLLER_T*) fw_controller,
+ (SCI_BASE_REMOTE_DEVICE_T*) expander_device,
+ (SCI_BASE_REQUEST_T*) fw_request,
+ SCI_CONTROLLER_INVALID_IO_TAG
+ );
+}
+
+
diff --git a/sys/dev/isci/scil/scif_sas_smp_remote_device.h b/sys/dev/isci/scil/scif_sas_smp_remote_device.h
new file mode 100644
index 0000000..a28683d
--- /dev/null
+++ b/sys/dev/isci/scil/scif_sas_smp_remote_device.h
@@ -0,0 +1,431 @@
+/*-
+ * 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.
+ *
+ * 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.
+ *
+ * $FreeBSD$
+ */
+#ifndef _SCIF_SAS_SMP_REMOTE_DEVICE_H_
+#define _SCIF_SAS_SMP_REMOTE_DEVICE_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif // __cplusplus
+
+
+#include <dev/isci/scil/sci_fast_list.h>
+#include <dev/isci/scil/scif_sas_smp_phy.h>
+
+/**
+ * @file
+ *
+ * @brief This file contains the protected interface structures, constants,
+ * and methods for the SCIF_SAS_SMP_REMOTE_DEVICE object.
+ */
+
+struct SCIF_SAS_CONTROLLER;
+struct SCIF_SAS_REMOTE_DEVICE;
+struct SCIF_SAS_INTERNAL_IO_REQUEST;
+struct SCIF_SAS_REQUEST;
+struct SCIF_SAS_SMP_PHY;
+
+#define SMP_REQUEST_RETRY_WAIT_DURATION 20
+#define SMP_SPINUP_HOLD_RELEASE_WAIT_DURATION 100
+
+/**
+ * @name SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_CODES
+ *
+ * These constants depict the various SMP remote device activities.
+ */
+/*@{*/
+#define NOT_IN_SMP_ACTIVITY 0xff
+#define SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_NONE 0x0
+#define SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_DISCOVER 0x1
+#define SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_TARGET_RESET 0x2
+#define SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_SATA_SPINUP_HOLD_RELEASE 0x3
+#define SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_CONFIG_ROUTE_TABLE 0x4
+#define SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_CLEAN_ROUTE_TABLE 0x5
+#define SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_CLEAR_AFFILIATION 0x6
+/*@}*/
+
+
+
+/**
+ * @name SCIF_SAS_CONFIG_ROUTE_TABLE_OPTION_CODES
+ *
+ * These constants depict the various configure route table options.
+ */
+/*@{*/
+#define SCIF_SAS_CONFIG_ROUTE_TABLE_LOWEST_PHY_ONLY 0
+#define SCIF_SAS_CONFIG_ROUTE_TABLE_MIDDLE_PHY_ONLY 1
+#define SCIF_SAS_CONFIG_ROUTE_TABLE_HIGHEST_PHY_ONLY 2
+#define SCIF_SAS_CONFIG_ROUTE_TABLE_ALL_PHYS 3
+/*@}*/
+
+/**
+ * @struct SCIF_SAS_SMP_REMOTE_DEVICE
+ *
+ * @brief The SCIF_SAS_SMP_REMOTE_DEVICE stores data for smp remote devices
+ * (expanders) discovering attached targets.
+ *
+ */
+typedef struct SCIF_SAS_SMP_REMOTE_DEVICE
+{
+ /**
+ * This field stores the current SMP request function in the discovering
+ * sequence.
+ */
+ U32 current_smp_request;
+
+ /**
+ * This field indicates a smp device is either in the middle of normal discover
+ * process or in the middle of resetting a expander attahced remote device.
+ */
+ U8 current_activity;
+
+ /**
+ * This field stores the current expander phy index for sending out SMP
+ * DISCOVER request.
+ */
+ U8 current_activity_phy_index;
+
+ /**
+ * This field stores the current route index to config route table for
+ * a phy.
+ */
+ U16 curr_config_route_index;
+
+ /**
+ * This field indicates whether a route table of an expander has been cleaned
+ * since a DISCOVER process starts.
+ */
+ BOOL is_route_table_cleaned;
+
+ /**
+ * This field stores the smp phy whose route entries are edited by sending
+ * CONFIG ROUTE INFO commands.
+ */
+ struct SCIF_SAS_SMP_PHY * config_route_smp_phy_anchor;
+
+ /*
+ * This field stores the current smp phy on a destination device's smp phy list whose
+ * attached device's sas address is to be edited into this smp device's route table.
+ * When one config route info response is processed, we can find the next smp phy to edit
+ * using this field's value.
+ */
+ struct SCIF_SAS_SMP_PHY * curr_config_route_destination_smp_phy;
+
+ /*
+ * This field stores the current smp phy to which a PHY CONTROL (clear affiliation)
+ * command is sent out.
+ */
+ struct SCIF_SAS_SMP_PHY * curr_clear_affiliation_phy;
+
+ /**
+ * This field is to indicate a smp activity for this smp device is
+ * to be started (not yet). The scheduled activity could be Discover or Config
+ * Route Table.
+ */
+ U8 scheduled_activity;
+
+ /**
+ * This timer is used for waiting before retrying a smp request, or before
+ * sending Discover request after Phy Control during Target Reset.
+ */
+ void * smp_activity_timer;
+
+ /**
+ * This field save the retry count for internal smp request. Since when
+ * an internal smp request gets retried, it has been destructed already.
+ */
+ U8 io_retry_count;
+
+ /**
+ * This field stores the number of phys for expander device found by decoding
+ * the SMP REPORT GENERAL response.
+ */
+ U8 number_of_phys;
+
+ /**
+ * This field indicates the maximum number of expander route indexes per phy for
+ * this expander device.
+ */
+ U16 expander_route_indexes;
+
+ /**
+ * This field indicates whether an expander device supports table-to-table
+ * connection.
+ */
+ BOOL is_table_to_table_supported;
+
+ /**
+ * This field indicates whether an expander device is externally configurable.
+ * If it is, it is not self-configuring and is not able to config others.
+ */
+ BOOL is_externally_configurable;
+
+ /**
+ * This field indicates whether an expander device is able to config others.
+ */
+ BOOL is_able_to_config_others;
+
+ /**
+ * This field contains the list of all smp phys that connect to another smp phy.
+ */
+ SCI_FAST_LIST_T smp_phy_list;
+
+}SCIF_SAS_SMP_REMOTE_DEVICE_T;
+
+void scif_sas_smp_remote_device_clear(
+ struct SCIF_SAS_REMOTE_DEVICE * fw_device
+);
+
+void scif_sas_smp_remote_device_construct(
+ struct SCIF_SAS_REMOTE_DEVICE * fw_device
+);
+
+SCI_STATUS scif_sas_smp_remote_device_decode_smp_response(
+ struct SCIF_SAS_REMOTE_DEVICE * fw_device,
+ struct SCIF_SAS_REQUEST * fw_request,
+ void * response_data,
+ SCI_IO_STATUS completion_status
+);
+
+SCI_STATUS scif_sas_smp_remote_device_decode_report_general_response(
+ struct SCIF_SAS_REMOTE_DEVICE * fw_device,
+ SMP_RESPONSE_T * smp_response
+);
+
+SCI_STATUS scif_sas_smp_remote_device_decode_initial_discover_response(
+ struct SCIF_SAS_REMOTE_DEVICE * fw_device,
+ SMP_RESPONSE_T * smp_response
+);
+
+SCI_STATUS scif_sas_smp_remote_device_decode_report_phy_sata_response(
+ struct SCIF_SAS_REMOTE_DEVICE * fw_device,
+ SMP_RESPONSE_T * smp_response
+);
+
+SCI_STATUS scif_sas_smp_remote_device_decode_target_reset_phy_control_response(
+ struct SCIF_SAS_REMOTE_DEVICE * fw_device,
+ SMP_RESPONSE_T * smp_response
+);
+
+SCI_STATUS scif_sas_smp_remote_device_decode_discover_phy_control_response(
+ struct SCIF_SAS_REMOTE_DEVICE * fw_device,
+ SMP_RESPONSE_T * smp_response
+);
+
+SCI_STATUS scif_sas_smp_remote_device_decode_target_reset_discover_response(
+ struct SCIF_SAS_REMOTE_DEVICE * fw_device,
+ SMP_RESPONSE_T * smp_response
+);
+
+SCI_STATUS scif_sas_smp_remote_device_decode_spinup_hold_release_discover_response(
+ struct SCIF_SAS_REMOTE_DEVICE * fw_device,
+ SMP_RESPONSE_T * smp_response
+);
+
+SCI_STATUS scif_sas_smp_remote_device_decode_config_route_info_response(
+ struct SCIF_SAS_REMOTE_DEVICE * fw_device,
+ SMP_RESPONSE_T * smp_response
+);
+
+void scif_sas_smp_remote_device_start_discover(
+ struct SCIF_SAS_REMOTE_DEVICE * fw_device
+);
+
+void scif_sas_smp_remote_device_continue_discover(
+ struct SCIF_SAS_REMOTE_DEVICE * fw_device
+);
+
+void scif_sas_smp_remote_device_finish_initial_discover(
+ struct SCIF_SAS_REMOTE_DEVICE * fw_device
+);
+
+void scif_sas_smp_remote_device_finish_discover(
+ struct SCIF_SAS_REMOTE_DEVICE * fw_device
+);
+
+void scif_sas_smp_remote_device_continue_target_reset(
+ struct SCIF_SAS_REMOTE_DEVICE * fw_device,
+ struct SCIF_SAS_REQUEST * fw_request
+);
+
+void scif_sas_smp_remote_device_fail_discover(
+ struct SCIF_SAS_REMOTE_DEVICE * fw_device
+);
+
+void scif_sas_smp_remote_device_fail_target_reset(
+ struct SCIF_SAS_REMOTE_DEVICE * fw_device,
+ struct SCIF_SAS_REQUEST * fw_request
+);
+
+void scif_sas_smp_remote_device_continue_current_activity(
+ struct SCIF_SAS_REMOTE_DEVICE * fw_device,
+ struct SCIF_SAS_REQUEST * fw_request,
+ SCI_STATUS status
+);
+
+void scif_sas_smp_remote_device_target_reset_poll(
+ struct SCIF_SAS_REQUEST * fw_request
+);
+
+void scif_sas_smp_remote_device_sata_spinup_hold_release(
+ struct SCIF_SAS_REMOTE_DEVICE * fw_device
+);
+
+void scif_sas_smp_remote_device_fail_target_spinup_hold_release(
+ struct SCIF_SAS_REMOTE_DEVICE * fw_device,
+ struct SCIF_SAS_REMOTE_DEVICE * target_device
+);
+
+void scif_sas_smp_remote_device_retry_internal_io(
+ struct SCIF_SAS_REMOTE_DEVICE * fw_device,
+ U8 io_retry_count,
+ U32 delay
+);
+
+BOOL scif_sas_smp_remote_device_is_in_activity(
+ struct SCIF_SAS_REMOTE_DEVICE * fw_device
+);
+
+SCIF_SAS_SMP_PHY_T * scif_sas_smp_remote_device_find_smp_phy_by_id(
+ U8 phy_identifier,
+ struct SCIF_SAS_SMP_REMOTE_DEVICE * smp_remote_device
+);
+
+void scif_sas_smp_remote_device_removed(
+ struct SCIF_SAS_REMOTE_DEVICE * this_device
+);
+
+void scif_sas_smp_remote_device_terminated_request_handler(
+ struct SCIF_SAS_REMOTE_DEVICE * fw_device,
+ struct SCIF_SAS_REQUEST * fw_request
+);
+
+void scif_sas_smp_remote_device_populate_smp_phy_list(
+ struct SCIF_SAS_REMOTE_DEVICE * fw_device
+);
+
+SCI_STATUS scif_sas_smp_remote_device_save_smp_phy_info(
+ struct SCIF_SAS_REMOTE_DEVICE * fw_device,
+ SMP_RESPONSE_DISCOVER_T * discover_response
+);
+
+#ifdef SCI_SMP_PHY_LIST_DEBUG_PRINT
+void scif_sas_smp_remote_device_print_smp_phy_list(
+ struct SCIF_SAS_REMOTE_DEVICE * fw_device
+);
+#endif
+
+void scif_sas_smp_remote_device_configure_upstream_expander_route_info(
+ struct SCIF_SAS_REMOTE_DEVICE * this_device
+);
+
+struct SCIF_SAS_REMOTE_DEVICE * scif_sas_remote_device_find_upstream_expander(
+ struct SCIF_SAS_REMOTE_DEVICE * this_device
+);
+
+struct SCIF_SAS_REMOTE_DEVICE * scif_sas_remote_device_find_downstream_expander(
+ struct SCIF_SAS_REMOTE_DEVICE * this_device
+);
+
+BOOL scif_sas_smp_remote_device_do_config_route_info(
+ struct SCIF_SAS_REMOTE_DEVICE * device_being_config,
+ struct SCIF_SAS_SMP_PHY * destination_smp_phy
+);
+
+void scif_sas_smp_remote_device_configure_route_table(
+ struct SCIF_SAS_REMOTE_DEVICE * device_being_config
+);
+
+void scif_sas_smp_remote_device_clean_route_table(
+ struct SCIF_SAS_REMOTE_DEVICE * fw_device
+);
+
+void scif_sas_smp_remote_device_clean_route_table_entry(
+ struct SCIF_SAS_REMOTE_DEVICE * fw_device
+);
+
+void scif_sas_smp_remote_device_cancel_config_route_table_activity(
+ struct SCIF_SAS_REMOTE_DEVICE * fw_device
+);
+
+void scif_sas_smp_remote_device_cancel_smp_activity(
+ struct SCIF_SAS_REMOTE_DEVICE * fw_device
+);
+
+U8 scif_sas_smp_remote_device_get_config_route_table_method(
+ struct SCIF_SAS_REMOTE_DEVICE * fw_device
+);
+
+void scif_sas_smp_remote_device_start_clear_affiliation(
+ struct SCIF_SAS_REMOTE_DEVICE * fw_device
+);
+
+void scif_sas_smp_remote_device_continue_clear_affiliation(
+ struct SCIF_SAS_REMOTE_DEVICE * fw_device
+);
+
+void scif_sas_smp_remote_device_finish_clear_affiliation(
+ struct SCIF_SAS_REMOTE_DEVICE * fw_device
+);
+
+void scif_sas_smp_remote_device_start_target_reset(
+ struct SCIF_SAS_REMOTE_DEVICE * expander_device,
+ struct SCIF_SAS_REMOTE_DEVICE * target_device,
+ struct SCIF_SAS_REQUEST * fw_request
+);
+
+#ifdef __cplusplus
+}
+#endif // __cplusplus
+
+#endif // _SCIF_SAS_SMP_REMOTE_DEVICE_H_
diff --git a/sys/dev/isci/scil/scif_sas_stp_io_request.c b/sys/dev/isci/scil/scif_sas_stp_io_request.c
new file mode 100644
index 0000000..55a19a2
--- /dev/null
+++ b/sys/dev/isci/scil/scif_sas_stp_io_request.c
@@ -0,0 +1,623 @@
+/*-
+ * 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.
+ *
+ * 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 <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/**
+ * @file
+ *
+ * @brief This file contains the method implementations for the
+ * SCIF_SAS_STP_IO_REQUEST object. The contents will implement
+ * SATA/STP specific functionality.
+ */
+
+#include <dev/isci/scil/scif_sas_stp_io_request.h>
+#include <dev/isci/scil/scif_sas_stp_remote_device.h>
+#include <dev/isci/scil/scif_sas_logger.h>
+#include <dev/isci/scil/scif_sas_controller.h>
+
+#include <dev/isci/scil/sci_status.h>
+#include <dev/isci/scil/scic_io_request.h>
+
+#include <dev/isci/scil/sati.h>
+#include <dev/isci/scil/sati_atapi.h>
+#include <dev/isci/scil/intel_sat.h>
+#include <dev/isci/scil/sati_util.h>
+#include <dev/isci/scil/sati_callbacks.h>
+
+//******************************************************************************
+// P R I V A T E M E T H O D S
+//******************************************************************************
+
+/**
+ * @brief This method provides SATA/STP CONSTRUCTED state specific handling
+ * for when the user attempts to start the supplied IO request. It
+ * will allocate NCQ tags if necessary.
+ *
+ * @param[in] io_request This parameter specifies the IO request object
+ * to be started.
+ *
+ * @return This method returns a value indicating if the IO request was
+ * successfully started or not.
+ * @retval SCI_SUCCESS This return value indicates successful starting
+ * of the IO request.
+ */
+static
+SCI_STATUS scif_sas_stp_io_request_constructed_start_handler(
+ SCI_BASE_REQUEST_T * io_request
+)
+{
+ SCIF_SAS_IO_REQUEST_T * fw_io = (SCIF_SAS_IO_REQUEST_T *) io_request;
+
+ SCIF_LOG_TRACE((
+ sci_base_object_get_logger(io_request),
+ SCIF_LOG_OBJECT_IO_REQUEST,
+ "scif_sas_stp_io_request_constructed_start_handler(0x%x) enter\n",
+ io_request
+ ));
+
+ if (fw_io->parent.stp.sequence.protocol == SAT_PROTOCOL_FPDMA)
+ {
+ SATA_FIS_REG_H2D_T * fis;
+
+ // For NCQ, we need to attempt to allocate an available tag.
+ fw_io->parent.stp.ncq_tag = scif_sas_stp_remote_device_allocate_ncq_tag(
+ fw_io->parent.device
+ );
+
+ if (fw_io->parent.stp.ncq_tag == SCIF_SAS_INVALID_NCQ_TAG)
+ return SCI_FAILURE_NO_NCQ_TAG_AVAILABLE;
+
+ // Set the NCQ tag in the host to device register FIS (upper 5 bits
+ // of the 8-bit sector count register).
+ fis = scic_stp_io_request_get_h2d_reg_address(fw_io->parent.core_object);
+ fis->sector_count = (fw_io->parent.stp.ncq_tag << 3);
+
+ // The Core also requires that we inform it separately regarding the
+ // NCQ tag for this IO.
+ scic_stp_io_request_set_ncq_tag(
+ fw_io->parent.core_object, fw_io->parent.stp.ncq_tag
+ );
+ }
+
+ return SCI_SUCCESS;
+}
+
+/**
+ * @brief This method provides SATA/STP CONSTRUCTED state specific handling
+ * for when the user attempts to complete the supplied IO request.
+ * This method will be invoked in the event the call to start the
+ * core IO request fails for some reason. In this situation, the
+ * NCQ tag will be freed.
+ *
+ * @param[in] io_request This parameter specifies the IO request object
+ * to be started.
+ *
+ * @return This method returns a value indicating if the IO request was
+ * successfully started or not.
+ * @retval SCI_SUCCESS This return value indicates successful starting
+ * of the IO request.
+ */
+static
+SCI_STATUS scif_sas_stp_io_request_constructed_complete_handler(
+ SCI_BASE_REQUEST_T * io_request
+)
+{
+ SCIF_SAS_IO_REQUEST_T * fw_io = (SCIF_SAS_IO_REQUEST_T *) io_request;
+
+ SCIF_LOG_TRACE((
+ sci_base_object_get_logger(io_request),
+ SCIF_LOG_OBJECT_IO_REQUEST,
+ "scif_sas_stp_io_request_constructed_complete_handler(0x%x) enter\n",
+ io_request
+ ));
+
+ if (fw_io->parent.stp.sequence.protocol == SAT_PROTOCOL_FPDMA)
+ {
+ // For NCQ, we need to return the tag back to the free pool.
+ if (fw_io->parent.stp.ncq_tag != SCIF_SAS_INVALID_NCQ_TAG)
+ scif_sas_stp_remote_device_free_ncq_tag(
+ fw_io->parent.device, fw_io->parent.stp.ncq_tag
+ );
+ }
+
+ return SCI_SUCCESS;
+}
+/**
+ * @brief This method provides SATA/STP STARTED state specific handling for
+ * when the user attempts to complete the supplied IO request.
+ * It will perform data/response translation and free NCQ tags
+ * if necessary.
+ *
+ * @param[in] io_request This parameter specifies the IO request object
+ * to be started.
+ *
+ * @return This method returns a value indicating if the IO request was
+ * successfully completed or not.
+ */
+static
+SCI_STATUS scif_sas_stp_core_cb_io_request_complete_handler(
+ SCIF_SAS_CONTROLLER_T * fw_controller,
+ SCIF_SAS_REMOTE_DEVICE_T * fw_device,
+ SCIF_SAS_REQUEST_T * fw_request,
+ SCI_STATUS * completion_status
+)
+{
+ SCIF_SAS_IO_REQUEST_T * fw_io = (SCIF_SAS_IO_REQUEST_T *) fw_request;
+
+ SCIF_LOG_TRACE((
+ sci_base_object_get_logger(fw_controller),
+ SCIF_LOG_OBJECT_IO_REQUEST,
+ "scif_sas_stp_core_cb_io_request_complete_handler(0x%x, 0x%x, 0x%x, 0x%x) enter\n",
+ fw_controller, fw_device, fw_request, *completion_status
+ ));
+
+ if (fw_io->parent.stp.sequence.protocol == SAT_PROTOCOL_FPDMA)
+ scif_sas_stp_remote_device_free_ncq_tag(
+ fw_request->device, fw_io->parent.stp.ncq_tag
+ );
+
+ // Translating the response is only necessary if:
+ // - some sort of error occurred resulting in having the error bit
+ // set in the ATA status register and values to decode in the
+ // ATA error register.
+ // - the command returns information in the register FIS itself,
+ // which requires translation.
+ // - the request completed ok but the sequence requires a callback
+ // to possibly continue the translation
+ if ((*completion_status == SCI_FAILURE_IO_RESPONSE_VALID) ||
+ ((sati_cb_do_translate_response(fw_request)) &&
+ (*completion_status != SCI_FAILURE_IO_TERMINATED)))
+ {
+ SATI_STATUS sati_status = sati_translate_command_response(
+ &fw_io->parent.stp.sequence, fw_io, fw_io
+ );
+ if (sati_status == SATI_COMPLETE)
+ *completion_status = SCI_SUCCESS;
+ else if (sati_status == SATI_FAILURE_CHECK_RESPONSE_DATA)
+ *completion_status = SCI_FAILURE_IO_RESPONSE_VALID;
+ else if (sati_status == SATI_SEQUENCE_INCOMPLETE)
+ {
+ // The translation indicates that additional SATA requests are
+ // necessary to finish the original SCSI request. As a result,
+ // do not complete the IO and begin the next stage of the
+ // translation.
+ return SCI_WARNING_SEQUENCE_INCOMPLETE;
+ }
+ else if (sati_status == SATI_COMPLETE_IO_DONE_EARLY)
+ *completion_status = SCI_SUCCESS_IO_DONE_EARLY;
+ else
+ {
+ // Something unexpected occurred during translation. Fail the
+ // IO request to the user.
+ *completion_status = SCI_FAILURE;
+ }
+ }
+ else if (*completion_status != SCI_SUCCESS)
+ {
+ SCIF_LOG_INFO((
+ sci_base_object_get_logger(fw_controller),
+ SCIF_LOG_OBJECT_IO_REQUEST,
+ "Sequence Terminated(0x%x, 0x%x, 0x%x)\n",
+ fw_controller, fw_device, fw_request
+ ));
+
+ sati_sequence_terminate(&fw_io->parent.stp.sequence, fw_io, fw_io);
+ }
+
+ return SCI_SUCCESS;
+}
+
+#if !defined(DISABLE_ATAPI)
+/**
+ * @brief This method provides STP PACKET io request STARTED state specific handling for
+ * when the user attempts to complete the supplied IO request.
+ * It will perform data/response translation.
+ *
+ * @param[in] io_request This parameter specifies the IO request object
+ * to be started.
+ *
+ * @return This method returns a value indicating if the IO request was
+ * successfully completed or not.
+ */
+static
+SCI_STATUS scif_sas_stp_core_cb_packet_io_request_complete_handler(
+ SCIF_SAS_CONTROLLER_T * fw_controller,
+ SCIF_SAS_REMOTE_DEVICE_T * fw_device,
+ SCIF_SAS_REQUEST_T * fw_request,
+ SCI_STATUS * completion_status
+)
+{
+ SCIF_SAS_IO_REQUEST_T * fw_io = (SCIF_SAS_IO_REQUEST_T *) fw_request;
+ SATI_STATUS sati_status;
+
+ SCIF_LOG_TRACE((
+ sci_base_object_get_logger(fw_controller),
+ SCIF_LOG_OBJECT_IO_REQUEST,
+ "scif_sas_stp_packet_core_cb_io_request_complete_handler(0x%x, 0x%x, 0x%x, 0x%x) enter\n",
+ fw_controller, fw_device, fw_request, *completion_status
+ ));
+
+ if (*completion_status == SCI_FAILURE_IO_RESPONSE_VALID)
+ {
+ sati_status = sati_atapi_translate_command_response(
+ &fw_io->parent.stp.sequence, fw_io, fw_io
+ );
+
+ if (sati_status == SATI_COMPLETE)
+ *completion_status = SCI_SUCCESS;
+ else if (sati_status == SATI_FAILURE_CHECK_RESPONSE_DATA)
+ *completion_status = SCI_FAILURE_IO_RESPONSE_VALID;
+ else if (sati_status == SATI_SEQUENCE_INCOMPLETE)
+ {
+ // The translation indicates that additional REQUEST SENSE command is
+ // necessary to finish the original SCSI request. As a result,
+ // do not complete the IO and begin the next stage of the IO.
+ return SCI_WARNING_SEQUENCE_INCOMPLETE;
+ }
+ else
+ {
+ // Something unexpected occurred during translation. Fail the
+ // IO request to the user.
+ *completion_status = SCI_FAILURE;
+ }
+ }
+ else if (*completion_status == SCI_SUCCESS &&
+ fw_request->stp.sequence.state == SATI_SEQUENCE_STATE_INCOMPLETE)
+ {
+ //The internal Request Sense command is completed successfully.
+ sati_atapi_translate_request_sense_response(
+ &fw_io->parent.stp.sequence, fw_io, fw_io
+ );
+
+ *completion_status = SCI_FAILURE_IO_RESPONSE_VALID;
+ }
+
+ return SCI_SUCCESS;
+}
+#endif // !defined(DISABLE_ATAPI)
+
+//******************************************************************************
+// P R O T E C T E D M E T H O D S
+//******************************************************************************
+
+/**
+ * @brief This method will construct the SATA/STP specific IO request
+ * object utilizing the SATI.
+ *
+ * @pre The scif_sas_request_construct() method should be invoked before
+ * calling this method.
+ *
+ * @param[in,out] stp_io_request This parameter specifies the stp_io_request
+ * to be constructed.
+ *
+ * @return Indicate if the construction was successful.
+ * @return SCI_FAILURE_NO_NCQ_TAG_AVAILABLE
+ * @return SCI_SUCCESS_IO_COMPLETE_BEFORE_START
+ * @return SCI_FAILURE_IO_RESPONSE_VALID
+ * @return SCI_FAILURE This return value indicates a change in the translator
+ * where a new return code has been given, but is not yet understood
+ * by this routine.
+ */
+SCI_STATUS scif_sas_stp_io_request_construct(
+ SCIF_SAS_IO_REQUEST_T * fw_io
+)
+{
+ SATI_STATUS sati_status;
+ SCI_STATUS sci_status = SCI_FAILURE;
+ SCIF_SAS_REMOTE_DEVICE_T * fw_device = fw_io->parent.device;
+
+ SCIF_LOG_TRACE((
+ sci_base_object_get_logger(fw_io),
+ SCIF_LOG_OBJECT_IO_REQUEST,
+ "scif_sas_stp_io_request_construct(0x%x) enter\n",
+ fw_io
+ ));
+
+ // The translator will indirectly invoke core methods to set the fields
+ // of the ATA register FIS inside of this method.
+ sati_status = sati_translate_command(
+ &fw_io->parent.stp.sequence,
+ &fw_device->protocol_device.stp_device.sati_device,
+ fw_io,
+ fw_io
+ );
+
+ if (sati_status == SATI_SUCCESS)
+ {
+ // Allow the core to finish construction of the IO request.
+ sci_status = scic_io_request_construct_basic_sata(fw_io->parent.core_object);
+ fw_io->parent.state_handlers = &stp_io_request_constructed_handlers;
+ fw_io->parent.protocol_complete_handler
+ = scif_sas_stp_core_cb_io_request_complete_handler;
+ }
+ else if (sati_status == SATI_SUCCESS_SGL_TRANSLATED)
+ {
+ SCIC_IO_SATA_PARAMETERS_T parms;
+ parms.do_translate_sgl = FALSE;
+
+ // The translation actually already caused translation of the
+ // scatter gather list. So, call into the core through an API
+ // that will not attempt to translate the SGL.
+ scic_io_request_construct_advanced_sata(
+ fw_io->parent.core_object, &parms
+ );
+ fw_io->parent.state_handlers = &stp_io_request_constructed_handlers;
+ fw_io->parent.protocol_complete_handler
+ = scif_sas_stp_core_cb_io_request_complete_handler;
+ // Done with translation
+ sci_status = SATI_SUCCESS;
+ }
+ else if (sati_status == SATI_COMPLETE)
+ sci_status = SCI_SUCCESS_IO_COMPLETE_BEFORE_START;
+ else if (sati_status == SATI_FAILURE_CHECK_RESPONSE_DATA)
+ sci_status = SCI_FAILURE_IO_RESPONSE_VALID;
+ else
+ {
+ SCIF_LOG_ERROR((
+ sci_base_object_get_logger(fw_io),
+ SCIF_LOG_OBJECT_IO_REQUEST,
+ "Unexpected SAT translation failure 0x%x\n",
+ fw_io
+ ));
+ }
+
+ return sci_status;
+}
+
+
+#if !defined(DISABLE_ATAPI)
+/**
+ * @brief This method will construct the STP PACKET protocol specific IO
+ * request object.
+ *
+ * @pre The scif_sas_request_construct() method should be invoked before
+ * calling this method.
+ *
+ * @param[in,out] fw_io This parameter specifies the stp packet io request
+ * to be constructed.
+ *
+ * @return Indicate if the construction was successful.
+ * @return SCI_SUCCESS_IO_COMPLETE_BEFORE_START
+ * @return SCI_FAILURE_IO_RESPONSE_VALID
+ * @return SCI_FAILURE This return value indicates a change in the translator
+ * where a new return code has been given, but is not yet understood
+ * by this routine.
+ */
+SCI_STATUS scif_sas_stp_packet_io_request_construct(
+ SCIF_SAS_IO_REQUEST_T * fw_io
+)
+{
+ SATI_STATUS sati_status;
+ SCI_STATUS sci_status = SCI_FAILURE;
+ SCIF_SAS_REMOTE_DEVICE_T * fw_device = fw_io->parent.device;
+
+ SCIF_LOG_TRACE((
+ sci_base_object_get_logger(fw_io),
+ SCIF_LOG_OBJECT_IO_REQUEST,
+ "scif_sas_stp_packet_io_request_construct(0x%x) enter\n",
+ fw_io
+ ));
+
+ sati_status = sati_atapi_translate_command(
+ &fw_io->parent.stp.sequence,
+ &fw_device->protocol_device.stp_device.sati_device,
+ fw_io,
+ fw_io
+ );
+
+ if (sati_status == SATI_SUCCESS)
+ {
+ // Allow the core to finish construction of the IO request.
+ sci_status = scic_io_request_construct_basic_sata(fw_io->parent.core_object);
+
+ fw_io->parent.protocol_complete_handler
+ = scif_sas_stp_core_cb_packet_io_request_complete_handler;
+ }
+ else if (sati_status == SATI_COMPLETE)
+ sci_status = SCI_SUCCESS_IO_COMPLETE_BEFORE_START;
+ else if (sati_status == SATI_FAILURE_CHECK_RESPONSE_DATA)
+ sci_status = SCI_FAILURE_IO_RESPONSE_VALID;
+ else
+ {
+ SCIF_LOG_ERROR((
+ sci_base_object_get_logger(fw_io),
+ SCIF_LOG_OBJECT_IO_REQUEST,
+ "Unexpected SAT ATAPI translation failure 0x%x\n",
+ fw_io
+ ));
+ }
+
+ return sci_status;
+}
+#endif
+
+
+#if !defined(DISABLE_ATAPI)
+/**
+ * @brief This method will get the number of bytes transferred in an packet IO.
+ *
+ * @param[in] fw_io This parameter specifies the stp packet io request whose
+ * actual transferred length is to be retrieved.
+ *
+ * @return Actual length of transferred data.
+ */
+U32 scif_sas_stp_packet_io_request_get_number_of_bytes_transferred(
+ SCIF_SAS_IO_REQUEST_T * fw_io
+)
+{
+ SCI_IO_REQUEST_HANDLE_T scic_io = scif_io_request_get_scic_handle(fw_io);
+ SCI_IO_STATUS io_status = scic_request_get_sci_status (scic_io);
+ U32 actual_data_length;
+
+ if (io_status == SCI_IO_FAILURE_RESPONSE_VALID)
+ actual_data_length = 0;
+ else if (io_status == SCI_IO_SUCCESS_IO_DONE_EARLY)
+ {
+ actual_data_length = sati_atapi_translate_number_of_bytes_transferred(
+ &fw_io->parent.stp.sequence, fw_io, fw_io);
+
+ if (actual_data_length == 0)
+ actual_data_length =
+ scic_io_request_get_number_of_bytes_transferred(scic_io);
+ }
+ else
+ actual_data_length =
+ scic_io_request_get_number_of_bytes_transferred(scic_io);
+
+ return actual_data_length;
+}
+#endif
+
+
+//******************************************************************************
+// P U B L I C M E T H O D S
+//******************************************************************************
+
+BOOL scic_cb_io_request_do_copy_rx_frames(
+ void * scic_user_io_request
+)
+{
+ SCIF_SAS_IO_REQUEST_T * fw_io = (SCIF_SAS_IO_REQUEST_T*) scic_user_io_request;
+
+ SCIF_LOG_TRACE((
+ sci_base_object_get_logger(fw_io),
+ SCIF_LOG_OBJECT_IO_REQUEST,
+ "scic_cb_io_request_do_copy_rx_frames(0x%x) enter\n",
+ fw_io
+ ));
+
+ // If the translation was a PIO DATA IN (i.e. read) and the request
+ // was actually a READ payload operation, then copy the data, since
+ // there will be SGL space allocated for the transfer.
+ if (fw_io->parent.stp.sequence.protocol == SAT_PROTOCOL_PIO_DATA_IN)
+ {
+ if (
+ (fw_io->parent.stp.sequence.type == SATI_SEQUENCE_ATA_PASSTHROUGH_12)
+ || (fw_io->parent.stp.sequence.type == SATI_SEQUENCE_ATA_PASSTHROUGH_16)
+ || (
+ (fw_io->parent.stp.sequence.type >= SATI_SEQUENCE_TYPE_READ_MIN)
+ && (fw_io->parent.stp.sequence.type <= SATI_SEQUENCE_TYPE_READ_MAX)
+ )
+ )
+ {
+ SCIF_LOG_TRACE((
+ sci_base_object_get_logger(fw_io),
+ SCIF_LOG_OBJECT_IO_REQUEST,
+ "scic_cb_io_request_do_copy_rx_frames(0x%x) TRUE\n",
+ fw_io
+ ));
+ return TRUE;
+ }
+ }
+
+ // For all other requests we leave the data in the core buffers.
+ // This allows the translation to translate without having to have
+ // separate space allocated into which to copy the data.
+ return FALSE;
+}
+
+// ---------------------------------------------------------------------------
+
+U8 scic_cb_request_get_sat_protocol(
+ void * scic_user_io_request
+)
+{
+ SCIF_SAS_IO_REQUEST_T * fw_io = (SCIF_SAS_IO_REQUEST_T*) scic_user_io_request;
+
+ return fw_io->parent.stp.sequence.protocol;
+}
+
+U8 *scic_cb_io_request_get_virtual_address_from_sgl(
+ void * scic_user_io_request,
+ U32 byte_offset
+)
+{
+ SCIF_SAS_REQUEST_T *fw_request =
+ (SCIF_SAS_REQUEST_T *) sci_object_get_association(scic_user_io_request);
+
+ return scif_cb_io_request_get_virtual_address_from_sgl(
+ sci_object_get_association(fw_request),
+ byte_offset
+ );
+}
+
+#ifdef ENABLE_OSSL_COPY_BUFFER
+void scic_cb_io_request_copy_buffer(
+ void * scic_user_io_request,
+ U8 *source_addr,
+ U32 offset,
+ U32 length
+)
+{
+ SCIF_SAS_REQUEST_T *fw_request =
+ (SCIF_SAS_REQUEST_T *)sci_object_get_association(scic_user_io_request);
+
+ return scif_cb_io_request_copy_buffer(
+ sci_object_get_association(fw_request),
+ source_addr,
+ offset,
+ length
+ );
+}
+#endif
+// ---------------------------------------------------------------------------
+
+SCI_BASE_REQUEST_STATE_HANDLER_T stp_io_request_constructed_handlers =
+{
+ scif_sas_stp_io_request_constructed_start_handler,
+ scif_sas_io_request_constructed_abort_handler,
+ scif_sas_stp_io_request_constructed_complete_handler,
+ scif_sas_io_request_default_destruct_handler
+};
+
diff --git a/sys/dev/isci/scil/scif_sas_stp_io_request.h b/sys/dev/isci/scil/scif_sas_stp_io_request.h
new file mode 100644
index 0000000..0c9ba4b
--- /dev/null
+++ b/sys/dev/isci/scil/scif_sas_stp_io_request.h
@@ -0,0 +1,101 @@
+/*-
+ * 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.
+ *
+ * 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.
+ *
+ * $FreeBSD$
+ */
+#ifndef _SCIF_SAS_STP_IO_REQUEST_H_
+#define _SCIF_SAS_STP_IO_REQUEST_H_
+
+/**
+ * @file
+ *
+ * @brief This file contains the protected interface structures, constants,
+ * and methods for the SCIF_SAS_STP_IO_REQUEST object.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif // __cplusplus
+
+#include <dev/isci/scil/sati_translator_sequence.h>
+#include <dev/isci/scil/sci_types.h>
+#include <dev/isci/scil/sci_status.h>
+#include <dev/isci/scil/sci_base_request.h>
+
+extern SCI_BASE_REQUEST_STATE_HANDLER_T stp_io_request_constructed_handlers;
+
+struct SCIF_SAS_IO_REQUEST;
+SCI_STATUS scif_sas_stp_io_request_construct(
+ struct SCIF_SAS_IO_REQUEST * fw_io
+);
+
+#if !defined(DISABLE_ATAPI)
+SCI_STATUS scif_sas_stp_packet_io_request_construct(
+ struct SCIF_SAS_IO_REQUEST * fw_io
+);
+#else // !defined(DISABLE_ATAPI)
+#define scif_sas_stp_packet_io_request_construct(fw_io) SCI_FAILURE
+#endif // !defined(DISABLE_ATAPI)
+
+#if !defined(DISABLE_ATAPI)
+U32 scif_sas_stp_packet_io_request_get_number_of_bytes_transferred(
+ struct SCIF_SAS_IO_REQUEST * fw_io
+);
+#else // !defined(DISABLE_ATAPI)
+#define scif_sas_stp_packet_io_request_get_number_of_bytes_transferred(fw_io) 0
+#endif // !defined(DISABLE_ATAPI)
+
+#ifdef __cplusplus
+}
+#endif // __cplusplus
+
+#endif // _SCIF_SAS_STP_IO_REQUEST_H_
+
diff --git a/sys/dev/isci/scil/scif_sas_stp_remote_device.c b/sys/dev/isci/scil/scif_sas_stp_remote_device.c
new file mode 100644
index 0000000..22e5c3c
--- /dev/null
+++ b/sys/dev/isci/scil/scif_sas_stp_remote_device.c
@@ -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.
+ *
+ * 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 <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/**
+ * @file
+ *
+ * @brief This file contains the protected interface structures, constants,
+ * and methods for the SCIF_SAS_STP_REMOTE_DEVICE object.
+ */
+
+#include <dev/isci/scil/scif_sas_stp_remote_device.h>
+#include <dev/isci/scil/scif_sas_remote_device.h>
+#include <dev/isci/scil/scif_sas_domain.h>
+#include <dev/isci/scil/scif_sas_controller.h>
+#include <dev/isci/scil/scif_sas_logger.h>
+#include <dev/isci/scil/intel_sat.h>
+
+/**
+ * @brief This method performs SATA/STP specific construction of the
+ * STP remote device object.
+ *
+ * @param[in] device This parameter specifies the STP remote device
+ * object to be constructed.
+ *
+ * @return none
+ */
+void scif_sas_stp_remote_device_construct(
+ SCIF_SAS_REMOTE_DEVICE_T * device
+)
+{
+ sati_device_construct(
+ &device->protocol_device.stp_device.sati_device,
+ device->domain->controller->user_parameters.sas.is_sata_ncq_enabled,
+ (U8) device->domain->controller->user_parameters.sas.max_ncq_depth,
+ device->domain->controller->user_parameters.sas.ignore_fua
+ );
+
+ device->protocol_device.stp_device.s_active = 0;
+}
+
+/**
+ * @brief This method attempts to allocate a valid NCQ tag from the list
+ * of available tags in the remote device.
+ *
+ * @todo Attempt to find a CLZ like instruction to optimize this routine
+ * down into a few instructions. I know there is one like it for IA.
+ *
+ * @param[in] fw_device This parameter specifies the remote device
+ * for which to allocate an available NCQ tag.
+ *
+ * @return Return an available NCQ tag.
+ * @retval 0-31 These values indicate an available tag was successfully
+ * allocated.
+ * @return SCIF_SAS_STP_INVALID_NCQ_TAG This value indicates that there are
+ * no available NCQ tags.
+ */
+U8 scif_sas_stp_remote_device_allocate_ncq_tag(
+ SCIF_SAS_REMOTE_DEVICE_T * fw_device
+)
+{
+ U8 ncq_tag = 0;
+ U32 tag_mask = 1;
+
+ SCIF_LOG_TRACE((
+ sci_base_object_get_logger(fw_device),
+ SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_IO_REQUEST,
+ "scif_sas_stp_remote_device_allocate_ncq_tag(0x%x)\n",
+ fw_device
+ ));
+
+ // Try to find an unused NCQ tag.
+ while ( (fw_device->protocol_device.stp_device.s_active & tag_mask)
+ && (ncq_tag < fw_device->protocol_device.stp_device.sati_device.ncq_depth) )
+ {
+ tag_mask <<= 1;
+ ncq_tag++;
+ }
+
+ // Check to see if we were able to find an available NCQ tag.
+ if (ncq_tag < fw_device->protocol_device.stp_device.sati_device.ncq_depth)
+ {
+ SCIF_LOG_INFO((
+ sci_base_object_get_logger(fw_device),
+ SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_IO_REQUEST,
+ "RemoteDevice:0x%x NcqTag:0x%x successful NCQ TAG allocation\n",
+ fw_device, ncq_tag
+ ));
+
+ fw_device->protocol_device.stp_device.s_active |= tag_mask;
+ return ncq_tag;
+ }
+
+ SCIF_LOG_INFO((
+ sci_base_object_get_logger(fw_device),
+ SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_IO_REQUEST,
+ "RemoteDevice:0x%x unable to allocate NCQ TAG\n",
+ fw_device
+ ));
+
+ // All NCQ tags are in use.
+ return SCIF_SAS_INVALID_NCQ_TAG;
+}
+
+/**
+ * @brief This method removes the specified tag from the list of
+ * outstanding tags. It doesn't return any values.
+ *
+ * @param[in] fw_device This parameter specifies the remote device for
+ * which to free an NCQ tag.
+ * @param[in] ncq_tag This parameter specifies the NCQ tag that is
+ * to be freed.
+ *
+ * @return none
+ */
+void scif_sas_stp_remote_device_free_ncq_tag(
+ struct SCIF_SAS_REMOTE_DEVICE * fw_device,
+ U8 ncq_tag
+)
+{
+ SCIF_LOG_INFO((
+ sci_base_object_get_logger(fw_device),
+ SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_IO_REQUEST,
+ "RemoteDevice:0x%x NcqTag:0x%x freeing NCQ TAG\n",
+ fw_device, ncq_tag
+ ));
+
+ fw_device->protocol_device.stp_device.s_active &= ~(1 << ncq_tag);
+}
+
+struct SCIF_SAS_REQUEST *
+scif_sas_stp_remote_device_get_request_by_ncq_tag(
+ struct SCIF_SAS_REMOTE_DEVICE * fw_device,
+ U8 ncq_tag
+)
+{
+ SCIF_SAS_DOMAIN_T * fw_domain = fw_device->domain;
+ SCI_FAST_LIST_ELEMENT_T * pending_request_element;
+ SCIF_SAS_REQUEST_T * pending_request = NULL;
+ SCIF_SAS_REQUEST_T * matching_request = NULL;
+
+ pending_request_element = fw_domain->request_list.list_head;
+
+ while (pending_request_element != NULL)
+ {
+ pending_request =
+ (SCIF_SAS_REQUEST_T*) sci_fast_list_get_object(pending_request_element);
+
+ // The current element may be deleted from the list becasue of
+ // IO completion so advance to the next element early
+ pending_request_element = sci_fast_list_get_next(pending_request_element);
+
+ if (
+ (pending_request->device == fw_device) &&
+ (pending_request->stp.sequence.protocol == SAT_PROTOCOL_FPDMA) &&
+ (pending_request->stp.ncq_tag == ncq_tag)
+ )
+ {
+ matching_request = pending_request;
+ }
+ }
+
+ return matching_request;
+}
diff --git a/sys/dev/isci/scil/scif_sas_stp_remote_device.h b/sys/dev/isci/scil/scif_sas_stp_remote_device.h
new file mode 100644
index 0000000..94e1b36
--- /dev/null
+++ b/sys/dev/isci/scil/scif_sas_stp_remote_device.h
@@ -0,0 +1,119 @@
+/*-
+ * 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.
+ *
+ * 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.
+ *
+ * $FreeBSD$
+ */
+#ifndef _SCIF_SAS_STP_REMOTE_DEVICE_H_
+#define _SCIF_SAS_STP_REMOTE_DEVICE_H_
+
+/**
+ * @file
+ *
+ * @brief This file contains the protected interface structures, constants,
+ * and methods for the SCIF_SAS_STP_REMOTE_DEVICE object.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif // __cplusplus
+
+#include <dev/isci/scil/sati_device.h>
+
+#define SCIF_SAS_INVALID_NCQ_TAG 0xFF
+
+/**
+ * @struct SCIF_SAS_STP_REMOTE_DEVICE
+ *
+ * @brief The SCI SAS STP Framework remote device object abstracts the SAS
+ * SATA/STP remote device level behavior for the framework component.
+ */
+typedef struct SCIF_SAS_STP_REMOTE_DEVICE
+{
+ /**
+ * This field contains all of the data utilized by the SCSI-to-ATA
+ * Translation Implementation (SATI).
+ */
+ SATI_DEVICE_T sati_device;
+
+ /**
+ * This field contains a list of free NCQ tags available for use in
+ * SATA Native Command Queuing (NCQ) requests.
+ */
+ U32 s_active;
+
+} SCIF_SAS_STP_REMOTE_DEVICE_T;
+
+struct SCIF_SAS_REMOTE_DEVICE;
+void scif_sas_stp_remote_device_construct(
+ struct SCIF_SAS_REMOTE_DEVICE * fw_device
+);
+
+U8 scif_sas_stp_remote_device_allocate_ncq_tag(
+ struct SCIF_SAS_REMOTE_DEVICE * fw_device
+);
+
+void scif_sas_stp_remote_device_free_ncq_tag(
+ struct SCIF_SAS_REMOTE_DEVICE * fw_device,
+ U8 ncq_tag
+);
+
+struct SCIF_SAS_REQUEST *
+scif_sas_stp_remote_device_get_request_by_ncq_tag(
+ struct SCIF_SAS_REMOTE_DEVICE * fw_device,
+ U8 ncq_tag
+);
+
+#ifdef __cplusplus
+}
+#endif // __cplusplus
+
+#endif // _SCIF_SAS_STP_REMOTE_DEVICE_H_
+
diff --git a/sys/dev/isci/scil/scif_sas_stp_task_request.c b/sys/dev/isci/scil/scif_sas_stp_task_request.c
new file mode 100644
index 0000000..2e26356
--- /dev/null
+++ b/sys/dev/isci/scil/scif_sas_stp_task_request.c
@@ -0,0 +1,265 @@
+/*-
+ * 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.
+ *
+ * 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 <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <dev/isci/scil/sati.h>
+#include <dev/isci/scil/scif_sas_logger.h>
+#include <dev/isci/scil/scif_sas_task_request.h>
+#include <dev/isci/scil/scif_sas_controller.h>
+#include <dev/isci/scil/scif_sas_remote_device.h>
+#include <dev/isci/scil/scif_sas_stp_task_request.h>
+#include <dev/isci/scil/scic_task_request.h>
+#include <dev/isci/scil/scic_controller.h>
+
+/**
+ * @brief This method provides SATA/STP STARTED state specific handling for
+ * when the user attempts to complete the supplied IO request.
+ * It will perform data/response translation and free NCQ tags
+ * if necessary.
+ *
+ * @param[in] io_request This parameter specifies the IO request object
+ * to be started.
+ *
+ * @return This method returns a value indicating if the IO request was
+ * successfully completed or not.
+ */
+static
+SCI_STATUS scif_sas_stp_core_cb_task_request_complete_handler(
+ SCIF_SAS_CONTROLLER_T * fw_controller,
+ SCIF_SAS_REMOTE_DEVICE_T * fw_device,
+ SCIF_SAS_REQUEST_T * fw_request,
+ SCI_STATUS * completion_status
+)
+{
+#if !defined(DISABLE_SATI_TASK_MANAGEMENT)
+ SCIF_SAS_TASK_REQUEST_T * fw_task = (SCIF_SAS_TASK_REQUEST_T *) fw_request;
+
+ SCIF_LOG_TRACE((
+ sci_base_object_get_logger(fw_controller),
+ SCIF_LOG_OBJECT_TASK_MANAGEMENT,
+ "scif_sas_stp_core_cb_task_request_complete_handler(0x%x, 0x%x, 0x%x, 0x%x) enter\n",
+ fw_controller, fw_device, fw_request, *completion_status
+ ));
+
+ // Translating the response is only necessary if some sort of error
+ // occurred resulting in having the error bit set in the ATA status
+ // register and values to decode in the ATA error register.
+ if ( (*completion_status == SCI_SUCCESS)
+ || (*completion_status == SCI_FAILURE_IO_RESPONSE_VALID) )
+ {
+ SATI_STATUS sati_status = sati_translate_task_response(
+ &fw_task->parent.stp.sequence,
+ fw_task,
+ fw_task
+ );
+
+ if (sati_status == SATI_COMPLETE)
+ *completion_status = SCI_SUCCESS;
+ else if (sati_status == SATI_FAILURE_CHECK_RESPONSE_DATA)
+ *completion_status = SCI_FAILURE_IO_RESPONSE_VALID;
+ else if (sati_status == SATI_SEQUENCE_INCOMPLETE)
+ {
+ // The translation indicates that additional SATA requests are
+ // necessary to finish the original SCSI request. As a result,
+ // do not complete the IO and begin the next stage of the
+ // translation.
+ /// @todo multiple ATA commands are required, but not supported yet.
+ return SCI_FAILURE;
+ }
+ else
+ {
+ // Something unexpected occurred during translation. Fail the
+ // IO request to the user.
+ *completion_status = SCI_FAILURE;
+ }
+ }
+ else //A stp task request sometimes fails.
+ {
+ if (scif_sas_task_request_get_function(fw_task) == SCI_SAS_ABORT_TASK_SET)
+ {
+ scif_sas_stp_task_request_abort_task_set_failure_handler(
+ fw_device, fw_task);
+ }
+ }
+
+ return SCI_SUCCESS;
+#else // !defined(DISABLE_SATI_TASK_MANAGEMENT)
+ return SCI_FAILURE;
+#endif // !defined(DISABLE_SATI_TASK_MANAGEMENT)
+}
+
+/**
+ * @file
+ *
+ * @brief This file contains the method implementations for the
+ * SCIF_SAS_STP_TASK_REQUEST object. The contents will implement
+ * SATA/STP specific functionality.
+ */
+SCI_STATUS scif_sas_stp_task_request_construct(
+ SCIF_SAS_TASK_REQUEST_T * fw_task
+)
+{
+ SCI_STATUS sci_status = SCI_FAILURE;
+
+#if !defined(DISABLE_SATI_TASK_MANAGEMENT)
+ SATI_STATUS sati_status;
+ SCIF_SAS_REMOTE_DEVICE_T * fw_device = fw_task->parent.device;
+
+ SCIF_LOG_TRACE((
+ sci_base_object_get_logger(fw_task),
+ SCIF_LOG_OBJECT_TASK_MANAGEMENT,
+ "scif_sas_stp_task_request_construct(0x%x) enter\n",
+ fw_task
+ ));
+
+ // The translator will indirectly invoke core methods to set the fields
+ // of the ATA register FIS inside of this method.
+ sati_status = sati_translate_task_management(
+ &fw_task->parent.stp.sequence,
+ &fw_device->protocol_device.stp_device.sati_device,
+ fw_task,
+ fw_task
+ );
+
+ if (sati_status == SATI_SUCCESS)
+ {
+ sci_status = scic_task_request_construct_sata(fw_task->parent.core_object);
+ //fw_task->parent.state_handlers = &stp_io_request_constructed_handlers;
+ fw_task->parent.protocol_complete_handler =
+ scif_sas_stp_core_cb_task_request_complete_handler;
+ }
+ else
+ {
+ SCIF_LOG_ERROR((
+ sci_base_object_get_logger(fw_task),
+ SCIF_LOG_OBJECT_TASK_MANAGEMENT,
+ "Task 0x%x received unexpected SAT translation failure 0x%x\n",
+ fw_task, sati_status
+ ));
+ }
+#endif // !defined(DISABLE_SATI_TASK_MANAGEMENT)
+
+ return sci_status;
+}
+
+
+/**
+ * @brief This method provides handling for failed stp TASK MANAGEMENT
+ * request.
+ *
+ * @param[in] fw_device This parameter specifies the target device the
+ * task management request towards to.
+ * @param[in] fw_request This parameter specifies the failed task management
+ * request.
+ * @param[in] completion_status This parameter sprecifies the completion
+ * status of the task management request's core status.
+ *
+ * @return None.
+ */
+void scif_sas_stp_task_request_abort_task_set_failure_handler(
+ SCIF_SAS_REMOTE_DEVICE_T * fw_device,
+ SCIF_SAS_TASK_REQUEST_T * fw_task
+)
+{
+#if !defined(DISABLE_SATI_TASK_MANAGEMENT)
+ SCIF_SAS_DOMAIN_T * fw_domain = fw_device->domain;
+ SCI_FAST_LIST_ELEMENT_T * pending_request_element;
+ SCIF_SAS_REQUEST_T * pending_request = NULL;
+
+ pending_request_element = fw_domain->request_list.list_head;
+
+ // Cycle through the list of IO requests. search all the
+ // outstanding IOs with "waiting for abort task set" flag,
+ // completes them now.
+ while (pending_request_element != NULL)
+ {
+ pending_request =
+ (SCIF_SAS_REQUEST_T*) sci_fast_list_get_object(pending_request_element);
+
+ // The current element may be deleted from the list becasue of
+ // IO completion so advance to the next element early
+ pending_request_element = sci_fast_list_get_next(pending_request_element);
+
+ if ( pending_request->device == fw_device
+ && pending_request->is_waiting_for_abort_task_set == TRUE )
+ {
+ //In case the pending_request is still in the middle of aborting.
+ //abort it again to the core.
+ SCI_STATUS abort_status;
+
+ //Reset the flag now since we are process the read log ext command now.
+ pending_request->is_waiting_for_abort_task_set = FALSE;
+
+ abort_status = scic_controller_terminate_request(
+ fw_domain->controller->core_object,
+ fw_device->core_object,
+ pending_request->core_object
+ );
+
+ if (abort_status == SCI_FAILURE_INVALID_STATE)
+ {
+ //the request must have not be in aborting state anymore, complete it now.
+ scif_cb_io_request_complete(
+ fw_domain->controller,
+ fw_device,
+ pending_request,
+ SCI_FAILURE_IO_TERMINATED
+ );
+ }
+ //otherwise, the abort succeeded. Since the waiting flag is cleared,
+ //the pending request will be completed later.
+ }
+ }
+#endif //#if !defined(DISABLE_SATI_TASK_MANAGEMENT)
+}
diff --git a/sys/dev/isci/scil/scif_sas_stp_task_request.h b/sys/dev/isci/scil/scif_sas_stp_task_request.h
new file mode 100644
index 0000000..cbba600
--- /dev/null
+++ b/sys/dev/isci/scil/scif_sas_stp_task_request.h
@@ -0,0 +1,106 @@
+/*-
+ * 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.
+ *
+ * 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.
+ *
+ * $FreeBSD$
+ */
+#ifndef _SCIF_SAS_STP_TASK_REQUEST_H_
+#define _SCIF_SAS_STP_TASK_REQUEST_H_
+
+/**
+ * @file
+ *
+ * @brief This file contains the protected interface structures, constants,
+ * and methods for the SCIF_SAS_STP_TASK_REQUEST object.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif // __cplusplus
+
+#include <dev/isci/scil/sati_translator_sequence.h>
+#include <dev/isci/scil/sci_types.h>
+#include <dev/isci/scil/sci_status.h>
+
+/**
+ * @struct SCIF_SAS_STP_TASK_REQUEST
+ *
+ * @brief This structure contains all of the data specific to performing
+ * SATA/STP IO requests.
+ */
+typedef struct SCIF_SAS_STP_TASK_REQUEST
+{
+ /**
+ * This field contains the translation information utilized by SATI.
+ * For more information on this field please refer to
+ * SATI_TRANSLATOR_SEQUENCE.
+ */
+ SATI_TRANSLATOR_SEQUENCE_T sequence;
+
+} SCIF_SAS_STP_TASK_REQUEST_T;
+
+//extern SCI_BASE_REQUEST_STATE_HANDLER_T stp_io_request_constructed_handlers;
+
+struct SCIF_SAS_TASK_REQUEST;
+SCI_STATUS scif_sas_stp_task_request_construct(
+ struct SCIF_SAS_TASK_REQUEST * fw_task
+);
+
+void scif_sas_stp_task_request_abort_task_set_failure_handler(
+ struct SCIF_SAS_REMOTE_DEVICE * fw_device,
+ struct SCIF_SAS_TASK_REQUEST * fw_task
+);
+
+#ifdef __cplusplus
+}
+#endif // __cplusplus
+
+#endif // _SCIF_SAS_STP_TASK_REQUEST_H_
+
diff --git a/sys/dev/isci/scil/scif_sas_task_request.c b/sys/dev/isci/scil/scif_sas_task_request.c
new file mode 100644
index 0000000..0dddf36
--- /dev/null
+++ b/sys/dev/isci/scil/scif_sas_task_request.c
@@ -0,0 +1,481 @@
+/*-
+ * 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.
+ *
+ * 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 <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/**
+ * @file
+ *
+ * @brief This file contains the task management request object
+ * (SCIF_SAS_TASK_REQUEST) method implementations.
+ */
+
+
+#include <dev/isci/scil/intel_sas.h>
+
+#include <dev/isci/scil/scic_task_request.h>
+#include <dev/isci/scil/scic_remote_device.h>
+#include <dev/isci/scil/scic_user_callback.h>
+#include <dev/isci/scil/scic_controller.h>
+#include <dev/isci/scil/scif_user_callback.h>
+
+#include <dev/isci/scil/scif_sas_request.h>
+#include <dev/isci/scil/scif_sas_task_request.h>
+#include <dev/isci/scil/scif_sas_stp_task_request.h>
+#include <dev/isci/scil/scif_sas_logger.h>
+#include <dev/isci/scil/scif_sas_controller.h>
+#include <dev/isci/scil/scif_sas_domain.h>
+#include <dev/isci/scil/scif_sas_remote_device.h>
+#include <dev/isci/scil/scif_sas_smp_io_request.h>
+
+//******************************************************************************
+//* P U B L I C M E T H O D S
+//******************************************************************************
+
+U32 scif_task_request_get_object_size(
+ void
+)
+{
+ return (sizeof(SCIF_SAS_TASK_REQUEST_T) + scic_task_request_get_object_size());
+}
+
+// ---------------------------------------------------------------------------
+
+U8 scif_sas_task_request_get_function(
+ SCIF_SAS_TASK_REQUEST_T *fw_task
+)
+{
+ return fw_task->function;
+}
+
+// ---------------------------------------------------------------------------
+
+static
+SCI_STATUS scif_sas_task_request_generic_construct(
+ SCI_CONTROLLER_HANDLE_T scif_controller,
+ SCI_REMOTE_DEVICE_HANDLE_T scif_remote_device,
+ U16 io_tag,
+ void * user_task_request_object,
+ void * task_request_memory,
+ SCI_TASK_REQUEST_HANDLE_T * scif_task_request,
+ U8 task_function
+)
+{
+ SCI_STATUS status;
+ SCIF_SAS_CONTROLLER_T * fw_controller = (SCIF_SAS_CONTROLLER_T*)
+ scif_controller;
+ SCIF_SAS_TASK_REQUEST_T * fw_task = (SCIF_SAS_TASK_REQUEST_T*)
+ task_request_memory;
+ SCIF_SAS_REMOTE_DEVICE_T * fw_device = (SCIF_SAS_REMOTE_DEVICE_T*)
+ scif_remote_device;
+ U8 * core_request_memory;
+
+ SCIF_LOG_TRACE((
+ sci_base_object_get_logger(fw_controller),
+ SCIF_LOG_OBJECT_TASK_MANAGEMENT,
+ "scif_task_request_construct(0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x) enter\n",
+ scif_controller, scif_remote_device, io_tag, user_task_request_object,
+ task_request_memory, scif_task_request
+ ));
+
+ // Initialize the user's handle to the framework task request.
+ *scif_task_request = fw_task;
+
+ // initialize affected request count
+ fw_task->affected_request_count = 0;
+ fw_task->io_tag_to_manage = SCI_CONTROLLER_INVALID_IO_TAG;
+ fw_task->function = task_function;
+
+ if (task_function == SCI_SAS_HARD_RESET )
+ {
+ if (fw_device->containing_device != NULL )
+ {// Target Reset is for an expander attached device,
+ // go down to construct smp Phy Control request.
+ scif_sas_smp_request_construct_phy_control(
+ fw_controller,
+ fw_device->containing_device,
+ PHY_OPERATION_HARD_RESET,
+ fw_device->expander_phy_identifier,
+ user_task_request_object,
+ task_request_memory
+ );
+ }
+ else
+ {
+ scif_sas_request_construct(
+ &fw_task->parent,
+ fw_device,
+ sci_base_object_get_logger(fw_controller),
+ scif_sas_task_request_state_table
+ );
+
+ // If target reset is for a DA device, don't build task at all.
+ // Just set object association.
+ sci_object_set_association(fw_task, user_task_request_object);
+ }
+
+ return SCI_SUCCESS;
+ }
+
+ // Construct the parent object first in order to ensure logging can
+ // function.
+ scif_sas_request_construct(
+ &fw_task->parent,
+ fw_device,
+ sci_base_object_get_logger(fw_controller),
+ scif_sas_task_request_state_table
+ );
+
+ core_request_memory = (U8 *)task_request_memory + sizeof(SCIF_SAS_TASK_REQUEST_T);
+
+ status = scic_task_request_construct(
+ fw_controller->core_object,
+ fw_device->core_object,
+ io_tag,
+ fw_task,
+ core_request_memory,
+ &fw_task->parent.core_object
+ );
+
+ if (status == SCI_SUCCESS)
+ {
+ SMP_DISCOVER_RESPONSE_PROTOCOLS_T dev_protocols;
+
+ // These associations must be set early for the core io request
+ // object construction to complete correctly as there will be
+ // callbacks into the user driver framework during core construction
+ sci_object_set_association(fw_task, user_task_request_object);
+ sci_object_set_association(fw_task->parent.core_object, fw_task);
+
+ // Perform protocol specific core IO request construction.
+ scic_remote_device_get_protocols(fw_device->core_object, &dev_protocols);
+ if (dev_protocols.u.bits.attached_ssp_target)
+ status = scic_task_request_construct_ssp(fw_task->parent.core_object);
+ else if (dev_protocols.u.bits.attached_stp_target)
+ status = scif_sas_stp_task_request_construct(fw_task);
+ else
+ status = SCI_FAILURE_UNSUPPORTED_PROTOCOL;
+
+ if (status == SCI_SUCCESS)
+ {
+ sci_base_state_machine_logger_initialize(
+ &fw_task->parent.parent.state_machine_logger,
+ &fw_task->parent.parent.state_machine,
+ &fw_task->parent.parent.parent,
+ scif_cb_logger_log_states,
+ "SCIF_SAS_TASK_REQUEST_T", "base_state_machine",
+ SCIF_LOG_OBJECT_TASK_MANAGEMENT
+ );
+ }
+ else
+ {
+ SCIF_LOG_WARNING((
+ sci_base_object_get_logger(fw_task),
+ SCIF_LOG_OBJECT_TASK_MANAGEMENT,
+ "Device:0x%x TaskRequest:0x%x Function:0x%x construct failed\n",
+ fw_device, fw_task, scif_sas_task_request_get_function(fw_task)
+ ));
+ }
+ }
+
+ return status;
+}
+
+// ---------------------------------------------------------------------------
+
+SCI_STATUS scif_sas_internal_task_request_construct(
+ SCI_CONTROLLER_HANDLE_T scif_controller,
+ SCI_REMOTE_DEVICE_HANDLE_T scif_remote_device,
+ U16 io_tag,
+ void * task_request_memory,
+ SCI_TASK_REQUEST_HANDLE_T * scif_task_request,
+ U8 task_function
+)
+{
+ SCI_STATUS status;
+ SCIF_SAS_TASK_REQUEST_T * fw_task;
+
+ status = scif_sas_task_request_generic_construct(
+ scif_controller,
+ scif_remote_device,
+ io_tag,
+ NULL,
+ task_request_memory,
+ scif_task_request,
+ task_function
+ );
+
+ fw_task = (SCIF_SAS_TASK_REQUEST_T *)task_request_memory;
+
+ fw_task->parent.is_internal = TRUE;
+
+ return status;
+}
+
+// ---------------------------------------------------------------------------
+
+SCI_STATUS scif_task_request_construct(
+ SCI_CONTROLLER_HANDLE_T scif_controller,
+ SCI_REMOTE_DEVICE_HANDLE_T scif_remote_device,
+ U16 io_tag,
+ void * user_task_request_object,
+ void * task_request_memory,
+ SCI_TASK_REQUEST_HANDLE_T * scif_task_request
+)
+{
+ SCI_STATUS status;
+ U8 task_function =
+ scif_cb_task_request_get_function(user_task_request_object);
+
+ status = scif_sas_task_request_generic_construct(
+ scif_controller,
+ scif_remote_device,
+ io_tag,
+ user_task_request_object,
+ task_request_memory,
+ scif_task_request,
+ task_function
+ );
+
+ return status;
+}
+
+// ---------------------------------------------------------------------------
+
+void scif_sas_internal_task_request_destruct(
+ SCIF_SAS_TASK_REQUEST_T * fw_internal_task
+)
+{
+ SCIF_SAS_CONTROLLER_T * fw_controller =
+ fw_internal_task->parent.device->domain->controller;
+ scif_sas_controller_free_internal_request(fw_controller, fw_internal_task);
+}
+
+// ---------------------------------------------------------------------------
+
+void scic_cb_task_request_complete(
+ SCI_CONTROLLER_HANDLE_T controller,
+ SCI_REMOTE_DEVICE_HANDLE_T remote_device,
+ SCI_TASK_REQUEST_HANDLE_T task_request,
+ SCI_TASK_STATUS completion_status
+)
+{
+ SCIF_SAS_CONTROLLER_T * fw_controller = (SCIF_SAS_CONTROLLER_T*)
+ sci_object_get_association(controller);
+ SCIF_SAS_REMOTE_DEVICE_T * fw_device = (SCIF_SAS_REMOTE_DEVICE_T*)
+ sci_object_get_association(remote_device);
+ SCIF_SAS_TASK_REQUEST_T * fw_task = (SCIF_SAS_TASK_REQUEST_T*)
+ sci_object_get_association(task_request);
+ SCI_STATUS status;
+
+ SCIF_LOG_TRACE((
+ sci_base_object_get_logger(fw_controller),
+ SCIF_LOG_OBJECT_TASK_MANAGEMENT,
+ "scic_cb_task_request_complete(0x%x, 0x%x, 0x%x, 0x%x) enter\n",
+ controller, remote_device, task_request, completion_status
+ ));
+
+ status = fw_task->parent.state_handlers->complete_handler(
+ &fw_task->parent.parent
+ );
+
+ if (status == SCI_SUCCESS)
+ {
+ if (fw_task->parent.protocol_complete_handler != NULL)
+ {
+ status = fw_task->parent.protocol_complete_handler(
+ fw_controller, fw_device, &fw_task->parent, (SCI_STATUS *)&completion_status
+ );
+ }
+
+ if (status == SCI_SUCCESS)
+ {
+ SCIF_LOG_WARNING((
+ sci_base_object_get_logger(fw_task),
+ SCIF_LOG_OBJECT_TASK_MANAGEMENT,
+ "RemoteDevice:0x%x TaskRequest:0x%x Function:0x%x CompletionStatus:0x%x "
+ "completed\n",
+ fw_device, fw_task,
+ scif_sas_task_request_get_function(fw_task),
+ completion_status
+ ));
+
+ // If this isn't an internal framework IO request, then simply pass the
+ // notification up to the SCIF user. Otherwise, immediately complete the
+ // task since there is no SCIF user to notify.
+ if (fw_task->parent.is_internal == FALSE)
+ {
+ scif_cb_task_request_complete(
+ fw_controller, fw_device, fw_task, completion_status
+ );
+ }
+ else
+ {
+ scif_controller_complete_task(
+ fw_controller,
+ fw_device,
+ fw_task
+ );
+ }
+ }
+ }
+}
+
+// ---------------------------------------------------------------------------
+
+U32 scic_cb_ssp_task_request_get_lun(
+ void * scic_user_task_request
+)
+{
+ SCIF_SAS_TASK_REQUEST_T * fw_task = (SCIF_SAS_TASK_REQUEST_T*)
+ scic_user_task_request;
+
+ fw_task->parent.lun = scif_cb_task_request_get_lun(
+ fw_task->parent.parent.parent.associated_object
+ );
+
+ return fw_task->parent.lun;
+}
+
+// ---------------------------------------------------------------------------
+
+U8 scic_cb_ssp_task_request_get_function(
+ void * scic_user_task_request
+)
+{
+ SCIF_SAS_TASK_REQUEST_T * fw_task = (SCIF_SAS_TASK_REQUEST_T*)
+ scic_user_task_request;
+
+ return scif_sas_task_request_get_function(fw_task);
+}
+
+// ---------------------------------------------------------------------------
+
+U16 scic_cb_ssp_task_request_get_io_tag_to_manage(
+ void * scic_user_task_request
+)
+{
+ SCIF_SAS_TASK_REQUEST_T * fw_task = (SCIF_SAS_TASK_REQUEST_T*)
+ scic_user_task_request;
+
+ fw_task->io_tag_to_manage
+ = scif_cb_task_request_get_io_tag_to_manage(
+ fw_task->parent.parent.parent.associated_object
+ );
+
+ return fw_task->io_tag_to_manage;
+}
+
+// ---------------------------------------------------------------------------
+
+void * scic_cb_ssp_task_request_get_response_data_address(
+ void * scic_user_task_request
+)
+{
+ SCIF_SAS_TASK_REQUEST_T * fw_task = (SCIF_SAS_TASK_REQUEST_T*)
+ scic_user_task_request;
+
+ return scif_cb_task_request_get_response_data_address(
+ fw_task->parent.parent.parent.associated_object
+ );
+}
+
+// ---------------------------------------------------------------------------
+
+U32 scic_cb_ssp_task_request_get_response_data_length(
+ void * scic_user_task_request
+)
+{
+ SCIF_SAS_TASK_REQUEST_T * fw_task = (SCIF_SAS_TASK_REQUEST_T*)
+ scic_user_task_request;
+
+ return scif_cb_task_request_get_response_data_length(
+ fw_task->parent.parent.parent.associated_object
+ );
+}
+
+//******************************************************************************
+//* P R O T E C T E D M E T H O D S
+//******************************************************************************
+
+/**
+ * @brief This method performs functionality required after a task management
+ * operation (either a task management request or a silicon task
+ * termination) has finished.
+ *
+ * @param[in] fw_task This parameter specifies the request that has
+ * the operation completing.
+ *
+ * @return none
+ */
+void scif_sas_task_request_operation_complete(
+ SCIF_SAS_TASK_REQUEST_T * fw_task
+)
+{
+ SCIF_LOG_TRACE((
+ sci_base_object_get_logger(fw_task),
+ SCIF_LOG_OBJECT_TASK_MANAGEMENT,
+ "scif_sas_task_request_operation_complete(0x%x) enter\n",
+ fw_task
+ ));
+
+ fw_task->affected_request_count--;
+
+ SCIF_LOG_INFO((
+ sci_base_object_get_logger(fw_task),
+ SCIF_LOG_OBJECT_TASK_MANAGEMENT,
+ "TaskRequest:0x%x current affected request count:0x%x\n",
+ fw_task, fw_task->affected_request_count
+ ));
+}
+
diff --git a/sys/dev/isci/scil/scif_sas_task_request.h b/sys/dev/isci/scil/scif_sas_task_request.h
new file mode 100644
index 0000000..3fd85e0
--- /dev/null
+++ b/sys/dev/isci/scil/scif_sas_task_request.h
@@ -0,0 +1,143 @@
+/*-
+ * 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.
+ *
+ * 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.
+ *
+ * $FreeBSD$
+ */
+#ifndef _SCIF_SAS_TASK_REQUEST_H_
+#define _SCIF_SAS_TASK_REQUEST_H_
+
+/**
+ * @file
+ *
+ * @brief This file contains the protected interface structures, constants,
+ * and methods for the SCIF_SAS_TASK_REQUEST object.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif // __cplusplus
+
+#include <dev/isci/scil/sati_translator_sequence.h>
+#include <dev/isci/scil/scif_task_request.h>
+#include <dev/isci/scil/sci_base_request.h>
+#include <dev/isci/scil/scif_sas_request.h>
+#include <dev/isci/scil/scif_sas_internal_io_request.h>
+#include <dev/isci/scil/intel_sas.h>
+
+/**
+ * @struct SCIF_SAS_TASK_REQUEST
+ *
+ * @brief The SCI SAS Framework Task request object abstracts the SAS task
+ * management behavior for the framework component. Additionally,
+ * it provides a higher level of abstraction for the core task
+ * request object.
+ */
+typedef struct SCIF_SAS_TASK_REQUEST
+{
+ /**
+ * The SCIF_SAS_REQUEST is the parent object for the
+ * SCIF_SAS_TASK_REQUEST object.
+ */
+ SCIF_SAS_REQUEST_T parent;
+
+ /**
+ * This field contains the number of current requests affected by
+ * this task management request. This number indicates all of the
+ * requests terminated in the silicon (including previous task requests).
+ */
+ U16 affected_request_count;
+
+ /**
+ * This field specifies the tag for the IO request or the tag to be
+ * managed for a task management request.
+ * This field is utilized during internal IO requests.
+ */
+ U16 io_tag_to_manage;
+
+ /**
+ * This field will be utilized to specify the task management function
+ * of this task request.
+ */
+ SCI_SAS_TASK_MGMT_FUNCTION_T function;
+
+} SCIF_SAS_TASK_REQUEST_T;
+
+extern SCI_BASE_STATE_T scif_sas_task_request_state_table[];
+extern SCI_BASE_REQUEST_STATE_HANDLER_T
+ scif_sas_task_request_state_handler_table[];
+
+void scif_sas_task_request_operation_complete(
+ SCIF_SAS_TASK_REQUEST_T * fw_task
+);
+
+U8 scif_sas_task_request_get_function(
+ SCIF_SAS_TASK_REQUEST_T * fw_task
+);
+
+SCI_STATUS scif_sas_internal_task_request_construct(
+ SCI_CONTROLLER_HANDLE_T scif_controller,
+ SCI_REMOTE_DEVICE_HANDLE_T scif_remote_device,
+ U16 io_tag,
+ void * task_request_memory,
+ SCI_TASK_REQUEST_HANDLE_T * scif_task_request,
+ U8 task_function
+);
+
+void scif_sas_internal_task_request_destruct(
+ SCIF_SAS_TASK_REQUEST_T * fw_internal_task
+);
+
+#ifdef __cplusplus
+}
+#endif // __cplusplus
+
+#endif // _SCIF_SAS_TASK_REQUEST_H_
+
diff --git a/sys/dev/isci/scil/scif_sas_task_request_state_handlers.c b/sys/dev/isci/scil/scif_sas_task_request_state_handlers.c
new file mode 100644
index 0000000..0e032e8
--- /dev/null
+++ b/sys/dev/isci/scil/scif_sas_task_request_state_handlers.c
@@ -0,0 +1,404 @@
+/*-
+ * 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.
+ *
+ * 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 <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/**
+ * @file
+ *
+ * @brief This file contains all of the method implementations pertaining
+ * to the framework io request state handler methods.
+ */
+
+#include <dev/isci/scil/scif_sas_logger.h>
+#include <dev/isci/scil/scif_sas_task_request.h>
+
+//******************************************************************************
+//* C O N S T R U C T E D H A N D L E R S
+//******************************************************************************
+
+/**
+ * @brief This method provides CONSTRUCTED state specific handling for
+ * when the user attempts to start the supplied task request.
+ *
+ * @param[in] task_request This parameter specifies the task request object
+ * to be started.
+ *
+ * @return This method returns a value indicating if the task request was
+ * successfully started or not.
+ * @retval SCI_SUCCESS This return value indicates successful starting
+ * of the task request.
+ */
+static
+SCI_STATUS scif_sas_task_request_constructed_start_handler(
+ SCI_BASE_REQUEST_T * task_request
+)
+{
+ sci_base_state_machine_change_state(
+ &task_request->state_machine, SCI_BASE_REQUEST_STATE_STARTED
+ );
+
+ return SCI_SUCCESS;
+}
+
+/**
+ * @brief This method provides CONSTRUCTED state specific handling for
+ * when the user attempts to abort the supplied task request.
+ *
+ * @param[in] task_request This parameter specifies the task request object
+ * to be aborted.
+ *
+ * @return This method returns a value indicating if the task request was
+ * successfully aborted or not.
+ * @retval SCI_SUCCESS This return value indicates successful aborting
+ * of the task request.
+ */
+static
+SCI_STATUS scif_sas_task_request_constructed_abort_handler(
+ SCI_BASE_REQUEST_T * task_request
+)
+{
+ sci_base_state_machine_change_state(
+ &task_request->state_machine, SCI_BASE_REQUEST_STATE_COMPLETED
+ );
+
+ return SCI_SUCCESS;
+}
+
+//******************************************************************************
+//* S T A R T E D H A N D L E R S
+//******************************************************************************
+
+/**
+ * @brief This method provides STARTED state specific handling for
+ * when the user attempts to abort the supplied task request.
+ *
+ * @param[in] task_request This parameter specifies the task request object
+ * to be aborted.
+ *
+ * @return This method returns a value indicating if the aborting the
+ * task request was successfully started.
+ * @retval SCI_SUCCESS This return value indicates that the abort process
+ * began successfully.
+ */
+static
+SCI_STATUS scif_sas_task_request_started_abort_handler(
+ SCI_BASE_REQUEST_T * task_request
+)
+{
+ SCIF_SAS_REQUEST_T * fw_request = (SCIF_SAS_REQUEST_T *) task_request;
+
+ sci_base_state_machine_change_state(
+ &task_request->state_machine, SCI_BASE_REQUEST_STATE_ABORTING
+ );
+
+ return fw_request->status;
+}
+
+/**
+ * @brief This method provides STARTED state specific handling for
+ * when the user attempts to complete the supplied task request.
+ *
+ * @param[in] task_request This parameter specifies the task request object
+ * to be completed.
+ *
+ * @return This method returns a value indicating if the completion of the
+ * task request was successful.
+ * @retval SCI_SUCCESS This return value indicates that the completion process
+ * was successful.
+ */
+static
+SCI_STATUS scif_sas_task_request_started_complete_handler(
+ SCI_BASE_REQUEST_T * task_request
+)
+{
+ sci_base_state_machine_change_state(
+ &task_request->state_machine, SCI_BASE_REQUEST_STATE_COMPLETED
+ );
+
+ return SCI_SUCCESS;
+}
+
+//******************************************************************************
+//* C O M P L E T E D H A N D L E R S
+//******************************************************************************
+
+/**
+ * @brief This method provides COMPLETED state specific handling for
+ * when the user attempts to destruct the supplied task request.
+ *
+ * @param[in] task_request This parameter specifies the task request object
+ * to be destructed.
+ *
+ * @return This method returns a value indicating if the destruct
+ * operation was successful.
+ * @retval SCI_SUCCESS This return value indicates that the destruct
+ * was successful.
+ */
+static
+SCI_STATUS scif_sas_task_request_completed_destruct_handler(
+ SCI_BASE_REQUEST_T * task_request
+)
+{
+ SCIF_SAS_REQUEST_T * fw_request = (SCIF_SAS_REQUEST_T *)task_request;
+
+ sci_base_state_machine_change_state(
+ &task_request->state_machine, SCI_BASE_REQUEST_STATE_FINAL
+ );
+
+ sci_base_state_machine_logger_deinitialize(
+ &task_request->state_machine_logger,
+ &task_request->state_machine
+ );
+
+ if (fw_request->is_internal == TRUE)
+ {
+ scif_sas_internal_task_request_destruct(
+ (SCIF_SAS_TASK_REQUEST_T *)fw_request
+ );
+ }
+
+ return SCI_SUCCESS;
+}
+
+//******************************************************************************
+//* A B O R T I N G H A N D L E R S
+//******************************************************************************
+
+/**
+ * @brief This method provides ABORTING state specific handling for
+ * when the user attempts to complete the supplied task request.
+ *
+ * @param[in] task_request This parameter specifies the task request object
+ * to be completed.
+ *
+ * @return This method returns a value indicating if the completion
+ * operation was successful.
+ * @retval SCI_SUCCESS This return value indicates that the completion
+ * was successful.
+ */
+static
+SCI_STATUS scif_sas_task_request_aborting_complete_handler(
+ SCI_BASE_REQUEST_T * task_request
+)
+{
+ sci_base_state_machine_change_state(
+ &task_request->state_machine, SCI_BASE_REQUEST_STATE_COMPLETED
+ );
+
+ return SCI_SUCCESS;
+}
+
+//******************************************************************************
+//* D E F A U L T H A N D L E R S
+//******************************************************************************
+
+/**
+ * @brief This method provides DEFAULT handling for when the user
+ * attempts to start the supplied task request.
+ *
+ * @param[in] task_request This parameter specifies the task request object
+ * to be started.
+ *
+ * @return This method returns an indication that the start operation is
+ * not allowed.
+ * @retval SCI_FAILURE_INVALID_STATE This value is always returned.
+ */
+static
+SCI_STATUS scif_sas_task_request_default_start_handler(
+ SCI_BASE_REQUEST_T * task_request
+)
+{
+ SCIF_LOG_ERROR((
+ sci_base_object_get_logger((SCIF_SAS_TASK_REQUEST_T *) task_request),
+ SCIF_LOG_OBJECT_TASK_MANAGEMENT,
+ "TaskRequest:0x%x State:0x%x invalid state to start\n",
+ task_request,
+ sci_base_state_machine_get_state(
+ &((SCIF_SAS_TASK_REQUEST_T *) task_request)->parent.parent.state_machine)
+ ));
+
+ return SCI_FAILURE_INVALID_STATE;
+}
+
+/**
+ * @brief This method provides DEFAULT handling for when the user
+ * attempts to abort the supplied task request.
+ *
+ * @param[in] task_request This parameter specifies the task request object
+ * to be aborted.
+ *
+ * @return This method returns an indication that the abort operation is
+ * not allowed.
+ * @retval SCI_FAILURE_INVALID_STATE This value is always returned.
+ */
+static
+SCI_STATUS scif_sas_task_request_default_abort_handler(
+ SCI_BASE_REQUEST_T * task_request
+)
+{
+ SCIF_LOG_ERROR((
+ sci_base_object_get_logger((SCIF_SAS_TASK_REQUEST_T *) task_request),
+ SCIF_LOG_OBJECT_TASK_MANAGEMENT,
+ "TaskRequest:0x%x State:0x%x invalid state to abort\n",
+ task_request,
+ sci_base_state_machine_get_state(
+ &((SCIF_SAS_TASK_REQUEST_T *) task_request)->parent.parent.state_machine)
+ ));
+
+ return SCI_FAILURE_INVALID_STATE;
+}
+
+/**
+ * @brief This method provides DEFAULT handling for when the user
+ * attempts to complete the supplied task request.
+ *
+ * @param[in] task_request This parameter specifies the task request object
+ * to be completed.
+ *
+ * @return This method returns an indication that complete operation is
+ * not allowed.
+ * @retval SCI_FAILURE_INVALID_STATE This value is always returned.
+ */
+static
+SCI_STATUS scif_sas_task_request_default_complete_handler(
+ SCI_BASE_REQUEST_T * task_request
+)
+{
+ SCIF_LOG_ERROR((
+ sci_base_object_get_logger((SCIF_SAS_TASK_REQUEST_T *) task_request),
+ SCIF_LOG_OBJECT_TASK_MANAGEMENT,
+ "TaskRequest:0x%x State:0x%x invalid state to complete\n",
+ task_request,
+ sci_base_state_machine_get_state(
+ &((SCIF_SAS_TASK_REQUEST_T *) task_request)->parent.parent.state_machine)
+ ));
+
+ return SCI_FAILURE_INVALID_STATE;
+}
+
+/**
+ * @brief This method provides DEFAULT handling for when the user
+ * attempts to destruct the supplied task request.
+ *
+ * @param[in] task_request This parameter specifies the task request object
+ * to be destructed.
+ *
+ * @return This method returns an indication that destruct operation is
+ * not allowed.
+ * @retval SCI_FAILURE_INVALID_STATE This value is always returned.
+ */
+static
+SCI_STATUS scif_sas_task_request_default_destruct_handler(
+ SCI_BASE_REQUEST_T * task_request
+)
+{
+ SCIF_LOG_ERROR((
+ sci_base_object_get_logger((SCIF_SAS_TASK_REQUEST_T *) task_request),
+ SCIF_LOG_OBJECT_TASK_MANAGEMENT,
+ "TaskRequest:0x%x State:0x%x invalid state to destruct.\n",
+ task_request,
+ sci_base_state_machine_get_state(
+ &((SCIF_SAS_TASK_REQUEST_T *) task_request)->parent.parent.state_machine)
+ ));
+
+ return SCI_FAILURE_INVALID_STATE;
+}
+
+
+SCI_BASE_REQUEST_STATE_HANDLER_T scif_sas_task_request_state_handler_table[] =
+{
+ // SCI_BASE_REQUEST_STATE_INITIAL
+ {
+ scif_sas_task_request_default_start_handler,
+ scif_sas_task_request_default_abort_handler,
+ scif_sas_task_request_default_complete_handler,
+ scif_sas_task_request_default_destruct_handler
+ },
+ // SCI_BASE_REQUEST_STATE_CONSTRUCTED
+ {
+ scif_sas_task_request_constructed_start_handler,
+ scif_sas_task_request_constructed_abort_handler,
+ scif_sas_task_request_default_complete_handler,
+ scif_sas_task_request_default_destruct_handler
+ },
+ // SCI_BASE_REQUEST_STATE_STARTED
+ {
+ scif_sas_task_request_default_start_handler,
+ scif_sas_task_request_started_abort_handler,
+ scif_sas_task_request_started_complete_handler,
+ scif_sas_task_request_default_destruct_handler
+ },
+ // SCI_BASE_REQUEST_STATE_COMPLETED
+ {
+ scif_sas_task_request_default_start_handler,
+ scif_sas_task_request_default_abort_handler,
+ scif_sas_task_request_default_complete_handler,
+ scif_sas_task_request_completed_destruct_handler
+ },
+ // SCI_BASE_REQUEST_STATE_ABORTING
+ {
+ scif_sas_task_request_default_start_handler,
+ scif_sas_task_request_default_abort_handler,
+ scif_sas_task_request_aborting_complete_handler,
+ scif_sas_task_request_default_destruct_handler
+ },
+ // SCI_BASE_REQUEST_STATE_FINAL
+ {
+ scif_sas_task_request_default_start_handler,
+ scif_sas_task_request_default_abort_handler,
+ scif_sas_task_request_default_complete_handler,
+ scif_sas_task_request_default_destruct_handler
+ },
+};
+
diff --git a/sys/dev/isci/scil/scif_sas_task_request_states.c b/sys/dev/isci/scil/scif_sas_task_request_states.c
new file mode 100644
index 0000000..684fda5
--- /dev/null
+++ b/sys/dev/isci/scil/scif_sas_task_request_states.c
@@ -0,0 +1,287 @@
+/*-
+ * 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.
+ *
+ * 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 <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/**
+ * @file
+ *
+ * @brief This file contains all of the SCIF_SAS_TASK_REQUEST object
+ * state entrance and exit method implementations.
+ */
+
+#include <dev/isci/scil/scif_sas_task_request.h>
+
+//******************************************************************************
+//* P R O T E C T E D M E T H O D S
+//******************************************************************************
+
+/**
+ * @brief This method implements the actions taken when entering the
+ * INITIAL state.
+ *
+ * @param[in] object This parameter specifies the base object for which
+ * the state transition is occurring. This is cast into a
+ * SCIF_SAS_TASK_REQUEST object in the method implementation.
+ *
+ * @return none
+ */
+static
+void scif_sas_task_request_initial_state_enter(
+ SCI_BASE_OBJECT_T *object
+)
+{
+ SCIF_SAS_TASK_REQUEST_T * fw_task = (SCIF_SAS_TASK_REQUEST_T *)object;
+
+ SET_STATE_HANDLER(
+ &fw_task->parent,
+ scif_sas_task_request_state_handler_table,
+ SCI_BASE_REQUEST_STATE_INITIAL
+ );
+
+ // Initial state is a transitional state to the constructed state
+ sci_base_state_machine_change_state(
+ &fw_task->parent.parent.state_machine, SCI_BASE_REQUEST_STATE_CONSTRUCTED
+ );
+}
+
+/**
+ * @brief This method implements the actions taken when entering the
+ * CONSTRUCTED state.
+ *
+ * @param[in] object This parameter specifies the base object for which
+ * the state transition is occurring. This is cast into a
+ * SCIF_SAS_TASK_REQUEST object in the method implementation.
+ *
+ * @return none
+ */
+static
+void scif_sas_task_request_constructed_state_enter(
+ SCI_BASE_OBJECT_T *object
+)
+{
+ SCIF_SAS_TASK_REQUEST_T * fw_task = (SCIF_SAS_TASK_REQUEST_T *)object;
+
+ SET_STATE_HANDLER(
+ &fw_task->parent,
+ scif_sas_task_request_state_handler_table,
+ SCI_BASE_REQUEST_STATE_CONSTRUCTED
+ );
+}
+
+/**
+ * @brief This method implements the actions taken when entering the
+ * STARTED state.
+ *
+ * @param[in] object This parameter specifies the base object for which
+ * the state transition is occurring. This is cast into a
+ * SCIF_SAS_TASK_REQUEST object in the method implementation.
+ *
+ * @return none
+ */
+static
+void scif_sas_task_request_started_state_enter(
+ SCI_BASE_OBJECT_T *object
+)
+{
+ SCIF_SAS_TASK_REQUEST_T * fw_task = (SCIF_SAS_TASK_REQUEST_T *)object;
+
+ SET_STATE_HANDLER(
+ &fw_task->parent,
+ scif_sas_task_request_state_handler_table,
+ SCI_BASE_REQUEST_STATE_STARTED
+ );
+
+ // Increment the affected request count to include the task performing
+ // the task management to ensure we don't complete the task request until
+ // all terminations and the task itself have completed.
+ fw_task->affected_request_count++;
+}
+
+/**
+ * @brief This method implements the actions taken when entering the
+ * COMPLETED state.
+ *
+ * @param[in] object This parameter specifies the base object for which
+ * the state transition is occurring. This is cast into a
+ * SCIF_SAS_TASK_REQUEST object in the method implementation.
+ *
+ * @return none
+ */
+static
+void scif_sas_task_request_completed_state_enter(
+ SCI_BASE_OBJECT_T *object
+)
+{
+ SCIF_SAS_TASK_REQUEST_T * fw_task = (SCIF_SAS_TASK_REQUEST_T *)object;
+
+ SET_STATE_HANDLER(
+ &fw_task->parent,
+ scif_sas_task_request_state_handler_table,
+ SCI_BASE_REQUEST_STATE_COMPLETED
+ );
+
+ // Check to see if the task management operation is now finished (i.e.
+ // all of the task terminations and the task management request are
+ // complete).
+ scif_sas_task_request_operation_complete(fw_task);
+}
+
+/**
+ * @brief This method implements the actions taken when entering the
+ * ABORTING state.
+ *
+ * @param[in] object This parameter specifies the base object for which
+ * the state transition is occurring. This is cast into a
+ * SCIF_SAS_TASK_REQUEST object in the method implementation.
+ *
+ * @return none
+ */
+static
+void scif_sas_task_request_aborting_state_enter(
+ SCI_BASE_OBJECT_T *object
+)
+{
+ SCIF_SAS_TASK_REQUEST_T * fw_task = (SCIF_SAS_TASK_REQUEST_T *)object;
+
+ SET_STATE_HANDLER(
+ &fw_task->parent,
+ scif_sas_task_request_state_handler_table,
+ SCI_BASE_REQUEST_STATE_ABORTING
+ );
+
+ /// @todo Is terminating a previously outstanding task request right?
+ fw_task->parent.status = scif_sas_request_terminate_start(
+ &fw_task->parent, fw_task->parent.core_object
+ );
+}
+
+/**
+ * @brief This method implements the actions taken when exiting the
+ * ABORTING state.
+ *
+ * @param[in] object This parameter specifies the base object for which
+ * the state transition is occurring. This is cast into a
+ * SCIF_SAS_TASK_REQUEST object in the method implementation.
+ *
+ * @return none
+ */
+static
+void scif_sas_task_request_aborting_state_exit(
+ SCI_BASE_OBJECT_T *object
+)
+{
+ SCIF_SAS_REQUEST_T * fw_request = (SCIF_SAS_REQUEST_T *)object;
+ scif_sas_request_terminate_complete(fw_request);
+}
+
+/**
+ * @brief This method implements the actions taken when entering the
+ * FINAL state.
+ *
+ * @param[in] object This parameter specifies the base object for which
+ * the state transition is occurring. This is cast into a
+ * SCIF_SAS_TASK_REQUEST object in the method implementation.
+ *
+ * @return none
+ */
+static
+void scif_sas_task_request_final_state_enter(
+ SCI_BASE_OBJECT_T *object
+)
+{
+ SCIF_SAS_TASK_REQUEST_T * fw_task = (SCIF_SAS_TASK_REQUEST_T *)object;
+
+ SET_STATE_HANDLER(
+ &fw_task->parent,
+ scif_sas_task_request_state_handler_table,
+ SCI_BASE_REQUEST_STATE_FINAL
+ );
+}
+
+
+SCI_BASE_STATE_T
+ scif_sas_task_request_state_table[SCI_BASE_REQUEST_MAX_STATES] =
+{
+ {
+ SCI_BASE_REQUEST_STATE_INITIAL,
+ scif_sas_task_request_initial_state_enter,
+ NULL
+ },
+ {
+ SCI_BASE_REQUEST_STATE_CONSTRUCTED,
+ scif_sas_task_request_constructed_state_enter,
+ NULL
+ },
+ {
+ SCI_BASE_REQUEST_STATE_STARTED,
+ scif_sas_task_request_started_state_enter,
+ NULL
+ },
+ {
+ SCI_BASE_REQUEST_STATE_COMPLETED,
+ scif_sas_task_request_completed_state_enter,
+ NULL
+ },
+ {
+ SCI_BASE_REQUEST_STATE_ABORTING,
+ scif_sas_task_request_aborting_state_enter,
+ scif_sas_task_request_aborting_state_exit
+ },
+ {
+ SCI_BASE_REQUEST_STATE_FINAL,
+ scif_sas_task_request_final_state_enter,
+ NULL
+ },
+};
+
diff --git a/sys/dev/isci/scil/scif_sas_timer.c b/sys/dev/isci/scil/scif_sas_timer.c
new file mode 100644
index 0000000..6457f60
--- /dev/null
+++ b/sys/dev/isci/scil/scif_sas_timer.c
@@ -0,0 +1,123 @@
+/*-
+ * 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.
+ *
+ * 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 <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/**
+ * @file
+ *
+ * @brief This file contains core callback notificiations implemented by
+ * the framework for timers.
+ */
+
+#include <dev/isci/scil/sci_types.h>
+#include <dev/isci/scil/scif_user_callback.h>
+#include <dev/isci/scil/scic_user_callback.h>
+
+#include <dev/isci/scil/scif_sas_controller.h>
+
+void * scic_cb_timer_create(
+ SCI_CONTROLLER_HANDLE_T controller,
+ SCI_TIMER_CALLBACK_T timer_callback,
+ void * cookie
+)
+{
+ SCIF_SAS_CONTROLLER_T * fw_controller = (SCIF_SAS_CONTROLLER_T *)
+ sci_object_get_association(controller);
+
+ return scif_cb_timer_create(fw_controller, timer_callback, cookie);
+}
+
+// -----------------------------------------------------------------------------
+
+void scic_cb_timer_destroy(
+ SCI_CONTROLLER_HANDLE_T controller,
+ void * timer
+)
+{
+ SCIF_SAS_CONTROLLER_T * fw_controller = (SCIF_SAS_CONTROLLER_T *)
+ sci_object_get_association(controller);
+ if (timer != NULL)
+ {
+ scif_cb_timer_destroy(fw_controller, timer);
+ timer = NULL;
+ }
+}
+
+// -----------------------------------------------------------------------------
+
+void scic_cb_timer_start(
+ SCI_CONTROLLER_HANDLE_T controller,
+ void * timer,
+ U32 milliseconds
+)
+{
+ SCIF_SAS_CONTROLLER_T * fw_controller = (SCIF_SAS_CONTROLLER_T *)
+ sci_object_get_association(controller);
+
+ scif_cb_timer_start(fw_controller, timer, milliseconds);
+}
+
+// -----------------------------------------------------------------------------
+
+void scic_cb_timer_stop(
+ SCI_CONTROLLER_HANDLE_T controller,
+ void * timer
+)
+{
+ SCIF_SAS_CONTROLLER_T * fw_controller = (SCIF_SAS_CONTROLLER_T *)
+ sci_object_get_association(controller);
+
+ scif_cb_timer_stop(fw_controller, timer);
+}
+
diff --git a/sys/dev/isci/scil/scif_task_request.h b/sys/dev/isci/scil/scif_task_request.h
new file mode 100644
index 0000000..c0ad087
--- /dev/null
+++ b/sys/dev/isci/scil/scif_task_request.h
@@ -0,0 +1,129 @@
+/*-
+ * 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.
+ *
+ * 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.
+ *
+ * $FreeBSD$
+ */
+#ifndef _SCIF_TASK_REQUEST_H_
+#define _SCIF_TASK_REQUEST_H_
+
+/**
+ * @file
+ *
+ * @brief This file contains the structures and interface methods that
+ * can be referenced and used by the SCI user for the SCI task
+ * management request object.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif // __cplusplus
+
+#include <dev/isci/scil/sci_types.h>
+#include <dev/isci/scil/sci_status.h>
+
+
+/**
+ * @brief This method simply returns the size required to construct an SCI
+ * based task request object (includes core & framework object size).
+ *
+ * @return Retrun the size of the SCI task request object.
+ */
+U32 scif_task_request_get_object_size(
+ void
+);
+
+/**
+ * @brief This method is called by the SCIF user to construct a task
+ * management request. This method will construct a SCIC task request
+ * internally.
+ *
+ * @note The SCI framework implementation will create an association between
+ * the user task request object and the framework task request object.
+ *
+ * @param[in] scif_controller the handle to the framework controller object
+ * for which to build an IO request.
+ * @param[in] scif_remote_device This parameter specifies the framework
+ * remote device with which this task request is to be associated.
+ * @param[in] 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
+ * scif_controller_start_task() method.
+ * @param[in] user_task_request_object This parameter specifies the user
+ * task request to be utilized during task construction. This task
+ * pointer will become the associated object for the framework
+ * task request object.
+ * @param[in] task_request_memory This parameter specifies the memory
+ * to be utilized in the construction of the framework task request.
+ * @param[in] scif_task_request This parameter specifies the handle to be
+ * utilized for all further interactions with this task request
+ * object.
+ *
+ * @return Indicate if the controller successfully built the task request.
+ * @retval SCI_SUCCESS This value is returned if the task request was
+ * successfully built.
+ */
+SCI_STATUS scif_task_request_construct(
+ SCI_CONTROLLER_HANDLE_T scif_controller,
+ SCI_REMOTE_DEVICE_HANDLE_T scif_remote_device,
+ U16 io_tag,
+ void * user_task_request_object,
+ void * task_request_memory,
+ SCI_TASK_REQUEST_HANDLE_T * scif_task_request
+);
+
+#ifdef __cplusplus
+}
+#endif // __cplusplus
+
+#endif // _SCIF_TASK_REQUEST_H_
+
diff --git a/sys/dev/isci/scil/scif_user_callback.h b/sys/dev/isci/scil/scif_user_callback.h
new file mode 100644
index 0000000..5478495
--- /dev/null
+++ b/sys/dev/isci/scil/scif_user_callback.h
@@ -0,0 +1,1049 @@
+/*-
+ * 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.
+ *
+ * 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.
+ *
+ * $FreeBSD$
+ */
+#ifndef _SCIF_USER_CALLBACK_H_
+#define _SCIF_USER_CALLBACK_H_
+
+/**
+ * @file
+ *
+ * @brief This file contains all of the interface methods/macros that must
+ * be implemented by an SCI Framework user.
+ */
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif // __cplusplus
+
+#include <dev/isci/scil/sci_types.h>
+#include <dev/isci/scil/sci_status.h>
+#include <dev/isci/scil/sci_controller.h>
+#include <dev/isci/scil/intel_sas.h>
+#include <dev/isci/scil/sci_memory_descriptor_list.h>
+
+
+/**
+ * @brief This callback method asks the user to create a timer and provide
+ * a handle for this timer for use in further timer interactions.
+ *
+ * @warning 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()).
+ *
+ * @param[in] timer_callback This parameter specifies the callback method
+ * to be invoked whenever the timer expires.
+ * @param[in] controller This parameter specifies the controller with
+ * which this timer is to be associated.
+ * @param[in] 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.
+ *
+ * @return 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 * scif_cb_timer_create(
+ SCI_CONTROLLER_HANDLE_T controller,
+ SCI_TIMER_CALLBACK_T timer_callback,
+ void * cookie
+);
+
+/**
+ * @brief This callback method asks the user to destory the supplied timer.
+ *
+ * @param[in] controller This parameter specifies the controller with
+ * which this timer is to associated.
+ * @param[in] timer This parameter specifies the timer to be destroyed.
+ *
+ * @return none
+ */
+void scif_cb_timer_destroy(
+ SCI_CONTROLLER_HANDLE_T controller,
+ void * timer
+);
+
+/**
+ * @brief This callback method asks the user to start the supplied timer.
+ *
+ * @warning All timers in the system started by the SCI Framework 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 Framework user's should be able to handle
+ * calls from the SCI Framework to stop a timer that may already
+ * be stopped.
+ *
+ * @param[in] controller This parameter specifies the controller with
+ * which this timer is to associated.
+ * @param[in] timer This parameter specifies the timer to be started.
+ * @param[in] 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.
+ *
+ * @return none
+ */
+void scif_cb_timer_start(
+ SCI_CONTROLLER_HANDLE_T controller,
+ void * timer,
+ U32 milliseconds
+);
+
+/**
+ * @brief This callback method asks the user to stop the supplied timer.
+ *
+ * @param[in] controller This parameter specifies the controller with
+ * which this timer is to associated.
+ * @param[in] timer This parameter specifies the timer to be stopped.
+ *
+ * @return none
+ */
+void scif_cb_timer_stop(
+ SCI_CONTROLLER_HANDLE_T controller,
+ void * timer
+);
+
+/**
+ * @brief This callback method asks the user to associate the supplied
+ * lock with an operating environment specific locking construct.
+ *
+ * @param[in] controller This parameter specifies the controller with
+ * which this lock is to be associated.
+ * @param[in] lock This parameter specifies the lock for which the
+ * user should associate an operating environment specific
+ * locking object.
+ *
+ * @see The SCI_LOCK_LEVEL enumeration for more information.
+ *
+ * @return none.
+ */
+void scif_cb_lock_associate(
+ SCI_CONTROLLER_HANDLE_T controller,
+ SCI_LOCK_HANDLE_T lock
+);
+
+/**
+ * @brief This callback method asks the user to de-associate the supplied
+ * lock with an operating environment specific locking construct.
+ *
+ * @param[in] controller This parameter specifies the controller with
+ * which this lock is to be de-associated.
+ * @param[in] lock This parameter specifies the lock for which the
+ * user should de-associate an operating environment specific
+ * locking object.
+ *
+ * @see The SCI_LOCK_LEVEL enumeration for more information.
+ *
+ * @return none.
+ */
+void scif_cb_lock_disassociate(
+ SCI_CONTROLLER_HANDLE_T controller,
+ SCI_LOCK_HANDLE_T lock
+);
+
+
+/**
+ * @brief This callback method asks the user to acquire/get the lock.
+ * This method should pend until the lock has been acquired.
+ *
+ * @param[in] controller This parameter specifies the controller with
+ * which this lock is associated.
+ * @param[in] lock This parameter specifies the lock to be acquired.
+ *
+ * @return none
+ */
+void scif_cb_lock_acquire(
+ SCI_CONTROLLER_HANDLE_T controller,
+ SCI_LOCK_HANDLE_T lock
+);
+
+/**
+ * @brief This callback method asks the user to release a lock.
+ *
+ * @param[in] controller This parameter specifies the controller with
+ * which this lock is associated.
+ * @param[in] lock This parameter specifies the lock to be released.
+ *
+ * @return none
+ */
+void scif_cb_lock_release(
+ SCI_CONTROLLER_HANDLE_T controller,
+ SCI_LOCK_HANDLE_T lock
+);
+
+/**
+ * @brief This user callback will inform the user that the controller has
+ * had a serious unexpected error. The user should not the error,
+ * disable interrupts, and wait for current ongoing processing to
+ * complete. Subsequently, the user should reset the controller.
+ *
+ * @param[in] controller This parameter specifies the controller that had
+ * an error.
+ *
+ * @return none
+ */
+void scif_cb_controller_error(
+ SCI_CONTROLLER_HANDLE_T controller,
+ SCI_CONTROLLER_ERROR error
+);
+
+/**
+ * @brief This user callback will inform the user that the controller has
+ * finished the start process.
+ *
+ * @param[in] controller This parameter specifies the controller that was
+ * started.
+ * @param[in] completion_status This parameter specifies the results of
+ * the start operation. SCI_SUCCESS indicates successful
+ * completion.
+ *
+ * @return none
+ */
+void scif_cb_controller_start_complete(
+ SCI_CONTROLLER_HANDLE_T controller,
+ SCI_STATUS completion_status
+);
+
+/**
+ * @brief This user callback will inform the user that the controller has
+ * finished the stop process. Note, after user calls
+ * scif_controller_stop(), before user receives this controller stop
+ * complete callback, user should not expect any callback from
+ * framework, such like scif_cb_domain_change_notification().
+ *
+ * @param[in] controller This parameter specifies the controller that was
+ * stopped.
+ * @param[in] completion_status This parameter specifies the results of
+ * the stop operation. SCI_SUCCESS indicates successful
+ * completion.
+ *
+ * @return none
+ */
+void scif_cb_controller_stop_complete(
+ SCI_CONTROLLER_HANDLE_T controller,
+ SCI_STATUS completion_status
+);
+
+/**
+ * @brief This method simply returns the virtual address associated
+ * with the scsi_io and byte_offset supplied parameters.
+ *
+ * @note This callback is not utilized in the fast path. The expectation
+ * is that this method is utilized for items such as SCSI to ATA
+ * translation for commands like INQUIRY, READ CAPACITY, etc.
+ *
+ * @param[in] scif_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.
+ * @param[in] byte_offset This parameter specifies the offset into the data
+ * buffers pointed to by the SGL. The byte offset starts at 0
+ * and continues until the last byte pointed to be the last SGL
+ * element.
+ *
+ * @return A virtual address pointer to the location specified by the
+ * parameters.
+ */
+U8 * scif_cb_io_request_get_virtual_address_from_sgl(
+ void * scif_user_io_request,
+ U32 byte_offset
+);
+
+#ifdef ENABLE_OSSL_COPY_BUFFER
+/**
+ * @brief This method is presently utilized in the PIO path,
+ * copies from UF buffer to the SGL buffer. This method
+ * can be served for other OS related copies.
+ *
+ * @param[in] 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.
+ * @param[in] source addr. Address of UF buffer.
+ * @param[in] offset. This parameter specifies the offset into the data
+ * buffers pointed to by the SGL. The byte offset starts at 0
+ * and continues until the last byte pointed to be the last SGL
+ * element.
+ * @param[in] length.
+ *
+ * @return None
+ */
+void scif_cb_io_request_copy_buffer(
+ void * scic_user_io_request,
+ U8 *source_addr,
+ U32 offset,
+ U32 length
+);
+#endif
+
+/**
+ * @brief This user callback will inform the user that an IO request has
+ * completed.
+ *
+ * @param[in] controller This parameter specifies the controller on
+ * which the IO request is completing.
+ * @param[in] remote_device This parameter specifies the remote device on
+ * which this request is completing.
+ * @param[in] io_request This parameter specifies the IO request that has
+ * completed.
+ * @param[in] completion_status This parameter specifies the results of
+ * the IO request operation. SCI_IO_SUCCESS indicates
+ * successful completion.
+ *
+ * @return none
+ */
+void scif_cb_io_request_complete(
+ SCI_CONTROLLER_HANDLE_T controller,
+ SCI_REMOTE_DEVICE_HANDLE_T remote_device,
+ SCI_IO_REQUEST_HANDLE_T io_request,
+ SCI_IO_STATUS completion_status
+);
+
+/**
+ * @brief This user callback will inform the user that a task management
+ * request completed.
+ *
+ * @param[in] controller This parameter specifies the controller on
+ * which the task management request is completing.
+ * @param[in] remote_device This parameter specifies the remote device on
+ * which this task management request is completing.
+ * @param[in] task_request This parameter specifies the task management
+ * request that has completed.
+ * @param[in] completion_status This parameter specifies the results of
+ * the IO request operation. SCI_TASK_SUCCESS indicates
+ * successful completion.
+ *
+ * @return none
+ */
+void scif_cb_task_request_complete(
+ SCI_CONTROLLER_HANDLE_T controller,
+ SCI_REMOTE_DEVICE_HANDLE_T remote_device,
+ SCI_TASK_REQUEST_HANDLE_T task_request,
+ SCI_TASK_STATUS completion_status
+);
+
+/**
+ * @brief This callback method asks the user to provide the number of
+ * bytes to be transfered as part of this request.
+ *
+ * @param[in] scif_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.
+ *
+ * @return This method returns the number of payload data bytes to be
+ * transfered for this IO request.
+ */
+U32 scif_cb_io_request_get_transfer_length(
+ void * scif_user_io_request
+);
+
+/**
+ * @brief This callback method asks the user to provide the data direction
+ * for this request.
+ *
+ * @param[in] scif_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.
+ *
+ * @return This method returns the value of SCI_IO_REQUEST_DATA_OUT,
+ * SCI_IO_REQUEST_DATA_IN, or SCI_IO_REQUEST_NO_DATA.
+ */
+SCI_IO_REQUEST_DATA_DIRECTION scif_cb_io_request_get_data_direction(
+ void * scif_user_io_request
+);
+
+#ifndef SCI_SGL_OPTIMIZATION_ENABLED
+/**
+ * @brief 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.
+ *
+ * @param[in] scif_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.
+ * @param[in] current_sge_address This parameter specifies the address for
+ * the current SGE (i.e. the one that has just processed).
+ * @param[out] next_sge An address specifying the location for the next scatter
+ * gather element to be processed.
+ *
+ * @return None.
+ */
+void scif_cb_io_request_get_next_sge(
+ void * scif_user_io_request,
+ void * current_sge_address,
+ void ** next_sge
+);
+#endif
+
+/**
+ * @brief This callback method asks the user to provide the contents of the
+ * "address" field in the Scatter-Gather Element.
+ *
+ * @param[in] scif_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.
+ * @param[in] sge_address This parameter specifies the address for the
+ * SGE from which to retrieve the address field.
+ *
+ * @return A physical address specifying the contents of the SGE's address
+ * field.
+ */
+SCI_PHYSICAL_ADDRESS scif_cb_sge_get_address_field(
+ void * scif_user_io_request,
+ void * sge_address
+);
+
+/**
+ * @brief This callback method asks the user to provide the contents of the
+ * "length" field in the Scatter-Gather Element.
+ *
+ * @param[in] scif_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.
+ * @param[in] sge_address This parameter specifies the address for the
+ * SGE from which to retrieve the address field.
+ *
+ * @return This method returns the length field specified inside the SGE
+ * referenced by the sge_address parameter.
+ */
+U32 scif_cb_sge_get_length_field(
+ void * scif_user_io_request,
+ void * sge_address
+);
+
+/**
+ * @brief This callback method asks the user to provide the address for
+ * the command descriptor block (CDB) associated with this IO request.
+ *
+ * @param[in] scif_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.
+ *
+ * @return This method returns the virtual address of the CDB.
+ */
+void * scif_cb_io_request_get_cdb_address(
+ void * scif_user_io_request
+);
+
+/**
+ * @brief This callback method asks the user to provide the length of
+ * the command descriptor block (CDB) associated with this IO request.
+ *
+ * @param[in] scif_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.
+ *
+ * @return This method returns the length of the CDB.
+ */
+U32 scif_cb_io_request_get_cdb_length(
+ void * scif_user_io_request
+);
+
+/**
+ * @brief This callback method asks the user to provide the Logical Unit (LUN)
+ * associated with this IO request.
+ *
+ * @note 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.
+ *
+ * @param[in] scif_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.
+ *
+ * @return This method returns the LUN associated with this request.
+ */
+U32 scif_cb_io_request_get_lun(
+ void * scif_user_io_request
+);
+
+/**
+ * @brief This callback method asks the user to provide the task attribute
+ * associated with this IO request.
+ *
+ * @note 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.
+ *
+ * @param[in] scif_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.
+ *
+ * @return This method returns the task attribute associated with this
+ * IO request.
+ */
+U32 scif_cb_io_request_get_task_attribute(
+ void * scif_user_io_request
+);
+
+/**
+ * @brief This callback method asks the user to provide the command priority
+ * associated with this IO request.
+ *
+ * @note 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.
+ *
+ * @param[in] scif_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.
+ *
+ * @return This method returns the command priority associated with this
+ * IO request.
+ */
+U32 scif_cb_io_request_get_command_priority(
+ void * scif_user_io_request
+);
+
+/**
+ * @brief This method returns the Logical Unit to be utilized for this
+ * task management request.
+ *
+ * @note 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.
+ *
+ * @param[in] scif_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.
+ *
+ * @return This method returns the LUN associated with this request.
+ * @todo This should be U64?
+ */
+U32 scif_cb_task_request_get_lun(
+ void * scif_user_task_request
+);
+
+/**
+ * @brief This method returns the task management function to be utilized
+ * for this task request.
+ *
+ * @note 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.
+ *
+ * @param[in] scif_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.
+ *
+ * @return This method returns an unsigned byte representing the task
+ * management function to be performed.
+ */
+U8 scif_cb_task_request_get_function(
+ void * scif_user_task_request
+);
+
+/**
+ * @brief 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.
+ *
+ * @param[in] scif_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.
+ *
+ * @return This method returns an unsigned 16-bit word depicting the IO
+ * tag to be managed.
+ */
+U16 scif_cb_task_request_get_io_tag_to_manage(
+ void * scif_user_task_request
+);
+
+/**
+ * @brief This callback method asks the user to provide the virtual
+ * address of the response data buffer for the supplied IO request.
+ *
+ * @param[in] scif_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.
+ *
+ * @return This method returns the virtual address for the response data buffer
+ * associated with this IO request.
+ */
+void * scif_cb_task_request_get_response_data_address(
+ void * scif_user_task_request
+);
+
+/**
+ * @brief This callback method asks the user to provide the length of the
+ * response data buffer for the supplied IO request.
+ *
+ * @param[in] scif_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.
+ *
+ * @return This method returns the length of the response buffer data
+ * associated with this IO request.
+ */
+U32 scif_cb_task_request_get_response_data_length(
+ void * scif_user_task_request
+);
+
+/**
+ * @brief In this method the user is expected to log the supplied
+ * error information. The user must be capable of handling variable
+ * length argument lists and should consider prepending the fact
+ * that this is an error from the framework.
+ *
+ * @param[in] logger_object This parameter specifies the logger object
+ * associated with this message.
+ * @param[in] log_object_mask This parameter specifies the log objects
+ * for which this message is being generated.
+ * @param[in] log_message This parameter specifies the message to be logged.
+ *
+ * @return none
+ */
+void scif_cb_logger_log_error(
+ SCI_LOGGER_HANDLE_T logger_object,
+ U32 log_object_mask,
+ char * log_message,
+ ...
+);
+
+/**
+ * @brief In this method the user is expected to log the supplied warning
+ * information. The user must be capable of handling variable
+ * length argument lists and should consider prepending the fact
+ * that this is a warning from the framework.
+ *
+ * @param[in] logger_object This parameter specifies the logger object
+ * associated with this message.
+ * @param[in] log_object_mask This parameter specifies the log objects
+ * for which this message is being generated.
+ * @param[in] log_message This parameter specifies the message to be logged.
+ *
+ * @return none
+ */
+void scif_cb_logger_log_warning(
+ SCI_LOGGER_HANDLE_T logger_object,
+ U32 log_object_mask,
+ char * log_message,
+ ...
+);
+
+/**
+ * @brief In this method the user is expected to log the supplied debug
+ * information. The user must be capable of handling variable
+ * length argument lists and should consider prepending the fact
+ * that this is a debug message from the framework.
+ *
+ * @param[in] logger_object This parameter specifies the logger object
+ * associated with this message.
+ * @param[in] log_object_mask This parameter specifies the log objects
+ * for which this message is being generated.
+ * @param[in] log_message This parameter specifies the message to be logged.
+ *
+ * @return none
+ */
+void scif_cb_logger_log_info(
+ SCI_LOGGER_HANDLE_T logger_object,
+ U32 log_object_mask,
+ char * log_message,
+ ...
+);
+
+
+/**
+ * @brief In this method the user is expected to log the supplied function
+ * trace information. The user must be capable of handling variable
+ * length argument lists and should consider prepending the fact
+ * that this is a function trace (i.e. entry/exit) message from the
+ * framework.
+ *
+ * @param[in] logger_object This parameter specifies the logger object
+ * associated with this message.
+ * @param[in] log_object_mask This parameter specifies the log objects
+ * for which this message is being generated.
+ * @param[in] log_message This parameter specifies the message to be logged.
+ *
+ * @return none
+ */
+void scif_cb_logger_log_trace(
+ SCI_LOGGER_HANDLE_T logger_object,
+ U32 log_object_mask,
+ char * log_message,
+ ...
+);
+
+
+/**
+ * @brief In this method the user is expected to log the supplied state
+ * transition information. The user must be capable of handling
+ * variable length argument lists and should consider prepending the
+ * fact that this is an error from the framework.
+ *
+ * @param[in] logger_object This parameter specifies the logger object
+ * associated with this message.
+ * @param[in] log_object_mask This parameter specifies the log objects
+ * for which this message is being generated.
+ * @param[in] log_message This parameter specifies the message to be logged.
+ *
+ * @return none
+ */
+void scif_cb_logger_log_states(
+ SCI_LOGGER_HANDLE_T logger_object,
+ U32 log_object_mask,
+ char * log_message,
+ ...
+);
+
+
+/**
+ * @brief This callback method informs the framework user that something
+ * in the supplied domain has changed (e.g. a device was added or
+ * removed).
+ *
+ * This callback is called by the framework outside of discovery or
+ * target reset processes. Specifically, domain changes occurring
+ * during these processes are handled by the framework. For example,
+ * in the case of Serial Attached SCSI, reception of a BROADCAST (CHANGE)
+ * during discovery will cause discovery to restart. Thus, discovery
+ * does not complete until all BCNs are processed. Note, during controller
+ * stopping/reset process, the framework user should not expect this call
+ * back.
+ *
+ * @param[in] controller This parameter specifies the controller object
+ * with which this callback is associated.
+ * @param[in] domain This parameter specifies the domain object with
+ * which this callback is associated.
+ *
+ * @return none
+ */
+void scif_cb_domain_change_notification(
+ SCI_CONTROLLER_HANDLE_T controller,
+ SCI_DOMAIN_HANDLE_T domain
+);
+
+
+/**
+ * @brief This callback method informs the framework user that a previously
+ * requested discovery operation on the domain has completed.
+ *
+ * @param[in] controller This parameter specifies the controller object
+ * with which this callback is associated.
+ * @param[in] domain This parameter specifies the domain object with
+ * which this callback is associated.
+ * @param[in] completion_status This parameter indicates the results of the
+ * discovery operation.
+ *
+ * @return none
+ */
+void scif_cb_domain_discovery_complete(
+ SCI_CONTROLLER_HANDLE_T controller,
+ SCI_DOMAIN_HANDLE_T domain,
+ SCI_STATUS completion_status
+);
+
+/**
+ * @brief This callback method informs the framework user that a previously
+ * requested reset operation on the domain has completed.
+ *
+ * @param[in] controller This parameter specifies the controller object
+ * with which this callback is associated.
+ * @param[in] domain This parameter specifies the domain object with
+ * which this callback is associated.
+ * @param[in] completion_status This parameter indicates the results of the
+ * reset operation.
+ *
+ * @return none
+ */
+void scif_cb_domain_reset_complete(
+ SCI_CONTROLLER_HANDLE_T controller,
+ SCI_DOMAIN_HANDLE_T domain,
+ SCI_STATUS completion_status
+);
+
+/**
+ * @brief This callback method informs the framework user that the domain
+ * is ready and capable of processing IO requests for devices found
+ * inside it.
+ *
+ * @param[in] controller This parameter specifies the controller object
+ * with which this callback is associated.
+ * @param[in] domain This parameter specifies the domain object with
+ * which this callback is associated.
+ *
+ * @return none
+ */
+void scif_cb_domain_ready(
+ SCI_CONTROLLER_HANDLE_T controller,
+ SCI_DOMAIN_HANDLE_T domain
+);
+
+/**
+ * @brief This callback method informs the framework user that the domain
+ * is no longer ready. Thus, it is incapable of processing IO
+ * requests for devices found inside it.
+ *
+ * @param[in] controller This parameter specifies the controller object
+ * with which this callback is associated.
+ * @param[in] domain This parameter specifies the domain object with
+ * which this callback is associated.
+ *
+ * @return none
+ */
+void scif_cb_domain_not_ready(
+ SCI_CONTROLLER_HANDLE_T controller,
+ SCI_DOMAIN_HANDLE_T domain
+);
+
+/**
+ * @brief This callback method informs the framework user that a new
+ * direct attached device was found in the domain.
+ *
+ * @param[in] controller This parameter specifies the controller object
+ * with which this callback is associated.
+ * @param[in] domain This parameter specifies the domain object with
+ * which this callback is associated.
+ * @param[in] sas_address This parameter specifies the SAS address of
+ * the new device.
+ * @param[in] protocols This parameter specifies the protocols
+ * supported by the newly discovered device.
+ *
+ * @return none
+ */
+void scif_cb_domain_da_device_added(
+ SCI_CONTROLLER_HANDLE_T controller,
+ SCI_DOMAIN_HANDLE_T domain,
+ SCI_SAS_ADDRESS_T * sas_address,
+ SCI_SAS_IDENTIFY_ADDRESS_FRAME_PROTOCOLS_T * protocols
+);
+
+/**
+ * @brief This callback method informs the framework user that a new
+ * expander attached device was found in the domain.
+ *
+ * @param[in] controller This parameter specifies the controller object
+ * with which this callback is associated.
+ * @param[in] domain This parameter specifies the domain object with
+ * which this callback is associated.
+ * @param[in] containing_device This parameter specifies the remote
+ * device that contains the device that was added.
+ * @param[in] smp_response This parameter specifies the SMP response
+ * data associated with the newly discovered device.
+ *
+ * @return none
+ */
+void scif_cb_domain_ea_device_added(
+ SCI_CONTROLLER_HANDLE_T controller,
+ SCI_DOMAIN_HANDLE_T domain,
+ SCI_REMOTE_DEVICE_HANDLE_T containing_device,
+ SMP_RESPONSE_DISCOVER_T * smp_response
+);
+
+/**
+ * @brief This callback method informs the framework user that a device
+ * has been removed from the domain.
+ *
+ * @param[in] controller This parameter specifies the controller object
+ * with which this callback is associated.
+ * @param[in] domain This parameter specifies the domain object with
+ * which this callback is associated.
+ * @param[in] remote_device This parameter specifies the device object with
+ * which this callback is associated.
+ *
+ * @return none
+ */
+void scif_cb_domain_device_removed(
+ SCI_CONTROLLER_HANDLE_T controller,
+ SCI_DOMAIN_HANDLE_T domain,
+ SCI_REMOTE_DEVICE_HANDLE_T remote_device
+);
+
+/**
+ * @brief This callback method informs the framework user that the remote
+ * device is ready and capable of processing IO requests.
+ *
+ * @param[in] controller This parameter specifies the controller object
+ * with which this callback is associated.
+ * @param[in] domain This parameter specifies the domain object with
+ * which this callback is associated.
+ * @param[in] remote_device This parameter specifies the device object with
+ * which this callback is associated.
+ *
+ * @return none
+ */
+void scif_cb_remote_device_ready(
+ SCI_CONTROLLER_HANDLE_T controller,
+ SCI_DOMAIN_HANDLE_T domain,
+ SCI_REMOTE_DEVICE_HANDLE_T remote_device
+);
+
+/**
+ * @brief This callback method informs the framework user that the remote
+ * device is not ready. Thus, it is incapable of processing IO
+ * requests.
+ *
+ * @param[in] controller This parameter specifies the controller object
+ * with which this callback is associated.
+ * @param[in] domain This parameter specifies the domain object with
+ * which this callback is associated.
+ * @param[in] remote_device This parameter specifies the device object with
+ * which this callback is associated.
+ *
+ * @return none
+ */
+void scif_cb_remote_device_not_ready(
+ SCI_CONTROLLER_HANDLE_T controller,
+ SCI_DOMAIN_HANDLE_T domain,
+ SCI_REMOTE_DEVICE_HANDLE_T remote_device
+);
+
+/**
+ * @brief This callback method informs the framework user that the remote
+ * device failed. This typically occurs shortly after the device
+ * has been discovered, during the configuration phase for the device.
+ *
+ * @param[in] controller This parameter specifies the controller object
+ * with which this callback is associated.
+ * @param[in] domain This parameter specifies the domain object with
+ * which this callback is associated.
+ * @param[in] remote_device This parameter specifies the device object with
+ * which this callback is associated.
+ * @param[in] status This parameter specifies the specific failure condition
+ * associated with this device failure.
+ *
+ * @return none
+ */
+void scif_cb_remote_device_failed(
+ SCI_CONTROLLER_HANDLE_T controller,
+ SCI_DOMAIN_HANDLE_T domain,
+ SCI_REMOTE_DEVICE_HANDLE_T remote_device,
+ SCI_STATUS status
+);
+
+
+
+/**
+ * @brief This callback method creates an OS specific deferred task
+ * for internal usage. The handler to deferred task is stored by OS
+ * driver.
+ *
+ * @param[in] controller This parameter specifies the controller object
+ * with which this callback is associated.
+ *
+ * @return none
+ */
+void scif_cb_start_internal_io_task_create(
+ SCI_CONTROLLER_HANDLE_T controller
+);
+
+
+/**
+ * @brief This callback method schedules a OS specific deferred task.
+ *
+ * @param[in] controller This parameter specifies the controller
+ * object with which this callback is associated.
+ * @param[in] start_internal_io_task_routine This parameter specifies the
+ * sci start_internal_io routine.
+ * @param[in] context This parameter specifies a handle to a parameter
+ * that will be passed into the "start_internal_io_task_routine"
+ * when it is invoked.
+ *
+ * @return none
+ */
+void scif_cb_start_internal_io_task_schedule(
+ SCI_CONTROLLER_HANDLE_T controller,
+ FUNCPTR start_internal_io_task_routine,
+ void * context
+);
+
+/**
+ * @brief This method will be invoked to allocate memory dynamically.
+ *
+ * @param[in] controller This parameter represents the controller
+ * object for which to allocate memory.
+ * @param[out] mde This parameter represents the memory descriptor to
+ * be filled in by the user that will reference the newly
+ * allocated memory.
+ *
+ * @return none
+ */
+void scif_cb_controller_allocate_memory(
+ SCI_CONTROLLER_HANDLE_T controller,
+ SCI_PHYSICAL_MEMORY_DESCRIPTOR_T * mde
+);
+
+/**
+ * @brief This method will be invoked to allocate memory dynamically.
+ *
+ * @param[in] controller This parameter represents the controller
+ * object for which to allocate memory.
+ * @param[out] mde This parameter represents the memory descriptor to
+ * be filled in by the user that will reference the newly
+ * allocated memory.
+ *
+ * @return none
+ */
+void scif_cb_controller_free_memory(
+ SCI_CONTROLLER_HANDLE_T controller,
+ SCI_PHYSICAL_MEMORY_DESCRIPTOR_T * mde
+);
+
+#ifdef __cplusplus
+}
+#endif // __cplusplus
+
+#endif // _SCIF_USER_CALLBACK_H_
+
diff --git a/sys/dev/isci/scil/scu_bios_definitions.h b/sys/dev/isci/scil/scu_bios_definitions.h
new file mode 100644
index 0000000..d0d12b5
--- /dev/null
+++ b/sys/dev/isci/scil/scu_bios_definitions.h
@@ -0,0 +1,1002 @@
+/*-
+ * 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.
+ *
+ * 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.
+ *
+ * $FreeBSD$
+ */
+#ifndef _SCU_BIOS_DEFINITIONS_H_
+#define _SCU_BIOS_DEFINITIONS_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif // __cplusplus
+
+/**
+ * IMPORTANT NOTE:
+ * This file can be used by an SCI Library based driver or
+ * stand-alone where the library is excluded. By excluding
+ * the SCI Library, inclusion of OS specific header files can
+ * be avoided. For example, a BIOS utility probably does not
+ * want to be bothered with inclusion of nested OS DDK include
+ * files that are not necessary for its function.
+ *
+ * To exclude the SCI Library, either uncomment the EXCLUDE_SCI_LIBRARY
+ * #define statement in environment.h or define the statement as an input
+ * to your compiler.
+ */
+
+#include <dev/isci/environment.h>
+
+#ifndef EXCLUDE_SCI_LIBRARY
+#include <dev/isci/scil/sci_types.h>
+#include <dev/isci/scil/intel_sas.h>
+#include <dev/isci/scil/sci_controller_constants.h>
+#endif /* EXCLUDE_SCI_LIBRARY */
+
+
+
+// For Intel Storage Controller Unit OEM Block
+#define SCI_OEM_PARAM_SIGNATURE "ISCUOEMB"
+
+#define SCI_PREBOOT_SOURCE_INIT (0x00)
+#define SCI_PREBOOT_SOURCE_OROM (0x80)
+#define SCI_PREBOOT_SOURCE_EFI (0x81)
+
+#define SCI_OEM_PARAM_VER_1_0 (0x10)
+#define SCI_OEM_PARAM_VER_1_1 (0x11)
+#define SCI_OEM_PARAM_VER_1_2 (0x12)
+#define SCI_OEM_PARAM_VER_1_3 (0x13)
+
+// current version
+#define SCI_OEM_PARAM_VER_CUR SCI_OEM_PARAM_VER_1_3
+
+// port configuration mode
+#define SCI_BIOS_MODE_MPC (0x00)
+#define SCI_BIOS_MODE_APC (0x01)
+
+
+#ifndef SCI_MAX_PHYS
+#define SCI_MAX_PHYS (4)
+#endif
+
+#ifndef SCI_MAX_PORTS
+#define SCI_MAX_PORTS (4)
+#endif
+
+
+/**
+ * @struct SCI_BIOS_OEM_PARAM_BLOCK_HDR
+ *
+ * @brief This structure defines the OEM Parameter block header.
+ */
+typedef struct SCI_BIOS_OEM_PARAM_BLOCK_HDR
+{
+ /**
+ * This field contains the OEM Parameter Block Signature which is
+ * used by BIOS and driver software to identify that the memory location
+ * contains valid OEM Parameter data. The value must be set to
+ * SCI_OEM_PARAM_SIGNATURE which is the string "ISCUOEMB" which
+ * stands for Intel Storage Controller Unit OEM Block.
+ */
+ U8 signature[8];
+ /**
+ * This field contains the size in bytes of the complete OEM
+ * Parameter Block, both header and payload hdr_length +
+ * (num_elements * element_length).
+ */
+ U16 total_block_length;
+ /**
+ * This field contains the size in bytes of the
+ * SCI_BIOS_OEM_PARAM_BLOCK_HDR. It also indicates the offset from
+ * the beginning of this data structure to where the actual
+ * parameter data payload begins.
+ */
+ U8 hdr_length;
+ /**
+ * This field contains the version info defining the structure
+ * of the OEM Parameter block.
+ */
+ U8 version;
+ /**
+ * This field contains a value indicating the preboot initialization
+ * method (Option ROM or UEFI driver) so that after OS transition,
+ * the OS driver can know the preboot method. OEMs who build a single
+ * flash image where the preboot method is unknown at manufacturing
+ * time should set this field to SCI_PREBOOT_SOURCE_INIT. Then
+ * after the block is retrieved into host memory and under preboot
+ * driver control, the OROM or UEFI driver can set this field
+ * appropriately (SCI_PREBOOT_SOURCE_OROM and SCI_PREBOOT_SOURCE_EFI,
+ * respectively).
+ */
+ U8 preboot_source;
+ /**
+ * This field contains the number of parameter descriptor elements
+ * (i.e. controller_elements) following this header. The number of
+ * elements corresponds to the number of SCU controller units contained
+ * in the platform:
+ * controller_element[0] = SCU0
+ * controller_element[1] = SCU1
+ */
+ U8 num_elements;
+ /**
+ * This field contains the size in bytes of the descriptor element(s)
+ * in the block.
+ */
+ U16 element_length;
+ /**
+ * Reserve fields for future use.
+ */
+ U8 reserved[8];
+
+} SCI_BIOS_OEM_PARAM_BLOCK_HDR_T;
+
+
+/**
+ * @struct SCIC_SDS_OEM_PARAMETERS VER 1.0
+ *
+ * @brief This structure delineates the various OEM parameters that must
+ * be set for the Intel SAS Storage Controller Unit (SCU).
+ */
+typedef struct SCI_BIOS_OEM_PARAM_ELEMENT
+{
+ /**
+ * Per SCU Controller Data
+ */
+ struct
+ {
+ /**
+ * This field indicates the port configuration mode for
+ * this controller:
+ * Automatic Port Configuration(APC) or
+ * Manual Port Configuration (MPC).
+ *
+ * APC means the Platform OEM expects SCI to configure
+ * SAS Ports automatically according to the discovered SAS
+ * Address pairs of the endpoints, wide and/or narrow.
+ *
+ * MPC means the Platform OEM manually defines wide or narrow
+ * connectors by apriori assigning PHYs to SAS Ports.
+ *
+ * By default, the mode type is APC
+ * in APC mode, if ANY of the phy mask is non-zero,
+ * SCI_FAILURE_INVALID_PARAMETER_VALUE will be returned
+ * from scic_oem_parameters_set AND the default oem
+ * configuration will be applied
+ * in MPC mode, if ALL of the phy masks are zero,
+ * SCI_FAILURE_INVALID_PARAMETER_VALUE will be returned
+ * from scic_oem_parameters_set AND the default oem
+ * configuration will be applied
+ */
+ U8 mode_type;
+
+ /**
+ * This field specifies the maximum number of direct attached
+ * devices the OEM will allow to have powered up simultaneously
+ * on this controller. This allows the OEM to avoid exceeding
+ * power supply limits for this platform. A value of zero
+ * indicates there are no restrictions.
+ */
+ U8 max_number_concurrent_device_spin_up;
+
+ /**
+ * This field indicates OEM's desired default
+ * Spread Spectrum Clocking (SSC) setting for Tx:
+ * enabled = 1
+ * disabled = 0
+ */
+ U8 do_enable_ssc;
+
+ U8 reserved;
+
+ } controller;
+
+ /**
+ * Per SAS Port data.
+ */
+ 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:
+ * Bit 0 = This controller's PHY index 0 (0x01)
+ * Bit 1 = This controller's PHY index 1 (0x02)
+ * Bit 2 = This controller's PHY index 2 (0x04)
+ * Bit 3 = This controller's PHY index 3 (0x08)
+ *
+ * Refer to the mode_type field for rules regarding APC and MPC mode.
+ * General rule: For APC mode phy_mask = 0
+ */
+ U8 phy_mask;
+
+ } ports[SCI_MAX_PORTS]; // Up to 4 Ports per SCU controller unit
+
+ /**
+ * Per PHY Parameter data.
+ */
+ struct
+ {
+ /**
+ * This field indicates the SAS Address that will be transmitted on
+ * this PHY index. The field is defined as a union, however, the
+ * OEM should use the U8 array definition when encoding it to ensure
+ * correct byte ordering.
+ *
+ * NOTE: If using APC MODE, along with phy_mask being set to ZERO, the
+ * SAS Addresses for all PHYs within a controller group SHALL be the
+ * same.
+ */
+ union
+ {
+ /**
+ * The array should be stored in little endian order. For example,
+ * if the desired SAS Address is 0x50010B90_0003538D, then it
+ * should be stored in the following manner:
+ * array[0] = 0x90
+ * array[1] = 0x0B
+ * array[2] = 0x01
+ * array[3] = 0x50
+ * array[4] = 0x8D
+ * array[5] = 0x53
+ * array[6] = 0x03
+ * array[7] = 0x00
+ */
+ U8 array[8];
+ /**
+ * This is the typedef'd version of the SAS Address used in
+ * the SCI Library.
+ */
+ SCI_SAS_ADDRESS_T sci_format;
+
+ } sas_address;
+
+ /**
+ * These are the per PHY equalization settings associated with the the
+ * AFE XCVR Tx Amplitude and Equalization Control Register Set
+ * (0 thru 3).
+ *
+ * Operational Note: The following Look-Up-Table registers are engaged
+ * by the AFE block after the following:
+ * - Software programs the Link Layer AFE Look Up Table Control
+ * Registers (AFE_LUTCR).
+ * - Software sets AFE XCVR Tx Control Register Tx Equalization
+ * Enable bit.
+ */
+ /**
+ * AFE_TX_AMP_CTRL0. This register is associated with AFE_LUTCR
+ * LUTSel=00b. It contains the Tx Equalization settings that will be
+ * used if a SATA 1.5Gbs or SATA 3.0Gbs device is direct-attached.
+ */
+ U32 afe_tx_amp_control0;
+
+ /**
+ * AFE_TX_AMP_CTRL1. This register is associated with AFE_LUTCR
+ * LUTSel=01b. It contains the Tx Equalization settings that will
+ * be used if a SATA 6.0Gbs device is direct-attached.
+ */
+ U32 afe_tx_amp_control1;
+
+ /**
+ * AFE_TX_AMP_CTRL2. This register is associated with AFE_LUTCR
+ * LUTSel=10b. It contains the Tx Equalization settings that will
+ * be used if a SAS 1.5Gbs or SAS 3.0Gbs device is direct-attached.
+ */
+ U32 afe_tx_amp_control2;
+
+ /**
+ * AFE_TX_AMP_CTRL3. This register is associated with AFE_LUTCR
+ * LUTSel=11b. It contains the Tx Equalization settings that will
+ * be used if a SAS 6.0Gbs device is direct-attached.
+ */
+ U32 afe_tx_amp_control3;
+
+ } phys[SCI_MAX_PHYS]; // 4 PHYs per SCU controller unit
+
+} SCI_BIOS_OEM_PARAM_ELEMENT_T;
+
+/**
+ * @struct SCIC_SDS_OEM_PARAMETERS VER 1.1
+ *
+ * @brief This structure delineates the various OEM parameters that must
+ * be set for the Intel SAS Storage Controller Unit (SCU).
+ */
+typedef struct SCI_BIOS_OEM_PARAM_ELEMENT_v_1_1
+{
+ /**
+ * Per SCU Controller Data
+ */
+ struct
+ {
+ /**
+ * This field indicates the port configuration mode for
+ * this controller:
+ * Automatic Port Configuration(APC) or
+ * Manual Port Configuration (MPC).
+ *
+ * APC means the Platform OEM expects SCI to configure
+ * SAS Ports automatically according to the discovered SAS
+ * Address pairs of the endpoints, wide and/or narrow.
+ *
+ * MPC means the Platform OEM manually defines wide or narrow
+ * connectors by apriori assigning PHYs to SAS Ports.
+ *
+ * By default, the mode type is APC
+ * in APC mode, if ANY of the phy mask is non-zero,
+ * SCI_FAILURE_INVALID_PARAMETER_VALUE will be returned
+ * from scic_oem_parameters_set AND the default oem
+ * configuration will be applied
+ * in MPC mode, if ALL of the phy masks are zero,
+ * SCI_FAILURE_INVALID_PARAMETER_VALUE will be returned
+ * from scic_oem_parameters_set AND the default oem
+ * configuration will be applied
+ */
+ U8 mode_type;
+
+ /**
+ * This field specifies the maximum number of direct attached
+ * devices the OEM will allow to have powered up simultaneously
+ * on this controller. This allows the OEM to avoid exceeding
+ * power supply limits for this platform. A value of zero
+ * indicates there are no restrictions.
+ */
+ U8 max_number_concurrent_device_spin_up;
+
+ /**
+ * This bitfield indicates the OEM's desired default Tx
+ * Spread Spectrum Clocking (SSC) settings for SATA and SAS.
+ * NOTE: Default SSC Modulation Frequency is 31.5KHz.
+ *--------------------------------------------------------------------*/
+ /**
+ * NOTE: Max spread for SATA is +0 / -5000 PPM.
+ * Down-spreading SSC (only method allowed for SATA):
+ * SATA SSC Tx Disabled = 0x0
+ * SATA SSC Tx at +0 / -1419 PPM Spread = 0x2
+ * SATA SSC Tx at +0 / -2129 PPM Spread = 0x3
+ * SATA SSC Tx at +0 / -4257 PPM Spread = 0x6
+ * SATA SSC Tx at +0 / -4967 PPM Spread = 0x7
+ */
+ U8 ssc_sata_tx_spread_level : 4;
+
+ /**
+ * SAS SSC Tx Disabled = 0x0
+ *
+ * NOTE: Max spread for SAS down-spreading +0 / -2300 PPM
+ * Down-spreading SSC:
+ * SAS SSC Tx at +0 / -1419 PPM Spread = 0x2
+ * SAS SSC Tx at +0 / -2129 PPM Spread = 0x3
+ *
+ * NOTE: Max spread for SAS center-spreading +2300 / -2300 PPM
+ * Center-spreading SSC:
+ * SAS SSC Tx at +1064 / -1064 PPM Spread = 0x3
+ * SAS SSC Tx at +2129 / -2129 PPM Spread = 0x6
+ */
+ U8 ssc_sas_tx_spread_level : 3;
+ /**
+ * NOTE: Refer to the SSC section of the SAS 2.x Specification
+ * for proper setting of this field. For standard SAS Initiator
+ * SAS PHY operation it should be 0 for Down-spreading.
+ * SAS SSC Tx spread type:
+ * Down-spreading SSC = 0
+ * Center-spreading SSC = 1
+ */
+ U8 ssc_sas_tx_type : 1;
+ /*--------------------------------------------------------------------*/
+
+ U8 reserved;
+
+ } controller;
+
+ /**
+ * Per SAS Port data.
+ */
+ 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:
+ * Bit 0 = This controller's PHY index 0 (0x01)
+ * Bit 1 = This controller's PHY index 1 (0x02)
+ * Bit 2 = This controller's PHY index 2 (0x04)
+ * Bit 3 = This controller's PHY index 3 (0x08)
+ *
+ * Refer to the mode_type field for rules regarding APC and MPC mode.
+ * General rule: For APC mode phy_mask = 0
+ */
+ U8 phy_mask;
+
+ } ports[SCI_MAX_PORTS]; // Up to 4 Ports per SCU controller unit
+
+ /**
+ * Per PHY Parameter data.
+ */
+ struct
+ {
+ /**
+ * This field indicates the SAS Address that will be transmitted on
+ * this PHY index. The field is defined as a union, however, the
+ * OEM should use the U8 array definition when encoding it to ensure
+ * correct byte ordering.
+ *
+ * NOTE: If using APC MODE, along with phy_mask being set to ZERO, the
+ * SAS Addresses for all PHYs within a controller group SHALL be the
+ * same.
+ */
+ union
+ {
+ /**
+ * The array should be stored in little endian order. For example,
+ * if the desired SAS Address is 0x50010B90_0003538D, then it
+ * should be stored in the following manner:
+ * array[0] = 0x90
+ * array[1] = 0x0B
+ * array[2] = 0x01
+ * array[3] = 0x50
+ * array[4] = 0x8D
+ * array[5] = 0x53
+ * array[6] = 0x03
+ * array[7] = 0x00
+ */
+ U8 array[8];
+ /**
+ * This is the typedef'd version of the SAS Address used in
+ * the SCI Library.
+ */
+ SCI_SAS_ADDRESS_T sci_format;
+
+ } sas_address;
+
+ /**
+ * These are the per PHY equalization settings associated with the the
+ * AFE XCVR Tx Amplitude and Equalization Control Register Set
+ * (0 thru 3).
+ *
+ * Operational Note: The following Look-Up-Table registers are engaged
+ * by the AFE block after the following:
+ * - Software programs the Link Layer AFE Look Up Table Control
+ * Registers (AFE_LUTCR).
+ * - Software sets AFE XCVR Tx Control Register Tx Equalization
+ * Enable bit.
+ */
+ /**
+ * AFE_TX_AMP_CTRL0. This register is associated with AFE_LUTCR
+ * LUTSel=00b. It contains the Tx Equalization settings that will be
+ * used if a SATA 1.5Gbs or SATA 3.0Gbs device is direct-attached.
+ */
+ U32 afe_tx_amp_control0;
+
+ /**
+ * AFE_TX_AMP_CTRL1. This register is associated with AFE_LUTCR
+ * LUTSel=01b. It contains the Tx Equalization settings that will
+ * be used if a SATA 6.0Gbs device is direct-attached.
+ */
+ U32 afe_tx_amp_control1;
+
+ /**
+ * AFE_TX_AMP_CTRL2. This register is associated with AFE_LUTCR
+ * LUTSel=10b. It contains the Tx Equalization settings that will
+ * be used if a SAS 1.5Gbs or SAS 3.0Gbs device is direct-attached.
+ */
+ U32 afe_tx_amp_control2;
+
+ /**
+ * AFE_TX_AMP_CTRL3. This register is associated with AFE_LUTCR
+ * LUTSel=11b. It contains the Tx Equalization settings that will
+ * be used if a SAS 6.0Gbs device is direct-attached.
+ */
+ U32 afe_tx_amp_control3;
+
+ } phys[SCI_MAX_PHYS]; // 4 PHYs per SCU controller unit
+
+} SCI_BIOS_OEM_PARAM_ELEMENT_v_1_1_T;
+
+/**
+ * @struct SCIC_SDS_OEM_PARAMETERS VER 1.2
+ *
+ * @brief This structure delineates the various OEM parameters that must
+ * be set for the Intel SAS Storage Controller Unit (SCU).
+ */
+typedef struct SCI_BIOS_OEM_PARAM_ELEMENT_v_1_2
+{
+ /**
+ * Per SCU Controller Data
+ */
+ struct
+ {
+ /**
+ * This field indicates the port configuration mode for
+ * this controller:
+ * Automatic Port Configuration(APC) or
+ * Manual Port Configuration (MPC).
+ *
+ * APC means the Platform OEM expects SCI to configure
+ * SAS Ports automatically according to the discovered SAS
+ * Address pairs of the endpoints, wide and/or narrow.
+ *
+ * MPC means the Platform OEM manually defines wide or narrow
+ * connectors by apriori assigning PHYs to SAS Ports.
+ *
+ * By default, the mode type is APC
+ * in APC mode, if ANY of the phy mask is non-zero,
+ * SCI_FAILURE_INVALID_PARAMETER_VALUE will be returned
+ * from scic_oem_parameters_set AND the default oem
+ * configuration will be applied
+ * in MPC mode, if ALL of the phy masks are zero,
+ * SCI_FAILURE_INVALID_PARAMETER_VALUE will be returned
+ * from scic_oem_parameters_set AND the default oem
+ * configuration will be applied
+ */
+ U8 mode_type;
+
+ /**
+ * This field specifies the maximum number of direct attached
+ * devices the OEM will allow to have powered up simultaneously
+ * on this controller. This allows the OEM to avoid exceeding
+ * power supply limits for this platform. A value of zero
+ * indicates there are no restrictions.
+ */
+ U8 max_number_concurrent_device_spin_up;
+
+ /**
+ * This bitfield indicates the OEM's desired default Tx
+ * Spread Spectrum Clocking (SSC) settings for SATA and SAS.
+ * NOTE: Default SSC Modulation Frequency is 31.5KHz.
+ *--------------------------------------------------------------------*/
+ /**
+ * NOTE: Max spread for SATA is +0 / -5000 PPM.
+ * Down-spreading SSC (only method allowed for SATA):
+ * SATA SSC Tx Disabled = 0x0
+ * SATA SSC Tx at +0 / -1419 PPM Spread = 0x2
+ * SATA SSC Tx at +0 / -2129 PPM Spread = 0x3
+ * SATA SSC Tx at +0 / -4257 PPM Spread = 0x6
+ * SATA SSC Tx at +0 / -4967 PPM Spread = 0x7
+ */
+ U8 ssc_sata_tx_spread_level : 4;
+
+ /**
+ * SAS SSC Tx Disabled = 0x0
+ *
+ * NOTE: Max spread for SAS down-spreading +0 / -2300 PPM
+ * Down-spreading SSC:
+ * SAS SSC Tx at +0 / -1419 PPM Spread = 0x2
+ * SAS SSC Tx at +0 / -2129 PPM Spread = 0x3
+ *
+ * NOTE: Max spread for SAS center-spreading +2300 / -2300 PPM
+ * Center-spreading SSC:
+ * SAS SSC Tx at +1064 / -1064 PPM Spread = 0x3
+ * SAS SSC Tx at +2129 / -2129 PPM Spread = 0x6
+ */
+ U8 ssc_sas_tx_spread_level : 3;
+ /**
+ * NOTE: Refer to the SSC section of the SAS 2.x Specification
+ * for proper setting of this field. For standard SAS Initiator
+ * SAS PHY operation it should be 0 for Down-spreading.
+ * SAS SSC Tx spread type:
+ * Down-spreading SSC = 0
+ * Center-spreading SSC = 1
+ */
+ U8 ssc_sas_tx_type : 1;
+
+ /**
+ * This field indicates length of the SAS/SATA cable between
+ * host and device.
+ * This field is used make relationship between analog parameters of
+ * the phy in the silicon and length of the cable.
+ * Supported length: "short"- up to 3m, "long"- more than 3m
+ * This is bit mask field:
+ *
+ * BIT: 7 6 5 4 3 2 1 0 (LSB)
+ * ASSIGNMENT: <-><-><-><-><phy3><phy2><phy1><phy0>
+ *
+ * For short cable corresponding bit shall be reset,
+ * for long cable shall be set.
+ */
+ U8 long_cable_selection_mask;
+
+ } controller;
+
+ /**
+ * Per SAS Port data.
+ */
+ 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:
+ * Bit 0 = This controller's PHY index 0 (0x01)
+ * Bit 1 = This controller's PHY index 1 (0x02)
+ * Bit 2 = This controller's PHY index 2 (0x04)
+ * Bit 3 = This controller's PHY index 3 (0x08)
+ *
+ * Refer to the mode_type field for rules regarding APC and MPC mode.
+ * General rule: For APC mode phy_mask = 0
+ */
+ U8 phy_mask;
+
+ } ports[SCI_MAX_PORTS]; // Up to 4 Ports per SCU controller unit
+
+ /**
+ * Per PHY Parameter data.
+ */
+ struct
+ {
+ /**
+ * This field indicates the SAS Address that will be transmitted on
+ * this PHY index. The field is defined as a union, however, the
+ * OEM should use the U8 array definition when encoding it to ensure
+ * correct byte ordering.
+ *
+ * NOTE: If using APC MODE, along with phy_mask being set to ZERO, the
+ * SAS Addresses for all PHYs within a controller group SHALL be the
+ * same.
+ */
+ union
+ {
+ /**
+ * The array should be stored in little endian order. For example,
+ * if the desired SAS Address is 0x50010B90_0003538D, then it
+ * should be stored in the following manner:
+ * array[0] = 0x90
+ * array[1] = 0x0B
+ * array[2] = 0x01
+ * array[3] = 0x50
+ * array[4] = 0x8D
+ * array[5] = 0x53
+ * array[6] = 0x03
+ * array[7] = 0x00
+ */
+ U8 array[8];
+ /**
+ * This is the typedef'd version of the SAS Address used in
+ * the SCI Library.
+ */
+ SCI_SAS_ADDRESS_T sci_format;
+
+ } sas_address;
+
+ /**
+ * These are the per PHY equalization settings associated with the the
+ * AFE XCVR Tx Amplitude and Equalization Control Register Set
+ * (0 thru 3).
+ *
+ * Operational Note: The following Look-Up-Table registers are engaged
+ * by the AFE block after the following:
+ * - Software programs the Link Layer AFE Look Up Table Control
+ * Registers (AFE_LUTCR).
+ * - Software sets AFE XCVR Tx Control Register Tx Equalization
+ * Enable bit.
+ */
+ /**
+ * AFE_TX_AMP_CTRL0. This register is associated with AFE_LUTCR
+ * LUTSel=00b. It contains the Tx Equalization settings that will be
+ * used if a SATA 1.5Gbs or SATA 3.0Gbs device is direct-attached.
+ */
+ U32 afe_tx_amp_control0;
+
+ /**
+ * AFE_TX_AMP_CTRL1. This register is associated with AFE_LUTCR
+ * LUTSel=01b. It contains the Tx Equalization settings that will
+ * be used if a SATA 6.0Gbs device is direct-attached.
+ */
+ U32 afe_tx_amp_control1;
+
+ /**
+ * AFE_TX_AMP_CTRL2. This register is associated with AFE_LUTCR
+ * LUTSel=10b. It contains the Tx Equalization settings that will
+ * be used if a SAS 1.5Gbs or SAS 3.0Gbs device is direct-attached.
+ */
+ U32 afe_tx_amp_control2;
+
+ /**
+ * AFE_TX_AMP_CTRL3. This register is associated with AFE_LUTCR
+ * LUTSel=11b. It contains the Tx Equalization settings that will
+ * be used if a SAS 6.0Gbs device is direct-attached.
+ */
+ U32 afe_tx_amp_control3;
+
+ } phys[SCI_MAX_PHYS]; // 4 PHYs per SCU controller unit
+
+} SCI_BIOS_OEM_PARAM_ELEMENT_v_1_2_T;
+
+/**
+ * @struct SCIC_SDS_OEM_PARAMETERS VER 1.3
+ *
+ * @brief This structure delineates the various OEM parameters that must
+ * be set for the Intel SAS Storage Controller Unit (SCU).
+ */
+typedef struct SCI_BIOS_OEM_PARAM_ELEMENT_v_1_3
+{
+ /**
+ * Per SCU Controller Data
+ */
+ struct
+ {
+ /**
+ * This field indicates the port configuration mode for
+ * this controller:
+ * Automatic Port Configuration(APC) or
+ * Manual Port Configuration (MPC).
+ *
+ * APC means the Platform OEM expects SCI to configure
+ * SAS Ports automatically according to the discovered SAS
+ * Address pairs of the endpoints, wide and/or narrow.
+ *
+ * MPC means the Platform OEM manually defines wide or narrow
+ * connectors by apriori assigning PHYs to SAS Ports.
+ *
+ * By default, the mode type is APC
+ * in APC mode, if ANY of the phy mask is non-zero,
+ * SCI_FAILURE_INVALID_PARAMETER_VALUE will be returned
+ * from scic_oem_parameters_set AND the default oem
+ * configuration will be applied
+ * in MPC mode, if ALL of the phy masks are zero,
+ * SCI_FAILURE_INVALID_PARAMETER_VALUE will be returned
+ * from scic_oem_parameters_set AND the default oem
+ * configuration will be applied
+ */
+ U8 mode_type;
+
+ /**
+ * This field specifies the maximum number of direct attached
+ * devices the OEM will allow to have powered up simultaneously
+ * on this controller. This allows the OEM to avoid exceeding
+ * power supply limits for this platform. A value of zero
+ * indicates there are no restrictions.
+ */
+ U8 max_number_concurrent_device_spin_up;
+
+ /**
+ * This bitfield indicates the OEM's desired default Tx
+ * Spread Spectrum Clocking (SSC) settings for SATA and SAS.
+ * NOTE: Default SSC Modulation Frequency is 31.5KHz.
+ *--------------------------------------------------------------------*/
+ /**
+ * NOTE: Max spread for SATA is +0 / -5000 PPM.
+ * Down-spreading SSC (only method allowed for SATA):
+ * SATA SSC Tx Disabled = 0x0
+ * SATA SSC Tx at +0 / -1419 PPM Spread = 0x2
+ * SATA SSC Tx at +0 / -2129 PPM Spread = 0x3
+ * SATA SSC Tx at +0 / -4257 PPM Spread = 0x6
+ * SATA SSC Tx at +0 / -4967 PPM Spread = 0x7
+ */
+ U8 ssc_sata_tx_spread_level : 4;
+
+ /**
+ * SAS SSC Tx Disabled = 0x0
+ *
+ * NOTE: Max spread for SAS down-spreading +0 / -2300 PPM
+ * Down-spreading SSC:
+ * SAS SSC Tx at +0 / -1419 PPM Spread = 0x2
+ * SAS SSC Tx at +0 / -2129 PPM Spread = 0x3
+ *
+ * NOTE: Max spread for SAS center-spreading +2300 / -2300 PPM
+ * Center-spreading SSC:
+ * SAS SSC Tx at +1064 / -1064 PPM Spread = 0x3
+ * SAS SSC Tx at +2129 / -2129 PPM Spread = 0x6
+ */
+ U8 ssc_sas_tx_spread_level : 3;
+ /**
+ * NOTE: Refer to the SSC section of the SAS 2.x Specification
+ * for proper setting of this field. For standard SAS Initiator
+ * SAS PHY operation it should be 0 for Down-spreading.
+ * SAS SSC Tx spread type:
+ * Down-spreading SSC = 0
+ * Center-spreading SSC = 1
+ */
+ U8 ssc_sas_tx_type : 1;
+
+ /**
+ * This field indicates length of the SAS/SATA cable between
+ * host and device.
+ * This field is used make relationship between analog parameters of
+ * the phy in the silicon and length of the cable.
+ * Supported cable attenuation levels:
+ * "short"- up to 3m, "medium"-3m to 6m, and "long"- more than 6m
+ * This is bit mask field:
+ *
+ * BIT: (MSB) 7 6 5 4
+ * ASSIGNMENT: <phy3><phy2><phy1><phy0> - Medium cable length assignment
+ * BIT: 3 2 1 0 (LSB)
+ * ASSIGNMENT: <phy3><phy2><phy1><phy0> - Long cable length assignment
+ *
+ * BITS 7-4 are set when the cable length is assigned to medium
+ * BITS 3-0 are set when the cable length is assigned to long
+ * The BIT positions are clear when the cable length is assigned to short
+ * Setting the bits for both long and medium cable length is undefined.
+ *
+ * A value of 0x84 would assign
+ * phy3 - medium
+ * phy2 - long
+ * phy1 - short
+ * phy0 - short
+ */
+ U8 cable_selection_mask;
+
+ } controller;
+
+ /**
+ * Per SAS Port data.
+ */
+ 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:
+ * Bit 0 = This controller's PHY index 0 (0x01)
+ * Bit 1 = This controller's PHY index 1 (0x02)
+ * Bit 2 = This controller's PHY index 2 (0x04)
+ * Bit 3 = This controller's PHY index 3 (0x08)
+ *
+ * Refer to the mode_type field for rules regarding APC and MPC mode.
+ * General rule: For APC mode phy_mask = 0
+ */
+ U8 phy_mask;
+
+ } ports[SCI_MAX_PORTS]; // Up to 4 Ports per SCU controller unit
+
+ /**
+ * Per PHY Parameter data.
+ */
+ struct
+ {
+ /**
+ * This field indicates the SAS Address that will be transmitted on
+ * this PHY index. The field is defined as a union, however, the
+ * OEM should use the U8 array definition when encoding it to ensure
+ * correct byte ordering.
+ *
+ * NOTE: If using APC MODE, along with phy_mask being set to ZERO, the
+ * SAS Addresses for all PHYs within a controller group SHALL be the
+ * same.
+ */
+ union
+ {
+ /**
+ * The array should be stored in little endian order. For example,
+ * if the desired SAS Address is 0x50010B90_0003538D, then it
+ * should be stored in the following manner:
+ * array[0] = 0x90
+ * array[1] = 0x0B
+ * array[2] = 0x01
+ * array[3] = 0x50
+ * array[4] = 0x8D
+ * array[5] = 0x53
+ * array[6] = 0x03
+ * array[7] = 0x00
+ */
+ U8 array[8];
+ /**
+ * This is the typedef'd version of the SAS Address used in
+ * the SCI Library.
+ */
+ SCI_SAS_ADDRESS_T sci_format;
+
+ } sas_address;
+
+ /**
+ * These are the per PHY equalization settings associated with the the
+ * AFE XCVR Tx Amplitude and Equalization Control Register Set
+ * (0 thru 3).
+ *
+ * Operational Note: The following Look-Up-Table registers are engaged
+ * by the AFE block after the following:
+ * - Software programs the Link Layer AFE Look Up Table Control
+ * Registers (AFE_LUTCR).
+ * - Software sets AFE XCVR Tx Control Register Tx Equalization
+ * Enable bit.
+ */
+ /**
+ * AFE_TX_AMP_CTRL0. This register is associated with AFE_LUTCR
+ * LUTSel=00b. It contains the Tx Equalization settings that will be
+ * used if a SATA 1.5Gbs or SATA 3.0Gbs device is direct-attached.
+ */
+ U32 afe_tx_amp_control0;
+
+ /**
+ * AFE_TX_AMP_CTRL1. This register is associated with AFE_LUTCR
+ * LUTSel=01b. It contains the Tx Equalization settings that will
+ * be used if a SATA 6.0Gbs device is direct-attached.
+ */
+ U32 afe_tx_amp_control1;
+
+ /**
+ * AFE_TX_AMP_CTRL2. This register is associated with AFE_LUTCR
+ * LUTSel=10b. It contains the Tx Equalization settings that will
+ * be used if a SAS 1.5Gbs or SAS 3.0Gbs device is direct-attached.
+ */
+ U32 afe_tx_amp_control2;
+
+ /**
+ * AFE_TX_AMP_CTRL3. This register is associated with AFE_LUTCR
+ * LUTSel=11b. It contains the Tx Equalization settings that will
+ * be used if a SAS 6.0Gbs device is direct-attached.
+ */
+ U32 afe_tx_amp_control3;
+
+ } phys[SCI_MAX_PHYS]; // 4 PHYs per SCU controller unit
+
+} SCI_BIOS_OEM_PARAM_ELEMENT_v_1_3_T;
+
+/**
+ * @struct SCI_BIOS_OEM_PARAM_BLOCK
+ *
+ * @brief This structure defines the OEM Parameter block as it will be stored
+ * in the last 512 bytes of the PDR region in the SPI flash. It must be
+ * unpacked or pack(1).
+ */
+typedef struct SCI_BIOS_OEM_PARAM_BLOCK
+{
+ /**
+ * OEM Parameter Block header.
+ */
+ SCI_BIOS_OEM_PARAM_BLOCK_HDR_T header;
+
+ /**
+ * Per controller element descriptor containing the controller's
+ * parameter data. The prototype defines just one of these descriptors,
+ * however, the actual runtime number is determined by the num_elements
+ * field in the header.
+ */
+ SCI_BIOS_OEM_PARAM_ELEMENT_T controller_element[1];
+
+} SCI_BIOS_OEM_PARAM_BLOCK_T;
+
+#ifdef __cplusplus
+}
+#endif // __cplusplus
+
+#endif // _SCU_BIOS_DEFINITIONS_H_
+
diff --git a/sys/dev/isci/scil/scu_completion_codes.h b/sys/dev/isci/scil/scu_completion_codes.h
new file mode 100644
index 0000000..2ea2b9d
--- /dev/null
+++ b/sys/dev/isci/scil/scu_completion_codes.h
@@ -0,0 +1,263 @@
+/*-
+ * 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.
+ *
+ * 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.
+ *
+ * $FreeBSD$
+ */
+#ifndef _SCU_COMPLETION_CODES_HEADER_
+#define _SCU_COMPLETION_CODES_HEADER_
+
+/**
+ * @file
+ *
+ * @brief This file contains the constants and macros for the SCU hardware
+ * completion codes.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif // __cplusplus
+
+#define SCU_COMPLETION_TYPE_SHIFT 28
+#define SCU_COMPLETION_TYPE_MASK 0x70000000
+
+/**
+ * This macro constructs an SCU completion type
+ */
+#define SCU_COMPLETION_TYPE(type) \
+ ((U32)(type) << SCU_COMPLETION_TYPE_SHIFT)
+
+/**
+ * These macros contain the SCU completion types
+ *
+ * @name 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
+
+/**
+ * This macro returns the SCU completion type.
+ */
+#define SCU_GET_COMPLETION_TYPE(completion_code) \
+ ((completion_code) & SCU_COMPLETION_TYPE_MASK)
+
+/**
+ * This macro returns the SCU completion status.
+ */
+#define SCU_GET_COMPLETION_STATUS(completion_code) \
+ ((completion_code) & SCU_COMPLETION_STATUS_MASK)
+
+/**
+ * This macro returns the transport layer completion status.
+ */
+#define SCU_GET_COMPLETION_TL_STATUS(completion_code) \
+ ((completion_code) & SCU_COMPLETION_TL_STATUS_MASK)
+
+/**
+ * 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)
+
+/**
+ * This macro takes a SCU_GET_COMPLETION_TL_STATUS and normalizes it for a
+ * return code.
+ */
+#define SCU_NORMALIZE_COMPLETION_STATUS(completion_code) \
+ ( \
+ ((U32)((completion_code) & SCU_COMPLETION_TL_STATUS_MASK)) \
+ >> SCU_COMPLETION_TL_STATUS_SHIFT \
+ )
+
+/**
+ * This macro returns the SDMA completion status.
+ */
+#define SCU_GET_COMPLETION_SDMA_STATUS(completion_code) \
+ ((completion_code) & SCU_COMPLETION_SDMA_STATUS_MASK)
+
+/**
+ * This macro returns the Protocol Engine Group from the completion code.
+ */
+#define SCU_GET_COMPLETION_PEG(completion_code) \
+ ((completion_code) & SCU_COMPLETION_PEG_MASK)
+
+/**
+ * This macro reuturns the logical port index from the completion code.
+ */
+#define SCU_GET_COMPLETION_PORT(completion_code) \
+ ((completion_code) & SCU_COMPLETION_PORT_MASK)
+
+/**
+ * This macro returns the PE index from the completion code.
+ */
+#define SCU_GET_PROTOCOL_ENGINE_INDEX(completion_code) \
+ (((U32)((completion_code) & SCU_COMPLETION_PE_MASK)) >> SCU_COMPLETION_PE_SHIFT)
+
+/**
+ * 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
+
+/**
+ * This macro returns a normalized frame index from an unsolicited frame
+ * completion.
+ */
+#define SCU_GET_FRAME_INDEX(completion_code) \
+ ( \
+ ((U32)((completion_code) & SCU_UNSOLICITED_FRAME_MASK)) \
+ >> SCU_UNSOLICITED_FRAME_SHIFT \
+ )
+
+#define SCU_UNSOLICITED_FRAME_ERROR_MASK 0x00008000
+
+/**
+ * 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_CMD_LL_R_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)
+#if defined(PBG_HBA_BETA_BUILD)
+#define SCU_TASK_DONE_CMD_SDMA_ERR ((U32)0x32)
+#define SCU_TASK_DONE_CMD_LL_ABORT_ERR ((U32)0x33)
+#endif
+#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)
+
+#ifdef __cplusplus
+}
+#endif // __cplusplus
+
+#endif // _SCU_COMPLETION_CODES_HEADER_
diff --git a/sys/dev/isci/scil/scu_constants.h b/sys/dev/isci/scil/scu_constants.h
new file mode 100644
index 0000000..98641d1
--- /dev/null
+++ b/sys/dev/isci/scil/scu_constants.h
@@ -0,0 +1,154 @@
+/*-
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 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.
+ *
+ * $FreeBSD$
+ */
+#ifndef _SCU_CONSTANTS_H_
+#define _SCU_CONSTANTS_H_
+
+/**
+ * @file
+ *
+ * @brief This file contains the SCU hardware constants.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif // __cplusplus
+
+#include <dev/isci/scil/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 (8)
+#define SCU_MIN_CRITICAL_NOTIFICATIONS (19)
+#define SCU_MIN_EVENTS (4)
+#define SCU_MIN_COMPLETION_QUEUE_SCRATCH (0)
+#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)
+
+#ifdef __cplusplus
+}
+#endif // __cplusplus
+
+#endif // _SCU_CONSTANTS_H_
diff --git a/sys/dev/isci/scil/scu_event_codes.h b/sys/dev/isci/scil/scu_event_codes.h
new file mode 100644
index 0000000..9aefede
--- /dev/null
+++ b/sys/dev/isci/scil/scu_event_codes.h
@@ -0,0 +1,343 @@
+/*-
+ * 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.
+ *
+ * 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.
+ *
+ * $FreeBSD$
+ */
+#ifndef __SCU_EVENT_CODES_HEADER__
+#define __SCU_EVENT_CODES_HEADER__
+
+/**
+ * @file
+ *
+ * @brief This file contains the constants and macros for the SCU event codes.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif // __cplusplus
+
+#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)
+
+/**
+ * This macro constructs an SCU event type from the type value.
+ */
+#define SCU_EVENT_TYPE(type) \
+ ((U32)(type) << SCU_EVENT_TYPE_CODE_SHIFT)
+
+/**
+ * This macro constructs an SCU event specifier from the code value.
+ */
+#define SCU_EVENT_SPECIFIC(code) \
+ ((U32)(code) << SCU_EVENT_SPECIFIC_CODE_SHIFT)
+
+/**
+ * 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))
+
+/**
+ * @name 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)
+/*@}*/
+
+/**
+ * @name SCU_EVENT_SPECIFIERS
+ */
+/*@{*/
+#define SCU_EVENT_SPECIFIER_DRIVER_SUSPEND 0x20
+#define SCU_EVENT_SPECIFIER_RNC_RELEASE 0x00
+/*@}*/
+
+/**
+ * @name SMU_COMMAND_EVENTS
+ */
+/*@{*/
+#define SCU_EVENT_INVALID_CONTEXT_COMMAND \
+ SCU_EVENT_MESSAGE(SCU_EVENT_TYPE_SMU_COMMAND_ERROR, 0x00)
+/*@}*/
+
+/**
+ * @name SMU_PCQ_EVENTS
+ */
+/*@{*/
+#define SCU_EVENT_UNCORRECTABLE_PCQ_ERROR \
+ SCU_EVENT_MESSAGE(SCU_EVENT_TYPE_SMU_PCQ_ERROR, 0x00)
+/*@}*/
+
+/**
+ * @name 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)
+/*@}*/
+
+/**
+ * @name TRANSPORT_LEVEL_ERRORS
+ */
+/*@{*/
+#define SCU_EVENT_ACK_NAK_TIMEOUT_ERROR \
+ SCU_EVENT_MESSAGE(SCU_EVENT_TYPE_TRANSPORT_ERROR, 0x00)
+/*@}*/
+
+/**
+ * @name 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)
+/*@}*/
+
+/**
+ * @name 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)
+/*@}*/
+
+/**
+ * @name 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)
+/*@}*/
+
+/**
+ * @name 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_TL_RNC_SUSPEND_TX_DONE_DATA_LEN_ERR \
+ SCU_EVENT_MESSAGE(SCU_EVENT_TYPE_RNC_SUSPEND_TX, 0x1A)
+#define SCU_EVENT_TL_RNC_SUSPEND_TX_DONE_OFFSET_ERR \
+ SCU_EVENT_MESSAGE(SCU_EVENT_TYPE_RNC_SUSPEND_TX, 0x20)
+#define SCU_EVENT_TL_RNC_SUSPEND_TX_DONE_DMASETUP_DIERR \
+ SCU_EVENT_MESSAGE(SCU_EVENT_TYPE_RNC_SUSPEND_TX, 0x27)
+#define SCU_EVENT_TL_RNC_SUSPEND_TX_DONE_XFERCNT_ERR \
+ SCU_EVENT_MESSAGE(SCU_EVENT_TYPE_RNC_SUSPEND_TX, 0x28)
+#define SCU_EVENT_TL_RNC_SUSPEND_TX_RX_DONE_PLD_LEN_ERR \
+ SCU_EVENT_MESSAGE(SCU_EVENT_TYPE_RNC_SUSPEND_TX_RX, 0x21)
+#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)
+/*@}*/
+
+/**
+ * @name 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)
+/*@}*/
+
+/**
+ * @name ERROR_COUNT_EVENT
+ */
+/*@{*/
+#define SCU_ERR_CNT_RX_CREDIT_BLOCKED_RECEIVED_INDEX 0x00
+#define SCU_ERR_CNT_TX_DONE_CREDIT_TIMEOUT_INDEX 0x01
+#define SCU_ERR_CNT_RX_DONE_CREDIT_TIMEOUT_INDEX 0x02
+#define SCU_ERR_CNT_INACTIVITY_TIMER_EXPIRED_INDEX 0x03
+#define SCU_ERR_CNT_TX_DONE_ACK_NAK_TIMEOUT_INDEX 0x04
+#define SCU_ERR_CNT_RX_DONE_ACK_NAK_TIMEOUT_INDEX 0x05
+#define SCU_ERR_CNT_MAX_INDEX 0x06
+
+#define SCU_EVENT_ERR_CNT(name) \
+ SCU_EVENT_MESSAGE(SCU_EVENT_TYPE_ERR_CNT_EVENT, SCU_ERR_CNT_ ## name ## _INDEX)
+/*@}*/
+
+/**
+ * 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)
+
+/**
+ * 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)
+
+/**
+ * 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)
+
+
+/**
+ * @name 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)
+/*@}*/
+
+#ifdef __cplusplus
+}
+#endif // __cplusplus
+
+#endif // __SCU_EVENT_CODES_HEADER__
diff --git a/sys/dev/isci/scil/scu_registers.h b/sys/dev/isci/scil/scu_registers.h
new file mode 100644
index 0000000..8157c1a
--- /dev/null
+++ b/sys/dev/isci/scil/scu_registers.h
@@ -0,0 +1,2121 @@
+/*-
+ * 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.
+ *
+ * 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.
+ *
+ * $FreeBSD$
+ */
+#ifndef _SCU_REGISTERS_H_
+#define _SCU_REGISTERS_H_
+
+/**
+ * @file
+ *
+ * @brief This file contains the constants and structures for the SCU memory
+ * mapped registers.
+ */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <dev/isci/scil/sci_types.h>
+#include <dev/isci/scil/scu_viit_data.h>
+
+
+
+// Generate a value for an SCU register
+#define SCU_GEN_VALUE(name, value) \
+ (((U32)(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 (0UL)
+#define SMU_POST_CONTEXT_PORT_CONTEXT_INDEX_MASK (0x00000FFFUL)
+#define SMU_POST_CONTEXT_PORT_LOGICAL_PORT_INDEX_SHIFT (12UL)
+#define SMU_POST_CONTEXT_PORT_LOGICAL_PORT_INDEX_MASK (0x0000F000UL)
+#define SMU_POST_CONTEXT_PORT_PROTOCOL_ENGINE_SHIFT (16UL)
+#define SMU_POST_CONTEXT_PORT_PROTOCOL_ENGINE_MASK (0x00030000UL)
+#define SMU_POST_CONTEXT_PORT_COMMAND_CONTEXT_SHIFT (18UL)
+#define SMU_POST_CONTEXT_PORT_COMMAND_CONTEXT_MASK (0x00FC0000UL)
+#define SMU_POST_CONTEXT_PORT_RESERVED_MASK (0xFF000000UL)
+
+#define SMU_PCP_GEN_VAL(name, value) \
+ SCU_GEN_VALUE(SMU_POST_CONTEXT_PORT_##name, value)
+
+//*****************************************************************************
+#define SMU_INTERRUPT_STATUS_COMPLETION_SHIFT (31UL)
+#define SMU_INTERRUPT_STATUS_COMPLETION_MASK (0x80000000UL)
+#define SMU_INTERRUPT_STATUS_QUEUE_SUSPEND_SHIFT (1UL)
+#define SMU_INTERRUPT_STATUS_QUEUE_SUSPEND_MASK (0x00000002UL)
+#define SMU_INTERRUPT_STATUS_QUEUE_ERROR_SHIFT (0UL)
+#define SMU_INTERRUPT_STATUS_QUEUE_ERROR_MASK (0x00000001UL)
+#define SMU_INTERRUPT_STATUS_RESERVED_MASK (0x7FFFFFFCUL)
+
+#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 (31UL)
+#define SMU_INTERRUPT_MASK_COMPLETION_MASK (0x80000000UL)
+#define SMU_INTERRUPT_MASK_QUEUE_SUSPEND_SHIFT (1UL)
+#define SMU_INTERRUPT_MASK_QUEUE_SUSPEND_MASK (0x00000002UL)
+#define SMU_INTERRUPT_MASK_QUEUE_ERROR_SHIFT (0UL)
+#define SMU_INTERRUPT_MASK_QUEUE_ERROR_MASK (0x00000001UL)
+#define SMU_INTERRUPT_MASK_RESERVED_MASK (0x7FFFFFFCUL)
+
+#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 (0UL)
+#define SMU_INTERRUPT_COALESCING_CONTROL_TIMER_MASK (0x0000001FUL)
+#define SMU_INTERRUPT_COALESCING_CONTROL_NUMBER_SHIFT (8UL)
+#define SMU_INTERRUPT_COALESCING_CONTROL_NUMBER_MASK (0x0000FF00UL)
+#define SMU_INTERRUPT_COALESCING_CONTROL_RESERVED_MASK (0xFFFF00E0UL)
+
+#define SMU_ICC_GEN_VAL(name, value) \
+ SCU_GEN_VALUE(SMU_INTERRUPT_COALESCING_CONTROL_##name, value)
+
+//*****************************************************************************
+#define SMU_TASK_CONTEXT_RANGE_START_SHIFT (0UL)
+#define SMU_TASK_CONTEXT_RANGE_START_MASK (0x00000FFFUL)
+#define SMU_TASK_CONTEXT_RANGE_ENDING_SHIFT (16UL)
+#define SMU_TASK_CONTEXT_RANGE_ENDING_MASK (0x0FFF0000UL)
+#define SMU_TASK_CONTEXT_RANGE_ENABLE_SHIFT (31UL)
+#define SMU_TASK_CONTEXT_RANGE_ENABLE_MASK (0x80000000UL)
+#define SMU_TASK_CONTEXT_RANGE_RESERVED_MASK (0x7000F000UL)
+
+#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 (0UL)
+#define SMU_COMPLETION_QUEUE_PUT_POINTER_MASK (0x00003FFFUL)
+#define SMU_COMPLETION_QUEUE_PUT_CYCLE_BIT_SHIFT (15UL)
+#define SMU_COMPLETION_QUEUE_PUT_CYCLE_BIT_MASK (0x00008000UL)
+#define SMU_COMPLETION_QUEUE_PUT_EVENT_POINTER_SHIFT (16UL)
+#define SMU_COMPLETION_QUEUE_PUT_EVENT_POINTER_MASK (0x03FF0000UL)
+#define SMU_COMPLETION_QUEUE_PUT_EVENT_CYCLE_BIT_SHIFT (26UL)
+#define SMU_COMPLETION_QUEUE_PUT_EVENT_CYCLE_BIT_MASK (0x04000000UL)
+#define SMU_COMPLETION_QUEUE_PUT_RESERVED_MASK (0xF8004000UL)
+
+#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 (0UL)
+#define SMU_COMPLETION_QUEUE_GET_POINTER_MASK (0x00003FFFUL)
+#define SMU_COMPLETION_QUEUE_GET_CYCLE_BIT_SHIFT (15UL)
+#define SMU_COMPLETION_QUEUE_GET_CYCLE_BIT_MASK (0x00008000UL)
+#define SMU_COMPLETION_QUEUE_GET_EVENT_POINTER_SHIFT (16UL)
+#define SMU_COMPLETION_QUEUE_GET_EVENT_POINTER_MASK (0x03FF0000UL)
+#define SMU_COMPLETION_QUEUE_GET_EVENT_CYCLE_BIT_SHIFT (26UL)
+#define SMU_COMPLETION_QUEUE_GET_EVENT_CYCLE_BIT_MASK (0x04000000UL)
+#define SMU_COMPLETION_QUEUE_GET_ENABLE_SHIFT (30UL)
+#define SMU_COMPLETION_QUEUE_GET_ENABLE_MASK (0x40000000UL)
+#define SMU_COMPLETION_QUEUE_GET_EVENT_ENABLE_SHIFT (31UL)
+#define SMU_COMPLETION_QUEUE_GET_EVENT_ENABLE_MASK (0x80000000UL)
+#define SMU_COMPLETION_QUEUE_GET_RESERVED_MASK (0x38004000UL)
+
+#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 (0UL)
+#define SMU_COMPLETION_QUEUE_CONTROL_QUEUE_LIMIT_MASK (0x00003FFFUL)
+#define SMU_COMPLETION_QUEUE_CONTROL_EVENT_LIMIT_SHIFT (16UL)
+#define SMU_COMPLETION_QUEUE_CONTROL_EVENT_LIMIT_MASK (0x03FF0000UL)
+#define SMU_COMPLETION_QUEUE_CONTROL_RESERVED_MASK (0xFC00C000UL)
+
+#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 (0UL)
+#define SMU_DEVICE_CONTEXT_CAPACITY_MAX_TC_MASK (0x00000FFFUL)
+#define SMU_DEVICE_CONTEXT_CAPACITY_MAX_LP_SHIFT (12UL)
+#define SMU_DEVICE_CONTEXT_CAPACITY_MAX_LP_MASK (0x00007000UL)
+#define SMU_DEVICE_CONTEXT_CAPACITY_MAX_RNC_SHIFT (15UL)
+#define SMU_DEVICE_CONTEXT_CAPACITY_MAX_RNC_MASK (0x07FF8000UL)
+#define SMU_DEVICE_CONTEXT_CAPACITY_MAX_PEG_SHIFT (27UL)
+#define SMU_DEVICE_CONTEXT_CAPACITY_MAX_PEG_MASK (0x08000000UL)
+#define SMU_DEVICE_CONTEXT_CAPACITY_RESERVED_MASK (0xF0000000UL)
+
+#define SMU_DCC_GEN_VAL(name, value) \
+ SCU_GEN_VALUE(SMU_DEVICE_CONTEXT_CAPACITY_##name, value)
+
+#define SMU_DCC_GET_MAX_PEG(value) \
+ ( \
+ ((U32)((value) & SMU_DEVICE_CONTEXT_CAPACITY_MAX_PEG_MASK)) \
+ >> SMU_DEVICE_CONTEXT_CAPACITY_MAX_LP_SHIFT \
+ )
+
+#define SMU_DCC_GET_MAX_LP(value) \
+ ( \
+ ((U32)((value) & SMU_DEVICE_CONTEXT_CAPACITY_MAX_LP_MASK)) \
+ >> SMU_DEVICE_CONTEXT_CAPACITY_MAX_LP_SHIFT \
+ )
+
+#define SMU_DCC_GET_MAX_TC(value) \
+ ( \
+ ((U32)((value) & SMU_DEVICE_CONTEXT_CAPACITY_MAX_TC_MASK)) \
+ >> SMU_DEVICE_CONTEXT_CAPACITY_MAX_TC_SHIFT \
+ )
+
+#define SMU_DCC_GET_MAX_RNC(value) \
+ ( \
+ ((U32)((value) & SMU_DEVICE_CONTEXT_CAPACITY_MAX_RNC_MASK)) \
+ >> SMU_DEVICE_CONTEXT_CAPACITY_MAX_RNC_SHIFT \
+ )
+
+//*****************************************************************************
+#define SMU_CLOCK_GATING_CONTROL_IDLE_ENABLE_SHIFT (0UL)
+#define SMU_CLOCK_GATING_CONTROL_IDLE_ENABLE_MASK (0x00000001UL)
+#define SMU_CLOCK_GATING_CONTROL_XCLK_ENABLE_SHIFT (1UL)
+#define SMU_CLOCK_GATING_CONTROL_XCLK_ENABLE_MASK (0x00000002UL)
+#define SMU_CLOCK_GATING_CONTROL_TXCLK_ENABLE_SHIFT (2UL)
+#define SMU_CLOCK_GATING_CONTROL_TXCLK_ENABLE_MASK (0x00000004UL)
+#define SMU_CLOCK_GATING_CONTROL_REGCLK_ENABLE_SHIFT (3UL)
+#define SMU_CLOCK_GATING_CONTROL_REGCLK_ENABLE_MASK (0x00000008UL)
+#define SMU_CLOCK_GATING_CONTROL_IDLE_TIMEOUT_SHIFT (16UL)
+#define SMU_CLOCK_GATING_CONTROL_IDLE_TIMEOUT_MASK (0x000F0000UL)
+#define SMU_CLOCK_GATING_CONTROL_FORCE_IDLE_SHIFT (31UL)
+#define SMU_CLOCK_GATING_CONTROL_FORCE_IDLE_MASK (0x80000000UL)
+#define SMU_CLOCK_GATING_CONTROL_RESERVED_MASK (0x7FF0FFF0UL)
+
+#define SMU_CGUCR_GEN_VAL(name, value) \
+ SCU_GEN_VALUE(SMU_CLOCK_GATING_CONTROL_##name, value)
+
+#define SMU_CGUCR_GEN_BIT(name) \
+ SCU_GEN_BIT(SMU_CLOCK_GATING_CONTROL_##name)
+
+// --------------------------------------------------------------------------
+
+#define SMU_CONTROL_STATUS_TASK_CONTEXT_RANGE_ENABLE_SHIFT (0UL)
+#define SMU_CONTROL_STATUS_TASK_CONTEXT_RANGE_ENABLE_MASK (0x00000001UL)
+#define SMU_CONTROL_STATUS_COMPLETION_BYTE_SWAP_ENABLE_SHIFT (1UL)
+#define SMU_CONTROL_STATUS_COMPLETION_BYTE_SWAP_ENABLE_MASK (0x00000002UL)
+#define SMU_CONTROL_STATUS_CONTEXT_RAM_INIT_COMPLETED_SHIFT (16UL)
+#define SMU_CONTROL_STATUS_CONTEXT_RAM_INIT_COMPLETED_MASK (0x00010000UL)
+#define SMU_CONTROL_STATUS_SCHEDULER_RAM_INIT_COMPLETED_SHIFT (17UL)
+#define SMU_CONTROL_STATUS_SCHEDULER_RAM_INIT_COMPLETED_MASK (0x00020000UL)
+#define SMU_CONTROL_STATUS_RESERVED_MASK (0xFFFCFFFCUL)
+
+#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 (0UL)
+#define SMU_SOFTRESET_CONTROL_RESET_PEG0_PE0_MASK (0x00000001UL)
+#define SMU_SOFTRESET_CONTROL_RESET_PEG0_PE1_SHIFT (1UL)
+#define SMU_SOFTRESET_CONTROL_RESET_PEG0_PE1_MASK (0x00000002UL)
+#define SMU_SOFTRESET_CONTROL_RESET_PEG0_PE2_SHIFT (2UL)
+#define SMU_SOFTRESET_CONTROL_RESET_PEG0_PE2_MASK (0x00000004UL)
+#define SMU_SOFTRESET_CONTROL_RESET_PEG0_PE3_SHIFT (3UL)
+#define SMU_SOFTRESET_CONTROL_RESET_PEG0_PE3_MASK (0x00000008UL)
+#define SMU_SOFTRESET_CONTROL_RESET_PEG1_PE0_SHIFT (8UL)
+#define SMU_SOFTRESET_CONTROL_RESET_PEG1_PE0_MASK (0x00000100UL)
+#define SMU_SOFTRESET_CONTROL_RESET_PEG1_PE1_SHIFT (9UL)
+#define SMU_SOFTRESET_CONTROL_RESET_PEG1_PE1_MASK (0x00000200UL)
+#define SMU_SOFTRESET_CONTROL_RESET_PEG1_PE2_SHIFT (10UL)
+#define SMU_SOFTRESET_CONTROL_RESET_PEG1_PE2_MASK (0x00000400UL)
+#define SMU_SOFTRESET_CONTROL_RESET_PEG1_PE3_SHIFT (11UL)
+#define SMU_SOFTRESET_CONTROL_RESET_PEG1_PE3_MASK (0x00000800UL)
+
+#define SMU_RESET_PROTOCOL_ENGINE(peg, pe) \
+ ((1UL << (pe)) << ((peg) * 8UL))
+
+#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 (16UL)
+#define SMU_SOFTRESET_CONTROL_RESET_WIDE_PORT_PEG0_LP0_MASK (0x00010000UL)
+#define SMU_SOFTRESET_CONTROL_RESET_WIDE_PORT_PEG0_LP2_SHIFT (17UL)
+#define SMU_SOFTRESET_CONTROL_RESET_WIDE_PORT_PEG0_LP2_MASK (0x00020000UL)
+#define SMU_SOFTRESET_CONTROL_RESET_WIDE_PORT_PEG1_LP0_SHIFT (18UL)
+#define SMU_SOFTRESET_CONTROL_RESET_WIDE_PORT_PEG1_LP0_MASK (0x00040000UL)
+#define SMU_SOFTRESET_CONTROL_RESET_WIDE_PORT_PEG1_LP2_SHIFT (19UL)
+#define SMU_SOFTRESET_CONTROL_RESET_WIDE_PORT_PEG1_LP2_MASK (0x00080000UL)
+
+#define SMU_RESET_WIDE_PORT_QUEUE(peg, wide_port) \
+ ((1UL << ((wide_port) / 2)) << ((peg) * 2UL) << 16UL)
+
+#define SMU_SOFTRESET_CONTROL_RESET_PEG0_SHIFT (20UL)
+#define SMU_SOFTRESET_CONTROL_RESET_PEG0_MASK (0x00100000UL)
+#define SMU_SOFTRESET_CONTROL_RESET_PEG1_SHIFT (21UL)
+#define SMU_SOFTRESET_CONTROL_RESET_PEG1_MASK (0x00200000UL)
+#define SMU_SOFTRESET_CONTROL_RESET_SCU_SHIFT (22UL)
+#define SMU_SOFTRESET_CONTROL_RESET_SCU_MASK (0x00400000UL)
+
+// 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) \
+ ( \
+ (1UL << ((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 (0UL)
+#define SMU_TASK_CONTEXT_ASSIGNMENT_STARTING_MASK (0x00000FFFUL)
+#define SMU_TASK_CONTEXT_ASSIGNMENT_ENDING_SHIFT (16UL)
+#define SMU_TASK_CONTEXT_ASSIGNMENT_ENDING_MASK (0x0FFF0000UL)
+#define SMU_TASK_CONTEXT_ASSIGNMENT_RANGE_CHECK_ENABLE_SHIFT (31UL)
+#define SMU_TASK_CONTEXT_ASSIGNMENT_RANGE_CHECK_ENABLE_MASK (0x80000000UL)
+#define SMU_TASK_CONTEXT_ASSIGNMENT_RESERVED_MASK (0x7000F000UL)
+
+#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 (0UL)
+#define SCU_SDMA_UNSOLICITED_FRAME_QUEUE_CONTROL_QUEUE_SIZE_MASK (0x00000FFFUL)
+#define SCU_SDMA_UNSOLICITED_FRAME_QUEUE_CONTROL_RESERVED_MASK (0xFFFFF000UL)
+
+#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 (0UL)
+#define SCU_SDMA_UNSOLICITED_FRAME_QUEUE_PUT_POINTER_MASK (0x00000FFFUL)
+#define SCU_SDMA_UNSOLICITED_FRAME_QUEUE_PUT_CYCLE_BIT_SHIFT (12UL)
+#define SCU_SDMA_UNSOLICITED_FRAME_QUEUE_PUT_CYCLE_BIT_MASK (0x00001000UL)
+#define SCU_SDMA_UNSOLICITED_FRAME_QUEUE_PUT_RESERVED_MASK (0xFFFFE000UL)
+
+#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 (0UL)
+#define SCU_SDMA_UNSOLICITED_FRAME_QUEUE_GET_POINTER_MASK (0x00000FFFUL)
+#define SCU_SDMA_UNSOLICITED_FRAME_QUEUE_GET_CYCLE_BIT_SHIFT (12UL)
+#define SCU_SDMA_UNSOLICITED_FRAME_QUEUE_GET_CYCLE_BIT_MASK (12UL)
+#define SCU_SDMA_UNSOLICITED_FRAME_QUEUE_GET_ENABLE_BIT_SHIFT (31UL)
+#define SCU_SDMA_UNSOLICITED_FRAME_QUEUE_GET_ENABLE_BIT_MASK (0x80000000UL)
+#define SCU_SDMA_UNSOLICITED_FRAME_QUEUE_GET_RESERVED_MASK (0x7FFFE000UL)
+
+#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 (0UL)
+#define SCU_PDMA_CONFIGURATION_ADDRESS_MODIFIER_MASK (0x0000FFFFUL)
+#define SCU_PDMA_CONFIGURATION_PCI_RELAXED_ORDERING_ENABLE_SHIFT (16UL)
+#define SCU_PDMA_CONFIGURATION_PCI_RELAXED_ORDERING_ENABLE_MASK (0x00010000UL)
+#define SCU_PDMA_CONFIGURATION_PCI_NO_SNOOP_ENABLE_SHIFT (17UL)
+#define SCU_PDMA_CONFIGURATION_PCI_NO_SNOOP_ENABLE_MASK (0x00020000UL)
+#define SCU_PDMA_CONFIGURATION_BIG_ENDIAN_CONTROL_BYTE_SWAP_SHIFT (18UL)
+#define SCU_PDMA_CONFIGURATION_BIG_ENDIAN_CONTROL_BYTE_SWAP_MASK (0x00040000UL)
+#define SCU_PDMA_CONFIGURATION_BIG_ENDIAN_CONTROL_XPI_SGL_FETCH_SHIFT (19UL)
+#define SCU_PDMA_CONFIGURATION_BIG_ENDIAN_CONTROL_XPI_SGL_FETCH_MASK (0x00080000UL)
+#define SCU_PDMA_CONFIGURATION_BIG_ENDIAN_CONTROL_XPI_RX_HEADER_RAM_WRITE_SHIFT (20UL)
+#define SCU_PDMA_CONFIGURATION_BIG_ENDIAN_CONTROL_XPI_RX_HEADER_RAM_WRITE_MASK (0x00100000UL)
+#define SCU_PDMA_CONFIGURATION_BIG_ENDIAN_CONTROL_XPI_UF_ADDRESS_FETCH_SHIFT (21UL)
+#define SCU_PDMA_CONFIGURATION_BIG_ENDIAN_CONTROL_XPI_UF_ADDRESS_FETCH_MASK (0x00200000UL)
+#define SCU_PDMA_CONFIGURATION_ADDRESS_MODIFIER_SELECT_SHIFT (22UL)
+#define SCU_PDMA_CONFIGURATION_ADDRESS_MODIFIER_SELECT_MASK (0x00400000UL)
+#define SCU_PDMA_CONFIGURATION_RESERVED_MASK (0xFF800000UL)
+
+#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 (8UL)
+#define SCU_CDMA_CONFIGURATION_PCI_RELAXED_ORDERING_ENABLE_MASK (0x00000100UL)
+
+#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 (0UL)
+#define SCU_LINK_LAYER_SPEED_NEGOTIATION_TIMER_VALUES_TIMEOUT_MASK (0x000000FFUL)
+#define SCU_LINK_LAYER_SPEED_NEGOTIATION_TIMER_VALUES_LOCK_TIME_SHIFT (8UL)
+#define SCU_LINK_LAYER_SPEED_NEGOTIATION_TIMER_VALUES_LOCK_TIME_MASK (0x0000FF00UL)
+#define SCU_LINK_LAYER_SPEED_NEGOTIATION_TIMER_VALUES_RATE_CHANGE_DELAY_SHIFT (16UL)
+#define SCU_LINK_LAYER_SPEED_NEGOTIATION_TIMER_VALUES_RATE_CHANGE_DELAY_MASK (0x00FF0000UL)
+#define SCU_LINK_LAYER_SPEED_NEGOTIATION_TIMER_VALUES_DWORD_SYNC_TIMEOUT_SHIFT (24UL)
+#define SCU_LINK_LAYER_SPEED_NEGOTIATION_TIMER_VALUES_DWORD_SYNC_TIMEOUT_MASK (0xFF000000UL)
+#define SCU_LINK_LAYER_SPEED_NECGOIATION_TIMER_VALUES_REQUIRED_MASK (0x00000000UL)
+#define SCU_LINK_LAYER_SPEED_NECGOIATION_TIMER_VALUES_DEFAULT_MASK (0x7D00676FUL)
+#define SCU_LINK_LAYER_SPEED_NECGOIATION_TIMER_VALUES_RESERVED_MASK (0x00FF0000UL)
+
+#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 (2UL)
+#define SCU_LINK_STATUS_DWORD_SYNC_AQUIRED_MASK (0x00000004UL)
+#define SCU_LINK_STATUS_TRANSMIT_PORT_SELECTION_DONE_SHIFT (4UL)
+#define SCU_LINK_STATUS_TRANSMIT_PORT_SELECTION_DONE_MASK (0x00000010UL)
+#define SCU_LINK_STATUS_RECEIVER_CREDIT_EXHAUSTED_SHIFT (5UL)
+#define SCU_LINK_STATUS_RECEIVER_CREDIT_EXHAUSTED_MASK (0x00000020UL)
+#define SCU_LINK_STATUS_RESERVED_MASK (0xFFFFFFCDUL)
+
+#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 (0UL)
+#define SCU_SAS_MAX_ARBITRATION_WAIT_TIME_TIMEOUT_VALUE_MASK (0x00007FFFUL)
+#define SCU_SAS_MAX_ARBITRATION_WAIT_TIME_TIMEOUT_SCALE_SHIFT (15UL)
+#define SCU_SAS_MAX_ARBITRATION_WAIT_TIME_TIMEOUT_SCALE_MASK (0x00008000UL)
+
+#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 (1UL)
+#define SCU_SAS_TRANSMIT_IDENTIFICATION_SMP_TARGET_MASK (0x00000002UL)
+#define SCU_SAS_TRANSMIT_IDENTIFICATION_STP_TARGET_SHIFT (2UL)
+#define SCU_SAS_TRANSMIT_IDENTIFICATION_STP_TARGET_MASK (0x00000004UL)
+#define SCU_SAS_TRANSMIT_IDENTIFICATION_SSP_TARGET_SHIFT (3UL)
+#define SCU_SAS_TRANSMIT_IDENTIFICATION_SSP_TARGET_MASK (0x00000008UL)
+#define SCU_SAS_TRANSMIT_IDENTIFICATION_DA_SATA_HOST_SHIFT (8UL)
+#define SCU_SAS_TRANSMIT_IDENTIFICATION_DA_SATA_HOST_MASK (0x00000100UL)
+#define SCU_SAS_TRANSMIT_IDENTIFICATION_SMP_INITIATOR_SHIFT (9UL)
+#define SCU_SAS_TRANSMIT_IDENTIFICATION_SMP_INITIATOR_MASK (0x00000200UL)
+#define SCU_SAS_TRANSMIT_IDENTIFICATION_STP_INITIATOR_SHIFT (10UL)
+#define SCU_SAS_TRANSMIT_IDENTIFICATION_STP_INITIATOR_MASK (0x00000400UL)
+#define SCU_SAS_TRANSMIT_IDENTIFICATION_SSP_INITIATOR_SHIFT (11UL)
+#define SCU_SAS_TRANSMIT_IDENTIFICATION_SSP_INITIATOR_MASK (0x00000800UL)
+#define SCU_SAS_TRANSMIT_IDENTIFICATION_REASON_CODE_SHIFT (16UL)
+#define SCU_SAS_TRANSMIT_IDENTIFICATION_REASON_CODE_MASK (0x000F0000UL)
+#define SCU_SAS_TRANSMIT_IDENTIFICATION_ADDRESS_FRAME_TYPE_SHIFT (24UL)
+#define SCU_SAS_TRANSMIT_IDENTIFICATION_ADDRESS_FRAME_TYPE_MASK (0x0F000000UL)
+#define SCU_SAS_TRANSMIT_IDENTIFICATION_DEVICE_TYPE_SHIFT (28UL)
+#define SCU_SAS_TRANSMIT_IDENTIFICATION_DEVICE_TYPE_MASK (0x70000000UL)
+#define SCU_SAS_TRANSMIT_IDENTIFICATION_RESERVED_MASK (0x80F0F1F1UL)
+
+#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 (16UL)
+#define SCU_LINK_LAYER_IDENTIFY_FRAME_PHY_IDENTIFIER_BREAK_REPLY_CAPABLE_MASK (0x00010000UL)
+#define SCU_LINK_LAYER_IDENTIFY_FRAME_PHY_IDENTIFIER_REQUESTED_INSIDE_ZPSDS_SHIFT (17UL)
+#define SCU_LINK_LAYER_IDENTIFY_FRAME_PHY_IDENTIFIER_REQUESTED_INSIDE_ZPSDS_MASK (0x00020000UL)
+#define SCU_LINK_LAYER_IDENTIFY_FRAME_PHY_IDENTIFIER_INSIDE_ZPSDS_PERSISTENT_SHIFT (18UL)
+#define SCU_LINK_LAYER_IDENTIFY_FRAME_PHY_IDENTIFIER_INSIDE_ZPSDS_PERSISTENT_MASK (0x00040000UL)
+#define SCU_LINK_LAYER_IDENTIFY_FRAME_PHY_IDENTIFIER_ID_SHIFT (24UL)
+#define SCU_LINK_LAYER_IDENTIFY_FRAME_PHY_IDENTIFIER_ID_MASK (0xFF000000UL)
+#define SCU_LINK_LAYER_IDENTIFY_FRAME_PHY_IDENTIFIER_RESERVED_MASK (0x00F800FFUL)
+
+#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 (4UL)
+#define SCU_SAS_PHY_CONFIGURATION_TX_PARITY_CHECK_MASK (0x00000010UL)
+#define SCU_SAS_PHY_CONFIGURATION_TX_BAD_CRC_SHIFT (6UL)
+#define SCU_SAS_PHY_CONFIGURATION_TX_BAD_CRC_MASK (0x00000040UL)
+#define SCU_SAS_PHY_CONFIGURATION_DISABLE_SCRAMBLER_SHIFT (7UL)
+#define SCU_SAS_PHY_CONFIGURATION_DISABLE_SCRAMBLER_MASK (0x00000080UL)
+#define SCU_SAS_PHY_CONFIGURATION_DISABLE_DESCRAMBLER_SHIFT (8UL)
+#define SCU_SAS_PHY_CONFIGURATION_DISABLE_DESCRAMBLER_MASK (0x00000100UL)
+#define SCU_SAS_PHY_CONFIGURATION_DISABLE_CREDIT_INSERTION_SHIFT (9UL)
+#define SCU_SAS_PHY_CONFIGURATION_DISABLE_CREDIT_INSERTION_MASK (0x00000200UL)
+#define SCU_SAS_PHY_CONFIGURATION_SUSPEND_PROTOCOL_ENGINE_SHIFT (11UL)
+#define SCU_SAS_PHY_CONFIGURATION_SUSPEND_PROTOCOL_ENGINE_MASK (0x00000800UL)
+#define SCU_SAS_PHY_CONFIGURATION_SATA_SPINUP_HOLD_SHIFT (12UL)
+#define SCU_SAS_PHY_CONFIGURATION_SATA_SPINUP_HOLD_MASK (0x00001000UL)
+#define SCU_SAS_PHY_CONFIGURATION_TRANSMIT_PORT_SELECTION_SIGNAL_SHIFT (13UL)
+#define SCU_SAS_PHY_CONFIGURATION_TRANSMIT_PORT_SELECTION_SIGNAL_MASK (0x00002000UL)
+#define SCU_SAS_PHY_CONFIGURATION_HARD_RESET_SHIFT (14UL)
+#define SCU_SAS_PHY_CONFIGURATION_HARD_RESET_MASK (0x00004000UL)
+#define SCU_SAS_PHY_CONFIGURATION_OOB_ENABLE_SHIFT (15UL)
+#define SCU_SAS_PHY_CONFIGURATION_OOB_ENABLE_MASK (0x00008000UL)
+#define SCU_SAS_PHY_CONFIGURATION_ENABLE_FRAME_TX_INSERT_ALIGN_SHIFT (23UL)
+#define SCU_SAS_PHY_CONFIGURATION_ENABLE_FRAME_TX_INSERT_ALIGN_MASK (0x00800000UL)
+#define SCU_SAS_PHY_CONFIGURATION_FORWARD_IDENTIFY_FRAME_SHIFT (27UL)
+#define SCU_SAS_PHY_CONFIGURATION_FORWARD_IDENTIFY_FRAME_MASK (0x08000000UL)
+#define SCU_SAS_PHY_CONFIGURATION_DISABLE_BYTE_TRANSPOSE_STP_FRAME_SHIFT (28UL)
+#define SCU_SAS_PHY_CONFIGURATION_DISABLE_BYTE_TRANSPOSE_STP_FRAME_MASK (0x10000000UL)
+#define SCU_SAS_PHY_CONFIGURATION_OOB_RESET_SHIFT (29UL)
+#define SCU_SAS_PHY_CONFIGURATION_OOB_RESET_MASK (0x20000000UL)
+#define SCU_SAS_PHY_CONFIGURATION_THREE_IAF_ENABLE_SHIFT (30UL)
+#define SCU_SAS_PHY_CONFIGURATION_THREE_IAF_ENABLE_MASK (0x40000000UL)
+#define SCU_SAS_PHY_CONFIGURATION_OOB_ALIGN0_ENABLE_SHIFT (31UL)
+#define SCU_SAS_PHY_CONFIGURATION_OOB_ALIGN0_ENABLE_MASK (0x80000000UL)
+#define SCU_SAS_PHY_CONFIGURATION_REQUIRED_MASK (0x0100000FUL)
+#define SCU_SAS_PHY_CONFIGURATION_DEFAULT_MASK (0x4180100FUL)
+#define SCU_SAS_PHY_CONFIGURATION_RESERVED_MASK (0x00000000UL)
+
+#define SCU_SAS_PCFG_GEN_BIT(name) \
+ SCU_GEN_BIT(SCU_SAS_PHY_CONFIGURATION_##name)
+
+#define SCU_LINK_LAYER_ALIGN_INSERTION_FREQUENCY_GENERAL_SHIFT (0UL)
+#define SCU_LINK_LAYER_ALIGN_INSERTION_FREQUENCY_GENERAL_MASK (0x000007FFUL)
+#define SCU_LINK_LAYER_ALIGN_INSERTION_FREQUENCY_CONNECTED_SHIFT (16UL)
+#define SCU_LINK_LAYER_ALIGN_INSERTION_FREQUENCY_CONNECTED_MASK (0x00ff0000UL)
+
+#define SCU_ALIGN_INSERTION_FREQUENCY_GEN_VAL(name, value) \
+ SCU_GEN_VALUE(SCU_LINK_LAYER_ALIGN_INSERTION_FREQUENCY_##name, value)
+
+#define SCU_LINK_LAYER_ENABLE_SPINUP_CONTROL_COUNT_SHIFT (0UL)
+#define SCU_LINK_LAYER_ENABLE_SPINUP_CONTROL_COUNT_MASK (0x0003FFFFUL)
+#define SCU_LINK_LAYER_ENABLE_SPINUP_CONTROL_ENABLE_SHIFT (31UL)
+#define SCU_LINK_LAYER_ENABLE_SPINUP_CONTROL_ENABLE_MASK (0x80000000UL)
+#define SCU_LINK_LAYER_ENABLE_SPINUP_CONTROL_RESERVED_MASK (0x7FFC0000UL)
+
+#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 (1UL)
+#define SCU_LINK_LAYER_PHY_CAPABILITIES_TXSSCTYPE_MASK (0x00000002UL)
+#define SCU_LINK_LAYER_PHY_CAPABILITIES_RLLRATE_SHIFT (4UL)
+#define SCU_LINK_LAYER_PHY_CAPABILITIES_RLLRATE_MASK (0x000000F0UL)
+#define SCU_LINK_LAYER_PHY_CAPABILITIES_SWO15GBPS_SHIFT (8UL)
+#define SCU_LINK_LAYER_PHY_CAPABILITIES_SWO15GBPS_MASK (0x00000100UL)
+#define SCU_LINK_LAYER_PHY_CAPABILITIES_SW15GBPS_SHIFT (9UL)
+#define SCU_LINK_LAYER_PHY_CAPABILITIES_SW15GBPS_MASK (0x00000201UL)
+#define SCU_LINK_LAYER_PHY_CAPABILITIES_SWO30GBPS_SHIFT (10UL)
+#define SCU_LINK_LAYER_PHY_CAPABILITIES_SWO30GBPS_MASK (0x00000401UL)
+#define SCU_LINK_LAYER_PHY_CAPABILITIES_SW30GBPS_SHIFT (11UL)
+#define SCU_LINK_LAYER_PHY_CAPABILITIES_SW30GBPS_MASK (0x00000801UL)
+#define SCU_LINK_LAYER_PHY_CAPABILITIES_SWO60GBPS_SHIFT (12UL)
+#define SCU_LINK_LAYER_PHY_CAPABILITIES_SWO60GBPS_MASK (0x00001001UL)
+#define SCU_LINK_LAYER_PHY_CAPABILITIES_SW60GBPS_SHIFT (13UL)
+#define SCU_LINK_LAYER_PHY_CAPABILITIES_SW60GBPS_MASK (0x00002001UL)
+#define SCU_LINK_LAYER_PHY_CAPABILITIES_EVEN_PARITY_SHIFT (31UL)
+#define SCU_LINK_LAYER_PHY_CAPABILITIES_EVEN_PARITY_MASK (0x80000000UL)
+#define SCU_LINK_LAYER_PHY_CAPABILITIES_DEFAULT_MASK (0x00003F01UL)
+#define SCU_LINK_LAYER_PHY_CAPABILITIES_REQUIRED_MASK (0x00000001UL)
+#define SCU_LINK_LAYER_PHY_CAPABILITIES_RESERVED_MASK (0x7FFFC00DUL)
+
+#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 (0UL)
+#define SCU_LINK_LAYER_PHY_SOURCE_ZONE_GROUP_CONTROL_VIRTUAL_EXPANDER_PHY_ZONE_GROUP_MASK (0x000000FFUL)
+#define SCU_LINK_LAYER_PHY_SOURCE_ZONE_GROUP_CONTROL_INSIDE_SOURCE_ZONE_GROUP_SHIFT (31UL)
+#define SCU_LINK_LAYER_PHY_SOURCE_ZONE_GROUP_CONTROL_INSIDE_SOURCE_ZONE_GROUP_MASK (0x80000000UL)
+#define SCU_LINK_LAYER_PHY_SOURCE_ZONE_GROUP_CONTROL_RESERVED_MASK (0x7FFFFF00UL)
+
+#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 (1UL)
+#define SCU_PROTOCOL_ENGINE_GROUP_VIRTUAL_ZONING_EXPANDER_CONTROL_ZONE0_LOCKED_MASK (0x00000002UL)
+#define SCU_PROTOCOL_ENGINE_GROUP_VIRTUAL_ZONING_EXPANDER_CONTROL_ZONE0_UPDATING_SHIFT (2UL)
+#define SCU_PROTOCOL_ENGINE_GROUP_VIRTUAL_ZONING_EXPANDER_CONTROL_ZONE0_UPDATING_MASK (0x00000004UL)
+#define SCU_PROTOCOL_ENGINE_GROUP_VIRTUAL_ZONING_EXPANDER_CONTROL_ZONE1_LOCKED_SHIFT (4UL)
+#define SCU_PROTOCOL_ENGINE_GROUP_VIRTUAL_ZONING_EXPANDER_CONTROL_ZONE1_LOCKED_MASK (0x00000010UL)
+#define SCU_PROTOCOL_ENGINE_GROUP_VIRTUAL_ZONING_EXPANDER_CONTROL_ZONE1_UPDATING_SHIFT (5UL)
+#define SCU_PROTOCOL_ENGINE_GROUP_VIRTUAL_ZONING_EXPANDER_CONTROL_ZONE1_UPDATING_MASK (0x00000020UL)
+#define SCU_PROTOCOL_ENGINE_GROUP_VIRTUAL_ZONING_EXPANDER_CONTROL_ZPT_ASSOCIATION_PE0_SHIFT (16UL)
+#define SCU_PROTOCOL_ENGINE_GROUP_VIRTUAL_ZONING_EXPANDER_CONTROL_ZPT_ASSOCIATION_PE0_MASK (0x00030000UL)
+#define SCU_PROTOCOL_ENGINE_GROUP_VIRTUAL_ZONING_EXPANDER_CONTROL_AIP_ENABLE_PE0_SHIFT (19UL)
+#define SCU_PROTOCOL_ENGINE_GROUP_VIRTUAL_ZONING_EXPANDER_CONTROL_AIP_ENABLE_PE0_MASK (0x00080000UL)
+#define SCU_PROTOCOL_ENGINE_GROUP_VIRTUAL_ZONING_EXPANDER_CONTROL_ZPT_ASSOCIATION_PE1_SHIFT (20UL)
+#define SCU_PROTOCOL_ENGINE_GROUP_VIRTUAL_ZONING_EXPANDER_CONTROL_ZPT_ASSOCIATION_PE1_MASK (0x00300000UL)
+#define SCU_PROTOCOL_ENGINE_GROUP_VIRTUAL_ZONING_EXPANDER_CONTROL_AIP_ENABLE_PE1_SHIFT (23UL)
+#define SCU_PROTOCOL_ENGINE_GROUP_VIRTUAL_ZONING_EXPANDER_CONTROL_AIP_ENABLE_PE1_MASK (0x00800000UL)
+#define SCU_PROTOCOL_ENGINE_GROUP_VIRTUAL_ZONING_EXPANDER_CONTROL_ZPT_ASSOCIATION_PE2_SHIFT (24UL)
+#define SCU_PROTOCOL_ENGINE_GROUP_VIRTUAL_ZONING_EXPANDER_CONTROL_ZPT_ASSOCIATION_PE2_MASK (0x03000000UL)
+#define SCU_PROTOCOL_ENGINE_GROUP_VIRTUAL_ZONING_EXPANDER_CONTROL_AIP_ENABLE_PE2_SHIFT (27UL)
+#define SCU_PROTOCOL_ENGINE_GROUP_VIRTUAL_ZONING_EXPANDER_CONTROL_AIP_ENABLE_PE2_MASK (0x08000000UL)
+#define SCU_PROTOCOL_ENGINE_GROUP_VIRTUAL_ZONING_EXPANDER_CONTROL_ZPT_ASSOCIATION_PE3_SHIFT (28UL)
+#define SCU_PROTOCOL_ENGINE_GROUP_VIRTUAL_ZONING_EXPANDER_CONTROL_ZPT_ASSOCIATION_PE3_MASK (0x30000000UL)
+#define SCU_PROTOCOL_ENGINE_GROUP_VIRTUAL_ZONING_EXPANDER_CONTROL_AIP_ENABLE_PE3_SHIFT (31UL)
+#define SCU_PROTOCOL_ENGINE_GROUP_VIRTUAL_ZONING_EXPANDER_CONTROL_AIP_ENABLE_PE3_MASK (0x80000000UL)
+#define SCU_PROTOCOL_ENGINE_GROUP_VIRTUAL_ZONING_EXPANDER_CONTROL_RESERVED_MASK (0x4444FFC9UL)
+
+#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 (0UL)
+#define SCU_PTSG_CONTROL_IT_NEXUS_TIMEOUT_MASK (0x0000FFFFUL)
+#define SCU_PTSG_CONTROL_TASK_TIMEOUT_SHIFT (16UL)
+#define SCU_PTSG_CONTROL_TASK_TIMEOUT_MASK (0x00FF0000UL)
+#define SCU_PTSG_CONTROL_PTSG_ENABLE_SHIFT (24UL)
+#define SCU_PTSG_CONTROL_PTSG_ENABLE_MASK (0x01000000UL)
+#define SCU_PTSG_CONTROL_ETM_ENABLE_SHIFT (25UL)
+#define SCU_PTSG_CONTROL_ETM_ENABLE_MASK (0x02000000UL)
+#define SCU_PTSG_CONTROL_DEFAULT_MASK (0x00020002UL)
+#define SCU_PTSG_CONTROL_REQUIRED_MASK (0x00000000UL)
+#define SCU_PTSG_CONTROL_RESERVED_MASK (0xFC000000UL)
+
+#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 (0UL)
+#define SCU_PTSG_REAL_TIME_CLOCK_MASK (0x0000FFFFUL)
+#define SCU_PTSG_REAL_TIME_CLOCK_RESERVED_MASK (0xFFFF0000UL)
+
+#define SCU_RTCR_GEN_VAL(name, val) \
+ SCU_GEN_VALUE(SCU_PTSG_##name, val)
+
+
+#define SCU_PTSG_REAL_TIME_CLOCK_CONTROL_PRESCALER_VALUE_SHIFT (0UL)
+#define SCU_PTSG_REAL_TIME_CLOCK_CONTROL_PRESCALER_VALUE_MASK (0x00FFFFFFUL)
+#define SCU_PTSG_REAL_TIME_CLOCK_CONTROL_RESERVED_MASK (0xFF000000UL)
+
+#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 (0UL)
+#define SCU_PTSG_PORT_TASK_SCHEDULER_CONTROL_SUSPEND_MASK (0x00000001UL)
+#define SCU_PTSG_PORT_TASK_SCHEDULER_CONTROL_ENABLE_SHIFT (1UL)
+#define SCU_PTSG_PORT_TASK_SCHEDULER_CONTROL_ENABLE_MASK (0x00000002UL)
+#define SCU_PTSG_PORT_TASK_SCHEDULER_CONTROL_RESERVED_MASK (0xFFFFFFFCUL)
+
+#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 (0UL)
+#define SCU_PTSG_PORT_TASK_SCHEDULER_STATUS_NEXT_RN_VALID_MASK (0x00000001UL)
+#define SCU_PTSG_PORT_TASK_SCHEDULER_STATUS_ACTIVE_RNSC_LIST_VALID_SHIFT (1UL)
+#define SCU_PTSG_PORT_TASK_SCHEDULER_STATUS_ACTIVE_RNSC_LIST_VALID_MASK (0x00000002UL)
+#define SCU_PTSG_PORT_TASK_SCHEDULER_STATUS_PTS_SUSPENDED_SHIFT (2UL)
+#define SCU_PTSG_PORT_TASK_SCHEDULER_STATUS_PTS_SUSPENDED_MASK (0x00000004UL)
+#define SCU_PTSG_PORT_TASK_SCHEDULER_STATUS_RESERVED_MASK (0xFFFFFFF8UL)
+
+#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 (0UL)
+#define SCU_SGPIO_CONTROL_SGPIO_ENABLE_MASK (0x00000001UL)
+#define SCU_SGPIO_CONTROL_SGPIO_SERIAL_CLOCK_SELECT_SHIFT (1UL)
+#define SCU_SGPIO_CONTROL_SGPIO_SERIAL_CLOCK_SELECT_MASK (0x00000002UL)
+#define SCU_SGPIO_CONTROL_SGPIO_SERIAL_SHIFT_WIDTH_SELECT_SHIFT (2UL)
+#define SCU_SGPIO_CONTROL_SGPIO_SERIAL_SHIFT_WIDTH_SELECT_MASK (0x00000004UL)
+#define SCU_SGPIO_CONTROL_SGPIO_TEST_BIT_SHIFT (15UL)
+#define SCU_SGPIO_CONTROL_SGPIO_TEST_BIT_MASK (0x00008000UL)
+#define SCU_SGPIO_CONTROL_SGPIO_RESERVED_MASK (0xFFFF7FF8UL)
+
+#define SCU_SGICRx_GEN_BIT(name) \
+ SCU_GEN_BIT(SCU_SGPIO_CONTROL_SGPIO_##name)
+
+#define SCU_SGPIO_PROGRAMMABLE_BLINK_REGISTER_R0_SHIFT (0UL)
+#define SCU_SGPIO_PROGRAMMABLE_BLINK_REGISTER_R0_MASK (0x0000000FUL)
+#define SCU_SGPIO_PROGRAMMABLE_BLINK_REGISTER_R1_SHIFT (4UL)
+#define SCU_SGPIO_PROGRAMMABLE_BLINK_REGISTER_R1_MASK (0x000000F0UL)
+#define SCU_SGPIO_PROGRAMMABLE_BLINK_REGISTER_R2_SHIFT (8UL)
+#define SCU_SGPIO_PROGRAMMABLE_BLINK_REGISTER_R2_MASK (0x00000F00UL)
+#define SCU_SGPIO_PROGRAMMABLE_BLINK_REGISTER_R3_SHIFT (12UL)
+#define SCU_SGPIO_PROGRAMMABLE_BLINK_REGISTER_R3_MASK (0x0000F000UL)
+#define SCU_SGPIO_PROGRAMMABLE_BLINK_REGISTER_RESERVED_MASK (0xFFFF0000UL)
+
+#define SCU_SGPBRx_GEN_VAL(name, valueUL) \
+ SCU_GEN_VALUE(SCU_SGPIO_PROGRAMMABLE_BLINK_REGISTER_##name, value)
+
+#define SCU_SGPIO_START_DRIVE_LOWER_R0_SHIFT (0UL)
+#define SCU_SGPIO_START_DRIVE_LOWER_R0_MASK (0x00000003UL)
+#define SCU_SGPIO_START_DRIVE_LOWER_R1_SHIFT (4UL)
+#define SCU_SGPIO_START_DRIVE_LOWER_R1_MASK (0x00000030UL)
+#define SCU_SGPIO_START_DRIVE_LOWER_R2_SHIFT (8UL)
+#define SCU_SGPIO_START_DRIVE_LOWER_R2_MASK (0x00000300UL)
+#define SCU_SGPIO_START_DRIVE_LOWER_R3_SHIFT (12UL)
+#define SCU_SGPIO_START_DRIVE_LOWER_R3_MASK (0x00003000UL)
+#define SCU_SGPIO_START_DRIVE_LOWER_RESERVED_MASK (0xFFFF8888UL)
+
+#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 (0UL)
+#define SCU_SGPIO_START_DRIVE_UPPER_R0_MASK (0x00000003UL)
+#define SCU_SGPIO_START_DRIVE_UPPER_R1_SHIFT (4UL)
+#define SCU_SGPIO_START_DRIVE_UPPER_R1_MASK (0x00000030UL)
+#define SCU_SGPIO_START_DRIVE_UPPER_R2_SHIFT (8UL)
+#define SCU_SGPIO_START_DRIVE_UPPER_R2_MASK (0x00000300UL)
+#define SCU_SGPIO_START_DRIVE_UPPER_R3_SHIFT (12UL)
+#define SCU_SGPIO_START_DRIVE_UPPER_R3_MASK (0x00003000UL)
+#define SCU_SGPIO_START_DRIVE_UPPER_RESERVED_MASK (0xFFFF8888UL)
+
+#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 (0UL)
+#define SCU_SGPIO_SERIAL_INPUT_DATA_LOWER_D0_MASK (0x00000003UL)
+#define SCU_SGPIO_SERIAL_INPUT_DATA_LOWER_D1_SHIFT (4UL)
+#define SCU_SGPIO_SERIAL_INPUT_DATA_LOWER_D1_MASK (0x00000030UL)
+#define SCU_SGPIO_SERIAL_INPUT_DATA_LOWER_D2_SHIFT (8UL)
+#define SCU_SGPIO_SERIAL_INPUT_DATA_LOWER_D2_MASK (0x00000300UL)
+#define SCU_SGPIO_SERIAL_INPUT_DATA_LOWER_D3_SHIFT (12UL)
+#define SCU_SGPIO_SERIAL_INPUT_DATA_LOWER_D3_MASK (0x00003000UL)
+#define SCU_SGPIO_SERIAL_INPUT_DATA_LOWER_RESERVED_MASK (0xFFFF8888UL)
+
+#define SCU_SGSIDLRx_GEN_VAL(name, valueUL) \
+ SCU_GEN_VALUE(SCU_SGPIO_SERIAL_INPUT_DATA_LOWER_##name, value)
+
+#define SCU_SGPIO_SERIAL_INPUT_DATA_UPPER_D0_SHIFT (0UL)
+#define SCU_SGPIO_SERIAL_INPUT_DATA_UPPER_D0_MASK (0x00000003UL)
+#define SCU_SGPIO_SERIAL_INPUT_DATA_UPPER_D1_SHIFT (4UL)
+#define SCU_SGPIO_SERIAL_INPUT_DATA_UPPER_D1_MASK (0x00000030UL)
+#define SCU_SGPIO_SERIAL_INPUT_DATA_UPPER_D2_SHIFT (8UL)
+#define SCU_SGPIO_SERIAL_INPUT_DATA_UPPER_D2_MASK (0x00000300UL)
+#define SCU_SGPIO_SERIAL_INPUT_DATA_UPPER_D3_SHIFT (12UL)
+#define SCU_SGPIO_SERIAL_INPUT_DATA_UPPER_D3_MASK (0x00003000UL)
+#define SCU_SGPIO_SERIAL_INPUT_DATA_UPPER_RESERVED_MASK (0xFFFF8888UL)
+
+#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 (0UL)
+#define SCU_SGPIO_VENDOR_SPECIFIC_CODE_MASK (0x0000000FUL)
+#define SCU_SGPIO_VENDOR_SPECIFIC_CODE_RESERVED_MASK (0xFFFFFFF0UL)
+
+#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 (0UL)
+#define SCU_SGPIO_OUPUT_DATA_SELECT_INPUT_DATA0_MASK (0x00000003UL)
+#define SCU_SGPIO_OUPUT_DATA_SELECT_INVERT_INPUT_DATA0_SHIFT (2UL)
+#define SCU_SGPIO_OUPUT_DATA_SELECT_INVERT_INPUT_DATA0_MASK (0x00000004UL)
+#define SCU_SGPIO_OUPUT_DATA_SELECT_JOG_ENABLE_DATA0_SHIFT (3UL)
+#define SCU_SGPIO_OUPUT_DATA_SELECT_JOG_ENABLE_DATA0_MASK (0x00000008UL)
+#define SCU_SGPIO_OUPUT_DATA_SELECT_INPUT_DATA1_SHIFT (4UL)
+#define SCU_SGPIO_OUPUT_DATA_SELECT_INPUT_DATA1_MASK (0x00000030UL)
+#define SCU_SGPIO_OUPUT_DATA_SELECT_INVERT_INPUT_DATA1_SHIFT (6UL)
+#define SCU_SGPIO_OUPUT_DATA_SELECT_INVERT_INPUT_DATA1_MASK (0x00000040UL)
+#define SCU_SGPIO_OUPUT_DATA_SELECT_JOG_ENABLE_DATA1_SHIFT (7UL)
+#define SCU_SGPIO_OUPUT_DATA_SELECT_JOG_ENABLE_DATA1_MASK (0x00000080UL)
+#define SCU_SGPIO_OUPUT_DATA_SELECT_INPUT_DATA2_SHIFT (8UL)
+#define SCU_SGPIO_OUPUT_DATA_SELECT_INPUT_DATA2_MASK (0x00000300UL)
+#define SCU_SGPIO_OUPUT_DATA_SELECT_INVERT_INPUT_DATA2_SHIFT (10UL)
+#define SCU_SGPIO_OUPUT_DATA_SELECT_INVERT_INPUT_DATA2_MASK (0x00000400UL)
+#define SCU_SGPIO_OUPUT_DATA_SELECT_JOG_ENABLE_DATA2_SHIFT (11UL)
+#define SCU_SGPIO_OUPUT_DATA_SELECT_JOG_ENABLE_DATA2_MASK (0x00000800UL)
+#define SCU_SGPIO_OUPUT_DATA_SELECT_RESERVED_MASK (0xFFFFF000UL)
+
+#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)
+
+#ifdef ARLINGTON_BUILD
+typedef char LEX_REGISTERS_T;
+#endif
+
+//*****************************************************************************
+//* 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
+ *
+ * @brief These are the SMU registers
+ * See SCU SMU Specification on how this register space is used.
+ */
+typedef 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;
+// 0x00A8 CGUCR
+ U32 clock_gating_control;
+// 0x00AC CGUPC
+ U32 clock_gating_performance;
+// 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
+} SMU_REGISTERS_T;
+
+//*****************************************************************************
+// 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
+ *
+ * @brief These are the SCU SDMA Registers
+ * See SCU SDMA specification on how these registers are used.
+ */
+typedef 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_SDMA_REGISTERS_T;
+
+//*****************************************************************************
+//* 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 (0UL)
+#define SCU_TLCR_HASH_SAS_CHECKING_ENABLE_MASK (0x00000001UL)
+#define SCU_TLCR_CLEAR_TCI_NCQ_MAPPING_TABLE_SHIFT (1UL)
+#define SCU_TLCR_CLEAR_TCI_NCQ_MAPPING_TABLE_MASK (0x00000002UL)
+#define SCU_TLCR_STP_WRITE_DATA_PREFETCH_SHIFT (3UL)
+#define SCU_TLCR_STP_WRITE_DATA_PREFETCH_MASK (0x00000008UL)
+#define SCU_TLCR_CMD_NAK_STATUS_CODE_SHIFT (4UL)
+#define SCU_TLCR_CMD_NAK_STATUS_CODE_MASK (0x00000010UL)
+#define SCU_TLCR_RESERVED_MASK (0xFFFFFFEBUL)
+
+#define SCU_TLCR_GEN_BIT(name) \
+ SCU_GEN_BIT(SCU_TLCR_##name)
+
+/**
+ * @struct SCU_TRANSPORT_LAYER_REGISTERS
+ *
+ * @brief These are the SCU Transport Layer registers see SSPTL spec for how
+ * they are used.
+ */
+typedef 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];
+
+} SCU_TRANSPORT_LAYER_REGISTERS_T;
+
+// 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_ECENCR_OFFSET 0x0050
+#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_PHY_TIMER_TIMEOUT_VALUES_ALIGN_DETECTION_SHIFT (0UL)
+#define SCU_SAS_PHY_TIMER_TIMEOUT_VALUES_ALIGN_DETECTION_MASK (0x000000FFUL)
+#define SCU_SAS_PHY_TIMER_TIMEOUT_VALUES_HOT_PLUG_SHIFT (8UL)
+#define SCU_SAS_PHY_TIMER_TIMEOUT_VALUES_HOT_PLUG_MASK (0x0000FF00UL)
+#define SCU_SAS_PHY_TIMER_TIMEOUT_VALUES_COMSAS_DETECTION_SHIFT (16UL)
+#define SCU_SAS_PHY_TIMER_TIMEOUT_VALUES_COMSAS_DETECTION_MASK (0x00FF0000UL)
+#define SCU_SAS_PHY_TIMER_TIMEOUT_VALUES_RATE_CHANGE_SHIFT (24UL)
+#define SCU_SAS_PHY_TIMER_TIMEOUT_VALUES_RATE_CHANGE_MASK (0xFF000000UL)
+
+#define SCU_SAS_PHYTOV_GEN_VAL(name, value) \
+ SCU_GEN_VALUE(SCU_SAS_PHY_TIMER_TIMEOUT_VALUES_##name, value)
+
+#define SCU_SAS_LINK_LAYER_CONTROL_MAX_LINK_RATE_SHIFT (0UL)
+#define SCU_SAS_LINK_LAYER_CONTROL_MAX_LINK_RATE_MASK (0x00000003UL)
+#define SCU_SAS_LINK_LAYER_CONTROL_MAX_LINK_RATE_GEN1 (0UL)
+#define SCU_SAS_LINK_LAYER_CONTROL_MAX_LINK_RATE_GEN2 (1UL)
+#define SCU_SAS_LINK_LAYER_CONTROL_MAX_LINK_RATE_GEN3 (2UL)
+#define SCU_SAS_LINK_LAYER_CONTROL_BROADCAST_PRIMITIVE_SHIFT (2UL)
+#define SCU_SAS_LINK_LAYER_CONTROL_BROADCAST_PRIMITIVE_MASK (0x000003FCUL)
+#define SCU_SAS_LINK_LAYER_CONTROL_CLOSE_NO_ACTIVE_TASK_DISABLE_SHIFT (16UL)
+#define SCU_SAS_LINK_LAYER_CONTROL_CLOSE_NO_ACTIVE_TASK_DISABLE_MASK (0x00010000UL)
+#define SCU_SAS_LINK_LAYER_CONTROL_CLOSE_NO_OUTBOUND_TASK_DISABLE_SHIFT (17UL)
+#define SCU_SAS_LINK_LAYER_CONTROL_CLOSE_NO_OUTBOUND_TASK_DISABLE_MASK (0x00020000UL)
+#define SCU_SAS_LINK_LAYER_CONTROL_NO_OUTBOUND_TASK_TIMEOUT_SHIFT (24UL)
+#define SCU_SAS_LINK_LAYER_CONTROL_NO_OUTBOUND_TASK_TIMEOUT_MASK (0xFF000000UL)
+#define SCU_SAS_LINK_LAYER_CONTROL_RESERVED (0x00FCFC00UL)
+
+#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
+
+// This macro define the DWORD SYNC ACQUIRED bit in link layer status register.
+#define SCU_SAS_LLSTA_DWORD_SYNCA_BIT 0x4
+
+/**
+ * @struct SCU_LINK_LAYER_REGISTERS
+ *
+ * @brief SCU Link Layer Registers
+ * See the SCU SSLL Specification on how these registers are used.
+ */
+typedef 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 phy_timer_timeout_values;
+// 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_ECENCR
+ 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];
+
+} SCU_LINK_LAYER_REGISTERS_T;
+
+// 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
+ *
+ * @brief SCU SGPIO Registers
+ * See the SCU SGPIO Specification on how these registers are used.
+ */
+typedef 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;
+// 0x001C Reserved
+ U32 reserved_001C;
+// 0x0020 SGPIO_SGODSR
+ U32 output_data_select[8];
+// Remainder of memory space 256 bytes
+ U32 reserved_1444_14ff[0x30];
+
+} SCU_SGPIO_REGISTERS_T;
+
+//*****************************************************************************
+//* 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
+ *
+ * @brief These are the control/stats pairs for each Port Task Scheduler.
+ * See the SCU SCHED Specification on how these registers are used.
+ */
+typedef struct SCU_PORT_TASK_SCHEDULER_REGISTERS
+{
+ U32 control;
+ U32 status;
+} SCU_PORT_TASK_SCHEDULER_REGISTERS_T;
+
+typedef U32 SCU_PORT_PE_CONFIGURATION_REGISTER_T;
+
+/**
+ * @struct SCU_PORT_TASK_SCHEDULER_GROUP_REGISTERS
+ *
+ * @brief These are the PORT Task Scheduler registers
+ * See the SCU SCHED Specification on how these registers are used.
+ */
+typedef 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
+ SCU_PORT_TASK_SCHEDULER_REGISTERS_T 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];
+
+} SCU_PORT_TASK_SCHEDULER_GROUP_REGISTERS_T;
+
+#define SCU_PTSG_SCUVZECR_OFFSET 0x003C
+
+//*****************************************************************************
+//* AFE REGISTERS
+//*****************************************************************************
+#define SCU_AFE_MMR_BASE 0xE000
+
+#if defined(ARLINGTON_BUILD)
+#define SCU_AFE_PLL_CTL_OFFSET 0x0000
+#define SCU_AFE_RXPI_CTL_OFFSET 0x0004
+#define SCU_AFE_MBIAS_CTL0_OFFSET 0x000C
+#define SCU_AFE_MBIAS_CTL1_OFFSET 0x0010
+#define SCU_AFE_COMM_STA_OFFSET 0x0020
+#define SCU_AFE_RXPI_STA_OFFSET 0x0024
+#define SCU_AFE_XCVR0_CTL0_OFFSET 0x0040
+#define SCU_AFE_XCVR1_CTL0_OFFSET 0x0044
+#define SCU_AFE_XCVR2_CTL0_OFFSET 0x0048
+#define SCU_AFE_XCVR3_CTL0_OFFSET 0x004C
+#define SCU_AFE_XCVR0_CTL1_OFFSET 0x0050
+#define SCU_AFE_XCVR1_CTL1_OFFSET 0x0054
+#define SCU_AFE_XCVR2_CTL1_OFFSET 0x0058
+#define SCU_AFE_XCVR3_CTL1_OFFSET 0x005C
+#define SCU_AFE_XCVR0_RXEQ_CTL_OFFSET 0x0060
+#define SCU_AFE_XCVR1_RXEQ_CTL_OFFSET 0x0064
+#define SCU_AFE_XCVR2_RXEQ_CTL_OFFSET 0x0068
+#define SCU_AFE_XCVR3_RXEQ_CTL_OFFSET 0x006C
+#define SCU_AFE_XCVR0_CDR_STA_OFFSET 0x0080
+#define SCU_AFE_XCVR1_CDR_STA_OFFSET 0x0084
+#define SCU_AFE_XCVR2_CDR_STA_OFFSET 0x0088
+#define SCU_AFE_XCVR3_CDR_STA_OFFSET 0x008C
+#define SCU_AFE_XCVR0_RXEQ_STA0_OFFSET 0x0090
+#define SCU_AFE_XCVR1_RXEQ_STA0_OFFSET 0x0094
+#define SCU_AFE_XCVR2_RXEQ_STA0_OFFSET 0x0098
+#define SCU_AFE_XCVR3_RXEQ_STA0_OFFSET 0x009C
+#define SCU_AFE_XCVR0_RXEQ_STA1_OFFSET 0x00A0
+#define SCU_AFE_XCVR1_RXEQ_STA1_OFFSET 0x00A4
+#define SCU_AFE_XCVR2_RXEQ_STA1_OFFSET 0x00A8
+#define SCU_AFE_XCVR3_RXEQ_STA1_OFFSET 0x00AC
+#define SCU_AFE_DFX_MSTR_CTL_OFFSET 0x0104
+#define SCU_AFE_NTL_CTL_OFFSET 0x010C
+#define SCU_AFE_DFX_XCVR_STA_CLR_OFFSET 0x0120
+#define SCU_AFE_NTL_STA_OFFSET 0x0124
+#define SCU_AFE_DFX_XCVR0_STA0_OFFSET 0x0130
+#define SCU_AFE_DFX_XCVR1_STA0_OFFSET 0x0134
+#define SCU_AFE_DFX_XCVR2_STA0_OFFSET 0x0138
+#define SCU_AFE_DFX_XCVR3_STA0_OFFSET 0x013C
+#define SCU_AFE_DFX_XCVR0_STA1_OFFSET 0x0140
+#define SCU_AFE_DFX_XCVR1_STA1_OFFSET 0x0144
+#define SCU_AFE_DFX_XCVR2_STA1_OFFSET 0x0148
+#define SCU_AFE_DFX_XCVR3_STA1_OFFSET 0x014C
+#define SCU_AFE_DFX_MON_CTL_OFFSET 0x0150
+
+#define SCU_AFE_DFX_RX_CTL0_AFE0_XCVR0_OFFSET 0x0180
+#define SCU_AFE_DFX_RX_CTL0_AFE0_XCVR1_OFFSET 0x0184
+#define SCU_AFE_DFX_RX_CTL0_AFE0_XCVR2_OFFSET 0x0188
+#define SCU_AFE_DFX_RX_CTL0_AFE0_XCVR3_OFFSET 0x018C
+#define SCU_AFE_DFX_RX_CTL0_AFE1_XCVR0_OFFSET 0x0980
+#define SCU_AFE_DFX_RX_CTL0_AFE1_XCVR1_OFFSET 0x0984
+#define SCU_AFE_DFX_RX_CTL0_AFE1_XCVR2_OFFSET 0x0988
+#define SCU_AFE_DFX_RX_CTL0_AFE1_XCVR3_OFFSET 0x098C
+
+#define SCU_AFE_DFX_RX_CTL1_AFE0_XCVR0_OFFSET 0x0190
+#define SCU_AFE_DFX_RX_CTL1_AFE0_XCVR1_OFFSET 0x0194
+#define SCU_AFE_DFX_RX_CTL1_AFE0_XCVR2_OFFSET 0x0198
+#define SCU_AFE_DFX_RX_CTL1_AFE0_XCVR3_OFFSET 0x019C
+#define SCU_AFE_DFX_RX_CTL1_AFE1_XCVR0_OFFSET 0x0990
+#define SCU_AFE_DFX_RX_CTL1_AFE1_XCVR1_OFFSET 0x0994
+#define SCU_AFE_DFX_RX_CTL1_AFE1_XCVR2_OFFSET 0x0998
+#define SCU_AFE_DFX_RX_CTL1_AFE1_XCVR3_OFFSET 0x099C
+
+#define SCU_AFE_PLL_DFX_CTL_OFFSET 0x01C0
+
+#define SCU_AFE_XCVR0_DFX_DATA_OFFSET 0x0200 // [0:0F]
+#define SCU_AFE_XCVR0_CC_OFFSET 0x0240
+#define SCU_AFE_XCVR0_DFX_IR_OFFSET 0x0250 // [0:1F]
+
+#define SCU_AFE_XCVR1_DFX_DATA_OFFSET 0x0300 // [0:0F]
+#define SCU_AFE_XCVR1_CC_OFFSET 0x0340
+#define SCU_AFE_XCVR1_DFX_IR_OFFSET 0x0350 // [0:1F]
+
+#define SCU_AFE_XCVR2_DFX_DATA_OFFSET 0x0400 // [0:0F]
+#define SCU_AFE_XCVR2_CC_OFFSET 0x0440
+#define SCU_AFE_XCVR2_DFX_IR_OFFSET 0x0450 // [0:1F]
+
+#define SCU_AFE_XCVR3_DFX_DATA_OFFSET 0x0500 // [0:0F]
+#define SCU_AFE_XCVR3_CC_OFFSET 0x0540
+#define SCU_AFE_XCVR3_DFX_IR_OFFSET 0x0550 // [0:1F]
+#else // defined(ARLINGTON_BUILD)
+
+#endif // defined(ARLINGTON_BUILD)
+
+/**
+ * @struct SCU_AFE_TRANSCEIVER
+ *
+ * @brief AFE Transceiver Registers
+ * See SCU AFE Specification for use of these registers.
+ *
+ * @note For ARLINGTON_BUILD see the SCU AFE specification.
+ * @note For PLEASANT_RIDGE_BUILD build see the Uaoa AFE specification.
+ */
+#if defined(ARLINGTON_BUILD)
+ struct SCU_AFE_TRANSCEIVER
+ {
+ // 0x00
+ U32 afe_transceiver_dfx_data[0x10];
+ // 0x40
+ U32 afe_transceiver_dpg_cycle_control;
+ // 0x44 - 0x4c
+ U32 reserved_0044_004c[3];
+ // 0x50
+ U32 afe_transceiver_dfx_instruction[0x20];
+ // 0xd0 - 0xfc
+ U32 reserved_00d0_00fc[0x0C];
+ };
+
+#elif defined(PLEASANT_RIDGE_BUILD) \
+ || defined(PBG_HBA_A0_BUILD) \
+ || defined(PBG_HBA_A2_BUILD) \
+ || defined(PBG_HBA_BETA_BUILD) \
+ || defined(PBG_BUILD)
+
+ // 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];
+ };
+#else // !defined(PLEASANT_RIDGE_BUILD) && !defined(ARLINGTON_BUILD)
+ #error "Target platform not defined."
+#endif // defined(PLEASANT_RIDGE_BUILD) || defined(ARLINGTON_BUILD)
+
+/**
+ * @struct SCU_AFE_REGISTERS
+ *
+ * @brief AFE Regsiters
+ * See SCU AFE Specification for use of these registers.
+ */
+#if defined(ARLINGTON_BUILD)
+ typedef struct SCU_AFE_REGISTERS
+ {
+ // 0x0000
+ U32 afe_pll_control;
+ // 0x0004
+ U32 afe_phase_interplator_control;
+ // 0x0008
+ U32 reservd_0008;
+ // 0x000C
+ U32 afe_bias_control[2];
+ // 0x0014 - 0x001c
+ U32 reserved_0014_001c[3];
+ // 0x0020
+ U32 afe_common_status;
+ // 0x0024
+ U32 afe_phase_interpolator_status;
+ // 0x0028 - 0x003C
+ U32 reserved_0028_003c[6];
+ // 0x0040
+ U32 afe_transceiver_control0[4];
+ // 0x0050
+ U32 afe_transceiver_control1[4];
+ // 0x0060
+ U32 afe_transceiver_equalization_control[4];
+ // 0x0070 - 0x007c
+ U32 reserved_0070_007c[4];
+ // 0x0080
+ U32 afe_transceiver_cdr_status[4];
+ // 0x0090
+ U32 afe_transceiver_rx_equaliation_status_register0[4];
+ // 0x00A0
+ U32 afe_transceiver_rx_equaliation_status_register1[4];
+ // 0x00B0 - 0x0100
+ U32 reserved_00b0_0100[0x15];
+ // 0x0104
+ U32 afe_dfx_master_control;
+ // 0x0108
+ U32 reserved_0108;
+ // 0x010c
+ U32 afe_no_touch_leakage_control;
+ // 0x0110 - 0x011C
+ U32 reserved_0110_011c[4];
+ // 0x0120
+ U32 afe_dfx_transceiver_status_clear;
+ // 0x0124
+ U32 afe_no_touch_leakage_status;
+ // 0x0128 - 0x012c
+ U32 reserved_0128_012c[2];
+ // 0x0130
+ U32 afe_dfx_transceiver_status_register0[4];
+ // 0x0140
+ U32 afe_dfx_transceiver_status_register1[4];
+ // 0x0150
+ U32 afe_dfx_transmit_monitor_control;
+ // 0x0154 - 0x017c
+ U32 reserved_0154_017C[0x0B];
+ // 0x0180
+ U32 afe_dfx_receive_control_register0[4];
+ // 0x0190
+ U32 afe_dfx_receive_control_register1[4];
+ // 0x1A0
+ U32 afe_dfx_transmit_control_register[4];
+ // 0x01B0 - 0x01BC
+ U32 reserved_01b0_01bc[4];
+ // 0x01C0
+ U32 afe_pll_dfx_control;
+ // 0x01c4 - 0x01fc
+ U32 reserved_01c4_01fc[0x0F];
+ // 0x0200 - 0x05fc
+ struct SCU_AFE_TRANSCEIVER afe_transceiver[4];
+
+ // 0x0600 - 0x06FC
+ U32 reserved_0600_06FC[0x40];
+
+ // 0x0700
+ struct SCU_AFE_TRANSCEIVER afe_all_transceiver;
+
+ U32 reserved_0800_2000[0x600];
+
+ } SCU_AFE_REGISTERS_T;
+
+#elif defined(PLEASANT_RIDGE_BUILD) \
+ || defined(PBG_HBA_A0_BUILD) \
+ || defined(PBG_HBA_A2_BUILD) \
+ || defined(PBG_HBA_BETA_BUILD) \
+ || defined(PBG_BUILD)
+
+ /* Uaoa AFE registers */
+ typedef 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];
+ } SCU_AFE_REGISTERS_T;
+#else // !defined(PBG_HBA_BUILD) && defined(PLEASANT_RIDGE_BUILD) && !defined(ARLINGTON_BUILD)
+ #error "Target platform not defined."
+#endif // defined(PBG_HBA_BUILD) || defined(PLEASANT_RIDGE_BUILD) || defined(ARLINGTON_BUILD)
+
+
+struct SCU_PROTOCOL_ENGINE_GROUP_REGISTERS
+{
+ U32 table[0xE0];
+};
+
+
+struct SCU_VIIT_IIT
+{
+ U32 table[256];
+};
+
+/**
+ * @brief 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];
+};
+
+/**
+ * @brief CRAM register. MMR base address for CRAMC is 0x6400
+ * relative to SCUBAR.
+ *
+ */
+struct SCU_COMPLETION_RAM
+{
+ U32 sram_base_address_0; //0x0000
+ U32 sram_upper_base_address_0; //0x0004
+ U32 sram_ecc_control_0; //0x0008
+ U32 sram_ecc_log_0; //0x000c
+ U32 sram_ecc_addrress_0; //0x0010
+ U32 sram_ecc_context_address_0; //0x0014
+ U32 sram_ecc_test_0; //0x0018
+ U32 sram_parity_control_and_status_0; //0x001C
+ U32 sram_parity_address_0; //0x0020
+ U32 sram_parity_upper_address_0; //0x0024
+ U32 sram_parity_context_0; //0x0028
+ U32 sram_memory_controller_interrupt_status_0; //0x002C
+ U32 sram_mcu_read_arbiter_control_0; //0x0030
+ U32 sram_mcu_write_arbiter_control_0; //0x0034
+ U32 smcu_error_event_counter_0_0; //0x0038
+
+ //Remainder CRAM register space
+ U32 reserved_003C_0200[113];
+};
+
+/**
+ * @brief FBRAM registers. MMR base address for FBRAM is
+ * 0x6600 relative to SCUBAR.
+ */
+struct SCU_FRAME_BUFFER_RAM
+{
+ U32 sram_base_address_1; //0x0000
+ U32 sram_upper_base_address_1; //0x0004
+ U32 sram_ecc_control_1; //0x0008
+ U32 sram_ecc_log_1; //0x000c
+ U32 sram_ecc_addrress_1; //0x0010
+ U32 sram_ecc_context_address_1; //0x0014
+ U32 sram_ecc_test_1; //0x0018
+ U32 sram_parity_control_and_status_1; //0x001C
+ U32 sram_parity_address_1; //0x0020
+ U32 sram_parity_upper_address_1; //0x0024
+ U32 sram_parity_context_1; //0x0028
+ U32 sram_memory_controller_interrupt_status_1; //0x002C
+ U32 sram_mcu_read_arbiter_control_1; //0x0030
+ U32 sram_mcu_write_arbiter_control_1; //0x0034
+ U32 smcu_error_event_counter_0_1; //0x0038
+
+ //Remainder of FBRAM register space
+ U32 reserved_003C_0200[113];
+};
+
+#define SCU_SCRATCH_RAM_SIZE_IN_DWORDS 256
+
+/**
+* @brief Placeholder for the scratch RAM registers.
+*
+*/
+struct SCU_SCRATCH_RAM
+{
+ U32 ram[SCU_SCRATCH_RAM_SIZE_IN_DWORDS];
+};
+
+/**
+ * @brief Placeholder since I am not yet sure what these registers are here
+ * for.
+ *
+ */
+struct NOA_PROTOCOL_ENGINE_PARTITION
+{
+ U32 reserved[64];
+};
+
+/**
+ * @brief Placeholder since I am not yet sure what these registers are here
+ * for.
+ *
+ */
+struct NOA_HUB_PARTITION
+{
+ U32 reserved[64];
+};
+
+/**
+ * @brief 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
+ *
+ * @brief 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
+ *
+ * @brief 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
+ *
+ * @brief 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.
+ * See SCU SMU Specification for how these registers are mapped.
+ *
+ */
+typedef 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;
+
+} SCU_REGISTERS_T;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // _SCU_REGISTERS_HEADER_
diff --git a/sys/dev/isci/scil/scu_remote_node_context.h b/sys/dev/isci/scil/scu_remote_node_context.h
new file mode 100644
index 0000000..78786ff
--- /dev/null
+++ b/sys/dev/isci/scil/scu_remote_node_context.h
@@ -0,0 +1,242 @@
+/*-
+ * 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.
+ *
+ * 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.
+ *
+ * $FreeBSD$
+ */
+#ifndef __SCU_REMOTE_NODE_CONTEXT_HEADER__
+#define __SCU_REMOTE_NODE_CONTEXT_HEADER__
+
+/**
+ * @file
+ *
+ * @brief This file contains the structures and constatns used by the SCU
+ * hardware to describe a remote node context.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif // __cplusplus
+
+#include <dev/isci/scil/sci_types.h>
+
+/**
+ * @struct SSP_REMOTE_NODE_CONTEXT
+ *
+ * @brief This structure contains the SCU hardware definition for an SSP
+ * remote node.
+ */
+typedef 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;
+
+} SSP_REMOTE_NODE_CONTEXT_T;
+
+/**
+ * @struct STP_REMOTE_NODE_CONTEXT
+ *
+ * @brief This structure contains the SCU hardware definition for a STP remote
+ * node.
+ *
+ * @todo STP Targets are not yet supported so this definition is a placeholder
+ * until we do support them.
+ */
+typedef struct STP_REMOTE_NODE_CONTEXT
+{
+ /**
+ * Placeholder data for the STP remote node.
+ */
+ U32 data[8];
+
+} STP_REMOTE_NODE_CONTEXT_T;
+
+/**
+ * @union SCU_REMOTE_NODE_CONTEXT
+ *
+ * @brief This union combines the SAS and SATA remote node definitions.
+ */
+typedef union SCU_REMOTE_NODE_CONTEXT
+{
+ /**
+ * SSP Remote Node
+ */
+ SSP_REMOTE_NODE_CONTEXT_T ssp;
+
+ /**
+ * STP Remote Node
+ */
+ STP_REMOTE_NODE_CONTEXT_T stp;
+
+} SCU_REMOTE_NODE_CONTEXT_T;
+
+#ifdef __cplusplus
+}
+#endif // __cplusplus
+
+#endif // __SCU_REMOTE_NODE_CONTEXT_HEADER__
diff --git a/sys/dev/isci/scil/scu_task_context.h b/sys/dev/isci/scil/scu_task_context.h
new file mode 100644
index 0000000..f73ce64
--- /dev/null
+++ b/sys/dev/isci/scil/scu_task_context.h
@@ -0,0 +1,965 @@
+/*-
+ * 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.
+ *
+ * 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.
+ *
+ * $FreeBSD$
+ */
+#ifndef _SCU_TASK_CONTEXT_H_
+#define _SCU_TASK_CONTEXT_H_
+
+/**
+ * @file
+ *
+ * @brief This file contains the structures and constants for the SCU hardware
+ * task context.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif // __cplusplus
+
+#include <dev/isci/scil/sci_types.h>
+
+/**
+ * @enum SCU_SSP_TASK_TYPE
+ *
+ * @brief 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
+ *
+ * @brief 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;
+
+
+/**
+ * @name SCU_CONTEXT_TYPE
+ */
+/*@{*/
+#define SCU_TASK_CONTEXT_TYPE 0
+#define SCU_RNC_CONTEXT_TYPE 1
+/*@}*/
+
+/**
+ * @name SCU_TASK_CONTEXT_VALIDITY
+ */
+/*@{*/
+#define SCU_TASK_CONTEXT_INVALID 0
+#define SCU_TASK_CONTEXT_VALID 1
+/*@}*/
+
+/**
+ * @name 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
+/*@}*/
+
+/**
+ * @name 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
+/**
+ * @name SATA_DIRECTION
+ */
+/*@{*/
+#define SCU_SATA_WRITE_DATA_DIRECTION 0
+#define SCU_SATA_READ_DATA_DIRECTION 1
+/*@}*/
+
+/**
+ * @name 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 21UL
+#define SCU_CONTEXT_COMMAND_REQUEST_TYPE_MASK 0x00E00000UL
+#define scu_get_command_request_type(x) \
+ ((x) & SCU_CONTEXT_COMMAND_REQUEST_TYPE_MASK)
+
+#define SCU_CONTEXT_COMMAND_REQUEST_SUBTYPE_SHIFT 18UL
+#define SCU_CONTEXT_COMMAND_REQUEST_SUBTYPE_MASK 0x001C0000UL
+#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 16UL
+#define SCU_CONTEXT_COMMAND_PROTOCOL_ENGINE_GROUP_MASK 0x00010000UL
+#define scu_get_command_protocl_engine_group(x) \
+ ((x) & SCU_CONTEXT_COMMAND_PROTOCOL_ENGINE_GROUP_MASK)
+
+#define SCU_CONTEXT_COMMAND_LOGICAL_PORT_SHIFT 12UL
+#define SCU_CONTEXT_COMMAND_LOGICAL_PORT_MASK 0x00007000UL
+#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)
+/*@}*/
+
+/**
+ * @name 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(0UL)
+#define SCU_CONTEXT_COMMAND_REQUEST_TYPE_DUMP_TC MAKE_SCU_CONTEXT_COMMAND_TYPE(1UL)
+#define SCU_CONTEXT_COMMAND_REQUEST_TYPE_POST_RNC MAKE_SCU_CONTEXT_COMMAND_TYPE(2UL)
+#define SCU_CONTEXT_COMMAND_REQUEST_TYPE_DUMP_RNC MAKE_SCU_CONTEXT_COMMAND_TYPE(3UL)
+#define SCU_CONTEXT_COMMAND_REQUEST_TYPE_OTHER_RNC MAKE_SCU_CONTEXT_COMMAND_TYPE(6UL)
+/*@}*/
+
+#define MAKE_SCU_CONTEXT_COMMAND_REQUEST(type, command) \
+ ((type) | (((U32)(command)) << SCU_CONTEXT_COMMAND_REQUEST_SUBTYPE_SHIFT))
+
+/**
+ * @name 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))
+/*@}*/
+
+/**
+ * @name 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
+ *
+ * @brief 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
+ *
+ * @brief 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
+ *
+ * @brief 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
+ *
+ * @brief 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;
+};
+
+/**
+ * @union PROTOCOL_CONTEXT
+ *
+ * @brief The union of the protocols that can be selected in the SCU task
+ * context field.
+ */
+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
+ * @typedef SCU_SGL_ELEMENT_T
+ *
+ * @brief 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.
+ */
+typedef 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;
+
+} SCU_SGL_ELEMENT_T;
+
+#define SCU_SGL_ELEMENT_PAIR_A 0
+#define SCU_SGL_ELEMENT_PAIR_B 1
+
+/**
+ * @struct SCU_SGL_ELEMENT_PAIR
+ *
+ * @brief 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.
+ */
+typedef struct SCU_SGL_ELEMENT_PAIR
+{
+ // OFFSET 0x60-0x68
+ /**
+ * This field is the SGL element A of the SGL pair.
+ */
+ SCU_SGL_ELEMENT_T A;
+
+ // OFFSET 0x6C-0x74
+ /**
+ * This field is the SGL element B of the SGL pair.
+ */
+ SCU_SGL_ELEMENT_T 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;
+
+} SCU_SGL_ELEMENT_PAIR_T;
+
+/**
+ * @struct TRANSPORT_SNAPSHOT
+ *
+ * @brief 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
+ *
+ * @brief 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.
+ */
+typedef 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.
+ */
+ SCU_SGL_ELEMENT_PAIR_T sgl_pair_ab;
+ // OFFSET 0x80-0x9C
+ /**
+ * This field is the second SGL element pair found in the TC data structure.
+ */
+ SCU_SGL_ELEMENT_PAIR_T sgl_pair_cd;
+
+ // OFFSET 0xA0-BC
+ SCU_SGL_ELEMENT_PAIR_T 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;
+
+} SCU_TASK_CONTEXT_T;
+
+#ifdef __cplusplus
+}
+#endif // __cplusplus
+
+#endif // _SCU_TASK_CONTEXT_H_
diff --git a/sys/dev/isci/scil/scu_unsolicited_frame.h b/sys/dev/isci/scil/scu_unsolicited_frame.h
new file mode 100644
index 0000000..a99a7b2
--- /dev/null
+++ b/sys/dev/isci/scil/scu_unsolicited_frame.h
@@ -0,0 +1,122 @@
+/*-
+ * 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.
+ *
+ * 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.
+ *
+ * $FreeBSD$
+ */
+/**
+ * @file
+ *
+ * @brief 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_
+
+#ifdef __cplusplus
+extern "C" {
+#endif // __cplusplus
+
+#include <dev/isci/scil/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.
+ */
+typedef 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];
+
+} SCU_UNSOLICITED_FRAME_HEADER_T;
+
+#ifdef __cplusplus
+}
+#endif // __cplusplus
+
+#endif // _SCU_UNSOLICITED_FRAME_H_
diff --git a/sys/dev/isci/scil/scu_viit_data.h b/sys/dev/isci/scil/scu_viit_data.h
new file mode 100644
index 0000000..9c9d14d
--- /dev/null
+++ b/sys/dev/isci/scil/scu_viit_data.h
@@ -0,0 +1,186 @@
+/*-
+ * 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.
+ *
+ * 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.
+ *
+ * $FreeBSD$
+ */
+#ifndef _SCU_VIIT_DATA_HEADER_
+#define _SCU_VIIT_DATA_HEADER_
+
+/**
+ * @file
+ *
+ * @brief This file contains the constants and structures for the SCU hardware
+ * VIIT table entries.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif // __cplusplus
+
+#include <dev/isci/scil/sci_types.h>
+
+#define SCU_VIIT_ENTRY_ID_MASK (0xC0000000UL)
+#define SCU_VIIT_ENTRY_ID_SHIFT (30UL)
+
+#define SCU_VIIT_ENTRY_FUNCTION_MASK (0x0FF00000UL)
+#define SCU_VIIT_ENTRY_FUNCTION_SHIFT (20UL)
+
+#define SCU_VIIT_ENTRY_IPPTMODE_MASK (0x0001F800UL)
+#define SCU_VIIT_ENTRY_IPPTMODE_SHIFT (12UL)
+
+#define SCU_VIIT_ENTRY_LPVIE_MASK (0x00000F00UL)
+#define SCU_VIIT_ENTRY_LPVIE_SHIFT (8UL)
+
+#define SCU_VIIT_ENTRY_STATUS_MASK (0x000000FFUL)
+#define SCU_VIIT_ENTRY_STATUS_SHIFT (0UL)
+
+#define SCU_VIIT_ENTRY_ID_INVALID (0UL << SCU_VIIT_ENTRY_ID_SHIFT)
+#define SCU_VIIT_ENTRY_ID_VIIT (1UL << SCU_VIIT_ENTRY_ID_SHIFT)
+#define SCU_VIIT_ENTRY_ID_IIT (2UL << SCU_VIIT_ENTRY_ID_SHIFT)
+#define SCU_VIIT_ENTRY_ID_VIRT_EXP (3UL << SCU_VIIT_ENTRY_ID_SHIFT)
+
+#define SCU_VIIT_IPPT_SSP_INITIATOR (0x01UL << SCU_VIIT_ENTRY_IPPTMODE_SHIFT)
+#define SCU_VIIT_IPPT_SMP_INITIATOR (0x02UL << SCU_VIIT_ENTRY_IPPTMODE_SHIFT)
+#define SCU_VIIT_IPPT_STP_INITIATOR (0x04UL << 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 (0x01UL << SCU_VIIT_ENTRY_STATUS_SHIFT)
+#define SCU_VIIT_STATUS_ADDRESS_VALID (0x02UL << SCU_VIIT_ENTRY_STATUS_SHIFT)
+#define SCU_VIIT_STATUS_RNI_VALID (0x04UL << 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 (0x10UL << SCU_VIIT_ENTRY_IPPTMODE_SHIFT)
+
+/**
+ * @struct SCU_VIIT_ENTRY
+ *
+ * @brief This is the SCU Virtual Initiator Table Entry
+ */
+typedef 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;
+
+} SCU_VIIT_ENTRY_T;
+
+
+// IIT Status Defines
+#define SCU_IIT_ENTRY_ID_MASK (0xC0000000UL)
+#define SCU_IIT_ENTRY_ID_SHIFT (30UL)
+
+#define SCU_IIT_ENTRY_STATUS_UPDATE_MASK (0x20000000UL)
+#define SCU_IIT_ENTRY_STATUS_UPDATE_SHIFT (29UL)
+
+#define SCU_IIT_ENTRY_LPI_MASK (0x00000F00UL)
+#define SCU_IIT_ENTRY_LPI_SHIFT (8UL)
+
+#define SCU_IIT_ENTRY_STATUS_MASK (0x000000FFUL)
+#define SCU_IIT_ENTRY_STATUS_SHIFT (0UL)
+
+// IIT Remote Initiator Defines
+#define SCU_IIT_ENTRY_REMOTE_TAG_MASK (0x0000FFFFUL)
+#define SCU_IIT_ENTRY_REMOTE_TAG_SHIFT (0UL)
+
+#define SCU_IIT_ENTRY_REMOTE_RNC_MASK (0x0FFF0000UL)
+#define SCU_IIT_ENTRY_REMOTE_RNC_SHIFT (16UL)
+
+#define SCU_IIT_ENTRY_ID_INVALID (0UL << SCU_IIT_ENTRY_ID_SHIFT)
+#define SCU_IIT_ENTRY_ID_VIIT (1UL << SCU_IIT_ENTRY_ID_SHIFT)
+#define SCU_IIT_ENTRY_ID_IIT (2UL << SCU_IIT_ENTRY_ID_SHIFT)
+#define SCU_IIT_ENTRY_ID_VIRT_EXP (3UL << SCU_IIT_ENTRY_ID_SHIFT)
+
+/**
+ * @struct SCU_IIT_ENTRY
+ *
+ * @brief This will be implemented later when we support virtual functions
+ */
+typedef struct SCU_IIT_ENTRY
+{
+ U32 status;
+ U32 remote_initiator_sas_address_hi;
+ U32 remote_initiator_sas_address_lo;
+ U32 remote_initiator;
+
+} SCU_IIT_ENTRY_T;
+
+#ifdef __cplusplus
+}
+#endif // __cplusplus
+
+#endif // _SCU_VIIT_DATA_HEADER_
diff --git a/sys/dev/isci/types.h b/sys/dev/isci/types.h
new file mode 100644
index 0000000..59c4834
--- /dev/null
+++ b/sys/dev/isci/types.h
@@ -0,0 +1,53 @@
+/*-
+ * 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.
+ *
+ * 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.
+ *
+ * $FreeBSD$
+ */
+#ifndef _DRIVER_INCLUDE_TYPES_H_
+#define _DRIVER_INCLUDE_TYPES_H_
+
+#include <dev/isci/environment.h>
+
+typedef uintptr_t POINTER_UINT;
+
+#ifndef NULL
+#define NULL ((void *)0)
+#endif
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+#ifndef TRUE
+#define TRUE (!FALSE)
+#endif
+
+typedef uint32_t BOOL;
+
+#endif /* _DRIVER_INCLUDE_TYPES_H_ */
OpenPOWER on IntegriCloud