diff options
Diffstat (limited to 'sys/dev/isci/scil/sati.c')
-rw-r--r-- | sys/dev/isci/scil/sati.c | 1250 |
1 files changed, 1250 insertions, 0 deletions
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; + } +} |