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 select (6 and 10-byte) commands with 5
60230557Sjimharris *        supported mode parameter pages (0x01, 0x02, 0x08, 0x0A, 0x1C).
61230557Sjimharris */
62230557Sjimharris
63230557Sjimharris#if !defined(DISABLE_SATI_MODE_SELECT)
64230557Sjimharris
65230557Sjimharris#include <dev/isci/scil/sati_mode_select.h>
66230557Sjimharris#include <dev/isci/scil/sati_mode_pages.h>
67230557Sjimharris#include <dev/isci/scil/sati_callbacks.h>
68230557Sjimharris#include <dev/isci/scil/sci_object.h>
69230557Sjimharris#include <dev/isci/scil/sati_translator_sequence.h>
70230557Sjimharris#include <dev/isci/scil/sati_util.h>
71230557Sjimharris
72230557Sjimharris//******************************************************************************
73230557Sjimharris//* P R I V A T E   M E T H O D S
74230557Sjimharris//******************************************************************************
75230557Sjimharris
76230557Sjimharris/**
77230557Sjimharris * @brief This method will get medium type parameter field per CDB size.
78230557Sjimharris *
79230557Sjimharris * @param[in] scsi_io This parameter specifies the user's SCSI IO object
80230557Sjimharris *            for which to calculate the mode page header.
81230557Sjimharris * @param[in] cdb_size This parameter specifies the number of bytes
82230557Sjimharris *            associated with the CDB for which to calculate the header.
83230557Sjimharris *
84230557Sjimharris * @return This method returns the medium type for the mode page header.
85230557Sjimharris */
86230557Sjimharrisstatic
87230557SjimharrisU8 sati_mode_select_get_medium_type(
88230557Sjimharris   U8 * mode_parameters,
89230557Sjimharris   U32  cdb_size
90230557Sjimharris)
91230557Sjimharris{
92230557Sjimharris   U8  medium_type =0xFF;
93230557Sjimharris   SCSI_MODE_SELECT_MODE_PARAMETER_HEADER_6_T * mode_parameters_6;
94230557Sjimharris   SCSI_MODE_SELECT_MODE_PARAMETER_HEADER_10_T * mode_parameters_10;
95230557Sjimharris
96230557Sjimharris   if(cdb_size == 6)
97230557Sjimharris   {
98230557Sjimharris      mode_parameters_6 = (SCSI_MODE_SELECT_MODE_PARAMETER_HEADER_6_T *) mode_parameters;
99230557Sjimharris      medium_type = mode_parameters_6->medium_type;
100230557Sjimharris   }
101230557Sjimharris   else if(cdb_size == 10)
102230557Sjimharris   {
103230557Sjimharris      mode_parameters_10 = (SCSI_MODE_SELECT_MODE_PARAMETER_HEADER_10_T *) mode_parameters;
104230557Sjimharris      medium_type = mode_parameters_10->medium_type;
105230557Sjimharris   }
106230557Sjimharris
107230557Sjimharris   return medium_type;
108230557Sjimharris}
109230557Sjimharris
110230557Sjimharris/**
111230557Sjimharris * @brief This method will retrieve Block Descriptor Length.
112230557Sjimharris *
113230557Sjimharris * @param[in] mode_parameters This parameter contains the address to the mode parameters.
114230557Sjimharris * @param[in] cdb_size This parameter specifies the number of bytes
115230557Sjimharris *            associated with the CDB for which to process the block descriptor.
116230557Sjimharris *
117230557Sjimharris * @return This method returns the size, in bytes, for the mode parameter block descriptor.
118230557Sjimharris */
119230557Sjimharrisstatic
120230557SjimharrisU32 sati_mode_select_get_mode_block_descriptor_length(
121230557Sjimharris   U8 * mode_parameters,
122230557Sjimharris   U32  cdb_size
123230557Sjimharris)
124230557Sjimharris{
125230557Sjimharris   U32 mode_block_descriptor_length = 0;
126230557Sjimharris   SCSI_MODE_SELECT_MODE_PARAMETER_HEADER_6_T * mode_parameters_6;
127230557Sjimharris   SCSI_MODE_SELECT_MODE_PARAMETER_HEADER_10_T * mode_parameters_10;
128230557Sjimharris
129230557Sjimharris   if(cdb_size == 6)
130230557Sjimharris   {
131230557Sjimharris      mode_parameters_6 = (SCSI_MODE_SELECT_MODE_PARAMETER_HEADER_6_T *) mode_parameters;
132230557Sjimharris      mode_block_descriptor_length = mode_parameters_6->block_descriptor_length;
133230557Sjimharris   }
134230557Sjimharris   else if(cdb_size == 10)
135230557Sjimharris   {
136230557Sjimharris      mode_parameters_10 = (SCSI_MODE_SELECT_MODE_PARAMETER_HEADER_10_T *) mode_parameters;
137230557Sjimharris      //Long LBA bit is the bit0 of the byte
138230557Sjimharris      //Spec says another way to get the block descriptor length to multiply the block number
139230557Sjimharris      //   with block length (8 or 16), but we can get it directly.
140230557Sjimharris      mode_block_descriptor_length =(((U16)mode_parameters_10->block_descriptor_length[0]) << 8) +
141230557Sjimharris         mode_parameters_10->block_descriptor_length[1];
142230557Sjimharris
143230557Sjimharris   }
144230557Sjimharris
145230557Sjimharris   return mode_block_descriptor_length;
146230557Sjimharris
147230557Sjimharris}
148230557Sjimharris
149230557Sjimharris/**
150230557Sjimharris * @brief This method will find the starting byte location for a page.
151230557Sjimharris *
152230557Sjimharris * @param[in] block_descriptor_length This parameter passes in the length of
153230557Sjimharris *            block descriptor.
154230557Sjimharris * @param[in] cdb_size This parameter specifies the number of bytes
155230557Sjimharris *            associated with the CDB for which to calculate the header.
156230557Sjimharris *
157230557Sjimharris * @return This method returns the offset, for the mode page.
158230557Sjimharris */
159230557Sjimharrisstatic
160230557SjimharrisU32 sati_mode_select_get_mode_page_offset(
161230557Sjimharris    U32 block_descriptor_length,
162230557Sjimharris    U32 cdb_size
163230557Sjimharris    )
164230557Sjimharris{
165230557Sjimharris   U32 mode_page_offset;
166230557Sjimharris
167230557Sjimharris   if(cdb_size == 6)
168230557Sjimharris   {
169230557Sjimharris      mode_page_offset =  sizeof(SCSI_MODE_SELECT_MODE_PARAMETER_HEADER_6_T) +  block_descriptor_length;
170230557Sjimharris   }
171230557Sjimharris   else if(cdb_size == 10)
172230557Sjimharris   {
173230557Sjimharris      mode_page_offset =  sizeof(SCSI_MODE_SELECT_MODE_PARAMETER_HEADER_10_T) +  block_descriptor_length;
174230557Sjimharris   }
175230557Sjimharris   else
176230557Sjimharris   {
177230557Sjimharris      mode_page_offset = 0;
178230557Sjimharris   }
179230557Sjimharris
180230557Sjimharris   return mode_page_offset;
181230557Sjimharris}
182230557Sjimharris
183230557Sjimharris/**
184230557Sjimharris * @brief This method will set the initial Mode Select processing state.
185230557Sjimharris */
186230557Sjimharrisstatic
187230557Sjimharrisvoid  sati_mode_select_initialize_mode_sel_processing_state(
188230557Sjimharris   SATI_TRANSLATOR_SEQUENCE_T * sequence,
189230557Sjimharris   void                       * scsi_io,
190230557Sjimharris   void                       * ata_io,
191230557Sjimharris   U32 data_transfer_length,
192230557Sjimharris   U32 mode_page_offset
193230557Sjimharris   )
194230557Sjimharris{
195230557Sjimharris   sequence->command_specific_data.process_state.ata_command_sent_for_cmp = 0;
196230557Sjimharris   sequence->command_specific_data.process_state.mode_page_offset=mode_page_offset;
197230557Sjimharris   sequence->command_specific_data.process_state.mode_pages_size = data_transfer_length  -  mode_page_offset;
198230557Sjimharris   sequence->command_specific_data.process_state.size_of_data_processed = 0;
199230557Sjimharris   sequence->command_specific_data.process_state.current_mode_page_processed = FALSE;
200230557Sjimharris}
201230557Sjimharris
202230557Sjimharris/**
203230557Sjimharris * @brief This method will get mode page size.
204230557Sjimharris *
205230557Sjimharris * @param[in] page_code This parameter contains page code for the current mode page.
206230557Sjimharris *
207230557Sjimharris * @return This method returns the size of current mode page.
208230557Sjimharris */
209230557Sjimharrisstatic
210230557SjimharrisU32 sati_mode_select_get_mode_page_size(
211230557Sjimharris   U8 page_code
212230557Sjimharris)
213230557Sjimharris{
214230557Sjimharris   U32 page_size=0;
215230557Sjimharris
216230557Sjimharris   switch (page_code)
217230557Sjimharris   {
218230557Sjimharris   case SCSI_MODE_PAGE_READ_WRITE_ERROR:
219230557Sjimharris      page_size=SCSI_MODE_PAGE_01_LENGTH;
220230557Sjimharris      break;
221230557Sjimharris
222230557Sjimharris   case SCSI_MODE_PAGE_DISCONNECT_RECONNECT:
223230557Sjimharris      page_size=SCSI_MODE_PAGE_02_LENGTH;
224230557Sjimharris      break;
225230557Sjimharris
226230557Sjimharris   case SCSI_MODE_PAGE_CACHING:
227230557Sjimharris      page_size=SCSI_MODE_PAGE_08_LENGTH;
228230557Sjimharris      break;
229230557Sjimharris
230230557Sjimharris   case SCSI_MODE_PAGE_CONTROL:
231230557Sjimharris      page_size=SCSI_MODE_PAGE_0A_LENGTH;
232230557Sjimharris      break;
233230557Sjimharris
234230557Sjimharris   case SCSI_MODE_PAGE_INFORMATIONAL_EXCP_CONTROL:
235230557Sjimharris      page_size=SCSI_MODE_PAGE_1C_LENGTH;
236230557Sjimharris      break;
237230557Sjimharris
238230557Sjimharris   case SCSI_MODE_PAGE_POWER_CONDITION:
239230557Sjimharris      page_size=SCSI_MODE_PAGE_1A_LENGTH;
240230557Sjimharris      break;
241230557Sjimharris   default:
242230557Sjimharris      page_size=0;
243230557Sjimharris      break;
244230557Sjimharris   }
245230557Sjimharris
246230557Sjimharris   return page_size;
247230557Sjimharris}
248230557Sjimharris
249230557Sjimharris/**
250230557Sjimharris * @brief This method will check the validity of parameter data of Read Write Error Recovery
251230557Sjimharris *            page and further processing the page data if necessary.
252230557Sjimharris *
253230557Sjimharris * @param[in] page_size This parameter specifies page size of current mode page.
254230557Sjimharris *
255230557Sjimharris * @return Indicate if the translation was successful.
256230557Sjimharris * @retval SATI_SUCCESS
257230557Sjimharris * @retval SATI_COMPLETE
258230557Sjimharris * @retval SATI_FAILURE_CHECK_RESPONSE_DATA
259230557Sjimharris */
260230557Sjimharrisstatic
261230557SjimharrisSATI_STATUS sati_mode_select_process_mode_page_read_write_error_recovery(
262230557Sjimharris   SATI_TRANSLATOR_SEQUENCE_T* sequence,
263230557Sjimharris   void     *  scsi_io,
264230557Sjimharris   U32   page_size
265230557Sjimharris   )
266230557Sjimharris{
267230557Sjimharris   SATI_STATUS status = SATI_FAILURE_CHECK_RESPONSE_DATA;
268230557Sjimharris
269230557Sjimharris   U8 current_mode_page[SCSI_MODE_PAGE_01_LENGTH]={0,0,0,0,0,0,0,0,0,0,0,0};
270230557Sjimharris   U32 mode_page_offset;
271230557Sjimharris
272230557Sjimharris   mode_page_offset = sequence->command_specific_data.process_state.mode_page_offset;
273230557Sjimharris
274230557Sjimharris   //Check all the defined bits for this page
275230557Sjimharris   //SPF(0b); Page length 0x0A;AWRE 1; ARRE 0; Error recovery bits 0; RC 0;
276230557Sjimharris   //Recovery time limit last two bytes 0
277230557Sjimharris
278230557Sjimharris   sati_get_data_byte(sequence, scsi_io, mode_page_offset,   &current_mode_page[0]);
279230557Sjimharris   sati_get_data_byte(sequence, scsi_io, mode_page_offset+1, &current_mode_page[1]);
280230557Sjimharris   sati_get_data_byte(sequence, scsi_io, mode_page_offset+2, &current_mode_page[2]);
281230557Sjimharris   sati_get_data_byte(sequence, scsi_io, mode_page_offset+10, &current_mode_page[10]);
282230557Sjimharris   sati_get_data_byte(sequence, scsi_io, mode_page_offset+11, &current_mode_page[11]);
283230557Sjimharris
284230557Sjimharris   if ( ((current_mode_page[0] & SCSI_MODE_SELECT_MODE_PAGE_SPF_MASK)!= 0) ||
285230557Sjimharris      (current_mode_page[1] != (SCSI_MODE_PAGE_01_LENGTH - 2)) ||
286230557Sjimharris      ((current_mode_page[2] & SCSI_MODE_SELECT_MODE_PAGE_01_AWRE_MASK) == 0) ||
287230557Sjimharris      ((current_mode_page[2] & SCSI_MODE_SELECT_MODE_PAGE_01_ARRE_MASK) != 0) ||
288230557Sjimharris      ((current_mode_page[2] & SCSI_MODE_SELECT_MODE_PAGE_01_RC_ERBITS_MASK) != 0) ||
289230557Sjimharris      (current_mode_page[10] != 0 ) ||
290230557Sjimharris      (current_mode_page[11] != 0 ) )
291230557Sjimharris   {
292230557Sjimharris      status = SATI_FAILURE_CHECK_RESPONSE_DATA;
293230557Sjimharris      return status;
294230557Sjimharris   }
295230557Sjimharris
296230557Sjimharris   //no need to send any command
297230557Sjimharris   {
298230557Sjimharris      sequence->command_specific_data.process_state.size_of_data_processed += page_size;
299230557Sjimharris      sequence->command_specific_data.process_state.mode_page_offset += page_size;
300230557Sjimharris      sequence->command_specific_data.process_state.current_mode_page_processed = TRUE;
301230557Sjimharris   }
302230557Sjimharris
303230557Sjimharris   status = SATI_COMPLETE;
304230557Sjimharris
305230557Sjimharris   return status;
306230557Sjimharris}
307230557Sjimharris
308230557Sjimharris/**
309230557Sjimharris * @brief This method will check the validity of parameter data of Disconnect Reconnect mode
310230557Sjimharris *            page and further processing the page data if necessary.
311230557Sjimharris *
312230557Sjimharris * @param[in] page_size This parameter specifies page size of current mode page.
313230557Sjimharris *
314230557Sjimharris * @return Indicate if the translation was successful.
315230557Sjimharris * @retval SATI_SUCCESS
316230557Sjimharris * @retval SATI_COMPLETE
317230557Sjimharris * @retval SATI_FAILURE_CHECK_RESPONSE_DATA
318230557Sjimharris */
319230557Sjimharrisstatic
320230557SjimharrisSATI_STATUS sati_mode_select_process_mode_page_disconnect_reconnect(
321230557Sjimharris   SATI_MODE_SELECT_PROCESSING_STATE_T * mode_select_process_state,
322230557Sjimharris   U32 page_size
323230557Sjimharris   )
324230557Sjimharris{
325230557Sjimharris   SATI_STATUS status = SATI_FAILURE_CHECK_RESPONSE_DATA;
326230557Sjimharris
327230557Sjimharris   // No need to check data for valid or invalid this page (undefined)
328230557Sjimharris   // No ata command to send
329230557Sjimharris   {
330230557Sjimharris      mode_select_process_state->size_of_data_processed += page_size;
331230557Sjimharris      mode_select_process_state->mode_page_offset += page_size;
332230557Sjimharris      mode_select_process_state->current_mode_page_processed = TRUE;
333230557Sjimharris   }
334230557Sjimharris
335230557Sjimharris   // No further interaction with remote devices
336230557Sjimharris   status = SATI_COMPLETE;
337230557Sjimharris
338230557Sjimharris   return status;
339230557Sjimharris}
340230557Sjimharris
341230557Sjimharris/**
342230557Sjimharris * @brief This method will check the validity of parameter data of Caching mode
343230557Sjimharris *            page and issue multiple ATA set feature commands to complete the translation.
344230557Sjimharris *
345230557Sjimharris * @param[in] page_size This parameter specifies page size of current mode page.
346230557Sjimharris *
347230557Sjimharris * @return Indicate if the translation was successful.
348230557Sjimharris * @retval SATI_SUCCESS
349230557Sjimharris * @retval SATI_COMPLETE
350230557Sjimharris * @retval SATI_FAILURE_CHECK_RESPONSE_DATA
351230557Sjimharris */
352230557Sjimharrisstatic
353230557SjimharrisSATI_STATUS sati_mode_select_process_mode_page_caching(
354230557Sjimharris   SATI_TRANSLATOR_SEQUENCE_T * sequence,
355230557Sjimharris   void * scsi_io,
356230557Sjimharris   void * ata_io,
357230557Sjimharris   U32 page_size
358230557Sjimharris   )
359230557Sjimharris{
360230557Sjimharris   SATI_STATUS status = SATI_FAILURE_CHECK_RESPONSE_DATA;
361230557Sjimharris
362230557Sjimharris   //SCSI_MODE_PAGE_08_LENGTH 0x14= 20
363230557Sjimharris   U8 current_mode_page[SCSI_MODE_PAGE_08_LENGTH] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
364230557Sjimharris   U32 mode_page_offset;
365230557Sjimharris   U32 index;
366230557Sjimharris
367230557Sjimharris   mode_page_offset = sequence->command_specific_data.process_state.mode_page_offset;
368230557Sjimharris   sequence->type = SATI_SEQUENCE_MODE_SELECT_MODE_PAGE_CACHING;
369230557Sjimharris
370230557Sjimharris   for(index = 0; index < SCSI_MODE_PAGE_08_LENGTH; index++)
371230557Sjimharris   {
372230557Sjimharris      sati_get_data_byte(sequence, scsi_io, mode_page_offset+index, &current_mode_page[index]);
373230557Sjimharris   }
374230557Sjimharris
375230557Sjimharris   //Check for data validity
376230557Sjimharris   //SPF(0b); Page length 0x12;Byte2 to Byte15 all 0 with exception DRA and WCE changeable
377230557Sjimharris
378230557Sjimharris   if (((current_mode_page[0] & SCSI_MODE_SELECT_MODE_PAGE_SPF_MASK)!= 0) ||
379230557Sjimharris      (current_mode_page[1] != (SCSI_MODE_PAGE_08_LENGTH-2)) ||
380230557Sjimharris      ((current_mode_page[2] | SCSI_MODE_PAGE_CACHE_PAGE_WCE_BIT)!=SCSI_MODE_PAGE_CACHE_PAGE_WCE_BIT) ||
381230557Sjimharris      (current_mode_page[3] != 0 ) ||
382230557Sjimharris      (current_mode_page[4] != 0 ) ||
383230557Sjimharris      (current_mode_page[5] != 0 ) ||
384230557Sjimharris      (current_mode_page[6] != 0 ) ||
385230557Sjimharris      (current_mode_page[7] != 0 ) ||
386230557Sjimharris      (current_mode_page[8] != 0 ) ||
387230557Sjimharris      (current_mode_page[9] != 0 ) ||
388230557Sjimharris      (current_mode_page[10] != 0 ) ||
389230557Sjimharris      (current_mode_page[11] != 0 ) ||
390230557Sjimharris      ((current_mode_page[12] & SCSI_MODE_SELECT_MODE_PAGE_08_FSW_LBCSS_NVDIS) != 0) ||
391230557Sjimharris      (current_mode_page[13] != 0 ) ||
392230557Sjimharris      (current_mode_page[14] != 0 ) ||
393230557Sjimharris      (current_mode_page[15] != 0 ))
394230557Sjimharris   {
395230557Sjimharris      //parameter data passed in containing data that doesn't meet the SAT-2 requirement
396230557Sjimharris      return SATI_FAILURE_CHECK_RESPONSE_DATA;
397230557Sjimharris   }
398230557Sjimharris
399230557Sjimharris   if(sequence->command_specific_data.process_state.ata_command_sent_for_cmp == 0)
400230557Sjimharris   {
401230557Sjimharris      //byte2 bit2 WCE==0 disable write cache WCE==1 enable write cache
402230557Sjimharris      //SCSI_MODE_PAGE_CACHE_PAGE_WCE_BIT ==0x4,
403230557Sjimharris
404230557Sjimharris      if ( (current_mode_page[2] & SCSI_MODE_PAGE_CACHE_PAGE_WCE_BIT) == 0)
405230557Sjimharris         sati_ata_set_features_construct(ata_io, sequence, ATA_SET_FEATURES_SUB_CMD_DISABLE_CACHE);
406230557Sjimharris      else
407230557Sjimharris         sati_ata_set_features_construct(ata_io, sequence, ATA_SET_FEATURES_SUB_CMD_ENABLE_CACHE);
408230557Sjimharris
409230557Sjimharris   }
410230557Sjimharris   else if(sequence->command_specific_data.process_state.ata_command_sent_for_cmp == 1)
411230557Sjimharris   {
412230557Sjimharris      // DRA bit is set to 0, enable Read look ahead AAh;
413230557Sjimharris      // DRA bit is set to 1, disable with set feature command 55h
414230557Sjimharris      // SCSI_MODE_PAGE_CACHE_PAGE_DRA_BIT== 0x20
415230557Sjimharris
416230557Sjimharris      if ( (current_mode_page[12] & SCSI_MODE_PAGE_CACHE_PAGE_DRA_BIT) == 0)
417230557Sjimharris         sati_ata_set_features_construct(ata_io, sequence,ATA_SET_FEATURES_SUB_CMD_ENABLE_READ_AHEAD);
418230557Sjimharris      else
419230557Sjimharris         sati_ata_set_features_construct(ata_io, sequence,ATA_SET_FEATURES_SUB_CMD_DISABLE_READ_AHEAD);
420230557Sjimharris
421230557Sjimharris      sequence->command_specific_data.process_state.size_of_data_processed += page_size;
422230557Sjimharris      sequence->command_specific_data.process_state.mode_page_offset += page_size;
423230557Sjimharris      sequence->command_specific_data.process_state.current_mode_page_processed = TRUE;
424230557Sjimharris
425230557Sjimharris
426230557Sjimharris   }
427230557Sjimharris   // No more ata commands to send
428230557Sjimharris
429230557Sjimharris   sequence->command_specific_data.process_state.ata_command_sent_for_cmp++;
430230557Sjimharris
431230557Sjimharris   status = SATI_SUCCESS;
432230557Sjimharris
433230557Sjimharris   return status;
434230557Sjimharris}
435230557Sjimharris
436230557Sjimharris/**
437230557Sjimharris * @brief This method will check the validity of parameter data of Control mode
438230557Sjimharris *            page and further processing the page data if necessary.
439230557Sjimharris *
440230557Sjimharris * @param[in] mode_select_process_state This parameter points to the processing state fields
441230557Sjimharris *            of current mode page.
442230557Sjimharris * @param[in] page_size This parameter specifies page size of current mode page.
443230557Sjimharris *
444230557Sjimharris * @return Indicate if the translation was successful.
445230557Sjimharris * @retval SATI_SUCCESS
446230557Sjimharris * @retval SATI_COMPLETE
447230557Sjimharris * @retval SATI_FAILURE_CHECK_RESPONSE_DATA
448230557Sjimharris */
449230557Sjimharrisstatic
450230557SjimharrisSATI_STATUS sati_mode_select_process_mode_page_control(
451230557Sjimharris         SATI_TRANSLATOR_SEQUENCE_T* sequence,
452230557Sjimharris         void     *  scsi_io,
453230557Sjimharris         void     *  ata_io,
454230557Sjimharris         U32 page_size
455230557Sjimharris      )
456230557Sjimharris{
457230557Sjimharris   SATI_STATUS status = SATI_FAILURE_CHECK_RESPONSE_DATA;
458230557Sjimharris
459230557Sjimharris   //SCSI_MODE_PAGE_0A_LENGTH 12
460230557Sjimharris   U8 current_mode_page[SCSI_MODE_PAGE_0A_LENGTH]={0,0,0,0,0,0,0,0,0,0};
461230557Sjimharris   U32 mode_page_offset;
462230557Sjimharris   U32 index;
463230557Sjimharris
464230557Sjimharris   mode_page_offset = sequence->command_specific_data.process_state.mode_page_offset;
465230557Sjimharris
466230557Sjimharris   for(index = 0; index < SCSI_MODE_PAGE_0A_LENGTH; index++)
467230557Sjimharris   {
468230557Sjimharris      sati_get_data_byte(sequence, scsi_io, mode_page_offset+index, &current_mode_page[index]);
469230557Sjimharris   }
470230557Sjimharris
471230557Sjimharris   //bit 1 and 2 of byte3 Qerr full task management model etc. then both bits 0
472230557Sjimharris   //byte 8 and 9 busy time out period variable if not ffff setable?
473230557Sjimharris   //check for page data validity
474230557Sjimharris   //Byte2: 0000???0b  Byte3: Queued Algorithm Modifier should be set to 1 QErr?
475230557Sjimharris   //Byte4: ??000???   Byte5: ?0???000
476230557Sjimharris
477230557Sjimharris   if (((current_mode_page[0] & SCSI_MODE_SELECT_MODE_PAGE_SPF_MASK)!= 0) ||
478230557Sjimharris      (current_mode_page[1] != (SCSI_MODE_PAGE_0A_LENGTH - 2)) ||
479230557Sjimharris      ((current_mode_page[2] & SCSI_MODE_SELECT_MODE_PAGE_0A_TST_TMF_RLEC) != 0) ||
480230557Sjimharris      ((current_mode_page[3] & SCSI_MODE_SELECT_MODE_PAGE_0A_MODIFIER) != 0) ||
481230557Sjimharris      ((current_mode_page[4] & SCSI_MODE_SELECT_MODE_PAGE_0A_UA_SWP ) != 0) ||
482230557Sjimharris      ((current_mode_page[5] & SCSI_MODE_SELECT_MODE_PAGE_0A_TAS_AUTO ) != 0 ) )
483230557Sjimharris   {
484230557Sjimharris      return SATI_FAILURE_CHECK_RESPONSE_DATA;
485230557Sjimharris   }
486230557Sjimharris
487230557Sjimharris   if ((current_mode_page[2] & SCSI_MODE_SELECT_MODE_PAGE_D_SENSE) != 0)
488230557Sjimharris       sequence->device->descriptor_sense_enable = SCSI_MODE_PAGE_CONTROL_D_SENSE_ENABLE;
489230557Sjimharris   else
490230557Sjimharris       sequence->device->descriptor_sense_enable = SCSI_MODE_PAGE_CONTROL_D_SENSE_DISABLE;
491230557Sjimharris
492230557Sjimharris   // no ata command need to be comfirmed
493230557Sjimharris   {
494230557Sjimharris      sequence->command_specific_data.process_state.size_of_data_processed += page_size;
495230557Sjimharris      sequence->command_specific_data.process_state.mode_page_offset += page_size;
496230557Sjimharris      sequence->command_specific_data.process_state.current_mode_page_processed = TRUE;
497230557Sjimharris   }
498230557Sjimharris
499230557Sjimharris   status = SATI_COMPLETE;
500230557Sjimharris
501230557Sjimharris   return status;
502230557Sjimharris}
503230557Sjimharris
504230557Sjimharris/**
505230557Sjimharris * @brief This method will check the validity of parameter data of Information Exception Control
506230557Sjimharris *            mode page and further processing the page data if necessary.
507230557Sjimharris *
508230557Sjimharris * @param[in] page_size This parameter specifies page size of current mode page.
509230557Sjimharris *
510230557Sjimharris * @return Indicate if the translation was successful.
511230557Sjimharris * @retval SATI_SUCCESS
512230557Sjimharris * @retval SATI_COMPLETE
513230557Sjimharris * @retval SATI_FAILURE_CHECK_RESPONSE_DATA
514230557Sjimharris */
515230557Sjimharrisstatic
516230557SjimharrisSATI_STATUS sati_mode_select_process_mode_page_informational_exception_control(
517230557Sjimharris   SATI_TRANSLATOR_SEQUENCE_T * sequence,
518230557Sjimharris   void     *  scsi_io,
519230557Sjimharris   void     *  ata_io,
520230557Sjimharris   U32 page_size
521230557Sjimharris   )
522230557Sjimharris{
523230557Sjimharris   SATI_STATUS status = SATI_FAILURE_CHECK_RESPONSE_DATA;
524230557Sjimharris
525230557Sjimharris   //SCSI_MODE_PAGE_1C_LENGTH 12
526230557Sjimharris   U8 current_mode_page[SCSI_MODE_PAGE_1C_LENGTH]={0,0,0,0,0,0,0,0,0,0,0,0};
527230557Sjimharris   U32 mode_page_offset;
528230557Sjimharris   U32 index;
529230557Sjimharris
530230557Sjimharris   mode_page_offset = sequence->command_specific_data.process_state.mode_page_offset;
531230557Sjimharris   sequence->type = SATI_SEQUENCE_MODE_SELECT_MODE_INFORMATION_EXCEPT_CONTROL;
532230557Sjimharris
533230557Sjimharris   for(index = 0; index < 4; index++)
534230557Sjimharris   {
535230557Sjimharris      sati_get_data_byte(sequence, scsi_io, mode_page_offset+index, &current_mode_page[index]);
536230557Sjimharris   }
537230557Sjimharris
538230557Sjimharris   //Check for data validity
539230557Sjimharris   //SPF(0b); Page length 0x0A; Byte2 0????0?? Byte3: ????1100
540230557Sjimharris   //SCSI_MODE_SELECT_MODE_PAGE_MRIE_BYTE same as REPORT_INFO_EXCEPTION_CONDITION_ON_REQUEST 0x6
541230557Sjimharris   //SCSI_MODE_PAGE_DEXCPT_ENABLE
542230557Sjimharris
543230557Sjimharris   if (((current_mode_page[0] & SCSI_MODE_SELECT_MODE_PAGE_SPF_MASK)!= 0) ||
544230557Sjimharris      (current_mode_page[1] != (SCSI_MODE_PAGE_1C_LENGTH - 2)) ||
545230557Sjimharris      ((current_mode_page[2] & SCSI_MODE_SELECT_MODE_PAGE_1C_PERF_TEST)!= 0 ) ||
546230557Sjimharris      ((current_mode_page[3] & SCSI_MODE_SELECT_MODE_PAGE_MRIE_MASK) !=
547230557Sjimharris      SCSI_MODE_SELECT_MODE_PAGE_MRIE_BYTE ))
548230557Sjimharris   {
549230557Sjimharris      return SATI_FAILURE_CHECK_RESPONSE_DATA;
550230557Sjimharris   }
551230557Sjimharris
552230557Sjimharris   // DEXCPT bit is set to 0, enable SMART reporting D8h;
553230557Sjimharris   // DEXCPT bit is set to 1, disable SMART reporting D9h
554230557Sjimharris   // SCSI_MODE_PAGE_DEXCPT_ENABLE== 0x08
555230557Sjimharris
556230557Sjimharris   if ( (current_mode_page[2] & SCSI_MODE_PAGE_DEXCPT_ENABLE) == 0)
557230557Sjimharris      sati_ata_smart_return_status_construct(ata_io, sequence, ATA_SMART_SUB_CMD_ENABLE);
558230557Sjimharris   else
559230557Sjimharris      sati_ata_smart_return_status_construct(ata_io, sequence, ATA_SMART_SUB_CMD_DISABLE);
560230557Sjimharris
561230557Sjimharris   sequence->command_specific_data.process_state.size_of_data_processed += page_size;
562230557Sjimharris   sequence->command_specific_data.process_state.mode_page_offset += page_size;
563230557Sjimharris   sequence->command_specific_data.process_state.current_mode_page_processed = TRUE;
564230557Sjimharris   // No more ata commands to send
565230557Sjimharris
566230557Sjimharris   status = SATI_SUCCESS;
567230557Sjimharris
568230557Sjimharris   return status;
569230557Sjimharris}
570230557Sjimharris
571230557Sjimharris/**
572230557Sjimharris * @brief This method will check the validity of parameter data of Power Condition mode
573230557Sjimharris *            page and issue multiple ATA set feature commands to complete the translation.
574230557Sjimharris *
575230557Sjimharris * @param[in] mode_select_process_state This parameter points to the processing state fields
576230557Sjimharris *            of current mode page.
577230557Sjimharris * @param[in] page_size This parameter specifies page size of current mode page.
578230557Sjimharris *
579230557Sjimharris * @return Indicate if the translation was successful.
580230557Sjimharris * @retval SATI_SUCCESS
581230557Sjimharris * @retval SATI_COMPLETE
582230557Sjimharris * @retval SATI_FAILURE_CHECK_RESPONSE_DATA
583230557Sjimharris */
584230557Sjimharrisstatic
585230557SjimharrisSATI_STATUS sati_mode_select_process_mode_page_power_condition(
586230557Sjimharris   SATI_TRANSLATOR_SEQUENCE_T * sequence,
587230557Sjimharris   void * scsi_io,
588230557Sjimharris   void * ata_io,
589230557Sjimharris   U32 page_size
590230557Sjimharris   )
591230557Sjimharris{
592230557Sjimharris   SATI_STATUS status = SATI_FAILURE_CHECK_RESPONSE_DATA;
593230557Sjimharris
594230557Sjimharris   //SCSI_MODE_PAGE_1A_LENGTH 10
595230557Sjimharris   U8 current_mode_page[SCSI_MODE_PAGE_1A_LENGTH] = {0,0,0,0,0,0,0,0,0,0};
596230557Sjimharris   U32 mode_page_offset;
597230557Sjimharris   U32 index;
598230557Sjimharris
599230557Sjimharris   U32 timer = 0;
600230557Sjimharris   U16 count = 0;
601230557Sjimharris
602230557Sjimharris   mode_page_offset = sequence->command_specific_data.process_state.mode_page_offset;
603230557Sjimharris
604230557Sjimharris   sequence->type = SATI_SEQUENCE_MODE_SELECT_MODE_POWER_CONDITION;
605230557Sjimharris
606230557Sjimharris   for(index = 0; index < SCSI_MODE_PAGE_1A_LENGTH; index++)
607230557Sjimharris   {
608230557Sjimharris      sati_get_data_byte(sequence, scsi_io, mode_page_offset+index, &current_mode_page[index]);
609230557Sjimharris   }
610230557Sjimharris
611230557Sjimharris   //Check for data validity
612230557Sjimharris   //SPF(0b); Page length 0x0A;
613230557Sjimharris
614230557Sjimharris   if (((current_mode_page[0] & SCSI_MODE_SELECT_MODE_PAGE_SPF_MASK)!= 0) ||
615230557Sjimharris      (current_mode_page[1] != (SCSI_MODE_PAGE_1A_LENGTH - 2) ) ||
616230557Sjimharris      ((current_mode_page[3] & SCSI_MODE_PAGE_POWER_CONDITION_IDLE)!= 0)
617230557Sjimharris      )
618230557Sjimharris   {
619230557Sjimharris      //parameter data passed in containing data that doesn't meet the SAT-2 requirement
620230557Sjimharris      return SATI_FAILURE_CHECK_RESPONSE_DATA;
621230557Sjimharris   }
622230557Sjimharris
623230557Sjimharris   // STANDBY bit is set to 0, do nothing since the standby timer can't be set;
624230557Sjimharris   // STANDBY bit is set to 1, translate the standby timer
625230557Sjimharris   // SCSI_MODE_PAGE_POWER_CONDITION_STANDBY== 0x01
626230557Sjimharris   if (current_mode_page[3] & SCSI_MODE_PAGE_POWER_CONDITION_STANDBY)
627230557Sjimharris   {
628230557Sjimharris      timer = (current_mode_page[8]<<24) + (current_mode_page[9]<<16) + (current_mode_page[10]<<8) + current_mode_page[11];
629230557Sjimharris
630230557Sjimharris      //If the ATA IDENTIFY DEVICE data word 49, bit 13 is set to one,
631230557Sjimharris      if (sequence->device->capabilities & SATI_DEVICE_CAP_STANDBY_ENABLE)
632230557Sjimharris      {
633230557Sjimharris         if (timer == 0)
634230557Sjimharris         {
635230557Sjimharris            //TPV=0 send ATA STANDBY_IMMEDIATE
636230557Sjimharris            sati_ata_standby_immediate_construct(ata_io, sequence);
637230557Sjimharris            sequence->command_specific_data.translated_command = ATA_STANDBY_IMMED;
638230557Sjimharris         }
639230557Sjimharris         else if ((timer > 0) && (timer <= 12000))
640230557Sjimharris         {
641230557Sjimharris            //1 to 12 000 INT((z - 1) / 50) + 1
642230557Sjimharris            count = (U16)((timer -1) / 50) + 1;
643230557Sjimharris            sati_ata_standby_construct(ata_io, sequence, count);
644230557Sjimharris         }
645230557Sjimharris         else if ((timer > 12000) && (timer <= 12600))
646230557Sjimharris         {
647230557Sjimharris            //12 001 to 12 600 FCh
648230557Sjimharris            sati_ata_standby_construct(ata_io, sequence, 0xFC);
649230557Sjimharris         }
650230557Sjimharris         else if ((timer > 12600) && (timer <= 12750))
651230557Sjimharris         {
652230557Sjimharris            //12 601 to 12 750 FFh
653230557Sjimharris            sati_ata_standby_construct(ata_io, sequence, 0xFF);
654230557Sjimharris         }
655230557Sjimharris         else if ((timer > 12750) && (timer < 18000))
656230557Sjimharris         {
657230557Sjimharris            //12 751 to 17 999 F1h
658230557Sjimharris            sati_ata_standby_construct(ata_io, sequence, 0xF1);
659230557Sjimharris         }
660230557Sjimharris         else if ((timer >= 18000) && (timer <= 198000))
661230557Sjimharris         {
662230557Sjimharris            //18 000 to 198 000 INT(z / 18 000) + 240
663230557Sjimharris            count = (U16)(timer / 18000) + 240;
664230557Sjimharris            sati_ata_standby_construct(ata_io, sequence, count);
665230557Sjimharris         }
666230557Sjimharris         else
667230557Sjimharris         {
668230557Sjimharris            //All other values FDh
669230557Sjimharris            sati_ata_standby_construct(ata_io, sequence, 0xFD);
670230557Sjimharris         }
671230557Sjimharris         status = SATI_SUCCESS ;
672230557Sjimharris      }
673230557Sjimharris      else
674230557Sjimharris      {
675230557Sjimharris         status = SATI_FAILURE_CHECK_RESPONSE_DATA;
676230557Sjimharris         //If the ATA IDENTIFY DEVICE data word 49, bit 13 is set to 0
677230557Sjimharris      }
678230557Sjimharris   }
679230557Sjimharris   else
680230557Sjimharris   {
681230557Sjimharris      status = SATI_COMPLETE;
682230557Sjimharris   }
683230557Sjimharris
684230557Sjimharris   sequence->command_specific_data.process_state.size_of_data_processed += page_size;
685230557Sjimharris   sequence->command_specific_data.process_state.mode_page_offset += page_size;
686230557Sjimharris   sequence->command_specific_data.process_state.current_mode_page_processed = TRUE;
687230557Sjimharris
688230557Sjimharris   return status;
689230557Sjimharris}
690230557Sjimharris
691230557Sjimharris/**
692230557Sjimharris * @brief This method will process the mode page.
693230557Sjimharris *
694230557Sjimharris *
695230557Sjimharris * @return Indicate if the translation was successful.
696230557Sjimharris * @retval SATI_SUCCESS
697230557Sjimharris * @retval SATI_COMPLETE
698230557Sjimharris * @retval SATI_FAILURE_CHECK_RESPONSE_DATA
699230557Sjimharris */
700230557Sjimharrisstatic
701230557SjimharrisSATI_STATUS sati_mode_select_process_mode_page(
702230557Sjimharris   SATI_TRANSLATOR_SEQUENCE_T* sequence,
703230557Sjimharris   void                      * scsi_io,
704230557Sjimharris   void                      * ata_io
705230557Sjimharris)
706230557Sjimharris{
707230557Sjimharris   SATI_STATUS status = SATI_FAILURE_CHECK_RESPONSE_DATA;
708230557Sjimharris
709230557Sjimharris   U8 page_code;
710230557Sjimharris   U32 page_size = 0; // in bytes
711230557Sjimharris   U32 size_of_data_to_be_processed;
712230557Sjimharris
713230557Sjimharris   U8 page_code_byte;
714230557Sjimharris   U32 mode_page_offset;
715230557Sjimharris
716230557Sjimharris   mode_page_offset = sequence->command_specific_data.process_state.mode_page_offset;
717230557Sjimharris
718230557Sjimharris   sati_get_data_byte(sequence, scsi_io, mode_page_offset, &page_code_byte);
719230557Sjimharris
720230557Sjimharris   // No more pages.
721230557Sjimharris   if(sequence->command_specific_data.process_state.mode_pages_size >
722230557Sjimharris      sequence->command_specific_data.process_state.size_of_data_processed)
723230557Sjimharris   {
724230557Sjimharris      //SCSI_MODE_SENSE_PAGE_CODE_ENABLE==0x3f same for Mode Select
725230557Sjimharris      page_code = page_code_byte & SCSI_MODE_SENSE_PAGE_CODE_ENABLE;
726230557Sjimharris      page_size = sati_mode_select_get_mode_page_size(page_code);
727230557Sjimharris      size_of_data_to_be_processed = sequence->command_specific_data.process_state.mode_pages_size
728230557Sjimharris         - sequence->command_specific_data.process_state.size_of_data_processed;
729230557Sjimharris
730230557Sjimharris      if( page_size == 0 )
731230557Sjimharris      {
732230557Sjimharris         status = SATI_FAILURE_CHECK_RESPONSE_DATA;
733230557Sjimharris      }
734230557Sjimharris      else
735230557Sjimharris      {
736230557Sjimharris         // process mode page
737230557Sjimharris         switch(page_code)
738230557Sjimharris         {
739230557Sjimharris         case SCSI_MODE_PAGE_READ_WRITE_ERROR:
740230557Sjimharris            status = sati_mode_select_process_mode_page_read_write_error_recovery(
741230557Sjimharris                        sequence,
742230557Sjimharris                        scsi_io,
743230557Sjimharris                        page_size
744230557Sjimharris                     );
745230557Sjimharris            break;
746230557Sjimharris
747230557Sjimharris         case SCSI_MODE_PAGE_DISCONNECT_RECONNECT:
748230557Sjimharris            status = sati_mode_select_process_mode_page_disconnect_reconnect(
749230557Sjimharris                        &sequence->command_specific_data.process_state,
750230557Sjimharris                        page_size
751230557Sjimharris                     );
752230557Sjimharris            break;
753230557Sjimharris
754230557Sjimharris         case SCSI_MODE_PAGE_CACHING:
755230557Sjimharris            status = sati_mode_select_process_mode_page_caching(
756230557Sjimharris                        sequence,
757230557Sjimharris                        scsi_io,
758230557Sjimharris                        ata_io,
759230557Sjimharris                        page_size
760230557Sjimharris                     );
761230557Sjimharris            break;
762230557Sjimharris
763230557Sjimharris         case SCSI_MODE_PAGE_CONTROL:
764230557Sjimharris            status = sati_mode_select_process_mode_page_control(
765230557Sjimharris                        sequence,
766230557Sjimharris                        scsi_io,
767230557Sjimharris                        ata_io,
768230557Sjimharris                        page_size
769230557Sjimharris                     );
770230557Sjimharris            break;
771230557Sjimharris
772230557Sjimharris         case SCSI_MODE_PAGE_INFORMATIONAL_EXCP_CONTROL:
773230557Sjimharris            status = sati_mode_select_process_mode_page_informational_exception_control(
774230557Sjimharris                        sequence,
775230557Sjimharris                        scsi_io,
776230557Sjimharris                        ata_io,
777230557Sjimharris                        page_size
778230557Sjimharris                     );
779230557Sjimharris            break;
780230557Sjimharris
781230557Sjimharris         case SCSI_MODE_PAGE_POWER_CONDITION:
782230557Sjimharris            status = sati_mode_select_process_mode_page_power_condition(
783230557Sjimharris                        sequence,
784230557Sjimharris                        scsi_io,
785230557Sjimharris                        ata_io,
786230557Sjimharris                        page_size
787230557Sjimharris                     );
788230557Sjimharris
789230557Sjimharris            break;
790230557Sjimharris
791230557Sjimharris         default:
792230557Sjimharris            break;
793230557Sjimharris         }
794230557Sjimharris
795230557Sjimharris      }
796230557Sjimharris   }
797230557Sjimharris
798230557Sjimharris   return status;
799230557Sjimharris}
800230557Sjimharris
801230557Sjimharris//******************************************************************************
802230557Sjimharris//* P U B L I C   M E T H O D S
803230557Sjimharris//******************************************************************************
804230557Sjimharris
805230557Sjimharris/**
806230557Sjimharris * @brief This method will translate the SCSI Mode Select 6 byte or 10 byte command
807230557Sjimharris *        into corresponding ATA commands.  Depending upon the capabilities
808230557Sjimharris *        supported by the target different ATA commands can be selected.
809230557Sjimharris *        Additionally, in some cases more than a single ATA command may
810230557Sjimharris *        be required.
811230557Sjimharris *
812230557Sjimharris * @return Indicate if the command translation succeeded.
813230557Sjimharris * @retval SCI_SUCCESS This is returned if the command translation was
814230557Sjimharris *         successful.
815230557Sjimharris * @retval SCI_COMPLETE This is returned if the command translation was
816230557Sjimharris *         successful and no ATA commands need to be set.
817230557Sjimharris * @retval SATI_FAILURE_CHECK_RESPONSE_DATA This value is returned if
818230557Sjimharris *         sense data has been created as a result of something specified
819230557Sjimharris *         in the parameter data fields.
820230557Sjimharris */
821230557Sjimharrisstatic
822230557SjimharrisSATI_STATUS sati_mode_select_translate_command(
823230557Sjimharris   SATI_TRANSLATOR_SEQUENCE_T   * sequence,
824230557Sjimharris   void                         * scsi_io,
825230557Sjimharris   void                         * ata_io,
826230557Sjimharris   U32                          cdb_size
827230557Sjimharris)
828230557Sjimharris{
829230557Sjimharris   SATI_STATUS status = SATI_FAILURE_CHECK_RESPONSE_DATA;
830230557Sjimharris   U32 mode_page_offset;
831230557Sjimharris   U32 block_descriptor_length;
832230557Sjimharris   U32 index;
833230557Sjimharris   U16 data_transfer_length;
834230557Sjimharris   U8 current_mode_parameters[8]={0,0,0,0,0,0,0,0};
835230557Sjimharris   U8 * cdb = sati_cb_get_cdb_address(scsi_io);
836230557Sjimharris
837230557Sjimharris   // cdb_size must be 6 or 10
838230557Sjimharris   if(FALSE == (cdb_size == 6 || cdb_size == 10))
839230557Sjimharris   {
840230557Sjimharris      return status;
841230557Sjimharris   }
842230557Sjimharris
843230557Sjimharris   if(sequence->state == SATI_SEQUENCE_STATE_INITIAL)
844230557Sjimharris   {
845230557Sjimharris      sequence->command_specific_data.process_state.ata_command_sent_for_cmp = 0;
846230557Sjimharris      sequence->state = SATI_SEQUENCE_STATE_TRANSLATE_DATA;
847230557Sjimharris   }
848230557Sjimharris
849230557Sjimharris   //First, initializes mode_sel_processing_state
850230557Sjimharris   if ( sequence->command_specific_data.process_state.ata_command_sent_for_cmp == 0 )
851230557Sjimharris   {
852230557Sjimharris      if (cdb_size == 6)
853230557Sjimharris      {
854230557Sjimharris         //CDB byte 4 is the parameter length
855230557Sjimharris         data_transfer_length = sati_get_cdb_byte(cdb, 4);
856230557Sjimharris      }
857230557Sjimharris      else
858230557Sjimharris      {
859230557Sjimharris         //CDB byte 7 and 8 for Mode Select 10
860230557Sjimharris         data_transfer_length = (sati_get_cdb_byte(cdb, 7) << 8) + sati_get_cdb_byte(cdb, 8);
861230557Sjimharris      }
862230557Sjimharris
863230557Sjimharris      sequence->allocation_length = data_transfer_length;
864230557Sjimharris
865230557Sjimharris      //Get 8 bytes for headers (4 bytes for Mode Select 6 and 8 bytes for Mode Select 10)
866230557Sjimharris      for( index = 0; index < 8; index++ )
867230557Sjimharris      {
868230557Sjimharris         sati_get_data_byte(sequence, scsi_io, index, &current_mode_parameters[index]);
869230557Sjimharris      }
870230557Sjimharris
871230557Sjimharris      //medium type should be 0
872230557Sjimharris      if ( sati_mode_select_get_medium_type(current_mode_parameters, cdb_size) != 0 )
873230557Sjimharris      {
874230557Sjimharris         sati_scsi_sense_data_construct(
875230557Sjimharris            sequence,
876230557Sjimharris            scsi_io,
877230557Sjimharris            SCSI_STATUS_CHECK_CONDITION,
878230557Sjimharris            SCSI_SENSE_ILLEGAL_REQUEST,
879230557Sjimharris            SCSI_ASC_INVALID_FIELD_IN_PARM_LIST,
880230557Sjimharris            SCSI_ASCQ_INVALID_FIELD_IN_PARM_LIST
881230557Sjimharris         );
882230557Sjimharris         return status;
883230557Sjimharris      }
884230557Sjimharris
885230557Sjimharris      block_descriptor_length = sati_mode_select_get_mode_block_descriptor_length(
886230557Sjimharris                                   current_mode_parameters,
887230557Sjimharris                                   cdb_size
888230557Sjimharris                                );
889230557Sjimharris
890230557Sjimharris      mode_page_offset = sati_mode_select_get_mode_page_offset(
891230557Sjimharris                            block_descriptor_length,
892230557Sjimharris                            cdb_size
893230557Sjimharris                         );
894230557Sjimharris
895230557Sjimharris      if(mode_page_offset > data_transfer_length)
896230557Sjimharris      {
897230557Sjimharris         sequence->state = SATI_SEQUENCE_STATE_FINAL;
898230557Sjimharris         status = SATI_FAILURE_CHECK_RESPONSE_DATA;
899230557Sjimharris      }
900230557Sjimharris      else
901230557Sjimharris      {
902230557Sjimharris         sati_mode_select_initialize_mode_sel_processing_state(
903230557Sjimharris            sequence,
904230557Sjimharris            scsi_io,
905230557Sjimharris            ata_io,
906230557Sjimharris            data_transfer_length,
907230557Sjimharris            mode_page_offset
908230557Sjimharris         );
909230557Sjimharris
910230557Sjimharris      }
911230557Sjimharris    }
912230557Sjimharris
913230557Sjimharris   // move to next mode page
914230557Sjimharris   if(sequence->command_specific_data.process_state.current_mode_page_processed)
915230557Sjimharris   {
916230557Sjimharris      sequence->command_specific_data.process_state.ata_command_sent_for_cmp = 0;
917230557Sjimharris      sequence->command_specific_data.process_state.current_mode_page_processed = FALSE;
918230557Sjimharris   }
919230557Sjimharris
920230557Sjimharris   status = sati_mode_select_process_mode_page(sequence, scsi_io, ata_io);
921230557Sjimharris
922230557Sjimharris   if(sequence->command_specific_data.process_state.current_mode_page_processed != FALSE)
923230557Sjimharris   {
924230557Sjimharris      // Done this page
925230557Sjimharris      sequence->state = SATI_SEQUENCE_STATE_FINAL;
926230557Sjimharris   }
927230557Sjimharris   else
928230557Sjimharris   {
929230557Sjimharris      sequence->state = SATI_SEQUENCE_STATE_INCOMPLETE;
930230557Sjimharris   }
931230557Sjimharris
932230557Sjimharris   if(status == SATI_FAILURE_CHECK_RESPONSE_DATA)
933230557Sjimharris   {
934230557Sjimharris      sequence->state = SATI_SEQUENCE_STATE_FINAL;
935230557Sjimharris      sati_scsi_sense_data_construct(
936230557Sjimharris         sequence,
937230557Sjimharris         scsi_io,
938230557Sjimharris         SCSI_STATUS_CHECK_CONDITION,
939230557Sjimharris         SCSI_SENSE_ILLEGAL_REQUEST,
940230557Sjimharris         SCSI_ASC_INVALID_FIELD_IN_PARM_LIST,
941230557Sjimharris         SCSI_ASCQ_INVALID_FIELD_IN_PARM_LIST
942230557Sjimharris      );
943230557Sjimharris   }
944230557Sjimharris
945230557Sjimharris   return status;
946230557Sjimharris}
947230557Sjimharris
948230557Sjimharris/**
949230557Sjimharris * @brief This method will call Mode Select 6 Translation command
950230557Sjimharris *        For more information on the parameters passed to this method,
951230557Sjimharris *        please reference sati_translate_command().
952230557Sjimharris *
953230557Sjimharris * @return Indicate if the command translation succeeded.
954230557Sjimharris * @retval SCI_SUCCESS This is returned if the command translation was
955230557Sjimharris *         successful.
956230557Sjimharris * @retval SCI_COMPLETE This is returned if the command translation was
957230557Sjimharris *         successful and no ATA commands need to be set.
958230557Sjimharris * @retval SATI_FAILURE_CHECK_RESPONSE_DATA This value is returned if
959230557Sjimharris *         sense data has been created as a result of something specified
960230557Sjimharris *         in the parameter data fields.
961230557Sjimharris */
962230557SjimharrisSATI_STATUS sati_mode_select_6_translate_command(
963230557Sjimharris   SATI_TRANSLATOR_SEQUENCE_T * sequence,
964230557Sjimharris   void                       * scsi_io,
965230557Sjimharris   void                       * ata_io
966230557Sjimharris)
967230557Sjimharris{
968230557Sjimharris   SATI_STATUS status=SATI_FAILURE;
969230557Sjimharris   U8 * cdb = sati_cb_get_cdb_address(scsi_io);
970230557Sjimharris
971230557Sjimharris   //PF bit needs to be 1 byte1 bit ???1????
972230557Sjimharris   if ((sati_get_cdb_byte(cdb, 1) & SCSI_MODE_SELECT_PF_MASK) == !SCSI_MODE_SELECT_PF_BIT)
973230557Sjimharris   {
974230557Sjimharris      sati_scsi_sense_data_construct(
975230557Sjimharris         sequence,
976230557Sjimharris         scsi_io,
977230557Sjimharris         SCSI_STATUS_CHECK_CONDITION,
978230557Sjimharris         SCSI_SENSE_ILLEGAL_REQUEST,
979230557Sjimharris         SCSI_ASC_INVALID_FIELD_IN_CDB,
980230557Sjimharris         SCSI_ASCQ_INVALID_FIELD_IN_CDB
981230557Sjimharris      );
982230557Sjimharris      status = SATI_FAILURE_CHECK_RESPONSE_DATA;
983230557Sjimharris      return status;
984230557Sjimharris   }
985230557Sjimharris
986230557Sjimharris   status=sati_mode_select_translate_command(
987230557Sjimharris             sequence,
988230557Sjimharris             scsi_io,
989230557Sjimharris             ata_io,
990230557Sjimharris             6
991230557Sjimharris          );
992230557Sjimharris
993230557Sjimharris   if(status == SATI_FAILURE_CHECK_RESPONSE_DATA)
994230557Sjimharris   {
995230557Sjimharris      sati_scsi_sense_data_construct(
996230557Sjimharris         sequence,
997230557Sjimharris         scsi_io,
998230557Sjimharris         SCSI_STATUS_CHECK_CONDITION,
999230557Sjimharris         SCSI_SENSE_ILLEGAL_REQUEST,
1000230557Sjimharris         SCSI_ASC_INVALID_FIELD_IN_PARM_LIST,
1001230557Sjimharris         SCSI_ASCQ_INVALID_FIELD_IN_PARM_LIST
1002230557Sjimharris      );
1003230557Sjimharris   }
1004230557Sjimharris   return status;
1005230557Sjimharris
1006230557Sjimharris}
1007230557Sjimharris
1008230557Sjimharris/**
1009230557Sjimharris * @brief This method will call Mode Select 10 translation command
1010230557Sjimharris *        For more information on the parameters passed to this method,
1011230557Sjimharris *        please reference sati_translate_command().
1012230557Sjimharris *
1013230557Sjimharris * @return Indicate if the command translation succeeded.
1014230557Sjimharris * @retval SCI_SUCCESS This is returned if the command translation was
1015230557Sjimharris *         successful.
1016230557Sjimharris * @retval SCI_COMPLETE This is returned if the command translation was
1017230557Sjimharris *         successful and no ATA commands need to be set.
1018230557Sjimharris * @retval SATI_FAILURE_CHECK_RESPONSE_DATA This value is returned if
1019230557Sjimharris *         sense data has been created as a result of something specified
1020230557Sjimharris *         in the parameter data fields.
1021230557Sjimharris */
1022230557SjimharrisSATI_STATUS sati_mode_select_10_translate_command(
1023230557Sjimharris   SATI_TRANSLATOR_SEQUENCE_T * sequence,
1024230557Sjimharris   void                       * scsi_io,
1025230557Sjimharris   void                       * ata_io
1026230557Sjimharris)
1027230557Sjimharris{
1028230557Sjimharris   SATI_STATUS status=SATI_FAILURE;
1029230557Sjimharris   U8 * cdb = sati_cb_get_cdb_address(scsi_io);
1030230557Sjimharris
1031230557Sjimharris   //PF bit needs to be 1 byte1 bit ???1????
1032230557Sjimharris   if ((sati_get_cdb_byte(cdb, 1) & SCSI_MODE_SELECT_PF_MASK) == !SCSI_MODE_SELECT_PF_BIT)
1033230557Sjimharris   {
1034230557Sjimharris      sati_scsi_sense_data_construct(
1035230557Sjimharris         sequence,
1036230557Sjimharris         scsi_io,
1037230557Sjimharris         SCSI_STATUS_CHECK_CONDITION,
1038230557Sjimharris         SCSI_SENSE_ILLEGAL_REQUEST,
1039230557Sjimharris         SCSI_ASC_INVALID_FIELD_IN_CDB,
1040230557Sjimharris         SCSI_ASCQ_INVALID_FIELD_IN_CDB
1041230557Sjimharris      );
1042230557Sjimharris      status = SATI_FAILURE_CHECK_RESPONSE_DATA;
1043230557Sjimharris      return status;
1044230557Sjimharris   }
1045230557Sjimharris
1046230557Sjimharris   status=sati_mode_select_translate_command(
1047230557Sjimharris             sequence,
1048230557Sjimharris             scsi_io,
1049230557Sjimharris             ata_io,
1050230557Sjimharris             10
1051230557Sjimharris          );
1052230557Sjimharris
1053230557Sjimharris   if(status == SATI_FAILURE_CHECK_RESPONSE_DATA)
1054230557Sjimharris   {
1055230557Sjimharris      sati_scsi_sense_data_construct(
1056230557Sjimharris         sequence,
1057230557Sjimharris         scsi_io,
1058230557Sjimharris         SCSI_STATUS_CHECK_CONDITION,
1059230557Sjimharris         SCSI_SENSE_ILLEGAL_REQUEST,
1060230557Sjimharris         SCSI_ASC_INVALID_FIELD_IN_PARM_LIST,
1061230557Sjimharris         SCSI_ASCQ_INVALID_FIELD_IN_PARM_LIST
1062230557Sjimharris      );
1063230557Sjimharris   }
1064230557Sjimharris   return status;
1065230557Sjimharris}
1066230557Sjimharris
1067230557Sjimharris/**
1068230557Sjimharris* @brief This method will conduct error handling for the ATA Set Features command
1069230557Sjimharris*        that is issued during a Mode Select translation for the Caching Mode
1070230557Sjimharris*        page.
1071230557Sjimharris*
1072230557Sjimharris*
1073230557Sjimharris* @return Indicate if the command translation succeeded.
1074230557Sjimharris*
1075230557Sjimharris* @retval SCI_COMPLETE This is returned if the command translation was
1076230557Sjimharris*         successful and no additional ATA commands need to be set.
1077230557Sjimharris* @retval SATI_FAILURE_CHECK_RESPONSE_DATA This value is returned if
1078230557Sjimharris*         sense data has been created as a result of an error returned
1079230557Sjimharris*/
1080230557SjimharrisSATI_STATUS sati_mode_select_translate_response(
1081230557SjimharrisSATI_TRANSLATOR_SEQUENCE_T * sequence,
1082230557Sjimharrisvoid                       * scsi_io,
1083230557Sjimharrisvoid                       * ata_io
1084230557Sjimharris)
1085230557Sjimharris{
1086230557Sjimharris   U8 * register_fis = sati_cb_get_d2h_register_fis_address(ata_io);
1087230557Sjimharris   SATI_STATUS status = SATI_FAILURE;
1088230557Sjimharris
1089230557Sjimharris   if(sati_get_ata_status(register_fis) & ATA_STATUS_REG_ERROR_BIT)
1090230557Sjimharris   {
1091230557Sjimharris      sati_scsi_sense_data_construct(
1092230557Sjimharris         sequence,
1093230557Sjimharris         scsi_io,
1094230557Sjimharris         SCSI_STATUS_CHECK_CONDITION,
1095230557Sjimharris         SCSI_SENSE_ABORTED_COMMAND,
1096230557Sjimharris         SCSI_ASC_NO_ADDITIONAL_SENSE,
1097230557Sjimharris         SCSI_ASCQ_NO_ADDITIONAL_SENSE
1098230557Sjimharris      );
1099230557Sjimharris      status = SATI_FAILURE_CHECK_RESPONSE_DATA;
1100230557Sjimharris   }
1101230557Sjimharris   else
1102230557Sjimharris   {
1103230557Sjimharris      if (sequence->state == SATI_SEQUENCE_STATE_INCOMPLETE)
1104230557Sjimharris      {
1105230557Sjimharris         status = SATI_SEQUENCE_INCOMPLETE;
1106230557Sjimharris      }
1107230557Sjimharris      else
1108230557Sjimharris      {
1109230557Sjimharris         status = SATI_COMPLETE;
1110230557Sjimharris      }
1111230557Sjimharris   }
1112230557Sjimharris   return status;
1113230557Sjimharris}
1114230557Sjimharris
1115230557Sjimharris#endif // !defined(DISABLE_SATI_MODE_SELECT)
1116