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 sense (6 and 10-byte) commands.
60 */
61
62 #if !defined(DISABLE_SATI_MODE_SENSE)
63
64 #include <dev/isci/scil/sati_mode_sense.h>
65 #include <dev/isci/scil/sati_mode_pages.h>
66 #include <dev/isci/scil/sati_callbacks.h>
67 #include <dev/isci/scil/sati_util.h>
68 #include <dev/isci/scil/intel_scsi.h>
69 #include <dev/isci/scil/intel_ata.h>
70
71 //******************************************************************************
72 //* P R I V A T E M E T H O D S
73 //******************************************************************************
74
75 #define STANDBY_TIMER_DISABLED 0x00
76 #define STANDBY_TIMER_ENABLED 0x01
77 #define STANDBY_TIMER_SUPPORTED 0x2000
78
79
80
81 /**
82 * @brief This method indicates if the supplied page control is supported
83 * by this translation implementation. Currently savable parameters
84 * (i.e. non-volatile) are not supported.
85 * For more information on the parameters passed to this method,
86 * please reference sati_translate_command().
87 *
88 * @return This method returns an indication of whether the page control
89 * specified in the SCSI CDB is supported.
90 * @retval SATI_SUCCESS This value is returned if the page control is
91 * supported.
92 * @retval SATI_FAILURE_CHECK_RESPONSE_DATA This value is returned if the
93 * page control is not supported.
94 */
95 static
sati_mode_sense_is_page_control_supported(SATI_TRANSLATOR_SEQUENCE_T * sequence,void * scsi_io)96 SATI_STATUS sati_mode_sense_is_page_control_supported(
97 SATI_TRANSLATOR_SEQUENCE_T * sequence,
98 void * scsi_io
99 )
100 {
101 U8 * cdb = sati_cb_get_cdb_address(scsi_io);
102
103 switch (sati_get_cdb_byte(cdb, 2) >> SCSI_MODE_SENSE_PC_SHIFT)
104 {
105 case SCSI_MODE_SENSE_PC_CURRENT:
106 case SCSI_MODE_SENSE_PC_DEFAULT:
107 case SCSI_MODE_SENSE_PC_CHANGEABLE:
108 return SATI_SUCCESS;
109 break;
110
111 default:
112 case SCSI_MODE_SENSE_PC_SAVED:
113 sati_scsi_sense_data_construct(
114 sequence,
115 scsi_io,
116 SCSI_STATUS_CHECK_CONDITION,
117 SCSI_SENSE_ILLEGAL_REQUEST,
118 SCSI_ASC_SAVING_PARMS_NOT_SUPPORTED,
119 SCSI_ASCQ_SAVING_PARMS_NOT_SUPPORTED
120 );
121 return SATI_FAILURE_CHECK_RESPONSE_DATA;
122 break;
123 }
124 }
125
126 /**
127 * @brief This method indicates if the page code field in the SCSI CDB
128 * is supported by this translation.
129 * For more information on the parameters passed to this method,
130 * please reference sati_translate_command().
131 *
132 * @param[in] cdb_length This parameter specifies the length of the SCSI
133 * CDB being translated (e.g. 6-byte, 10-byte, 12-byte, etc.)
134 *
135 * @return This method returns an indication as to whether the page code
136 * in the CDB is supported.
137 * @retval SATI_SUCCESS This value is returned if the page code is
138 * supported.
139 * @retval SATI_FAILURE_CHECK_RESPONSE_DATA This value is returned if the
140 * page code is not supported.
141 */
142 static
sati_mode_sense_is_page_code_supported(SATI_TRANSLATOR_SEQUENCE_T * sequence,void * scsi_io,U8 cdb_length)143 SATI_STATUS sati_mode_sense_is_page_code_supported(
144 SATI_TRANSLATOR_SEQUENCE_T * sequence,
145 void * scsi_io,
146 U8 cdb_length
147 )
148 {
149 U8 * cdb = sati_cb_get_cdb_address(scsi_io);
150
151 switch (sati_get_cdb_byte(cdb, 2) & SCSI_MODE_SENSE_PAGE_CODE_ENABLE)
152 {
153 case SCSI_MODE_PAGE_CACHING:
154 if (sati_get_cdb_byte(cdb, 0) == SCSI_MODE_SENSE_6)
155 sequence->type = SATI_SEQUENCE_MODE_SENSE_6_CACHING;
156 else
157 sequence->type = SATI_SEQUENCE_MODE_SENSE_10_CACHING;
158 break;
159
160 case SCSI_MODE_PAGE_ALL_PAGES:
161 if (sati_get_cdb_byte(cdb, 0) == SCSI_MODE_SENSE_6)
162 sequence->type = SATI_SEQUENCE_MODE_SENSE_6_ALL_PAGES;
163 else
164 sequence->type = SATI_SEQUENCE_MODE_SENSE_10_ALL_PAGES;
165 break;
166
167 case SCSI_MODE_PAGE_READ_WRITE_ERROR:
168 if (sati_get_cdb_byte(cdb, 0) == SCSI_MODE_SENSE_6)
169 sequence->type = SATI_SEQUENCE_MODE_SENSE_6_READ_WRITE_ERROR;
170 else
171 sequence->type = SATI_SEQUENCE_MODE_SENSE_10_READ_WRITE_ERROR;
172 break;
173
174 case SCSI_MODE_PAGE_DISCONNECT_RECONNECT:
175 if (sati_get_cdb_byte(cdb, 0) == SCSI_MODE_SENSE_6)
176 sequence->type = SATI_SEQUENCE_MODE_SENSE_6_DISCONNECT_RECONNECT;
177 else
178 sequence->type = SATI_SEQUENCE_MODE_SENSE_10_DISCONNECT_RECONNECT;
179 break;
180
181 case SCSI_MODE_PAGE_CONTROL:
182 if (sati_get_cdb_byte(cdb, 0) == SCSI_MODE_SENSE_6)
183 sequence->type = SATI_SEQUENCE_MODE_SENSE_6_CONTROL;
184 else
185 sequence->type = SATI_SEQUENCE_MODE_SENSE_10_CONTROL;
186 break;
187
188 case SCSI_MODE_PAGE_POWER_CONDITION:
189 if (sati_get_cdb_byte(cdb, 0) == SCSI_MODE_SENSE_6)
190 sequence->type = SATI_SEQUENCE_MODE_SENSE_6_POWER_CONDITION;
191 else
192 sequence->type = SATI_SEQUENCE_MODE_SENSE_10_POWER_CONDITION;
193 break;
194
195 case SCSI_MODE_PAGE_INFORMATIONAL_EXCP_CONTROL:
196 // The informational exceptions control page is only useful
197 // if SMART is supported.
198 if ((sequence->device->capabilities | SATI_DEVICE_CAP_SMART_SUPPORT)
199 == 0)
200 {
201 // For a MODE SENSE, utilize INVALID FIELD IN CDB,
202 // For a MODE SELECT, utilize INVALID FIELD IN PARAMETER LIST.
203 if (sati_get_cdb_byte(cdb, 0) == SCSI_MODE_SENSE_6)
204 {
205 sati_scsi_sense_data_construct(
206 sequence,
207 scsi_io,
208 SCSI_STATUS_CHECK_CONDITION,
209 SCSI_SENSE_ILLEGAL_REQUEST,
210 SCSI_ASC_INVALID_FIELD_IN_CDB,
211 SCSI_ASCQ_INVALID_FIELD_IN_CDB
212 );
213 }
214 else
215 {
216 sati_scsi_sense_data_construct(
217 sequence,
218 scsi_io,
219 SCSI_STATUS_CHECK_CONDITION,
220 SCSI_SENSE_ILLEGAL_REQUEST,
221 SCSI_ASC_INVALID_FIELD_IN_PARM_LIST,
222 SCSI_ASCQ_INVALID_FIELD_IN_PARM_LIST
223 );
224 }
225
226 return SATI_FAILURE_CHECK_RESPONSE_DATA;
227 }
228
229 if (sati_get_cdb_byte(cdb, 0) == SCSI_MODE_SENSE_6)
230 sequence->type = SATI_SEQUENCE_MODE_SENSE_6_INFORMATIONAL_EXCP_CONTROL;
231 else
232 sequence->type = SATI_SEQUENCE_MODE_SENSE_10_INFORMATIONAL_EXCP_CONTROL;
233 break;
234
235 default:
236 sati_scsi_sense_data_construct(
237 sequence,
238 scsi_io,
239 SCSI_STATUS_CHECK_CONDITION,
240 SCSI_SENSE_ILLEGAL_REQUEST,
241 SCSI_ASC_INVALID_FIELD_IN_CDB,
242 SCSI_ASCQ_INVALID_FIELD_IN_CDB
243 );
244 return SATI_FAILURE_CHECK_RESPONSE_DATA;
245 break;
246 }
247
248 return SATI_SUCCESS;
249 }
250
251 //******************************************************************************
252 //* P R O T E C T E D M E T H O D S
253 //******************************************************************************
254
255 /**
256 * @brief This method will calculate the size of the mode sense data header.
257 * This includes the block descriptor if one is requested.
258 *
259 * @param[in] scsi_io This parameter specifies the user's SCSI IO object
260 * for which to calculate the mode page header.
261 * @param[in] cdb_size This parameter specifies the number of bytes
262 * associated with the CDB for which to calculate the header.
263 *
264 * @return This method returns the size, in bytes, for the mode page header.
265 */
sati_mode_sense_calculate_page_header(void * scsi_io,U8 cdb_size)266 U16 sati_mode_sense_calculate_page_header(
267 void * scsi_io,
268 U8 cdb_size
269 )
270 {
271 U8 * cdb = sati_cb_get_cdb_address(scsi_io);
272 U16 page_length = 0;
273
274 // The Mode page header length is different for 6-byte vs. 10-byte CDBs.
275 if (cdb_size == 6)
276 page_length += SCSI_MODE_SENSE_6_HEADER_LENGTH;
277 else
278 page_length += SCSI_MODE_SENSE_10_HEADER_LENGTH;
279
280 // Are block descriptors disabled (DBD)? 0 indicates they are enabled.
281 if ((sati_get_cdb_byte(cdb, 1) & SCSI_MODE_SENSE_DBD_ENABLE) == 0)
282 {
283 // The LLBAA bit is not defined for 6-byte mode sense requests.
284 if ( (cdb_size == 10)
285 && (sati_get_cdb_byte(cdb, 1) & SCSI_MODE_SENSE_LLBAA_ENABLE) )
286 page_length += SCSI_MODE_SENSE_LLBA_BLOCK_DESCRIPTOR_LENGTH;
287 else
288 page_length += SCSI_MODE_SENSE_STD_BLOCK_DESCRIPTOR_LENGTH;
289 }
290
291 return page_length;
292 }
293
294 /**
295 * @brief This method performs command translation common to all mode sense
296 * requests (6 or 10 byte).
297 * For more information on the parameters passed to this method,
298 * please reference sati_translate_command().
299 *
300 * @param[in] cdb_length This parameter specifies the number of bytes
301 * in the CDB (6 or 10).
302 *
303 * @return This method returns an indication as to whether the translation
304 * succeeded.
305 * @retval SCI_SUCCESS This value is returned if translation succeeded.
306 * @see sati_mode_sense_is_page_control_supported() or
307 * sati_mode_sense_is_page_code_supported() for more information.
308 */
sati_mode_sense_translate_command(SATI_TRANSLATOR_SEQUENCE_T * sequence,void * scsi_io,void * ata_io,U8 cdb_length)309 SATI_STATUS sati_mode_sense_translate_command(
310 SATI_TRANSLATOR_SEQUENCE_T * sequence,
311 void * scsi_io,
312 void * ata_io,
313 U8 cdb_length
314 )
315 {
316 SATI_STATUS status;
317
318 /**
319 * Validate that the supplied page control (PC) field is supported.
320 */
321 status = sati_mode_sense_is_page_control_supported(sequence, scsi_io);
322 if (status != SATI_SUCCESS)
323 return status;
324
325 /**
326 * Validate that the supplied page code is supported.
327 */
328 status = sati_mode_sense_is_page_code_supported(sequence,scsi_io,cdb_length);
329 if (status != SATI_SUCCESS)
330 return status;
331
332 sati_ata_identify_device_construct(ata_io, sequence);
333
334 return SATI_SUCCESS;
335 }
336
337 /**
338 * @brief This method will build the standard block descriptor for a MODE
339 * SENSE 6 or 10 byte request.
340 * For more information on the parameters passed to this method,
341 * please reference sati_translate_command().
342 *
343 * @param[in] identify This parameter specifies the IDENTIFY DEVICE data
344 * associated with the SCSI IO.
345 * @param[in] offset This parameter specifies the offset into the data
346 * buffer at which to build the block descriptor.
347 *
348 * @return This method returns the size of the block descriptor built.
349 */
sati_mode_sense_build_std_block_descriptor(SATI_TRANSLATOR_SEQUENCE_T * sequence,void * scsi_io,ATA_IDENTIFY_DEVICE_DATA_T * identify,U32 offset)350 U32 sati_mode_sense_build_std_block_descriptor(
351 SATI_TRANSLATOR_SEQUENCE_T * sequence,
352 void * scsi_io,
353 ATA_IDENTIFY_DEVICE_DATA_T * identify,
354 U32 offset
355 )
356 {
357 U32 lba_low = 0;
358 U32 lba_high = 0;
359 U32 sector_size = 0;
360
361 // Extract the sector information (sector size, logical blocks) from
362 // the retrieved ATA identify device data.
363 sati_ata_identify_device_get_sector_info(
364 identify, &lba_high, &lba_low, §or_size
365 );
366
367 // Fill in the 4-byte logical block address field.
368 sati_set_data_byte(sequence, scsi_io, offset, (U8)((lba_low>>24) & 0xFF));
369 sati_set_data_byte(sequence, scsi_io, offset+1, (U8)((lba_low>>16) & 0xFF));
370 sati_set_data_byte(sequence, scsi_io, offset+2, (U8)((lba_low>>8) & 0xFF));
371 sati_set_data_byte(sequence, scsi_io, offset+3, (U8)(lba_low & 0xFF));
372
373 // Clear the reserved field.
374 sati_set_data_byte(sequence, scsi_io, offset+4, 0);
375
376 // Fill in the three byte Block Length field
377 sati_set_data_byte(sequence,scsi_io, offset+5, (U8)((sector_size>>16) & 0xFF));
378 sati_set_data_byte(sequence,scsi_io, offset+6, (U8)((sector_size>>8) & 0xFF));
379 sati_set_data_byte(sequence,scsi_io, offset+7, (U8)(sector_size & 0xFF));
380
381 return SCSI_MODE_SENSE_STD_BLOCK_DESCRIPTOR_LENGTH;
382 }
383
384 /**
385 * @brief This method simply copies the mode sense data into the buffer
386 * at the location specified by page_start. The buffer copied is
387 * determined by page_control (e.g. current, default, or changeable
388 * values).
389 * For more information on the parameters passed to this method,
390 * please reference sati_translate_command().
391 *
392 * @param[in] page_start This parameter specifies the starting offset at
393 * which to copy the mode page data.
394 * @param[in] page_control This parameter specifies the page control
395 * indicating the source buffer to be copied.
396 * @param[in] page_code This specifies the mode sense page to copy.
397 *
398 * @return This method returns the size of the mode page data being copied.
399 */
sati_mode_sense_copy_initial_data(SATI_TRANSLATOR_SEQUENCE_T * sequence,void * scsi_io,U32 page_start,U8 page_control,U8 page_code)400 U32 sati_mode_sense_copy_initial_data(
401 SATI_TRANSLATOR_SEQUENCE_T * sequence,
402 void * scsi_io,
403 U32 page_start,
404 U8 page_control,
405 U8 page_code
406 )
407 {
408 U16 page_index = sati_mode_page_get_page_index(page_code);
409 U32 page_length = sat_mode_page_sizes[page_index];
410
411 // Find out if the current values are requested or if the default
412 // values are being requested.
413 if (page_control == SCSI_MODE_SENSE_PC_CHANGEABLE)
414 {
415 // Copy the changeable mode page information.
416 sati_copy_data(
417 sequence,
418 scsi_io,
419 page_start,
420 sat_changeable_mode_pages[page_index],
421 page_length
422 );
423 }
424 else
425 {
426 // Copy the default static values template to the user data area.
427 sati_copy_data(
428 sequence,
429 scsi_io,
430 page_start,
431 sat_default_mode_pages[page_index],
432 page_length
433 );
434 }
435
436 return page_length;
437 }
438
439 /**
440 * @brief This method performs the read/write error recovery mode page
441 * specific data translation based upon the contents of the remote
442 * device IDENTIFY DEVICE data.
443 * For more information on the parameters passed to this method,
444 * please reference sati_translate_command().
445 *
446 * @param[in] identify This parameter specifies the remote device's
447 * IDENTIFY DEVICE data received as part of the IO request.
448 * @param[in] offset This parameter specifies the offset into the data
449 * buffer where the translated data is to be written.
450 *
451 * @return This method returns the size of the mode page data that was
452 * translated.
453 */
sati_mode_sense_read_write_error_translate_data(SATI_TRANSLATOR_SEQUENCE_T * sequence,void * scsi_io,ATA_IDENTIFY_DEVICE_DATA_T * identify,U32 offset)454 U32 sati_mode_sense_read_write_error_translate_data(
455 SATI_TRANSLATOR_SEQUENCE_T * sequence,
456 void * scsi_io,
457 ATA_IDENTIFY_DEVICE_DATA_T * identify,
458 U32 offset
459 )
460 {
461 U8 * cdb = sati_cb_get_cdb_address(scsi_io);
462 U8 page_control = sati_get_cdb_byte(cdb, 2) >> SCSI_MODE_SENSE_PC_SHIFT;
463 U32 page_length;
464
465 page_length = sati_mode_sense_copy_initial_data(
466 sequence,
467 scsi_io,
468 offset,
469 page_control,
470 SCSI_MODE_PAGE_READ_WRITE_ERROR
471 );
472
473 // Currently we do not override any bits in this mode page from the
474 // identify data.
475
476 return page_length;
477 }
478
479 /**
480 * @brief This method performs the disconnect/reconnect mode page
481 * specific data translation based upon the contents of the remote
482 * device IDENTIFY DEVICE data.
483 * For more information on the parameters passed to this method,
484 * please reference sati_translate_command().
485 *
486 * @param[in] identify This parameter specifies the remote device's
487 * IDENTIFY DEVICE data received as part of the IO request.
488 * @param[in] offset This parameter specifies the offset into the data
489 * buffer where the translated data is to be written.
490 *
491 * @return This method returns the size of the mode page data that was
492 * translated.
493 */
sati_mode_sense_disconnect_reconnect_translate_data(SATI_TRANSLATOR_SEQUENCE_T * sequence,void * scsi_io,ATA_IDENTIFY_DEVICE_DATA_T * identify,U32 offset)494 U32 sati_mode_sense_disconnect_reconnect_translate_data(
495 SATI_TRANSLATOR_SEQUENCE_T * sequence,
496 void * scsi_io,
497 ATA_IDENTIFY_DEVICE_DATA_T * identify,
498 U32 offset
499 )
500 {
501 U8 * cdb = sati_cb_get_cdb_address(scsi_io);
502 U8 page_control = sati_get_cdb_byte(cdb, 2) >> SCSI_MODE_SENSE_PC_SHIFT;
503 U32 page_length;
504
505 page_length = sati_mode_sense_copy_initial_data(
506 sequence,
507 scsi_io,
508 offset,
509 page_control,
510 SCSI_MODE_PAGE_DISCONNECT_RECONNECT
511 );
512
513 // Currently we do not override any bits in this mode page from the
514 // identify data.
515
516 return page_length;
517 }
518
519 /**
520 * @brief This method performs the caching mode page specific data
521 * translation based upon the contents of the remote device IDENTIFY
522 * DEVICE data.
523 * For more information on the parameters passed to this method,
524 * please reference sati_translate_command().
525 *
526 * @param[in] identify This parameter specifies the remote device's
527 * IDENTIFY DEVICE data received as part of the IO request.
528 * @param[in] offset This parameter specifies the offset into the data
529 * buffer where the translated data is to be written.
530 *
531 * @return This method returns the size of the mode page data that was
532 * translated.
533 */
sati_mode_sense_caching_translate_data(SATI_TRANSLATOR_SEQUENCE_T * sequence,void * scsi_io,ATA_IDENTIFY_DEVICE_DATA_T * identify,U32 offset)534 U32 sati_mode_sense_caching_translate_data(
535 SATI_TRANSLATOR_SEQUENCE_T * sequence,
536 void * scsi_io,
537 ATA_IDENTIFY_DEVICE_DATA_T * identify,
538 U32 offset
539 )
540 {
541 U8 * cdb = sati_cb_get_cdb_address(scsi_io);
542 U8 page_control = sati_get_cdb_byte(cdb, 2) >> SCSI_MODE_SENSE_PC_SHIFT;
543 U32 page_length;
544
545 page_length = sati_mode_sense_copy_initial_data(
546 sequence,
547 scsi_io,
548 offset,
549 page_control,
550 SCSI_MODE_PAGE_CACHING
551 );
552
553 // If the request queried for the current values, then
554 // we need to translate the data from the IDENTIFY DEVICE request.
555 if (page_control == SCSI_MODE_SENSE_PC_CURRENT)
556 {
557 U8 value;
558
559 // Update the Write Cache Enabled (WCE) bit in the mode page data
560 // buffer based on the identify response.
561 if ((identify->command_set_enabled0 & ATA_IDENTIFY_DEVICE_WCE_ENABLE) != 0)
562 {
563 sati_get_data_byte(sequence, scsi_io, offset+2, &value);
564 value |= SCSI_MODE_PAGE_CACHE_PAGE_WCE_BIT;
565 sati_set_data_byte(sequence, scsi_io, offset+2, value);
566 //This byte has been set twice and needs to be decremented
567 sequence->number_data_bytes_set--;
568 }
569
570 // Update the Disable Read Ahead (DRA) bit in the mode page data
571 // buffer based on the identify response.
572 if ((identify->command_set_enabled0 & ATA_IDENTIFY_DEVICE_RA_ENABLE) == 0)
573 {
574 // In SATA the polarity of the bits is inverse.
575 // - SCSI = Disable Read Ahead
576 // - ATA = Read Ahead
577 sati_get_data_byte(sequence, scsi_io, offset+12, &value);
578 value |= SCSI_MODE_PAGE_CACHE_PAGE_DRA_BIT;
579 sati_set_data_byte(sequence, scsi_io, offset+12, value);
580
581 //This byte has been set twice, the first time in
582 //sati_mode_sense_copy_initial_data. number_data_bytes_set
583 //needs to be decremented
584 sequence->number_data_bytes_set--;
585 }
586 }
587
588 return page_length;
589 }
590
591 /**
592 * @brief This method performs the control mode page specific data
593 * translation based upon the contents of the remote device
594 * IDENTIFY DEVICE data.
595 * For more information on the parameters passed to this method,
596 * please reference sati_translate_command().
597 *
598 * @param[in] identify This parameter specifies the remote device's
599 * IDENTIFY DEVICE data received as part of the IO request.
600 * @param[in] offset This parameter specifies the offset into the data
601 * buffer where the translated data is to be written.
602 *
603 * @return This method returns the size of the mode page data that was
604 * translated.
605 */
sati_mode_sense_control_translate_data(SATI_TRANSLATOR_SEQUENCE_T * sequence,void * scsi_io,ATA_IDENTIFY_DEVICE_DATA_T * identify,U32 offset)606 U32 sati_mode_sense_control_translate_data(
607 SATI_TRANSLATOR_SEQUENCE_T * sequence,
608 void * scsi_io,
609 ATA_IDENTIFY_DEVICE_DATA_T * identify,
610 U32 offset
611 )
612 {
613 U8 * cdb = sati_cb_get_cdb_address(scsi_io);
614 U8 page_control = sati_get_cdb_byte(cdb, 2) >> SCSI_MODE_SENSE_PC_SHIFT;
615 U32 page_length;
616 U8 value;
617
618 page_length = sati_mode_sense_copy_initial_data(
619 sequence,
620 scsi_io,
621 offset,
622 page_control,
623 SCSI_MODE_PAGE_CONTROL
624 );
625
626 if (sequence->device->descriptor_sense_enable)
627 {
628 sati_get_data_byte(sequence, scsi_io, offset+2,
629 &value);
630
631 sati_set_data_byte(sequence, scsi_io, offset+2,
632 value | SCSI_MODE_SELECT_MODE_PAGE_D_SENSE);
633 }
634
635 return page_length;
636 }
637
638 /**
639 * @brief This method performs the informational exceptions control mode
640 * page specific data translation based upon the contents of the
641 * remote device IDENTIFY DEVICE data.
642 * For more information on the parameters passed to this method,
643 * please reference sati_translate_command().
644 *
645 * @param[in] identify This parameter specifies the remote device's
646 * IDENTIFY DEVICE data received as part of the IO request.
647 * @param[in] offset This parameter specifies the offset into the data
648 * buffer where the translated data is to be written.
649 *
650 * @return This method returns the size of the mode page data that was
651 * translated.
652 */
sati_mode_sense_informational_excp_control_translate_data(SATI_TRANSLATOR_SEQUENCE_T * sequence,void * scsi_io,ATA_IDENTIFY_DEVICE_DATA_T * identify,U32 offset)653 U32 sati_mode_sense_informational_excp_control_translate_data(
654 SATI_TRANSLATOR_SEQUENCE_T * sequence,
655 void * scsi_io,
656 ATA_IDENTIFY_DEVICE_DATA_T * identify,
657 U32 offset
658 )
659 {
660 U8 * cdb = sati_cb_get_cdb_address(scsi_io);
661 U8 page_control = sati_get_cdb_byte(cdb, 2) >> SCSI_MODE_SENSE_PC_SHIFT;
662 U32 page_length;
663
664 page_length = sati_mode_sense_copy_initial_data(
665 sequence,
666 scsi_io,
667 offset,
668 page_control,
669 SCSI_MODE_PAGE_INFORMATIONAL_EXCP_CONTROL
670 );
671
672 // If the request queried for the current values, then
673 // we need to translate the data from the IDENTIFY DEVICE request.
674 if (page_control == SCSI_MODE_SENSE_PC_CURRENT)
675 {
676 U8 value;
677
678 sati_get_data_byte(sequence, scsi_io, offset+2, &value);
679
680 // Determine if the SMART feature set is supported and enabled.
681 if ( (identify->command_set_supported0
682 & ATA_IDENTIFY_COMMAND_SET_SUPPORTED0_SMART_ENABLE)
683 && (identify->command_set_enabled0
684 & ATA_IDENTIFY_COMMAND_SET_ENABLED0_SMART_ENABLE) )
685 {
686 // Clear the DXCPT field since the SMART feature is supported/enabled.
687 value &= ~SCSI_MODE_PAGE_INFORMATIONAL_EXCP_DXCPT_ENABLE;
688 }
689 else
690 {
691 // Set the Disable Exception Control (DXCPT) field since the SMART
692 // feature is not supported or enabled.
693 value |= SCSI_MODE_PAGE_INFORMATIONAL_EXCP_DXCPT_ENABLE;
694 }
695
696 sati_set_data_byte(sequence, scsi_io, offset+2, value);
697
698 //This byte has been set twice, the first time in
699 //sati_mode_sense_copy_initial_data. number_data_bytes_set
700 //needs to be decremented
701 sequence->number_data_bytes_set--;
702 }
703
704 return page_length;
705 }
706
707 /**
708 * @brief This method performs the Power Condition mode page
709 * specific data translation based upon the contents of the
710 * remote device IDENTIFY DEVICE data.
711 * For more information on the parameters passed to this method,
712 * please reference sati_translate_command().
713 *
714 * @param[in] identify This parameter specifies the remote device's
715 * IDENTIFY DEVICE data received as part of the IO request.
716 * @param[in] offset This parameter specifies the offset into the data
717 * buffer where the translated data is to be written.
718 *
719 * @return This method returns the size of the mode page data that was
720 * translated.
721 */
sati_mode_sense_power_condition_translate_data(SATI_TRANSLATOR_SEQUENCE_T * sequence,void * scsi_io,ATA_IDENTIFY_DEVICE_DATA_T * identify,U32 offset)722 U32 sati_mode_sense_power_condition_translate_data(
723 SATI_TRANSLATOR_SEQUENCE_T * sequence,
724 void * scsi_io,
725 ATA_IDENTIFY_DEVICE_DATA_T * identify,
726 U32 offset
727 )
728 {
729 U8 * cdb = sati_cb_get_cdb_address(scsi_io);
730 U8 page_control = sati_get_cdb_byte(cdb, 2) >> SCSI_MODE_SENSE_PC_SHIFT;
731
732 U8 ata_sb_timer;
733
734 //Represents tenths of seconds
735 U32 standby_timer = 0x00000000;
736
737 U8 standby_enabled = STANDBY_TIMER_DISABLED;
738
739 if ((page_control == SCSI_MODE_SENSE_PC_CURRENT) &&
740 (identify->capabilities1 & STANDBY_TIMER_SUPPORTED))
741 {
742 standby_enabled = STANDBY_TIMER_ENABLED;
743
744 ata_sb_timer = sequence->device->ata_standby_timer;
745
746 //converting ATA timer values into SCSI timer values
747 if(ata_sb_timer <= 0xF0)
748 {
749 standby_timer = ata_sb_timer * 50;
750 }
751 else if(ata_sb_timer <= 0xFB)
752 {
753 standby_timer = ((ata_sb_timer - 240) * 18000);
754 }
755 else if(ata_sb_timer == 0xFC)
756 {
757 standby_timer = 12600;
758 }
759 else if(ata_sb_timer == 0xFD)
760 {
761 standby_timer = 432000;
762 }
763 else if(ata_sb_timer == 0xFF)
764 {
765 standby_timer = 12750;
766 }
767 else
768 {
769 standby_timer = 0xFFFFFFFF;
770 }
771 }
772
773 sati_set_data_byte(sequence, scsi_io, offset, SCSI_MODE_PAGE_POWER_CONDITION);
774 sati_set_data_byte(sequence, scsi_io, offset + 1, (SCSI_MODE_PAGE_1A_LENGTH - 2));
775 sati_set_data_byte(sequence, scsi_io, offset + 2, 0x00);
776 sati_set_data_byte(sequence, scsi_io, offset + 3, standby_enabled);
777 sati_set_data_byte(sequence, scsi_io, offset + 4, 0x00);
778 sati_set_data_byte(sequence, scsi_io, offset + 5, 0x00);
779 sati_set_data_byte(sequence, scsi_io, offset + 6, 0x00);
780 sati_set_data_byte(sequence, scsi_io, offset + 7, 0x00);
781 sati_set_data_byte(sequence, scsi_io, offset + 8, (U8) (standby_timer >> 24));
782 sati_set_data_byte(sequence, scsi_io, offset + 9, (U8) (standby_timer >> 16));
783 sati_set_data_byte(sequence, scsi_io, offset + 10, (U8) (standby_timer >> 8));
784 sati_set_data_byte(sequence, scsi_io, offset + 11, (U8) standby_timer);
785
786 return SCSI_MODE_PAGE_1A_LENGTH;
787 }
788
789 /**
790 * @brief This method performs the all pages mode page specific data
791 * translation based upon the contents of the remote device
792 * IDENTIFY DEVICE data. The ALL PAGES mode sense request asks
793 * for all of mode pages and sub-pages in a single page.
794 * The mode pages are added in ascending order.
795 * For more information on the parameters passed to this method,
796 * please reference sati_translate_command().
797 *
798 * @param[in] identify This parameter specifies the remote device's
799 * IDENTIFY DEVICE data received as part of the IO request.
800 * @param[in] offset This parameter specifies the offset into the data
801 * buffer where the translated data is to be written.
802 *
803 * @return This method returns the size of the mode page data that was
804 * translated.
805 */
sati_mode_sense_all_pages_translate_data(SATI_TRANSLATOR_SEQUENCE_T * sequence,void * scsi_io,ATA_IDENTIFY_DEVICE_DATA_T * identify,U32 offset)806 U32 sati_mode_sense_all_pages_translate_data(
807 SATI_TRANSLATOR_SEQUENCE_T * sequence,
808 void * scsi_io,
809 ATA_IDENTIFY_DEVICE_DATA_T * identify,
810 U32 offset
811 )
812 {
813 offset += sati_mode_sense_read_write_error_translate_data(
814 sequence, scsi_io, identify, offset
815 );
816
817 offset += sati_mode_sense_disconnect_reconnect_translate_data(
818 sequence, scsi_io, identify, offset
819 );
820
821 offset += sati_mode_sense_caching_translate_data(
822 sequence, scsi_io, identify, offset
823 );
824
825 offset += sati_mode_sense_control_translate_data(
826 sequence, scsi_io, identify, offset
827 );
828
829 offset += sati_mode_sense_informational_excp_control_translate_data(
830 sequence, scsi_io, identify, offset
831 );
832
833 return offset;
834 }
835
836 #endif // !defined(DISABLE_SATI_MODE_SENSE)
837
838