xref: /freebsd/sys/dev/isci/scil/sati_mode_select.c (revision aa24f48b361effe51163877d84f1b70d32b77e04)
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$");
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  */
86 static
87 U8 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  */
119 static
120 U32 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  */
159 static
160 U32 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  */
186 static
187 void  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  */
209 static
210 U32 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  */
260 static
261 SATI_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  */
319 static
320 SATI_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  */
352 static
353 SATI_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  */
449 static
450 SATI_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  */
515 static
516 SATI_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  */
584 static
585 SATI_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  */
700 static
701 SATI_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  */
821 static
822 SATI_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  */
962 SATI_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  */
1022 SATI_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 */
1080 SATI_STATUS sati_mode_select_translate_response(
1081 SATI_TRANSLATOR_SEQUENCE_T * sequence,
1082 void                       * scsi_io,
1083 void                       * 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