sati_mode_sense.c revision 330897
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: stable/11/sys/dev/isci/scil/sati_mode_sense.c 330897 2018-03-14 03:19:51Z eadler $");
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 */
97static
98SATI_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 */
144static
145SATI_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 */
268U16 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 */
311SATI_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 */
352U32 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 */
402U32 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 */
456U32 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 */
496U32 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 */
536U32 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 */
608U32 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 */
655U32 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*/
724U32 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 */
808U32 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