sati_inquiry.c revision 330897
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: stable/11/sys/dev/isci/scil/sati_inquiry.c 330897 2018-03-14 03:19:51Z eadler $");
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*/
95static
96void 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 */
158void 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 */
253static
254void 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 */
285void 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*/
323void 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 */
383void 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*/
572SATI_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 */
658SATI_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*/
767void 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