freebsd-dev/sys/dev/isci/scil/sati.c
Pedro F. Giffuni 718cf2ccb9 sys/dev: further adoption of SPDX licensing ID tags.
Mainly focus on files that use BSD 2-Clause license, however the tool I
was using misidentified many licenses so this was mostly a manual - error
prone - task.

The Software Package Data Exchange (SPDX) group provides a specification
to make it easier for automated tools to detect and summarize well known
opensource licenses. We are gradually adopting the specification, noting
that the tags are considered only advisory and do not, in any way,
superceed or replace the license texts.
2017-11-27 14:52:40 +00:00

1249 lines
39 KiB
C

/*-
* 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;
}
}