/** * @brief This method will translate the ATA CHECK POWER MODE register FIS * response into an appropriate SCSI response. * For more information on the parameters passed to this method, * please reference sati_translate_response(). * * @return Indicate if the response translation succeeded. * @retval SCI_SUCCESS This is returned if the data translation was * successful. */ SATI_STATUS sati_test_unit_ready_translate_response( SATI_TRANSLATOR_SEQUENCE_T * sequence, void * scsi_io, void * ata_io ) { U8 * register_fis = sati_cb_get_d2h_register_fis_address(ata_io); /** * SAT dictates: * - If the ATA CHECK POWER MODE command returns an error, then * return sense data indicating the LOGICAL UNIT DOES NOT RESPONSE * TO SELECTION. * - All other cases are considered successful. */ if (sati_get_ata_status(register_fis) & ATA_STATUS_REG_ERROR_BIT) { sati_scsi_sense_data_construct( sequence, scsi_io, SCSI_STATUS_CHECK_CONDITION, SCSI_SENSE_NOT_READY, SCSI_ASC_LUN_NOT_RESPOND_TO_SELECTION, SCSI_ASCQ_LUN_NOT_RESPOND_TO_SELECTION ); return SATI_FAILURE_CHECK_RESPONSE_DATA; } return SATI_COMPLETE; }
/** * @brief This method will conduct error handling for the ATA Set Features command * that is issued during a Mode Select translation for the Caching Mode * page. * * * @return Indicate if the command translation succeeded. * * @retval SCI_COMPLETE This is returned if the command translation was * successful and no additional 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 an error returned */ SATI_STATUS sati_mode_select_translate_response( SATI_TRANSLATOR_SEQUENCE_T * sequence, void * scsi_io, void * ata_io ) { U8 * register_fis = sati_cb_get_d2h_register_fis_address(ata_io); SATI_STATUS status = SATI_FAILURE; if(sati_get_ata_status(register_fis) & ATA_STATUS_REG_ERROR_BIT) { sati_scsi_sense_data_construct( sequence, scsi_io, SCSI_STATUS_CHECK_CONDITION, SCSI_SENSE_ABORTED_COMMAND, SCSI_ASC_NO_ADDITIONAL_SENSE, SCSI_ASCQ_NO_ADDITIONAL_SENSE ); status = SATI_FAILURE_CHECK_RESPONSE_DATA; } else { if (sequence->state == SATI_SEQUENCE_STATE_INCOMPLETE) { status = SATI_SEQUENCE_INCOMPLETE; } else { status = SATI_COMPLETE; } } return status; }
/** * @brief This method finishes the construction of the SCSI data associated with a request for the ATA information vital product data (VPD) page. The ATA device signature is written into the data response from the task fle registers after issuing a Execute Device Diagnostic command. * * @param[in] sequence This parameter specifies the translator sequence * object to be utilized during data translation. * @param[out] scsi_io This parameter specifies the user IO request for * which to construct the ATA information page. * @param[in] ata_io This parameter specifies the ATA payload * buffer location and size to be translated. * * @return none */ void sati_inquiry_ata_information_finish_translation( SATI_TRANSLATOR_SEQUENCE_T * sequence, void * scsi_io, void * ata_io ) { U8 * register_fis = sati_cb_get_d2h_register_fis_address(ata_io); U32 offset; //SATA transport sati_set_data_byte(sequence, scsi_io, 36, 0x34); sati_set_data_byte(sequence, scsi_io, 37, 0x00); sati_set_data_byte(sequence, scsi_io, 38, (U8) sati_get_ata_status(register_fis)); sati_set_data_byte(sequence, scsi_io, 39, (U8) sati_get_ata_error(register_fis)); sati_set_data_byte(sequence, scsi_io, 40, sati_get_ata_lba_low(register_fis)); sati_set_data_byte(sequence, scsi_io, 41, sati_get_ata_lba_mid(register_fis)); sati_set_data_byte(sequence, scsi_io, 42, sati_get_ata_lba_high(register_fis)); sati_set_data_byte(sequence, scsi_io, 43, sati_get_ata_device(register_fis)); sati_set_data_byte(sequence, scsi_io, 44, sati_get_ata_lba_low_ext(register_fis)); sati_set_data_byte(sequence, scsi_io, 45, sati_get_ata_lba_mid_ext(register_fis)); sati_set_data_byte(sequence, scsi_io, 46, sati_get_ata_lba_high_ext(register_fis)); sati_set_data_byte(sequence, scsi_io, 47, 0x00); sati_set_data_byte(sequence, scsi_io, 48, sati_get_ata_sector_count(register_fis)); sati_set_data_byte(sequence, scsi_io, 49, sati_get_ata_sector_count_exp(register_fis)); for(offset = 50; offset < 56; offset++) { sati_set_data_byte(sequence, scsi_io, offset, 0x00); } sequence->state = SATI_SEQUENCE_STATE_FINAL; }
/** * @brief This method will translate the response to the SATI Write Long * translation. This response is only error checking the * ATA Write Uncorrectable command. * * @return SATI_STATUS Indicates if the response translation succeeded. * @retval SCI_COMPLETE 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_response( SATI_TRANSLATOR_SEQUENCE_T * sequence, void * scsi_io, void * ata_io ) { U8 * register_fis = sati_cb_get_d2h_register_fis_address(ata_io); if (sati_get_ata_status(register_fis) & ATA_STATUS_REG_ERROR_BIT) { sati_scsi_sense_data_construct( sequence, scsi_io, SCSI_STATUS_CHECK_CONDITION, SCSI_SENSE_ABORTED_COMMAND, SCSI_ASC_COMMAND_SEQUENCE_ERROR, SCSI_ASCQ_NO_ADDITIONAL_SENSE ); return SATI_FAILURE_CHECK_RESPONSE_DATA; } else { return SATI_COMPLETE; } }
/** * @brief This method will complete the Read Buffer Translation by copying the ATA response data into the SCSI request DATA buffer. * For more information on the parameters passed to this method, * please reference sati_translate_command(). * * @return Indicates if the command translation succeeded. * @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_response( SATI_TRANSLATOR_SEQUENCE_T * sequence, void * scsi_io, void * ata_io ) { U8 * register_fis = sati_cb_get_d2h_register_fis_address(ata_io); U8 ata_status = (U8) sati_get_ata_status(register_fis); SATI_STATUS status = SATI_COMPLETE; if (ata_status & ATA_STATUS_REG_ERROR_BIT) { sati_scsi_sense_data_construct( sequence, scsi_io, SCSI_STATUS_CHECK_CONDITION, SCSI_SENSE_ABORTED_COMMAND, SCSI_ASC_NO_ADDITIONAL_SENSE, SCSI_ASCQ_NO_ADDITIONAL_SENSE ); status = SATI_FAILURE_CHECK_RESPONSE_DATA; } else { void * ata_data = sati_cb_get_ata_data_address(ata_io); if(ata_data == NULL) { status = SATI_FAILURE; } else { //copy ATA data into SCSI data buffer sati_copy_data( sequence, scsi_io, 0, ata_data, 512 ); } } sequence->state = SATI_SEQUENCE_STATE_FINAL; return status; }
/** * @brief This method will complete the Write Buffer Translation by checking * for ATA errors and then creating a unit attention condition for * changed microcode. * * @return Indicates if the command translation succeeded. * @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_write_buffer_translate_response( SATI_TRANSLATOR_SEQUENCE_T * sequence, void * scsi_io, void * ata_io ) { U8 * register_fis = sati_cb_get_d2h_register_fis_address(ata_io); U8 ata_status = (U8) sati_get_ata_status(register_fis); SATI_STATUS status = SATI_FAILURE; if (ata_status & ATA_STATUS_REG_ERROR_BIT) { sati_scsi_sense_data_construct( sequence, scsi_io, SCSI_STATUS_CHECK_CONDITION, SCSI_SENSE_ABORTED_COMMAND, SCSI_ASC_NO_ADDITIONAL_SENSE, SCSI_ASCQ_NO_ADDITIONAL_SENSE ); status = SATI_FAILURE_CHECK_RESPONSE_DATA; } else { switch(sequence->type) { case SATI_SEQUENCE_WRITE_BUFFER_MICROCODE: sati_scsi_sense_data_construct( sequence, scsi_io, SCSI_STATUS_GOOD, SCSI_SENSE_UNIT_ATTENTION, SCSI_ASC_MICROCODE_HAS_CHANGED, SCSI_ASCQ_MICROCODE_HAS_CHANGED ); status = SATI_COMPLETE; break; default: status = SATI_COMPLETE; break; } } sequence->state = SATI_SEQUENCE_STATE_FINAL; return status; }
SATI_STATUS sati_atapi_translate_command_response( SATI_TRANSLATOR_SEQUENCE_T * sequence, void * scsi_io, void * atapi_io ) { SATI_STATUS status = SATI_COMPLETE; U8 * register_fis = sati_cb_get_d2h_register_fis_address(atapi_io); U8 ata_status; /** * If the device fault bit is set in the status register, then * set the sense data and return. */ ata_status = (U8) sati_get_ata_status(register_fis); if (ata_status & ATA_STATUS_REG_DEVICE_FAULT_BIT) { sati_scsi_sense_data_construct( sequence, scsi_io, SCSI_STATUS_CHECK_CONDITION, SCSI_SENSE_HARDWARE_ERROR, SCSI_ASC_INTERNAL_TARGET_FAILURE, SCSI_ASCQ_INTERNAL_TARGET_FAILURE ); sequence->device->state = SATI_DEVICE_STATE_DEVICE_FAULT_OCCURRED; return SATI_FAILURE_CHECK_RESPONSE_DATA; } else if (ata_status & ATA_STATUS_REG_ERROR_BIT) { //reset the register_fis. memset(register_fis, 0, sizeof(SATA_FIS_REG_D2H_T)); //Internal Request Sense command is needed. sequence->state = SATI_SEQUENCE_STATE_INCOMPLETE; return SATI_SEQUENCE_INCOMPLETE; } return status; }
/** * @brief This method will translate the ATA command register FIS * response into an appropriate SCSI response for Unmap. * For more information on the parameters passed to this method, * please reference sati_translate_response(). * * @return Indicate if the response translation succeeded. * @retval SATI_SUCCESS This is returned if the command translation was * successful. * @retval SATI_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_unmap_translate_response( SATI_TRANSLATOR_SEQUENCE_T * sequence, void * scsi_io, void * ata_io ) { U8 * register_fis = sati_cb_get_d2h_register_fis_address(ata_io); SATI_UNMAP_PROCESSING_STATE_T * unmap_process_state; SATI_STATUS sati_status = SATI_COMPLETE; unmap_process_state = &sequence->command_specific_data.unmap_process_state; if (sati_get_ata_status(register_fis) & ATA_STATUS_REG_ERROR_BIT) { sequence->state = SATI_SEQUENCE_STATE_FINAL; sati_scsi_sense_data_construct( sequence, scsi_io, SCSI_STATUS_CHECK_CONDITION, SCSI_SENSE_ABORTED_COMMAND, SCSI_ASC_NO_ADDITIONAL_SENSE, SCSI_ASCQ_NO_ADDITIONAL_SENSE ); // All done, terminate the translation sati_unmap_terminate(sequence, scsi_io, ata_io); } else { if (sequence->state != SATI_SEQUENCE_STATE_INCOMPLETE) { // All done, terminate the translation sati_unmap_terminate(sequence, scsi_io, ata_io); } else { // Still translating sati_status = SATI_SEQUENCE_STATE_INCOMPLETE; } } return sati_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 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 response to the SATI Request Sense * translation. ATA_Check_Power_Mode and ATA_SMART_Return_Status will * be translated into a SCSI sense data response. * * @return SATI_STATUS Indicates if the response translation succeeded. * */ SATI_STATUS sati_request_sense_translate_response( SATI_TRANSLATOR_SEQUENCE_T * sequence, void * scsi_io, void * ata_io ) { U8 * register_fis = sati_cb_get_d2h_register_fis_address(ata_io); U32 mid_register; U32 high_register; U32 sector_count; SATI_STATUS status = SATI_FAILURE; if(sati_get_ata_status(register_fis) & ATA_STATUS_REG_ERROR_BIT) { sati_scsi_sense_data_construct( sequence, scsi_io, SCSI_STATUS_CHECK_CONDITION, SCSI_SENSE_ABORTED_COMMAND, SCSI_ASC_NO_ADDITIONAL_SENSE , SCSI_ASCQ_NO_ADDITIONAL_SENSE ); status = SATI_FAILURE_CHECK_RESPONSE_DATA; } else { switch(sequence->type) { case SATI_SEQUENCE_REQUEST_SENSE_SMART_RETURN_STATUS: mid_register = sati_get_ata_lba_mid(register_fis); high_register = sati_get_ata_lba_high(register_fis); if(mid_register == ATA_MID_REGISTER_THRESHOLD_EXCEEDED && high_register == ATA_HIGH_REGISTER_THRESHOLD_EXCEEDED) { sati_request_sense_data_response_construct( sequence, scsi_io, SCSI_SENSE_NO_SENSE, SCSI_ASC_HARDWARE_IMPENDING_FAILURE, SCSI_ASCQ_GENERAL_HARD_DRIVE_FAILURE ); status = SATI_COMPLETE; } else { sati_request_sense_data_response_construct( sequence, scsi_io, SCSI_SENSE_NO_SENSE, SCSI_ASC_NO_ADDITIONAL_SENSE, SCSI_ASCQ_NO_ADDITIONAL_SENSE ); status = SATI_COMPLETE; } break; case SATI_SEQUENCE_REQUEST_SENSE_CHECK_POWER_MODE: sector_count = sati_get_ata_sector_count(register_fis); switch(sector_count) { case ATA_STANDBY_POWER_MODE: sati_request_sense_data_response_construct( sequence, scsi_io, SCSI_SENSE_NO_SENSE, SCSI_ASC_POWER_STATE_CHANGE, SCSI_ASCQ_POWER_STATE_CHANGE_TO_STANDBY ); status = SATI_COMPLETE; break; case ATA_IDLE_POWER_MODE: sati_request_sense_data_response_construct( sequence, scsi_io, SCSI_SENSE_NO_SENSE, SCSI_ASC_POWER_STATE_CHANGE, SCSI_ASCQ_POWER_STATE_CHANGE_TO_IDLE ); status = SATI_COMPLETE; break; case ATA_ACTIVE_POWER_MODE: sati_request_sense_data_response_construct( sequence, scsi_io, SCSI_SENSE_NO_SENSE, SCSI_ASC_NO_ADDITIONAL_SENSE, SCSI_ASCQ_NO_ADDITIONAL_SENSE ); status = SATI_COMPLETE; break; default: break; } break; default: sati_request_sense_data_response_construct( sequence, scsi_io, SCSI_SENSE_NO_SENSE, SCSI_ASC_NO_ADDITIONAL_SENSE, SCSI_ASCQ_NO_ADDITIONAL_SENSE ); status = SATI_COMPLETE; } } return status; }