xref: /freebsd/sys/dev/isci/scil/sati_inquiry.c (revision 924226fba12cc9a228c73b956e1b7fa24c60b055)
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  *
61  * @brief This file contains the method implementations required to
62  *        translate the SCSI inquiry command.
63  *        The following (VPD) pages are currently supported:
64  *        - Standard
65  *        - Supported Pages
66  *        - Unit Serial Number
67  *        - Device Identification
68  */
69 
70 #if !defined(DISABLE_SATI_INQUIRY)
71 
72 #include <dev/isci/scil/sati_inquiry.h>
73 #include <dev/isci/scil/sati_callbacks.h>
74 #include <dev/isci/scil/sati_util.h>
75 #include <dev/isci/scil/intel_ata.h>
76 #include <dev/isci/scil/intel_scsi.h>
77 
78 //******************************************************************************
79 //* P R I V A T E   M E T H O D S
80 //******************************************************************************
81 /**
82 * @brief This method builds the SCSI data associated with the SATI product
83 *        revision that is commonly used on the Standard inquiry response and
84 *        the ATA information page.
85 *
86 * @param[in]  sequence This parameter specifies the translator sequence
87 *             object to be utilized during data translation.
88 * @param[in]  ata_input_data This parameter specifies ata data received from
89 *             the remote device.
90 * @param[out] scsi_io This parameter specifies the user IO request for
91 *             which to construct the standard inquiry data.
92 *
93 * @return none
94 */
95 static
96 void sati_inquiry_construct_product_revision(
97    SATI_TRANSLATOR_SEQUENCE_T * sequence,
98    void                       * ata_input_data,
99    void                       * scsi_io
100 )
101 {
102    ATA_IDENTIFY_DEVICE_DATA_T * identify = (ATA_IDENTIFY_DEVICE_DATA_T*)
103       ata_input_data;
104 
105    // Fill in the product revision level field.
106    // Per SAT, copy portions of the firmware revision that is not filled
107    // with spaces.  Some devices left-align their firmware rev ID, while
108    // others right-align.
109    if (  (identify->firmware_revision[4] == 0x20)
110        && (identify->firmware_revision[5] == 0x20)
111        && (identify->firmware_revision[6] == 0x20)
112        && (identify->firmware_revision[7] == 0x20) )
113    {
114       sati_ata_identify_device_copy_data(
115          sequence,
116          scsi_io,
117          32,
118          ata_input_data,
119          ATA_IDENTIFY_DEVICE_GET_OFFSET(firmware_revision),
120          4,
121          TRUE
122        );
123    }
124    else
125    {
126       // Since the last 4 bytes of the firmware revision are not spaces,
127       // utilize these bytes as the firmware revision in the inquiry data.
128       sati_ata_identify_device_copy_data(
129          sequence,
130          scsi_io,
131          32,
132          ata_input_data,
133          ATA_IDENTIFY_DEVICE_GET_OFFSET(firmware_revision)+4,
134          4,
135          TRUE
136       );
137    }
138 }
139 
140 
141 //******************************************************************************
142 //* P U B L I C   M E T H O D S
143 //******************************************************************************
144 
145 /**
146  * @brief This method builds the SCSI data associated with a SCSI standard
147  *        inquiry request.
148  *
149  * @param[in]  sequence This parameter specifies the translator sequence
150  *             object to be utilized during data translation.
151  * @param[in]  ata_input_data This parameter specifies ata data received from
152  *             the remote device.
153  * @param[out] scsi_io This parameter specifies the user IO request for
154  *             which to construct the standard inquiry data.
155  *
156  * @return none
157  */
158 void sati_inquiry_standard_translate_data(
159    SATI_TRANSLATOR_SEQUENCE_T * sequence,
160    void                       * ata_input_data,
161    void                       * scsi_io
162 )
163 {
164    ATA_IDENTIFY_DEVICE_DATA_T * identify = (ATA_IDENTIFY_DEVICE_DATA_T*)
165                                            ata_input_data;
166    U32  index;
167 
168    // Device type is disk, attached to this lun.
169    sati_set_data_byte(sequence, scsi_io, 0, 0x00);
170 
171    // If the device indicates it's a removable media device, then set the
172    // RMB bit
173    if (identify->general_config_bits & ATA_IDENTIFY_REMOVABLE_MEDIA_ENABLE)
174       sati_set_data_byte(sequence, scsi_io, 1, 0x80);
175    else
176       sati_set_data_byte(sequence, scsi_io, 1, 0x00);
177 
178    sati_set_data_byte(sequence, scsi_io, 2, 0x05); // Indicate SPC-3 support
179    sati_set_data_byte(sequence, scsi_io, 3, 0x02); // Response Format SPC-3
180 
181    sati_set_data_byte(sequence, scsi_io, 4, 62); // 62 Additional Data Bytes.
182                                                  // n-4 per the spec, we end at
183                                                  // byte 66, so 66-4.
184    sati_set_data_byte(sequence, scsi_io, 5, 0x00);
185    sati_set_data_byte(sequence, scsi_io, 6, 0x00);
186    sati_set_data_byte(sequence, scsi_io, 7, 0x02); // Enable Cmd Queueing
187 
188    // The Vender identification field is set to "ATA     "
189    sati_set_data_byte(sequence, scsi_io, 8, 0x41);
190    sati_set_data_byte(sequence, scsi_io, 9, 0x54);
191    sati_set_data_byte(sequence, scsi_io, 10, 0x41);
192    sati_set_data_byte(sequence, scsi_io, 11, 0x20);
193    sati_set_data_byte(sequence, scsi_io, 12, 0x20);
194    sati_set_data_byte(sequence, scsi_io, 13, 0x20);
195    sati_set_data_byte(sequence, scsi_io, 14, 0x20);
196    sati_set_data_byte(sequence, scsi_io, 15, 0x20);
197 
198    // Fill in the product ID field.
199    sati_ata_identify_device_copy_data(
200       sequence,
201       scsi_io,
202       16,
203       ata_input_data,
204       ATA_IDENTIFY_DEVICE_GET_OFFSET(model_number),
205       16,
206       TRUE
207    );
208 
209    sati_inquiry_construct_product_revision(
210       sequence,
211       ata_input_data,
212       scsi_io
213    );
214 
215    // Set the remaining fields up to the version descriptors to 0.
216    for (index = 36; index < 58; index++)
217       sati_set_data_byte(sequence, scsi_io, index, 0);
218 
219    // Add version descriptors for the various protocols in play.
220 
221    // SAM-4
222    sati_set_data_byte(sequence, scsi_io, 58, 0);
223    sati_set_data_byte(sequence, scsi_io, 59, 0x80);
224 
225    // SAS-2
226    sati_set_data_byte(sequence, scsi_io, 60, 0x0C);
227    sati_set_data_byte(sequence, scsi_io, 61, 0x20);
228 
229    // SPC-4
230    sati_set_data_byte(sequence, scsi_io, 62, 0x04);
231    sati_set_data_byte(sequence, scsi_io, 63, 0x60);
232 
233    // SBC-3
234    sati_set_data_byte(sequence, scsi_io, 64, 0x04);
235    sati_set_data_byte(sequence, scsi_io, 65, 0xC0);
236 
237    // ATA/ATAPI-8 ACS
238    sati_set_data_byte(sequence, scsi_io, 66, 0x16);
239    sati_set_data_byte(sequence, scsi_io, 67, 0x23);
240 }
241 
242 /**
243  * @brief This method builds the SCSI data associated with an SCSI inquiry
244  *        for the supported VPD pages page.
245  *
246  * @param[in]  sequence This parameter specifies the translator sequence
247  *             object to be utilized during data translation.
248  * @param[out] scsi_io This parameter specifies the user IO request for
249  *             which to construct the supported VPD page information.
250  *
251  * @return none
252  */
253 static
254 void sati_inquiry_supported_pages_translate_data(
255    SATI_TRANSLATOR_SEQUENCE_T * sequence,
256    void                       * scsi_io
257 )
258 {
259    // Formulate the SCSI output data for the caller.
260    sati_set_data_byte(sequence, scsi_io, 0, 0); // Qualifier and Device Type
261    sati_set_data_byte(sequence, scsi_io, 1, SCSI_INQUIRY_SUPPORTED_PAGES_PAGE);
262    sati_set_data_byte(sequence, scsi_io, 2, 0); // Reserved.
263    sati_set_data_byte(sequence, scsi_io, 3, 4); // # VPD pages supported
264    sati_set_data_byte(sequence, scsi_io, 4, SCSI_INQUIRY_SUPPORTED_PAGES_PAGE);
265    sati_set_data_byte(sequence, scsi_io, 5, SCSI_INQUIRY_UNIT_SERIAL_NUM_PAGE);
266    sati_set_data_byte(sequence, scsi_io, 6, SCSI_INQUIRY_DEVICE_ID_PAGE);
267    sati_set_data_byte(sequence, scsi_io, 7, SCSI_INQUIRY_ATA_INFORMATION_PAGE);
268    sati_set_data_byte(sequence, scsi_io, 8, SCSI_INQUIRY_BLOCK_DEVICE_PAGE);
269    sati_set_data_byte(sequence, scsi_io, 9, 0); // End of the list
270 }
271 
272 /**
273  * @brief This method builds the SCSI data associated with a request for
274  *        the unit serial number vital product data (VPD) page.
275  *
276  * @param[in]  sequence This parameter specifies the translator sequence
277  *             object to be utilized during data translation.
278  * @param[in]  ata_input_data This parameter specifies ata data received from
279  *             the remote device.
280  * @param[out] scsi_io This parameter specifies the user IO request for
281  *             which to construct the unit serial number data.
282  *
283  * @return none
284  */
285 void sati_inquiry_serial_number_translate_data(
286    SATI_TRANSLATOR_SEQUENCE_T * sequence,
287    void                       * ata_input_data,
288    void                       * scsi_io
289 )
290 {
291    // Peripheral qualifier (0x0, currently connected)
292    // Peripheral device type (0x0 direct-access block device)
293    sati_set_data_byte(sequence, scsi_io, 0, 0x00);
294 
295    sati_set_data_byte(sequence, scsi_io, 1, SCSI_INQUIRY_UNIT_SERIAL_NUM_PAGE);
296    sati_set_data_byte(sequence, scsi_io, 2, 0x00);  // Reserved
297    sati_set_data_byte(sequence, scsi_io, 3, ATA_IDENTIFY_SERIAL_NUMBER_LEN);
298 
299    sati_ata_identify_device_copy_data(
300       sequence,
301       scsi_io,
302       4,
303       ata_input_data,
304       ATA_IDENTIFY_DEVICE_GET_OFFSET(serial_number),
305       ATA_IDENTIFY_SERIAL_NUMBER_LEN,
306       TRUE
307    );
308 }
309 
310 /**
311 * @brief This method builds the SCSI data associated with a request for
312 *        the Block Device Characteristics vital product data (VPD) page.
313 *
314 * @param[in]  sequence This parameter specifies the translator sequence
315 *             object to be utilized during data translation.
316 * @param[in]  ata_input_data This parameter specifies ata data received from
317 *             the remote device.
318 * @param[out] scsi_io This parameter specifies the user IO request for
319 *             which to construct the unit serial number data.
320 *
321 * @return none
322 */
323 void sati_inquiry_block_device_translate_data(
324    SATI_TRANSLATOR_SEQUENCE_T * sequence,
325    void                       * ata_input_data,
326    void                       * scsi_io
327 )
328 {
329    ATA_IDENTIFY_DEVICE_DATA_T * identify = (ATA_IDENTIFY_DEVICE_DATA_T*)
330       ata_input_data;
331 
332    U32 offset;
333 
334    // Peripheral qualifier (0x0, currently connected)
335    // Peripheral device type (0x0 direct-access block device)
336    sati_set_data_byte(sequence, scsi_io, 0, 0x00);
337 
338    sati_set_data_byte(sequence, scsi_io, 1, SCSI_INQUIRY_BLOCK_DEVICE_PAGE);
339 
340    //PAGE LENGTH 0x003C
341    sati_set_data_byte(sequence, scsi_io, 2, 0x00);
342    sati_set_data_byte(sequence, scsi_io, 3, SCSI_INQUIRY_BLOCK_DEVICE_LENGTH);
343 
344    sati_ata_identify_device_copy_data(
345       sequence,
346       scsi_io,
347       4,
348       ata_input_data,
349       ATA_IDENTIFY_DEVICE_GET_OFFSET(nominal_media_rotation_rate),
350       2,
351       FALSE
352     );
353 
354     sati_set_data_byte(sequence, scsi_io, 6, 0x00);
355 
356     sati_set_data_byte(
357        sequence,
358        scsi_io,
359        7,
360        (identify->device_nominal_form_factor & 0x0F) // only need bits 0-3
361     );
362 
363     //bytes 8-63 are reserved
364     for(offset = 8; offset < 64; offset++)
365     {
366        sati_set_data_byte(sequence, scsi_io, offset, 0x00);
367     }
368 }
369 
370 /**
371  * @brief This method builds the SCSI data associated with a request for
372  *        the device identification vital product data (VPD) page.
373  *
374  * @param[in]  sequence This parameter specifies the translator sequence
375  *             object to be utilized during data translation.
376  * @param[in]  ata_input_data This parameter specifies ata data received from
377  *             the remote device.
378  * @param[out] scsi_io This parameter specifies the user IO request for
379  *             which to construct the device ID page.
380  *
381  * @return none
382  */
383 void sati_inquiry_device_id_translate_data(
384    SATI_TRANSLATOR_SEQUENCE_T * sequence,
385    void                       * ata_input_data,
386    void                       * scsi_io
387 )
388 {
389    ATA_IDENTIFY_DEVICE_DATA_T * identify    = (ATA_IDENTIFY_DEVICE_DATA_T*)
390                                               ata_input_data;
391    U16                     byte_offset = 4;
392    U16                     page_length;
393 
394    // Peripheral qualifier (0x0, currently connected)
395    // Peripheral device type (0x0 direct-access block device)
396    sati_set_data_byte(sequence, scsi_io, 0, 0x00);
397 
398    sati_set_data_byte(sequence, scsi_io, 1, SCSI_INQUIRY_DEVICE_ID_PAGE);
399 
400    /**
401     * If World Wide Names are supported by this target, then build an
402     * identification descriptor using the WWN.
403     */
404 
405    if (identify->command_set_supported_extention
406        & ATA_IDENTIFY_COMMAND_SET_WWN_SUPPORT_ENABLE)
407    {
408 
409       sati_set_data_byte(sequence,
410          scsi_io, 4, SCSI_FC_PROTOCOL_IDENTIFIER | SCSI_BINARY_CODE_SET
411       );
412 
413 
414       sati_set_data_byte(sequence,
415          scsi_io, 5, SCSI_LUN_ASSOCIATION | SCSI_NAA_IDENTIFIER_TYPE
416       );
417 
418       sati_set_data_byte(sequence, scsi_io, 6, 0);
419       sati_set_data_byte(sequence, scsi_io, 7, 0x08); // WWN are 8 bytes long
420 
421       // Copy data from the identify device world wide name field into the
422       // buffer.
423       sati_ata_identify_device_copy_data(
424          sequence,
425          scsi_io,
426          8,
427          ata_input_data,
428          ATA_IDENTIFY_DEVICE_GET_OFFSET(world_wide_name),
429          ATA_IDENTIFY_WWN_LEN,
430          FALSE
431       );
432 
433       byte_offset = 16;
434    }
435 
436    /**
437     * Build a identification descriptor using the model number & serial number.
438     */
439 
440    sati_set_data_byte(sequence,
441       scsi_io, byte_offset, SCSI_FC_PROTOCOL_IDENTIFIER | SCSI_ASCII_CODE_SET
442    );
443    byte_offset++;
444    sati_set_data_byte(sequence,
445       scsi_io, byte_offset, SCSI_LUN_ASSOCIATION | SCSI_T10_IDENTIFIER_TYPE
446    );
447    byte_offset++;
448    sati_set_data_byte(sequence, scsi_io, byte_offset, 0);
449    byte_offset++;
450 
451    // Identifier length (8 bytes for "ATA     " + 40 bytes from ATA IDENTIFY
452    // model number field + 20 bytes from ATA IDENTIFY serial number field.
453    sati_set_data_byte(
454       sequence,
455       scsi_io,
456       byte_offset,
457       8 + (ATA_IDENTIFY_SERIAL_NUMBER_LEN) + (ATA_IDENTIFY_MODEL_NUMBER_LEN)
458    );
459    byte_offset++;
460 
461    // Per SAT, write "ATA     ".
462    sati_set_data_byte(sequence, scsi_io, byte_offset, 0x41);
463    byte_offset++;
464    sati_set_data_byte(sequence, scsi_io, byte_offset, 0x54);
465    byte_offset++;
466    sati_set_data_byte(sequence, scsi_io, byte_offset, 0x41);
467    byte_offset++;
468    sati_set_data_byte(sequence, scsi_io, byte_offset, 0x20);
469    byte_offset++;
470    sati_set_data_byte(sequence, scsi_io, byte_offset, 0x20);
471    byte_offset++;
472    sati_set_data_byte(sequence, scsi_io, byte_offset, 0x20);
473    byte_offset++;
474    sati_set_data_byte(sequence, scsi_io, byte_offset, 0x20);
475    byte_offset++;
476    sati_set_data_byte(sequence, scsi_io, byte_offset, 0x20);
477    byte_offset++;
478 
479    // Copy data from the identify device model number field into the
480    // buffer and update the byte_offset.
481    sati_ata_identify_device_copy_data(
482       sequence,
483       scsi_io,
484       byte_offset,
485       ata_input_data,
486       ATA_IDENTIFY_DEVICE_GET_OFFSET(model_number),
487       ATA_IDENTIFY_MODEL_NUMBER_LEN,
488       TRUE
489    );
490 
491    byte_offset += ATA_IDENTIFY_MODEL_NUMBER_LEN;
492 
493    // Copy data from the identify device serial number field into the
494    // buffer and update the byte_offset.
495    sati_ata_identify_device_copy_data(
496       sequence,
497       scsi_io,
498       byte_offset,
499       ata_input_data,
500       ATA_IDENTIFY_DEVICE_GET_OFFSET(serial_number),
501       ATA_IDENTIFY_SERIAL_NUMBER_LEN,
502       TRUE
503    );
504 
505    byte_offset += ATA_IDENTIFY_SERIAL_NUMBER_LEN;
506 
507    /**
508     * If the target is contained in a SAS Domain, then build a target port
509     * ID descriptor using the SAS address.
510     */
511 
512 #if     defined(SATI_TRANSPORT_SUPPORTS_SAS)       \
513      && defined(DISABLE_MSFT_SCSI_COMPLIANCE_SUPPORT)
514    {
515       SCI_SAS_ADDRESS_T sas_address;
516 
517       sati_set_data_byte(
518          sequence,
519          scsi_io,
520          byte_offset,
521          SCSI_SAS_PROTOCOL_IDENTIFIER | SCSI_BINARY_CODE_SET
522       );
523       byte_offset++;
524 
525       sati_set_data_byte(
526          sequence,
527          scsi_io,
528          byte_offset,
529          SCSI_PIV_ENABLE | SCSI_TARGET_PORT_ASSOCIATION |
530          SCSI_NAA_IDENTIFIER_TYPE
531       );
532 
533       byte_offset++;
534       sati_set_data_byte(sequence, scsi_io, byte_offset, 0);
535       byte_offset++;
536       sati_set_data_byte(sequence, scsi_io, byte_offset, 8); // SAS Addr=8 bytes
537       byte_offset++;
538 
539       sati_cb_device_get_sas_address(scsi_io, &sas_address);
540 
541       // Store the SAS address in the target port descriptor.
542       sati_set_data_dword(sequence, scsi_io, byte_offset, sas_address.high);
543       byte_offset += 4;
544       sati_set_data_dword(sequence, scsi_io, byte_offset, sas_address.low);
545       byte_offset += 4;
546    }
547 #endif // SATI_TRANSPORT_SUPPORTS_SAS && DISABLE_MSFT_SCSI_COMPLIANCE_SUPPORT
548 
549    /**
550     * Set the Page length field.  The page length is n-3, where n is the
551     * last offset in the page (considered page length - 4).
552     */
553 
554    page_length = byte_offset - 4;
555    sati_set_data_byte(sequence, scsi_io, 2, (U8)((page_length & 0xFF00) >> 8));
556    sati_set_data_byte(sequence, scsi_io, 3, (U8)(page_length & 0x00FF));
557 }
558 
559 /**
560 * @brief This method builds the SCSI data associated with a request for
561 *        the  ATA information vital product data (VPD) page.
562 *
563 * @param[in]  sequence This parameter specifies the translator sequence
564 *             object to be utilized during data translation.
565 * @param[in]  ata_input_data This parameter specifies ata data received from
566 *             a identify device command processed by the remote device.
567 * @param[out] scsi_io This parameter specifies the user IO request for
568 *             which to construct the ATA information page.
569 *
570 * @return none
571 */
572 SATI_STATUS sati_inquiry_ata_information_translate_data(
573    SATI_TRANSLATOR_SEQUENCE_T * sequence,
574    void                       * ata_input_data,
575    void                       * scsi_io
576 )
577 {
578    sati_set_data_byte(sequence, scsi_io, 0, 0x00);
579    sati_set_data_byte(sequence, scsi_io, 1, SCSI_INQUIRY_ATA_INFORMATION_PAGE);
580    sati_set_data_byte(sequence, scsi_io, 2, 0x02);
581    sati_set_data_byte(sequence, scsi_io, 3, 0x38);
582 
583    //Reserved SAT2r07
584    sati_set_data_byte(sequence, scsi_io, 4, 0x00);
585    sati_set_data_byte(sequence, scsi_io, 5, 0x00);
586    sati_set_data_byte(sequence, scsi_io, 6, 0x00);
587    sati_set_data_byte(sequence, scsi_io, 7, 0x00);
588 
589    // The Vender identification field is set to "ATA     "
590    sati_set_data_byte(sequence, scsi_io, 8, 0x41);
591    sati_set_data_byte(sequence, scsi_io, 9, 0x54);
592    sati_set_data_byte(sequence, scsi_io, 10, 0x41);
593    sati_set_data_byte(sequence, scsi_io, 11, 0x20);
594    sati_set_data_byte(sequence, scsi_io, 12, 0x20);
595    sati_set_data_byte(sequence, scsi_io, 13, 0x20);
596    sati_set_data_byte(sequence, scsi_io, 14, 0x20);
597    sati_set_data_byte(sequence, scsi_io, 15, 0x20);
598 
599    //SAT Product identification
600    sati_ata_identify_device_copy_data(
601       sequence,
602       scsi_io,
603       16,
604       ata_input_data,
605       ATA_IDENTIFY_DEVICE_GET_OFFSET(model_number),
606       16,
607       TRUE
608    );
609 
610    //SAT Product Revision level bytes 32-35
611    sati_inquiry_construct_product_revision(
612       sequence,
613       ata_input_data,
614       scsi_io
615    );
616 
617    //skipping ATA device signature for now
618 
619    //Command code
620    sati_set_data_byte(sequence, scsi_io, 56, 0xEC);
621 
622    //Reserved SAT2r07
623    sati_set_data_byte(sequence, scsi_io, 57, 0x00);
624    sati_set_data_byte(sequence, scsi_io, 58, 0x00);
625    sati_set_data_byte(sequence, scsi_io, 59, 0x00);
626 
627    //copy all ATA identify device data
628    sati_ata_identify_device_copy_data(
629       sequence,
630       scsi_io,
631       60,
632       ata_input_data,
633       0,
634       sizeof(ATA_IDENTIFY_DEVICE_DATA_T),
635       FALSE
636    );
637 
638    //Need to send ATA Execute Device Diagnostic command still
639    sequence->state = SATI_SEQUENCE_STATE_INCOMPLETE;
640 
641    return SATI_SEQUENCE_INCOMPLETE;
642 }
643 
644 /**
645  * @brief This method will translate the inquiry SCSI command into
646  *        an ATA IDENTIFY DEVICE command.  It will handle several different
647  *        VPD pages and the standard inquiry page.
648  *        For more information on the parameters passed to this method,
649  *        please reference sati_translate_command().
650  *
651  * @return Indicate if the command translation succeeded.
652  * @retval SCI_SUCCESS This is returned if the command translation was
653  *         successful.
654  * @retval SATI_FAILURE_CHECK_RESPONSE_DATA This value is returned if
655  *         the page isn't supported, or the page code
656  *         field is not zero when the EVPD bit is 0.
657  */
658 SATI_STATUS sati_inquiry_translate_command(
659    SATI_TRANSLATOR_SEQUENCE_T * sequence,
660    void                       * scsi_io,
661    void                       * ata_io
662 )
663 {
664    U8 * cdb = sati_cb_get_cdb_address(scsi_io);
665 
666    /**
667     * SPC dictates:
668     * - that the page code field must be 0, if VPD enable is 0.
669     */
670    if (  ((sati_get_cdb_byte(cdb, 1) & SCSI_INQUIRY_EVPD_ENABLE) == 0)
671       && (sati_get_cdb_byte(cdb, 2) != 0) )
672    {
673       sati_scsi_sense_data_construct(
674          sequence,
675          scsi_io,
676          SCSI_STATUS_CHECK_CONDITION,
677          SCSI_SENSE_ILLEGAL_REQUEST,
678          SCSI_ASC_INVALID_FIELD_IN_CDB,
679          SCSI_ASCQ_INVALID_FIELD_IN_CDB
680       );
681       return SATI_FAILURE_CHECK_RESPONSE_DATA;
682    }
683 
684    // Set the data length based on the allocation length field in the CDB.
685    sequence->allocation_length = (sati_get_cdb_byte(cdb, 3) << 8) |
686                                  (sati_get_cdb_byte(cdb, 4));
687 
688    // Check to see if there was a request for the vital product data or just
689    // the standard inquiry.
690    if (sati_get_cdb_byte(cdb, 1) & SCSI_INQUIRY_EVPD_ENABLE)
691    {
692       // Parse the page code to determine which translator to invoke.
693       switch (sati_get_cdb_byte(cdb, 2))
694       {
695          case SCSI_INQUIRY_SUPPORTED_PAGES_PAGE:
696             sequence->type  = SATI_SEQUENCE_INQUIRY_SUPPORTED_PAGES;
697             sati_inquiry_supported_pages_translate_data(sequence, scsi_io);
698             return SATI_COMPLETE;
699          break;
700 
701          case SCSI_INQUIRY_UNIT_SERIAL_NUM_PAGE:
702             sequence->type = SATI_SEQUENCE_INQUIRY_SERIAL_NUMBER;
703          break;
704 
705          case SCSI_INQUIRY_DEVICE_ID_PAGE:
706             sequence->type = SATI_SEQUENCE_INQUIRY_DEVICE_ID;
707          break;
708 
709          case SCSI_INQUIRY_ATA_INFORMATION_PAGE:
710 
711             if(sequence->state == SATI_SEQUENCE_STATE_INCOMPLETE)
712             {
713                sati_ata_execute_device_diagnostic_construct(
714                   ata_io,
715                   sequence
716                );
717                sequence->type = SATI_SEQUENCE_INQUIRY_EXECUTE_DEVICE_DIAG;
718             }
719             else
720             {
721                sequence->type = SATI_SEQUENCE_INQUIRY_ATA_INFORMATION;
722             }
723          break;
724 
725          case SCSI_INQUIRY_BLOCK_DEVICE_PAGE:
726             sequence->type = SATI_SEQUENCE_INQUIRY_BLOCK_DEVICE;
727          break;
728 
729          default:
730             sati_scsi_sense_data_construct(
731                sequence,
732                scsi_io,
733                SCSI_STATUS_CHECK_CONDITION,
734                SCSI_SENSE_ILLEGAL_REQUEST,
735                SCSI_ASC_INVALID_FIELD_IN_CDB,
736                SCSI_ASCQ_INVALID_FIELD_IN_CDB
737             );
738             return SATI_FAILURE_CHECK_RESPONSE_DATA;
739          break;
740       }
741    }
742    else
743    {
744       sequence->type = SATI_SEQUENCE_INQUIRY_STANDARD;
745    }
746 
747    sati_ata_identify_device_construct(ata_io, sequence);
748 
749    return SATI_SUCCESS;
750 }
751 
752 /**
753 * @brief This method finishes the construction of the SCSI data associated
754          with a request for the  ATA information vital product data (VPD) page.
755          The ATA device signature is written into the data response from the
756          task fle registers after issuing a Execute Device Diagnostic command.
757 *
758 * @param[in]  sequence This parameter specifies the translator sequence
759 *             object to be utilized during data translation.
760 * @param[out] scsi_io This parameter specifies the user IO request for
761 *             which to construct the ATA information page.
762 * @param[in]  ata_io This parameter specifies the ATA payload
763 *             buffer location and size to be translated.
764 *
765 * @return none
766 */
767 void sati_inquiry_ata_information_finish_translation(
768    SATI_TRANSLATOR_SEQUENCE_T * sequence,
769    void                       * scsi_io,
770    void                       * ata_io
771 )
772 {
773    U8 * register_fis = sati_cb_get_d2h_register_fis_address(ata_io);
774    U32 offset;
775 
776    //SATA transport
777    sati_set_data_byte(sequence, scsi_io, 36, 0x34);
778    sati_set_data_byte(sequence, scsi_io, 37, 0x00);
779    sati_set_data_byte(sequence, scsi_io, 38, (U8) sati_get_ata_status(register_fis));
780    sati_set_data_byte(sequence, scsi_io, 39, (U8) sati_get_ata_error(register_fis));
781    sati_set_data_byte(sequence, scsi_io, 40, sati_get_ata_lba_low(register_fis));
782    sati_set_data_byte(sequence, scsi_io, 41, sati_get_ata_lba_mid(register_fis));
783    sati_set_data_byte(sequence, scsi_io, 42, sati_get_ata_lba_high(register_fis));
784    sati_set_data_byte(sequence, scsi_io, 43, sati_get_ata_device(register_fis));
785    sati_set_data_byte(sequence, scsi_io, 44, sati_get_ata_lba_low_ext(register_fis));
786    sati_set_data_byte(sequence, scsi_io, 45, sati_get_ata_lba_mid_ext(register_fis));
787    sati_set_data_byte(sequence, scsi_io, 46, sati_get_ata_lba_high_ext(register_fis));
788    sati_set_data_byte(sequence, scsi_io, 47, 0x00);
789    sati_set_data_byte(sequence, scsi_io, 48, sati_get_ata_sector_count(register_fis));
790    sati_set_data_byte(sequence, scsi_io, 49, sati_get_ata_sector_count_exp(register_fis));
791 
792    for(offset = 50; offset < 56; offset++)
793    {
794       sati_set_data_byte(sequence, scsi_io, offset, 0x00);
795    }
796 
797    sequence->state = SATI_SEQUENCE_STATE_FINAL;
798 }
799 
800 #endif // !defined(DISABLE_SATI_INQUIRY)
801 
802