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 /**
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
sati_mode_select_get_medium_type(U8 * mode_parameters,U32 cdb_size)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
sati_mode_select_get_mode_block_descriptor_length(U8 * mode_parameters,U32 cdb_size)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
sati_mode_select_get_mode_page_offset(U32 block_descriptor_length,U32 cdb_size)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
sati_mode_select_initialize_mode_sel_processing_state(SATI_TRANSLATOR_SEQUENCE_T * sequence,void * scsi_io,void * ata_io,U32 data_transfer_length,U32 mode_page_offset)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
sati_mode_select_get_mode_page_size(U8 page_code)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
sati_mode_select_process_mode_page_read_write_error_recovery(SATI_TRANSLATOR_SEQUENCE_T * sequence,void * scsi_io,U32 page_size)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, ¤t_mode_page[0]);
279 sati_get_data_byte(sequence, scsi_io, mode_page_offset+1, ¤t_mode_page[1]);
280 sati_get_data_byte(sequence, scsi_io, mode_page_offset+2, ¤t_mode_page[2]);
281 sati_get_data_byte(sequence, scsi_io, mode_page_offset+10, ¤t_mode_page[10]);
282 sati_get_data_byte(sequence, scsi_io, mode_page_offset+11, ¤t_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
sati_mode_select_process_mode_page_disconnect_reconnect(SATI_MODE_SELECT_PROCESSING_STATE_T * mode_select_process_state,U32 page_size)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
sati_mode_select_process_mode_page_caching(SATI_TRANSLATOR_SEQUENCE_T * sequence,void * scsi_io,void * ata_io,U32 page_size)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, ¤t_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
sati_mode_select_process_mode_page_control(SATI_TRANSLATOR_SEQUENCE_T * sequence,void * scsi_io,void * ata_io,U32 page_size)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, ¤t_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
sati_mode_select_process_mode_page_informational_exception_control(SATI_TRANSLATOR_SEQUENCE_T * sequence,void * scsi_io,void * ata_io,U32 page_size)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, ¤t_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
sati_mode_select_process_mode_page_power_condition(SATI_TRANSLATOR_SEQUENCE_T * sequence,void * scsi_io,void * ata_io,U32 page_size)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, ¤t_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
sati_mode_select_process_mode_page(SATI_TRANSLATOR_SEQUENCE_T * sequence,void * scsi_io,void * ata_io)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
sati_mode_select_translate_command(SATI_TRANSLATOR_SEQUENCE_T * sequence,void * scsi_io,void * ata_io,U32 cdb_size)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, ¤t_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 */
sati_mode_select_6_translate_command(SATI_TRANSLATOR_SEQUENCE_T * sequence,void * scsi_io,void * ata_io)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 */
sati_mode_select_10_translate_command(SATI_TRANSLATOR_SEQUENCE_T * sequence,void * scsi_io,void * ata_io)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 */
sati_mode_select_translate_response(SATI_TRANSLATOR_SEQUENCE_T * sequence,void * scsi_io,void * ata_io)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