xref: /freebsd/sys/dev/isci/scil/sati_mode_select.c (revision 580744621f33383027108364dcadad718df46ffe)
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  */
88 static
89 U8 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  */
121 static
122 U32 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  */
161 static
162 U32 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  */
188 static
189 void  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  */
211 static
212 U32 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  */
262 static
263 SATI_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  */
321 static
322 SATI_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  */
354 static
355 SATI_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  */
451 static
452 SATI_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  */
517 static
518 SATI_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  */
586 static
587 SATI_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  */
702 static
703 SATI_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  */
823 static
824 SATI_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  */
964 SATI_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  */
1024 SATI_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 */
1082 SATI_STATUS sati_mode_select_translate_response(
1083 SATI_TRANSLATOR_SEQUENCE_T * sequence,
1084 void                       * scsi_io,
1085 void                       * 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