/*- * 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 /** * @file * @brief This file contains all of the method implementations that * provide generic support for SATI. Some methods can be utilized * by a user to construct ATA/ATAPI commands, copy ATA device * structure data, fill in sense data, etc. */ #include #include #include #include #include #include /** * @brief This method will set the data direction, protocol, and transfer * kength for an ATA non-data command. * * @pre It is expected that the user will use this method for setting these * values in a non-data ATA command constuct. * * @param[out] ata_io This parameter specifies the ATA IO request structure * for which to build the IDENTIFY DEVICE command. * @param[in] sequence This parameter specifies the translator sequence * for which the command is being constructed. * * @return none. */ void sati_ata_non_data_command( void * ata_io, SATI_TRANSLATOR_SEQUENCE_T * sequence ) { sequence->data_direction = SATI_DATA_DIRECTION_NONE; sequence->protocol = SAT_PROTOCOL_NON_DATA; sequence->ata_transfer_length = 0; } /** * @brief This method will construct the ATA identify device command. * * @pre It is expected that the user has properly set the current contents * of the register FIS to 0. * * @param[out] ata_io This parameter specifies the ATA IO request structure * for which to build the IDENTIFY DEVICE command. * @param[in] sequence This parameter specifies the translator sequence * for which the command is being constructed. * * @return none. */ void sati_ata_identify_device_construct( void * ata_io, SATI_TRANSLATOR_SEQUENCE_T * sequence ) { U8 * register_fis = sati_cb_get_h2d_register_fis_address(ata_io); sati_set_ata_command(register_fis, ATA_IDENTIFY_DEVICE); sequence->data_direction = SATI_DATA_DIRECTION_IN; sequence->protocol = SAT_PROTOCOL_PIO_DATA_IN; sequence->ata_transfer_length = sizeof(ATA_IDENTIFY_DEVICE_DATA_T); } /** * @brief This method will construct the ATA Execute Device Diagnostic command. * * @param[out] ata_io This parameter specifies the ATA IO request structure * for which to build the IDENTIFY DEVICE command. * @param[in] sequence This parameter specifies the translator sequence * for which the command is being constructed. * * @return none. */ void sati_ata_execute_device_diagnostic_construct( void * ata_io, SATI_TRANSLATOR_SEQUENCE_T * sequence ) { U8 * register_fis = sati_cb_get_h2d_register_fis_address(ata_io); sati_set_ata_command(register_fis, ATA_EXECUTE_DEVICE_DIAG); sequence->data_direction = SATI_DATA_DIRECTION_IN; sequence->protocol = SAT_PROTOCOL_DEVICE_DIAGNOSTIC; sequence->ata_transfer_length = 16; } /** * @brief This method will set data bytes in the user data area. If the * caller requests it, the data written will be forced to ascii * printable characters if it isn't already a printable character. * A printable character is considered to be >= 0x20 and <= 0x70. * * @param[in] sequence This parameter specifies the translation sequence * for which to copy and swap the data. * @param[out] destination_scsi_io This parameter specifies the SCSI IO * request containing the destination buffer into which to copy. * @param[in] destination_offset This parameter specifies the offset into * the data buffer where the information will be copied to. * @param[in] source_value This parameter specifies the value retrieved * from the source buffer that is to be copied into the user * buffer area. * @param[in] use_printable_chars This parameter indicates if the copy should * ensure that the value copied is considered an ASCII printable * character (e.g. A, B, " ", etc.). These characters reside * in the 0x20 - 0x7E ASCII range. * * @return none */ static void sati_set_ascii_data_byte( SATI_TRANSLATOR_SEQUENCE_T * sequence, void * destination_scsi_io, U32 destination_offset, U8 source_value, BOOL use_printable_chars ) { // if the user requests that the copied data be ascii printable, then // default to " " (i.e. 0x20) for all non-ascii printable characters. if((use_printable_chars == TRUE) && ((source_value < 0x20) || (source_value > 0x7E))) { source_value = 0x20; } sati_set_data_byte( sequence, destination_scsi_io, destination_offset, source_value ); } /** * @brief This method performs a copy operation using an offset into the * source buffer, an offset into the destination buffer, and a length. * It will perform the byte swap from the 16-bit identify field * into the network byte order SCSI location. * * @param[in] sequence This parameter specifies the translation sequence * for which to copy and swap the data. * @param[out] destination_scsi_io This parameter specifies the SCSI IO * request containing the destination buffer into which to copy. * @param[in] destination_offset This parameter specifies the offset into * the data buffer where the information will be copied to. * @param[in] source_buffer This parameter specifies the source buffer from * which the data will be copied. * @param[in] source_offset This parameter specifies the offset into the * source buffer where the copy shall begin. * @param[in] length This parameter specifies the number of bytes to copy * during this operation. * @param[in] use_printable_chars This parameter indicates if the copy should * ensure that the value copied is considered an ASCII printable * character (e.g. A, B, " ", etc.). These characters reside * in the 0x20 - 0x7E ASCII range. * * @return none */ void sati_ata_identify_device_copy_data( SATI_TRANSLATOR_SEQUENCE_T * sequence, void * destination_scsi_io, U32 destination_offset, U8 * source_buffer, U32 source_offset, U32 length, BOOL use_printable_chars ) { source_buffer += source_offset; while (length > 0) { sati_set_ascii_data_byte( sequence, destination_scsi_io, destination_offset, *(source_buffer+1), use_printable_chars ); sati_set_ascii_data_byte( sequence, destination_scsi_io, destination_offset+1, *source_buffer, use_printable_chars ); destination_offset += 2; source_buffer += 2; length -= 2; } } /** * @brief This method performs a copy operation using a source buffer, * an offset into the destination buffer, and a length. * * @param[in] sequence This parameter specifies the translation sequence * for which to copy and swap the data. * @param[out] destination_scsi_io This parameter specifies the SCSI IO * request containing the destination buffer into which to copy. * @param[in] destination_offset This parameter specifies the offset into * the data buffer where the information will be copied to. * @param[in] source_buffer This parameter specifies the source buffer from * which the data will be copied. * @param[in] length This parameter specifies the number of bytes to copy * during this operation. * * @return none */ void sati_copy_data( SATI_TRANSLATOR_SEQUENCE_T * sequence, void * destination_scsi_io, U32 destination_offset, U8 * source_buffer, U32 length ) { while (length > 0) { sati_set_data_byte( sequence, destination_scsi_io, destination_offset, *source_buffer ); destination_offset++; source_buffer++; length--; } } /** * @brief This method extracts the Logical Block Address high and low 32-bit * values and the sector count 32-bit value from the ATA identify * device data. * * @param[in] identify This parameter specifies the ATA_IDENTIFY_DEVICE_DATA * from which to extract the sector information. * @param[out] lba_high This parameter specifies the upper 32 bits for the * number of logical block addresses for the device. The upper * 16-bits should always be 0, since 48-bits of LBA is the most * supported by an ATA device. * @param[out] lba_low This parameter specifies the lower 32 bits for the * number of logical block addresses for the device. * @param[out] sector_size This parameter specifies the 32-bits of sector * size. If the ATA device doesn't support reporting it's * sector size, then 512 bytes is utilized as the default value. * * @return none */ void sati_ata_identify_device_get_sector_info( ATA_IDENTIFY_DEVICE_DATA_T * identify, U32 * lba_high, U32 * lba_low, U32 * sector_size ) { // Calculate the values to be returned // Calculation will be different if the SATA device supports // 48-bit addressing. Bit 10 of Word 86 of ATA Identify if (identify->command_set_enabled1 & ATA_IDENTIFY_COMMAND_SET_SUPPORTED1_48BIT_ENABLE) { // This drive supports 48-bit addressing *lba_high = identify->max_48bit_lba[7] << 24; *lba_high |= identify->max_48bit_lba[6] << 16; *lba_high |= identify->max_48bit_lba[5] << 8; *lba_high |= identify->max_48bit_lba[4]; *lba_low = identify->max_48bit_lba[3] << 24; *lba_low |= identify->max_48bit_lba[2] << 16; *lba_low |= identify->max_48bit_lba[1] << 8; *lba_low |= identify->max_48bit_lba[0]; } else { // This device doesn't support 48-bit addressing // Pull out the largest LBA from words 60 and 61. *lba_high = 0; *lba_low = identify->total_num_sectors[3] << 24; *lba_low |= identify->total_num_sectors[2] << 16; *lba_low |= identify->total_num_sectors[1] << 8; *lba_low |= identify->total_num_sectors[0]; } // If the ATA device reports its sector size (bit 12 of Word 106), // then use that instead. if (identify->physical_logical_sector_info & ATA_IDENTIFY_SECTOR_LARGER_THEN_512_ENABLE) { *sector_size = identify->words_per_logical_sector[3] << 24; *sector_size |= identify->words_per_logical_sector[2] << 16; *sector_size |= identify->words_per_logical_sector[1] << 8; *sector_size |= identify->words_per_logical_sector[0]; } else { // Default the sector size to 512 bytes *sector_size = 512; } } /** * @brief This method will construct the ATA check power mode command. * * @pre It is expected that the user has properly set the current contents * of the register FIS to 0. * * @param[out] ata_io This parameter specifies the ATA IO request structure * for which to build the CHECK POWER MODE command. * @param[in] sequence This parameter specifies the translator sequence * for which the command is being constructed. * * @return none. */ void sati_ata_check_power_mode_construct( void * ata_io, SATI_TRANSLATOR_SEQUENCE_T * sequence ) { U8 * register_fis = sati_cb_get_h2d_register_fis_address(ata_io); sati_set_ata_command(register_fis, ATA_CHECK_POWER_MODE); sati_ata_non_data_command(ata_io, sequence); } /** * @brief This method is utilized to set a specific byte in the sense * data area. It will ensure that the supplied byte offset * isn't larger then the length of the requested sense data. * * @param[in] scsi_io This parameter specifies the user SCSI IO request * for which to set the sense data byte. * @param[in] byte_offset This parameter specifies the byte offset into * the sense data buffer where the data should be written. * @param[in] value This parameter specifies the 8-bit value to be written * into the sense data area. * * @return none */ void sati_set_sense_data_byte( U8 * sense_data, U32 max_sense_data_len, U32 byte_offset, U8 value ) { // Ensure that we don't attempt to write past the end of the sense // data buffer. if (byte_offset < max_sense_data_len) sense_data[byte_offset] = value; } /** * @brief This method will construct the common response IU in the user * request's response IU location. * * @param[out] rsp_iu This parameter specifies the user request's * response IU to be constructed. * @param[in] scsi_status This parameter specifies the SCSI status * value for the user's IO request. * @param[in] sense_data_length This parameter specifies the sense data * length for response IU. * @param[in] data_present The parameter specifies the specific * data present value for response IU. * * @return none */ void sati_scsi_common_response_iu_construct( SCI_SSP_RESPONSE_IU_T * rsp_iu, U8 scsi_status, U8 sense_data_length, U8 data_present ) { rsp_iu->sense_data_length[3] = sense_data_length; rsp_iu->sense_data_length[2] = 0; rsp_iu->sense_data_length[1] = 0; rsp_iu->sense_data_length[0] = 0; rsp_iu->status = scsi_status; rsp_iu->data_present = data_present; } /** * @brief This method will construct the buffer for sense data * sense data buffer location. Additionally, it will set the user's * SCSI status. * * @param[in,out] scsi_io This parameter specifies the user's IO request * for which to construct the buffer for sense data. * @param[in] scsi_status This parameter specifies the SCSI status * value for the user's IO request. * @param[out] sense_data This parameter * * @return none */ static void sati_scsi_get_sense_data_buffer( SATI_TRANSLATOR_SEQUENCE_T * sequence, void * scsi_io, U8 scsi_status, U8 ** sense_data, U32 * sense_len) { #ifdef SATI_TRANSPORT_SUPPORTS_SAS SCI_SSP_RESPONSE_IU_T * rsp_iu = (SCI_SSP_RESPONSE_IU_T*) sati_cb_get_response_iu_address(scsi_io); sati_scsi_common_response_iu_construct( rsp_iu, scsi_status, sati_scsi_get_sense_data_length(sequence, scsi_io), SCSI_RESPONSE_DATA_PRES_SENSE_DATA ); *sense_data = (U8*) rsp_iu->data; *sense_len = SSP_RESPONSE_IU_MAX_DATA * 4; // dwords to bytes #else *sense_data = sati_cb_get_sense_data_address(scsi_io); *sense_len = sati_cb_get_sense_data_length(scsi_io); sati_cb_set_scsi_status(scsi_io, scsi_status); #endif // SATI_TRANSPORT_SUPPORTS_SAS } /** * @brief This method extract response code based on on device settings. * * @return response code */ static U8 sati_scsi_get_sense_data_response_code(SATI_TRANSLATOR_SEQUENCE_T * sequence) { if (sequence->device->descriptor_sense_enable) { return SCSI_DESCRIPTOR_CURRENT_RESPONSE_CODE; } else { return SCSI_FIXED_CURRENT_RESPONSE_CODE; } } /** * @brief This method will return length of descriptor sense data for executed command. * * @return sense data length */ static U8 sati_scsi_get_descriptor_sense_data_length(SATI_TRANSLATOR_SEQUENCE_T * sequence, void * scsi_io) { U8 * cdb = sati_cb_get_cdb_address(scsi_io); //Initial value is descriptor header length U8 length = 8; switch (sati_get_cdb_byte(cdb, 0)) { #if !defined(DISABLE_SATI_WRITE_LONG) case SCSI_WRITE_LONG_10: case SCSI_WRITE_LONG_16: length += SCSI_BLOCK_DESCRIPTOR_LENGTH + SCSI_INFORMATION_DESCRIPTOR_LENGTH; break; #endif // !defined(DISABLE_SATI_WRITE_LONG) #if !defined(DISABLE_SATI_REASSIGN_BLOCKS) case SCSI_REASSIGN_BLOCKS: length += SCSI_CMD_SPECIFIC_DESCRIPTOR_LENGTH + SCSI_INFORMATION_DESCRIPTOR_LENGTH; break; #endif // !defined(DISABLE_SATI_REASSIGN_BLOCKS) case SCSI_READ_6: case SCSI_READ_10: case SCSI_READ_12: case SCSI_READ_16: case SCSI_WRITE_6: case SCSI_WRITE_10: case SCSI_WRITE_12: case SCSI_WRITE_16: #if !defined(DISABLE_SATI_VERIFY) case SCSI_VERIFY_10: case SCSI_VERIFY_12: case SCSI_VERIFY_16: #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: case SCSI_WRITE_AND_VERIFY_12: case SCSI_WRITE_AND_VERIFY_16: #endif // !defined(DISABLE_SATI_WRITE_AND_VERIFY) // && !defined(DISABLE_SATI_VERIFY) // && !defined(DISABLE_SATI_WRITE) length += SCSI_INFORMATION_DESCRIPTOR_LENGTH; break; } return length; } /** * @brief This method will return length of sense data. * * @return sense data length */ U8 sati_scsi_get_sense_data_length(SATI_TRANSLATOR_SEQUENCE_T * sequence, void * scsi_io) { U8 response_code; response_code = sati_scsi_get_sense_data_response_code(sequence); switch (response_code) { case SCSI_FIXED_CURRENT_RESPONSE_CODE: case SCSI_FIXED_DEFERRED_RESPONSE_CODE: return SCSI_FIXED_SENSE_DATA_BASE_LENGTH; break; case SCSI_DESCRIPTOR_CURRENT_RESPONSE_CODE: case SCSI_DESCRIPTOR_DEFERRED_RESPONSE_CODE: return sati_scsi_get_descriptor_sense_data_length(sequence, scsi_io); break; } return SCSI_FIXED_SENSE_DATA_BASE_LENGTH; } /** * @brief This method will construct the sense data buffer in the user's * sense data buffer location. Additionally, it will set the user's * SCSI status. * * @param[in] sequence This parameter specifies the translation sequence * for which to construct the sense data. * @param[in,out] scsi_io This parameter specifies the user's IO request * for which to construct the sense data. * @param[in] scsi_status This parameter specifies the SCSI status * value for the user's IO request. * @param[in] sense_key This parameter specifies the sense key to * be set for the user's IO request. * @param[in] additional_sense_code This parameter specifies the * additional sense code (ASC) key to be set for the user's * IO request. * @param[in] additional_sense_code_qualifier This parameter specifies * the additional sense code qualifier (ASCQ) key to be set * for the user's IO request. * * @return none */ void sati_scsi_sense_data_construct( SATI_TRANSLATOR_SEQUENCE_T * sequence, void * scsi_io, U8 scsi_status, U8 sense_key, U8 additional_sense_code, U8 additional_sense_code_qualifier ) { U8 response_code; response_code = sati_scsi_get_sense_data_response_code(sequence); switch (response_code) { case SCSI_FIXED_CURRENT_RESPONSE_CODE: case SCSI_FIXED_DEFERRED_RESPONSE_CODE: sati_scsi_fixed_sense_data_construct(sequence, scsi_io, scsi_status, response_code, sense_key, additional_sense_code, additional_sense_code_qualifier); break; case SCSI_DESCRIPTOR_CURRENT_RESPONSE_CODE: case SCSI_DESCRIPTOR_DEFERRED_RESPONSE_CODE: sati_scsi_descriptor_sense_data_construct(sequence, scsi_io, scsi_status, response_code, sense_key, additional_sense_code, additional_sense_code_qualifier); break; } sequence->is_sense_response_set = TRUE; } /** * @brief This method will construct the block descriptor in the user's descriptor * sense data buffer location. * * @param[in] sense_data This parameter specifies the user SCSI IO request * for which to set the sense data byte. * @param[in] sense_len This parameter specifies length of the sense data * to be returned by SATI. * @param[out] descriptor_len This parameter returns the length of constructed * descriptor. * * @return none */ static void sati_scsi_block_descriptor_construct( U8 * sense_data, U32 sense_len) { U8 ili = 1; sati_set_sense_data_byte(sense_data, sense_len, 0, SCSI_BLOCK_DESCRIPTOR_TYPE); sati_set_sense_data_byte(sense_data, sense_len, 1, SCSI_BLOCK_DESCRIPTOR_ADDITIONAL_LENGTH); sati_set_sense_data_byte(sense_data, sense_len, 2, 0); sati_set_sense_data_byte(sense_data, sense_len, 3, (ili << 5)); } /** * @brief This method will construct the command-specific descriptor for * the descriptor sense data buffer in the user's sense data buffer * location. * * @param[in] sense_data This parameter specifies the user SCSI IO request * for which to set the sense data byte. * @param[in] sense_len This parameter specifies length of the sense data * to be returned by SATI. * @param[out] descriptor_len This parameter returns the length of constructed * descriptor. * @param[in] information_buff This parameter specifies the address for which * to set the command-specific information buffer. * * @return none */ static void sati_scsi_command_specific_descriptor_construct( U8 * sense_data, U32 sense_len, U8 * information_buff) { U8 i; sati_set_sense_data_byte(sense_data, sense_len, 0, SCSI_CMD_SPECIFIC_DESCRIPTOR_TYPE); sati_set_sense_data_byte(sense_data, sense_len, 1, SCSI_CMD_SPECIFIC_DESCRIPTOR_ADDITIONAL_LENGTH); sati_set_sense_data_byte(sense_data, sense_len, 2, 0); sati_set_sense_data_byte(sense_data, sense_len, 3, 0); // fill information buffer // SBC 5.20.1 REASSIGN BLOCKS command overview // If information about the first LBA not reassigned is not available // COMMAND-SPECIFIC INFORMATION field shall be set to FFFF_FFFF_FFFF_FFFFh for (i=0; i<8; i++) sati_set_sense_data_byte(sense_data, sense_len, 4 + i, information_buff==NULL?0xFF:information_buff[i]); } /** * @brief This method will construct the information descriptor for * the descriptor sense data buffer in the user's sense data buffer * location. * * @param[in] sense_data This parameter specifies the user SCSI IO request * for which to set the sense data byte. * @param[in] sense_len This parameter specifies length of the sense data * to be returned by SATI. * @param[out] descriptor_len This parameter returns the length of constructed * descriptor. * @param[in] information_buff This parameter specifies the address for which * to set the information buffer. * * @return none */ static void sati_scsi_information_descriptor_construct( U8 * sense_data, U32 sense_len, U8 * information_buff) { U8 i; U8 valid = 1; sati_set_sense_data_byte(sense_data, sense_len, 0, SCSI_INFORMATION_DESCRIPTOR_TYPE); sati_set_sense_data_byte(sense_data, sense_len, 1, SCSI_INFORMATION_DESCRIPTOR_ADDITIONAL_LENGTH); sati_set_sense_data_byte(sense_data, sense_len, 2, (valid << 7)); sati_set_sense_data_byte(sense_data, sense_len, 3, 0); // fill information buffer for (i=0; i<8; i++) sati_set_sense_data_byte(sense_data, sense_len, 4 + i, information_buff==NULL?0:information_buff[i]); } /** * @brief This method will construct the descriptors in the user's descriptor * sense data buffer location. * * @param[in,out] scsi_io This parameter specifies the user's IO request * for which to construct the sense data. * @param[in] sense_data This parameter specifies the user SCSI IO request * for which to set the sense data byte. * @param[in] sense_len This parameter specifies length of the sense data * to be returned by SATI. * @param[out] descriptor_len This parameter returns the length of constructed * descriptor. * @param[in] information_buff This parameter specifies the address for which * to set the information buffer. * * @return none */ static void sati_scsi_common_descriptors_construct( void * scsi_io, U8 * sense_data, U32 sense_len, U8 * information_buff) { U8 * cdb = sati_cb_get_cdb_address(scsi_io); U8 offset = 0; switch (sati_get_cdb_byte(cdb, 0)) { #if !defined(DISABLE_SATI_WRITE_LONG) case SCSI_WRITE_LONG_10: case SCSI_WRITE_LONG_16: sati_scsi_block_descriptor_construct( sense_data + offset, sense_len - offset); offset += SCSI_BLOCK_DESCRIPTOR_LENGTH; sati_scsi_information_descriptor_construct( sense_data + offset, sense_len - offset, information_buff); offset += SCSI_INFORMATION_DESCRIPTOR_LENGTH; break; #endif // !defined(DISABLE_SATI_WRITE_LONG) #if !defined(DISABLE_SATI_REASSIGN_BLOCKS) case SCSI_REASSIGN_BLOCKS: sati_scsi_command_specific_descriptor_construct( sense_data + offset, sense_len - offset, NULL); offset += SCSI_CMD_SPECIFIC_DESCRIPTOR_LENGTH; sati_scsi_information_descriptor_construct( sense_data + offset, sense_len - offset, information_buff); offset += SCSI_INFORMATION_DESCRIPTOR_LENGTH; break; #endif // !defined(DISABLE_SATI_REASSIGN_BLOCKS) case SCSI_READ_6: case SCSI_READ_10: case SCSI_READ_12: case SCSI_READ_16: case SCSI_WRITE_6: case SCSI_WRITE_10: case SCSI_WRITE_12: case SCSI_WRITE_16: #if !defined(DISABLE_SATI_VERIFY) case SCSI_VERIFY_10: case SCSI_VERIFY_12: case SCSI_VERIFY_16: #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: case SCSI_WRITE_AND_VERIFY_12: case SCSI_WRITE_AND_VERIFY_16: #endif // !defined(DISABLE_SATI_WRITE_AND_VERIFY) // && !defined(DISABLE_SATI_VERIFY) // && !defined(DISABLE_SATI_WRITE) sati_scsi_information_descriptor_construct( sense_data + offset, sense_len - offset, information_buff); offset += SCSI_INFORMATION_DESCRIPTOR_LENGTH; break; } } /** * @brief This method will construct the descriptor sense data buffer in * the user's sense data buffer location. Additionally, it will set * the user's SCSI status. * * @param[in] sequence This parameter specifies the translation sequence * for which to construct the sense data. * @param[in,out] scsi_io This parameter specifies the user's IO request * for which to construct the sense data. * @param[in] scsi_status This parameter specifies the SCSI status * value for the user's IO request. * @param[in] sense_key This parameter specifies the sense key to * be set for the user's IO request. * @param[in] additional_sense_code This parameter specifies the * additional sense code (ASC) key to be set for the user's * IO request. * @param[in] additional_sense_code_qualifier This parameter specifies * the additional sense code qualifier (ASCQ) key to be set * for the user's IO request. * * @return none */ void sati_scsi_descriptor_sense_data_construct( SATI_TRANSLATOR_SEQUENCE_T * sequence, void * scsi_io, U8 scsi_status, U8 response_code, U8 sense_key, U8 additional_sense_code, U8 additional_sense_code_qualifier ) { U8 * sense_data; U32 sense_len; sati_scsi_get_sense_data_buffer(sequence, scsi_io, scsi_status, &sense_data, &sense_len); sati_set_sense_data_byte( sense_data, sense_len, 0, response_code ); sati_set_sense_data_byte(sense_data, sense_len, 1, sense_key); sati_set_sense_data_byte(sense_data, sense_len, 2, additional_sense_code); sati_set_sense_data_byte(sense_data, sense_len, 3, additional_sense_code_qualifier); sati_set_sense_data_byte(sense_data, sense_len, 4, 0); sati_set_sense_data_byte(sense_data, sense_len, 5, 0); sati_set_sense_data_byte(sense_data, sense_len, 6, 0); sati_scsi_common_descriptors_construct(scsi_io, sense_data + 8, sense_len, NULL); sati_set_sense_data_byte(sense_data, sense_len, 7, sati_scsi_get_descriptor_sense_data_length(sequence, scsi_io) - 8); } /** * @brief This method will construct the fixed format sense data buffer * in the user's sense data buffer location. Additionally, it will * set the user's SCSI status. * * @param[in] sequence This parameter specifies the translation sequence * for which to construct the sense data. * @param[in,out] scsi_io This parameter specifies the user's IO request * for which to construct the sense data. * @param[in] scsi_status This parameter specifies the SCSI status * value for the user's IO request. * @param[in] sense_key This parameter specifies the sense key to * be set for the user's IO request. * @param[in] additional_sense_code This parameter specifies the * additional sense code (ASC) key to be set for the user's * IO request. * @param[in] additional_sense_code_qualifier This parameter specifies * the additional sense code qualifier (ASCQ) key to be set * for the user's IO request. * * @return none */ void sati_scsi_fixed_sense_data_construct( SATI_TRANSLATOR_SEQUENCE_T * sequence, void * scsi_io, U8 scsi_status, U8 response_code, U8 sense_key, U8 additional_sense_code, U8 additional_sense_code_qualifier ) { U8 * sense_data; U32 sense_len; sati_scsi_get_sense_data_buffer(sequence, scsi_io, scsi_status, &sense_data, &sense_len); // Write out the sense data format per SPC-4. // We utilize the fixed format sense data format. sati_set_sense_data_byte( sense_data, sense_len, 0, response_code | SCSI_FIXED_SENSE_DATA_VALID_BIT ); sati_set_sense_data_byte(sense_data, sense_len, 1, 0); sati_set_sense_data_byte(sense_data, sense_len, 2, sense_key); sati_set_sense_data_byte(sense_data, sense_len, 3, 0); sati_set_sense_data_byte(sense_data, sense_len, 4, 0); sati_set_sense_data_byte(sense_data, sense_len, 5, 0); sati_set_sense_data_byte(sense_data, sense_len, 6, 0); sati_set_sense_data_byte(sense_data, sense_len, 7, (sense_len < 18 ? sense_len - 1 : 17) - 7); sati_set_sense_data_byte(sense_data, sense_len, 8, 0); sati_set_sense_data_byte(sense_data, sense_len, 9, 0); sati_set_sense_data_byte(sense_data, sense_len, 10, 0); sati_set_sense_data_byte(sense_data, sense_len, 11, 0); sati_set_sense_data_byte(sense_data, sense_len, 12, additional_sense_code); sati_set_sense_data_byte(sense_data, sense_len, 13, additional_sense_code_qualifier); sati_set_sense_data_byte(sense_data, sense_len, 14, 0); sati_set_sense_data_byte(sense_data, sense_len, 15, 0); sati_set_sense_data_byte(sense_data, sense_len, 16, 0); sati_set_sense_data_byte(sense_data, sense_len, 17, 0); } /** * @brief This method will construct common sense data that will be identical in * both read error sense construct functions. * sati_scsi_read_ncq_error_sense_construct, * sati_scsi_read_error_sense_construct * * @param[in] sense_data This parameter specifies the user SCSI IO request * for which to set the sense data byte. * @param[in] sense_len This parameter specifies length of the sense data * to be returned by SATI. * @param[in] sense_key This parameter specifies the sense key to * be set for the user's IO request. * @param[in] additional_sense_code This parameter specifies the * additional sense code (ASC) key to be set for the user's * IO request. * @param[in] additional_sense_code_qualifier This parameter specifies * the additional sense code qualifier (ASCQ) key to be set * for the user's IO request. * * @return none */ static void sati_scsi_common_fixed_sense_construct( U8 * sense_data, U32 sense_len, U8 sense_key, U8 additional_sense_code, U8 additional_sense_code_qualifier ) { sati_set_sense_data_byte(sense_data, sense_len, 1, 0); sati_set_sense_data_byte(sense_data, sense_len, 2, sense_key); //Bytes 3, 4, 5, 6 are set in read_error_sense_construct functions sati_set_sense_data_byte(sense_data, sense_len, 7, (sense_len < 18 ? sense_len - 1 : 17) - 7); sati_set_sense_data_byte(sense_data, sense_len, 8, 0); sati_set_sense_data_byte(sense_data, sense_len, 9, 0); sati_set_sense_data_byte(sense_data, sense_len, 10, 0); sati_set_sense_data_byte(sense_data, sense_len, 11, 0); sati_set_sense_data_byte(sense_data, sense_len, 12, additional_sense_code); sati_set_sense_data_byte(sense_data, sense_len, 13, additional_sense_code_qualifier); sati_set_sense_data_byte(sense_data, sense_len, 14, 0); sati_set_sense_data_byte(sense_data, sense_len, 15, 0x80); sati_set_sense_data_byte(sense_data, sense_len, 16, 0); sati_set_sense_data_byte(sense_data, sense_len, 17, 0); } /** * @brief This method will construct the descriptor sense data buffer in * the user's sense data buffer location. Additionally, it will set * the user's SCSI status. * * @param[in] sequence This parameter specifies the translation sequence * for which to construct the sense data. * @param[in,out] scsi_io This parameter specifies the user's IO request * for which to construct the sense data. * @param[in] scsi_status This parameter specifies the SCSI status * value for the user's IO request. * @param[in] sense_key This parameter specifies the sense key to * be set for the user's IO request. * @param[in] additional_sense_code This parameter specifies the * additional sense code (ASC) key to be set for the user's * IO request. * @param[in] additional_sense_code_qualifier This parameter specifies * the additional sense code qualifier (ASCQ) key to be set * for the user's IO request. * * @return none */ static void sati_scsi_common_descriptor_sense_construct( SATI_TRANSLATOR_SEQUENCE_T * sequence, void * scsi_io, U8 * sense_data, U32 sense_len, U8 sense_key, U8 additional_sense_code, U8 additional_sense_code_qualifier, U8 * information_buff ) { sati_set_sense_data_byte(sense_data, sense_len, 1, sense_key); sati_set_sense_data_byte(sense_data, sense_len, 2, additional_sense_code); sati_set_sense_data_byte(sense_data, sense_len, 3, additional_sense_code_qualifier); sati_set_sense_data_byte(sense_data, sense_len, 4, 0); sati_set_sense_data_byte(sense_data, sense_len, 5, 0); sati_set_sense_data_byte(sense_data, sense_len, 6, 0); sati_scsi_common_descriptors_construct(scsi_io, sense_data + 8, sense_len, information_buff); sati_set_sense_data_byte(sense_data, sense_len, 7, sati_scsi_get_descriptor_sense_data_length(sequence, scsi_io) - 8); } /** * @brief This method will construct the sense data buffer in the user's * descriptor sense data buffer location. Additionally, it will set * the user's SCSI status. This is only used for NCQ uncorrectable * read errors * * @param[in] sequence This parameter specifies the translation sequence * for which to construct the sense data. * @param[in,out] scsi_io This parameter specifies the user's IO request * for which to construct the sense data. * @param[in] ata_input_data This parameter specifies the user's ATA IO * response from a Read Log Ext command. * @param[in] scsi_status This parameter specifies the SCSI status * value for the user's IO request. * @param[in] sense_key This parameter specifies the sense key to * be set for the user's IO request. * @param[in] additional_sense_code This parameter specifies the * additional sense code (ASC) key to be set for the user's * IO request. * @param[in] additional_sense_code_qualifier This parameter specifies * the additional sense code qualifier (ASCQ) key to be set * for the user's IO request. * * @return none */ static void sati_scsi_read_ncq_error_descriptor_sense_construct( SATI_TRANSLATOR_SEQUENCE_T * sequence, void * scsi_io, void * ata_input_data, U8 scsi_status, U8 response_code, U8 sense_key, U8 additional_sense_code, U8 additional_sense_code_qualifier ) { U8 * sense_data; U32 sense_len; U8 information_buff[8] = {0}; ATA_NCQ_COMMAND_ERROR_LOG_T * ncq_log = (ATA_NCQ_COMMAND_ERROR_LOG_T *) ata_input_data; sati_scsi_get_sense_data_buffer(sequence, scsi_io, scsi_status, &sense_data, &sense_len); sati_set_sense_data_byte( sense_data, sense_len, 0, response_code ); information_buff[2] = ncq_log->lba_47_40; information_buff[3] = ncq_log->lba_39_32; information_buff[4] = ncq_log->lba_31_24; information_buff[5] = ncq_log->lba_23_16; information_buff[6] = ncq_log->lba_15_8; information_buff[7] = ncq_log->lba_7_0; sati_scsi_common_descriptor_sense_construct( sequence, scsi_io, sense_data, sense_len, sense_key, additional_sense_code, additional_sense_code_qualifier, information_buff ); } /** * @brief This method will construct the sense data buffer in the user's * sense data buffer location. Additionally, it will set the user's * SCSI status. This is only used for NCQ uncorrectable read errors * * @param[in] sequence This parameter specifies the translation sequence * for which to construct the sense data. * @param[in,out] scsi_io This parameter specifies the user's IO request * for which to construct the sense data. * @param[in] ata_input_data This parameter specifies the user's ATA IO * response from a Read Log Ext command. * @param[in] scsi_status This parameter specifies the SCSI status * value for the user's IO request. * @param[in] sense_key This parameter specifies the sense key to * be set for the user's IO request. * @param[in] additional_sense_code This parameter specifies the * additional sense code (ASC) key to be set for the user's * IO request. * @param[in] additional_sense_code_qualifier This parameter specifies * the additional sense code qualifier (ASCQ) key to be set * for the user's IO request. * * @return none */ static void sati_scsi_read_ncq_error_fixed_sense_construct( SATI_TRANSLATOR_SEQUENCE_T * sequence, void * scsi_io, void * ata_input_data, U8 scsi_status, U8 response_code, U8 sense_key, U8 additional_sense_code, U8 additional_sense_code_qualifier ) { U8 * sense_data; U32 sense_len; U8 valid = TRUE; ATA_NCQ_COMMAND_ERROR_LOG_T * ncq_log = (ATA_NCQ_COMMAND_ERROR_LOG_T *) ata_input_data; sati_scsi_get_sense_data_buffer(sequence, scsi_io, scsi_status, &sense_data, &sense_len); if(ncq_log->lba_39_32 > 0) { valid = FALSE; } sati_set_sense_data_byte( sense_data, sense_len, 0, (valid << 7) | response_code ); sati_set_sense_data_byte(sense_data, sense_len, 3, ncq_log->lba_31_24); sati_set_sense_data_byte(sense_data, sense_len, 4, ncq_log->lba_23_16); sati_set_sense_data_byte(sense_data, sense_len, 5, ncq_log->lba_15_8); sati_set_sense_data_byte(sense_data, sense_len, 6, ncq_log->lba_7_0); sati_scsi_common_fixed_sense_construct( sense_data, sense_len, sense_key, additional_sense_code, additional_sense_code_qualifier ); } void sati_scsi_read_ncq_error_sense_construct( SATI_TRANSLATOR_SEQUENCE_T * sequence, void * scsi_io, void * ata_input_data, U8 scsi_status, U8 sense_key, U8 additional_sense_code, U8 additional_sense_code_qualifier ) { U8 response_code; response_code = sati_scsi_get_sense_data_response_code(sequence); switch (response_code) { case SCSI_FIXED_CURRENT_RESPONSE_CODE: case SCSI_FIXED_DEFERRED_RESPONSE_CODE: sati_scsi_read_ncq_error_fixed_sense_construct(sequence, scsi_io, ata_input_data, scsi_status, response_code, sense_key, additional_sense_code, additional_sense_code_qualifier); break; case SCSI_DESCRIPTOR_CURRENT_RESPONSE_CODE: case SCSI_DESCRIPTOR_DEFERRED_RESPONSE_CODE: sati_scsi_read_ncq_error_descriptor_sense_construct(sequence, scsi_io, ata_input_data, scsi_status, response_code, sense_key, additional_sense_code, additional_sense_code_qualifier); break; } sequence->is_sense_response_set = TRUE; } /** * @brief This method will construct the sense data buffer in the user's * sense data buffer location. Additionally, it will set the user's * SCSI status. This is used for uncorrectable read errors. * * @param[in] sequence This parameter specifies the translation sequence * for which to construct the sense data. * @param[in,out] scsi_io This parameter specifies the user's IO request * for which to construct the sense data. * @param[in] ata_io This parameter is a pointer to the ATA IO data used * to get the ATA register fis. * @param[in] scsi_status This parameter specifies the SCSI status * value for the user's IO request. * @param[in] sense_key This parameter specifies the sense key to * be set for the user's IO request. * @param[in] additional_sense_code This parameter specifies the * additional sense code (ASC) key to be set for the user's * IO request. * @param[in] additional_sense_code_qualifier This parameter specifies * the additional sense code qualifier (ASCQ) key to be set * for the user's IO request. * * @return none */ static void sati_scsi_read_error_descriptor_sense_construct( SATI_TRANSLATOR_SEQUENCE_T * sequence, void * scsi_io, void * ata_io, U8 scsi_status, U8 response_code, U8 sense_key, U8 additional_sense_code, U8 additional_sense_code_qualifier ) { U8 * sense_data; U32 sense_len; U8 information_buff[8] = {0}; U8 * register_fis = sati_cb_get_d2h_register_fis_address(ata_io); sati_scsi_get_sense_data_buffer(sequence, scsi_io, scsi_status, &sense_data, &sense_len); information_buff[2] = sati_get_ata_lba_high_ext(register_fis); information_buff[3] = sati_get_ata_lba_mid_ext(register_fis); information_buff[4] = sati_get_ata_lba_low_ext(register_fis); information_buff[5] = sati_get_ata_lba_high(register_fis); information_buff[6] = sati_get_ata_lba_mid(register_fis); information_buff[7] = sati_get_ata_lba_low(register_fis); sati_set_sense_data_byte( sense_data, sense_len, 0, SCSI_DESCRIPTOR_CURRENT_RESPONSE_CODE ); sati_scsi_common_descriptor_sense_construct( sequence, scsi_io, sense_data, sense_len, sense_key, additional_sense_code, additional_sense_code_qualifier, information_buff ); } /** * @brief This method will construct the sense data buffer in the user's * sense data buffer location. Additionally, it will set the user's * SCSI status. This is used for uncorrectable read errors. * * @param[in] sequence This parameter specifies the translation sequence * for which to construct the sense data. * @param[in,out] scsi_io This parameter specifies the user's IO request * for which to construct the sense data. * @param[in] ata_io This parameter is a pointer to the ATA IO data used * to get the ATA register fis. * @param[in] scsi_status This parameter specifies the SCSI status * value for the user's IO request. * @param[in] sense_key This parameter specifies the sense key to * be set for the user's IO request. * @param[in] additional_sense_code This parameter specifies the * additional sense code (ASC) key to be set for the user's * IO request. * @param[in] additional_sense_code_qualifier This parameter specifies * the additional sense code qualifier (ASCQ) key to be set * for the user's IO request. * * @return none */ static void sati_scsi_read_error_fixed_sense_construct( SATI_TRANSLATOR_SEQUENCE_T * sequence, void * scsi_io, void * ata_io, U8 scsi_status, U8 response_code, U8 sense_key, U8 additional_sense_code, U8 additional_sense_code_qualifier ) { U8 * sense_data; U32 sense_len; U8 valid = TRUE; U8 * register_fis = sati_cb_get_d2h_register_fis_address(ata_io); sati_scsi_get_sense_data_buffer(sequence, scsi_io, scsi_status, &sense_data, &sense_len); if(sati_get_ata_lba_mid_ext(register_fis) > 0) { valid = FALSE; } sati_set_sense_data_byte(sense_data, sense_len, 3, sati_get_ata_lba_low_ext(register_fis)); sati_set_sense_data_byte(sense_data, sense_len, 4, sati_get_ata_lba_high(register_fis)); sati_set_sense_data_byte(sense_data, sense_len, 5, sati_get_ata_lba_mid(register_fis)); sati_set_sense_data_byte(sense_data, sense_len, 6, sati_get_ata_lba_low(register_fis)); sati_set_sense_data_byte( sense_data, sense_len, 0, (valid << 7) | SCSI_FIXED_CURRENT_RESPONSE_CODE ); sati_scsi_common_fixed_sense_construct( sense_data, sense_len, sense_key, additional_sense_code, additional_sense_code_qualifier ); } void sati_scsi_read_error_sense_construct( SATI_TRANSLATOR_SEQUENCE_T * sequence, void * scsi_io, void * ata_input_data, U8 scsi_status, U8 sense_key, U8 additional_sense_code, U8 additional_sense_code_qualifier ) { U8 response_code; response_code = sati_scsi_get_sense_data_response_code(sequence); switch (response_code) { case SCSI_FIXED_CURRENT_RESPONSE_CODE: case SCSI_FIXED_DEFERRED_RESPONSE_CODE: sati_scsi_read_error_fixed_sense_construct(sequence, scsi_io, ata_input_data, scsi_status, response_code, sense_key, additional_sense_code, additional_sense_code_qualifier); break; case SCSI_DESCRIPTOR_CURRENT_RESPONSE_CODE: case SCSI_DESCRIPTOR_DEFERRED_RESPONSE_CODE: sati_scsi_read_error_descriptor_sense_construct(sequence, scsi_io, ata_input_data, scsi_status, response_code, sense_key, additional_sense_code, additional_sense_code_qualifier); break; } sequence->is_sense_response_set = TRUE; } /* * @brief This method builds the scsi response data for a sata task management * request. * * @param[in] sequence This parameter specifies the translation sequence * for which to construct the sense data. * @param[in,out] scsi_io This parameter specifies the user's IO request * for which to construct the sense data. * @param[in] response_data The response status for the task management * request. */ void sati_scsi_response_data_construct( SATI_TRANSLATOR_SEQUENCE_T * sequence, void * scsi_io, U8 response_data ) { #ifdef SATI_TRANSPORT_SUPPORTS_SAS SCI_SSP_RESPONSE_IU_T * rsp_iu = (SCI_SSP_RESPONSE_IU_T*) sati_cb_get_response_iu_address(scsi_io); rsp_iu->data_present = 0x01; rsp_iu->response_data_length[3] = sizeof(U32); rsp_iu->status = 0; ((U8 *)rsp_iu->data)[3] = response_data; #else #endif // SATI_TRANSPORT_SUPPORTS_SAS } /** * @brief This method checks to make sure that the translation isn't * exceeding the allocation length specified in the CDB prior * to retrieving the payload data byte from the user's buffer. * * @param[in,out] scsi_io This parameter specifies the user's IO request * for which to set the user payload data byte. * @param[in] byte_offset This parameter specifies the offset into * the user's payload buffer at which to write the supplied * value. * @param[in] value This parameter specifies the memory location into * which to read the value from the user's payload buffer. * * @return none */ void sati_get_data_byte( SATI_TRANSLATOR_SEQUENCE_T * sequence, void * scsi_io, U32 byte_offset, U8 * value ) { if (byte_offset < sequence->allocation_length) sati_cb_get_data_byte(scsi_io, byte_offset, value); } /** * @brief This method checks to make sure that the translation isn't * exceeding the allocation length specified in the CDB while * translating payload data into the user's buffer. * * @param[in] sequence This parameter specifies the translation sequence * for which to set the user payload data byte. * @param[in,out] scsi_io This parameter specifies the user's IO request * for which to set the user payload data byte. * @param[in] byte_offset This parameter specifies the offset into * the user's payload buffer at which to write the supplied * value. * @param[in] value This parameter specifies the new value to be * written out into the user's payload buffer. * * @return none */ void sati_set_data_byte( SATI_TRANSLATOR_SEQUENCE_T * sequence, void * scsi_io, U32 byte_offset, U8 value ) { if (byte_offset < sequence->allocation_length) { sequence->number_data_bytes_set++; sati_cb_set_data_byte(scsi_io, byte_offset, value); } } /** * @brief This method checks to make sure that the translation isn't * exceeding the allocation length specified in the CDB while * translating payload data into the user's buffer. * * @param[in] sequence This parameter specifies the translation sequence * for which to set the user payload data dword. * @param[in,out] scsi_io This parameter specifies the user's IO request * for which to set the user payload data dword. * @param[in] byte_offset This parameter specifies the offset into * the user's payload buffer at which to write the supplied * value. * @param[in] value This parameter specifies the new value to be * written out into the user's payload buffer. * * @return none */ void sati_set_data_dword( SATI_TRANSLATOR_SEQUENCE_T * sequence, void * scsi_io, U32 byte_offset, U32 value ) { /// @todo Check to ensure that the bytes appear correctly (SAS Address). sati_set_data_byte(sequence, scsi_io, byte_offset, (U8)value & 0xFF); byte_offset++; sati_set_data_byte(sequence, scsi_io, byte_offset, (U8)(value >> 8) & 0xFF); byte_offset++; sati_set_data_byte(sequence, scsi_io, byte_offset, (U8)(value >> 16) & 0xFF); byte_offset++; sati_set_data_byte(sequence, scsi_io, byte_offset, (U8)(value >> 24) & 0xFF); } /** * @brief This method will construct the ATA flush cache command. * * @pre It is expected that the user has properly set the current contents * of the register FIS to 0. * * @param[out] ata_io This parameter specifies the ATA IO request structure * for which to build the FLUSH CACHE command. * @param[in] sequence This parameter specifies the translator sequence * for which the command is being constructed. * * @return none. */ void sati_ata_flush_cache_construct( void * ata_io, SATI_TRANSLATOR_SEQUENCE_T * sequence ) { U8 * register_fis = sati_cb_get_h2d_register_fis_address(ata_io); sati_set_ata_command(register_fis, ATA_FLUSH_CACHE); sati_ata_non_data_command(ata_io, sequence); } /** * @brief This method will construct the ATA standby immediate command. * * @pre It is expected that the user has properly set the current contents * of the register FIS to 0. * * @param[out] ata_io This parameter specifies the ATA IO request structure * for which to build the STANDBY IMMEDIATE command. * @param[in] sequence This parameter specifies the translator sequence * for which the command is being constructed. * * @param[in] count This parameter specifies the time period programmed * into the Standby Timer. See ATA8 spec for more details * @return none. */ void sati_ata_standby_construct( void * ata_io, SATI_TRANSLATOR_SEQUENCE_T * sequence, U16 count ) { U8 * register_fis = sati_cb_get_h2d_register_fis_address(ata_io); sati_set_ata_command(register_fis, ATA_STANDBY); sati_set_ata_sector_count(register_fis, count); sequence->device->ata_standby_timer = (U8) count; sati_ata_non_data_command(ata_io, sequence); } /** * @brief This method will construct the ATA standby immediate command. * * @pre It is expected that the user has properly set the current contents * of the register FIS to 0. * * @param[out] ata_io This parameter specifies the ATA IO request structure * for which to build the STANDBY IMMEDIATE command. * @param[in] sequence This parameter specifies the translator sequence * for which the command is being constructed. * * @return none. */ void sati_ata_standby_immediate_construct( void * ata_io, SATI_TRANSLATOR_SEQUENCE_T * sequence ) { U8 * register_fis = sati_cb_get_h2d_register_fis_address(ata_io); sati_set_ata_command(register_fis, ATA_STANDBY_IMMED); sati_ata_non_data_command(ata_io, sequence); } /** * @brief This method will construct the ATA idle immediate command. * * @pre It is expected that the user has properly set the current contents * of the register FIS to 0. * * @param[out] ata_io This parameter specifies the ATA IO request structure * for which to build the IDLE IMMEDIATE command. * @param[in] sequence This parameter specifies the translator sequence * for which the command is being constructed. * * @return none. */ void sati_ata_idle_immediate_construct( void * ata_io, SATI_TRANSLATOR_SEQUENCE_T * sequence ) { U8 * register_fis = sati_cb_get_h2d_register_fis_address(ata_io); sati_set_ata_command(register_fis, ATA_IDLE_IMMED); sati_set_ata_features(register_fis, 0x00); sati_set_ata_sector_count(register_fis, 0x00); sati_set_ata_lba_high(register_fis, 0x00); sati_set_ata_lba_mid(register_fis, 0x00); sati_set_ata_lba_low(register_fis, 0x00); sati_ata_non_data_command(ata_io, sequence); } /** * @brief This method will construct the ATA idle immediate command for Unload Features. * * @pre It is expected that the user has properly set the current contents * of the register FIS to 0. * * @param[out] ata_io This parameter specifies the ATA IO request structure * for which to build the IDLE IMMEDIATE command. * @param[in] sequence This parameter specifies the translator sequence * for which the command is being constructed. * * @return none. */ void sati_ata_idle_immediate_unload_construct( void * ata_io, SATI_TRANSLATOR_SEQUENCE_T * sequence ) { U8 * register_fis = sati_cb_get_h2d_register_fis_address(ata_io); sati_set_ata_command(register_fis, ATA_IDLE_IMMED); sati_set_ata_features(register_fis, 0x44); sati_set_ata_sector_count(register_fis, 0x00); sati_set_ata_lba_high(register_fis, 0x55); sati_set_ata_lba_mid(register_fis, 0x4E); sati_set_ata_lba_low(register_fis, 0x4C); sati_ata_non_data_command(ata_io, sequence); } /** * @brief This method will construct the ATA IDLE command.\ * * @pre It is expected that the user has properly set the current contents * of the register FIS to 0. * * @param[out] ata_io This parameter specifies the ATA IO request structure * for which to build the ATA IDLE command. * @param[in] sequence This parameter specifies the translator sequence * for which the command is being constructed. * * @return none. */ void sati_ata_idle_construct( void * ata_io, SATI_TRANSLATOR_SEQUENCE_T * sequence ) { U8 * register_fis = sati_cb_get_h2d_register_fis_address(ata_io); sati_set_ata_command(register_fis, ATA_IDLE); sati_set_ata_features(register_fis, 0x00); sati_set_ata_sector_count(register_fis, 0x00); sequence->device->ata_standby_timer = 0x00; sati_set_ata_lba_high(register_fis, 0x00); sati_set_ata_lba_mid(register_fis, 0x00); sati_set_ata_lba_low(register_fis, 0x00); sati_ata_non_data_command(ata_io, sequence); } /** * @brief This method will construct the ATA MEDIA EJECT command. * * @pre It is expected that the user has properly set the current contents * of the register FIS to 0. * * @param[out] ata_io This parameter specifies the ATA IO request structure * for which to build the MEDIA EJCT command. * @param[in] sequence This parameter specifies the translator sequence * for which the command is being constructed. * * @return none. */ void sati_ata_media_eject_construct( void * ata_io, SATI_TRANSLATOR_SEQUENCE_T * sequence ) { U8 * register_fis = sati_cb_get_h2d_register_fis_address(ata_io); sati_set_ata_command(register_fis, ATA_MEDIA_EJECT); sati_ata_non_data_command(ata_io, sequence); } /** * @brief This method will construct the ATA read verify sector(s) command. * * @pre It is expected that the user has properly set the current contents * of the register FIS to 0. * * @param[out] ata_io This parameter specifies the ATA IO request structure * for which to build the ATA READ VERIFY SECTOR(S) command. * @param[in] sequence This parameter specifies the translator sequence * for which the command is being constructed. * * @return none. */ void sati_ata_read_verify_sectors_construct( void * ata_io, SATI_TRANSLATOR_SEQUENCE_T * sequence ) { U8 * register_fis = sati_cb_get_h2d_register_fis_address(ata_io); sati_set_ata_command(register_fis, ATA_READ_VERIFY_SECTORS); //According to SAT-2 (v7) 9.11.3 sati_set_ata_sector_count(register_fis, 1); //According to SAT-2 (v7) 9.11.3, set LBA to a value between zero and the //maximum LBA supported by the ATA device in its current configuration. //From the unit test, it seems we have to set LBA to a non-zero value. sati_set_ata_lba_low(register_fis, 1); sati_ata_non_data_command(ata_io, sequence); } /** * @brief This method will construct a ATA SMART Return Status command so the * status of the ATA device can be returned. The status of the SMART * threshold will be returned by this command. * * @return N/A * */ void sati_ata_smart_return_status_construct( void * ata_io, SATI_TRANSLATOR_SEQUENCE_T * sequence, U8 feature_value ) { U8 * register_fis = sati_cb_get_h2d_register_fis_address(ata_io); sati_set_ata_command(register_fis, ATA_SMART); sati_set_ata_features(register_fis, feature_value); sati_set_ata_lba_high(register_fis, 0xC2); sati_set_ata_lba_mid(register_fis, 0x4F); sati_ata_non_data_command(ata_io, sequence); } /** * @brief This method will construct a ATA SMART Return Status command so the * status of the ATA device can be returned. The status of the SMART * threshold will be returned by this command. * * @return N/A * */ void sati_ata_smart_read_log_construct( void * ata_io, SATI_TRANSLATOR_SEQUENCE_T * sequence, U8 log_address, U32 transfer_length ) { U8 * register_fis = sati_cb_get_h2d_register_fis_address(ata_io); sati_set_ata_command(register_fis, ATA_SMART); sati_set_ata_features(register_fis, ATA_SMART_SUB_CMD_READ_LOG); sati_set_ata_lba_high(register_fis, 0xC2); sati_set_ata_lba_mid(register_fis, 0x4F); sati_set_ata_lba_low(register_fis, log_address); sequence->data_direction = SATI_DATA_DIRECTION_IN; sequence->protocol = SAT_PROTOCOL_PIO_DATA_IN; sequence->ata_transfer_length = transfer_length; } /** * @brief This method will construct a Write Uncorrectable ATA command that * will write one sector with a pseudo or flagged error. The type of * error is specified by the feature value. * * @return N/A * */ void sati_ata_write_uncorrectable_construct( void * ata_io, SATI_TRANSLATOR_SEQUENCE_T * sequence, U8 feature_value ) { U8 * register_fis = sati_cb_get_h2d_register_fis_address(ata_io); sati_set_ata_command(register_fis, ATA_WRITE_UNCORRECTABLE); sati_set_ata_features(register_fis, feature_value); sati_set_ata_sector_count(register_fis, 0x0001); sati_ata_non_data_command(ata_io, sequence); } /** * @brief This method will construct a Mode Select ATA SET FEATURES command * For example, Enable/Disable Write Cache, Enable/Disable Read Ahead * * @return N/A * */ void sati_ata_set_features_construct( void * ata_io, SATI_TRANSLATOR_SEQUENCE_T * sequence, U8 feature ) { U8 * register_fis = sati_cb_get_h2d_register_fis_address(ata_io); sati_set_ata_command(register_fis, ATA_SET_FEATURES); sati_set_ata_features(register_fis, feature); sati_ata_non_data_command(ata_io, sequence); } /** * @brief This method will construct a Read Log ext ATA command that * will request a log page based on the log_address. * * @param[in] log_address This parameter specifies the log page * to be returned from Read Log Ext. * * @param[in] transfer_length This parameter specifies the size of the * log page response returned by Read Log Ext. * * @return N/A * */ void sati_ata_read_log_ext_construct( void * ata_io, SATI_TRANSLATOR_SEQUENCE_T * sequence, U8 log_address, U32 transfer_length ) { U8 * register_fis = sati_cb_get_h2d_register_fis_address(ata_io); sati_set_ata_command(register_fis, ATA_READ_LOG_EXT); sati_set_ata_lba_low(register_fis, log_address); sati_set_ata_lba_mid(register_fis, 0x00); sati_set_ata_lba_mid_exp(register_fis, 0x00); sati_set_ata_sector_count(register_fis, 0x01); sequence->data_direction = SATI_DATA_DIRECTION_IN; sequence->protocol = SAT_PROTOCOL_PIO_DATA_IN; sequence->ata_transfer_length = transfer_length; } /** * @brief This method will check if the ATA device is in the stopped power * state. This is used for all medium access commands for SAT * compliance. See SAT2r07 section 9.11.1 * * @param[in] sequence - SATI sequence data with the device state. * * @return TRUE If device is stopped * */ BOOL sati_device_state_stopped( SATI_TRANSLATOR_SEQUENCE_T * sequence, void * scsi_io ) { if(sequence->device->state == SATI_DEVICE_STATE_STOPPED) { sati_scsi_sense_data_construct( sequence, scsi_io, SCSI_STATUS_CHECK_CONDITION, SCSI_SENSE_NOT_READY , SCSI_ASC_INITIALIZING_COMMAND_REQUIRED, SCSI_ASCQ_INITIALIZING_COMMAND_REQUIRED ); return TRUE; } return FALSE; } /** * @brief This method will construct a ATA Read Buffer command that * will request PIO in data containing the target device's buffer. * * @param[out] ata_io This parameter specifies the ATA IO request structure * for which to build the ATA READ VERIFY SECTOR(S) command. * @param[in] sequence This parameter specifies the translator sequence * for which the command is being constructed. * @return N/A * */ void sati_ata_read_buffer_construct( void * ata_io, SATI_TRANSLATOR_SEQUENCE_T * sequence ) { U8 * register_fis = sati_cb_get_h2d_register_fis_address(ata_io); sati_set_ata_command(register_fis, ATA_READ_BUFFER); sequence->data_direction = SATI_DATA_DIRECTION_IN; sequence->protocol = SAT_PROTOCOL_PIO_DATA_IN; sequence->ata_transfer_length = 512; } /** * @brief This method will construct a ATA Write Buffer command that * will send PIO out data to the target device's buffer. * * @param[out] ata_io This parameter specifies the ATA IO request structure * for which to build the ATA READ VERIFY SECTOR(S) command. * @param[in] sequence This parameter specifies the translator sequence * for which the command is being constructed. * @return N/A * */ void sati_ata_write_buffer_construct( void * ata_io, SATI_TRANSLATOR_SEQUENCE_T * sequence ) { U8 * register_fis = sati_cb_get_h2d_register_fis_address(ata_io); sati_set_ata_command(register_fis, ATA_WRITE_BUFFER); sequence->data_direction = SATI_DATA_DIRECTION_OUT; sequence->protocol = SAT_PROTOCOL_PIO_DATA_OUT; sequence->ata_transfer_length = 512; } /** * @brief This method will construct a ATA Download Microcode command that * will send PIO out data containing new firmware for the target drive. * * @param[out] ata_io This parameter specifies the ATA IO request structure * for which to build the ATA READ VERIFY SECTOR(S) command. * @param[in] sequence This parameter specifies the translator sequence * for which the command is being constructed. * @param[in] mode This parameter specifies the download microcode sub-command * code. * @param[in] allocation_length This parameter specifies the number of bytes * being sent to the target device. * @param[in] buffer_offset This parameter specifies the buffer offset for the * data sent to the target device. * * @return N/A * */ void sati_ata_download_microcode_construct( void * ata_io, SATI_TRANSLATOR_SEQUENCE_T * sequence, U8 mode, U32 allocation_length, U32 buffer_offset ) { U8 * register_fis = sati_cb_get_h2d_register_fis_address(ata_io); U32 allocation_blocks = allocation_length >> 9; U32 buffer_blkoffset = buffer_offset >> 9; sati_set_ata_command(register_fis, ATA_DOWNLOAD_MICROCODE); sati_set_ata_features(register_fis, mode); if(mode == ATA_MICROCODE_DOWNLOAD_SAVE) { sati_set_ata_sector_count(register_fis, (U8) (allocation_length >> 9)); sati_set_ata_lba_low(register_fis, (U8) (allocation_length >> 17)); } else //mode == 0x03 { sati_set_ata_sector_count(register_fis, (U8) (allocation_blocks & 0xff)); sati_set_ata_lba_low(register_fis, (U8) ((allocation_blocks >> 8) & 0xff)); sati_set_ata_lba_mid(register_fis, (U8) (buffer_blkoffset & 0xff)); sati_set_ata_lba_high(register_fis, (U8) ((buffer_blkoffset >> 8) & 0xff)); } if((allocation_length == 0) && (buffer_offset == 0)) { sati_ata_non_data_command(ata_io, sequence); } else { sequence->data_direction = SATI_DATA_DIRECTION_OUT; sequence->protocol = SAT_PROTOCOL_PIO_DATA_OUT; sequence->ata_transfer_length = allocation_length; } }