#include <sys/cdefs.h>
#if !defined(DISABLE_SATI_LOG_SENSE)
#include <dev/isci/scil/sati_log_sense.h>
#include <dev/isci/scil/sati_callbacks.h>
#include <dev/isci/scil/sati_util.h>
static
void sati_supported_log_page_construct(
SATI_TRANSLATOR_SEQUENCE_T * sequence,
void * scsi_io
)
{
U32 next_byte;
sati_set_data_byte(sequence, scsi_io, 0, 0x00);
sati_set_data_byte(sequence, scsi_io, 1, 0x00);
sati_set_data_byte(sequence, scsi_io, 2, 0x00);
sati_set_data_byte(sequence, scsi_io, 3, 0x02);
next_byte = 4;
if(sequence->device->capabilities & SATI_DEVICE_CAP_SMART_SUPPORT)
{
sati_set_data_byte(
sequence,
scsi_io,
next_byte,
SCSI_LOG_PAGE_INFORMATION_EXCEPTION
);
next_byte = 5;
}
if(sequence->device->capabilities & SATI_DEVICE_CAP_SMART_SELF_TEST_SUPPORT)
{
sati_set_data_byte(
sequence,
scsi_io,
next_byte,
SCSI_LOG_PAGE_SELF_TEST
);
}
}
static
void sati_set_parameters_to_zero(
SATI_TRANSLATOR_SEQUENCE_T * sequence,
void * scsi_io
)
{
sati_set_data_byte(sequence, scsi_io, 8, 0x00);
sati_set_data_byte(sequence, scsi_io, 9, 0x00);
sati_set_data_byte(sequence, scsi_io, 10, 0x00);
sati_set_data_byte(sequence, scsi_io, 11, 0x00);
sati_set_data_byte(sequence, scsi_io, 12, 0x00);
sati_set_data_byte(sequence, scsi_io, 13, 0x00);
sati_set_data_byte(sequence, scsi_io, 14, 0x00);
sati_set_data_byte(sequence, scsi_io, 15, 0x00);
sati_set_data_byte(sequence, scsi_io, 16, 0x00);
sati_set_data_byte(sequence, scsi_io, 17, 0x00);
sati_set_data_byte(sequence, scsi_io, 18, 0x00);
sati_set_data_byte(sequence, scsi_io, 19, 0x00);
sati_set_data_byte(sequence, scsi_io, 20, 0x00);
sati_set_data_byte(sequence, scsi_io, 21, 0x00);
sati_set_data_byte(sequence, scsi_io, 22, 0x00);
sati_set_data_byte(sequence, scsi_io, 23, 0x00);
}
static
void sati_translate_sense_values(
SATI_TRANSLATOR_SEQUENCE_T * sequence,
void * scsi_io,
U8 self_test_status_byte
)
{
sati_set_data_byte(
sequence,
scsi_io,
21,
SCSI_DIAGNOSTIC_FAILURE_ON_COMPONENT
);
switch(self_test_status_byte)
{
case 1:
sati_set_data_byte(sequence, scsi_io, 20, SCSI_SENSE_ABORTED_COMMAND);
sati_set_data_byte(sequence, scsi_io, 22, 0x81);
break;
case 2:
sati_set_data_byte(sequence, scsi_io, 20, SCSI_SENSE_ABORTED_COMMAND);
sati_set_data_byte(sequence, scsi_io, 22, 0x82);
break;
case 3:
sati_set_data_byte(sequence, scsi_io, 20, SCSI_SENSE_ABORTED_COMMAND);
sati_set_data_byte(sequence, scsi_io, 22, 0x83);
break;
case 4:
sati_set_data_byte(sequence, scsi_io, 20, SCSI_SENSE_HARDWARE_ERROR);
sati_set_data_byte(sequence, scsi_io, 22, 0x84);
break;
case 5:
sati_set_data_byte(sequence, scsi_io, 20, SCSI_SENSE_HARDWARE_ERROR);
sati_set_data_byte(sequence, scsi_io, 22, 0x85);
break;
case 6:
sati_set_data_byte(sequence, scsi_io, 20, SCSI_SENSE_HARDWARE_ERROR);
sati_set_data_byte(sequence, scsi_io, 22, 0x86);
break;
case 7:
sati_set_data_byte(sequence, scsi_io, 20, SCSI_SENSE_MEDIUM_ERROR);
sati_set_data_byte(sequence, scsi_io, 22, 0x87);
break;
case 8:
sati_set_data_byte(sequence, scsi_io, 20, SCSI_SENSE_HARDWARE_ERROR);
sati_set_data_byte(sequence, scsi_io, 22, 0x88);
break;
default:
sati_set_data_byte(sequence, scsi_io, 20, SCSI_SENSE_NO_SENSE);
sati_set_data_byte(sequence, scsi_io, 21, SCSI_ASC_NO_ADDITIONAL_SENSE);
sati_set_data_byte(sequence, scsi_io, 22, 0x00);
break;
}
}
static
void sati_get_self_test_results(
SATI_TRANSLATOR_SEQUENCE_T * sequence,
void * scsi_io,
ATA_EXTENDED_SMART_SELF_TEST_LOG_T * ata_log
)
{
U16 descriptor_index = *((U16 *)(&ata_log->self_test_descriptor_index[0]));
if(descriptor_index <= 0)
{
sati_set_parameters_to_zero(sequence, scsi_io);
}
else
{
sati_set_data_byte(
sequence,
scsi_io,
8,
ata_log->descriptor_entrys[descriptor_index].DESCRIPTOR_ENTRY.status_byte
);
sati_set_data_byte(sequence, scsi_io, 9, 0x00);
sati_set_data_byte(
sequence,
scsi_io,
10,
ata_log->descriptor_entrys[descriptor_index].DESCRIPTOR_ENTRY.time_stamp_high
);
sati_set_data_byte(
sequence,
scsi_io,
11,
ata_log->descriptor_entrys[descriptor_index].DESCRIPTOR_ENTRY.time_stamp_low
);
sati_set_data_byte(sequence, scsi_io, 12, 0x00);
sati_set_data_byte(sequence, scsi_io, 13, 0x00);
sati_set_data_byte(
sequence,
scsi_io,
14,
ata_log->descriptor_entrys[descriptor_index].DESCRIPTOR_ENTRY.failing_lba_high_ext
);
sati_set_data_byte(
sequence,
scsi_io,
15,
ata_log->descriptor_entrys[descriptor_index].DESCRIPTOR_ENTRY.failing_lba_mid_ext
);
sati_set_data_byte(
sequence,
scsi_io,
16,
ata_log->descriptor_entrys[descriptor_index].DESCRIPTOR_ENTRY.failing_lba_low_ext
);
sati_set_data_byte(
sequence,
scsi_io,
17,
ata_log->descriptor_entrys[descriptor_index].DESCRIPTOR_ENTRY.failing_lba_high
);
sati_set_data_byte(
sequence,
scsi_io,
18,
ata_log->descriptor_entrys[descriptor_index].DESCRIPTOR_ENTRY.failing_lba_mid
);
sati_set_data_byte(
sequence,
scsi_io,
19,
ata_log->descriptor_entrys[descriptor_index].DESCRIPTOR_ENTRY.failing_lba_low
);
sati_translate_sense_values(
sequence,
scsi_io,
ata_log->descriptor_entrys[descriptor_index].DESCRIPTOR_ENTRY.status_byte
);
}
}
static
void sati_self_test_log_header_construct(
SATI_TRANSLATOR_SEQUENCE_T * sequence,
void * scsi_io
)
{
sati_set_data_byte(sequence, scsi_io, 0, 0x10);
sati_set_data_byte(sequence, scsi_io, 1, 0x00);
sati_set_data_byte(sequence, scsi_io, 2, 0x00);
sati_set_data_byte(sequence, scsi_io, 3, 0x14);
sati_set_data_byte(sequence, scsi_io, 4, 0x00);
sati_set_data_byte(sequence, scsi_io, 5, 0x01);
sati_set_data_byte(sequence, scsi_io, 6, 0x03);
sati_set_data_byte(sequence, scsi_io, 7, 0x10);
}
static
void sati_extended_self_test_log_page_construct(
SATI_TRANSLATOR_SEQUENCE_T * sequence,
void * scsi_io,
void * ata_data
)
{
ATA_EXTENDED_SMART_SELF_TEST_LOG_T * ata_log =
(ATA_EXTENDED_SMART_SELF_TEST_LOG_T*) ata_data;
sati_self_test_log_header_construct(sequence, scsi_io);
if( (ata_log->self_test_descriptor_index[0] == 0) &&
(ata_log->self_test_descriptor_index[1] == 0))
{
sati_set_parameters_to_zero(sequence, scsi_io);
}
else
{
sati_get_self_test_results(sequence, scsi_io, ata_log);
}
}
static
void sati_self_test_log_page_construct(
SATI_TRANSLATOR_SEQUENCE_T * sequence,
void * scsi_io,
void * ata_data
)
{
ATA_SMART_SELF_TEST_LOG_T * ata_log =
(ATA_SMART_SELF_TEST_LOG_T*) ata_data;
sati_self_test_log_header_construct(sequence, scsi_io);
sati_set_data_byte(
sequence,
scsi_io,
8,
ata_log->descriptor_entrys[0].SMART_DESCRIPTOR_ENTRY.status_byte
);
sati_set_data_byte(sequence, scsi_io, 9, 0x00);
sati_set_data_byte(
sequence,
scsi_io,
10,
ata_log->descriptor_entrys[0].SMART_DESCRIPTOR_ENTRY.time_stamp_high
);
sati_set_data_byte(
sequence,
scsi_io,
11,
ata_log->descriptor_entrys[0].SMART_DESCRIPTOR_ENTRY.time_stamp_low
);
sati_set_data_byte(sequence, scsi_io, 12, 0x00);
sati_set_data_byte(sequence, scsi_io, 13, 0x00);
sati_set_data_byte(sequence, scsi_io, 14, 0x00);
sati_set_data_byte(sequence, scsi_io, 15, 0x00);
sati_set_data_byte(
sequence,
scsi_io,
16,
ata_log->descriptor_entrys[0].SMART_DESCRIPTOR_ENTRY.failing_lba_low_ext
);
sati_set_data_byte(
sequence,
scsi_io,
17,
ata_log->descriptor_entrys[0].SMART_DESCRIPTOR_ENTRY.failing_lba_high
);
sati_set_data_byte(
sequence,
scsi_io,
18,
ata_log->descriptor_entrys[0].SMART_DESCRIPTOR_ENTRY.failing_lba_mid
);
sati_set_data_byte(
sequence,
scsi_io,
19,
ata_log->descriptor_entrys[0].SMART_DESCRIPTOR_ENTRY.failing_lba_low
);
sati_translate_sense_values(
sequence,
scsi_io,
ata_log->descriptor_entrys[0].SMART_DESCRIPTOR_ENTRY.status_byte
);
}
static
void sati_information_exception_log_page_contruct(
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 = sati_get_ata_lba_mid(register_fis);
U32 high_register = sati_get_ata_lba_high(register_fis);
sati_set_data_byte(
sequence,
scsi_io,
0,
SCSI_LOG_PAGE_INFORMATION_EXCEPTION
);
sati_set_data_byte(sequence, scsi_io, 1, 0x00);
sati_set_data_byte(sequence, scsi_io, 2, 0x00);
sati_set_data_byte(sequence, scsi_io, 3, 0x08);
sati_set_data_byte(sequence, scsi_io, 4, 0x00);
sati_set_data_byte(sequence, scsi_io, 5, 0x00);
sati_set_data_byte(sequence, scsi_io, 6, 0x03);
sati_set_data_byte(sequence, scsi_io, 7, 0x04);
if(mid_register == ATA_MID_REGISTER_THRESHOLD_EXCEEDED
&& high_register == ATA_HIGH_REGISTER_THRESHOLD_EXCEEDED)
{
sati_set_data_byte(
sequence,
scsi_io,
8,
SCSI_ASC_HARDWARE_IMPENDING_FAILURE
);
sati_set_data_byte(
sequence,
scsi_io,
9,
SCSI_ASCQ_GENERAL_HARD_DRIVE_FAILURE
);
}
else
{
sati_set_data_byte(sequence, scsi_io, 8, SCSI_ASC_NO_ADDITIONAL_SENSE);
sati_set_data_byte(sequence, scsi_io, 9, SCSI_ASCQ_NO_ADDITIONAL_SENSE);
}
sati_set_data_byte(sequence, scsi_io, 10, 0xFF);
}
SATI_STATUS sati_log_sense_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;
if(SATI_LOG_SENSE_GET_PC_FIELD(cdb) == 1 &&
(sati_get_cdb_byte(cdb, 3) == 0))
{
sequence->allocation_length = (sati_get_cdb_byte(cdb, 7) << 8) |
(sati_get_cdb_byte(cdb, 8));
switch(SATI_LOG_SENSE_GET_PAGE_CODE(cdb))
{
case SCSI_LOG_PAGE_SUPPORTED_PAGES :
sati_supported_log_page_construct(sequence, scsi_io);
sequence->type = SATI_SEQUENCE_LOG_SENSE_SUPPORTED_LOG_PAGE;
status = SATI_COMPLETE;
break;
case SCSI_LOG_PAGE_SELF_TEST :
if((sequence->device->capabilities &
SATI_DEVICE_CAP_SMART_SELF_TEST_SUPPORT) == 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
);
status = SATI_FAILURE_CHECK_RESPONSE_DATA;
}
else
{
if((sequence->device->capabilities &
SATI_DEVICE_CAP_48BIT_ENABLE))
{
sati_ata_read_log_ext_construct(
ata_io,
sequence,
ATA_LOG_PAGE_EXTENDED_SMART_SELF_TEST,
sizeof(ATA_EXTENDED_SMART_SELF_TEST_LOG_T)
);
sequence->type =
SATI_SEQUENCE_LOG_SENSE_EXTENDED_SELF_TEST_LOG_PAGE;
status = SATI_SUCCESS;
}
else
{
sati_ata_smart_read_log_construct(
ata_io,
sequence,
ATA_LOG_PAGE_SMART_SELF_TEST,
sizeof(ATA_SMART_SELF_TEST_LOG_T)
);
sequence->type = SATI_SEQUENCE_LOG_SENSE_SELF_TEST_LOG_PAGE;
status = SATI_SUCCESS;
}
}
break;
case SCSI_LOG_PAGE_INFORMATION_EXCEPTION :
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_LOG_SENSE_INFO_EXCEPTION_LOG_PAGE;
status = SATI_SUCCESS;
}
else
{
sati_scsi_sense_data_construct(
sequence,
scsi_io,
SCSI_STATUS_CHECK_CONDITION,
SCSI_SENSE_ABORTED_COMMAND,
SCSI_ASC_ATA_DEVICE_FEATURE_NOT_ENABLED,
SCSI_ASCQ_ATA_DEVICE_FEATURE_NOT_ENABLED
);
status = SATI_FAILURE_CHECK_RESPONSE_DATA;
}
}
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
);
status = SATI_FAILURE_CHECK_RESPONSE_DATA;
}
break;
default :
sati_scsi_sense_data_construct(
sequence,
scsi_io,
SCSI_STATUS_CHECK_CONDITION,
SCSI_SENSE_ILLEGAL_REQUEST,
SCSI_ASC_NO_ADDITIONAL_SENSE ,
SCSI_ASCQ_NO_ADDITIONAL_SENSE
);
status = SATI_FAILURE_CHECK_RESPONSE_DATA;
break;
}
}
return status;
}
SATI_STATUS sati_log_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);
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
{
void * ata_data = sati_cb_get_ata_data_address(ata_io);
if(ata_data == NULL)
{
return SATI_FAILURE;
}
switch(sequence->type)
{
case SATI_SEQUENCE_LOG_SENSE_EXTENDED_SELF_TEST_LOG_PAGE:
sati_extended_self_test_log_page_construct(
sequence, scsi_io, ata_data
);
status = SATI_COMPLETE;
break;
case SATI_SEQUENCE_LOG_SENSE_SELF_TEST_LOG_PAGE:
sati_self_test_log_page_construct(sequence, scsi_io, ata_data);
status = SATI_COMPLETE;
break;
case SATI_SEQUENCE_LOG_SENSE_INFO_EXCEPTION_LOG_PAGE:
sati_information_exception_log_page_contruct(
sequence, scsi_io, ata_io
);
status = SATI_COMPLETE;
break;
default:
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;
break;
}
}
return status;
}
#endif