sati_mode_select.c revision 331722
1/*-
2 * This file is provided under a dual BSD/GPLv2 license.  When using or
3 * redistributing this file, you may do so under either license.
4 *
5 * GPL LICENSE SUMMARY
6 *
7 * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of version 2 of the GNU General Public License as
11 * published by the Free Software Foundation.
12 *
13 * This program is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16 * General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
21 * The full GNU General Public License is included in this distribution
22 * in the file called LICENSE.GPL.
23 *
24 * BSD LICENSE
25 *
26 * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
27 * All rights reserved.
28 *
29 * Redistribution and use in source and binary forms, with or without
30 * modification, are permitted provided that the following conditions
31 * are met:
32 *
33 *   * Redistributions of source code must retain the above copyright
34 *     notice, this list of conditions and the following disclaimer.
35 *   * Redistributions in binary form must reproduce the above copyright
36 *     notice, this list of conditions and the following disclaimer in
37 *     the documentation and/or other materials provided with the
38 *     distribution.
39 *
40 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
41 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
42 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
43 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
44 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
45 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
46 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
47 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
48 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
49 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
50 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
51 */
52
53#include <sys/cdefs.h>
54__FBSDID("$FreeBSD: stable/11/sys/dev/isci/scil/sati_mode_select.c 331722 2018-03-29 02:50:57Z eadler $");
55
56/**
57 * @file
58 * @brief This file contains the method implementations required to
59 *        translate the SCSI mode select (6 and 10-byte) commands with 5
60 *        supported mode parameter pages (0x01, 0x02, 0x08, 0x0A, 0x1C).
61 */
62
63#if !defined(DISABLE_SATI_MODE_SELECT)
64
65#include <dev/isci/scil/sati_mode_select.h>
66#include <dev/isci/scil/sati_mode_pages.h>
67#include <dev/isci/scil/sati_callbacks.h>
68#include <dev/isci/scil/sci_object.h>
69#include <dev/isci/scil/sati_translator_sequence.h>
70#include <dev/isci/scil/sati_util.h>
71
72//******************************************************************************
73//* P R I V A T E   M E T H O D S
74//******************************************************************************
75
76/**
77 * @brief This method will get medium type parameter field per CDB size.
78 *
79 * @param[in] scsi_io This parameter specifies the user's SCSI IO object
80 *            for which to calculate the mode page header.
81 * @param[in] cdb_size This parameter specifies the number of bytes
82 *            associated with the CDB for which to calculate the header.
83 *
84 * @return This method returns the medium type for the mode page header.
85 */
86static
87U8 sati_mode_select_get_medium_type(
88   U8 * mode_parameters,
89   U32  cdb_size
90)
91{
92   U8  medium_type =0xFF;
93   SCSI_MODE_SELECT_MODE_PARAMETER_HEADER_6_T * mode_parameters_6;
94   SCSI_MODE_SELECT_MODE_PARAMETER_HEADER_10_T * mode_parameters_10;
95
96   if(cdb_size == 6)
97   {
98      mode_parameters_6 = (SCSI_MODE_SELECT_MODE_PARAMETER_HEADER_6_T *) mode_parameters;
99      medium_type = mode_parameters_6->medium_type;
100   }
101   else if(cdb_size == 10)
102   {
103      mode_parameters_10 = (SCSI_MODE_SELECT_MODE_PARAMETER_HEADER_10_T *) mode_parameters;
104      medium_type = mode_parameters_10->medium_type;
105   }
106
107   return medium_type;
108}
109
110/**
111 * @brief This method will retrieve Block Descriptor Length.
112 *
113 * @param[in] mode_parameters This parameter contains the address to the mode parameters.
114 * @param[in] cdb_size This parameter specifies the number of bytes
115 *            associated with the CDB for which to process the block descriptor.
116 *
117 * @return This method returns the size, in bytes, for the mode parameter block descriptor.
118 */
119static
120U32 sati_mode_select_get_mode_block_descriptor_length(
121   U8 * mode_parameters,
122   U32  cdb_size
123)
124{
125   U32 mode_block_descriptor_length = 0;
126   SCSI_MODE_SELECT_MODE_PARAMETER_HEADER_6_T * mode_parameters_6;
127   SCSI_MODE_SELECT_MODE_PARAMETER_HEADER_10_T * mode_parameters_10;
128
129   if(cdb_size == 6)
130   {
131      mode_parameters_6 = (SCSI_MODE_SELECT_MODE_PARAMETER_HEADER_6_T *) mode_parameters;
132      mode_block_descriptor_length = mode_parameters_6->block_descriptor_length;
133   }
134   else if(cdb_size == 10)
135   {
136      mode_parameters_10 = (SCSI_MODE_SELECT_MODE_PARAMETER_HEADER_10_T *) mode_parameters;
137      //Long LBA bit is the bit0 of the byte
138      //Spec says another way to get the block descriptor length to multiply the block number
139      //   with block length (8 or 16), but we can get it directly.
140      mode_block_descriptor_length =(((U16)mode_parameters_10->block_descriptor_length[0]) << 8) +
141         mode_parameters_10->block_descriptor_length[1];
142
143   }
144
145   return mode_block_descriptor_length;
146
147}
148
149/**
150 * @brief This method will find the starting byte location for a page.
151 *
152 * @param[in] block_descriptor_length This parameter passes in the length of
153 *            block descriptor.
154 * @param[in] cdb_size This parameter specifies the number of bytes
155 *            associated with the CDB for which to calculate the header.
156 *
157 * @return This method returns the offset, for the mode page.
158 */
159static
160U32 sati_mode_select_get_mode_page_offset(
161    U32 block_descriptor_length,
162    U32 cdb_size
163    )
164{
165   U32 mode_page_offset;
166
167   if(cdb_size == 6)
168   {
169      mode_page_offset =  sizeof(SCSI_MODE_SELECT_MODE_PARAMETER_HEADER_6_T) +  block_descriptor_length;
170   }
171   else if(cdb_size == 10)
172   {
173      mode_page_offset =  sizeof(SCSI_MODE_SELECT_MODE_PARAMETER_HEADER_10_T) +  block_descriptor_length;
174   }
175   else
176   {
177      mode_page_offset = 0;
178   }
179
180   return mode_page_offset;
181}
182
183/**
184 * @brief This method will set the initial Mode Select processing state.
185 */
186static
187void  sati_mode_select_initialize_mode_sel_processing_state(
188   SATI_TRANSLATOR_SEQUENCE_T * sequence,
189   void                       * scsi_io,
190   void                       * ata_io,
191   U32 data_transfer_length,
192   U32 mode_page_offset
193   )
194{
195   sequence->command_specific_data.process_state.ata_command_sent_for_cmp = 0;
196   sequence->command_specific_data.process_state.mode_page_offset=mode_page_offset;
197   sequence->command_specific_data.process_state.mode_pages_size = data_transfer_length  -  mode_page_offset;
198   sequence->command_specific_data.process_state.size_of_data_processed = 0;
199   sequence->command_specific_data.process_state.current_mode_page_processed = FALSE;
200}
201
202/**
203 * @brief This method will get mode page size.
204 *
205 * @param[in] page_code This parameter contains page code for the current mode page.
206 *
207 * @return This method returns the size of current mode page.
208 */
209static
210U32 sati_mode_select_get_mode_page_size(
211   U8 page_code
212)
213{
214   U32 page_size=0;
215
216   switch (page_code)
217   {
218   case SCSI_MODE_PAGE_READ_WRITE_ERROR:
219      page_size=SCSI_MODE_PAGE_01_LENGTH;
220      break;
221
222   case SCSI_MODE_PAGE_DISCONNECT_RECONNECT:
223      page_size=SCSI_MODE_PAGE_02_LENGTH;
224      break;
225
226   case SCSI_MODE_PAGE_CACHING:
227      page_size=SCSI_MODE_PAGE_08_LENGTH;
228      break;
229
230   case SCSI_MODE_PAGE_CONTROL:
231      page_size=SCSI_MODE_PAGE_0A_LENGTH;
232      break;
233
234   case SCSI_MODE_PAGE_INFORMATIONAL_EXCP_CONTROL:
235      page_size=SCSI_MODE_PAGE_1C_LENGTH;
236      break;
237
238   case SCSI_MODE_PAGE_POWER_CONDITION:
239      page_size=SCSI_MODE_PAGE_1A_LENGTH;
240      break;
241   default:
242      page_size=0;
243      break;
244   }
245
246   return page_size;
247}
248
249/**
250 * @brief This method will check the validity of parameter data of Read Write Error Recovery
251 *            page and further processing the page data if necessary.
252 *
253 * @param[in] page_size This parameter specifies page size of current mode page.
254 *
255 * @return Indicate if the translation was successful.
256 * @retval SATI_SUCCESS
257 * @retval SATI_COMPLETE
258 * @retval SATI_FAILURE_CHECK_RESPONSE_DATA
259 */
260static
261SATI_STATUS sati_mode_select_process_mode_page_read_write_error_recovery(
262   SATI_TRANSLATOR_SEQUENCE_T* sequence,
263   void     *  scsi_io,
264   U32   page_size
265   )
266{
267   SATI_STATUS status = SATI_FAILURE_CHECK_RESPONSE_DATA;
268
269   U8 current_mode_page[SCSI_MODE_PAGE_01_LENGTH]={0,0,0,0,0,0,0,0,0,0,0,0};
270   U32 mode_page_offset;
271
272   mode_page_offset = sequence->command_specific_data.process_state.mode_page_offset;
273
274   //Check all the defined bits for this page
275   //SPF(0b); Page length 0x0A;AWRE 1; ARRE 0; Error recovery bits 0; RC 0;
276   //Recovery time limit last two bytes 0
277
278   sati_get_data_byte(sequence, scsi_io, mode_page_offset,   &current_mode_page[0]);
279   sati_get_data_byte(sequence, scsi_io, mode_page_offset+1, &current_mode_page[1]);
280   sati_get_data_byte(sequence, scsi_io, mode_page_offset+2, &current_mode_page[2]);
281   sati_get_data_byte(sequence, scsi_io, mode_page_offset+10, &current_mode_page[10]);
282   sati_get_data_byte(sequence, scsi_io, mode_page_offset+11, &current_mode_page[11]);
283
284   if ( ((current_mode_page[0] & SCSI_MODE_SELECT_MODE_PAGE_SPF_MASK)!= 0) ||
285      (current_mode_page[1] != (SCSI_MODE_PAGE_01_LENGTH - 2)) ||
286      ((current_mode_page[2] & SCSI_MODE_SELECT_MODE_PAGE_01_AWRE_MASK) == 0) ||
287      ((current_mode_page[2] & SCSI_MODE_SELECT_MODE_PAGE_01_ARRE_MASK) != 0) ||
288      ((current_mode_page[2] & SCSI_MODE_SELECT_MODE_PAGE_01_RC_ERBITS_MASK) != 0) ||
289      (current_mode_page[10] != 0 ) ||
290      (current_mode_page[11] != 0 ) )
291   {
292      status = SATI_FAILURE_CHECK_RESPONSE_DATA;
293      return status;
294   }
295
296   //no need to send any command
297   {
298      sequence->command_specific_data.process_state.size_of_data_processed += page_size;
299      sequence->command_specific_data.process_state.mode_page_offset += page_size;
300      sequence->command_specific_data.process_state.current_mode_page_processed = TRUE;
301   }
302
303   status = SATI_COMPLETE;
304
305   return status;
306}
307
308/**
309 * @brief This method will check the validity of parameter data of Disconnect Reconnect mode
310 *            page and further processing the page data if necessary.
311 *
312 * @param[in] page_size This parameter specifies page size of current mode page.
313 *
314 * @return Indicate if the translation was successful.
315 * @retval SATI_SUCCESS
316 * @retval SATI_COMPLETE
317 * @retval SATI_FAILURE_CHECK_RESPONSE_DATA
318 */
319static
320SATI_STATUS sati_mode_select_process_mode_page_disconnect_reconnect(
321   SATI_MODE_SELECT_PROCESSING_STATE_T * mode_select_process_state,
322   U32 page_size
323   )
324{
325   SATI_STATUS status = SATI_FAILURE_CHECK_RESPONSE_DATA;
326
327   // No need to check data for valid or invalid this page (undefined)
328   // No ata command to send
329   {
330      mode_select_process_state->size_of_data_processed += page_size;
331      mode_select_process_state->mode_page_offset += page_size;
332      mode_select_process_state->current_mode_page_processed = TRUE;
333   }
334
335   // No further interaction with remote devices
336   status = SATI_COMPLETE;
337
338   return status;
339}
340
341/**
342 * @brief This method will check the validity of parameter data of Caching mode
343 *            page and issue multiple ATA set feature commands to complete the translation.
344 *
345 * @param[in] page_size This parameter specifies page size of current mode page.
346 *
347 * @return Indicate if the translation was successful.
348 * @retval SATI_SUCCESS
349 * @retval SATI_COMPLETE
350 * @retval SATI_FAILURE_CHECK_RESPONSE_DATA
351 */
352static
353SATI_STATUS sati_mode_select_process_mode_page_caching(
354   SATI_TRANSLATOR_SEQUENCE_T * sequence,
355   void * scsi_io,
356   void * ata_io,
357   U32 page_size
358   )
359{
360   SATI_STATUS status = SATI_FAILURE_CHECK_RESPONSE_DATA;
361
362   //SCSI_MODE_PAGE_08_LENGTH 0x14= 20
363   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};
364   U32 mode_page_offset;
365   U32 index;
366
367   mode_page_offset = sequence->command_specific_data.process_state.mode_page_offset;
368   sequence->type = SATI_SEQUENCE_MODE_SELECT_MODE_PAGE_CACHING;
369
370   for(index = 0; index < SCSI_MODE_PAGE_08_LENGTH; index++)
371   {
372      sati_get_data_byte(sequence, scsi_io, mode_page_offset+index, &current_mode_page[index]);
373   }
374
375   //Check for data validity
376   //SPF(0b); Page length 0x12;Byte2 to Byte15 all 0 with exception DRA and WCE changeable
377
378   if (((current_mode_page[0] & SCSI_MODE_SELECT_MODE_PAGE_SPF_MASK)!= 0) ||
379      (current_mode_page[1] != (SCSI_MODE_PAGE_08_LENGTH-2)) ||
380      ((current_mode_page[2] | SCSI_MODE_PAGE_CACHE_PAGE_WCE_BIT)!=SCSI_MODE_PAGE_CACHE_PAGE_WCE_BIT) ||
381      (current_mode_page[3] != 0 ) ||
382      (current_mode_page[4] != 0 ) ||
383      (current_mode_page[5] != 0 ) ||
384      (current_mode_page[6] != 0 ) ||
385      (current_mode_page[7] != 0 ) ||
386      (current_mode_page[8] != 0 ) ||
387      (current_mode_page[9] != 0 ) ||
388      (current_mode_page[10] != 0 ) ||
389      (current_mode_page[11] != 0 ) ||
390      ((current_mode_page[12] & SCSI_MODE_SELECT_MODE_PAGE_08_FSW_LBCSS_NVDIS) != 0) ||
391      (current_mode_page[13] != 0 ) ||
392      (current_mode_page[14] != 0 ) ||
393      (current_mode_page[15] != 0 ))
394   {
395      //parameter data passed in containing data that doesn't meet the SAT-2 requirement
396      return SATI_FAILURE_CHECK_RESPONSE_DATA;
397   }
398
399   if(sequence->command_specific_data.process_state.ata_command_sent_for_cmp == 0)
400   {
401      //byte2 bit2 WCE==0 disable write cache WCE==1 enable write cache
402      //SCSI_MODE_PAGE_CACHE_PAGE_WCE_BIT ==0x4,
403
404      if ( (current_mode_page[2] & SCSI_MODE_PAGE_CACHE_PAGE_WCE_BIT) == 0)
405         sati_ata_set_features_construct(ata_io, sequence, ATA_SET_FEATURES_SUB_CMD_DISABLE_CACHE);
406      else
407         sati_ata_set_features_construct(ata_io, sequence, ATA_SET_FEATURES_SUB_CMD_ENABLE_CACHE);
408
409   }
410   else if(sequence->command_specific_data.process_state.ata_command_sent_for_cmp == 1)
411   {
412      // DRA bit is set to 0, enable Read look ahead AAh;
413      // DRA bit is set to 1, disable with set feature command 55h
414      // SCSI_MODE_PAGE_CACHE_PAGE_DRA_BIT== 0x20
415
416      if ( (current_mode_page[12] & SCSI_MODE_PAGE_CACHE_PAGE_DRA_BIT) == 0)
417         sati_ata_set_features_construct(ata_io, sequence,ATA_SET_FEATURES_SUB_CMD_ENABLE_READ_AHEAD);
418      else
419         sati_ata_set_features_construct(ata_io, sequence,ATA_SET_FEATURES_SUB_CMD_DISABLE_READ_AHEAD);
420
421      sequence->command_specific_data.process_state.size_of_data_processed += page_size;
422      sequence->command_specific_data.process_state.mode_page_offset += page_size;
423      sequence->command_specific_data.process_state.current_mode_page_processed = TRUE;
424
425
426   }
427   // No more ata commands to send
428
429   sequence->command_specific_data.process_state.ata_command_sent_for_cmp++;
430
431   status = SATI_SUCCESS;
432
433   return status;
434}
435
436/**
437 * @brief This method will check the validity of parameter data of Control mode
438 *            page and further processing the page data if necessary.
439 *
440 * @param[in] mode_select_process_state This parameter points to the processing state fields
441 *            of current mode page.
442 * @param[in] page_size This parameter specifies page size of current mode page.
443 *
444 * @return Indicate if the translation was successful.
445 * @retval SATI_SUCCESS
446 * @retval SATI_COMPLETE
447 * @retval SATI_FAILURE_CHECK_RESPONSE_DATA
448 */
449static
450SATI_STATUS sati_mode_select_process_mode_page_control(
451         SATI_TRANSLATOR_SEQUENCE_T* sequence,
452         void     *  scsi_io,
453         void     *  ata_io,
454         U32 page_size
455      )
456{
457   SATI_STATUS status = SATI_FAILURE_CHECK_RESPONSE_DATA;
458
459   //SCSI_MODE_PAGE_0A_LENGTH 12
460   U8 current_mode_page[SCSI_MODE_PAGE_0A_LENGTH]={0,0,0,0,0,0,0,0,0,0};
461   U32 mode_page_offset;
462   U32 index;
463
464   mode_page_offset = sequence->command_specific_data.process_state.mode_page_offset;
465
466   for(index = 0; index < SCSI_MODE_PAGE_0A_LENGTH; index++)
467   {
468      sati_get_data_byte(sequence, scsi_io, mode_page_offset+index, &current_mode_page[index]);
469   }
470
471   //bit 1 and 2 of byte3 Qerr full task management model etc. then both bits 0
472   //byte 8 and 9 busy time out period variable if not ffff setable?
473   //check for page data validity
474   //Byte2: 0000???0b  Byte3: Queued Algorithm Modifier should be set to 1 QErr?
475   //Byte4: ??000???   Byte5: ?0???000
476
477   if (((current_mode_page[0] & SCSI_MODE_SELECT_MODE_PAGE_SPF_MASK)!= 0) ||
478      (current_mode_page[1] != (SCSI_MODE_PAGE_0A_LENGTH - 2)) ||
479      ((current_mode_page[2] & SCSI_MODE_SELECT_MODE_PAGE_0A_TST_TMF_RLEC) != 0) ||
480      ((current_mode_page[3] & SCSI_MODE_SELECT_MODE_PAGE_0A_MODIFIER) != 0) ||
481      ((current_mode_page[4] & SCSI_MODE_SELECT_MODE_PAGE_0A_UA_SWP ) != 0) ||
482      ((current_mode_page[5] & SCSI_MODE_SELECT_MODE_PAGE_0A_TAS_AUTO ) != 0 ) )
483   {
484      return SATI_FAILURE_CHECK_RESPONSE_DATA;
485   }
486
487   if ((current_mode_page[2] & SCSI_MODE_SELECT_MODE_PAGE_D_SENSE) != 0)
488       sequence->device->descriptor_sense_enable = SCSI_MODE_PAGE_CONTROL_D_SENSE_ENABLE;
489   else
490       sequence->device->descriptor_sense_enable = SCSI_MODE_PAGE_CONTROL_D_SENSE_DISABLE;
491
492   // no ata command need to be comfirmed
493   {
494      sequence->command_specific_data.process_state.size_of_data_processed += page_size;
495      sequence->command_specific_data.process_state.mode_page_offset += page_size;
496      sequence->command_specific_data.process_state.current_mode_page_processed = TRUE;
497   }
498
499   status = SATI_COMPLETE;
500
501   return status;
502}
503
504/**
505 * @brief This method will check the validity of parameter data of Information Exception Control
506 *            mode page and further processing the page data if necessary.
507 *
508 * @param[in] page_size This parameter specifies page size of current mode page.
509 *
510 * @return Indicate if the translation was successful.
511 * @retval SATI_SUCCESS
512 * @retval SATI_COMPLETE
513 * @retval SATI_FAILURE_CHECK_RESPONSE_DATA
514 */
515static
516SATI_STATUS sati_mode_select_process_mode_page_informational_exception_control(
517   SATI_TRANSLATOR_SEQUENCE_T * sequence,
518   void     *  scsi_io,
519   void     *  ata_io,
520   U32 page_size
521   )
522{
523   SATI_STATUS status = SATI_FAILURE_CHECK_RESPONSE_DATA;
524
525   //SCSI_MODE_PAGE_1C_LENGTH 12
526   U8 current_mode_page[SCSI_MODE_PAGE_1C_LENGTH]={0,0,0,0,0,0,0,0,0,0,0,0};
527   U32 mode_page_offset;
528   U32 index;
529
530   mode_page_offset = sequence->command_specific_data.process_state.mode_page_offset;
531   sequence->type = SATI_SEQUENCE_MODE_SELECT_MODE_INFORMATION_EXCEPT_CONTROL;
532
533   for(index = 0; index < 4; index++)
534   {
535      sati_get_data_byte(sequence, scsi_io, mode_page_offset+index, &current_mode_page[index]);
536   }
537
538   //Check for data validity
539   //SPF(0b); Page length 0x0A; Byte2 0????0?? Byte3: ????1100
540   //SCSI_MODE_SELECT_MODE_PAGE_MRIE_BYTE same as REPORT_INFO_EXCEPTION_CONDITION_ON_REQUEST 0x6
541   //SCSI_MODE_PAGE_DEXCPT_ENABLE
542
543   if (((current_mode_page[0] & SCSI_MODE_SELECT_MODE_PAGE_SPF_MASK)!= 0) ||
544      (current_mode_page[1] != (SCSI_MODE_PAGE_1C_LENGTH - 2)) ||
545      ((current_mode_page[2] & SCSI_MODE_SELECT_MODE_PAGE_1C_PERF_TEST)!= 0 ) ||
546      ((current_mode_page[3] & SCSI_MODE_SELECT_MODE_PAGE_MRIE_MASK) !=
547      SCSI_MODE_SELECT_MODE_PAGE_MRIE_BYTE ))
548   {
549      return SATI_FAILURE_CHECK_RESPONSE_DATA;
550   }
551
552   // DEXCPT bit is set to 0, enable SMART reporting D8h;
553   // DEXCPT bit is set to 1, disable SMART reporting D9h
554   // SCSI_MODE_PAGE_DEXCPT_ENABLE== 0x08
555
556   if ( (current_mode_page[2] & SCSI_MODE_PAGE_DEXCPT_ENABLE) == 0)
557      sati_ata_smart_return_status_construct(ata_io, sequence, ATA_SMART_SUB_CMD_ENABLE);
558   else
559      sati_ata_smart_return_status_construct(ata_io, sequence, ATA_SMART_SUB_CMD_DISABLE);
560
561   sequence->command_specific_data.process_state.size_of_data_processed += page_size;
562   sequence->command_specific_data.process_state.mode_page_offset += page_size;
563   sequence->command_specific_data.process_state.current_mode_page_processed = TRUE;
564   // No more ata commands to send
565
566   status = SATI_SUCCESS;
567
568   return status;
569}
570
571/**
572 * @brief This method will check the validity of parameter data of Power Condition mode
573 *            page and issue multiple ATA set feature commands to complete the translation.
574 *
575 * @param[in] mode_select_process_state This parameter points to the processing state fields
576 *            of current mode page.
577 * @param[in] page_size This parameter specifies page size of current mode page.
578 *
579 * @return Indicate if the translation was successful.
580 * @retval SATI_SUCCESS
581 * @retval SATI_COMPLETE
582 * @retval SATI_FAILURE_CHECK_RESPONSE_DATA
583 */
584static
585SATI_STATUS sati_mode_select_process_mode_page_power_condition(
586   SATI_TRANSLATOR_SEQUENCE_T * sequence,
587   void * scsi_io,
588   void * ata_io,
589   U32 page_size
590   )
591{
592   SATI_STATUS status = SATI_FAILURE_CHECK_RESPONSE_DATA;
593
594   //SCSI_MODE_PAGE_1A_LENGTH 10
595   U8 current_mode_page[SCSI_MODE_PAGE_1A_LENGTH] = {0,0,0,0,0,0,0,0,0,0};
596   U32 mode_page_offset;
597   U32 index;
598
599   U32 timer = 0;
600   U16 count = 0;
601
602   mode_page_offset = sequence->command_specific_data.process_state.mode_page_offset;
603
604   sequence->type = SATI_SEQUENCE_MODE_SELECT_MODE_POWER_CONDITION;
605
606   for(index = 0; index < SCSI_MODE_PAGE_1A_LENGTH; index++)
607   {
608      sati_get_data_byte(sequence, scsi_io, mode_page_offset+index, &current_mode_page[index]);
609   }
610
611   //Check for data validity
612   //SPF(0b); Page length 0x0A;
613
614   if (((current_mode_page[0] & SCSI_MODE_SELECT_MODE_PAGE_SPF_MASK)!= 0) ||
615      (current_mode_page[1] != (SCSI_MODE_PAGE_1A_LENGTH - 2) ) ||
616      ((current_mode_page[3] & SCSI_MODE_PAGE_POWER_CONDITION_IDLE)!= 0)
617      )
618   {
619      //parameter data passed in containing data that doesn't meet the SAT-2 requirement
620      return SATI_FAILURE_CHECK_RESPONSE_DATA;
621   }
622
623   // STANDBY bit is set to 0, do nothing since the standby timer can't be set;
624   // STANDBY bit is set to 1, translate the standby timer
625   // SCSI_MODE_PAGE_POWER_CONDITION_STANDBY== 0x01
626   if (current_mode_page[3] & SCSI_MODE_PAGE_POWER_CONDITION_STANDBY)
627   {
628      timer = (current_mode_page[8]<<24) + (current_mode_page[9]<<16) + (current_mode_page[10]<<8) + current_mode_page[11];
629
630      //If the ATA IDENTIFY DEVICE data word 49, bit 13 is set to one,
631      if (sequence->device->capabilities & SATI_DEVICE_CAP_STANDBY_ENABLE)
632      {
633         if (timer == 0)
634         {
635            //TPV=0 send ATA STANDBY_IMMEDIATE
636            sati_ata_standby_immediate_construct(ata_io, sequence);
637            sequence->command_specific_data.translated_command = ATA_STANDBY_IMMED;
638         }
639         else if ((timer > 0) && (timer <= 12000))
640         {
641            //1 to 12 000 INT((z - 1) / 50) + 1
642            count = (U16)((timer -1) / 50) + 1;
643            sati_ata_standby_construct(ata_io, sequence, count);
644         }
645         else if ((timer > 12000) && (timer <= 12600))
646         {
647            //12 001 to 12 600 FCh
648            sati_ata_standby_construct(ata_io, sequence, 0xFC);
649         }
650         else if ((timer > 12600) && (timer <= 12750))
651         {
652            //12 601 to 12 750 FFh
653            sati_ata_standby_construct(ata_io, sequence, 0xFF);
654         }
655         else if ((timer > 12750) && (timer < 18000))
656         {
657            //12 751 to 17 999 F1h
658            sati_ata_standby_construct(ata_io, sequence, 0xF1);
659         }
660         else if ((timer >= 18000) && (timer <= 198000))
661         {
662            //18 000 to 198 000 INT(z / 18 000) + 240
663            count = (U16)(timer / 18000) + 240;
664            sati_ata_standby_construct(ata_io, sequence, count);
665         }
666         else
667         {
668            //All other values FDh
669            sati_ata_standby_construct(ata_io, sequence, 0xFD);
670         }
671         status = SATI_SUCCESS ;
672      }
673      else
674      {
675         status = SATI_FAILURE_CHECK_RESPONSE_DATA;
676         //If the ATA IDENTIFY DEVICE data word 49, bit 13 is set to 0
677      }
678   }
679   else
680   {
681      status = SATI_COMPLETE;
682   }
683
684   sequence->command_specific_data.process_state.size_of_data_processed += page_size;
685   sequence->command_specific_data.process_state.mode_page_offset += page_size;
686   sequence->command_specific_data.process_state.current_mode_page_processed = TRUE;
687
688   return status;
689}
690
691/**
692 * @brief This method will process the mode page.
693 *
694 *
695 * @return Indicate if the translation was successful.
696 * @retval SATI_SUCCESS
697 * @retval SATI_COMPLETE
698 * @retval SATI_FAILURE_CHECK_RESPONSE_DATA
699 */
700static
701SATI_STATUS sati_mode_select_process_mode_page(
702   SATI_TRANSLATOR_SEQUENCE_T* sequence,
703   void                      * scsi_io,
704   void                      * ata_io
705)
706{
707   SATI_STATUS status = SATI_FAILURE_CHECK_RESPONSE_DATA;
708
709   U8 page_code;
710   U32 page_size = 0; // in bytes
711   U32 size_of_data_to_be_processed;
712
713   U8 page_code_byte;
714   U32 mode_page_offset;
715
716   mode_page_offset = sequence->command_specific_data.process_state.mode_page_offset;
717
718   sati_get_data_byte(sequence, scsi_io, mode_page_offset, &page_code_byte);
719
720   // No more pages.
721   if(sequence->command_specific_data.process_state.mode_pages_size >
722      sequence->command_specific_data.process_state.size_of_data_processed)
723   {
724      //SCSI_MODE_SENSE_PAGE_CODE_ENABLE==0x3f same for Mode Select
725      page_code = page_code_byte & SCSI_MODE_SENSE_PAGE_CODE_ENABLE;
726      page_size = sati_mode_select_get_mode_page_size(page_code);
727      size_of_data_to_be_processed = sequence->command_specific_data.process_state.mode_pages_size
728         - sequence->command_specific_data.process_state.size_of_data_processed;
729
730      if( page_size == 0 )
731      {
732         status = SATI_FAILURE_CHECK_RESPONSE_DATA;
733      }
734      else
735      {
736         // process mode page
737         switch(page_code)
738         {
739         case SCSI_MODE_PAGE_READ_WRITE_ERROR:
740            status = sati_mode_select_process_mode_page_read_write_error_recovery(
741                        sequence,
742                        scsi_io,
743                        page_size
744                     );
745            break;
746
747         case SCSI_MODE_PAGE_DISCONNECT_RECONNECT:
748            status = sati_mode_select_process_mode_page_disconnect_reconnect(
749                        &sequence->command_specific_data.process_state,
750                        page_size
751                     );
752            break;
753
754         case SCSI_MODE_PAGE_CACHING:
755            status = sati_mode_select_process_mode_page_caching(
756                        sequence,
757                        scsi_io,
758                        ata_io,
759                        page_size
760                     );
761            break;
762
763         case SCSI_MODE_PAGE_CONTROL:
764            status = sati_mode_select_process_mode_page_control(
765                        sequence,
766                        scsi_io,
767                        ata_io,
768                        page_size
769                     );
770            break;
771
772         case SCSI_MODE_PAGE_INFORMATIONAL_EXCP_CONTROL:
773            status = sati_mode_select_process_mode_page_informational_exception_control(
774                        sequence,
775                        scsi_io,
776                        ata_io,
777                        page_size
778                     );
779            break;
780
781         case SCSI_MODE_PAGE_POWER_CONDITION:
782            status = sati_mode_select_process_mode_page_power_condition(
783                        sequence,
784                        scsi_io,
785                        ata_io,
786                        page_size
787                     );
788
789            break;
790
791         default:
792            break;
793         }
794
795      }
796   }
797
798   return status;
799}
800
801//******************************************************************************
802//* P U B L I C   M E T H O D S
803//******************************************************************************
804
805/**
806 * @brief This method will translate the SCSI Mode Select 6 byte or 10 byte command
807 *        into corresponding ATA commands.  Depending upon the capabilities
808 *        supported by the target different ATA commands can be selected.
809 *        Additionally, in some cases more than a single ATA command may
810 *        be required.
811 *
812 * @return Indicate if the command translation succeeded.
813 * @retval SCI_SUCCESS This is returned if the command translation was
814 *         successful.
815 * @retval SCI_COMPLETE This is returned if the command translation was
816 *         successful and no ATA commands need to be set.
817 * @retval SATI_FAILURE_CHECK_RESPONSE_DATA This value is returned if
818 *         sense data has been created as a result of something specified
819 *         in the parameter data fields.
820 */
821static
822SATI_STATUS sati_mode_select_translate_command(
823   SATI_TRANSLATOR_SEQUENCE_T   * sequence,
824   void                         * scsi_io,
825   void                         * ata_io,
826   U32                          cdb_size
827)
828{
829   SATI_STATUS status = SATI_FAILURE_CHECK_RESPONSE_DATA;
830   U32 mode_page_offset;
831   U32 block_descriptor_length;
832   U32 index;
833   U16 data_transfer_length;
834   U8 current_mode_parameters[8]={0,0,0,0,0,0,0,0};
835   U8 * cdb = sati_cb_get_cdb_address(scsi_io);
836
837   // cdb_size must be 6 or 10
838   if(FALSE == (cdb_size == 6 || cdb_size == 10))
839   {
840      return status;
841   }
842
843   if(sequence->state == SATI_SEQUENCE_STATE_INITIAL)
844   {
845      sequence->command_specific_data.process_state.ata_command_sent_for_cmp = 0;
846      sequence->state = SATI_SEQUENCE_STATE_TRANSLATE_DATA;
847   }
848
849   //First, initializes mode_sel_processing_state
850   if ( sequence->command_specific_data.process_state.ata_command_sent_for_cmp == 0 )
851   {
852      if (cdb_size == 6)
853      {
854         //CDB byte 4 is the parameter length
855         data_transfer_length = sati_get_cdb_byte(cdb, 4);
856      }
857      else
858      {
859         //CDB byte 7 and 8 for Mode Select 10
860         data_transfer_length = (sati_get_cdb_byte(cdb, 7) << 8) + sati_get_cdb_byte(cdb, 8);
861      }
862
863      sequence->allocation_length = data_transfer_length;
864
865      //Get 8 bytes for headers (4 bytes for Mode Select 6 and 8 bytes for Mode Select 10)
866      for( index = 0; index < 8; index++ )
867      {
868         sati_get_data_byte(sequence, scsi_io, index, &current_mode_parameters[index]);
869      }
870
871      //medium type should be 0
872      if ( sati_mode_select_get_medium_type(current_mode_parameters, cdb_size) != 0 )
873      {
874         sati_scsi_sense_data_construct(
875            sequence,
876            scsi_io,
877            SCSI_STATUS_CHECK_CONDITION,
878            SCSI_SENSE_ILLEGAL_REQUEST,
879            SCSI_ASC_INVALID_FIELD_IN_PARM_LIST,
880            SCSI_ASCQ_INVALID_FIELD_IN_PARM_LIST
881         );
882         return status;
883      }
884
885      block_descriptor_length = sati_mode_select_get_mode_block_descriptor_length(
886                                   current_mode_parameters,
887                                   cdb_size
888                                );
889
890      mode_page_offset = sati_mode_select_get_mode_page_offset(
891                            block_descriptor_length,
892                            cdb_size
893                         );
894
895      if(mode_page_offset > data_transfer_length)
896      {
897         sequence->state = SATI_SEQUENCE_STATE_FINAL;
898         status = SATI_FAILURE_CHECK_RESPONSE_DATA;
899      }
900      else
901      {
902         sati_mode_select_initialize_mode_sel_processing_state(
903            sequence,
904            scsi_io,
905            ata_io,
906            data_transfer_length,
907            mode_page_offset
908         );
909
910      }
911    }
912
913   // move to next mode page
914   if(sequence->command_specific_data.process_state.current_mode_page_processed)
915   {
916      sequence->command_specific_data.process_state.ata_command_sent_for_cmp = 0;
917      sequence->command_specific_data.process_state.current_mode_page_processed = FALSE;
918   }
919
920   status = sati_mode_select_process_mode_page(sequence, scsi_io, ata_io);
921
922   if(sequence->command_specific_data.process_state.current_mode_page_processed != FALSE)
923   {
924      // Done this page
925      sequence->state = SATI_SEQUENCE_STATE_FINAL;
926   }
927   else
928   {
929      sequence->state = SATI_SEQUENCE_STATE_INCOMPLETE;
930   }
931
932   if(status == SATI_FAILURE_CHECK_RESPONSE_DATA)
933   {
934      sequence->state = SATI_SEQUENCE_STATE_FINAL;
935      sati_scsi_sense_data_construct(
936         sequence,
937         scsi_io,
938         SCSI_STATUS_CHECK_CONDITION,
939         SCSI_SENSE_ILLEGAL_REQUEST,
940         SCSI_ASC_INVALID_FIELD_IN_PARM_LIST,
941         SCSI_ASCQ_INVALID_FIELD_IN_PARM_LIST
942      );
943   }
944
945   return status;
946}
947
948/**
949 * @brief This method will call Mode Select 6 Translation command
950 *        For more information on the parameters passed to this method,
951 *        please reference sati_translate_command().
952 *
953 * @return Indicate if the command translation succeeded.
954 * @retval SCI_SUCCESS This is returned if the command translation was
955 *         successful.
956 * @retval SCI_COMPLETE This is returned if the command translation was
957 *         successful and no ATA commands need to be set.
958 * @retval SATI_FAILURE_CHECK_RESPONSE_DATA This value is returned if
959 *         sense data has been created as a result of something specified
960 *         in the parameter data fields.
961 */
962SATI_STATUS sati_mode_select_6_translate_command(
963   SATI_TRANSLATOR_SEQUENCE_T * sequence,
964   void                       * scsi_io,
965   void                       * ata_io
966)
967{
968   SATI_STATUS status=SATI_FAILURE;
969   U8 * cdb = sati_cb_get_cdb_address(scsi_io);
970
971   //PF bit needs to be 1 byte1 bit ???1????
972   if ((sati_get_cdb_byte(cdb, 1) & SCSI_MODE_SELECT_PF_MASK) == !SCSI_MODE_SELECT_PF_BIT)
973   {
974      sati_scsi_sense_data_construct(
975         sequence,
976         scsi_io,
977         SCSI_STATUS_CHECK_CONDITION,
978         SCSI_SENSE_ILLEGAL_REQUEST,
979         SCSI_ASC_INVALID_FIELD_IN_CDB,
980         SCSI_ASCQ_INVALID_FIELD_IN_CDB
981      );
982      status = SATI_FAILURE_CHECK_RESPONSE_DATA;
983      return status;
984   }
985
986   status=sati_mode_select_translate_command(
987             sequence,
988             scsi_io,
989             ata_io,
990             6
991          );
992
993   if(status == SATI_FAILURE_CHECK_RESPONSE_DATA)
994   {
995      sati_scsi_sense_data_construct(
996         sequence,
997         scsi_io,
998         SCSI_STATUS_CHECK_CONDITION,
999         SCSI_SENSE_ILLEGAL_REQUEST,
1000         SCSI_ASC_INVALID_FIELD_IN_PARM_LIST,
1001         SCSI_ASCQ_INVALID_FIELD_IN_PARM_LIST
1002      );
1003   }
1004   return status;
1005
1006}
1007
1008/**
1009 * @brief This method will call Mode Select 10 translation command
1010 *        For more information on the parameters passed to this method,
1011 *        please reference sati_translate_command().
1012 *
1013 * @return Indicate if the command translation succeeded.
1014 * @retval SCI_SUCCESS This is returned if the command translation was
1015 *         successful.
1016 * @retval SCI_COMPLETE This is returned if the command translation was
1017 *         successful and no ATA commands need to be set.
1018 * @retval SATI_FAILURE_CHECK_RESPONSE_DATA This value is returned if
1019 *         sense data has been created as a result of something specified
1020 *         in the parameter data fields.
1021 */
1022SATI_STATUS sati_mode_select_10_translate_command(
1023   SATI_TRANSLATOR_SEQUENCE_T * sequence,
1024   void                       * scsi_io,
1025   void                       * ata_io
1026)
1027{
1028   SATI_STATUS status=SATI_FAILURE;
1029   U8 * cdb = sati_cb_get_cdb_address(scsi_io);
1030
1031   //PF bit needs to be 1 byte1 bit ???1????
1032   if ((sati_get_cdb_byte(cdb, 1) & SCSI_MODE_SELECT_PF_MASK) == !SCSI_MODE_SELECT_PF_BIT)
1033   {
1034      sati_scsi_sense_data_construct(
1035         sequence,
1036         scsi_io,
1037         SCSI_STATUS_CHECK_CONDITION,
1038         SCSI_SENSE_ILLEGAL_REQUEST,
1039         SCSI_ASC_INVALID_FIELD_IN_CDB,
1040         SCSI_ASCQ_INVALID_FIELD_IN_CDB
1041      );
1042      status = SATI_FAILURE_CHECK_RESPONSE_DATA;
1043      return status;
1044   }
1045
1046   status=sati_mode_select_translate_command(
1047             sequence,
1048             scsi_io,
1049             ata_io,
1050             10
1051          );
1052
1053   if(status == SATI_FAILURE_CHECK_RESPONSE_DATA)
1054   {
1055      sati_scsi_sense_data_construct(
1056         sequence,
1057         scsi_io,
1058         SCSI_STATUS_CHECK_CONDITION,
1059         SCSI_SENSE_ILLEGAL_REQUEST,
1060         SCSI_ASC_INVALID_FIELD_IN_PARM_LIST,
1061         SCSI_ASCQ_INVALID_FIELD_IN_PARM_LIST
1062      );
1063   }
1064   return status;
1065}
1066
1067/**
1068* @brief This method will conduct error handling for the ATA Set Features command
1069*        that is issued during a Mode Select translation for the Caching Mode
1070*        page.
1071*
1072*
1073* @return Indicate if the command translation succeeded.
1074*
1075* @retval SCI_COMPLETE This is returned if the command translation was
1076*         successful and no additional ATA commands need to be set.
1077* @retval SATI_FAILURE_CHECK_RESPONSE_DATA This value is returned if
1078*         sense data has been created as a result of an error returned
1079*/
1080SATI_STATUS sati_mode_select_translate_response(
1081SATI_TRANSLATOR_SEQUENCE_T * sequence,
1082void                       * scsi_io,
1083void                       * ata_io
1084)
1085{
1086   U8 * register_fis = sati_cb_get_d2h_register_fis_address(ata_io);
1087   SATI_STATUS status = SATI_FAILURE;
1088
1089   if(sati_get_ata_status(register_fis) & ATA_STATUS_REG_ERROR_BIT)
1090   {
1091      sati_scsi_sense_data_construct(
1092         sequence,
1093         scsi_io,
1094         SCSI_STATUS_CHECK_CONDITION,
1095         SCSI_SENSE_ABORTED_COMMAND,
1096         SCSI_ASC_NO_ADDITIONAL_SENSE,
1097         SCSI_ASCQ_NO_ADDITIONAL_SENSE
1098      );
1099      status = SATI_FAILURE_CHECK_RESPONSE_DATA;
1100   }
1101   else
1102   {
1103      if (sequence->state == SATI_SEQUENCE_STATE_INCOMPLETE)
1104      {
1105         status = SATI_SEQUENCE_INCOMPLETE;
1106      }
1107      else
1108      {
1109         status = SATI_COMPLETE;
1110      }
1111   }
1112   return status;
1113}
1114
1115#endif // !defined(DISABLE_SATI_MODE_SELECT)
1116