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