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