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