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