1230557Sjimharris /*-
2230557Sjimharris * This file is provided under a dual BSD/GPLv2 license.  When using or
3230557Sjimharris * redistributing this file, you may do so under either license.
4230557Sjimharris *
5230557Sjimharris * GPL LICENSE SUMMARY
6230557Sjimharris *
7230557Sjimharris * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
8230557Sjimharris *
9230557Sjimharris * This program is free software; you can redistribute it and/or modify
10230557Sjimharris * it under the terms of version 2 of the GNU General Public License as
11230557Sjimharris * published by the Free Software Foundation.
12230557Sjimharris *
13230557Sjimharris * This program is distributed in the hope that it will be useful, but
14230557Sjimharris * WITHOUT ANY WARRANTY; without even the implied warranty of
15230557Sjimharris * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16230557Sjimharris * General Public License for more details.
17230557Sjimharris *
18230557Sjimharris * You should have received a copy of the GNU General Public License
19230557Sjimharris * along with this program; if not, write to the Free Software
20230557Sjimharris * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
21230557Sjimharris * The full GNU General Public License is included in this distribution
22230557Sjimharris * in the file called LICENSE.GPL.
23230557Sjimharris *
24230557Sjimharris * BSD LICENSE
25230557Sjimharris *
26230557Sjimharris * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
27230557Sjimharris * All rights reserved.
28230557Sjimharris *
29230557Sjimharris * Redistribution and use in source and binary forms, with or without
30230557Sjimharris * modification, are permitted provided that the following conditions
31230557Sjimharris * are met:
32230557Sjimharris *
33230557Sjimharris *   * Redistributions of source code must retain the above copyright
34230557Sjimharris *     notice, this list of conditions and the following disclaimer.
35230557Sjimharris *   * Redistributions in binary form must reproduce the above copyright
36230557Sjimharris *     notice, this list of conditions and the following disclaimer in
37230557Sjimharris *     the documentation and/or other materials provided with the
38230557Sjimharris *     distribution.
39230557Sjimharris *
40230557Sjimharris * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
41230557Sjimharris * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
42230557Sjimharris * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
43230557Sjimharris * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
44230557Sjimharris * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
45230557Sjimharris * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
46230557Sjimharris * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
47230557Sjimharris * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
48230557Sjimharris * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
49230557Sjimharris * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
50230557Sjimharris * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
51230557Sjimharris */
52230557Sjimharris
53230557Sjimharris#include <sys/cdefs.h>
54230557Sjimharris__FBSDID("$FreeBSD$");
55230557Sjimharris
56230557Sjimharris/**
57230557Sjimharris * @file
58230557Sjimharris * @brief This file contains the method implementations required to
59230557Sjimharris *        translate the SCSI mode sense (6 and 10-byte) commands.
60230557Sjimharris */
61230557Sjimharris
62230557Sjimharris#if !defined(DISABLE_SATI_MODE_SENSE)
63230557Sjimharris
64230557Sjimharris#include <dev/isci/scil/sati_mode_sense.h>
65230557Sjimharris#include <dev/isci/scil/sati_mode_pages.h>
66230557Sjimharris#include <dev/isci/scil/sati_callbacks.h>
67230557Sjimharris#include <dev/isci/scil/sati_util.h>
68230557Sjimharris#include <dev/isci/scil/intel_scsi.h>
69230557Sjimharris#include <dev/isci/scil/intel_ata.h>
70230557Sjimharris
71230557Sjimharris//******************************************************************************
72230557Sjimharris//* P R I V A T E   M E T H O D S
73230557Sjimharris//******************************************************************************
74230557Sjimharris
75230557Sjimharris#define STANDBY_TIMER_DISABLED  0x00
76230557Sjimharris#define STANDBY_TIMER_ENABLED   0x01
77230557Sjimharris#define STANDBY_TIMER_SUPPORTED 0x2000
78230557Sjimharris
79230557Sjimharris
80230557Sjimharris
81230557Sjimharris/**
82230557Sjimharris * @brief This method indicates if the supplied page control is supported
83230557Sjimharris *        by this translation implementation.  Currently savable parameters
84230557Sjimharris *        (i.e. non-volatile) are not supported.
85230557Sjimharris *        For more information on the parameters passed to this method,
86230557Sjimharris *        please reference sati_translate_command().
87230557Sjimharris *
88230557Sjimharris * @return This method returns an indication of whether the page control
89230557Sjimharris *         specified in the SCSI CDB is supported.
90230557Sjimharris * @retval SATI_SUCCESS This value is returned if the page control is
91230557Sjimharris *         supported.
92230557Sjimharris * @retval SATI_FAILURE_CHECK_RESPONSE_DATA This value is returned if the
93230557Sjimharris *         page control is not supported.
94230557Sjimharris */
95230557Sjimharrisstatic
96230557SjimharrisSATI_STATUS sati_mode_sense_is_page_control_supported(
97230557Sjimharris   SATI_TRANSLATOR_SEQUENCE_T * sequence,
98230557Sjimharris   void                       * scsi_io
99230557Sjimharris)
100230557Sjimharris{
101230557Sjimharris   U8 * cdb = sati_cb_get_cdb_address(scsi_io);
102230557Sjimharris
103230557Sjimharris   switch (sati_get_cdb_byte(cdb, 2) >> SCSI_MODE_SENSE_PC_SHIFT)
104230557Sjimharris   {
105230557Sjimharris      case SCSI_MODE_SENSE_PC_CURRENT:
106230557Sjimharris      case SCSI_MODE_SENSE_PC_DEFAULT:
107230557Sjimharris      case SCSI_MODE_SENSE_PC_CHANGEABLE:
108230557Sjimharris         return SATI_SUCCESS;
109230557Sjimharris      break;
110230557Sjimharris
111230557Sjimharris      default:
112230557Sjimharris      case SCSI_MODE_SENSE_PC_SAVED:
113230557Sjimharris         sati_scsi_sense_data_construct(
114230557Sjimharris            sequence,
115230557Sjimharris            scsi_io,
116230557Sjimharris            SCSI_STATUS_CHECK_CONDITION,
117230557Sjimharris            SCSI_SENSE_ILLEGAL_REQUEST,
118230557Sjimharris            SCSI_ASC_SAVING_PARMS_NOT_SUPPORTED,
119230557Sjimharris            SCSI_ASCQ_SAVING_PARMS_NOT_SUPPORTED
120230557Sjimharris         );
121230557Sjimharris         return SATI_FAILURE_CHECK_RESPONSE_DATA;
122230557Sjimharris      break;
123230557Sjimharris   }
124230557Sjimharris}
125230557Sjimharris
126230557Sjimharris/**
127230557Sjimharris * @brief This method indicates if the page code field in the SCSI CDB
128230557Sjimharris *        is supported by this translation.
129230557Sjimharris *        For more information on the parameters passed to this method,
130230557Sjimharris *        please reference sati_translate_command().
131230557Sjimharris *
132230557Sjimharris * @param[in] cdb_length This parameter specifies the length of the SCSI
133230557Sjimharris *            CDB being translated (e.g. 6-byte, 10-byte, 12-byte, etc.)
134230557Sjimharris *
135230557Sjimharris * @return This method returns an indication as to whether the page code
136230557Sjimharris *         in the CDB is supported.
137230557Sjimharris * @retval SATI_SUCCESS This value is returned if the page code is
138230557Sjimharris *         supported.
139230557Sjimharris * @retval SATI_FAILURE_CHECK_RESPONSE_DATA This value is returned if the
140230557Sjimharris *         page code is not supported.
141230557Sjimharris */
142230557Sjimharrisstatic
143230557SjimharrisSATI_STATUS sati_mode_sense_is_page_code_supported(
144230557Sjimharris   SATI_TRANSLATOR_SEQUENCE_T * sequence,
145230557Sjimharris   void                       * scsi_io,
146230557Sjimharris   U8                           cdb_length
147230557Sjimharris)
148230557Sjimharris{
149230557Sjimharris   U8 * cdb = sati_cb_get_cdb_address(scsi_io);
150230557Sjimharris
151230557Sjimharris   switch (sati_get_cdb_byte(cdb, 2) & SCSI_MODE_SENSE_PAGE_CODE_ENABLE)
152230557Sjimharris   {
153230557Sjimharris      case SCSI_MODE_PAGE_CACHING:
154230557Sjimharris         if (sati_get_cdb_byte(cdb, 0) == SCSI_MODE_SENSE_6)
155230557Sjimharris            sequence->type = SATI_SEQUENCE_MODE_SENSE_6_CACHING;
156230557Sjimharris         else
157230557Sjimharris            sequence->type = SATI_SEQUENCE_MODE_SENSE_10_CACHING;
158230557Sjimharris      break;
159230557Sjimharris
160230557Sjimharris      case SCSI_MODE_PAGE_ALL_PAGES:
161230557Sjimharris         if (sati_get_cdb_byte(cdb, 0) == SCSI_MODE_SENSE_6)
162230557Sjimharris            sequence->type = SATI_SEQUENCE_MODE_SENSE_6_ALL_PAGES;
163230557Sjimharris         else
164230557Sjimharris            sequence->type = SATI_SEQUENCE_MODE_SENSE_10_ALL_PAGES;
165230557Sjimharris      break;
166230557Sjimharris
167230557Sjimharris      case SCSI_MODE_PAGE_READ_WRITE_ERROR:
168230557Sjimharris         if (sati_get_cdb_byte(cdb, 0) == SCSI_MODE_SENSE_6)
169230557Sjimharris            sequence->type = SATI_SEQUENCE_MODE_SENSE_6_READ_WRITE_ERROR;
170230557Sjimharris         else
171230557Sjimharris            sequence->type = SATI_SEQUENCE_MODE_SENSE_10_READ_WRITE_ERROR;
172230557Sjimharris      break;
173230557Sjimharris
174230557Sjimharris      case SCSI_MODE_PAGE_DISCONNECT_RECONNECT:
175230557Sjimharris         if (sati_get_cdb_byte(cdb, 0) == SCSI_MODE_SENSE_6)
176230557Sjimharris            sequence->type = SATI_SEQUENCE_MODE_SENSE_6_DISCONNECT_RECONNECT;
177230557Sjimharris         else
178230557Sjimharris            sequence->type = SATI_SEQUENCE_MODE_SENSE_10_DISCONNECT_RECONNECT;
179230557Sjimharris      break;
180230557Sjimharris
181230557Sjimharris      case SCSI_MODE_PAGE_CONTROL:
182230557Sjimharris         if (sati_get_cdb_byte(cdb, 0) == SCSI_MODE_SENSE_6)
183230557Sjimharris            sequence->type = SATI_SEQUENCE_MODE_SENSE_6_CONTROL;
184230557Sjimharris         else
185230557Sjimharris            sequence->type = SATI_SEQUENCE_MODE_SENSE_10_CONTROL;
186230557Sjimharris      break;
187230557Sjimharris
188230557Sjimharris      case SCSI_MODE_PAGE_POWER_CONDITION:
189230557Sjimharris         if (sati_get_cdb_byte(cdb, 0) == SCSI_MODE_SENSE_6)
190230557Sjimharris            sequence->type = SATI_SEQUENCE_MODE_SENSE_6_POWER_CONDITION;
191230557Sjimharris         else
192230557Sjimharris            sequence->type = SATI_SEQUENCE_MODE_SENSE_10_POWER_CONDITION;
193230557Sjimharris      break;
194230557Sjimharris
195230557Sjimharris      case SCSI_MODE_PAGE_INFORMATIONAL_EXCP_CONTROL:
196230557Sjimharris         // The informational exceptions control page is only useful
197230557Sjimharris         // if SMART is supported.
198230557Sjimharris         if ((sequence->device->capabilities | SATI_DEVICE_CAP_SMART_SUPPORT)
199230557Sjimharris             == 0)
200230557Sjimharris         {
201230557Sjimharris            // For a MODE SENSE, utilize INVALID FIELD IN CDB,
202230557Sjimharris            // For a MODE SELECT, utilize INVALID FIELD IN PARAMETER LIST.
203230557Sjimharris            if (sati_get_cdb_byte(cdb, 0) == SCSI_MODE_SENSE_6)
204230557Sjimharris            {
205230557Sjimharris               sati_scsi_sense_data_construct(
206230557Sjimharris                  sequence,
207230557Sjimharris                  scsi_io,
208230557Sjimharris                  SCSI_STATUS_CHECK_CONDITION,
209230557Sjimharris                  SCSI_SENSE_ILLEGAL_REQUEST,
210230557Sjimharris                  SCSI_ASC_INVALID_FIELD_IN_CDB,
211230557Sjimharris                  SCSI_ASCQ_INVALID_FIELD_IN_CDB
212230557Sjimharris               );
213230557Sjimharris            }
214230557Sjimharris            else
215230557Sjimharris            {
216230557Sjimharris               sati_scsi_sense_data_construct(
217230557Sjimharris                  sequence,
218230557Sjimharris                  scsi_io,
219230557Sjimharris                  SCSI_STATUS_CHECK_CONDITION,
220230557Sjimharris                  SCSI_SENSE_ILLEGAL_REQUEST,
221230557Sjimharris                  SCSI_ASC_INVALID_FIELD_IN_PARM_LIST,
222230557Sjimharris                  SCSI_ASCQ_INVALID_FIELD_IN_PARM_LIST
223230557Sjimharris               );
224230557Sjimharris            }
225230557Sjimharris
226230557Sjimharris            return SATI_FAILURE_CHECK_RESPONSE_DATA;
227230557Sjimharris         }
228230557Sjimharris
229230557Sjimharris         if (sati_get_cdb_byte(cdb, 0) == SCSI_MODE_SENSE_6)
230230557Sjimharris            sequence->type = SATI_SEQUENCE_MODE_SENSE_6_INFORMATIONAL_EXCP_CONTROL;
231230557Sjimharris         else
232230557Sjimharris            sequence->type = SATI_SEQUENCE_MODE_SENSE_10_INFORMATIONAL_EXCP_CONTROL;
233230557Sjimharris      break;
234230557Sjimharris
235230557Sjimharris      default:
236230557Sjimharris         sati_scsi_sense_data_construct(
237230557Sjimharris            sequence,
238230557Sjimharris            scsi_io,
239230557Sjimharris            SCSI_STATUS_CHECK_CONDITION,
240230557Sjimharris            SCSI_SENSE_ILLEGAL_REQUEST,
241230557Sjimharris            SCSI_ASC_INVALID_FIELD_IN_CDB,
242230557Sjimharris            SCSI_ASCQ_INVALID_FIELD_IN_CDB
243230557Sjimharris         );
244230557Sjimharris         return SATI_FAILURE_CHECK_RESPONSE_DATA;
245230557Sjimharris      break;
246230557Sjimharris   }
247230557Sjimharris
248230557Sjimharris   return SATI_SUCCESS;
249230557Sjimharris}
250230557Sjimharris
251230557Sjimharris//******************************************************************************
252230557Sjimharris//* P R O T E C T E D   M E T H O D S
253230557Sjimharris//******************************************************************************
254230557Sjimharris
255230557Sjimharris/**
256230557Sjimharris * @brief This method will calculate the size of the mode sense data header.
257230557Sjimharris *        This includes the block descriptor if one is requested.
258230557Sjimharris *
259230557Sjimharris * @param[in] scsi_io This parameter specifies the user's SCSI IO object
260230557Sjimharris *            for which to calculate the mode page header.
261230557Sjimharris * @param[in] cdb_size This parameter specifies the number of bytes
262230557Sjimharris *            associated with the CDB for which to calculate the header.
263230557Sjimharris *
264230557Sjimharris * @return This method returns the size, in bytes, for the mode page header.
265230557Sjimharris */
266230557SjimharrisU16 sati_mode_sense_calculate_page_header(
267230557Sjimharris   void * scsi_io,
268230557Sjimharris   U8     cdb_size
269230557Sjimharris)
270230557Sjimharris{
271230557Sjimharris   U8 * cdb         = sati_cb_get_cdb_address(scsi_io);
272230557Sjimharris   U16  page_length = 0;
273230557Sjimharris
274230557Sjimharris   // The Mode page header length is different for 6-byte vs. 10-byte CDBs.
275230557Sjimharris   if (cdb_size == 6)
276230557Sjimharris      page_length += SCSI_MODE_SENSE_6_HEADER_LENGTH;
277230557Sjimharris   else
278230557Sjimharris      page_length += SCSI_MODE_SENSE_10_HEADER_LENGTH;
279230557Sjimharris
280230557Sjimharris   // Are block descriptors disabled (DBD)?  0 indicates they are enabled.
281230557Sjimharris   if ((sati_get_cdb_byte(cdb, 1) & SCSI_MODE_SENSE_DBD_ENABLE) == 0)
282230557Sjimharris   {
283230557Sjimharris      // The LLBAA bit is not defined for 6-byte mode sense requests.
284230557Sjimharris      if (  (cdb_size == 10)
285230557Sjimharris         && (sati_get_cdb_byte(cdb, 1) & SCSI_MODE_SENSE_LLBAA_ENABLE) )
286230557Sjimharris         page_length += SCSI_MODE_SENSE_LLBA_BLOCK_DESCRIPTOR_LENGTH;
287230557Sjimharris      else
288230557Sjimharris         page_length += SCSI_MODE_SENSE_STD_BLOCK_DESCRIPTOR_LENGTH;
289230557Sjimharris   }
290230557Sjimharris
291230557Sjimharris   return page_length;
292230557Sjimharris}
293230557Sjimharris
294230557Sjimharris/**
295230557Sjimharris * @brief This method performs command translation common to all mode sense
296230557Sjimharris *        requests (6 or 10 byte).
297230557Sjimharris *        For more information on the parameters passed to this method,
298230557Sjimharris *        please reference sati_translate_command().
299230557Sjimharris *
300230557Sjimharris * @param[in] cdb_length This parameter specifies the number of bytes
301230557Sjimharris *            in the CDB (6 or 10).
302230557Sjimharris *
303230557Sjimharris * @return This method returns an indication as to whether the translation
304230557Sjimharris *         succeeded.
305230557Sjimharris * @retval SCI_SUCCESS This value is returned if translation succeeded.
306230557Sjimharris * @see sati_mode_sense_is_page_control_supported() or
307230557Sjimharris *      sati_mode_sense_is_page_code_supported() for more information.
308230557Sjimharris */
309230557SjimharrisSATI_STATUS sati_mode_sense_translate_command(
310230557Sjimharris   SATI_TRANSLATOR_SEQUENCE_T * sequence,
311230557Sjimharris   void                       * scsi_io,
312230557Sjimharris   void                       * ata_io,
313230557Sjimharris   U8                           cdb_length
314230557Sjimharris)
315230557Sjimharris{
316230557Sjimharris   SATI_STATUS   status;
317230557Sjimharris
318230557Sjimharris   /**
319230557Sjimharris    * Validate that the supplied page control (PC) field is supported.
320230557Sjimharris    */
321230557Sjimharris   status = sati_mode_sense_is_page_control_supported(sequence, scsi_io);
322230557Sjimharris   if (status != SATI_SUCCESS)
323230557Sjimharris      return status;
324230557Sjimharris
325230557Sjimharris   /**
326230557Sjimharris    * Validate that the supplied page code is supported.
327230557Sjimharris    */
328230557Sjimharris   status = sati_mode_sense_is_page_code_supported(sequence,scsi_io,cdb_length);
329230557Sjimharris   if (status != SATI_SUCCESS)
330230557Sjimharris      return status;
331230557Sjimharris
332230557Sjimharris   sati_ata_identify_device_construct(ata_io, sequence);
333230557Sjimharris
334230557Sjimharris   return SATI_SUCCESS;
335230557Sjimharris}
336230557Sjimharris
337230557Sjimharris/**
338230557Sjimharris * @brief This method will build the standard block descriptor for a MODE
339230557Sjimharris *        SENSE 6 or 10 byte request.
340230557Sjimharris *        For more information on the parameters passed to this method,
341230557Sjimharris *        please reference sati_translate_command().
342230557Sjimharris *
343230557Sjimharris * @param[in] identify This parameter specifies the IDENTIFY DEVICE data
344230557Sjimharris *            associated with the SCSI IO.
345230557Sjimharris * @param[in] offset This parameter specifies the offset into the data
346230557Sjimharris *            buffer at which to build the block descriptor.
347230557Sjimharris *
348230557Sjimharris * @return This method returns the size of the block descriptor built.
349230557Sjimharris */
350230557SjimharrisU32 sati_mode_sense_build_std_block_descriptor(
351230557Sjimharris   SATI_TRANSLATOR_SEQUENCE_T * sequence,
352230557Sjimharris   void                       * scsi_io,
353230557Sjimharris   ATA_IDENTIFY_DEVICE_DATA_T * identify,
354230557Sjimharris   U32                          offset
355230557Sjimharris)
356230557Sjimharris{
357230557Sjimharris   U32  lba_low     = 0;
358230557Sjimharris   U32  lba_high    = 0;
359230557Sjimharris   U32  sector_size = 0;
360230557Sjimharris
361230557Sjimharris   // Extract the sector information (sector size, logical blocks) from
362230557Sjimharris   // the retrieved ATA identify device data.
363230557Sjimharris   sati_ata_identify_device_get_sector_info(
364230557Sjimharris      identify, &lba_high, &lba_low, &sector_size
365230557Sjimharris   );
366230557Sjimharris
367230557Sjimharris   // Fill in the 4-byte logical block address field.
368230557Sjimharris   sati_set_data_byte(sequence, scsi_io, offset,   (U8)((lba_low>>24) & 0xFF));
369230557Sjimharris   sati_set_data_byte(sequence, scsi_io, offset+1, (U8)((lba_low>>16) & 0xFF));
370230557Sjimharris   sati_set_data_byte(sequence, scsi_io, offset+2, (U8)((lba_low>>8)  & 0xFF));
371230557Sjimharris   sati_set_data_byte(sequence, scsi_io, offset+3, (U8)(lba_low & 0xFF));
372230557Sjimharris
373230557Sjimharris   // Clear the reserved field.
374230557Sjimharris   sati_set_data_byte(sequence, scsi_io, offset+4, 0);
375230557Sjimharris
376230557Sjimharris   // Fill in the three byte Block Length field
377230557Sjimharris   sati_set_data_byte(sequence,scsi_io, offset+5, (U8)((sector_size>>16) & 0xFF));
378230557Sjimharris   sati_set_data_byte(sequence,scsi_io, offset+6, (U8)((sector_size>>8)  & 0xFF));
379230557Sjimharris   sati_set_data_byte(sequence,scsi_io, offset+7, (U8)(sector_size & 0xFF));
380230557Sjimharris
381230557Sjimharris   return SCSI_MODE_SENSE_STD_BLOCK_DESCRIPTOR_LENGTH;
382230557Sjimharris}
383230557Sjimharris
384230557Sjimharris/**
385230557Sjimharris * @brief This method simply copies the mode sense data into the buffer
386230557Sjimharris *        at the location specified by page_start.  The buffer copied is
387230557Sjimharris *        determined by page_control (e.g. current, default, or changeable
388230557Sjimharris *        values).
389230557Sjimharris *        For more information on the parameters passed to this method,
390230557Sjimharris *        please reference sati_translate_command().
391230557Sjimharris *
392230557Sjimharris * @param[in] page_start This parameter specifies the starting offset at
393230557Sjimharris *            which to copy the mode page data.
394230557Sjimharris * @param[in] page_control This parameter specifies the page control
395230557Sjimharris *            indicating the source buffer to be copied.
396230557Sjimharris * @param[in] page_code This specifies the mode sense page to copy.
397230557Sjimharris *
398230557Sjimharris * @return This method returns the size of the mode page data being copied.
399230557Sjimharris */
400230557SjimharrisU32 sati_mode_sense_copy_initial_data(
401230557Sjimharris   SATI_TRANSLATOR_SEQUENCE_T * sequence,
402230557Sjimharris   void                       * scsi_io,
403230557Sjimharris   U32                          page_start,
404230557Sjimharris   U8                           page_control,
405230557Sjimharris   U8                           page_code
406230557Sjimharris)
407230557Sjimharris{
408230557Sjimharris   U16 page_index  = sati_mode_page_get_page_index(page_code);
409230557Sjimharris   U32 page_length = sat_mode_page_sizes[page_index];
410230557Sjimharris
411230557Sjimharris   // Find out if the current values are requested or if the default
412230557Sjimharris   // values are being requested.
413230557Sjimharris   if (page_control == SCSI_MODE_SENSE_PC_CHANGEABLE)
414230557Sjimharris   {
415230557Sjimharris      // Copy the changeable mode page information.
416230557Sjimharris      sati_copy_data(
417230557Sjimharris         sequence,
418230557Sjimharris         scsi_io,
419230557Sjimharris         page_start,
420230557Sjimharris         sat_changeable_mode_pages[page_index],
421230557Sjimharris         page_length
422230557Sjimharris      );
423230557Sjimharris   }
424230557Sjimharris   else
425230557Sjimharris   {
426230557Sjimharris      // Copy the default static values template to the user data area.
427230557Sjimharris      sati_copy_data(
428230557Sjimharris         sequence,
429230557Sjimharris         scsi_io,
430230557Sjimharris         page_start,
431230557Sjimharris         sat_default_mode_pages[page_index],
432230557Sjimharris         page_length
433230557Sjimharris      );
434230557Sjimharris   }
435230557Sjimharris
436230557Sjimharris   return page_length;
437230557Sjimharris}
438230557Sjimharris
439230557Sjimharris/**
440230557Sjimharris * @brief This method performs the read/write error recovery mode page
441230557Sjimharris *        specific data translation based upon the contents of the remote
442230557Sjimharris *        device IDENTIFY DEVICE data.
443230557Sjimharris *        For more information on the parameters passed to this method,
444230557Sjimharris *        please reference sati_translate_command().
445230557Sjimharris *
446230557Sjimharris * @param[in] identify This parameter specifies the remote device's
447230557Sjimharris *            IDENTIFY DEVICE data received as part of the IO request.
448230557Sjimharris * @param[in] offset This parameter specifies the offset into the data
449230557Sjimharris *            buffer where the translated data is to be written.
450230557Sjimharris *
451230557Sjimharris * @return This method returns the size of the mode page data that was
452230557Sjimharris *         translated.
453230557Sjimharris */
454230557SjimharrisU32 sati_mode_sense_read_write_error_translate_data(
455230557Sjimharris   SATI_TRANSLATOR_SEQUENCE_T * sequence,
456230557Sjimharris   void                       * scsi_io,
457230557Sjimharris   ATA_IDENTIFY_DEVICE_DATA_T * identify,
458230557Sjimharris   U32                          offset
459230557Sjimharris)
460230557Sjimharris{
461230557Sjimharris   U8 * cdb          = sati_cb_get_cdb_address(scsi_io);
462230557Sjimharris   U8   page_control = sati_get_cdb_byte(cdb, 2) >> SCSI_MODE_SENSE_PC_SHIFT;
463230557Sjimharris   U32  page_length;
464230557Sjimharris
465230557Sjimharris   page_length = sati_mode_sense_copy_initial_data(
466230557Sjimharris                    sequence,
467230557Sjimharris                    scsi_io,
468230557Sjimharris                    offset,
469230557Sjimharris                    page_control,
470230557Sjimharris                    SCSI_MODE_PAGE_READ_WRITE_ERROR
471230557Sjimharris                 );
472230557Sjimharris
473230557Sjimharris   // Currently we do not override any bits in this mode page from the
474230557Sjimharris   // identify data.
475230557Sjimharris
476230557Sjimharris   return page_length;
477230557Sjimharris}
478230557Sjimharris
479230557Sjimharris/**
480230557Sjimharris * @brief This method performs the disconnect/reconnect mode page
481230557Sjimharris *        specific data translation based upon the contents of the remote
482230557Sjimharris *        device IDENTIFY DEVICE data.
483230557Sjimharris *        For more information on the parameters passed to this method,
484230557Sjimharris *        please reference sati_translate_command().
485230557Sjimharris *
486230557Sjimharris * @param[in] identify This parameter specifies the remote device's
487230557Sjimharris *            IDENTIFY DEVICE data received as part of the IO request.
488230557Sjimharris * @param[in] offset This parameter specifies the offset into the data
489230557Sjimharris *            buffer where the translated data is to be written.
490230557Sjimharris *
491230557Sjimharris * @return This method returns the size of the mode page data that was
492230557Sjimharris *         translated.
493230557Sjimharris */
494230557SjimharrisU32 sati_mode_sense_disconnect_reconnect_translate_data(
495230557Sjimharris   SATI_TRANSLATOR_SEQUENCE_T * sequence,
496230557Sjimharris   void                       * scsi_io,
497230557Sjimharris   ATA_IDENTIFY_DEVICE_DATA_T * identify,
498230557Sjimharris   U32                          offset
499230557Sjimharris)
500230557Sjimharris{
501230557Sjimharris   U8 * cdb          = sati_cb_get_cdb_address(scsi_io);
502230557Sjimharris   U8   page_control = sati_get_cdb_byte(cdb, 2) >> SCSI_MODE_SENSE_PC_SHIFT;
503230557Sjimharris   U32  page_length;
504230557Sjimharris
505230557Sjimharris   page_length = sati_mode_sense_copy_initial_data(
506230557Sjimharris                    sequence,
507230557Sjimharris                    scsi_io,
508230557Sjimharris                    offset,
509230557Sjimharris                    page_control,
510230557Sjimharris                    SCSI_MODE_PAGE_DISCONNECT_RECONNECT
511230557Sjimharris                 );
512230557Sjimharris
513230557Sjimharris   // Currently we do not override any bits in this mode page from the
514230557Sjimharris   // identify data.
515230557Sjimharris
516230557Sjimharris   return page_length;
517230557Sjimharris}
518230557Sjimharris
519230557Sjimharris/**
520230557Sjimharris * @brief This method performs the caching mode page specific data
521230557Sjimharris *        translation based upon the contents of the remote device IDENTIFY
522230557Sjimharris *        DEVICE data.
523230557Sjimharris *        For more information on the parameters passed to this method,
524230557Sjimharris *        please reference sati_translate_command().
525230557Sjimharris *
526230557Sjimharris * @param[in] identify This parameter specifies the remote device's
527230557Sjimharris *            IDENTIFY DEVICE data received as part of the IO request.
528230557Sjimharris * @param[in] offset This parameter specifies the offset into the data
529230557Sjimharris *            buffer where the translated data is to be written.
530230557Sjimharris *
531230557Sjimharris * @return This method returns the size of the mode page data that was
532230557Sjimharris *         translated.
533230557Sjimharris */
534230557SjimharrisU32 sati_mode_sense_caching_translate_data(
535230557Sjimharris   SATI_TRANSLATOR_SEQUENCE_T * sequence,
536230557Sjimharris   void                       * scsi_io,
537230557Sjimharris   ATA_IDENTIFY_DEVICE_DATA_T * identify,
538230557Sjimharris   U32                          offset
539230557Sjimharris)
540230557Sjimharris{
541230557Sjimharris   U8 * cdb          = sati_cb_get_cdb_address(scsi_io);
542230557Sjimharris   U8   page_control = sati_get_cdb_byte(cdb, 2) >> SCSI_MODE_SENSE_PC_SHIFT;
543230557Sjimharris   U32  page_length;
544230557Sjimharris
545230557Sjimharris   page_length = sati_mode_sense_copy_initial_data(
546230557Sjimharris                    sequence,
547230557Sjimharris                    scsi_io,
548230557Sjimharris                    offset,
549230557Sjimharris                    page_control,
550230557Sjimharris                    SCSI_MODE_PAGE_CACHING
551230557Sjimharris                 );
552230557Sjimharris
553230557Sjimharris   // If the request queried for the current values, then
554230557Sjimharris   // we need to translate the data from the IDENTIFY DEVICE request.
555230557Sjimharris   if (page_control == SCSI_MODE_SENSE_PC_CURRENT)
556230557Sjimharris   {
557230557Sjimharris      U8  value;
558230557Sjimharris
559230557Sjimharris      // Update the Write Cache Enabled (WCE) bit in the mode page data
560230557Sjimharris      // buffer based on the identify response.
561230557Sjimharris      if ((identify->command_set_enabled0 & ATA_IDENTIFY_DEVICE_WCE_ENABLE) != 0)
562230557Sjimharris      {
563230557Sjimharris         sati_get_data_byte(sequence, scsi_io, offset+2, &value);
564230557Sjimharris         value |= SCSI_MODE_PAGE_CACHE_PAGE_WCE_BIT;
565230557Sjimharris         sati_set_data_byte(sequence, scsi_io, offset+2, value);
566230557Sjimharris         //This byte has been set twice and needs to be decremented
567230557Sjimharris         sequence->number_data_bytes_set--;
568230557Sjimharris      }
569230557Sjimharris
570230557Sjimharris      // Update the Disable Read Ahead (DRA) bit in the mode page data
571230557Sjimharris      // buffer based on the identify response.
572230557Sjimharris      if ((identify->command_set_enabled0 & ATA_IDENTIFY_DEVICE_RA_ENABLE) == 0)
573230557Sjimharris      {
574230557Sjimharris         // In SATA the polarity of the bits is inverse.
575230557Sjimharris         // - SCSI = Disable Read Ahead
576230557Sjimharris         // - ATA = Read Ahead
577230557Sjimharris         sati_get_data_byte(sequence, scsi_io, offset+12, &value);
578230557Sjimharris         value |= SCSI_MODE_PAGE_CACHE_PAGE_DRA_BIT;
579230557Sjimharris         sati_set_data_byte(sequence, scsi_io, offset+12, value);
580230557Sjimharris
581230557Sjimharris         //This byte has been set twice, the first time in
582230557Sjimharris         //sati_mode_sense_copy_initial_data. number_data_bytes_set
583230557Sjimharris         //needs to be decremented
584230557Sjimharris         sequence->number_data_bytes_set--;
585230557Sjimharris      }
586230557Sjimharris   }
587230557Sjimharris
588230557Sjimharris   return page_length;
589230557Sjimharris}
590230557Sjimharris
591230557Sjimharris/**
592230557Sjimharris * @brief This method performs the control mode page specific data
593230557Sjimharris *        translation based upon the contents of the remote device
594230557Sjimharris *        IDENTIFY DEVICE data.
595230557Sjimharris *        For more information on the parameters passed to this method,
596230557Sjimharris *        please reference sati_translate_command().
597230557Sjimharris *
598230557Sjimharris * @param[in] identify This parameter specifies the remote device's
599230557Sjimharris *            IDENTIFY DEVICE data received as part of the IO request.
600230557Sjimharris * @param[in] offset This parameter specifies the offset into the data
601230557Sjimharris *            buffer where the translated data is to be written.
602230557Sjimharris *
603230557Sjimharris * @return This method returns the size of the mode page data that was
604230557Sjimharris *         translated.
605230557Sjimharris */
606230557SjimharrisU32 sati_mode_sense_control_translate_data(
607230557Sjimharris   SATI_TRANSLATOR_SEQUENCE_T * sequence,
608230557Sjimharris   void                       * scsi_io,
609230557Sjimharris   ATA_IDENTIFY_DEVICE_DATA_T * identify,
610230557Sjimharris   U32                          offset
611230557Sjimharris)
612230557Sjimharris{
613230557Sjimharris   U8 * cdb          = sati_cb_get_cdb_address(scsi_io);
614230557Sjimharris   U8   page_control = sati_get_cdb_byte(cdb, 2) >> SCSI_MODE_SENSE_PC_SHIFT;
615230557Sjimharris   U32  page_length;
616230557Sjimharris   U8   value;
617230557Sjimharris
618230557Sjimharris   page_length = sati_mode_sense_copy_initial_data(
619230557Sjimharris                    sequence,
620230557Sjimharris                    scsi_io,
621230557Sjimharris                    offset,
622230557Sjimharris                    page_control,
623230557Sjimharris                    SCSI_MODE_PAGE_CONTROL
624230557Sjimharris                 );
625230557Sjimharris
626230557Sjimharris   if (sequence->device->descriptor_sense_enable)
627230557Sjimharris   {
628230557Sjimharris       sati_get_data_byte(sequence, scsi_io, offset+2,
629230557Sjimharris               &value);
630230557Sjimharris
631230557Sjimharris       sati_set_data_byte(sequence, scsi_io, offset+2,
632230557Sjimharris               value | SCSI_MODE_SELECT_MODE_PAGE_D_SENSE);
633230557Sjimharris   }
634230557Sjimharris
635230557Sjimharris   return page_length;
636230557Sjimharris}
637230557Sjimharris
638230557Sjimharris/**
639230557Sjimharris * @brief This method performs the informational exceptions control mode
640230557Sjimharris *        page specific data translation based upon the contents of the
641230557Sjimharris *        remote device IDENTIFY DEVICE data.
642230557Sjimharris *        For more information on the parameters passed to this method,
643230557Sjimharris *        please reference sati_translate_command().
644230557Sjimharris *
645230557Sjimharris * @param[in] identify This parameter specifies the remote device's
646230557Sjimharris *            IDENTIFY DEVICE data received as part of the IO request.
647230557Sjimharris * @param[in] offset This parameter specifies the offset into the data
648230557Sjimharris *            buffer where the translated data is to be written.
649230557Sjimharris *
650230557Sjimharris * @return This method returns the size of the mode page data that was
651230557Sjimharris *         translated.
652230557Sjimharris */
653230557SjimharrisU32 sati_mode_sense_informational_excp_control_translate_data(
654230557Sjimharris   SATI_TRANSLATOR_SEQUENCE_T * sequence,
655230557Sjimharris   void                       * scsi_io,
656230557Sjimharris   ATA_IDENTIFY_DEVICE_DATA_T * identify,
657230557Sjimharris   U32                          offset
658230557Sjimharris)
659230557Sjimharris{
660230557Sjimharris   U8 * cdb          = sati_cb_get_cdb_address(scsi_io);
661230557Sjimharris   U8   page_control = sati_get_cdb_byte(cdb, 2) >> SCSI_MODE_SENSE_PC_SHIFT;
662230557Sjimharris   U32  page_length;
663230557Sjimharris
664230557Sjimharris   page_length = sati_mode_sense_copy_initial_data(
665230557Sjimharris                    sequence,
666230557Sjimharris                    scsi_io,
667230557Sjimharris                    offset,
668230557Sjimharris                    page_control,
669230557Sjimharris                    SCSI_MODE_PAGE_INFORMATIONAL_EXCP_CONTROL
670230557Sjimharris                 );
671230557Sjimharris
672230557Sjimharris   // If the request queried for the current values, then
673230557Sjimharris   // we need to translate the data from the IDENTIFY DEVICE request.
674230557Sjimharris   if (page_control == SCSI_MODE_SENSE_PC_CURRENT)
675230557Sjimharris   {
676230557Sjimharris      U8 value;
677230557Sjimharris
678230557Sjimharris      sati_get_data_byte(sequence, scsi_io, offset+2, &value);
679230557Sjimharris
680230557Sjimharris      // Determine if the SMART feature set is supported and enabled.
681230557Sjimharris      if (  (identify->command_set_supported0
682230557Sjimharris                & ATA_IDENTIFY_COMMAND_SET_SUPPORTED0_SMART_ENABLE)
683230557Sjimharris         && (identify->command_set_enabled0
684230557Sjimharris                & ATA_IDENTIFY_COMMAND_SET_ENABLED0_SMART_ENABLE) )
685230557Sjimharris      {
686230557Sjimharris         // Clear the DXCPT field since the SMART feature is supported/enabled.
687230557Sjimharris         value &= ~SCSI_MODE_PAGE_INFORMATIONAL_EXCP_DXCPT_ENABLE;
688230557Sjimharris      }
689230557Sjimharris      else
690230557Sjimharris      {
691230557Sjimharris         // Set the Disable Exception Control (DXCPT) field since the SMART
692230557Sjimharris         // feature is not supported or enabled.
693230557Sjimharris         value |= SCSI_MODE_PAGE_INFORMATIONAL_EXCP_DXCPT_ENABLE;
694230557Sjimharris      }
695230557Sjimharris
696230557Sjimharris      sati_set_data_byte(sequence, scsi_io, offset+2, value);
697230557Sjimharris
698230557Sjimharris      //This byte has been set twice, the first time in
699230557Sjimharris      //sati_mode_sense_copy_initial_data. number_data_bytes_set
700230557Sjimharris      //needs to be decremented
701230557Sjimharris      sequence->number_data_bytes_set--;
702230557Sjimharris   }
703230557Sjimharris
704230557Sjimharris   return page_length;
705230557Sjimharris}
706230557Sjimharris
707230557Sjimharris/**
708230557Sjimharris* @brief This method performs the Power Condition mode page
709230557Sjimharris*        specific data translation based upon the contents of the
710230557Sjimharris*        remote device IDENTIFY DEVICE data.
711230557Sjimharris*        For more information on the parameters passed to this method,
712230557Sjimharris*        please reference sati_translate_command().
713230557Sjimharris*
714230557Sjimharris* @param[in] identify This parameter specifies the remote device's
715230557Sjimharris*            IDENTIFY DEVICE data received as part of the IO request.
716230557Sjimharris* @param[in] offset This parameter specifies the offset into the data
717230557Sjimharris*            buffer where the translated data is to be written.
718230557Sjimharris*
719230557Sjimharris* @return This method returns the size of the mode page data that was
720230557Sjimharris*         translated.
721230557Sjimharris*/
722230557SjimharrisU32 sati_mode_sense_power_condition_translate_data(
723230557Sjimharris   SATI_TRANSLATOR_SEQUENCE_T * sequence,
724230557Sjimharris   void                       * scsi_io,
725230557Sjimharris   ATA_IDENTIFY_DEVICE_DATA_T * identify,
726230557Sjimharris   U32                          offset
727230557Sjimharris)
728230557Sjimharris{
729230557Sjimharris   U8 * cdb          = sati_cb_get_cdb_address(scsi_io);
730230557Sjimharris   U8   page_control = sati_get_cdb_byte(cdb, 2) >> SCSI_MODE_SENSE_PC_SHIFT;
731230557Sjimharris
732230557Sjimharris   U8 ata_sb_timer;
733230557Sjimharris
734230557Sjimharris   //Represents tenths of seconds
735230557Sjimharris   U32 standby_timer = 0x00000000;
736230557Sjimharris
737230557Sjimharris   U8 standby_enabled = STANDBY_TIMER_DISABLED;
738230557Sjimharris
739230557Sjimharris   if ((page_control == SCSI_MODE_SENSE_PC_CURRENT) &&
740230557Sjimharris       (identify->capabilities1 & STANDBY_TIMER_SUPPORTED))
741230557Sjimharris   {
742230557Sjimharris      standby_enabled = STANDBY_TIMER_ENABLED;
743230557Sjimharris
744230557Sjimharris      ata_sb_timer = sequence->device->ata_standby_timer;
745230557Sjimharris
746230557Sjimharris      //converting ATA timer values into SCSI timer values
747230557Sjimharris      if(ata_sb_timer <= 0xF0)
748230557Sjimharris      {
749230557Sjimharris         standby_timer = ata_sb_timer * 50;
750230557Sjimharris      }
751230557Sjimharris      else if(ata_sb_timer <= 0xFB)
752230557Sjimharris      {
753230557Sjimharris         standby_timer = ((ata_sb_timer - 240) * 18000);
754230557Sjimharris      }
755230557Sjimharris      else if(ata_sb_timer == 0xFC)
756230557Sjimharris      {
757230557Sjimharris         standby_timer = 12600;
758230557Sjimharris      }
759230557Sjimharris      else if(ata_sb_timer == 0xFD)
760230557Sjimharris      {
761230557Sjimharris         standby_timer = 432000;
762230557Sjimharris      }
763230557Sjimharris      else if(ata_sb_timer == 0xFF)
764230557Sjimharris      {
765230557Sjimharris         standby_timer = 12750;
766230557Sjimharris      }
767230557Sjimharris      else
768230557Sjimharris      {
769230557Sjimharris         standby_timer = 0xFFFFFFFF;
770230557Sjimharris      }
771230557Sjimharris   }
772230557Sjimharris
773230557Sjimharris   sati_set_data_byte(sequence, scsi_io, offset, SCSI_MODE_PAGE_POWER_CONDITION);
774230557Sjimharris   sati_set_data_byte(sequence, scsi_io, offset + 1, (SCSI_MODE_PAGE_1A_LENGTH - 2));
775230557Sjimharris   sati_set_data_byte(sequence, scsi_io, offset + 2, 0x00);
776230557Sjimharris   sati_set_data_byte(sequence, scsi_io, offset + 3, standby_enabled);
777230557Sjimharris   sati_set_data_byte(sequence, scsi_io, offset + 4, 0x00);
778230557Sjimharris   sati_set_data_byte(sequence, scsi_io, offset + 5, 0x00);
779230557Sjimharris   sati_set_data_byte(sequence, scsi_io, offset + 6, 0x00);
780230557Sjimharris   sati_set_data_byte(sequence, scsi_io, offset + 7, 0x00);
781230557Sjimharris   sati_set_data_byte(sequence, scsi_io, offset + 8, (U8) (standby_timer >> 24));
782230557Sjimharris   sati_set_data_byte(sequence, scsi_io, offset + 9, (U8) (standby_timer >> 16));
783230557Sjimharris   sati_set_data_byte(sequence, scsi_io, offset + 10, (U8) (standby_timer >> 8));
784230557Sjimharris   sati_set_data_byte(sequence, scsi_io, offset + 11, (U8) standby_timer);
785230557Sjimharris
786230557Sjimharris   return SCSI_MODE_PAGE_1A_LENGTH;
787230557Sjimharris}
788230557Sjimharris
789230557Sjimharris/**
790230557Sjimharris * @brief This method performs the all pages mode page specific data
791230557Sjimharris *        translation based upon the contents of the remote device
792230557Sjimharris *        IDENTIFY DEVICE data.  The ALL PAGES mode sense request asks
793230557Sjimharris *        for all of mode pages and sub-pages in a single page.
794230557Sjimharris *        The mode pages are added in ascending order.
795230557Sjimharris *        For more information on the parameters passed to this method,
796230557Sjimharris *        please reference sati_translate_command().
797230557Sjimharris *
798230557Sjimharris * @param[in] identify This parameter specifies the remote device's
799230557Sjimharris *            IDENTIFY DEVICE data received as part of the IO request.
800230557Sjimharris * @param[in] offset This parameter specifies the offset into the data
801230557Sjimharris *            buffer where the translated data is to be written.
802230557Sjimharris *
803230557Sjimharris * @return This method returns the size of the mode page data that was
804230557Sjimharris *         translated.
805230557Sjimharris */
806230557SjimharrisU32 sati_mode_sense_all_pages_translate_data(
807230557Sjimharris   SATI_TRANSLATOR_SEQUENCE_T * sequence,
808230557Sjimharris   void                       * scsi_io,
809230557Sjimharris   ATA_IDENTIFY_DEVICE_DATA_T * identify,
810230557Sjimharris   U32                          offset
811230557Sjimharris)
812230557Sjimharris{
813230557Sjimharris   offset += sati_mode_sense_read_write_error_translate_data(
814230557Sjimharris                sequence, scsi_io, identify, offset
815230557Sjimharris             );
816230557Sjimharris
817230557Sjimharris   offset += sati_mode_sense_disconnect_reconnect_translate_data(
818230557Sjimharris                sequence, scsi_io, identify, offset
819230557Sjimharris             );
820230557Sjimharris
821230557Sjimharris   offset += sati_mode_sense_caching_translate_data(
822230557Sjimharris                sequence, scsi_io, identify, offset
823230557Sjimharris             );
824230557Sjimharris
825230557Sjimharris   offset += sati_mode_sense_control_translate_data(
826230557Sjimharris                sequence, scsi_io, identify, offset
827230557Sjimharris             );
828230557Sjimharris
829230557Sjimharris   offset += sati_mode_sense_informational_excp_control_translate_data(
830230557Sjimharris                sequence, scsi_io, identify, offset
831230557Sjimharris             );
832230557Sjimharris
833230557Sjimharris   return offset;
834230557Sjimharris}
835230557Sjimharris
836230557Sjimharris#endif // !defined(DISABLE_SATI_MODE_SENSE)
837230557Sjimharris
838