1230557Sjimharris /*- 2230557Sjimharris * This file is provided under a dual BSD/GPLv2 license. When using or 3230557Sjimharris * redistributing this file, you may do so under either license. 4230557Sjimharris * 5230557Sjimharris * GPL LICENSE SUMMARY 6230557Sjimharris * 7230557Sjimharris * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. 8230557Sjimharris * 9230557Sjimharris * This program is free software; you can redistribute it and/or modify 10230557Sjimharris * it under the terms of version 2 of the GNU General Public License as 11230557Sjimharris * published by the Free Software Foundation. 12230557Sjimharris * 13230557Sjimharris * This program is distributed in the hope that it will be useful, but 14230557Sjimharris * WITHOUT ANY WARRANTY; without even the implied warranty of 15230557Sjimharris * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16230557Sjimharris * General Public License for more details. 17230557Sjimharris * 18230557Sjimharris * You should have received a copy of the GNU General Public License 19230557Sjimharris * along with this program; if not, write to the Free Software 20230557Sjimharris * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. 21230557Sjimharris * The full GNU General Public License is included in this distribution 22230557Sjimharris * in the file called LICENSE.GPL. 23230557Sjimharris * 24230557Sjimharris * BSD LICENSE 25230557Sjimharris * 26230557Sjimharris * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. 27230557Sjimharris * All rights reserved. 28230557Sjimharris * 29230557Sjimharris * Redistribution and use in source and binary forms, with or without 30230557Sjimharris * modification, are permitted provided that the following conditions 31230557Sjimharris * are met: 32230557Sjimharris * 33230557Sjimharris * * Redistributions of source code must retain the above copyright 34230557Sjimharris * notice, this list of conditions and the following disclaimer. 35230557Sjimharris * * Redistributions in binary form must reproduce the above copyright 36230557Sjimharris * notice, this list of conditions and the following disclaimer in 37230557Sjimharris * the documentation and/or other materials provided with the 38230557Sjimharris * distribution. 39230557Sjimharris * 40230557Sjimharris * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 41230557Sjimharris * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 42230557Sjimharris * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 43230557Sjimharris * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 44230557Sjimharris * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 45230557Sjimharris * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 46230557Sjimharris * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 47230557Sjimharris * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 48230557Sjimharris * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 49230557Sjimharris * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 50230557Sjimharris * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 51230557Sjimharris */ 52230557Sjimharris 53230557Sjimharris#include <sys/cdefs.h> 54230557Sjimharris__FBSDID("$FreeBSD$"); 55230557Sjimharris 56230557Sjimharris/** 57230557Sjimharris * @file 58230557Sjimharris * @brief This file contains the method implementations required to 59230557Sjimharris * translate the SCSI mode sense (6 and 10-byte) commands. 60230557Sjimharris */ 61230557Sjimharris 62230557Sjimharris#if !defined(DISABLE_SATI_MODE_SENSE) 63230557Sjimharris 64230557Sjimharris#include <dev/isci/scil/sati_mode_sense.h> 65230557Sjimharris#include <dev/isci/scil/sati_mode_pages.h> 66230557Sjimharris#include <dev/isci/scil/sati_callbacks.h> 67230557Sjimharris#include <dev/isci/scil/sati_util.h> 68230557Sjimharris#include <dev/isci/scil/intel_scsi.h> 69230557Sjimharris#include <dev/isci/scil/intel_ata.h> 70230557Sjimharris 71230557Sjimharris//****************************************************************************** 72230557Sjimharris//* P R I V A T E M E T H O D S 73230557Sjimharris//****************************************************************************** 74230557Sjimharris 75230557Sjimharris#define STANDBY_TIMER_DISABLED 0x00 76230557Sjimharris#define STANDBY_TIMER_ENABLED 0x01 77230557Sjimharris#define STANDBY_TIMER_SUPPORTED 0x2000 78230557Sjimharris 79230557Sjimharris 80230557Sjimharris 81230557Sjimharris/** 82230557Sjimharris * @brief This method indicates if the supplied page control is supported 83230557Sjimharris * by this translation implementation. Currently savable parameters 84230557Sjimharris * (i.e. non-volatile) are not supported. 85230557Sjimharris * For more information on the parameters passed to this method, 86230557Sjimharris * please reference sati_translate_command(). 87230557Sjimharris * 88230557Sjimharris * @return This method returns an indication of whether the page control 89230557Sjimharris * specified in the SCSI CDB is supported. 90230557Sjimharris * @retval SATI_SUCCESS This value is returned if the page control is 91230557Sjimharris * supported. 92230557Sjimharris * @retval SATI_FAILURE_CHECK_RESPONSE_DATA This value is returned if the 93230557Sjimharris * page control is not supported. 94230557Sjimharris */ 95230557Sjimharrisstatic 96230557SjimharrisSATI_STATUS sati_mode_sense_is_page_control_supported( 97230557Sjimharris SATI_TRANSLATOR_SEQUENCE_T * sequence, 98230557Sjimharris void * scsi_io 99230557Sjimharris) 100230557Sjimharris{ 101230557Sjimharris U8 * cdb = sati_cb_get_cdb_address(scsi_io); 102230557Sjimharris 103230557Sjimharris switch (sati_get_cdb_byte(cdb, 2) >> SCSI_MODE_SENSE_PC_SHIFT) 104230557Sjimharris { 105230557Sjimharris case SCSI_MODE_SENSE_PC_CURRENT: 106230557Sjimharris case SCSI_MODE_SENSE_PC_DEFAULT: 107230557Sjimharris case SCSI_MODE_SENSE_PC_CHANGEABLE: 108230557Sjimharris return SATI_SUCCESS; 109230557Sjimharris break; 110230557Sjimharris 111230557Sjimharris default: 112230557Sjimharris case SCSI_MODE_SENSE_PC_SAVED: 113230557Sjimharris sati_scsi_sense_data_construct( 114230557Sjimharris sequence, 115230557Sjimharris scsi_io, 116230557Sjimharris SCSI_STATUS_CHECK_CONDITION, 117230557Sjimharris SCSI_SENSE_ILLEGAL_REQUEST, 118230557Sjimharris SCSI_ASC_SAVING_PARMS_NOT_SUPPORTED, 119230557Sjimharris SCSI_ASCQ_SAVING_PARMS_NOT_SUPPORTED 120230557Sjimharris ); 121230557Sjimharris return SATI_FAILURE_CHECK_RESPONSE_DATA; 122230557Sjimharris break; 123230557Sjimharris } 124230557Sjimharris} 125230557Sjimharris 126230557Sjimharris/** 127230557Sjimharris * @brief This method indicates if the page code field in the SCSI CDB 128230557Sjimharris * is supported by this translation. 129230557Sjimharris * For more information on the parameters passed to this method, 130230557Sjimharris * please reference sati_translate_command(). 131230557Sjimharris * 132230557Sjimharris * @param[in] cdb_length This parameter specifies the length of the SCSI 133230557Sjimharris * CDB being translated (e.g. 6-byte, 10-byte, 12-byte, etc.) 134230557Sjimharris * 135230557Sjimharris * @return This method returns an indication as to whether the page code 136230557Sjimharris * in the CDB is supported. 137230557Sjimharris * @retval SATI_SUCCESS This value is returned if the page code is 138230557Sjimharris * supported. 139230557Sjimharris * @retval SATI_FAILURE_CHECK_RESPONSE_DATA This value is returned if the 140230557Sjimharris * page code is not supported. 141230557Sjimharris */ 142230557Sjimharrisstatic 143230557SjimharrisSATI_STATUS sati_mode_sense_is_page_code_supported( 144230557Sjimharris SATI_TRANSLATOR_SEQUENCE_T * sequence, 145230557Sjimharris void * scsi_io, 146230557Sjimharris U8 cdb_length 147230557Sjimharris) 148230557Sjimharris{ 149230557Sjimharris U8 * cdb = sati_cb_get_cdb_address(scsi_io); 150230557Sjimharris 151230557Sjimharris switch (sati_get_cdb_byte(cdb, 2) & SCSI_MODE_SENSE_PAGE_CODE_ENABLE) 152230557Sjimharris { 153230557Sjimharris case SCSI_MODE_PAGE_CACHING: 154230557Sjimharris if (sati_get_cdb_byte(cdb, 0) == SCSI_MODE_SENSE_6) 155230557Sjimharris sequence->type = SATI_SEQUENCE_MODE_SENSE_6_CACHING; 156230557Sjimharris else 157230557Sjimharris sequence->type = SATI_SEQUENCE_MODE_SENSE_10_CACHING; 158230557Sjimharris break; 159230557Sjimharris 160230557Sjimharris case SCSI_MODE_PAGE_ALL_PAGES: 161230557Sjimharris if (sati_get_cdb_byte(cdb, 0) == SCSI_MODE_SENSE_6) 162230557Sjimharris sequence->type = SATI_SEQUENCE_MODE_SENSE_6_ALL_PAGES; 163230557Sjimharris else 164230557Sjimharris sequence->type = SATI_SEQUENCE_MODE_SENSE_10_ALL_PAGES; 165230557Sjimharris break; 166230557Sjimharris 167230557Sjimharris case SCSI_MODE_PAGE_READ_WRITE_ERROR: 168230557Sjimharris if (sati_get_cdb_byte(cdb, 0) == SCSI_MODE_SENSE_6) 169230557Sjimharris sequence->type = SATI_SEQUENCE_MODE_SENSE_6_READ_WRITE_ERROR; 170230557Sjimharris else 171230557Sjimharris sequence->type = SATI_SEQUENCE_MODE_SENSE_10_READ_WRITE_ERROR; 172230557Sjimharris break; 173230557Sjimharris 174230557Sjimharris case SCSI_MODE_PAGE_DISCONNECT_RECONNECT: 175230557Sjimharris if (sati_get_cdb_byte(cdb, 0) == SCSI_MODE_SENSE_6) 176230557Sjimharris sequence->type = SATI_SEQUENCE_MODE_SENSE_6_DISCONNECT_RECONNECT; 177230557Sjimharris else 178230557Sjimharris sequence->type = SATI_SEQUENCE_MODE_SENSE_10_DISCONNECT_RECONNECT; 179230557Sjimharris break; 180230557Sjimharris 181230557Sjimharris case SCSI_MODE_PAGE_CONTROL: 182230557Sjimharris if (sati_get_cdb_byte(cdb, 0) == SCSI_MODE_SENSE_6) 183230557Sjimharris sequence->type = SATI_SEQUENCE_MODE_SENSE_6_CONTROL; 184230557Sjimharris else 185230557Sjimharris sequence->type = SATI_SEQUENCE_MODE_SENSE_10_CONTROL; 186230557Sjimharris break; 187230557Sjimharris 188230557Sjimharris case SCSI_MODE_PAGE_POWER_CONDITION: 189230557Sjimharris if (sati_get_cdb_byte(cdb, 0) == SCSI_MODE_SENSE_6) 190230557Sjimharris sequence->type = SATI_SEQUENCE_MODE_SENSE_6_POWER_CONDITION; 191230557Sjimharris else 192230557Sjimharris sequence->type = SATI_SEQUENCE_MODE_SENSE_10_POWER_CONDITION; 193230557Sjimharris break; 194230557Sjimharris 195230557Sjimharris case SCSI_MODE_PAGE_INFORMATIONAL_EXCP_CONTROL: 196230557Sjimharris // The informational exceptions control page is only useful 197230557Sjimharris // if SMART is supported. 198230557Sjimharris if ((sequence->device->capabilities | SATI_DEVICE_CAP_SMART_SUPPORT) 199230557Sjimharris == 0) 200230557Sjimharris { 201230557Sjimharris // For a MODE SENSE, utilize INVALID FIELD IN CDB, 202230557Sjimharris // For a MODE SELECT, utilize INVALID FIELD IN PARAMETER LIST. 203230557Sjimharris if (sati_get_cdb_byte(cdb, 0) == SCSI_MODE_SENSE_6) 204230557Sjimharris { 205230557Sjimharris sati_scsi_sense_data_construct( 206230557Sjimharris sequence, 207230557Sjimharris scsi_io, 208230557Sjimharris SCSI_STATUS_CHECK_CONDITION, 209230557Sjimharris SCSI_SENSE_ILLEGAL_REQUEST, 210230557Sjimharris SCSI_ASC_INVALID_FIELD_IN_CDB, 211230557Sjimharris SCSI_ASCQ_INVALID_FIELD_IN_CDB 212230557Sjimharris ); 213230557Sjimharris } 214230557Sjimharris else 215230557Sjimharris { 216230557Sjimharris sati_scsi_sense_data_construct( 217230557Sjimharris sequence, 218230557Sjimharris scsi_io, 219230557Sjimharris SCSI_STATUS_CHECK_CONDITION, 220230557Sjimharris SCSI_SENSE_ILLEGAL_REQUEST, 221230557Sjimharris SCSI_ASC_INVALID_FIELD_IN_PARM_LIST, 222230557Sjimharris SCSI_ASCQ_INVALID_FIELD_IN_PARM_LIST 223230557Sjimharris ); 224230557Sjimharris } 225230557Sjimharris 226230557Sjimharris return SATI_FAILURE_CHECK_RESPONSE_DATA; 227230557Sjimharris } 228230557Sjimharris 229230557Sjimharris if (sati_get_cdb_byte(cdb, 0) == SCSI_MODE_SENSE_6) 230230557Sjimharris sequence->type = SATI_SEQUENCE_MODE_SENSE_6_INFORMATIONAL_EXCP_CONTROL; 231230557Sjimharris else 232230557Sjimharris sequence->type = SATI_SEQUENCE_MODE_SENSE_10_INFORMATIONAL_EXCP_CONTROL; 233230557Sjimharris break; 234230557Sjimharris 235230557Sjimharris default: 236230557Sjimharris sati_scsi_sense_data_construct( 237230557Sjimharris sequence, 238230557Sjimharris scsi_io, 239230557Sjimharris SCSI_STATUS_CHECK_CONDITION, 240230557Sjimharris SCSI_SENSE_ILLEGAL_REQUEST, 241230557Sjimharris SCSI_ASC_INVALID_FIELD_IN_CDB, 242230557Sjimharris SCSI_ASCQ_INVALID_FIELD_IN_CDB 243230557Sjimharris ); 244230557Sjimharris return SATI_FAILURE_CHECK_RESPONSE_DATA; 245230557Sjimharris break; 246230557Sjimharris } 247230557Sjimharris 248230557Sjimharris return SATI_SUCCESS; 249230557Sjimharris} 250230557Sjimharris 251230557Sjimharris//****************************************************************************** 252230557Sjimharris//* P R O T E C T E D M E T H O D S 253230557Sjimharris//****************************************************************************** 254230557Sjimharris 255230557Sjimharris/** 256230557Sjimharris * @brief This method will calculate the size of the mode sense data header. 257230557Sjimharris * This includes the block descriptor if one is requested. 258230557Sjimharris * 259230557Sjimharris * @param[in] scsi_io This parameter specifies the user's SCSI IO object 260230557Sjimharris * for which to calculate the mode page header. 261230557Sjimharris * @param[in] cdb_size This parameter specifies the number of bytes 262230557Sjimharris * associated with the CDB for which to calculate the header. 263230557Sjimharris * 264230557Sjimharris * @return This method returns the size, in bytes, for the mode page header. 265230557Sjimharris */ 266230557SjimharrisU16 sati_mode_sense_calculate_page_header( 267230557Sjimharris void * scsi_io, 268230557Sjimharris U8 cdb_size 269230557Sjimharris) 270230557Sjimharris{ 271230557Sjimharris U8 * cdb = sati_cb_get_cdb_address(scsi_io); 272230557Sjimharris U16 page_length = 0; 273230557Sjimharris 274230557Sjimharris // The Mode page header length is different for 6-byte vs. 10-byte CDBs. 275230557Sjimharris if (cdb_size == 6) 276230557Sjimharris page_length += SCSI_MODE_SENSE_6_HEADER_LENGTH; 277230557Sjimharris else 278230557Sjimharris page_length += SCSI_MODE_SENSE_10_HEADER_LENGTH; 279230557Sjimharris 280230557Sjimharris // Are block descriptors disabled (DBD)? 0 indicates they are enabled. 281230557Sjimharris if ((sati_get_cdb_byte(cdb, 1) & SCSI_MODE_SENSE_DBD_ENABLE) == 0) 282230557Sjimharris { 283230557Sjimharris // The LLBAA bit is not defined for 6-byte mode sense requests. 284230557Sjimharris if ( (cdb_size == 10) 285230557Sjimharris && (sati_get_cdb_byte(cdb, 1) & SCSI_MODE_SENSE_LLBAA_ENABLE) ) 286230557Sjimharris page_length += SCSI_MODE_SENSE_LLBA_BLOCK_DESCRIPTOR_LENGTH; 287230557Sjimharris else 288230557Sjimharris page_length += SCSI_MODE_SENSE_STD_BLOCK_DESCRIPTOR_LENGTH; 289230557Sjimharris } 290230557Sjimharris 291230557Sjimharris return page_length; 292230557Sjimharris} 293230557Sjimharris 294230557Sjimharris/** 295230557Sjimharris * @brief This method performs command translation common to all mode sense 296230557Sjimharris * requests (6 or 10 byte). 297230557Sjimharris * For more information on the parameters passed to this method, 298230557Sjimharris * please reference sati_translate_command(). 299230557Sjimharris * 300230557Sjimharris * @param[in] cdb_length This parameter specifies the number of bytes 301230557Sjimharris * in the CDB (6 or 10). 302230557Sjimharris * 303230557Sjimharris * @return This method returns an indication as to whether the translation 304230557Sjimharris * succeeded. 305230557Sjimharris * @retval SCI_SUCCESS This value is returned if translation succeeded. 306230557Sjimharris * @see sati_mode_sense_is_page_control_supported() or 307230557Sjimharris * sati_mode_sense_is_page_code_supported() for more information. 308230557Sjimharris */ 309230557SjimharrisSATI_STATUS sati_mode_sense_translate_command( 310230557Sjimharris SATI_TRANSLATOR_SEQUENCE_T * sequence, 311230557Sjimharris void * scsi_io, 312230557Sjimharris void * ata_io, 313230557Sjimharris U8 cdb_length 314230557Sjimharris) 315230557Sjimharris{ 316230557Sjimharris SATI_STATUS status; 317230557Sjimharris 318230557Sjimharris /** 319230557Sjimharris * Validate that the supplied page control (PC) field is supported. 320230557Sjimharris */ 321230557Sjimharris status = sati_mode_sense_is_page_control_supported(sequence, scsi_io); 322230557Sjimharris if (status != SATI_SUCCESS) 323230557Sjimharris return status; 324230557Sjimharris 325230557Sjimharris /** 326230557Sjimharris * Validate that the supplied page code is supported. 327230557Sjimharris */ 328230557Sjimharris status = sati_mode_sense_is_page_code_supported(sequence,scsi_io,cdb_length); 329230557Sjimharris if (status != SATI_SUCCESS) 330230557Sjimharris return status; 331230557Sjimharris 332230557Sjimharris sati_ata_identify_device_construct(ata_io, sequence); 333230557Sjimharris 334230557Sjimharris return SATI_SUCCESS; 335230557Sjimharris} 336230557Sjimharris 337230557Sjimharris/** 338230557Sjimharris * @brief This method will build the standard block descriptor for a MODE 339230557Sjimharris * SENSE 6 or 10 byte request. 340230557Sjimharris * For more information on the parameters passed to this method, 341230557Sjimharris * please reference sati_translate_command(). 342230557Sjimharris * 343230557Sjimharris * @param[in] identify This parameter specifies the IDENTIFY DEVICE data 344230557Sjimharris * associated with the SCSI IO. 345230557Sjimharris * @param[in] offset This parameter specifies the offset into the data 346230557Sjimharris * buffer at which to build the block descriptor. 347230557Sjimharris * 348230557Sjimharris * @return This method returns the size of the block descriptor built. 349230557Sjimharris */ 350230557SjimharrisU32 sati_mode_sense_build_std_block_descriptor( 351230557Sjimharris SATI_TRANSLATOR_SEQUENCE_T * sequence, 352230557Sjimharris void * scsi_io, 353230557Sjimharris ATA_IDENTIFY_DEVICE_DATA_T * identify, 354230557Sjimharris U32 offset 355230557Sjimharris) 356230557Sjimharris{ 357230557Sjimharris U32 lba_low = 0; 358230557Sjimharris U32 lba_high = 0; 359230557Sjimharris U32 sector_size = 0; 360230557Sjimharris 361230557Sjimharris // Extract the sector information (sector size, logical blocks) from 362230557Sjimharris // the retrieved ATA identify device data. 363230557Sjimharris sati_ata_identify_device_get_sector_info( 364230557Sjimharris identify, &lba_high, &lba_low, §or_size 365230557Sjimharris ); 366230557Sjimharris 367230557Sjimharris // Fill in the 4-byte logical block address field. 368230557Sjimharris sati_set_data_byte(sequence, scsi_io, offset, (U8)((lba_low>>24) & 0xFF)); 369230557Sjimharris sati_set_data_byte(sequence, scsi_io, offset+1, (U8)((lba_low>>16) & 0xFF)); 370230557Sjimharris sati_set_data_byte(sequence, scsi_io, offset+2, (U8)((lba_low>>8) & 0xFF)); 371230557Sjimharris sati_set_data_byte(sequence, scsi_io, offset+3, (U8)(lba_low & 0xFF)); 372230557Sjimharris 373230557Sjimharris // Clear the reserved field. 374230557Sjimharris sati_set_data_byte(sequence, scsi_io, offset+4, 0); 375230557Sjimharris 376230557Sjimharris // Fill in the three byte Block Length field 377230557Sjimharris sati_set_data_byte(sequence,scsi_io, offset+5, (U8)((sector_size>>16) & 0xFF)); 378230557Sjimharris sati_set_data_byte(sequence,scsi_io, offset+6, (U8)((sector_size>>8) & 0xFF)); 379230557Sjimharris sati_set_data_byte(sequence,scsi_io, offset+7, (U8)(sector_size & 0xFF)); 380230557Sjimharris 381230557Sjimharris return SCSI_MODE_SENSE_STD_BLOCK_DESCRIPTOR_LENGTH; 382230557Sjimharris} 383230557Sjimharris 384230557Sjimharris/** 385230557Sjimharris * @brief This method simply copies the mode sense data into the buffer 386230557Sjimharris * at the location specified by page_start. The buffer copied is 387230557Sjimharris * determined by page_control (e.g. current, default, or changeable 388230557Sjimharris * values). 389230557Sjimharris * For more information on the parameters passed to this method, 390230557Sjimharris * please reference sati_translate_command(). 391230557Sjimharris * 392230557Sjimharris * @param[in] page_start This parameter specifies the starting offset at 393230557Sjimharris * which to copy the mode page data. 394230557Sjimharris * @param[in] page_control This parameter specifies the page control 395230557Sjimharris * indicating the source buffer to be copied. 396230557Sjimharris * @param[in] page_code This specifies the mode sense page to copy. 397230557Sjimharris * 398230557Sjimharris * @return This method returns the size of the mode page data being copied. 399230557Sjimharris */ 400230557SjimharrisU32 sati_mode_sense_copy_initial_data( 401230557Sjimharris SATI_TRANSLATOR_SEQUENCE_T * sequence, 402230557Sjimharris void * scsi_io, 403230557Sjimharris U32 page_start, 404230557Sjimharris U8 page_control, 405230557Sjimharris U8 page_code 406230557Sjimharris) 407230557Sjimharris{ 408230557Sjimharris U16 page_index = sati_mode_page_get_page_index(page_code); 409230557Sjimharris U32 page_length = sat_mode_page_sizes[page_index]; 410230557Sjimharris 411230557Sjimharris // Find out if the current values are requested or if the default 412230557Sjimharris // values are being requested. 413230557Sjimharris if (page_control == SCSI_MODE_SENSE_PC_CHANGEABLE) 414230557Sjimharris { 415230557Sjimharris // Copy the changeable mode page information. 416230557Sjimharris sati_copy_data( 417230557Sjimharris sequence, 418230557Sjimharris scsi_io, 419230557Sjimharris page_start, 420230557Sjimharris sat_changeable_mode_pages[page_index], 421230557Sjimharris page_length 422230557Sjimharris ); 423230557Sjimharris } 424230557Sjimharris else 425230557Sjimharris { 426230557Sjimharris // Copy the default static values template to the user data area. 427230557Sjimharris sati_copy_data( 428230557Sjimharris sequence, 429230557Sjimharris scsi_io, 430230557Sjimharris page_start, 431230557Sjimharris sat_default_mode_pages[page_index], 432230557Sjimharris page_length 433230557Sjimharris ); 434230557Sjimharris } 435230557Sjimharris 436230557Sjimharris return page_length; 437230557Sjimharris} 438230557Sjimharris 439230557Sjimharris/** 440230557Sjimharris * @brief This method performs the read/write error recovery mode page 441230557Sjimharris * specific data translation based upon the contents of the remote 442230557Sjimharris * device IDENTIFY DEVICE data. 443230557Sjimharris * For more information on the parameters passed to this method, 444230557Sjimharris * please reference sati_translate_command(). 445230557Sjimharris * 446230557Sjimharris * @param[in] identify This parameter specifies the remote device's 447230557Sjimharris * IDENTIFY DEVICE data received as part of the IO request. 448230557Sjimharris * @param[in] offset This parameter specifies the offset into the data 449230557Sjimharris * buffer where the translated data is to be written. 450230557Sjimharris * 451230557Sjimharris * @return This method returns the size of the mode page data that was 452230557Sjimharris * translated. 453230557Sjimharris */ 454230557SjimharrisU32 sati_mode_sense_read_write_error_translate_data( 455230557Sjimharris SATI_TRANSLATOR_SEQUENCE_T * sequence, 456230557Sjimharris void * scsi_io, 457230557Sjimharris ATA_IDENTIFY_DEVICE_DATA_T * identify, 458230557Sjimharris U32 offset 459230557Sjimharris) 460230557Sjimharris{ 461230557Sjimharris U8 * cdb = sati_cb_get_cdb_address(scsi_io); 462230557Sjimharris U8 page_control = sati_get_cdb_byte(cdb, 2) >> SCSI_MODE_SENSE_PC_SHIFT; 463230557Sjimharris U32 page_length; 464230557Sjimharris 465230557Sjimharris page_length = sati_mode_sense_copy_initial_data( 466230557Sjimharris sequence, 467230557Sjimharris scsi_io, 468230557Sjimharris offset, 469230557Sjimharris page_control, 470230557Sjimharris SCSI_MODE_PAGE_READ_WRITE_ERROR 471230557Sjimharris ); 472230557Sjimharris 473230557Sjimharris // Currently we do not override any bits in this mode page from the 474230557Sjimharris // identify data. 475230557Sjimharris 476230557Sjimharris return page_length; 477230557Sjimharris} 478230557Sjimharris 479230557Sjimharris/** 480230557Sjimharris * @brief This method performs the disconnect/reconnect mode page 481230557Sjimharris * specific data translation based upon the contents of the remote 482230557Sjimharris * device IDENTIFY DEVICE data. 483230557Sjimharris * For more information on the parameters passed to this method, 484230557Sjimharris * please reference sati_translate_command(). 485230557Sjimharris * 486230557Sjimharris * @param[in] identify This parameter specifies the remote device's 487230557Sjimharris * IDENTIFY DEVICE data received as part of the IO request. 488230557Sjimharris * @param[in] offset This parameter specifies the offset into the data 489230557Sjimharris * buffer where the translated data is to be written. 490230557Sjimharris * 491230557Sjimharris * @return This method returns the size of the mode page data that was 492230557Sjimharris * translated. 493230557Sjimharris */ 494230557SjimharrisU32 sati_mode_sense_disconnect_reconnect_translate_data( 495230557Sjimharris SATI_TRANSLATOR_SEQUENCE_T * sequence, 496230557Sjimharris void * scsi_io, 497230557Sjimharris ATA_IDENTIFY_DEVICE_DATA_T * identify, 498230557Sjimharris U32 offset 499230557Sjimharris) 500230557Sjimharris{ 501230557Sjimharris U8 * cdb = sati_cb_get_cdb_address(scsi_io); 502230557Sjimharris U8 page_control = sati_get_cdb_byte(cdb, 2) >> SCSI_MODE_SENSE_PC_SHIFT; 503230557Sjimharris U32 page_length; 504230557Sjimharris 505230557Sjimharris page_length = sati_mode_sense_copy_initial_data( 506230557Sjimharris sequence, 507230557Sjimharris scsi_io, 508230557Sjimharris offset, 509230557Sjimharris page_control, 510230557Sjimharris SCSI_MODE_PAGE_DISCONNECT_RECONNECT 511230557Sjimharris ); 512230557Sjimharris 513230557Sjimharris // Currently we do not override any bits in this mode page from the 514230557Sjimharris // identify data. 515230557Sjimharris 516230557Sjimharris return page_length; 517230557Sjimharris} 518230557Sjimharris 519230557Sjimharris/** 520230557Sjimharris * @brief This method performs the caching mode page specific data 521230557Sjimharris * translation based upon the contents of the remote device IDENTIFY 522230557Sjimharris * DEVICE data. 523230557Sjimharris * For more information on the parameters passed to this method, 524230557Sjimharris * please reference sati_translate_command(). 525230557Sjimharris * 526230557Sjimharris * @param[in] identify This parameter specifies the remote device's 527230557Sjimharris * IDENTIFY DEVICE data received as part of the IO request. 528230557Sjimharris * @param[in] offset This parameter specifies the offset into the data 529230557Sjimharris * buffer where the translated data is to be written. 530230557Sjimharris * 531230557Sjimharris * @return This method returns the size of the mode page data that was 532230557Sjimharris * translated. 533230557Sjimharris */ 534230557SjimharrisU32 sati_mode_sense_caching_translate_data( 535230557Sjimharris SATI_TRANSLATOR_SEQUENCE_T * sequence, 536230557Sjimharris void * scsi_io, 537230557Sjimharris ATA_IDENTIFY_DEVICE_DATA_T * identify, 538230557Sjimharris U32 offset 539230557Sjimharris) 540230557Sjimharris{ 541230557Sjimharris U8 * cdb = sati_cb_get_cdb_address(scsi_io); 542230557Sjimharris U8 page_control = sati_get_cdb_byte(cdb, 2) >> SCSI_MODE_SENSE_PC_SHIFT; 543230557Sjimharris U32 page_length; 544230557Sjimharris 545230557Sjimharris page_length = sati_mode_sense_copy_initial_data( 546230557Sjimharris sequence, 547230557Sjimharris scsi_io, 548230557Sjimharris offset, 549230557Sjimharris page_control, 550230557Sjimharris SCSI_MODE_PAGE_CACHING 551230557Sjimharris ); 552230557Sjimharris 553230557Sjimharris // If the request queried for the current values, then 554230557Sjimharris // we need to translate the data from the IDENTIFY DEVICE request. 555230557Sjimharris if (page_control == SCSI_MODE_SENSE_PC_CURRENT) 556230557Sjimharris { 557230557Sjimharris U8 value; 558230557Sjimharris 559230557Sjimharris // Update the Write Cache Enabled (WCE) bit in the mode page data 560230557Sjimharris // buffer based on the identify response. 561230557Sjimharris if ((identify->command_set_enabled0 & ATA_IDENTIFY_DEVICE_WCE_ENABLE) != 0) 562230557Sjimharris { 563230557Sjimharris sati_get_data_byte(sequence, scsi_io, offset+2, &value); 564230557Sjimharris value |= SCSI_MODE_PAGE_CACHE_PAGE_WCE_BIT; 565230557Sjimharris sati_set_data_byte(sequence, scsi_io, offset+2, value); 566230557Sjimharris //This byte has been set twice and needs to be decremented 567230557Sjimharris sequence->number_data_bytes_set--; 568230557Sjimharris } 569230557Sjimharris 570230557Sjimharris // Update the Disable Read Ahead (DRA) bit in the mode page data 571230557Sjimharris // buffer based on the identify response. 572230557Sjimharris if ((identify->command_set_enabled0 & ATA_IDENTIFY_DEVICE_RA_ENABLE) == 0) 573230557Sjimharris { 574230557Sjimharris // In SATA the polarity of the bits is inverse. 575230557Sjimharris // - SCSI = Disable Read Ahead 576230557Sjimharris // - ATA = Read Ahead 577230557Sjimharris sati_get_data_byte(sequence, scsi_io, offset+12, &value); 578230557Sjimharris value |= SCSI_MODE_PAGE_CACHE_PAGE_DRA_BIT; 579230557Sjimharris sati_set_data_byte(sequence, scsi_io, offset+12, value); 580230557Sjimharris 581230557Sjimharris //This byte has been set twice, the first time in 582230557Sjimharris //sati_mode_sense_copy_initial_data. number_data_bytes_set 583230557Sjimharris //needs to be decremented 584230557Sjimharris sequence->number_data_bytes_set--; 585230557Sjimharris } 586230557Sjimharris } 587230557Sjimharris 588230557Sjimharris return page_length; 589230557Sjimharris} 590230557Sjimharris 591230557Sjimharris/** 592230557Sjimharris * @brief This method performs the control mode page specific data 593230557Sjimharris * translation based upon the contents of the remote device 594230557Sjimharris * IDENTIFY DEVICE data. 595230557Sjimharris * For more information on the parameters passed to this method, 596230557Sjimharris * please reference sati_translate_command(). 597230557Sjimharris * 598230557Sjimharris * @param[in] identify This parameter specifies the remote device's 599230557Sjimharris * IDENTIFY DEVICE data received as part of the IO request. 600230557Sjimharris * @param[in] offset This parameter specifies the offset into the data 601230557Sjimharris * buffer where the translated data is to be written. 602230557Sjimharris * 603230557Sjimharris * @return This method returns the size of the mode page data that was 604230557Sjimharris * translated. 605230557Sjimharris */ 606230557SjimharrisU32 sati_mode_sense_control_translate_data( 607230557Sjimharris SATI_TRANSLATOR_SEQUENCE_T * sequence, 608230557Sjimharris void * scsi_io, 609230557Sjimharris ATA_IDENTIFY_DEVICE_DATA_T * identify, 610230557Sjimharris U32 offset 611230557Sjimharris) 612230557Sjimharris{ 613230557Sjimharris U8 * cdb = sati_cb_get_cdb_address(scsi_io); 614230557Sjimharris U8 page_control = sati_get_cdb_byte(cdb, 2) >> SCSI_MODE_SENSE_PC_SHIFT; 615230557Sjimharris U32 page_length; 616230557Sjimharris U8 value; 617230557Sjimharris 618230557Sjimharris page_length = sati_mode_sense_copy_initial_data( 619230557Sjimharris sequence, 620230557Sjimharris scsi_io, 621230557Sjimharris offset, 622230557Sjimharris page_control, 623230557Sjimharris SCSI_MODE_PAGE_CONTROL 624230557Sjimharris ); 625230557Sjimharris 626230557Sjimharris if (sequence->device->descriptor_sense_enable) 627230557Sjimharris { 628230557Sjimharris sati_get_data_byte(sequence, scsi_io, offset+2, 629230557Sjimharris &value); 630230557Sjimharris 631230557Sjimharris sati_set_data_byte(sequence, scsi_io, offset+2, 632230557Sjimharris value | SCSI_MODE_SELECT_MODE_PAGE_D_SENSE); 633230557Sjimharris } 634230557Sjimharris 635230557Sjimharris return page_length; 636230557Sjimharris} 637230557Sjimharris 638230557Sjimharris/** 639230557Sjimharris * @brief This method performs the informational exceptions control mode 640230557Sjimharris * page specific data translation based upon the contents of the 641230557Sjimharris * remote device IDENTIFY DEVICE data. 642230557Sjimharris * For more information on the parameters passed to this method, 643230557Sjimharris * please reference sati_translate_command(). 644230557Sjimharris * 645230557Sjimharris * @param[in] identify This parameter specifies the remote device's 646230557Sjimharris * IDENTIFY DEVICE data received as part of the IO request. 647230557Sjimharris * @param[in] offset This parameter specifies the offset into the data 648230557Sjimharris * buffer where the translated data is to be written. 649230557Sjimharris * 650230557Sjimharris * @return This method returns the size of the mode page data that was 651230557Sjimharris * translated. 652230557Sjimharris */ 653230557SjimharrisU32 sati_mode_sense_informational_excp_control_translate_data( 654230557Sjimharris SATI_TRANSLATOR_SEQUENCE_T * sequence, 655230557Sjimharris void * scsi_io, 656230557Sjimharris ATA_IDENTIFY_DEVICE_DATA_T * identify, 657230557Sjimharris U32 offset 658230557Sjimharris) 659230557Sjimharris{ 660230557Sjimharris U8 * cdb = sati_cb_get_cdb_address(scsi_io); 661230557Sjimharris U8 page_control = sati_get_cdb_byte(cdb, 2) >> SCSI_MODE_SENSE_PC_SHIFT; 662230557Sjimharris U32 page_length; 663230557Sjimharris 664230557Sjimharris page_length = sati_mode_sense_copy_initial_data( 665230557Sjimharris sequence, 666230557Sjimharris scsi_io, 667230557Sjimharris offset, 668230557Sjimharris page_control, 669230557Sjimharris SCSI_MODE_PAGE_INFORMATIONAL_EXCP_CONTROL 670230557Sjimharris ); 671230557Sjimharris 672230557Sjimharris // If the request queried for the current values, then 673230557Sjimharris // we need to translate the data from the IDENTIFY DEVICE request. 674230557Sjimharris if (page_control == SCSI_MODE_SENSE_PC_CURRENT) 675230557Sjimharris { 676230557Sjimharris U8 value; 677230557Sjimharris 678230557Sjimharris sati_get_data_byte(sequence, scsi_io, offset+2, &value); 679230557Sjimharris 680230557Sjimharris // Determine if the SMART feature set is supported and enabled. 681230557Sjimharris if ( (identify->command_set_supported0 682230557Sjimharris & ATA_IDENTIFY_COMMAND_SET_SUPPORTED0_SMART_ENABLE) 683230557Sjimharris && (identify->command_set_enabled0 684230557Sjimharris & ATA_IDENTIFY_COMMAND_SET_ENABLED0_SMART_ENABLE) ) 685230557Sjimharris { 686230557Sjimharris // Clear the DXCPT field since the SMART feature is supported/enabled. 687230557Sjimharris value &= ~SCSI_MODE_PAGE_INFORMATIONAL_EXCP_DXCPT_ENABLE; 688230557Sjimharris } 689230557Sjimharris else 690230557Sjimharris { 691230557Sjimharris // Set the Disable Exception Control (DXCPT) field since the SMART 692230557Sjimharris // feature is not supported or enabled. 693230557Sjimharris value |= SCSI_MODE_PAGE_INFORMATIONAL_EXCP_DXCPT_ENABLE; 694230557Sjimharris } 695230557Sjimharris 696230557Sjimharris sati_set_data_byte(sequence, scsi_io, offset+2, value); 697230557Sjimharris 698230557Sjimharris //This byte has been set twice, the first time in 699230557Sjimharris //sati_mode_sense_copy_initial_data. number_data_bytes_set 700230557Sjimharris //needs to be decremented 701230557Sjimharris sequence->number_data_bytes_set--; 702230557Sjimharris } 703230557Sjimharris 704230557Sjimharris return page_length; 705230557Sjimharris} 706230557Sjimharris 707230557Sjimharris/** 708230557Sjimharris* @brief This method performs the Power Condition mode page 709230557Sjimharris* specific data translation based upon the contents of the 710230557Sjimharris* remote device IDENTIFY DEVICE data. 711230557Sjimharris* For more information on the parameters passed to this method, 712230557Sjimharris* please reference sati_translate_command(). 713230557Sjimharris* 714230557Sjimharris* @param[in] identify This parameter specifies the remote device's 715230557Sjimharris* IDENTIFY DEVICE data received as part of the IO request. 716230557Sjimharris* @param[in] offset This parameter specifies the offset into the data 717230557Sjimharris* buffer where the translated data is to be written. 718230557Sjimharris* 719230557Sjimharris* @return This method returns the size of the mode page data that was 720230557Sjimharris* translated. 721230557Sjimharris*/ 722230557SjimharrisU32 sati_mode_sense_power_condition_translate_data( 723230557Sjimharris SATI_TRANSLATOR_SEQUENCE_T * sequence, 724230557Sjimharris void * scsi_io, 725230557Sjimharris ATA_IDENTIFY_DEVICE_DATA_T * identify, 726230557Sjimharris U32 offset 727230557Sjimharris) 728230557Sjimharris{ 729230557Sjimharris U8 * cdb = sati_cb_get_cdb_address(scsi_io); 730230557Sjimharris U8 page_control = sati_get_cdb_byte(cdb, 2) >> SCSI_MODE_SENSE_PC_SHIFT; 731230557Sjimharris 732230557Sjimharris U8 ata_sb_timer; 733230557Sjimharris 734230557Sjimharris //Represents tenths of seconds 735230557Sjimharris U32 standby_timer = 0x00000000; 736230557Sjimharris 737230557Sjimharris U8 standby_enabled = STANDBY_TIMER_DISABLED; 738230557Sjimharris 739230557Sjimharris if ((page_control == SCSI_MODE_SENSE_PC_CURRENT) && 740230557Sjimharris (identify->capabilities1 & STANDBY_TIMER_SUPPORTED)) 741230557Sjimharris { 742230557Sjimharris standby_enabled = STANDBY_TIMER_ENABLED; 743230557Sjimharris 744230557Sjimharris ata_sb_timer = sequence->device->ata_standby_timer; 745230557Sjimharris 746230557Sjimharris //converting ATA timer values into SCSI timer values 747230557Sjimharris if(ata_sb_timer <= 0xF0) 748230557Sjimharris { 749230557Sjimharris standby_timer = ata_sb_timer * 50; 750230557Sjimharris } 751230557Sjimharris else if(ata_sb_timer <= 0xFB) 752230557Sjimharris { 753230557Sjimharris standby_timer = ((ata_sb_timer - 240) * 18000); 754230557Sjimharris } 755230557Sjimharris else if(ata_sb_timer == 0xFC) 756230557Sjimharris { 757230557Sjimharris standby_timer = 12600; 758230557Sjimharris } 759230557Sjimharris else if(ata_sb_timer == 0xFD) 760230557Sjimharris { 761230557Sjimharris standby_timer = 432000; 762230557Sjimharris } 763230557Sjimharris else if(ata_sb_timer == 0xFF) 764230557Sjimharris { 765230557Sjimharris standby_timer = 12750; 766230557Sjimharris } 767230557Sjimharris else 768230557Sjimharris { 769230557Sjimharris standby_timer = 0xFFFFFFFF; 770230557Sjimharris } 771230557Sjimharris } 772230557Sjimharris 773230557Sjimharris sati_set_data_byte(sequence, scsi_io, offset, SCSI_MODE_PAGE_POWER_CONDITION); 774230557Sjimharris sati_set_data_byte(sequence, scsi_io, offset + 1, (SCSI_MODE_PAGE_1A_LENGTH - 2)); 775230557Sjimharris sati_set_data_byte(sequence, scsi_io, offset + 2, 0x00); 776230557Sjimharris sati_set_data_byte(sequence, scsi_io, offset + 3, standby_enabled); 777230557Sjimharris sati_set_data_byte(sequence, scsi_io, offset + 4, 0x00); 778230557Sjimharris sati_set_data_byte(sequence, scsi_io, offset + 5, 0x00); 779230557Sjimharris sati_set_data_byte(sequence, scsi_io, offset + 6, 0x00); 780230557Sjimharris sati_set_data_byte(sequence, scsi_io, offset + 7, 0x00); 781230557Sjimharris sati_set_data_byte(sequence, scsi_io, offset + 8, (U8) (standby_timer >> 24)); 782230557Sjimharris sati_set_data_byte(sequence, scsi_io, offset + 9, (U8) (standby_timer >> 16)); 783230557Sjimharris sati_set_data_byte(sequence, scsi_io, offset + 10, (U8) (standby_timer >> 8)); 784230557Sjimharris sati_set_data_byte(sequence, scsi_io, offset + 11, (U8) standby_timer); 785230557Sjimharris 786230557Sjimharris return SCSI_MODE_PAGE_1A_LENGTH; 787230557Sjimharris} 788230557Sjimharris 789230557Sjimharris/** 790230557Sjimharris * @brief This method performs the all pages mode page specific data 791230557Sjimharris * translation based upon the contents of the remote device 792230557Sjimharris * IDENTIFY DEVICE data. The ALL PAGES mode sense request asks 793230557Sjimharris * for all of mode pages and sub-pages in a single page. 794230557Sjimharris * The mode pages are added in ascending order. 795230557Sjimharris * For more information on the parameters passed to this method, 796230557Sjimharris * please reference sati_translate_command(). 797230557Sjimharris * 798230557Sjimharris * @param[in] identify This parameter specifies the remote device's 799230557Sjimharris * IDENTIFY DEVICE data received as part of the IO request. 800230557Sjimharris * @param[in] offset This parameter specifies the offset into the data 801230557Sjimharris * buffer where the translated data is to be written. 802230557Sjimharris * 803230557Sjimharris * @return This method returns the size of the mode page data that was 804230557Sjimharris * translated. 805230557Sjimharris */ 806230557SjimharrisU32 sati_mode_sense_all_pages_translate_data( 807230557Sjimharris SATI_TRANSLATOR_SEQUENCE_T * sequence, 808230557Sjimharris void * scsi_io, 809230557Sjimharris ATA_IDENTIFY_DEVICE_DATA_T * identify, 810230557Sjimharris U32 offset 811230557Sjimharris) 812230557Sjimharris{ 813230557Sjimharris offset += sati_mode_sense_read_write_error_translate_data( 814230557Sjimharris sequence, scsi_io, identify, offset 815230557Sjimharris ); 816230557Sjimharris 817230557Sjimharris offset += sati_mode_sense_disconnect_reconnect_translate_data( 818230557Sjimharris sequence, scsi_io, identify, offset 819230557Sjimharris ); 820230557Sjimharris 821230557Sjimharris offset += sati_mode_sense_caching_translate_data( 822230557Sjimharris sequence, scsi_io, identify, offset 823230557Sjimharris ); 824230557Sjimharris 825230557Sjimharris offset += sati_mode_sense_control_translate_data( 826230557Sjimharris sequence, scsi_io, identify, offset 827230557Sjimharris ); 828230557Sjimharris 829230557Sjimharris offset += sati_mode_sense_informational_excp_control_translate_data( 830230557Sjimharris sequence, scsi_io, identify, offset 831230557Sjimharris ); 832230557Sjimharris 833230557Sjimharris return offset; 834230557Sjimharris} 835230557Sjimharris 836230557Sjimharris#endif // !defined(DISABLE_SATI_MODE_SENSE) 837230557Sjimharris 838