/*- * This file is provided under a dual BSD/GPLv2 license. When using or * redistributing this file, you may do so under either license. * * GPL LICENSE SUMMARY * * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. * The full GNU General Public License is included in this distribution * in the file called LICENSE.GPL. * * BSD LICENSE * * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must 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 __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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include //****************************************************************************** //* 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 ); 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; } }