2 * SPDX-License-Identifier: BSD-2-Clause OR GPL-2.0
4 * This file is provided under a dual BSD/GPLv2 license. When using or
5 * redistributing this file, you may do so under either license.
9 * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of version 2 of the GNU General Public License as
13 * published by the Free Software Foundation.
15 * This program is distributed in the hope that it will be useful, but
16 * WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
23 * The full GNU General Public License is included in this distribution
24 * in the file called LICENSE.GPL.
28 * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
29 * All rights reserved.
31 * Redistribution and use in source and binary forms, with or without
32 * modification, are permitted provided that the following conditions
35 * * Redistributions of source code must retain the above copyright
36 * notice, this list of conditions and the following disclaimer.
37 * * Redistributions in binary form must reproduce the above copyright
38 * notice, this list of conditions and the following disclaimer in
39 * the documentation and/or other materials provided with the
42 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
43 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
44 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
45 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
46 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
47 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
48 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
49 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
50 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
51 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
52 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
55 #include <sys/cdefs.h>
56 __FBSDID("$FreeBSD$");
60 * @brief This file contains the method definitions to translate
61 * SCSI Log Sense command based of the SATv2 spec.
64 #if !defined(DISABLE_SATI_LOG_SENSE)
66 #include <dev/isci/scil/sati_log_sense.h>
67 #include <dev/isci/scil/sati_callbacks.h>
68 #include <dev/isci/scil/sati_util.h>
70 //******************************************************************************
71 //* P R I V A T E M E T H O D S
72 //******************************************************************************
75 * @brief This method constructs the SATI supported log page. This is a log
76 * containing the page codes of all the SATI supported log pages.
82 void sati_supported_log_page_construct(
83 SATI_TRANSLATOR_SEQUENCE_T * sequence,
88 //set SPF = 0 and PAGE_CODE = 0
89 sati_set_data_byte(sequence, scsi_io, 0, 0x00);
91 //set SUBPAGE_CODE = 0
92 sati_set_data_byte(sequence, scsi_io, 1, 0x00);
94 //set the Page Length to (n-3) or 2 because only two log pages are supported
95 sati_set_data_byte(sequence, scsi_io, 2, 0x00);
96 sati_set_data_byte(sequence, scsi_io, 3, 0x02);
98 //specify the next byte to be set
101 if(sequence->device->capabilities & SATI_DEVICE_CAP_SMART_SUPPORT)
107 SCSI_LOG_PAGE_INFORMATION_EXCEPTION
112 if(sequence->device->capabilities & SATI_DEVICE_CAP_SMART_SELF_TEST_SUPPORT)
118 SCSI_LOG_PAGE_SELF_TEST
124 * @brief This method sets bytes 4-19 of the self-test log parameter to zero.
130 void sati_set_parameters_to_zero(
131 SATI_TRANSLATOR_SEQUENCE_T * sequence,
135 sati_set_data_byte(sequence, scsi_io, 8, 0x00); //log_parameter byte 4
136 sati_set_data_byte(sequence, scsi_io, 9, 0x00); //log_parameter byte 5
137 sati_set_data_byte(sequence, scsi_io, 10, 0x00); //log_parameter byte 6
138 sati_set_data_byte(sequence, scsi_io, 11, 0x00); //log_parameter byte 7
139 sati_set_data_byte(sequence, scsi_io, 12, 0x00); //log_parameter byte 8
140 sati_set_data_byte(sequence, scsi_io, 13, 0x00); //log_parameter byte 9
141 sati_set_data_byte(sequence, scsi_io, 14, 0x00); //log_parameter byte 10
142 sati_set_data_byte(sequence, scsi_io, 15, 0x00); //log_parameter byte 11
143 sati_set_data_byte(sequence, scsi_io, 16, 0x00); //log_parameter byte 12
144 sati_set_data_byte(sequence, scsi_io, 17, 0x00); //log_parameter byte 13
145 sati_set_data_byte(sequence, scsi_io, 18, 0x00); //log_parameter byte 14
146 sati_set_data_byte(sequence, scsi_io, 19, 0x00); //log_parameter byte 15
147 sati_set_data_byte(sequence, scsi_io, 20, 0x00); //log_parameter byte 16
148 sati_set_data_byte(sequence, scsi_io, 21, 0x00); //log_parameter byte 17
149 sati_set_data_byte(sequence, scsi_io, 22, 0x00); //log_parameter byte 18
150 sati_set_data_byte(sequence, scsi_io, 23, 0x00); //log_parameter byte 19
154 * @brief This method translates the ATA Extended SMART self-test log into
155 * SCSI Sense Key, Additional Sense Code, and Additional Sense code
156 * qualifiers based on the self test status byte in the appropriate
163 void sati_translate_sense_values(
164 SATI_TRANSLATOR_SEQUENCE_T * sequence,
166 U8 self_test_status_byte
174 SCSI_DIAGNOSTIC_FAILURE_ON_COMPONENT
177 switch(self_test_status_byte)
181 sati_set_data_byte(sequence, scsi_io, 20, SCSI_SENSE_ABORTED_COMMAND);
184 sati_set_data_byte(sequence, scsi_io, 22, 0x81);
189 sati_set_data_byte(sequence, scsi_io, 20, SCSI_SENSE_ABORTED_COMMAND);
192 sati_set_data_byte(sequence, scsi_io, 22, 0x82);
197 sati_set_data_byte(sequence, scsi_io, 20, SCSI_SENSE_ABORTED_COMMAND);
200 sati_set_data_byte(sequence, scsi_io, 22, 0x83);
205 sati_set_data_byte(sequence, scsi_io, 20, SCSI_SENSE_HARDWARE_ERROR);
208 sati_set_data_byte(sequence, scsi_io, 22, 0x84);
213 sati_set_data_byte(sequence, scsi_io, 20, SCSI_SENSE_HARDWARE_ERROR);
216 sati_set_data_byte(sequence, scsi_io, 22, 0x85);
221 sati_set_data_byte(sequence, scsi_io, 20, SCSI_SENSE_HARDWARE_ERROR);
224 sati_set_data_byte(sequence, scsi_io, 22, 0x86);
229 sati_set_data_byte(sequence, scsi_io, 20, SCSI_SENSE_MEDIUM_ERROR);
232 sati_set_data_byte(sequence, scsi_io, 22, 0x87);
237 sati_set_data_byte(sequence, scsi_io, 20, SCSI_SENSE_HARDWARE_ERROR);
240 sati_set_data_byte(sequence, scsi_io, 22, 0x88);
245 sati_set_data_byte(sequence, scsi_io, 20, SCSI_SENSE_NO_SENSE);
247 sati_set_data_byte(sequence, scsi_io, 21, SCSI_ASC_NO_ADDITIONAL_SENSE);
249 sati_set_data_byte(sequence, scsi_io, 22, 0x00);
256 * @brief This method retrieves the correct self-test results by checking the
257 * descriptor index in the extended SMART self-test log. The index is
258 * used to determine the appropriate descriptor entry.
264 void sati_get_self_test_results(
265 SATI_TRANSLATOR_SEQUENCE_T * sequence,
267 ATA_EXTENDED_SMART_SELF_TEST_LOG_T * ata_log
270 U16 descriptor_index = *((U16 *)(&ata_log->self_test_descriptor_index[0]));
273 * SATv2 wants data from descriptor N where N is equal to
274 * (descriptor_index - parameter_code) + 1. Since parameter
275 * code is always 0x0001 just checking descriptor_index.
278 if(descriptor_index <= 0)
280 sati_set_parameters_to_zero(sequence, scsi_io);
288 ata_log->descriptor_entrys[descriptor_index].DESCRIPTOR_ENTRY.status_byte
291 //Sef-test number unspecified per satv2
292 sati_set_data_byte(sequence, scsi_io, 9, 0x00);
297 ata_log->descriptor_entrys[descriptor_index].DESCRIPTOR_ENTRY.time_stamp_high
304 ata_log->descriptor_entrys[descriptor_index].DESCRIPTOR_ENTRY.time_stamp_low
307 //set to zero because it's a 48bit address
308 sati_set_data_byte(sequence, scsi_io, 12, 0x00);
309 sati_set_data_byte(sequence, scsi_io, 13, 0x00);
315 ata_log->descriptor_entrys[descriptor_index].DESCRIPTOR_ENTRY.failing_lba_high_ext
322 ata_log->descriptor_entrys[descriptor_index].DESCRIPTOR_ENTRY.failing_lba_mid_ext
329 ata_log->descriptor_entrys[descriptor_index].DESCRIPTOR_ENTRY.failing_lba_low_ext
336 ata_log->descriptor_entrys[descriptor_index].DESCRIPTOR_ENTRY.failing_lba_high
343 ata_log->descriptor_entrys[descriptor_index].DESCRIPTOR_ENTRY.failing_lba_mid
350 ata_log->descriptor_entrys[descriptor_index].DESCRIPTOR_ENTRY.failing_lba_low
353 sati_translate_sense_values(
356 ata_log->descriptor_entrys[descriptor_index].DESCRIPTOR_ENTRY.status_byte
362 * @brief This method will construct the first eight bytes of the SCSI self test
363 * log page for both cases when SATI sends a ATA read log ext and a smart
370 void sati_self_test_log_header_construct(
371 SATI_TRANSLATOR_SEQUENCE_T * sequence,
375 //PAGE CODE for Self-Test Log Page
376 sati_set_data_byte(sequence, scsi_io, 0, 0x10);
377 sati_set_data_byte(sequence, scsi_io, 1, 0x00);
379 //PAGE LENGTH is 0x14 instead of 0x190, not returning 20/0x190 log perameters
380 sati_set_data_byte(sequence, scsi_io, 2, 0x00);
381 sati_set_data_byte(sequence, scsi_io, 3, 0x14);
384 * Log PARAMETER 0x0001
385 * Only sending one log parameter per self-test request.
387 sati_set_data_byte(sequence, scsi_io, 4, 0x00); //log_parameter byte 0
388 sati_set_data_byte(sequence, scsi_io, 5, 0x01); //log_parameter byte 1
390 //Set to 0x03 per SATv2 spec
391 sati_set_data_byte(sequence, scsi_io, 6, 0x03); //log_parameter byte 2
393 //Parameter Length set to 0x10 per SATv2 spec
394 sati_set_data_byte(sequence, scsi_io, 7, 0x10); //log_parameter byte 3
398 * @brief This method will construct the SCSI self test log page from
399 * the Extended SMART self-test log response received from the
400 * ATA device. The response is from a ATA_Read_Log_EXT command
407 void sati_extended_self_test_log_page_construct(
408 SATI_TRANSLATOR_SEQUENCE_T * sequence,
413 ATA_EXTENDED_SMART_SELF_TEST_LOG_T * ata_log =
414 (ATA_EXTENDED_SMART_SELF_TEST_LOG_T*) ata_data;
416 sati_self_test_log_header_construct(sequence, scsi_io);
419 if( (ata_log->self_test_descriptor_index[0] == 0) &&
420 (ata_log->self_test_descriptor_index[1] == 0))
422 sati_set_parameters_to_zero(sequence, scsi_io);
426 sati_get_self_test_results(sequence, scsi_io, ata_log);
431 * @brief This method will construct the SCSI self test log page from
432 * the SMART self-test log response received from the ATA device.
433 * The response is from a ATA_SMART_Read_Log command issued by SATI.
439 void sati_self_test_log_page_construct(
440 SATI_TRANSLATOR_SEQUENCE_T * sequence,
445 ATA_SMART_SELF_TEST_LOG_T * ata_log =
446 (ATA_SMART_SELF_TEST_LOG_T*) ata_data;
448 sati_self_test_log_header_construct(sequence, scsi_io);
450 //first descriptor entry(index == 0) is always used because scsi_parameter_code == 1
455 ata_log->descriptor_entrys[0].SMART_DESCRIPTOR_ENTRY.status_byte
458 //Sef-test number unspecified per satv2
459 sati_set_data_byte(sequence, scsi_io, 9, 0x00);
465 ata_log->descriptor_entrys[0].SMART_DESCRIPTOR_ENTRY.time_stamp_high
472 ata_log->descriptor_entrys[0].SMART_DESCRIPTOR_ENTRY.time_stamp_low
475 //set to zero because it's a 28bit address
476 sati_set_data_byte(sequence, scsi_io, 12, 0x00);
477 sati_set_data_byte(sequence, scsi_io, 13, 0x00);
478 sati_set_data_byte(sequence, scsi_io, 14, 0x00);
479 sati_set_data_byte(sequence, scsi_io, 15, 0x00);
485 ata_log->descriptor_entrys[0].SMART_DESCRIPTOR_ENTRY.failing_lba_low_ext
492 ata_log->descriptor_entrys[0].SMART_DESCRIPTOR_ENTRY.failing_lba_high
499 ata_log->descriptor_entrys[0].SMART_DESCRIPTOR_ENTRY.failing_lba_mid
506 ata_log->descriptor_entrys[0].SMART_DESCRIPTOR_ENTRY.failing_lba_low
509 sati_translate_sense_values(
512 ata_log->descriptor_entrys[0].SMART_DESCRIPTOR_ENTRY.status_byte
517 * @brief This method will construct the SCSI information exception log page from
518 * the ATA SMART response received from the ATA device. The response is
519 * from a ATA SMART return status command issued by SATI.
525 void sati_information_exception_log_page_contruct(
526 SATI_TRANSLATOR_SEQUENCE_T * sequence,
531 U8 * register_fis = sati_cb_get_d2h_register_fis_address(ata_io);
532 U32 mid_register = sati_get_ata_lba_mid(register_fis);
533 U32 high_register = sati_get_ata_lba_high(register_fis);
535 //Information Exception Page code
540 SCSI_LOG_PAGE_INFORMATION_EXCEPTION
544 sati_set_data_byte(sequence, scsi_io, 1, 0x00);
546 //Page length of log parameters
547 sati_set_data_byte(sequence, scsi_io, 2, 0x00);
548 sati_set_data_byte(sequence, scsi_io, 3, 0x08);
551 sati_set_data_byte(sequence, scsi_io, 4, 0x00);
552 sati_set_data_byte(sequence, scsi_io, 5, 0x00);
555 sati_set_data_byte(sequence, scsi_io, 6, 0x03);
557 sati_set_data_byte(sequence, scsi_io, 7, 0x04);
559 if(mid_register == ATA_MID_REGISTER_THRESHOLD_EXCEEDED
560 && high_register == ATA_HIGH_REGISTER_THRESHOLD_EXCEEDED)
566 SCSI_ASC_HARDWARE_IMPENDING_FAILURE
573 SCSI_ASCQ_GENERAL_HARD_DRIVE_FAILURE
578 sati_set_data_byte(sequence, scsi_io, 8, SCSI_ASC_NO_ADDITIONAL_SENSE);
579 sati_set_data_byte(sequence, scsi_io, 9, SCSI_ASCQ_NO_ADDITIONAL_SENSE);
581 //setting most recent temperature reading to 0xFF(not supported) for now.
582 sati_set_data_byte(sequence, scsi_io, 10, 0xFF);
585 //******************************************************************************
586 //* P U B L I C M E T H O D S
587 //******************************************************************************
590 * @brief This method will translate the SCSI Log Sense command into ATA commands
591 * specified by SATv2. ATA commands Read Log EXT and SMART Read Log will
592 * be issued by this translation.
594 * @return SATI_STATUS Indicates if the command translation succeeded.
597 SATI_STATUS sati_log_sense_translate_command(
598 SATI_TRANSLATOR_SEQUENCE_T * sequence,
603 U8 * cdb = sati_cb_get_cdb_address(scsi_io);
604 SATI_STATUS status = SATI_FAILURE;
606 if(SATI_LOG_SENSE_GET_PC_FIELD(cdb) == 1 &&
607 (sati_get_cdb_byte(cdb, 3) == 0))
609 sequence->allocation_length = (sati_get_cdb_byte(cdb, 7) << 8) |
610 (sati_get_cdb_byte(cdb, 8));
612 switch(SATI_LOG_SENSE_GET_PAGE_CODE(cdb))
614 //Return Supported Log Pages log page
615 case SCSI_LOG_PAGE_SUPPORTED_PAGES :
616 sati_supported_log_page_construct(sequence, scsi_io);
617 sequence->type = SATI_SEQUENCE_LOG_SENSE_SUPPORTED_LOG_PAGE;
618 status = SATI_COMPLETE;
621 //Return Self-Test Results log page
622 case SCSI_LOG_PAGE_SELF_TEST :
624 if((sequence->device->capabilities &
625 SATI_DEVICE_CAP_SMART_SELF_TEST_SUPPORT) == 0)
627 sati_scsi_sense_data_construct(
630 SCSI_STATUS_CHECK_CONDITION,
631 SCSI_SENSE_ILLEGAL_REQUEST,
632 SCSI_ASC_INVALID_FIELD_IN_CDB,
633 SCSI_ASCQ_INVALID_FIELD_IN_CDB
635 status = SATI_FAILURE_CHECK_RESPONSE_DATA;
639 //check if 48-bit Address feature set is supported
640 if((sequence->device->capabilities &
641 SATI_DEVICE_CAP_48BIT_ENABLE))
643 //ATA Read Log Ext with log address set to 0x07
644 sati_ata_read_log_ext_construct(
647 ATA_LOG_PAGE_EXTENDED_SMART_SELF_TEST,
648 sizeof(ATA_EXTENDED_SMART_SELF_TEST_LOG_T)
651 SATI_SEQUENCE_LOG_SENSE_EXTENDED_SELF_TEST_LOG_PAGE;
652 status = SATI_SUCCESS;
656 //ATA Smart Read Log with log address set to 0x06
657 sati_ata_smart_read_log_construct(
660 ATA_LOG_PAGE_SMART_SELF_TEST,
661 sizeof(ATA_SMART_SELF_TEST_LOG_T)
663 sequence->type = SATI_SEQUENCE_LOG_SENSE_SELF_TEST_LOG_PAGE;
664 status = SATI_SUCCESS;
669 //Return Informational Exceptions log page
670 case SCSI_LOG_PAGE_INFORMATION_EXCEPTION :
671 if(sequence->device->capabilities & SATI_DEVICE_CAP_SMART_SUPPORT)
673 if(sequence->device->capabilities & SATI_DEVICE_CAP_SMART_ENABLE)
675 sati_ata_smart_return_status_construct(
678 ATA_SMART_SUB_CMD_RETURN_STATUS
681 SATI_SEQUENCE_LOG_SENSE_INFO_EXCEPTION_LOG_PAGE;
682 status = SATI_SUCCESS;
686 sati_scsi_sense_data_construct(
689 SCSI_STATUS_CHECK_CONDITION,
690 SCSI_SENSE_ABORTED_COMMAND,
691 SCSI_ASC_ATA_DEVICE_FEATURE_NOT_ENABLED,
692 SCSI_ASCQ_ATA_DEVICE_FEATURE_NOT_ENABLED
695 status = SATI_FAILURE_CHECK_RESPONSE_DATA;
700 sati_scsi_sense_data_construct(
703 SCSI_STATUS_CHECK_CONDITION,
704 SCSI_SENSE_ILLEGAL_REQUEST,
705 SCSI_ASC_INVALID_FIELD_IN_CDB,
706 SCSI_ASCQ_INVALID_FIELD_IN_CDB
709 status = SATI_FAILURE_CHECK_RESPONSE_DATA;
713 //UNSPECIFIED SATv2r9
714 sati_scsi_sense_data_construct(
717 SCSI_STATUS_CHECK_CONDITION,
718 SCSI_SENSE_ILLEGAL_REQUEST,
719 SCSI_ASC_NO_ADDITIONAL_SENSE ,
720 SCSI_ASCQ_NO_ADDITIONAL_SENSE
722 status = SATI_FAILURE_CHECK_RESPONSE_DATA;
730 * @brief This method will translate the response to the SATI Log Sense
731 * translation. ATA command responses will be translated into the
732 * correct SCSI log pages to be returned by SATI.
734 * @return SATI_STATUS Indicates if the response translation succeeded.
737 SATI_STATUS sati_log_sense_translate_response(
738 SATI_TRANSLATOR_SEQUENCE_T * sequence,
743 U8 * register_fis = sati_cb_get_d2h_register_fis_address(ata_io);
744 SATI_STATUS status = SATI_FAILURE;
746 if(sati_get_ata_status(register_fis) & ATA_STATUS_REG_ERROR_BIT)
748 sati_scsi_sense_data_construct(
751 SCSI_STATUS_CHECK_CONDITION,
752 SCSI_SENSE_ABORTED_COMMAND,
753 SCSI_ASC_NO_ADDITIONAL_SENSE ,
754 SCSI_ASCQ_NO_ADDITIONAL_SENSE
756 status = SATI_FAILURE_CHECK_RESPONSE_DATA;
761 void * ata_data = sati_cb_get_ata_data_address(ata_io);
768 switch(sequence->type)
770 case SATI_SEQUENCE_LOG_SENSE_EXTENDED_SELF_TEST_LOG_PAGE:
771 sati_extended_self_test_log_page_construct(
772 sequence, scsi_io, ata_data
775 status = SATI_COMPLETE;
778 case SATI_SEQUENCE_LOG_SENSE_SELF_TEST_LOG_PAGE:
779 sati_self_test_log_page_construct(sequence, scsi_io, ata_data);
780 status = SATI_COMPLETE;
783 case SATI_SEQUENCE_LOG_SENSE_INFO_EXCEPTION_LOG_PAGE:
784 //This function needs a d->h register fis, not ata data
785 sati_information_exception_log_page_contruct(
786 sequence, scsi_io, ata_io
789 status = SATI_COMPLETE;
793 sati_scsi_sense_data_construct(
796 SCSI_STATUS_CHECK_CONDITION,
797 SCSI_SENSE_ABORTED_COMMAND,
798 SCSI_ASC_NO_ADDITIONAL_SENSE ,
799 SCSI_ASCQ_NO_ADDITIONAL_SENSE
801 status = SATI_FAILURE_CHECK_RESPONSE_DATA;
808 #endif // !defined(DISABLE_SATI_LOG_SENSE)