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