/** * @brief This method builds the mode parameter header for a 10-byte SCSI * mode sense data response. The parameter header is 4 bytes in * size. * For more information on the parameters passed to this method, * please reference sati_translate_command(). * * @param[in] identify This parameter specifies the ATA remote device's * received IDENTIFY DEVICE data. * @param[in] mode_data_length This parameter specifies the amount of data * to be returned as part of this mode sense request. * * @return This method returns the number of bytes written into the * mode sense data buffer. */ static U32 sati_mode_sense_10_build_header( SATI_TRANSLATOR_SEQUENCE_T * sequence, void * scsi_io, ATA_IDENTIFY_DEVICE_DATA_T * identify, U16 mode_data_length ) { U8 * cdb = sati_cb_get_cdb_address(scsi_io); // Fill in the length of the mode parameter data returned (do not include // the size of the mode data length field in the total). Adjust the // mode data length to not include the mode data length fields itself // (i.e. subtract 2). mode_data_length -= 2; sati_set_data_byte(sequence, scsi_io, 0, (U8)(mode_data_length >> 8) & 0xFF); sati_set_data_byte(sequence, scsi_io, 1, (U8)(mode_data_length & 0xFF)); // Medium Type is 0 for SBC devices sati_set_data_byte(sequence, scsi_io, 2, SCSI_MODE_HEADER_MEDIUM_TYPE_SBC); // Write Protect (WP), Rsvd, DPOFUA, Rsvd if (sequence->device->capabilities & SATI_DEVICE_CAP_DMA_FUA_ENABLE) sati_set_data_byte(sequence,scsi_io,3,SCSI_MODE_SENSE_HEADER_FUA_ENABLE); else sati_set_data_byte(sequence, scsi_io, 3, 0); // Set the reserved bytes to 0. The LONGLBA field in byte 4 is overridden // later in this method if LLBAA is enabled. sati_set_data_byte(sequence, scsi_io, 4, 0); sati_set_data_byte(sequence, scsi_io, 5, 0); // The MSB for the block descriptor length is never used since the // largest block descriptor in this translator is 16-bytes in size. sati_set_data_byte(sequence, scsi_io, 6, 0); // Set the LSB block descriptor length if block descriptors are utilized. if (sati_get_cdb_byte(cdb, 1) & SCSI_MODE_SENSE_DBD_ENABLE) sati_set_data_byte(sequence, scsi_io, 7, 0); else { // If Long Logical Block Address are allowed, then the block descriptor // is larger (16 bytes total). if (sati_get_cdb_byte(cdb, 1) & SCSI_MODE_SENSE_LLBAA_ENABLE) { sati_set_data_byte(sequence, scsi_io, 4, 1); sati_set_data_byte( sequence, scsi_io, 7, SCSI_MODE_SENSE_LLBA_BLOCK_DESCRIPTOR_LENGTH ); } else { sati_set_data_byte( sequence, scsi_io, 7, SCSI_MODE_SENSE_STD_BLOCK_DESCRIPTOR_LENGTH ); } } return SCSI_MODE_SENSE_10_HEADER_LENGTH; }
/** * @brief This method perform the data translation common to all SCSI MODE * SENSE 10 byte commands. This includes building the mode page * header and block descriptor (if requested). * 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 to be used during translation. * @param[in] transfer_length This parameter specifies the size of the * mode page (including header & block descriptor). * * @return This method returns the number of bytes written into the user's * mode page data buffer. */ static U32 sati_mode_sense_10_translate_data( SATI_TRANSLATOR_SEQUENCE_T * sequence, ATA_IDENTIFY_DEVICE_DATA_T * identify, void * scsi_io, U16 transfer_length ) { U8 * cdb = sati_cb_get_cdb_address(scsi_io); U32 offset; offset = sati_mode_sense_10_build_header( sequence, scsi_io, identify, transfer_length ); // Determine if the caller disabled block descriptors (DBD). If not, // then generate a block descriptor. if ((sati_get_cdb_byte(cdb, 1) & SCSI_MODE_SENSE_DBD_ENABLE) == 0) { // If the user requested the Long LBA format descriptor, then build // it if (sati_get_cdb_byte(cdb, 1) & SCSI_MODE_SENSE_LLBAA_ENABLE) offset += sati_mode_sense_10_build_llba_block_descriptor( sequence, scsi_io, identify, offset ); else offset += sati_mode_sense_build_std_block_descriptor( sequence, scsi_io, identify, offset ); } return offset; }
/** * @brief This method will translate the SCSI read 12 command into a * corresponding ATA read command. Depending upon the capabilities * supported by the target different ATA commands can be selected. * It ensures that all translation required for this command is * performed successfully. * For more information on the parameters passed to this method, * please reference sati_translate_command(). * * @return Indicate if the command translation succeeded. * @see sati_read_32_bit_lba_translate_command() for return values. */ SATI_STATUS sati_read_12_translate_command( SATI_TRANSLATOR_SEQUENCE_T * sequence, void * scsi_io, void * ata_io ) { U8 * cdb = sati_cb_get_cdb_address(scsi_io); U32 sector_count = (sati_get_cdb_byte(cdb, 6) << 24) | (sati_get_cdb_byte(cdb, 7) << 16) | (sati_get_cdb_byte(cdb, 8) << 8) | (sati_get_cdb_byte(cdb, 9)); if(sati_device_state_stopped(sequence, scsi_io)) { return SATI_FAILURE_CHECK_RESPONSE_DATA; } else { sequence->type = SATI_SEQUENCE_READ_12; return sati_read_32_bit_lba_translate_command( sequence, scsi_io, ata_io, sector_count, 11 ); } }
/** * @brief This method performs all of the translation required for a * SCSI VERIFY 16 byte CDB. * This includes: * - logical block address translation * - transfer length (sector count) translation * - translation items common to all VERIFY CDB sizes. * For more information on the parameters passed to this method, * please reference sati_translate_command(). * * @return Indicate if the command translation was successful. * For more information on return values please reference * sati_move_set_sector_count(), sati_verify_translate_command() */ SATI_STATUS sati_verify_16_translate_command( SATI_TRANSLATOR_SEQUENCE_T * sequence, void * scsi_io, void * ata_io ) { SATI_STATUS status; U8 * cdb = sati_cb_get_cdb_address(scsi_io); U32 sector_count = (sati_get_cdb_byte(cdb, 10) << 24) | (sati_get_cdb_byte(cdb, 11) << 16) | (sati_get_cdb_byte(cdb, 12) << 8) | (sati_get_cdb_byte(cdb, 13)); if(sati_device_state_stopped(sequence, scsi_io)) { return SATI_FAILURE_CHECK_RESPONSE_DATA; } else { sequence->type = SATI_SEQUENCE_VERIFY_16; // Fill in the Logical Block Address field. status = sati_move_translate_64_bit_lba(sequence, scsi_io, ata_io); if (status != SATI_SUCCESS) return status; // Fill in the Sector Count fields. status = sati_move_set_sector_count(sequence,scsi_io,ata_io,sector_count,0); if (status != SATI_SUCCESS) return status; return sati_verify_translate_command(sequence, scsi_io, ata_io); } }
U32 sati_atapi_translate_number_of_bytes_transferred( SATI_TRANSLATOR_SEQUENCE_T * sequence, void * scsi_io, void * atapi_io ) { U8* cdb = sati_cb_get_cdb_address(scsi_io); U8 response_data; U32 data_length = 0; switch(cdb[0]) { case SCSI_MODE_SENSE_10: sati_cb_get_data_byte(scsi_io, 1, &response_data); data_length = response_data+2; break; case 0x51: //READ DISC INFORMATION sati_cb_get_data_byte(scsi_io, 1, &response_data); data_length = response_data+2; break; default: break; } return data_length; }
/** * @brief This method builds the mode parameter header for a 6-byte SCSI * mode sense data response. The parameter header is 4 bytes in * size. * For more information on the parameters passed to this method, * please reference sati_translate_command(). * * @param[in] identify This parameter specifies the ATA remote device's * received IDENTIFY DEVICE data. * @param[in] mode_data_length This parameter specifies the amount of data * to be returned as part of this mode sense request. * * @return This method returns the number of bytes written into the * data buffer. */ static U32 sati_mode_sense_6_build_header( SATI_TRANSLATOR_SEQUENCE_T * sequence, void * scsi_io, ATA_IDENTIFY_DEVICE_DATA_T * identify, U8 mode_data_length ) { U8 * cdb = sati_cb_get_cdb_address(scsi_io); // Fill in the length of the mode parameter data returned (do not include // the size of the mode data length field in the total). sati_set_data_byte(sequence, scsi_io, 0, (U8)mode_data_length-1); // Medium Type is 0 for SBC devices sati_set_data_byte(sequence, scsi_io, 1, SCSI_MODE_HEADER_MEDIUM_TYPE_SBC); // Write Protect (WP), Rsvd, DPOFUA, Rsvd if (sequence->device->capabilities & SATI_DEVICE_CAP_DMA_FUA_ENABLE) sati_set_data_byte(sequence,scsi_io,2,SCSI_MODE_SENSE_HEADER_FUA_ENABLE); else sati_set_data_byte(sequence, scsi_io, 2, 0); // Set the block descriptor length if block descriptors are utilized. if (sati_get_cdb_byte(cdb, 1) & SCSI_MODE_SENSE_DBD_ENABLE) sati_set_data_byte(sequence, scsi_io, 3, 0); else sati_set_data_byte( sequence, scsi_io, 3, SCSI_MODE_SENSE_STD_BLOCK_DESCRIPTOR_LENGTH ); return SCSI_MODE_SENSE_6_HEADER_LENGTH; }
/** * @brief This method performs the SCSI SYNCHRONIZE_CACHE 10 and 16 command translation * functionality common to all SYNCHRONIZE_CACHE command sizes. * This includes: * - setting the command register * - setting the device head register * - filling in fields in the SATI_TRANSLATOR_SEQUENCE object. * For more information on the parameters passed to this method, * please reference sati_translate_command(). * * @return Indicate if the method was successfully completed. * @retval SATI_SUCCESS This is returned in all other cases. */ SATI_STATUS sati_synchronize_cache_translate_command( SATI_TRANSLATOR_SEQUENCE_T * sequence, void * scsi_io, void * ata_io ) { U8 * cdb = sati_cb_get_cdb_address(scsi_io); U8 * register_fis = sati_cb_get_h2d_register_fis_address(ata_io); sequence->type = SATI_SEQUENCE_SYNCHRONIZE_CACHE; sequence->protocol = SAT_PROTOCOL_NON_DATA; sequence->data_direction = SATI_DATA_DIRECTION_NONE; if (sati_get_cdb_byte(cdb, 1) & SCSI_SYNCHRONIZE_CACHE_IMMED_ENABLED) { //currently we ignore immed bit. ; } // Ensure the device supports the 48 bit feature set. if (sequence->device->capabilities & SATI_DEVICE_CAP_48BIT_ENABLE) sati_set_ata_command(register_fis, ATA_FLUSH_CACHE_EXT); else sati_set_ata_command(register_fis, ATA_FLUSH_CACHE); return SATI_SUCCESS; }
/** * @brief This method will translate the SCSI mode sense 6 byte command * into corresponding ATA commands. If the command is well-formed, * then the translation will result in an ATA IDENTIFY DEVICE * command. * For more information on the parameters passed to this method, * please reference sati_translate_command(). * * @return Indicate if the command translation succeeded. * @retval SCI_SUCCESS This is returned if the command translation was * successful. * @retval SATI_FAILURE_CHECK_RESPONSE_DATA This value is returned if * sense data has been created as a result of something specified * in the CDB. */ SATI_STATUS sati_mode_sense_6_translate_command( SATI_TRANSLATOR_SEQUENCE_T * sequence, void * scsi_io, void * ata_io ) { U8 * cdb = sati_cb_get_cdb_address(scsi_io); // Set the data length based on the allocation length field in the CDB. sequence->allocation_length = sati_get_cdb_byte(cdb, 4); return sati_mode_sense_translate_command(sequence, scsi_io, ata_io, 6); }
/** * @brief This method will translate the read capacity 16 SCSI command into * an ATA IDENTIFY DEVICE command. * For more information on the parameters passed to this method, * please reference sati_translate_command(). * * @return Indicate if the command translation succeeded. * @retval SCI_SUCCESS This is returned if the command translation was * successful. * @retval SATI_FAILURE_CHECK_RESPONSE_DATA This value is returned if the * LBA field is not 0, the PMI bit is not 0. */ SATI_STATUS sati_read_capacity_16_translate_command( SATI_TRANSLATOR_SEQUENCE_T * sequence, void * scsi_io, void * ata_io ) { U8 * cdb = sati_cb_get_cdb_address(scsi_io); /** * SAT dictates: * - the LBA field must be 0 * - the PMI bit must be 0 */ if ( ( (sati_get_cdb_byte(cdb, 2) != 0) || (sati_get_cdb_byte(cdb, 3) != 0) || (sati_get_cdb_byte(cdb, 4) != 0) || (sati_get_cdb_byte(cdb, 5) != 0) || (sati_get_cdb_byte(cdb, 6) != 0) || (sati_get_cdb_byte(cdb, 7) != 0) || (sati_get_cdb_byte(cdb, 8) != 0) || (sati_get_cdb_byte(cdb, 9) != 0) ) || ((sati_get_cdb_byte(cdb, 14) & SCSI_READ_CAPACITY_PMI_BIT_ENABLE) == 1) ) { 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; } // The CDB is properly formed. sequence->allocation_length = (sati_get_cdb_byte(cdb, 10) << 24) | (sati_get_cdb_byte(cdb, 11) << 16) | (sati_get_cdb_byte(cdb, 12) << 8) | (sati_get_cdb_byte(cdb, 13)); sequence->type = SATI_SEQUENCE_READ_CAPACITY_16; sati_ata_identify_device_construct(ata_io, sequence); return SATI_SUCCESS; }
/** * @brief This method will translate the SCSI mode sense 6 byte command * into corresponding ATA commands. If the command is well-formed, * then the translation will result in an ATA IDENTIFY DEVICE * command. * For more information on the parameters passed to this method, * please reference sati_translate_command(). * * @return Indicate if the command translation succeeded. * @retval SCI_SUCCESS This is returned if the command translation was * successful. * @retval SATI_FAILURE_CHECK_RESPONSE_DATA This value is returned if * sense data has been created as a result of something specified * in the CDB. */ SATI_STATUS sati_mode_sense_10_translate_command( SATI_TRANSLATOR_SEQUENCE_T * sequence, void * scsi_io, void * ata_io ) { U8 * cdb = sati_cb_get_cdb_address(scsi_io); sequence->command_specific_data.scratch = 0; // Set the data length based on the allocation length field in the CDB. sequence->allocation_length = (sati_get_cdb_byte(cdb, 7) << 8) | (sati_get_cdb_byte(cdb, 8)); return sati_mode_sense_translate_command(sequence, scsi_io, ata_io, 10); }
/** * @brief This method will call Mode Select 6 Translation command * For more information on the parameters passed to this method, * please reference sati_translate_command(). * * @return Indicate if the command translation succeeded. * @retval SCI_SUCCESS This is returned if the command translation was * successful. * @retval SCI_COMPLETE This is returned if the command translation was * successful and no ATA commands need to be set. * @retval SATI_FAILURE_CHECK_RESPONSE_DATA This value is returned if * sense data has been created as a result of something specified * in the parameter data fields. */ SATI_STATUS sati_mode_select_6_translate_command( SATI_TRANSLATOR_SEQUENCE_T * sequence, void * scsi_io, void * ata_io ) { SATI_STATUS status=SATI_FAILURE; U8 * cdb = sati_cb_get_cdb_address(scsi_io); //PF bit needs to be 1 byte1 bit ???1???? if ((sati_get_cdb_byte(cdb, 1) & SCSI_MODE_SELECT_PF_MASK) == !SCSI_MODE_SELECT_PF_BIT) { 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 ); status = SATI_FAILURE_CHECK_RESPONSE_DATA; return status; } status=sati_mode_select_translate_command( sequence, scsi_io, ata_io, 6 ); if(status == SATI_FAILURE_CHECK_RESPONSE_DATA) { 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 status; }
/** * @brief This method will translate the REPORT LUN SCSI command. This * command is immediately completed, since there is no applicable * ATA/ATAPI command. The data payload is written and SATI_COMPLETE * is always returned. * For more information on the parameters passed to this method, * please reference sati_translate_command(). * * @return This method always indicates the translation is complete. * @retval SATI_COMPLETE This value is always returned. */ SATI_STATUS sati_report_luns_translate_command( SATI_TRANSLATOR_SEQUENCE_T * sequence, void * scsi_io, void * ata_io ) { U8 * cdb = sati_cb_get_cdb_address(scsi_io); // Set the data length based on the allocation length field in the CDB. sequence->allocation_length = (sati_get_cdb_byte(cdb, 6) << 24) | (sati_get_cdb_byte(cdb, 7) << 16) | (sati_get_cdb_byte(cdb, 8) << 8) | (sati_get_cdb_byte(cdb, 9)); // The first 4 bytes indicate the length of the LUN list. Each // LUN entry is 8 bytes. There is only ever LUN 0 for ATA/ATAPI // devices. The value reported is: n-7, where n is the last byte // offset (i.e. 15) in the REPORT LUN data. sati_set_data_byte(sequence, scsi_io, 0, 0); sati_set_data_byte(sequence, scsi_io, 1, 0); sati_set_data_byte(sequence, scsi_io, 2, 0); sati_set_data_byte(sequence, scsi_io, 3, 8); // Bytes 4-7 are reserved. sati_set_data_byte(sequence, scsi_io, 4, 0); sati_set_data_byte(sequence, scsi_io, 5, 0); sati_set_data_byte(sequence, scsi_io, 6, 0); sati_set_data_byte(sequence, scsi_io, 7, 0); // Add in our single LUN of zero. sati_set_data_byte(sequence, scsi_io, 8, 0); sati_set_data_byte(sequence, scsi_io, 9, 0); sati_set_data_byte(sequence, scsi_io, 10, 0); sati_set_data_byte(sequence, scsi_io, 11, 0); sati_set_data_byte(sequence, scsi_io, 12, 0); sati_set_data_byte(sequence, scsi_io, 13, 0); sati_set_data_byte(sequence, scsi_io, 14, 0); sati_set_data_byte(sequence, scsi_io, 15, 0); return SATI_COMPLETE; }
/** * @brief This method performs the SCSI VERIFY command translation * functionality common to all VERIFY command sizes. * This includes: * - setting the command register * - setting the device head register * - filling in fields in the SATI_TRANSLATOR_SEQUENCE object. * For more information on the parameters passed to this method, * please reference sati_translate_command(). * * @return Indicate if the method was successfully completed. * @retval SATI_SUCCESS This is returned in all other cases. */ static SATI_STATUS sati_verify_translate_command( SATI_TRANSLATOR_SEQUENCE_T * sequence, void * scsi_io, void * ata_io ) { U8 * cdb = sati_cb_get_cdb_address(scsi_io); U8 * register_fis = sati_cb_get_h2d_register_fis_address(ata_io); /** * The translator doesn't support performing the byte check operation. * As a result, error the request if the BYTCHK bit is set. */ if ((sati_get_cdb_byte(cdb, 1) & SCSI_VERIFY_BYTCHK_ENABLED)) { 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; } sequence->protocol = SAT_PROTOCOL_NON_DATA; sequence->data_direction = SATI_DATA_DIRECTION_NONE; sati_set_ata_device_head(register_fis, ATA_DEV_HEAD_REG_LBA_MODE_ENABLE); // Ensure the device supports the 48 bit feature set. if (sequence->device->capabilities & SATI_DEVICE_CAP_48BIT_ENABLE) sati_set_ata_command(register_fis, ATA_READ_VERIFY_SECTORS_EXT); else sati_set_ata_command(register_fis, ATA_READ_VERIFY_SECTORS); return SATI_SUCCESS; }
/** * @brief This method will translate the SCSI read 16 command into a * corresponding ATA read command. Depending upon the capabilities * supported by the target different ATA commands can be selected. * It ensures that all translation required for this command is * performed successfully. * For more information on the parameters passed to this method, * please reference sati_translate_command(). * * @return Indicate if the command translation succeeded. * @see sati_read_large_translate_command(), sati_move_translate_64_bit_lba() * for additional return values. */ SATI_STATUS sati_read_16_translate_command( SATI_TRANSLATOR_SEQUENCE_T * sequence, void * scsi_io, void * ata_io ) { SATI_STATUS status; U8 device_head = 0; U8 * cdb = sati_cb_get_cdb_address(scsi_io); U32 sector_count = (sati_get_cdb_byte(cdb, 10) << 24) | (sati_get_cdb_byte(cdb, 11) << 16) | (sati_get_cdb_byte(cdb, 12) << 8) | (sati_get_cdb_byte(cdb, 13)); if(sati_device_state_stopped(sequence, scsi_io)) { return SATI_FAILURE_CHECK_RESPONSE_DATA; } else { sequence->type = SATI_SEQUENCE_READ_16; // Translate the sector count, write command register, and check various // other parts of the CDB. status = sati_read_large_translate_command( sequence, scsi_io, ata_io, sector_count, &device_head ); // Attempt to translate the 64-bit LBA field from the SCSI request // into the 48-bits of LBA in the ATA register FIS. if (status == SATI_SUCCESS) { sati_move_translate_command(sequence, scsi_io, ata_io, device_head); status = sati_move_translate_64_bit_lba(sequence, scsi_io, ata_io); } return status; } }
/** * @brief This method will translate the ATA command * response * * @return Indicate if the command translation succeeded. * @retval SATI_COMPLETE This is returned if the command translation was * successful. * @retval SATI_FAILURE This is returned if the command translation was * unsuccessful */ SATI_STATUS sati_passthrough_translate_response( SATI_TRANSLATOR_SEQUENCE_T * sequence, void * scsi_io, void * ata_io ) { U8 * cdb; U8 * register_fis; cdb = sati_cb_get_cdb_address(scsi_io); register_fis = sati_cb_get_d2h_register_fis_address(ata_io); // Check for device errors if (sati_get_ata_status(register_fis) & ATA_STATUS_REG_ERROR_BIT) { sati_translate_error(sequence, scsi_io, (U8)sati_get_ata_error(register_fis)); return SATI_FAILURE_CHECK_RESPONSE_DATA; } sequence->state = SATI_SEQUENCE_STATE_FINAL; // If the user set the check condition bit, fill out the sense data if (PASSTHROUGH_CDB_CK_COND(cdb) || PASSTHROUGH_CDB_PROTOCOL(cdb) == PASSTHROUGH_RETURN_RESPONSE) { sati_passthrough_construct_sense( sequence, register_fis, scsi_io, SCSI_STATUS_CHECK_CONDITION, SCSI_SENSE_RECOVERED_ERROR, SCSI_ASC_NO_ADDITIONAL_SENSE, SCSI_ASCQ_ATA_PASS_THROUGH_INFORMATION_AVAILABLE ); return SATI_FAILURE_CHECK_RESPONSE_DATA; } return SATI_COMPLETE; }
/** * @brief This method perform the data translation common to all SCSI MODE * SENSE 6 byte commands. This includes building the mode page * header and block descriptor (if requested). * 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 to be used during translation. * @param[in] transfer_length This parameter specifies the size of the * mode page (including header & block descriptor). * * @return This method returns the number of bytes written into the user's * mode page data buffer. */ static U32 sati_mode_sense_6_translate_data( SATI_TRANSLATOR_SEQUENCE_T * sequence, ATA_IDENTIFY_DEVICE_DATA_T * identify, void * scsi_io, U8 transfer_length ) { U8 * cdb = sati_cb_get_cdb_address(scsi_io); U32 offset; offset = sati_mode_sense_6_build_header( sequence, scsi_io, identify, transfer_length ); // Determine if the caller disabled block descriptors (DBD). If not, // then generate a block descriptor. if ((sati_get_cdb_byte(cdb, 1) & SCSI_MODE_SENSE_DBD_ENABLE) == 0) offset += sati_mode_sense_build_std_block_descriptor( sequence, scsi_io, identify, offset ); return offset; }
/** * @brief This method will translate the SCSI Read Buffer command * into a corresponding ATA Read Buffer command. * For more information on the parameters passed to this method, * please reference sati_translate_command(). * * @return Indicates if the command translation succeeded. * @retval SATI_SUCCESS indicates that the translation was supported and occurred * without error. * @retval SATI_FAILURE_CHECK_RESPONSE_DATA This value is returned if * there is a translation failure. * @retval SATI_COMPLETE indicates that the translation was supported, occurred without * error, and no additional translation is necessary. */ SATI_STATUS sati_read_buffer_translate_command( SATI_TRANSLATOR_SEQUENCE_T * sequence, void * scsi_io, void * ata_io ) { U8 * cdb = sati_cb_get_cdb_address(scsi_io); SATI_STATUS status = SATI_FAILURE; U32 allocation_length; U32 buffer_offset; allocation_length = ((sati_get_cdb_byte(cdb, 6) << 16) | (sati_get_cdb_byte(cdb, 7) << 8) | (sati_get_cdb_byte(cdb, 8))); buffer_offset = ((sati_get_cdb_byte(cdb, 3) << 16) | (sati_get_cdb_byte(cdb, 4) << 8) | (sati_get_cdb_byte(cdb, 5))); sequence->allocation_length = allocation_length; switch(sati_get_cdb_byte(cdb, 1)) { case SATI_READ_BUFFER_MODE_DATA: if((allocation_length == 512) && (buffer_offset == 0) && (sati_get_cdb_byte(cdb, 2) == 0)) { sati_ata_read_buffer_construct(ata_io, sequence); sequence->type = SATI_SEQUENCE_READ_BUFFER; sequence->state = SATI_SEQUENCE_STATE_AWAIT_RESPONSE; status = SATI_SUCCESS; } else { 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 ); sequence->state = SATI_SEQUENCE_STATE_FINAL; status = SATI_FAILURE_CHECK_RESPONSE_DATA; } break; case SATI_READ_BUFFER_MODE_DESCRIPTOR: //allocation legnth must be at least four to return translated data if(allocation_length < 4) { 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 ); sequence->state = SATI_SEQUENCE_STATE_FINAL; status = SATI_FAILURE_CHECK_RESPONSE_DATA; } else { //figure out if we support other buffer id's sati_set_data_byte(sequence, scsi_io, 0, 0x09); //offset boundary sati_set_data_byte(sequence, scsi_io, 1, 0x00); sati_set_data_byte(sequence, scsi_io, 2, 0x02); //buffer capacity 0x200 sati_set_data_byte(sequence, scsi_io, 3, 0x00); sequence->state = SATI_SEQUENCE_STATE_FINAL; status = SATI_COMPLETE; } break; default: //Unspecified sat2v7, returning invalid cdb 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 ); sequence->state = SATI_SEQUENCE_STATE_FINAL; status = SATI_FAILURE_CHECK_RESPONSE_DATA; } return status; }
SATI_STATUS sati_atapi_translate_command( SATI_TRANSLATOR_SEQUENCE_T * sequence, SATI_DEVICE_T * sati_device, void * scsi_io, void * atapi_io ) { SATI_STATUS status; U8 * cdb = sati_cb_get_cdb_address(scsi_io); SATA_FIS_REG_H2D_T * register_fis = (SATA_FIS_REG_H2D_T *)sati_cb_get_h2d_register_fis_address(atapi_io); U8 io_direction = SATI_DATA_DIRECTION_IN; //No sense response has been set for the translation sequence yet sequence->is_sense_response_set = FALSE; // Default to no translation response required sequence->is_translate_response_required = FALSE; sequence->number_data_bytes_set = 0; sequence->device = sati_device; sequence->command_specific_data.scratch = 0; sati_cb_get_data_direction(scsi_io, &io_direction); //set sat protocol. if (io_direction == SATI_DATA_DIRECTION_NONE) sequence->protocol = SAT_PROTOCOL_PACKET_NON_DATA; else if (io_direction == SATI_DATA_DIRECTION_IN) sequence->protocol = SAT_PROTOCOL_PACKET_DMA_DATA_IN; else if (io_direction == SATI_DATA_DIRECTION_OUT) sequence->protocol = SAT_PROTOCOL_PACKET_DMA_DATA_OUT; // We don't send Report Luns command out. if (sati_get_cdb_byte(cdb, 0) == SCSI_REPORT_LUNS) { status = sati_report_luns_translate_command( sequence, scsi_io, atapi_io ); } else if (sati_cb_get_lun(scsi_io) != 0) { sati_scsi_sense_data_construct( sequence, scsi_io, SCSI_STATUS_CHECK_CONDITION, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_LOGICAL_UNIT_NOT_SUPPORTED, 0 ); status = SATI_FAILURE_CHECK_RESPONSE_DATA; } else { if (sequence->state == SATI_SEQUENCE_STATE_INCOMPLETE) { //Request Sense command is required. U8 request_sense_cdb[SATI_ATAPI_REQUEST_SENSE_CDB_LENGTH] = {0x3, 0x0, 0x0, 0x0, 0x12, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}; //set the sequence->protocol to DATA_IN anyway; sequence->protocol = SAT_PROTOCOL_PACKET_DMA_DATA_IN; //set the cdb for Request Sense using command_specific_data field. memcpy(sequence->command_specific_data.sati_atapi_data.request_sense_cdb, request_sense_cdb, SATI_ATAPI_REQUEST_SENSE_CDB_LENGTH ); } //build Packet Fis for any other command translation. register_fis->command = ATA_PACKET; register_fis->features |= ATA_PACKET_FEATURE_DMA; register_fis->fis_type = SATA_FIS_TYPE_REGH2D; register_fis->command_flag = 1; status = SATI_SUCCESS; } return status; }
/** * @brief This method will translate the SCSI Passthrough command * into the corresponding ATA command. * * @return Indicate if the command translation succeeded. * @retval SATI_SUCCESS This is returned if the command translation was * successful. * @retval SATI_FAILURE This is returned if the command translation was * unsuccessful */ SATI_STATUS sati_passthrough_16_translate_command( SATI_TRANSLATOR_SEQUENCE_T * sequence, void * scsi_io, void * ata_io ) { SATI_STATUS status; U8 * cdb; U8 * register_fis; status = SATI_FAILURE; sequence->type = SATI_SEQUENCE_ATA_PASSTHROUGH_16; sequence->state = SATI_SEQUENCE_STATE_TRANSLATE_DATA; cdb = sati_cb_get_cdb_address(scsi_io); sequence->protocol = PASSTHROUGH_CDB_PROTOCOL(cdb); register_fis = sati_cb_get_h2d_register_fis_address(ata_io); /* * CAM will send passthrough commands with protocol set to multiword * DMA even though no multiword DMA mode is selected on the device. * This is because some controllers (LSI) will only accept * ATA_PASSTHROUGH commands with DMA mode - not UDMA_IN/OUT. * * Since isci does not support multiword DMA, fix this up here. */ if (sequence->protocol == PASSTHROUGH_DMA) { if (PASSTHROUGH_CDB_T_DIR(cdb) == 0x1) { sequence->protocol = PASSTHROUGH_UDMA_DATA_IN; } else { sequence->protocol = PASSTHROUGH_UDMA_DATA_OUT; } } if (sati_passthrough_check_direction(sequence, cdb) != SATI_COMPLETE || sati_passthrough_multiple_count_error(cdb) ) { // Fail due to mismatch 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; } if (PASSTHROUGH_CDB_EXTEND(cdb) == 1) { sati_set_ata_features_exp(register_fis, sati_get_cdb_byte(cdb, 3)); sati_set_ata_sector_count_exp(register_fis, sati_get_cdb_byte(cdb, 5)); sati_set_ata_lba_low_exp(register_fis, sati_get_cdb_byte(cdb, 7)); sati_set_ata_lba_mid_exp(register_fis, sati_get_cdb_byte(cdb, 9)); sati_set_ata_lba_high_exp(register_fis, sati_get_cdb_byte(cdb, 11)); } if (PASSTHROUGH_CDB_CK_COND(cdb) || PASSTHROUGH_CDB_PROTOCOL(cdb) == PASSTHROUGH_RETURN_RESPONSE) { sequence->is_translate_response_required = TRUE; } sati_set_ata_features(register_fis, sati_get_cdb_byte(cdb, 4)); sati_set_ata_sector_count(register_fis, sati_get_cdb_byte(cdb, 6)); sati_set_ata_lba_low(register_fis, sati_get_cdb_byte(cdb, 8)); sati_set_ata_lba_mid(register_fis, sati_get_cdb_byte(cdb, 10)); sati_set_ata_lba_high(register_fis, sati_get_cdb_byte(cdb, 12)); sati_set_ata_device_head(register_fis, sati_get_cdb_byte(cdb, 13)); sati_set_ata_command(register_fis, sati_get_cdb_byte(cdb, 14)); sequence->state = SATI_SEQUENCE_STATE_AWAIT_RESPONSE; return SATI_SUCCESS; }
/** * @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] register_fis This parameter specifies the fis from which * to get the 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_passthrough_construct_sense( SATI_TRANSLATOR_SEQUENCE_T * sequence, U8 * register_fis, void * scsi_io, U8 scsi_status, U8 sense_key, U8 additional_sense_code, U8 additional_sense_code_qualifier ) { U8 * sense_data; U32 sense_len; U8 * cdb; unsigned char sector_count_upper; unsigned char lba_upper; #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, SCSI_FIXED_SENSE_DATA_BASE_LENGTH, 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); #endif // SATI_TRANSPORT_SUPPORTS_SAS sati_scsi_sense_data_construct( sequence, scsi_io, scsi_status, sense_key, additional_sense_code, additional_sense_code_qualifier ); cdb = sati_cb_get_cdb_address(scsi_io); if (sati_get_ata_sector_count_ext(register_fis) != 0) { sector_count_upper = 1; } else { sector_count_upper = 0; } if (sati_get_ata_lba_high_ext(register_fis) != 0 || sati_get_ata_lba_mid_ext(register_fis) != 0 || sati_get_ata_lba_low_ext(register_fis) != 0) { lba_upper = 1; } else { lba_upper = 0; } // Information section sati_set_sense_data_byte(sense_data, sense_len, 3, (U8)sati_get_ata_error(register_fis)); sati_set_sense_data_byte(sense_data, sense_len, 4, (U8)sati_get_ata_status(register_fis)); sati_set_sense_data_byte(sense_data, sense_len, 5, sati_get_ata_device(register_fis)); sati_set_sense_data_byte(sense_data, sense_len, 6, sati_get_ata_sector_count(register_fis)); // Command specific section sati_set_sense_data_byte(sense_data, sense_len, 8, (PASSTHROUGH_CDB_EXTEND(cdb) << 7) | (sector_count_upper << 6) | (lba_upper << 5)); sati_set_sense_data_byte(sense_data, sense_len, 9, sati_get_ata_lba_high(register_fis)); sati_set_sense_data_byte(sense_data, sense_len, 10, sati_get_ata_lba_mid(register_fis)); sati_set_sense_data_byte(sense_data, sense_len, 11, sati_get_ata_lba_low(register_fis)); sequence->is_sense_response_set = TRUE; }
/** * @brief This method will translate the inquiry SCSI command into * an ATA IDENTIFY DEVICE command. It will handle several different * VPD pages and the standard inquiry page. * For more information on the parameters passed to this method, * please reference sati_translate_command(). * * @return Indicate if the command translation succeeded. * @retval SCI_SUCCESS This is returned if the command translation was * successful. * @retval SATI_FAILURE_CHECK_RESPONSE_DATA This value is returned if * the page isn't supported, or the page code * field is not zero when the EVPD bit is 0. */ SATI_STATUS sati_inquiry_translate_command( SATI_TRANSLATOR_SEQUENCE_T * sequence, void * scsi_io, void * ata_io ) { U8 * cdb = sati_cb_get_cdb_address(scsi_io); /** * SPC dictates: * - that the page code field must be 0, if VPD enable is 0. */ if ( ((sati_get_cdb_byte(cdb, 1) & SCSI_INQUIRY_EVPD_ENABLE) == 0) && (sati_get_cdb_byte(cdb, 2) != 0) ) { 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; } // Set the data length based on the allocation length field in the CDB. sequence->allocation_length = (sati_get_cdb_byte(cdb, 3) << 8) | (sati_get_cdb_byte(cdb, 4)); // Check to see if there was a request for the vital product data or just // the standard inquiry. if (sati_get_cdb_byte(cdb, 1) & SCSI_INQUIRY_EVPD_ENABLE) { // Parse the page code to determine which translator to invoke. switch (sati_get_cdb_byte(cdb, 2)) { case SCSI_INQUIRY_SUPPORTED_PAGES_PAGE: sequence->type = SATI_SEQUENCE_INQUIRY_SUPPORTED_PAGES; sati_inquiry_supported_pages_translate_data(sequence, scsi_io); return SATI_COMPLETE; break; case SCSI_INQUIRY_UNIT_SERIAL_NUM_PAGE: sequence->type = SATI_SEQUENCE_INQUIRY_SERIAL_NUMBER; break; case SCSI_INQUIRY_DEVICE_ID_PAGE: sequence->type = SATI_SEQUENCE_INQUIRY_DEVICE_ID; break; case SCSI_INQUIRY_ATA_INFORMATION_PAGE: if(sequence->state == SATI_SEQUENCE_STATE_INCOMPLETE) { sati_ata_execute_device_diagnostic_construct( ata_io, sequence ); sequence->type = SATI_SEQUENCE_INQUIRY_EXECUTE_DEVICE_DIAG; } else { sequence->type = SATI_SEQUENCE_INQUIRY_ATA_INFORMATION; } break; case SCSI_INQUIRY_BLOCK_DEVICE_PAGE: sequence->type = SATI_SEQUENCE_INQUIRY_BLOCK_DEVICE; 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; } } else { sequence->type = SATI_SEQUENCE_INQUIRY_STANDARD; } sati_ata_identify_device_construct(ata_io, sequence); return SATI_SUCCESS; }
/** * @brief This method will translate the SCSI Write Buffer command * into a corresponding ATA Write Buffer and Download Microcode commands. * For more information on the parameters passed to this method, * please reference sati_translate_command(). * * @return Indicates if the command translation succeeded. * @retval SATI_SUCCESS indicates that the translation was supported and occurred * without error. * @retval SATI_FAILURE_CHECK_RESPONSE_DATA This value is returned if * there is a translation failure. */ SATI_STATUS sati_write_buffer_translate_command( SATI_TRANSLATOR_SEQUENCE_T * sequence, void * scsi_io, void * ata_io ) { U8 * cdb = sati_cb_get_cdb_address(scsi_io); SATI_STATUS status = SATI_FAILURE; U32 allocation_length; U32 allocation_blocks; U32 buffer_offset; allocation_length = ((sati_get_cdb_byte(cdb, 6) << 16) | (sati_get_cdb_byte(cdb, 7) << 8) | (sati_get_cdb_byte(cdb, 8))); buffer_offset = ((sati_get_cdb_byte(cdb, 3) << 16) | (sati_get_cdb_byte(cdb, 4) << 8) | (sati_get_cdb_byte(cdb, 5))); sequence->allocation_length = allocation_length; allocation_blocks = allocation_length / DOWNLOAD_MICROCODE_BLOCK_SIZE; switch(sati_get_cdb_byte(cdb, 1)) { case WRITE_BUFFER_WRITE_DATA: if((allocation_length == DOWNLOAD_MICROCODE_BLOCK_SIZE) && (buffer_offset == 0) && (sati_get_cdb_byte(cdb, 2) == 0)) { sati_ata_write_buffer_construct(ata_io, sequence); sequence->type = SATI_SEQUENCE_WRITE_BUFFER; sequence->state = SATI_SEQUENCE_STATE_AWAIT_RESPONSE; status = SATI_SUCCESS; } else { 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 ); sequence->state = SATI_SEQUENCE_STATE_FINAL; status = SATI_FAILURE_CHECK_RESPONSE_DATA; } break; case WRITE_BUFFER_DOWNLOAD_SAVE: sati_ata_download_microcode_construct( ata_io, sequence, ATA_MICROCODE_DOWNLOAD_SAVE, allocation_length, buffer_offset ); sequence->type = SATI_SEQUENCE_WRITE_BUFFER_MICROCODE; sequence->state = SATI_SEQUENCE_STATE_AWAIT_RESPONSE; status = SATI_SUCCESS; break; case WRITE_BUFFER_OFFSET_DOWNLOAD_SAVE: if(((allocation_length & 0x000001FF) == 0) && //Bits 08:00 need to be zero per SAT2v7 ((buffer_offset & 0x000001FF) == 0) && (allocation_blocks <= sequence->device->max_blocks_per_microcode_command) && ((allocation_blocks >= sequence->device->min_blocks_per_microcode_command) || (allocation_length == 0))) { sati_ata_download_microcode_construct( ata_io, sequence, ATA_MICROCODE_OFFSET_DOWNLOAD, allocation_length, buffer_offset ); sequence->type = SATI_SEQUENCE_WRITE_BUFFER_MICROCODE; sequence->state = SATI_SEQUENCE_STATE_AWAIT_RESPONSE; status = SATI_SUCCESS; } else { 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 ); sequence->state = SATI_SEQUENCE_STATE_FINAL; status = SATI_FAILURE_CHECK_RESPONSE_DATA; } break; default: //unsupported Write Buffer Mode 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 ); sequence->state = SATI_SEQUENCE_STATE_FINAL; status = SATI_FAILURE_CHECK_RESPONSE_DATA; break; } return status; }
/** * @brief This method will translate the SCSI Mode Select 6 byte or 10 byte command * into corresponding ATA commands. Depending upon the capabilities * supported by the target different ATA commands can be selected. * Additionally, in some cases more than a single ATA command may * be required. * * @return Indicate if the command translation succeeded. * @retval SCI_SUCCESS This is returned if the command translation was * successful. * @retval SCI_COMPLETE This is returned if the command translation was * successful and no ATA commands need to be set. * @retval SATI_FAILURE_CHECK_RESPONSE_DATA This value is returned if * sense data has been created as a result of something specified * in the parameter data fields. */ static SATI_STATUS sati_mode_select_translate_command( SATI_TRANSLATOR_SEQUENCE_T * sequence, void * scsi_io, void * ata_io, U32 cdb_size ) { SATI_STATUS status = SATI_FAILURE_CHECK_RESPONSE_DATA; U32 mode_page_offset; U32 block_descriptor_length; U32 index; U16 data_transfer_length; U8 current_mode_parameters[8]={0,0,0,0,0,0,0,0}; U8 * cdb = sati_cb_get_cdb_address(scsi_io); // cdb_size must be 6 or 10 if(FALSE == (cdb_size == 6 || cdb_size == 10)) { return status; } if(sequence->state == SATI_SEQUENCE_STATE_INITIAL) { sequence->command_specific_data.process_state.ata_command_sent_for_cmp = 0; sequence->state = SATI_SEQUENCE_STATE_TRANSLATE_DATA; } //First, initializes mode_sel_processing_state if ( sequence->command_specific_data.process_state.ata_command_sent_for_cmp == 0 ) { if (cdb_size == 6) { //CDB byte 4 is the parameter length data_transfer_length = sati_get_cdb_byte(cdb, 4); } else { //CDB byte 7 and 8 for Mode Select 10 data_transfer_length = (sati_get_cdb_byte(cdb, 7) << 8) + sati_get_cdb_byte(cdb, 8); } sequence->allocation_length = data_transfer_length; //Get 8 bytes for headers (4 bytes for Mode Select 6 and 8 bytes for Mode Select 10) for( index = 0; index < 8; index++ ) { sati_get_data_byte(sequence, scsi_io, index, ¤t_mode_parameters[index]); } //medium type should be 0 if ( sati_mode_select_get_medium_type(current_mode_parameters, cdb_size) != 0 ) { 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 status; } block_descriptor_length = sati_mode_select_get_mode_block_descriptor_length( current_mode_parameters, cdb_size ); mode_page_offset = sati_mode_select_get_mode_page_offset( block_descriptor_length, cdb_size ); if(mode_page_offset > data_transfer_length) { sequence->state = SATI_SEQUENCE_STATE_FINAL; status = SATI_FAILURE_CHECK_RESPONSE_DATA; } else { sati_mode_select_initialize_mode_sel_processing_state( sequence, scsi_io, ata_io, data_transfer_length, mode_page_offset ); } } // move to next mode page if(sequence->command_specific_data.process_state.current_mode_page_processed) { sequence->command_specific_data.process_state.ata_command_sent_for_cmp = 0; sequence->command_specific_data.process_state.current_mode_page_processed = FALSE; } status = sati_mode_select_process_mode_page(sequence, scsi_io, ata_io); if(sequence->command_specific_data.process_state.current_mode_page_processed != FALSE) { // Done this page sequence->state = SATI_SEQUENCE_STATE_FINAL; } else { sequence->state = SATI_SEQUENCE_STATE_INCOMPLETE; } if(status == SATI_FAILURE_CHECK_RESPONSE_DATA) { sequence->state = SATI_SEQUENCE_STATE_FINAL; 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 status; }
/** * @brief This method will translate the write long 10 & 16 SCSI commands into * ATA write uncorrectable commands. For more information on the * parameters passed to this method, please reference * sati_translate_command(). * * @return Indicate if the command translation succeeded. * @retval SCI_SUCCESS This is returned if the command translation was * successful. * @retval SATI_FAILURE_CHECK_RESPONSE_DATA is returned if there was * a problem with the translation of write long. * */ SATI_STATUS sati_write_long_translate_command( SATI_TRANSLATOR_SEQUENCE_T * sequence, void * scsi_io, void * ata_io ) { U8 * cdb = sati_cb_get_cdb_address(scsi_io); SATI_STATUS status = SATI_FAILURE; U16 byte_transfer_length; U8 device_head = 0; if((sequence->device->capabilities & SATI_DEVICE_CAP_WRITE_UNCORRECTABLE_ENABLE) == 0) { sati_scsi_sense_data_construct( sequence, scsi_io, SCSI_STATUS_CHECK_CONDITION, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INVALID_COMMAND_OPERATION_CODE, SCSI_ASCQ_INVALID_COMMAND_OPERATION_CODE ); return SATI_FAILURE_CHECK_RESPONSE_DATA; } //Write Long 10 if(sati_get_cdb_byte(cdb, 0) == SCSI_WRITE_LONG_10) { byte_transfer_length = (sati_get_cdb_byte(cdb, 7) << 8) | (sati_get_cdb_byte(cdb, 8)); sati_move_translate_32_bit_lba(sequence, scsi_io, ata_io); } else //Write Long 16 { byte_transfer_length = (sati_get_cdb_byte(cdb, 12) << 8) | (sati_get_cdb_byte(cdb, 13)); status = sati_move_translate_64_bit_lba(sequence, scsi_io, ata_io); if( status == SATI_FAILURE_CHECK_RESPONSE_DATA) { return status; } } sati_move_translate_command(sequence, scsi_io, ata_io, device_head); if( byte_transfer_length != 0 ) { 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; } switch(SATI_WRITE_LONG_GET_COR_WR_PB_BITS(cdb)) { case WR_UNCOR_BIT : if( (sequence->device->capabilities & SATI_DEVICE_CAP_MULTIPLE_SECTORS_PER_PHYSCIAL_SECTOR) != 0 ) { 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; } else { sati_ata_write_uncorrectable_construct( ata_io, sequence, ATA_WRITE_UNCORRECTABLE_PSUEDO ); sequence->type = SATI_SEQUENCE_WRITE_LONG; status = SATI_SUCCESS; } break; case WR_UNCOR_PBLOCK_BIT : sati_ata_write_uncorrectable_construct( ata_io, sequence, ATA_WRITE_UNCORRECTABLE_PSUEDO ); sequence->type = SATI_SEQUENCE_WRITE_LONG; status = SATI_SUCCESS; break; case COR_DIS_WR_UNCORR_BIT : sati_ata_write_uncorrectable_construct( ata_io, sequence, ATA_WRITE_UNCORRECTABLE_FLAGGED ); sequence->type = SATI_SEQUENCE_WRITE_LONG; status = SATI_SUCCESS; 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 status; }
/** * @brief This method will translate the SCSI request sense command * into corresponding ATA commands. Depending on supported and enabled * capabilities like SMART, different ATA commands can be selected. * For more information on the parameters passed to this method, * please reference sati_translate_command(). * * @return Indicates if the command translation succeeded. * @retval SATI_SUCCESS indicates that the translation was supported and occurred * without error. * @retval SATI_FAILURE_CHECK_RESPONSE_DATA This value is returned if * the SATII is processing a format unit commmand. * @retval SATI_COMPLETE indicates that the translation was supported, occurred without * error, and no additional translation is necessary. */ SATI_STATUS sati_request_sense_translate_command( SATI_TRANSLATOR_SEQUENCE_T * sequence, void * scsi_io, void * ata_io ) { U8 * cdb = sati_cb_get_cdb_address(scsi_io); //check if SATI is processing format unit command switch(sequence->device->state) { case SATI_DEVICE_STATE_FORMAT_UNIT_IN_PROGRESS: sati_scsi_sense_data_construct( sequence, scsi_io, SCSI_STATUS_GOOD, SCSI_SENSE_NOT_READY, SCSI_ASC_LUN_FORMAT_IN_PROGRESS, SCSI_ASCQ_LUN_FORMAT_IN_PROGRESS ); return SATI_COMPLETE; break; case SATI_DEVICE_STATE_UNIT_ATTENTION_CONDITION: sati_scsi_sense_data_construct( sequence, scsi_io, SCSI_STATUS_GOOD, SCSI_SENSE_UNIT_ATTENTION, sequence->device->unit_attention_asc, sequence->device->unit_attention_ascq ); return SATI_COMPLETE; break; //sending sense data status Idle, this is set by start_stop_unit case SATI_DEVICE_STATE_IDLE: sati_scsi_sense_data_construct( sequence, scsi_io, SCSI_STATUS_GOOD, SCSI_SENSE_NO_SENSE, SCSI_ASC_POWER_STATE_CHANGE, SCSI_ASCQ_IDLE_CONDITION_ACTIVATE_BY_COMMAND ); return SATI_COMPLETE; break; //sending sense data status Standby, this is set by start_stop_unit case SATI_DEVICE_STATE_STANDBY: sati_scsi_sense_data_construct( sequence, scsi_io, SCSI_STATUS_GOOD, SCSI_SENSE_NO_SENSE, SCSI_ASC_POWER_STATE_CHANGE, SCSI_ASCQ_STANDBY_CONDITION_ACTIVATE_BY_COMMAND ); return SATI_COMPLETE; break; case SATI_DEVICE_STATE_STOPPED: sati_scsi_sense_data_construct( sequence, scsi_io, SCSI_STATUS_GOOD, SCSI_SENSE_NO_SENSE, SCSI_ASC_NO_ADDITIONAL_SENSE, SCSI_ASCQ_NO_ADDITIONAL_SENSE ); return SATI_COMPLETE; break; default: break; } sequence->allocation_length = sati_get_cdb_byte(cdb, 4); //Check if the device has SMART support & SMART enabled if(sequence->device->capabilities & SATI_DEVICE_CAP_SMART_SUPPORT) { if(sequence->device->capabilities & SATI_DEVICE_CAP_SMART_ENABLE) { sati_ata_smart_return_status_construct( ata_io, sequence, ATA_SMART_SUB_CMD_RETURN_STATUS ); sequence->type = SATI_SEQUENCE_REQUEST_SENSE_SMART_RETURN_STATUS; return SATI_SUCCESS; } } sati_ata_check_power_mode_construct(ata_io, sequence); sequence->type = SATI_SEQUENCE_REQUEST_SENSE_CHECK_POWER_MODE; return SATI_SUCCESS; }
/** * @brief This method will be called before starting the first unmap translation * * @return Indicate if the translation was successful. * @retval SATI_SUCCESS This is returned if the command translation was * successful and no further processing. * @retval SATI_COMPLETE - The initial processing was completed successfully * @retval SATI_FAILURE_CHECK_RESPONSE_DATA - Failed the initial processing */ SATI_STATUS sati_unmap_initial_processing( SATI_TRANSLATOR_SEQUENCE_T * sequence, void * scsi_io, void * ata_io ) { SATI_UNMAP_PROCESSING_STATE_T * unmap_process_state; U8 * cdb; U16 unmap_length; U32 descriptor_length; U32 index; U32 max_dsm_blocks; U8 unmap_param_list[8]; unmap_process_state = &sequence->command_specific_data.unmap_process_state; // Set up the sequence type for unmap translation sequence->type = SATI_SEQUENCE_UNMAP; // Make sure the device is TRIM capable if ((sequence->device->capabilities & SATI_DEVICE_CAP_DSM_TRIM_SUPPORT) != SATI_DEVICE_CAP_DSM_TRIM_SUPPORT) { // Can't send TRIM request to device that does not support it 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; } // get the amount of data being sent from the cdb cdb = sati_cb_get_cdb_address(scsi_io); unmap_length = (sati_get_cdb_byte(cdb, 7) << 8) | sati_get_cdb_byte(cdb, 8); // If nothing has been requested return success now. if (unmap_length == 0) { // SAT: This is not an error return SATI_SUCCESS; } if (unmap_length < SATI_UNMAP_SIZEOF_SCSI_UNMAP_PARAMETER_LIST) { // Not enough length specified in the CDB 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; } sequence->allocation_length = unmap_length; // Get the unmap parameter header for(index = 0; index < SATI_UNMAP_SIZEOF_SCSI_UNMAP_PARAMETER_LIST; index++) { sati_get_data_byte(sequence, scsi_io, index, &unmap_param_list[index]); } descriptor_length = (unmap_param_list[2] << 8) | unmap_param_list[3]; // Check length again if (descriptor_length == 0) { // SAT: This is not an error return SATI_SUCCESS; } if ((U32)(unmap_length - SATI_UNMAP_SIZEOF_SCSI_UNMAP_PARAMETER_LIST) < descriptor_length) { // Not enough length specified in the CDB 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; } // Save the maximum unmap block descriptors in this request unmap_process_state->max_unmap_block_descriptors = descriptor_length/SATI_UNMAP_SIZEOF_SCSI_UNMAP_BLOCK_DESCRIPTOR; // Determine the maximum size of the write buffer that will be required // for the translation in terms of number of blocks max_dsm_blocks = sati_unmap_get_max_buffer_size_in_blocks(sequence); // Save the maximum number of DSM descriptors we can send during the translation unmap_process_state->max_lba_range_entries = (max_dsm_blocks*sequence->device->logical_block_size)/sizeof(TRIM_PAIR); // Get the write buffer for the translation sati_cb_allocate_dma_buffer( scsi_io, max_dsm_blocks*sequence->device->logical_block_size, &(unmap_process_state->virtual_unmap_buffer), &(unmap_process_state->physical_unmap_buffer_low), &(unmap_process_state->physical_unmap_buffer_high)); // Makes sure we have a buffer if (unmap_process_state->virtual_unmap_buffer == NULL) { // Resource failure sati_scsi_sense_data_construct( sequence, scsi_io, SCSI_STATUS_BUSY, SCSI_SENSE_NO_SENSE, SCSI_ASC_NO_ADDITIONAL_SENSE, SCSI_ASCQ_NO_ADDITIONAL_SENSE ); return SATI_FAILURE_CHECK_RESPONSE_DATA; } // Get the first SGL entry. This code will only use one 4K page so will // only utilize the first sge. sati_cb_sgl_next_sge(scsi_io, ata_io, NULL, &(unmap_process_state->unmap_buffer_sgl_pair)); // Load the first descriptor to start the translation loop unmap_process_state->current_unmap_block_descriptor_index = SATI_UNMAP_SIZEOF_SCSI_UNMAP_PARAMETER_LIST; sati_unmap_load_next_descriptor(sequence,scsi_io); // Next state will be incomplete since translation // will require a callback and possibly more requests. sequence->state = SATI_SEQUENCE_STATE_INCOMPLETE; return SATI_COMPLETE; }