838 lines
30 KiB
C
838 lines
30 KiB
C
|
/*-
|
||
|
* This file is provided under a dual BSD/GPLv2 license. When using or
|
||
|
* redistributing this file, you may do so under either license.
|
||
|
*
|
||
|
* GPL LICENSE SUMMARY
|
||
|
*
|
||
|
* Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
|
||
|
*
|
||
|
* This program is free software; you can redistribute it and/or modify
|
||
|
* it under the terms of version 2 of the GNU General Public License as
|
||
|
* published by the Free Software Foundation.
|
||
|
*
|
||
|
* This program is distributed in the hope that it will be useful, but
|
||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||
|
* General Public License for more details.
|
||
|
*
|
||
|
* You should have received a copy of the GNU General Public License
|
||
|
* along with this program; if not, write to the Free Software
|
||
|
* Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
|
||
|
* The full GNU General Public License is included in this distribution
|
||
|
* in the file called LICENSE.GPL.
|
||
|
*
|
||
|
* BSD LICENSE
|
||
|
*
|
||
|
* Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
|
||
|
* All rights reserved.
|
||
|
*
|
||
|
* Redistribution and use in source and binary forms, with or without
|
||
|
* modification, are permitted provided that the following conditions
|
||
|
* are met:
|
||
|
*
|
||
|
* * Redistributions of source code must retain the above copyright
|
||
|
* notice, this list of conditions and the following disclaimer.
|
||
|
* * Redistributions in binary form must reproduce the above copyright
|
||
|
* notice, this list of conditions and the following disclaimer in
|
||
|
* the documentation and/or other materials provided with the
|
||
|
* distribution.
|
||
|
*
|
||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||
|
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||
|
*/
|
||
|
|
||
|
#include <sys/cdefs.h>
|
||
|
__FBSDID("$FreeBSD$");
|
||
|
|
||
|
/**
|
||
|
* @file
|
||
|
* @brief This file contains the method implementations required to
|
||
|
* translate the SCSI mode sense (6 and 10-byte) commands.
|
||
|
*/
|
||
|
|
||
|
#if !defined(DISABLE_SATI_MODE_SENSE)
|
||
|
|
||
|
#include <dev/isci/scil/sati_mode_sense.h>
|
||
|
#include <dev/isci/scil/sati_mode_pages.h>
|
||
|
#include <dev/isci/scil/sati_callbacks.h>
|
||
|
#include <dev/isci/scil/sati_util.h>
|
||
|
#include <dev/isci/scil/intel_scsi.h>
|
||
|
#include <dev/isci/scil/intel_ata.h>
|
||
|
|
||
|
//******************************************************************************
|
||
|
//* P R I V A T E M E T H O D S
|
||
|
//******************************************************************************
|
||
|
|
||
|
#define STANDBY_TIMER_DISABLED 0x00
|
||
|
#define STANDBY_TIMER_ENABLED 0x01
|
||
|
#define STANDBY_TIMER_SUPPORTED 0x2000
|
||
|
|
||
|
|
||
|
|
||
|
/**
|
||
|
* @brief This method indicates if the supplied page control is supported
|
||
|
* by this translation implementation. Currently savable parameters
|
||
|
* (i.e. non-volatile) are not supported.
|
||
|
* For more information on the parameters passed to this method,
|
||
|
* please reference sati_translate_command().
|
||
|
*
|
||
|
* @return This method returns an indication of whether the page control
|
||
|
* specified in the SCSI CDB is supported.
|
||
|
* @retval SATI_SUCCESS This value is returned if the page control is
|
||
|
* supported.
|
||
|
* @retval SATI_FAILURE_CHECK_RESPONSE_DATA This value is returned if the
|
||
|
* page control is not supported.
|
||
|
*/
|
||
|
static
|
||
|
SATI_STATUS sati_mode_sense_is_page_control_supported(
|
||
|
SATI_TRANSLATOR_SEQUENCE_T * sequence,
|
||
|
void * scsi_io
|
||
|
)
|
||
|
{
|
||
|
U8 * cdb = sati_cb_get_cdb_address(scsi_io);
|
||
|
|
||
|
switch (sati_get_cdb_byte(cdb, 2) >> SCSI_MODE_SENSE_PC_SHIFT)
|
||
|
{
|
||
|
case SCSI_MODE_SENSE_PC_CURRENT:
|
||
|
case SCSI_MODE_SENSE_PC_DEFAULT:
|
||
|
case SCSI_MODE_SENSE_PC_CHANGEABLE:
|
||
|
return SATI_SUCCESS;
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
case SCSI_MODE_SENSE_PC_SAVED:
|
||
|
sati_scsi_sense_data_construct(
|
||
|
sequence,
|
||
|
scsi_io,
|
||
|
SCSI_STATUS_CHECK_CONDITION,
|
||
|
SCSI_SENSE_ILLEGAL_REQUEST,
|
||
|
SCSI_ASC_SAVING_PARMS_NOT_SUPPORTED,
|
||
|
SCSI_ASCQ_SAVING_PARMS_NOT_SUPPORTED
|
||
|
);
|
||
|
return SATI_FAILURE_CHECK_RESPONSE_DATA;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @brief This method indicates if the page code field in the SCSI CDB
|
||
|
* is supported by this translation.
|
||
|
* For more information on the parameters passed to this method,
|
||
|
* please reference sati_translate_command().
|
||
|
*
|
||
|
* @param[in] cdb_length This parameter specifies the length of the SCSI
|
||
|
* CDB being translated (e.g. 6-byte, 10-byte, 12-byte, etc.)
|
||
|
*
|
||
|
* @return This method returns an indication as to whether the page code
|
||
|
* in the CDB is supported.
|
||
|
* @retval SATI_SUCCESS This value is returned if the page code is
|
||
|
* supported.
|
||
|
* @retval SATI_FAILURE_CHECK_RESPONSE_DATA This value is returned if the
|
||
|
* page code is not supported.
|
||
|
*/
|
||
|
static
|
||
|
SATI_STATUS sati_mode_sense_is_page_code_supported(
|
||
|
SATI_TRANSLATOR_SEQUENCE_T * sequence,
|
||
|
void * scsi_io,
|
||
|
U8 cdb_length
|
||
|
)
|
||
|
{
|
||
|
U8 * cdb = sati_cb_get_cdb_address(scsi_io);
|
||
|
|
||
|
switch (sati_get_cdb_byte(cdb, 2) & SCSI_MODE_SENSE_PAGE_CODE_ENABLE)
|
||
|
{
|
||
|
case SCSI_MODE_PAGE_CACHING:
|
||
|
if (sati_get_cdb_byte(cdb, 0) == SCSI_MODE_SENSE_6)
|
||
|
sequence->type = SATI_SEQUENCE_MODE_SENSE_6_CACHING;
|
||
|
else
|
||
|
sequence->type = SATI_SEQUENCE_MODE_SENSE_10_CACHING;
|
||
|
break;
|
||
|
|
||
|
case SCSI_MODE_PAGE_ALL_PAGES:
|
||
|
if (sati_get_cdb_byte(cdb, 0) == SCSI_MODE_SENSE_6)
|
||
|
sequence->type = SATI_SEQUENCE_MODE_SENSE_6_ALL_PAGES;
|
||
|
else
|
||
|
sequence->type = SATI_SEQUENCE_MODE_SENSE_10_ALL_PAGES;
|
||
|
break;
|
||
|
|
||
|
case SCSI_MODE_PAGE_READ_WRITE_ERROR:
|
||
|
if (sati_get_cdb_byte(cdb, 0) == SCSI_MODE_SENSE_6)
|
||
|
sequence->type = SATI_SEQUENCE_MODE_SENSE_6_READ_WRITE_ERROR;
|
||
|
else
|
||
|
sequence->type = SATI_SEQUENCE_MODE_SENSE_10_READ_WRITE_ERROR;
|
||
|
break;
|
||
|
|
||
|
case SCSI_MODE_PAGE_DISCONNECT_RECONNECT:
|
||
|
if (sati_get_cdb_byte(cdb, 0) == SCSI_MODE_SENSE_6)
|
||
|
sequence->type = SATI_SEQUENCE_MODE_SENSE_6_DISCONNECT_RECONNECT;
|
||
|
else
|
||
|
sequence->type = SATI_SEQUENCE_MODE_SENSE_10_DISCONNECT_RECONNECT;
|
||
|
break;
|
||
|
|
||
|
case SCSI_MODE_PAGE_CONTROL:
|
||
|
if (sati_get_cdb_byte(cdb, 0) == SCSI_MODE_SENSE_6)
|
||
|
sequence->type = SATI_SEQUENCE_MODE_SENSE_6_CONTROL;
|
||
|
else
|
||
|
sequence->type = SATI_SEQUENCE_MODE_SENSE_10_CONTROL;
|
||
|
break;
|
||
|
|
||
|
case SCSI_MODE_PAGE_POWER_CONDITION:
|
||
|
if (sati_get_cdb_byte(cdb, 0) == SCSI_MODE_SENSE_6)
|
||
|
sequence->type = SATI_SEQUENCE_MODE_SENSE_6_POWER_CONDITION;
|
||
|
else
|
||
|
sequence->type = SATI_SEQUENCE_MODE_SENSE_10_POWER_CONDITION;
|
||
|
break;
|
||
|
|
||
|
case SCSI_MODE_PAGE_INFORMATIONAL_EXCP_CONTROL:
|
||
|
// The informational exceptions control page is only useful
|
||
|
// if SMART is supported.
|
||
|
if ((sequence->device->capabilities | SATI_DEVICE_CAP_SMART_SUPPORT)
|
||
|
== 0)
|
||
|
{
|
||
|
// For a MODE SENSE, utilize INVALID FIELD IN CDB,
|
||
|
// For a MODE SELECT, utilize INVALID FIELD IN PARAMETER LIST.
|
||
|
if (sati_get_cdb_byte(cdb, 0) == SCSI_MODE_SENSE_6)
|
||
|
{
|
||
|
sati_scsi_sense_data_construct(
|
||
|
sequence,
|
||
|
scsi_io,
|
||
|
SCSI_STATUS_CHECK_CONDITION,
|
||
|
SCSI_SENSE_ILLEGAL_REQUEST,
|
||
|
SCSI_ASC_INVALID_FIELD_IN_CDB,
|
||
|
SCSI_ASCQ_INVALID_FIELD_IN_CDB
|
||
|
);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
sati_scsi_sense_data_construct(
|
||
|
sequence,
|
||
|
scsi_io,
|
||
|
SCSI_STATUS_CHECK_CONDITION,
|
||
|
SCSI_SENSE_ILLEGAL_REQUEST,
|
||
|
SCSI_ASC_INVALID_FIELD_IN_PARM_LIST,
|
||
|
SCSI_ASCQ_INVALID_FIELD_IN_PARM_LIST
|
||
|
);
|
||
|
}
|
||
|
|
||
|
return SATI_FAILURE_CHECK_RESPONSE_DATA;
|
||
|
}
|
||
|
|
||
|
if (sati_get_cdb_byte(cdb, 0) == SCSI_MODE_SENSE_6)
|
||
|
sequence->type = SATI_SEQUENCE_MODE_SENSE_6_INFORMATIONAL_EXCP_CONTROL;
|
||
|
else
|
||
|
sequence->type = SATI_SEQUENCE_MODE_SENSE_10_INFORMATIONAL_EXCP_CONTROL;
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
sati_scsi_sense_data_construct(
|
||
|
sequence,
|
||
|
scsi_io,
|
||
|
SCSI_STATUS_CHECK_CONDITION,
|
||
|
SCSI_SENSE_ILLEGAL_REQUEST,
|
||
|
SCSI_ASC_INVALID_FIELD_IN_CDB,
|
||
|
SCSI_ASCQ_INVALID_FIELD_IN_CDB
|
||
|
);
|
||
|
return SATI_FAILURE_CHECK_RESPONSE_DATA;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
return SATI_SUCCESS;
|
||
|
}
|
||
|
|
||
|
//******************************************************************************
|
||
|
//* P R O T E C T E D M E T H O D S
|
||
|
//******************************************************************************
|
||
|
|
||
|
/**
|
||
|
* @brief This method will calculate the size of the mode sense data header.
|
||
|
* This includes the block descriptor if one is requested.
|
||
|
*
|
||
|
* @param[in] scsi_io This parameter specifies the user's SCSI IO object
|
||
|
* for which to calculate the mode page header.
|
||
|
* @param[in] cdb_size This parameter specifies the number of bytes
|
||
|
* associated with the CDB for which to calculate the header.
|
||
|
*
|
||
|
* @return This method returns the size, in bytes, for the mode page header.
|
||
|
*/
|
||
|
U16 sati_mode_sense_calculate_page_header(
|
||
|
void * scsi_io,
|
||
|
U8 cdb_size
|
||
|
)
|
||
|
{
|
||
|
U8 * cdb = sati_cb_get_cdb_address(scsi_io);
|
||
|
U16 page_length = 0;
|
||
|
|
||
|
// The Mode page header length is different for 6-byte vs. 10-byte CDBs.
|
||
|
if (cdb_size == 6)
|
||
|
page_length += SCSI_MODE_SENSE_6_HEADER_LENGTH;
|
||
|
else
|
||
|
page_length += SCSI_MODE_SENSE_10_HEADER_LENGTH;
|
||
|
|
||
|
// Are block descriptors disabled (DBD)? 0 indicates they are enabled.
|
||
|
if ((sati_get_cdb_byte(cdb, 1) & SCSI_MODE_SENSE_DBD_ENABLE) == 0)
|
||
|
{
|
||
|
// The LLBAA bit is not defined for 6-byte mode sense requests.
|
||
|
if ( (cdb_size == 10)
|
||
|
&& (sati_get_cdb_byte(cdb, 1) & SCSI_MODE_SENSE_LLBAA_ENABLE) )
|
||
|
page_length += SCSI_MODE_SENSE_LLBA_BLOCK_DESCRIPTOR_LENGTH;
|
||
|
else
|
||
|
page_length += SCSI_MODE_SENSE_STD_BLOCK_DESCRIPTOR_LENGTH;
|
||
|
}
|
||
|
|
||
|
return page_length;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @brief This method performs command translation common to all mode sense
|
||
|
* requests (6 or 10 byte).
|
||
|
* For more information on the parameters passed to this method,
|
||
|
* please reference sati_translate_command().
|
||
|
*
|
||
|
* @param[in] cdb_length This parameter specifies the number of bytes
|
||
|
* in the CDB (6 or 10).
|
||
|
*
|
||
|
* @return This method returns an indication as to whether the translation
|
||
|
* succeeded.
|
||
|
* @retval SCI_SUCCESS This value is returned if translation succeeded.
|
||
|
* @see sati_mode_sense_is_page_control_supported() or
|
||
|
* sati_mode_sense_is_page_code_supported() for more information.
|
||
|
*/
|
||
|
SATI_STATUS sati_mode_sense_translate_command(
|
||
|
SATI_TRANSLATOR_SEQUENCE_T * sequence,
|
||
|
void * scsi_io,
|
||
|
void * ata_io,
|
||
|
U8 cdb_length
|
||
|
)
|
||
|
{
|
||
|
SATI_STATUS status;
|
||
|
|
||
|
/**
|
||
|
* Validate that the supplied page control (PC) field is supported.
|
||
|
*/
|
||
|
status = sati_mode_sense_is_page_control_supported(sequence, scsi_io);
|
||
|
if (status != SATI_SUCCESS)
|
||
|
return status;
|
||
|
|
||
|
/**
|
||
|
* Validate that the supplied page code is supported.
|
||
|
*/
|
||
|
status = sati_mode_sense_is_page_code_supported(sequence,scsi_io,cdb_length);
|
||
|
if (status != SATI_SUCCESS)
|
||
|
return status;
|
||
|
|
||
|
sati_ata_identify_device_construct(ata_io, sequence);
|
||
|
|
||
|
return SATI_SUCCESS;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @brief This method will build the standard block descriptor for a MODE
|
||
|
* SENSE 6 or 10 byte request.
|
||
|
* For more information on the parameters passed to this method,
|
||
|
* please reference sati_translate_command().
|
||
|
*
|
||
|
* @param[in] identify This parameter specifies the IDENTIFY DEVICE data
|
||
|
* associated with the SCSI IO.
|
||
|
* @param[in] offset This parameter specifies the offset into the data
|
||
|
* buffer at which to build the block descriptor.
|
||
|
*
|
||
|
* @return This method returns the size of the block descriptor built.
|
||
|
*/
|
||
|
U32 sati_mode_sense_build_std_block_descriptor(
|
||
|
SATI_TRANSLATOR_SEQUENCE_T * sequence,
|
||
|
void * scsi_io,
|
||
|
ATA_IDENTIFY_DEVICE_DATA_T * identify,
|
||
|
U32 offset
|
||
|
)
|
||
|
{
|
||
|
U32 lba_low = 0;
|
||
|
U32 lba_high = 0;
|
||
|
U32 sector_size = 0;
|
||
|
|
||
|
// Extract the sector information (sector size, logical blocks) from
|
||
|
// the retrieved ATA identify device data.
|
||
|
sati_ata_identify_device_get_sector_info(
|
||
|
identify, &lba_high, &lba_low, §or_size
|
||
|
);
|
||
|
|
||
|
// Fill in the 4-byte logical block address field.
|
||
|
sati_set_data_byte(sequence, scsi_io, offset, (U8)((lba_low>>24) & 0xFF));
|
||
|
sati_set_data_byte(sequence, scsi_io, offset+1, (U8)((lba_low>>16) & 0xFF));
|
||
|
sati_set_data_byte(sequence, scsi_io, offset+2, (U8)((lba_low>>8) & 0xFF));
|
||
|
sati_set_data_byte(sequence, scsi_io, offset+3, (U8)(lba_low & 0xFF));
|
||
|
|
||
|
// Clear the reserved field.
|
||
|
sati_set_data_byte(sequence, scsi_io, offset+4, 0);
|
||
|
|
||
|
// Fill in the three byte Block Length field
|
||
|
sati_set_data_byte(sequence,scsi_io, offset+5, (U8)((sector_size>>16) & 0xFF));
|
||
|
sati_set_data_byte(sequence,scsi_io, offset+6, (U8)((sector_size>>8) & 0xFF));
|
||
|
sati_set_data_byte(sequence,scsi_io, offset+7, (U8)(sector_size & 0xFF));
|
||
|
|
||
|
return SCSI_MODE_SENSE_STD_BLOCK_DESCRIPTOR_LENGTH;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @brief This method simply copies the mode sense data into the buffer
|
||
|
* at the location specified by page_start. The buffer copied is
|
||
|
* determined by page_control (e.g. current, default, or changeable
|
||
|
* values).
|
||
|
* For more information on the parameters passed to this method,
|
||
|
* please reference sati_translate_command().
|
||
|
*
|
||
|
* @param[in] page_start This parameter specifies the starting offset at
|
||
|
* which to copy the mode page data.
|
||
|
* @param[in] page_control This parameter specifies the page control
|
||
|
* indicating the source buffer to be copied.
|
||
|
* @param[in] page_code This specifies the mode sense page to copy.
|
||
|
*
|
||
|
* @return This method returns the size of the mode page data being copied.
|
||
|
*/
|
||
|
U32 sati_mode_sense_copy_initial_data(
|
||
|
SATI_TRANSLATOR_SEQUENCE_T * sequence,
|
||
|
void * scsi_io,
|
||
|
U32 page_start,
|
||
|
U8 page_control,
|
||
|
U8 page_code
|
||
|
)
|
||
|
{
|
||
|
U16 page_index = sati_mode_page_get_page_index(page_code);
|
||
|
U32 page_length = sat_mode_page_sizes[page_index];
|
||
|
|
||
|
// Find out if the current values are requested or if the default
|
||
|
// values are being requested.
|
||
|
if (page_control == SCSI_MODE_SENSE_PC_CHANGEABLE)
|
||
|
{
|
||
|
// Copy the changeable mode page information.
|
||
|
sati_copy_data(
|
||
|
sequence,
|
||
|
scsi_io,
|
||
|
page_start,
|
||
|
sat_changeable_mode_pages[page_index],
|
||
|
page_length
|
||
|
);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// Copy the default static values template to the user data area.
|
||
|
sati_copy_data(
|
||
|
sequence,
|
||
|
scsi_io,
|
||
|
page_start,
|
||
|
sat_default_mode_pages[page_index],
|
||
|
page_length
|
||
|
);
|
||
|
}
|
||
|
|
||
|
return page_length;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @brief This method performs the read/write error recovery mode page
|
||
|
* specific data translation based upon the contents of the remote
|
||
|
* device IDENTIFY DEVICE data.
|
||
|
* For more information on the parameters passed to this method,
|
||
|
* please reference sati_translate_command().
|
||
|
*
|
||
|
* @param[in] identify This parameter specifies the remote device's
|
||
|
* IDENTIFY DEVICE data received as part of the IO request.
|
||
|
* @param[in] offset This parameter specifies the offset into the data
|
||
|
* buffer where the translated data is to be written.
|
||
|
*
|
||
|
* @return This method returns the size of the mode page data that was
|
||
|
* translated.
|
||
|
*/
|
||
|
U32 sati_mode_sense_read_write_error_translate_data(
|
||
|
SATI_TRANSLATOR_SEQUENCE_T * sequence,
|
||
|
void * scsi_io,
|
||
|
ATA_IDENTIFY_DEVICE_DATA_T * identify,
|
||
|
U32 offset
|
||
|
)
|
||
|
{
|
||
|
U8 * cdb = sati_cb_get_cdb_address(scsi_io);
|
||
|
U8 page_control = sati_get_cdb_byte(cdb, 2) >> SCSI_MODE_SENSE_PC_SHIFT;
|
||
|
U32 page_length;
|
||
|
|
||
|
page_length = sati_mode_sense_copy_initial_data(
|
||
|
sequence,
|
||
|
scsi_io,
|
||
|
offset,
|
||
|
page_control,
|
||
|
SCSI_MODE_PAGE_READ_WRITE_ERROR
|
||
|
);
|
||
|
|
||
|
// Currently we do not override any bits in this mode page from the
|
||
|
// identify data.
|
||
|
|
||
|
return page_length;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @brief This method performs the disconnect/reconnect mode page
|
||
|
* specific data translation based upon the contents of the remote
|
||
|
* device IDENTIFY DEVICE data.
|
||
|
* For more information on the parameters passed to this method,
|
||
|
* please reference sati_translate_command().
|
||
|
*
|
||
|
* @param[in] identify This parameter specifies the remote device's
|
||
|
* IDENTIFY DEVICE data received as part of the IO request.
|
||
|
* @param[in] offset This parameter specifies the offset into the data
|
||
|
* buffer where the translated data is to be written.
|
||
|
*
|
||
|
* @return This method returns the size of the mode page data that was
|
||
|
* translated.
|
||
|
*/
|
||
|
U32 sati_mode_sense_disconnect_reconnect_translate_data(
|
||
|
SATI_TRANSLATOR_SEQUENCE_T * sequence,
|
||
|
void * scsi_io,
|
||
|
ATA_IDENTIFY_DEVICE_DATA_T * identify,
|
||
|
U32 offset
|
||
|
)
|
||
|
{
|
||
|
U8 * cdb = sati_cb_get_cdb_address(scsi_io);
|
||
|
U8 page_control = sati_get_cdb_byte(cdb, 2) >> SCSI_MODE_SENSE_PC_SHIFT;
|
||
|
U32 page_length;
|
||
|
|
||
|
page_length = sati_mode_sense_copy_initial_data(
|
||
|
sequence,
|
||
|
scsi_io,
|
||
|
offset,
|
||
|
page_control,
|
||
|
SCSI_MODE_PAGE_DISCONNECT_RECONNECT
|
||
|
);
|
||
|
|
||
|
// Currently we do not override any bits in this mode page from the
|
||
|
// identify data.
|
||
|
|
||
|
return page_length;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @brief This method performs the caching mode page specific data
|
||
|
* translation based upon the contents of the remote device IDENTIFY
|
||
|
* DEVICE data.
|
||
|
* For more information on the parameters passed to this method,
|
||
|
* please reference sati_translate_command().
|
||
|
*
|
||
|
* @param[in] identify This parameter specifies the remote device's
|
||
|
* IDENTIFY DEVICE data received as part of the IO request.
|
||
|
* @param[in] offset This parameter specifies the offset into the data
|
||
|
* buffer where the translated data is to be written.
|
||
|
*
|
||
|
* @return This method returns the size of the mode page data that was
|
||
|
* translated.
|
||
|
*/
|
||
|
U32 sati_mode_sense_caching_translate_data(
|
||
|
SATI_TRANSLATOR_SEQUENCE_T * sequence,
|
||
|
void * scsi_io,
|
||
|
ATA_IDENTIFY_DEVICE_DATA_T * identify,
|
||
|
U32 offset
|
||
|
)
|
||
|
{
|
||
|
U8 * cdb = sati_cb_get_cdb_address(scsi_io);
|
||
|
U8 page_control = sati_get_cdb_byte(cdb, 2) >> SCSI_MODE_SENSE_PC_SHIFT;
|
||
|
U32 page_length;
|
||
|
|
||
|
page_length = sati_mode_sense_copy_initial_data(
|
||
|
sequence,
|
||
|
scsi_io,
|
||
|
offset,
|
||
|
page_control,
|
||
|
SCSI_MODE_PAGE_CACHING
|
||
|
);
|
||
|
|
||
|
// If the request queried for the current values, then
|
||
|
// we need to translate the data from the IDENTIFY DEVICE request.
|
||
|
if (page_control == SCSI_MODE_SENSE_PC_CURRENT)
|
||
|
{
|
||
|
U8 value;
|
||
|
|
||
|
// Update the Write Cache Enabled (WCE) bit in the mode page data
|
||
|
// buffer based on the identify response.
|
||
|
if ((identify->command_set_enabled0 & ATA_IDENTIFY_DEVICE_WCE_ENABLE) != 0)
|
||
|
{
|
||
|
sati_get_data_byte(sequence, scsi_io, offset+2, &value);
|
||
|
value |= SCSI_MODE_PAGE_CACHE_PAGE_WCE_BIT;
|
||
|
sati_set_data_byte(sequence, scsi_io, offset+2, value);
|
||
|
//This byte has been set twice and needs to be decremented
|
||
|
sequence->number_data_bytes_set--;
|
||
|
}
|
||
|
|
||
|
// Update the Disable Read Ahead (DRA) bit in the mode page data
|
||
|
// buffer based on the identify response.
|
||
|
if ((identify->command_set_enabled0 & ATA_IDENTIFY_DEVICE_RA_ENABLE) == 0)
|
||
|
{
|
||
|
// In SATA the polarity of the bits is inverse.
|
||
|
// - SCSI = Disable Read Ahead
|
||
|
// - ATA = Read Ahead
|
||
|
sati_get_data_byte(sequence, scsi_io, offset+12, &value);
|
||
|
value |= SCSI_MODE_PAGE_CACHE_PAGE_DRA_BIT;
|
||
|
sati_set_data_byte(sequence, scsi_io, offset+12, value);
|
||
|
|
||
|
//This byte has been set twice, the first time in
|
||
|
//sati_mode_sense_copy_initial_data. number_data_bytes_set
|
||
|
//needs to be decremented
|
||
|
sequence->number_data_bytes_set--;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return page_length;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @brief This method performs the control mode page specific data
|
||
|
* translation based upon the contents of the remote device
|
||
|
* IDENTIFY DEVICE data.
|
||
|
* For more information on the parameters passed to this method,
|
||
|
* please reference sati_translate_command().
|
||
|
*
|
||
|
* @param[in] identify This parameter specifies the remote device's
|
||
|
* IDENTIFY DEVICE data received as part of the IO request.
|
||
|
* @param[in] offset This parameter specifies the offset into the data
|
||
|
* buffer where the translated data is to be written.
|
||
|
*
|
||
|
* @return This method returns the size of the mode page data that was
|
||
|
* translated.
|
||
|
*/
|
||
|
U32 sati_mode_sense_control_translate_data(
|
||
|
SATI_TRANSLATOR_SEQUENCE_T * sequence,
|
||
|
void * scsi_io,
|
||
|
ATA_IDENTIFY_DEVICE_DATA_T * identify,
|
||
|
U32 offset
|
||
|
)
|
||
|
{
|
||
|
U8 * cdb = sati_cb_get_cdb_address(scsi_io);
|
||
|
U8 page_control = sati_get_cdb_byte(cdb, 2) >> SCSI_MODE_SENSE_PC_SHIFT;
|
||
|
U32 page_length;
|
||
|
U8 value;
|
||
|
|
||
|
page_length = sati_mode_sense_copy_initial_data(
|
||
|
sequence,
|
||
|
scsi_io,
|
||
|
offset,
|
||
|
page_control,
|
||
|
SCSI_MODE_PAGE_CONTROL
|
||
|
);
|
||
|
|
||
|
if (sequence->device->descriptor_sense_enable)
|
||
|
{
|
||
|
sati_get_data_byte(sequence, scsi_io, offset+2,
|
||
|
&value);
|
||
|
|
||
|
sati_set_data_byte(sequence, scsi_io, offset+2,
|
||
|
value | SCSI_MODE_SELECT_MODE_PAGE_D_SENSE);
|
||
|
}
|
||
|
|
||
|
return page_length;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @brief This method performs the informational exceptions control mode
|
||
|
* page specific data translation based upon the contents of the
|
||
|
* remote device IDENTIFY DEVICE data.
|
||
|
* For more information on the parameters passed to this method,
|
||
|
* please reference sati_translate_command().
|
||
|
*
|
||
|
* @param[in] identify This parameter specifies the remote device's
|
||
|
* IDENTIFY DEVICE data received as part of the IO request.
|
||
|
* @param[in] offset This parameter specifies the offset into the data
|
||
|
* buffer where the translated data is to be written.
|
||
|
*
|
||
|
* @return This method returns the size of the mode page data that was
|
||
|
* translated.
|
||
|
*/
|
||
|
U32 sati_mode_sense_informational_excp_control_translate_data(
|
||
|
SATI_TRANSLATOR_SEQUENCE_T * sequence,
|
||
|
void * scsi_io,
|
||
|
ATA_IDENTIFY_DEVICE_DATA_T * identify,
|
||
|
U32 offset
|
||
|
)
|
||
|
{
|
||
|
U8 * cdb = sati_cb_get_cdb_address(scsi_io);
|
||
|
U8 page_control = sati_get_cdb_byte(cdb, 2) >> SCSI_MODE_SENSE_PC_SHIFT;
|
||
|
U32 page_length;
|
||
|
|
||
|
page_length = sati_mode_sense_copy_initial_data(
|
||
|
sequence,
|
||
|
scsi_io,
|
||
|
offset,
|
||
|
page_control,
|
||
|
SCSI_MODE_PAGE_INFORMATIONAL_EXCP_CONTROL
|
||
|
);
|
||
|
|
||
|
// If the request queried for the current values, then
|
||
|
// we need to translate the data from the IDENTIFY DEVICE request.
|
||
|
if (page_control == SCSI_MODE_SENSE_PC_CURRENT)
|
||
|
{
|
||
|
U8 value;
|
||
|
|
||
|
sati_get_data_byte(sequence, scsi_io, offset+2, &value);
|
||
|
|
||
|
// Determine if the SMART feature set is supported and enabled.
|
||
|
if ( (identify->command_set_supported0
|
||
|
& ATA_IDENTIFY_COMMAND_SET_SUPPORTED0_SMART_ENABLE)
|
||
|
&& (identify->command_set_enabled0
|
||
|
& ATA_IDENTIFY_COMMAND_SET_ENABLED0_SMART_ENABLE) )
|
||
|
{
|
||
|
// Clear the DXCPT field since the SMART feature is supported/enabled.
|
||
|
value &= ~SCSI_MODE_PAGE_INFORMATIONAL_EXCP_DXCPT_ENABLE;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// Set the Disable Exception Control (DXCPT) field since the SMART
|
||
|
// feature is not supported or enabled.
|
||
|
value |= SCSI_MODE_PAGE_INFORMATIONAL_EXCP_DXCPT_ENABLE;
|
||
|
}
|
||
|
|
||
|
sati_set_data_byte(sequence, scsi_io, offset+2, value);
|
||
|
|
||
|
//This byte has been set twice, the first time in
|
||
|
//sati_mode_sense_copy_initial_data. number_data_bytes_set
|
||
|
//needs to be decremented
|
||
|
sequence->number_data_bytes_set--;
|
||
|
}
|
||
|
|
||
|
return page_length;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @brief This method performs the Power Condition mode page
|
||
|
* specific data translation based upon the contents of the
|
||
|
* remote device IDENTIFY DEVICE data.
|
||
|
* For more information on the parameters passed to this method,
|
||
|
* please reference sati_translate_command().
|
||
|
*
|
||
|
* @param[in] identify This parameter specifies the remote device's
|
||
|
* IDENTIFY DEVICE data received as part of the IO request.
|
||
|
* @param[in] offset This parameter specifies the offset into the data
|
||
|
* buffer where the translated data is to be written.
|
||
|
*
|
||
|
* @return This method returns the size of the mode page data that was
|
||
|
* translated.
|
||
|
*/
|
||
|
U32 sati_mode_sense_power_condition_translate_data(
|
||
|
SATI_TRANSLATOR_SEQUENCE_T * sequence,
|
||
|
void * scsi_io,
|
||
|
ATA_IDENTIFY_DEVICE_DATA_T * identify,
|
||
|
U32 offset
|
||
|
)
|
||
|
{
|
||
|
U8 * cdb = sati_cb_get_cdb_address(scsi_io);
|
||
|
U8 page_control = sati_get_cdb_byte(cdb, 2) >> SCSI_MODE_SENSE_PC_SHIFT;
|
||
|
|
||
|
U8 ata_sb_timer;
|
||
|
|
||
|
//Represents tenths of seconds
|
||
|
U32 standby_timer = 0x00000000;
|
||
|
|
||
|
U8 standby_enabled = STANDBY_TIMER_DISABLED;
|
||
|
|
||
|
if ((page_control == SCSI_MODE_SENSE_PC_CURRENT) &&
|
||
|
(identify->capabilities1 & STANDBY_TIMER_SUPPORTED))
|
||
|
{
|
||
|
standby_enabled = STANDBY_TIMER_ENABLED;
|
||
|
|
||
|
ata_sb_timer = sequence->device->ata_standby_timer;
|
||
|
|
||
|
//converting ATA timer values into SCSI timer values
|
||
|
if(ata_sb_timer <= 0xF0)
|
||
|
{
|
||
|
standby_timer = ata_sb_timer * 50;
|
||
|
}
|
||
|
else if(ata_sb_timer <= 0xFB)
|
||
|
{
|
||
|
standby_timer = ((ata_sb_timer - 240) * 18000);
|
||
|
}
|
||
|
else if(ata_sb_timer == 0xFC)
|
||
|
{
|
||
|
standby_timer = 12600;
|
||
|
}
|
||
|
else if(ata_sb_timer == 0xFD)
|
||
|
{
|
||
|
standby_timer = 432000;
|
||
|
}
|
||
|
else if(ata_sb_timer == 0xFF)
|
||
|
{
|
||
|
standby_timer = 12750;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
standby_timer = 0xFFFFFFFF;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
sati_set_data_byte(sequence, scsi_io, offset, SCSI_MODE_PAGE_POWER_CONDITION);
|
||
|
sati_set_data_byte(sequence, scsi_io, offset + 1, (SCSI_MODE_PAGE_1A_LENGTH - 2));
|
||
|
sati_set_data_byte(sequence, scsi_io, offset + 2, 0x00);
|
||
|
sati_set_data_byte(sequence, scsi_io, offset + 3, standby_enabled);
|
||
|
sati_set_data_byte(sequence, scsi_io, offset + 4, 0x00);
|
||
|
sati_set_data_byte(sequence, scsi_io, offset + 5, 0x00);
|
||
|
sati_set_data_byte(sequence, scsi_io, offset + 6, 0x00);
|
||
|
sati_set_data_byte(sequence, scsi_io, offset + 7, 0x00);
|
||
|
sati_set_data_byte(sequence, scsi_io, offset + 8, (U8) (standby_timer >> 24));
|
||
|
sati_set_data_byte(sequence, scsi_io, offset + 9, (U8) (standby_timer >> 16));
|
||
|
sati_set_data_byte(sequence, scsi_io, offset + 10, (U8) (standby_timer >> 8));
|
||
|
sati_set_data_byte(sequence, scsi_io, offset + 11, (U8) standby_timer);
|
||
|
|
||
|
return SCSI_MODE_PAGE_1A_LENGTH;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @brief This method performs the all pages mode page specific data
|
||
|
* translation based upon the contents of the remote device
|
||
|
* IDENTIFY DEVICE data. The ALL PAGES mode sense request asks
|
||
|
* for all of mode pages and sub-pages in a single page.
|
||
|
* The mode pages are added in ascending order.
|
||
|
* For more information on the parameters passed to this method,
|
||
|
* please reference sati_translate_command().
|
||
|
*
|
||
|
* @param[in] identify This parameter specifies the remote device's
|
||
|
* IDENTIFY DEVICE data received as part of the IO request.
|
||
|
* @param[in] offset This parameter specifies the offset into the data
|
||
|
* buffer where the translated data is to be written.
|
||
|
*
|
||
|
* @return This method returns the size of the mode page data that was
|
||
|
* translated.
|
||
|
*/
|
||
|
U32 sati_mode_sense_all_pages_translate_data(
|
||
|
SATI_TRANSLATOR_SEQUENCE_T * sequence,
|
||
|
void * scsi_io,
|
||
|
ATA_IDENTIFY_DEVICE_DATA_T * identify,
|
||
|
U32 offset
|
||
|
)
|
||
|
{
|
||
|
offset += sati_mode_sense_read_write_error_translate_data(
|
||
|
sequence, scsi_io, identify, offset
|
||
|
);
|
||
|
|
||
|
offset += sati_mode_sense_disconnect_reconnect_translate_data(
|
||
|
sequence, scsi_io, identify, offset
|
||
|
);
|
||
|
|
||
|
offset += sati_mode_sense_caching_translate_data(
|
||
|
sequence, scsi_io, identify, offset
|
||
|
);
|
||
|
|
||
|
offset += sati_mode_sense_control_translate_data(
|
||
|
sequence, scsi_io, identify, offset
|
||
|
);
|
||
|
|
||
|
offset += sati_mode_sense_informational_excp_control_translate_data(
|
||
|
sequence, scsi_io, identify, offset
|
||
|
);
|
||
|
|
||
|
return offset;
|
||
|
}
|
||
|
|
||
|
#endif // !defined(DISABLE_SATI_MODE_SENSE)
|
||
|
|