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