xref: /freebsd/sys/dev/isci/scil/sati_mode_sense.c (revision 7661de35d15f582ab33e3bd6b8d909601557e436)
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, &sector_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