1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause OR GPL-2.0 3 * 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. 6 * 7 * GPL LICENSE SUMMARY 8 * 9 * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. 10 * 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. 14 * 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. 19 * 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. 25 * 26 * BSD LICENSE 27 * 28 * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. 29 * All rights reserved. 30 * 31 * Redistribution and use in source and binary forms, with or without 32 * modification, are permitted provided that the following conditions 33 * are met: 34 * 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 40 * distribution. 41 * 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. 53 */ 54 55 #include <sys/cdefs.h> 56 __FBSDID("$FreeBSD$"); 57 58 /** 59 * @file 60 * @brief This file contains the method implementations required to 61 * translate the SCSI mode sense (6 and 10-byte) commands. 62 */ 63 64 #if !defined(DISABLE_SATI_MODE_SENSE) 65 66 #include <dev/isci/scil/sati_mode_sense.h> 67 #include <dev/isci/scil/sati_mode_pages.h> 68 #include <dev/isci/scil/sati_callbacks.h> 69 #include <dev/isci/scil/sati_util.h> 70 #include <dev/isci/scil/intel_scsi.h> 71 #include <dev/isci/scil/intel_ata.h> 72 73 //****************************************************************************** 74 //* P R I V A T E M E T H O D S 75 //****************************************************************************** 76 77 #define STANDBY_TIMER_DISABLED 0x00 78 #define STANDBY_TIMER_ENABLED 0x01 79 #define STANDBY_TIMER_SUPPORTED 0x2000 80 81 82 83 /** 84 * @brief This method indicates if the supplied page control is supported 85 * by this translation implementation. Currently savable parameters 86 * (i.e. non-volatile) are not supported. 87 * For more information on the parameters passed to this method, 88 * please reference sati_translate_command(). 89 * 90 * @return This method returns an indication of whether the page control 91 * specified in the SCSI CDB is supported. 92 * @retval SATI_SUCCESS This value is returned if the page control is 93 * supported. 94 * @retval SATI_FAILURE_CHECK_RESPONSE_DATA This value is returned if the 95 * page control is not supported. 96 */ 97 static 98 SATI_STATUS sati_mode_sense_is_page_control_supported( 99 SATI_TRANSLATOR_SEQUENCE_T * sequence, 100 void * scsi_io 101 ) 102 { 103 U8 * cdb = sati_cb_get_cdb_address(scsi_io); 104 105 switch (sati_get_cdb_byte(cdb, 2) >> SCSI_MODE_SENSE_PC_SHIFT) 106 { 107 case SCSI_MODE_SENSE_PC_CURRENT: 108 case SCSI_MODE_SENSE_PC_DEFAULT: 109 case SCSI_MODE_SENSE_PC_CHANGEABLE: 110 return SATI_SUCCESS; 111 break; 112 113 default: 114 case SCSI_MODE_SENSE_PC_SAVED: 115 sati_scsi_sense_data_construct( 116 sequence, 117 scsi_io, 118 SCSI_STATUS_CHECK_CONDITION, 119 SCSI_SENSE_ILLEGAL_REQUEST, 120 SCSI_ASC_SAVING_PARMS_NOT_SUPPORTED, 121 SCSI_ASCQ_SAVING_PARMS_NOT_SUPPORTED 122 ); 123 return SATI_FAILURE_CHECK_RESPONSE_DATA; 124 break; 125 } 126 } 127 128 /** 129 * @brief This method indicates if the page code field in the SCSI CDB 130 * is supported by this translation. 131 * For more information on the parameters passed to this method, 132 * please reference sati_translate_command(). 133 * 134 * @param[in] cdb_length This parameter specifies the length of the SCSI 135 * CDB being translated (e.g. 6-byte, 10-byte, 12-byte, etc.) 136 * 137 * @return This method returns an indication as to whether the page code 138 * in the CDB is supported. 139 * @retval SATI_SUCCESS This value is returned if the page code is 140 * supported. 141 * @retval SATI_FAILURE_CHECK_RESPONSE_DATA This value is returned if the 142 * page code is not supported. 143 */ 144 static 145 SATI_STATUS sati_mode_sense_is_page_code_supported( 146 SATI_TRANSLATOR_SEQUENCE_T * sequence, 147 void * scsi_io, 148 U8 cdb_length 149 ) 150 { 151 U8 * cdb = sati_cb_get_cdb_address(scsi_io); 152 153 switch (sati_get_cdb_byte(cdb, 2) & SCSI_MODE_SENSE_PAGE_CODE_ENABLE) 154 { 155 case SCSI_MODE_PAGE_CACHING: 156 if (sati_get_cdb_byte(cdb, 0) == SCSI_MODE_SENSE_6) 157 sequence->type = SATI_SEQUENCE_MODE_SENSE_6_CACHING; 158 else 159 sequence->type = SATI_SEQUENCE_MODE_SENSE_10_CACHING; 160 break; 161 162 case SCSI_MODE_PAGE_ALL_PAGES: 163 if (sati_get_cdb_byte(cdb, 0) == SCSI_MODE_SENSE_6) 164 sequence->type = SATI_SEQUENCE_MODE_SENSE_6_ALL_PAGES; 165 else 166 sequence->type = SATI_SEQUENCE_MODE_SENSE_10_ALL_PAGES; 167 break; 168 169 case SCSI_MODE_PAGE_READ_WRITE_ERROR: 170 if (sati_get_cdb_byte(cdb, 0) == SCSI_MODE_SENSE_6) 171 sequence->type = SATI_SEQUENCE_MODE_SENSE_6_READ_WRITE_ERROR; 172 else 173 sequence->type = SATI_SEQUENCE_MODE_SENSE_10_READ_WRITE_ERROR; 174 break; 175 176 case SCSI_MODE_PAGE_DISCONNECT_RECONNECT: 177 if (sati_get_cdb_byte(cdb, 0) == SCSI_MODE_SENSE_6) 178 sequence->type = SATI_SEQUENCE_MODE_SENSE_6_DISCONNECT_RECONNECT; 179 else 180 sequence->type = SATI_SEQUENCE_MODE_SENSE_10_DISCONNECT_RECONNECT; 181 break; 182 183 case SCSI_MODE_PAGE_CONTROL: 184 if (sati_get_cdb_byte(cdb, 0) == SCSI_MODE_SENSE_6) 185 sequence->type = SATI_SEQUENCE_MODE_SENSE_6_CONTROL; 186 else 187 sequence->type = SATI_SEQUENCE_MODE_SENSE_10_CONTROL; 188 break; 189 190 case SCSI_MODE_PAGE_POWER_CONDITION: 191 if (sati_get_cdb_byte(cdb, 0) == SCSI_MODE_SENSE_6) 192 sequence->type = SATI_SEQUENCE_MODE_SENSE_6_POWER_CONDITION; 193 else 194 sequence->type = SATI_SEQUENCE_MODE_SENSE_10_POWER_CONDITION; 195 break; 196 197 case SCSI_MODE_PAGE_INFORMATIONAL_EXCP_CONTROL: 198 // The informational exceptions control page is only useful 199 // if SMART is supported. 200 if ((sequence->device->capabilities | SATI_DEVICE_CAP_SMART_SUPPORT) 201 == 0) 202 { 203 // For a MODE SENSE, utilize INVALID FIELD IN CDB, 204 // For a MODE SELECT, utilize INVALID FIELD IN PARAMETER LIST. 205 if (sati_get_cdb_byte(cdb, 0) == SCSI_MODE_SENSE_6) 206 { 207 sati_scsi_sense_data_construct( 208 sequence, 209 scsi_io, 210 SCSI_STATUS_CHECK_CONDITION, 211 SCSI_SENSE_ILLEGAL_REQUEST, 212 SCSI_ASC_INVALID_FIELD_IN_CDB, 213 SCSI_ASCQ_INVALID_FIELD_IN_CDB 214 ); 215 } 216 else 217 { 218 sati_scsi_sense_data_construct( 219 sequence, 220 scsi_io, 221 SCSI_STATUS_CHECK_CONDITION, 222 SCSI_SENSE_ILLEGAL_REQUEST, 223 SCSI_ASC_INVALID_FIELD_IN_PARM_LIST, 224 SCSI_ASCQ_INVALID_FIELD_IN_PARM_LIST 225 ); 226 } 227 228 return SATI_FAILURE_CHECK_RESPONSE_DATA; 229 } 230 231 if (sati_get_cdb_byte(cdb, 0) == SCSI_MODE_SENSE_6) 232 sequence->type = SATI_SEQUENCE_MODE_SENSE_6_INFORMATIONAL_EXCP_CONTROL; 233 else 234 sequence->type = SATI_SEQUENCE_MODE_SENSE_10_INFORMATIONAL_EXCP_CONTROL; 235 break; 236 237 default: 238 sati_scsi_sense_data_construct( 239 sequence, 240 scsi_io, 241 SCSI_STATUS_CHECK_CONDITION, 242 SCSI_SENSE_ILLEGAL_REQUEST, 243 SCSI_ASC_INVALID_FIELD_IN_CDB, 244 SCSI_ASCQ_INVALID_FIELD_IN_CDB 245 ); 246 return SATI_FAILURE_CHECK_RESPONSE_DATA; 247 break; 248 } 249 250 return SATI_SUCCESS; 251 } 252 253 //****************************************************************************** 254 //* P R O T E C T E D M E T H O D S 255 //****************************************************************************** 256 257 /** 258 * @brief This method will calculate the size of the mode sense data header. 259 * This includes the block descriptor if one is requested. 260 * 261 * @param[in] scsi_io This parameter specifies the user's SCSI IO object 262 * for which to calculate the mode page header. 263 * @param[in] cdb_size This parameter specifies the number of bytes 264 * associated with the CDB for which to calculate the header. 265 * 266 * @return This method returns the size, in bytes, for the mode page header. 267 */ 268 U16 sati_mode_sense_calculate_page_header( 269 void * scsi_io, 270 U8 cdb_size 271 ) 272 { 273 U8 * cdb = sati_cb_get_cdb_address(scsi_io); 274 U16 page_length = 0; 275 276 // The Mode page header length is different for 6-byte vs. 10-byte CDBs. 277 if (cdb_size == 6) 278 page_length += SCSI_MODE_SENSE_6_HEADER_LENGTH; 279 else 280 page_length += SCSI_MODE_SENSE_10_HEADER_LENGTH; 281 282 // Are block descriptors disabled (DBD)? 0 indicates they are enabled. 283 if ((sati_get_cdb_byte(cdb, 1) & SCSI_MODE_SENSE_DBD_ENABLE) == 0) 284 { 285 // The LLBAA bit is not defined for 6-byte mode sense requests. 286 if ( (cdb_size == 10) 287 && (sati_get_cdb_byte(cdb, 1) & SCSI_MODE_SENSE_LLBAA_ENABLE) ) 288 page_length += SCSI_MODE_SENSE_LLBA_BLOCK_DESCRIPTOR_LENGTH; 289 else 290 page_length += SCSI_MODE_SENSE_STD_BLOCK_DESCRIPTOR_LENGTH; 291 } 292 293 return page_length; 294 } 295 296 /** 297 * @brief This method performs command translation common to all mode sense 298 * requests (6 or 10 byte). 299 * For more information on the parameters passed to this method, 300 * please reference sati_translate_command(). 301 * 302 * @param[in] cdb_length This parameter specifies the number of bytes 303 * in the CDB (6 or 10). 304 * 305 * @return This method returns an indication as to whether the translation 306 * succeeded. 307 * @retval SCI_SUCCESS This value is returned if translation succeeded. 308 * @see sati_mode_sense_is_page_control_supported() or 309 * sati_mode_sense_is_page_code_supported() for more information. 310 */ 311 SATI_STATUS sati_mode_sense_translate_command( 312 SATI_TRANSLATOR_SEQUENCE_T * sequence, 313 void * scsi_io, 314 void * ata_io, 315 U8 cdb_length 316 ) 317 { 318 SATI_STATUS status; 319 320 /** 321 * Validate that the supplied page control (PC) field is supported. 322 */ 323 status = sati_mode_sense_is_page_control_supported(sequence, scsi_io); 324 if (status != SATI_SUCCESS) 325 return status; 326 327 /** 328 * Validate that the supplied page code is supported. 329 */ 330 status = sati_mode_sense_is_page_code_supported(sequence,scsi_io,cdb_length); 331 if (status != SATI_SUCCESS) 332 return status; 333 334 sati_ata_identify_device_construct(ata_io, sequence); 335 336 return SATI_SUCCESS; 337 } 338 339 /** 340 * @brief This method will build the standard block descriptor for a MODE 341 * SENSE 6 or 10 byte request. 342 * For more information on the parameters passed to this method, 343 * please reference sati_translate_command(). 344 * 345 * @param[in] identify This parameter specifies the IDENTIFY DEVICE data 346 * associated with the SCSI IO. 347 * @param[in] offset This parameter specifies the offset into the data 348 * buffer at which to build the block descriptor. 349 * 350 * @return This method returns the size of the block descriptor built. 351 */ 352 U32 sati_mode_sense_build_std_block_descriptor( 353 SATI_TRANSLATOR_SEQUENCE_T * sequence, 354 void * scsi_io, 355 ATA_IDENTIFY_DEVICE_DATA_T * identify, 356 U32 offset 357 ) 358 { 359 U32 lba_low = 0; 360 U32 lba_high = 0; 361 U32 sector_size = 0; 362 363 // Extract the sector information (sector size, logical blocks) from 364 // the retrieved ATA identify device data. 365 sati_ata_identify_device_get_sector_info( 366 identify, &lba_high, &lba_low, §or_size 367 ); 368 369 // Fill in the 4-byte logical block address field. 370 sati_set_data_byte(sequence, scsi_io, offset, (U8)((lba_low>>24) & 0xFF)); 371 sati_set_data_byte(sequence, scsi_io, offset+1, (U8)((lba_low>>16) & 0xFF)); 372 sati_set_data_byte(sequence, scsi_io, offset+2, (U8)((lba_low>>8) & 0xFF)); 373 sati_set_data_byte(sequence, scsi_io, offset+3, (U8)(lba_low & 0xFF)); 374 375 // Clear the reserved field. 376 sati_set_data_byte(sequence, scsi_io, offset+4, 0); 377 378 // Fill in the three byte Block Length field 379 sati_set_data_byte(sequence,scsi_io, offset+5, (U8)((sector_size>>16) & 0xFF)); 380 sati_set_data_byte(sequence,scsi_io, offset+6, (U8)((sector_size>>8) & 0xFF)); 381 sati_set_data_byte(sequence,scsi_io, offset+7, (U8)(sector_size & 0xFF)); 382 383 return SCSI_MODE_SENSE_STD_BLOCK_DESCRIPTOR_LENGTH; 384 } 385 386 /** 387 * @brief This method simply copies the mode sense data into the buffer 388 * at the location specified by page_start. The buffer copied is 389 * determined by page_control (e.g. current, default, or changeable 390 * values). 391 * For more information on the parameters passed to this method, 392 * please reference sati_translate_command(). 393 * 394 * @param[in] page_start This parameter specifies the starting offset at 395 * which to copy the mode page data. 396 * @param[in] page_control This parameter specifies the page control 397 * indicating the source buffer to be copied. 398 * @param[in] page_code This specifies the mode sense page to copy. 399 * 400 * @return This method returns the size of the mode page data being copied. 401 */ 402 U32 sati_mode_sense_copy_initial_data( 403 SATI_TRANSLATOR_SEQUENCE_T * sequence, 404 void * scsi_io, 405 U32 page_start, 406 U8 page_control, 407 U8 page_code 408 ) 409 { 410 U16 page_index = sati_mode_page_get_page_index(page_code); 411 U32 page_length = sat_mode_page_sizes[page_index]; 412 413 // Find out if the current values are requested or if the default 414 // values are being requested. 415 if (page_control == SCSI_MODE_SENSE_PC_CHANGEABLE) 416 { 417 // Copy the changeable mode page information. 418 sati_copy_data( 419 sequence, 420 scsi_io, 421 page_start, 422 sat_changeable_mode_pages[page_index], 423 page_length 424 ); 425 } 426 else 427 { 428 // Copy the default static values template to the user data area. 429 sati_copy_data( 430 sequence, 431 scsi_io, 432 page_start, 433 sat_default_mode_pages[page_index], 434 page_length 435 ); 436 } 437 438 return page_length; 439 } 440 441 /** 442 * @brief This method performs the read/write error recovery mode page 443 * specific data translation based upon the contents of the remote 444 * device IDENTIFY DEVICE data. 445 * For more information on the parameters passed to this method, 446 * please reference sati_translate_command(). 447 * 448 * @param[in] identify This parameter specifies the remote device's 449 * IDENTIFY DEVICE data received as part of the IO request. 450 * @param[in] offset This parameter specifies the offset into the data 451 * buffer where the translated data is to be written. 452 * 453 * @return This method returns the size of the mode page data that was 454 * translated. 455 */ 456 U32 sati_mode_sense_read_write_error_translate_data( 457 SATI_TRANSLATOR_SEQUENCE_T * sequence, 458 void * scsi_io, 459 ATA_IDENTIFY_DEVICE_DATA_T * identify, 460 U32 offset 461 ) 462 { 463 U8 * cdb = sati_cb_get_cdb_address(scsi_io); 464 U8 page_control = sati_get_cdb_byte(cdb, 2) >> SCSI_MODE_SENSE_PC_SHIFT; 465 U32 page_length; 466 467 page_length = sati_mode_sense_copy_initial_data( 468 sequence, 469 scsi_io, 470 offset, 471 page_control, 472 SCSI_MODE_PAGE_READ_WRITE_ERROR 473 ); 474 475 // Currently we do not override any bits in this mode page from the 476 // identify data. 477 478 return page_length; 479 } 480 481 /** 482 * @brief This method performs the disconnect/reconnect mode page 483 * specific data translation based upon the contents of the remote 484 * device IDENTIFY DEVICE data. 485 * For more information on the parameters passed to this method, 486 * please reference sati_translate_command(). 487 * 488 * @param[in] identify This parameter specifies the remote device's 489 * IDENTIFY DEVICE data received as part of the IO request. 490 * @param[in] offset This parameter specifies the offset into the data 491 * buffer where the translated data is to be written. 492 * 493 * @return This method returns the size of the mode page data that was 494 * translated. 495 */ 496 U32 sati_mode_sense_disconnect_reconnect_translate_data( 497 SATI_TRANSLATOR_SEQUENCE_T * sequence, 498 void * scsi_io, 499 ATA_IDENTIFY_DEVICE_DATA_T * identify, 500 U32 offset 501 ) 502 { 503 U8 * cdb = sati_cb_get_cdb_address(scsi_io); 504 U8 page_control = sati_get_cdb_byte(cdb, 2) >> SCSI_MODE_SENSE_PC_SHIFT; 505 U32 page_length; 506 507 page_length = sati_mode_sense_copy_initial_data( 508 sequence, 509 scsi_io, 510 offset, 511 page_control, 512 SCSI_MODE_PAGE_DISCONNECT_RECONNECT 513 ); 514 515 // Currently we do not override any bits in this mode page from the 516 // identify data. 517 518 return page_length; 519 } 520 521 /** 522 * @brief This method performs the caching mode page specific data 523 * translation based upon the contents of the remote device IDENTIFY 524 * DEVICE data. 525 * For more information on the parameters passed to this method, 526 * please reference sati_translate_command(). 527 * 528 * @param[in] identify This parameter specifies the remote device's 529 * IDENTIFY DEVICE data received as part of the IO request. 530 * @param[in] offset This parameter specifies the offset into the data 531 * buffer where the translated data is to be written. 532 * 533 * @return This method returns the size of the mode page data that was 534 * translated. 535 */ 536 U32 sati_mode_sense_caching_translate_data( 537 SATI_TRANSLATOR_SEQUENCE_T * sequence, 538 void * scsi_io, 539 ATA_IDENTIFY_DEVICE_DATA_T * identify, 540 U32 offset 541 ) 542 { 543 U8 * cdb = sati_cb_get_cdb_address(scsi_io); 544 U8 page_control = sati_get_cdb_byte(cdb, 2) >> SCSI_MODE_SENSE_PC_SHIFT; 545 U32 page_length; 546 547 page_length = sati_mode_sense_copy_initial_data( 548 sequence, 549 scsi_io, 550 offset, 551 page_control, 552 SCSI_MODE_PAGE_CACHING 553 ); 554 555 // If the request queried for the current values, then 556 // we need to translate the data from the IDENTIFY DEVICE request. 557 if (page_control == SCSI_MODE_SENSE_PC_CURRENT) 558 { 559 U8 value; 560 561 // Update the Write Cache Enabled (WCE) bit in the mode page data 562 // buffer based on the identify response. 563 if ((identify->command_set_enabled0 & ATA_IDENTIFY_DEVICE_WCE_ENABLE) != 0) 564 { 565 sati_get_data_byte(sequence, scsi_io, offset+2, &value); 566 value |= SCSI_MODE_PAGE_CACHE_PAGE_WCE_BIT; 567 sati_set_data_byte(sequence, scsi_io, offset+2, value); 568 //This byte has been set twice and needs to be decremented 569 sequence->number_data_bytes_set--; 570 } 571 572 // Update the Disable Read Ahead (DRA) bit in the mode page data 573 // buffer based on the identify response. 574 if ((identify->command_set_enabled0 & ATA_IDENTIFY_DEVICE_RA_ENABLE) == 0) 575 { 576 // In SATA the polarity of the bits is inverse. 577 // - SCSI = Disable Read Ahead 578 // - ATA = Read Ahead 579 sati_get_data_byte(sequence, scsi_io, offset+12, &value); 580 value |= SCSI_MODE_PAGE_CACHE_PAGE_DRA_BIT; 581 sati_set_data_byte(sequence, scsi_io, offset+12, value); 582 583 //This byte has been set twice, the first time in 584 //sati_mode_sense_copy_initial_data. number_data_bytes_set 585 //needs to be decremented 586 sequence->number_data_bytes_set--; 587 } 588 } 589 590 return page_length; 591 } 592 593 /** 594 * @brief This method performs the control mode page specific data 595 * translation based upon the contents of the remote device 596 * IDENTIFY DEVICE data. 597 * For more information on the parameters passed to this method, 598 * please reference sati_translate_command(). 599 * 600 * @param[in] identify This parameter specifies the remote device's 601 * IDENTIFY DEVICE data received as part of the IO request. 602 * @param[in] offset This parameter specifies the offset into the data 603 * buffer where the translated data is to be written. 604 * 605 * @return This method returns the size of the mode page data that was 606 * translated. 607 */ 608 U32 sati_mode_sense_control_translate_data( 609 SATI_TRANSLATOR_SEQUENCE_T * sequence, 610 void * scsi_io, 611 ATA_IDENTIFY_DEVICE_DATA_T * identify, 612 U32 offset 613 ) 614 { 615 U8 * cdb = sati_cb_get_cdb_address(scsi_io); 616 U8 page_control = sati_get_cdb_byte(cdb, 2) >> SCSI_MODE_SENSE_PC_SHIFT; 617 U32 page_length; 618 U8 value; 619 620 page_length = sati_mode_sense_copy_initial_data( 621 sequence, 622 scsi_io, 623 offset, 624 page_control, 625 SCSI_MODE_PAGE_CONTROL 626 ); 627 628 if (sequence->device->descriptor_sense_enable) 629 { 630 sati_get_data_byte(sequence, scsi_io, offset+2, 631 &value); 632 633 sati_set_data_byte(sequence, scsi_io, offset+2, 634 value | SCSI_MODE_SELECT_MODE_PAGE_D_SENSE); 635 } 636 637 return page_length; 638 } 639 640 /** 641 * @brief This method performs the informational exceptions control mode 642 * page specific data translation based upon the contents of the 643 * remote device IDENTIFY DEVICE data. 644 * For more information on the parameters passed to this method, 645 * please reference sati_translate_command(). 646 * 647 * @param[in] identify This parameter specifies the remote device's 648 * IDENTIFY DEVICE data received as part of the IO request. 649 * @param[in] offset This parameter specifies the offset into the data 650 * buffer where the translated data is to be written. 651 * 652 * @return This method returns the size of the mode page data that was 653 * translated. 654 */ 655 U32 sati_mode_sense_informational_excp_control_translate_data( 656 SATI_TRANSLATOR_SEQUENCE_T * sequence, 657 void * scsi_io, 658 ATA_IDENTIFY_DEVICE_DATA_T * identify, 659 U32 offset 660 ) 661 { 662 U8 * cdb = sati_cb_get_cdb_address(scsi_io); 663 U8 page_control = sati_get_cdb_byte(cdb, 2) >> SCSI_MODE_SENSE_PC_SHIFT; 664 U32 page_length; 665 666 page_length = sati_mode_sense_copy_initial_data( 667 sequence, 668 scsi_io, 669 offset, 670 page_control, 671 SCSI_MODE_PAGE_INFORMATIONAL_EXCP_CONTROL 672 ); 673 674 // If the request queried for the current values, then 675 // we need to translate the data from the IDENTIFY DEVICE request. 676 if (page_control == SCSI_MODE_SENSE_PC_CURRENT) 677 { 678 U8 value; 679 680 sati_get_data_byte(sequence, scsi_io, offset+2, &value); 681 682 // Determine if the SMART feature set is supported and enabled. 683 if ( (identify->command_set_supported0 684 & ATA_IDENTIFY_COMMAND_SET_SUPPORTED0_SMART_ENABLE) 685 && (identify->command_set_enabled0 686 & ATA_IDENTIFY_COMMAND_SET_ENABLED0_SMART_ENABLE) ) 687 { 688 // Clear the DXCPT field since the SMART feature is supported/enabled. 689 value &= ~SCSI_MODE_PAGE_INFORMATIONAL_EXCP_DXCPT_ENABLE; 690 } 691 else 692 { 693 // Set the Disable Exception Control (DXCPT) field since the SMART 694 // feature is not supported or enabled. 695 value |= SCSI_MODE_PAGE_INFORMATIONAL_EXCP_DXCPT_ENABLE; 696 } 697 698 sati_set_data_byte(sequence, scsi_io, offset+2, value); 699 700 //This byte has been set twice, the first time in 701 //sati_mode_sense_copy_initial_data. number_data_bytes_set 702 //needs to be decremented 703 sequence->number_data_bytes_set--; 704 } 705 706 return page_length; 707 } 708 709 /** 710 * @brief This method performs the Power Condition mode page 711 * specific data translation based upon the contents of the 712 * remote device IDENTIFY DEVICE data. 713 * For more information on the parameters passed to this method, 714 * please reference sati_translate_command(). 715 * 716 * @param[in] identify This parameter specifies the remote device's 717 * IDENTIFY DEVICE data received as part of the IO request. 718 * @param[in] offset This parameter specifies the offset into the data 719 * buffer where the translated data is to be written. 720 * 721 * @return This method returns the size of the mode page data that was 722 * translated. 723 */ 724 U32 sati_mode_sense_power_condition_translate_data( 725 SATI_TRANSLATOR_SEQUENCE_T * sequence, 726 void * scsi_io, 727 ATA_IDENTIFY_DEVICE_DATA_T * identify, 728 U32 offset 729 ) 730 { 731 U8 * cdb = sati_cb_get_cdb_address(scsi_io); 732 U8 page_control = sati_get_cdb_byte(cdb, 2) >> SCSI_MODE_SENSE_PC_SHIFT; 733 734 U8 ata_sb_timer; 735 736 //Represents tenths of seconds 737 U32 standby_timer = 0x00000000; 738 739 U8 standby_enabled = STANDBY_TIMER_DISABLED; 740 741 if ((page_control == SCSI_MODE_SENSE_PC_CURRENT) && 742 (identify->capabilities1 & STANDBY_TIMER_SUPPORTED)) 743 { 744 standby_enabled = STANDBY_TIMER_ENABLED; 745 746 ata_sb_timer = sequence->device->ata_standby_timer; 747 748 //converting ATA timer values into SCSI timer values 749 if(ata_sb_timer <= 0xF0) 750 { 751 standby_timer = ata_sb_timer * 50; 752 } 753 else if(ata_sb_timer <= 0xFB) 754 { 755 standby_timer = ((ata_sb_timer - 240) * 18000); 756 } 757 else if(ata_sb_timer == 0xFC) 758 { 759 standby_timer = 12600; 760 } 761 else if(ata_sb_timer == 0xFD) 762 { 763 standby_timer = 432000; 764 } 765 else if(ata_sb_timer == 0xFF) 766 { 767 standby_timer = 12750; 768 } 769 else 770 { 771 standby_timer = 0xFFFFFFFF; 772 } 773 } 774 775 sati_set_data_byte(sequence, scsi_io, offset, SCSI_MODE_PAGE_POWER_CONDITION); 776 sati_set_data_byte(sequence, scsi_io, offset + 1, (SCSI_MODE_PAGE_1A_LENGTH - 2)); 777 sati_set_data_byte(sequence, scsi_io, offset + 2, 0x00); 778 sati_set_data_byte(sequence, scsi_io, offset + 3, standby_enabled); 779 sati_set_data_byte(sequence, scsi_io, offset + 4, 0x00); 780 sati_set_data_byte(sequence, scsi_io, offset + 5, 0x00); 781 sati_set_data_byte(sequence, scsi_io, offset + 6, 0x00); 782 sati_set_data_byte(sequence, scsi_io, offset + 7, 0x00); 783 sati_set_data_byte(sequence, scsi_io, offset + 8, (U8) (standby_timer >> 24)); 784 sati_set_data_byte(sequence, scsi_io, offset + 9, (U8) (standby_timer >> 16)); 785 sati_set_data_byte(sequence, scsi_io, offset + 10, (U8) (standby_timer >> 8)); 786 sati_set_data_byte(sequence, scsi_io, offset + 11, (U8) standby_timer); 787 788 return SCSI_MODE_PAGE_1A_LENGTH; 789 } 790 791 /** 792 * @brief This method performs the all pages mode page specific data 793 * translation based upon the contents of the remote device 794 * IDENTIFY DEVICE data. The ALL PAGES mode sense request asks 795 * for all of mode pages and sub-pages in a single page. 796 * The mode pages are added in ascending order. 797 * For more information on the parameters passed to this method, 798 * please reference sati_translate_command(). 799 * 800 * @param[in] identify This parameter specifies the remote device's 801 * IDENTIFY DEVICE data received as part of the IO request. 802 * @param[in] offset This parameter specifies the offset into the data 803 * buffer where the translated data is to be written. 804 * 805 * @return This method returns the size of the mode page data that was 806 * translated. 807 */ 808 U32 sati_mode_sense_all_pages_translate_data( 809 SATI_TRANSLATOR_SEQUENCE_T * sequence, 810 void * scsi_io, 811 ATA_IDENTIFY_DEVICE_DATA_T * identify, 812 U32 offset 813 ) 814 { 815 offset += sati_mode_sense_read_write_error_translate_data( 816 sequence, scsi_io, identify, offset 817 ); 818 819 offset += sati_mode_sense_disconnect_reconnect_translate_data( 820 sequence, scsi_io, identify, offset 821 ); 822 823 offset += sati_mode_sense_caching_translate_data( 824 sequence, scsi_io, identify, offset 825 ); 826 827 offset += sati_mode_sense_control_translate_data( 828 sequence, scsi_io, identify, offset 829 ); 830 831 offset += sati_mode_sense_informational_excp_control_translate_data( 832 sequence, scsi_io, identify, offset 833 ); 834 835 return offset; 836 } 837 838 #endif // !defined(DISABLE_SATI_MODE_SENSE) 839 840