1230557Sjimharris/*-
2230557Sjimharris * This file is provided under a dual BSD/GPLv2 license.  When using or
3230557Sjimharris * redistributing this file, you may do so under either license.
4230557Sjimharris *
5230557Sjimharris * GPL LICENSE SUMMARY
6230557Sjimharris *
7230557Sjimharris * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
8230557Sjimharris *
9230557Sjimharris * This program is free software; you can redistribute it and/or modify
10230557Sjimharris * it under the terms of version 2 of the GNU General Public License as
11230557Sjimharris * published by the Free Software Foundation.
12230557Sjimharris *
13230557Sjimharris * This program is distributed in the hope that it will be useful, but
14230557Sjimharris * WITHOUT ANY WARRANTY; without even the implied warranty of
15230557Sjimharris * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16230557Sjimharris * General Public License for more details.
17230557Sjimharris *
18230557Sjimharris * You should have received a copy of the GNU General Public License
19230557Sjimharris * along with this program; if not, write to the Free Software
20230557Sjimharris * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
21230557Sjimharris * The full GNU General Public License is included in this distribution
22230557Sjimharris * in the file called LICENSE.GPL.
23230557Sjimharris *
24230557Sjimharris * BSD LICENSE
25230557Sjimharris *
26230557Sjimharris * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
27230557Sjimharris * All rights reserved.
28230557Sjimharris *
29230557Sjimharris * Redistribution and use in source and binary forms, with or without
30230557Sjimharris * modification, are permitted provided that the following conditions
31230557Sjimharris * are met:
32230557Sjimharris *
33230557Sjimharris *   * Redistributions of source code must retain the above copyright
34230557Sjimharris *     notice, this list of conditions and the following disclaimer.
35230557Sjimharris *   * Redistributions in binary form must reproduce the above copyright
36230557Sjimharris *     notice, this list of conditions and the following disclaimer in
37230557Sjimharris *     the documentation and/or other materials provided with the
38230557Sjimharris *     distribution.
39230557Sjimharris *
40230557Sjimharris * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
41230557Sjimharris * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
42230557Sjimharris * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
43230557Sjimharris * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
44230557Sjimharris * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
45230557Sjimharris * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
46230557Sjimharris * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
47230557Sjimharris * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
48230557Sjimharris * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
49230557Sjimharris * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
50230557Sjimharris * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
51230557Sjimharris */
52230557Sjimharris
53230557Sjimharris#include <sys/cdefs.h>
54230557Sjimharris__FBSDID("$FreeBSD$");
55230557Sjimharris
56230557Sjimharris/**
57230557Sjimharris * @file
58230557Sjimharris *
59230557Sjimharris * @brief This file contains the method implementations required to
60230557Sjimharris *        translate the SCSI inquiry command.
61230557Sjimharris *        The following (VPD) pages are currently supported:
62230557Sjimharris *        - Standard
63230557Sjimharris *        - Supported Pages
64230557Sjimharris *        - Unit Serial Number
65230557Sjimharris *        - Device Identification
66230557Sjimharris */
67230557Sjimharris
68230557Sjimharris#if !defined(DISABLE_SATI_INQUIRY)
69230557Sjimharris
70230557Sjimharris#include <dev/isci/scil/sati_inquiry.h>
71230557Sjimharris#include <dev/isci/scil/sati_callbacks.h>
72230557Sjimharris#include <dev/isci/scil/sati_util.h>
73230557Sjimharris#include <dev/isci/scil/intel_ata.h>
74230557Sjimharris#include <dev/isci/scil/intel_scsi.h>
75230557Sjimharris
76230557Sjimharris//******************************************************************************
77230557Sjimharris//* P R I V A T E   M E T H O D S
78230557Sjimharris//******************************************************************************
79230557Sjimharris/**
80230557Sjimharris* @brief This method builds the SCSI data associated with the SATI product
81230557Sjimharris*        revision that is commonly used on the Standard inquiry response and
82230557Sjimharris*        the ATA information page.
83230557Sjimharris*
84230557Sjimharris* @param[in]  sequence This parameter specifies the translator sequence
85230557Sjimharris*             object to be utilized during data translation.
86230557Sjimharris* @param[in]  ata_input_data This parameter specifies ata data received from
87230557Sjimharris*             the remote device.
88230557Sjimharris* @param[out] scsi_io This parameter specifies the user IO request for
89230557Sjimharris*             which to construct the standard inquiry data.
90230557Sjimharris*
91230557Sjimharris* @return none
92230557Sjimharris*/
93230557Sjimharrisstatic
94230557Sjimharrisvoid sati_inquiry_construct_product_revision(
95230557Sjimharris   SATI_TRANSLATOR_SEQUENCE_T * sequence,
96230557Sjimharris   void                       * ata_input_data,
97230557Sjimharris   void                       * scsi_io
98230557Sjimharris)
99230557Sjimharris{
100230557Sjimharris   ATA_IDENTIFY_DEVICE_DATA_T * identify = (ATA_IDENTIFY_DEVICE_DATA_T*)
101230557Sjimharris      ata_input_data;
102230557Sjimharris
103230557Sjimharris   // Fill in the product revision level field.
104230557Sjimharris   // Per SAT, copy portions of the firmware revision that is not filled
105230557Sjimharris   // with spaces.  Some devices left-align their firmware rev ID, while
106230557Sjimharris   // others right-align.
107230557Sjimharris   if (  (identify->firmware_revision[4] == 0x20)
108230557Sjimharris       && (identify->firmware_revision[5] == 0x20)
109230557Sjimharris       && (identify->firmware_revision[6] == 0x20)
110230557Sjimharris       && (identify->firmware_revision[7] == 0x20) )
111230557Sjimharris   {
112230557Sjimharris      sati_ata_identify_device_copy_data(
113230557Sjimharris         sequence,
114230557Sjimharris         scsi_io,
115230557Sjimharris         32,
116230557Sjimharris         ata_input_data,
117230557Sjimharris         ATA_IDENTIFY_DEVICE_GET_OFFSET(firmware_revision),
118230557Sjimharris         4,
119230557Sjimharris         TRUE
120230557Sjimharris       );
121230557Sjimharris   }
122230557Sjimharris   else
123230557Sjimharris   {
124230557Sjimharris      // Since the last 4 bytes of the firmware revision are not spaces,
125230557Sjimharris      // utilize these bytes as the firmware revision in the inquiry data.
126230557Sjimharris      sati_ata_identify_device_copy_data(
127230557Sjimharris         sequence,
128230557Sjimharris         scsi_io,
129230557Sjimharris         32,
130230557Sjimharris         ata_input_data,
131230557Sjimharris         ATA_IDENTIFY_DEVICE_GET_OFFSET(firmware_revision)+4,
132230557Sjimharris         4,
133230557Sjimharris         TRUE
134230557Sjimharris      );
135230557Sjimharris   }
136230557Sjimharris}
137230557Sjimharris
138230557Sjimharris
139230557Sjimharris//******************************************************************************
140230557Sjimharris//* P U B L I C   M E T H O D S
141230557Sjimharris//******************************************************************************
142230557Sjimharris
143230557Sjimharris/**
144230557Sjimharris * @brief This method builds the SCSI data associated with a SCSI standard
145230557Sjimharris *        inquiry request.
146230557Sjimharris *
147230557Sjimharris * @param[in]  sequence This parameter specifies the translator sequence
148230557Sjimharris *             object to be utilized during data translation.
149230557Sjimharris * @param[in]  ata_input_data This parameter specifies ata data received from
150230557Sjimharris *             the remote device.
151230557Sjimharris * @param[out] scsi_io This parameter specifies the user IO request for
152230557Sjimharris *             which to construct the standard inquiry data.
153230557Sjimharris *
154230557Sjimharris * @return none
155230557Sjimharris */
156230557Sjimharrisvoid sati_inquiry_standard_translate_data(
157230557Sjimharris   SATI_TRANSLATOR_SEQUENCE_T * sequence,
158230557Sjimharris   void                       * ata_input_data,
159230557Sjimharris   void                       * scsi_io
160230557Sjimharris)
161230557Sjimharris{
162230557Sjimharris   ATA_IDENTIFY_DEVICE_DATA_T * identify = (ATA_IDENTIFY_DEVICE_DATA_T*)
163230557Sjimharris                                           ata_input_data;
164230557Sjimharris   U32  index;
165230557Sjimharris
166230557Sjimharris   // Device type is disk, attached to this lun.
167230557Sjimharris   sati_set_data_byte(sequence, scsi_io, 0, 0x00);
168230557Sjimharris
169230557Sjimharris   // If the device indicates it's a removable media device, then set the
170230557Sjimharris   // RMB bit
171230557Sjimharris   if (identify->general_config_bits & ATA_IDENTIFY_REMOVABLE_MEDIA_ENABLE)
172230557Sjimharris      sati_set_data_byte(sequence, scsi_io, 1, 0x80);
173230557Sjimharris   else
174230557Sjimharris      sati_set_data_byte(sequence, scsi_io, 1, 0x00);
175230557Sjimharris
176230557Sjimharris   sati_set_data_byte(sequence, scsi_io, 2, 0x05); // Indicate SPC-3 support
177230557Sjimharris   sati_set_data_byte(sequence, scsi_io, 3, 0x02); // Response Format SPC-3
178230557Sjimharris
179230557Sjimharris   sati_set_data_byte(sequence, scsi_io, 4, 62); // 62 Additional Data Bytes.
180230557Sjimharris                                                 // n-4 per the spec, we end at
181230557Sjimharris                                                 // byte 66, so 66-4.
182230557Sjimharris   sati_set_data_byte(sequence, scsi_io, 5, 0x00);
183230557Sjimharris   sati_set_data_byte(sequence, scsi_io, 6, 0x00);
184230557Sjimharris   sati_set_data_byte(sequence, scsi_io, 7, 0x02); // Enable Cmd Queueing
185230557Sjimharris
186230557Sjimharris   // The Vender identification field is set to "ATA     "
187230557Sjimharris   sati_set_data_byte(sequence, scsi_io, 8, 0x41);
188230557Sjimharris   sati_set_data_byte(sequence, scsi_io, 9, 0x54);
189230557Sjimharris   sati_set_data_byte(sequence, scsi_io, 10, 0x41);
190230557Sjimharris   sati_set_data_byte(sequence, scsi_io, 11, 0x20);
191230557Sjimharris   sati_set_data_byte(sequence, scsi_io, 12, 0x20);
192230557Sjimharris   sati_set_data_byte(sequence, scsi_io, 13, 0x20);
193230557Sjimharris   sati_set_data_byte(sequence, scsi_io, 14, 0x20);
194230557Sjimharris   sati_set_data_byte(sequence, scsi_io, 15, 0x20);
195230557Sjimharris
196230557Sjimharris   // Fill in the product ID field.
197230557Sjimharris   sati_ata_identify_device_copy_data(
198230557Sjimharris      sequence,
199230557Sjimharris      scsi_io,
200230557Sjimharris      16,
201230557Sjimharris      ata_input_data,
202230557Sjimharris      ATA_IDENTIFY_DEVICE_GET_OFFSET(model_number),
203230557Sjimharris      16,
204230557Sjimharris      TRUE
205230557Sjimharris   );
206230557Sjimharris
207230557Sjimharris   sati_inquiry_construct_product_revision(
208230557Sjimharris      sequence,
209230557Sjimharris      ata_input_data,
210230557Sjimharris      scsi_io
211230557Sjimharris   );
212230557Sjimharris
213230557Sjimharris   // Set the remaining fields up to the version descriptors to 0.
214230557Sjimharris   for (index = 36; index < 58; index++)
215230557Sjimharris      sati_set_data_byte(sequence, scsi_io, index, 0);
216230557Sjimharris
217230557Sjimharris   // Add version descriptors for the various protocols in play.
218230557Sjimharris
219230557Sjimharris   // SAM-4
220230557Sjimharris   sati_set_data_byte(sequence, scsi_io, 58, 0);
221230557Sjimharris   sati_set_data_byte(sequence, scsi_io, 59, 0x80);
222230557Sjimharris
223230557Sjimharris   // SAS-2
224230557Sjimharris   sati_set_data_byte(sequence, scsi_io, 60, 0x0C);
225230557Sjimharris   sati_set_data_byte(sequence, scsi_io, 61, 0x20);
226230557Sjimharris
227230557Sjimharris   // SPC-4
228230557Sjimharris   sati_set_data_byte(sequence, scsi_io, 62, 0x04);
229230557Sjimharris   sati_set_data_byte(sequence, scsi_io, 63, 0x60);
230230557Sjimharris
231230557Sjimharris   // SBC-3
232230557Sjimharris   sati_set_data_byte(sequence, scsi_io, 64, 0x04);
233230557Sjimharris   sati_set_data_byte(sequence, scsi_io, 65, 0xC0);
234230557Sjimharris
235230557Sjimharris   // ATA/ATAPI-8 ACS
236230557Sjimharris   sati_set_data_byte(sequence, scsi_io, 66, 0x16);
237230557Sjimharris   sati_set_data_byte(sequence, scsi_io, 67, 0x23);
238230557Sjimharris}
239230557Sjimharris
240230557Sjimharris/**
241230557Sjimharris * @brief This method builds the SCSI data associated with an SCSI inquiry
242230557Sjimharris *        for the supported VPD pages page.
243230557Sjimharris *
244230557Sjimharris * @param[in]  sequence This parameter specifies the translator sequence
245230557Sjimharris *             object to be utilized during data translation.
246230557Sjimharris * @param[out] scsi_io This parameter specifies the user IO request for
247230557Sjimharris *             which to construct the supported VPD page information.
248230557Sjimharris *
249230557Sjimharris * @return none
250230557Sjimharris */
251230557Sjimharrisstatic
252230557Sjimharrisvoid sati_inquiry_supported_pages_translate_data(
253230557Sjimharris   SATI_TRANSLATOR_SEQUENCE_T * sequence,
254230557Sjimharris   void                       * scsi_io
255230557Sjimharris)
256230557Sjimharris{
257230557Sjimharris   // Formulate the SCSI output data for the caller.
258230557Sjimharris   sati_set_data_byte(sequence, scsi_io, 0, 0); // Qualifier and Device Type
259230557Sjimharris   sati_set_data_byte(sequence, scsi_io, 1, SCSI_INQUIRY_SUPPORTED_PAGES_PAGE);
260230557Sjimharris   sati_set_data_byte(sequence, scsi_io, 2, 0); // Reserved.
261230557Sjimharris   sati_set_data_byte(sequence, scsi_io, 3, 4); // # VPD pages supported
262230557Sjimharris   sati_set_data_byte(sequence, scsi_io, 4, SCSI_INQUIRY_SUPPORTED_PAGES_PAGE);
263230557Sjimharris   sati_set_data_byte(sequence, scsi_io, 5, SCSI_INQUIRY_UNIT_SERIAL_NUM_PAGE);
264230557Sjimharris   sati_set_data_byte(sequence, scsi_io, 6, SCSI_INQUIRY_DEVICE_ID_PAGE);
265230557Sjimharris   sati_set_data_byte(sequence, scsi_io, 7, SCSI_INQUIRY_ATA_INFORMATION_PAGE);
266230557Sjimharris   sati_set_data_byte(sequence, scsi_io, 8, SCSI_INQUIRY_BLOCK_DEVICE_PAGE);
267230557Sjimharris   sati_set_data_byte(sequence, scsi_io, 9, 0); // End of the list
268230557Sjimharris}
269230557Sjimharris
270230557Sjimharris/**
271230557Sjimharris * @brief This method builds the SCSI data associated with a request for
272230557Sjimharris *        the unit serial number vital product data (VPD) page.
273230557Sjimharris *
274230557Sjimharris * @param[in]  sequence This parameter specifies the translator sequence
275230557Sjimharris *             object to be utilized during data translation.
276230557Sjimharris * @param[in]  ata_input_data This parameter specifies ata data received from
277230557Sjimharris *             the remote device.
278230557Sjimharris * @param[out] scsi_io This parameter specifies the user IO request for
279230557Sjimharris *             which to construct the unit serial number data.
280230557Sjimharris *
281230557Sjimharris * @return none
282230557Sjimharris */
283230557Sjimharrisvoid sati_inquiry_serial_number_translate_data(
284230557Sjimharris   SATI_TRANSLATOR_SEQUENCE_T * sequence,
285230557Sjimharris   void                       * ata_input_data,
286230557Sjimharris   void                       * scsi_io
287230557Sjimharris)
288230557Sjimharris{
289230557Sjimharris   // Peripheral qualifier (0x0, currently connected)
290230557Sjimharris   // Peripheral device type (0x0 direct-access block device)
291230557Sjimharris   sati_set_data_byte(sequence, scsi_io, 0, 0x00);
292230557Sjimharris
293230557Sjimharris   sati_set_data_byte(sequence, scsi_io, 1, SCSI_INQUIRY_UNIT_SERIAL_NUM_PAGE);
294230557Sjimharris   sati_set_data_byte(sequence, scsi_io, 2, 0x00);  // Reserved
295230557Sjimharris   sati_set_data_byte(sequence, scsi_io, 3, ATA_IDENTIFY_SERIAL_NUMBER_LEN);
296230557Sjimharris
297230557Sjimharris   sati_ata_identify_device_copy_data(
298230557Sjimharris      sequence,
299230557Sjimharris      scsi_io,
300230557Sjimharris      4,
301230557Sjimharris      ata_input_data,
302230557Sjimharris      ATA_IDENTIFY_DEVICE_GET_OFFSET(serial_number),
303230557Sjimharris      ATA_IDENTIFY_SERIAL_NUMBER_LEN,
304230557Sjimharris      TRUE
305230557Sjimharris   );
306230557Sjimharris}
307230557Sjimharris
308230557Sjimharris/**
309230557Sjimharris* @brief This method builds the SCSI data associated with a request for
310230557Sjimharris*        the Block Device Characteristics vital product data (VPD) page.
311230557Sjimharris*
312230557Sjimharris* @param[in]  sequence This parameter specifies the translator sequence
313230557Sjimharris*             object to be utilized during data translation.
314230557Sjimharris* @param[in]  ata_input_data This parameter specifies ata data received from
315230557Sjimharris*             the remote device.
316230557Sjimharris* @param[out] scsi_io This parameter specifies the user IO request for
317230557Sjimharris*             which to construct the unit serial number data.
318230557Sjimharris*
319230557Sjimharris* @return none
320230557Sjimharris*/
321230557Sjimharrisvoid sati_inquiry_block_device_translate_data(
322230557Sjimharris   SATI_TRANSLATOR_SEQUENCE_T * sequence,
323230557Sjimharris   void                       * ata_input_data,
324230557Sjimharris   void                       * scsi_io
325230557Sjimharris)
326230557Sjimharris{
327230557Sjimharris   ATA_IDENTIFY_DEVICE_DATA_T * identify = (ATA_IDENTIFY_DEVICE_DATA_T*)
328230557Sjimharris      ata_input_data;
329230557Sjimharris
330230557Sjimharris   U32 offset;
331230557Sjimharris
332230557Sjimharris   // Peripheral qualifier (0x0, currently connected)
333230557Sjimharris   // Peripheral device type (0x0 direct-access block device)
334230557Sjimharris   sati_set_data_byte(sequence, scsi_io, 0, 0x00);
335230557Sjimharris
336230557Sjimharris   sati_set_data_byte(sequence, scsi_io, 1, SCSI_INQUIRY_BLOCK_DEVICE_PAGE);
337230557Sjimharris
338230557Sjimharris   //PAGE LENGTH 0x003C
339230557Sjimharris   sati_set_data_byte(sequence, scsi_io, 2, 0x00);
340230557Sjimharris   sati_set_data_byte(sequence, scsi_io, 3, SCSI_INQUIRY_BLOCK_DEVICE_LENGTH);
341230557Sjimharris
342230557Sjimharris   sati_ata_identify_device_copy_data(
343230557Sjimharris      sequence,
344230557Sjimharris      scsi_io,
345230557Sjimharris      4,
346230557Sjimharris      ata_input_data,
347230557Sjimharris      ATA_IDENTIFY_DEVICE_GET_OFFSET(nominal_media_rotation_rate),
348230557Sjimharris      2,
349230557Sjimharris      FALSE
350230557Sjimharris    );
351230557Sjimharris
352230557Sjimharris    sati_set_data_byte(sequence, scsi_io, 6, 0x00);
353230557Sjimharris
354230557Sjimharris    sati_set_data_byte(
355230557Sjimharris       sequence,
356230557Sjimharris       scsi_io,
357230557Sjimharris       7,
358230557Sjimharris       (identify->device_nominal_form_factor & 0x0F) // only need bits 0-3
359230557Sjimharris    );
360230557Sjimharris
361230557Sjimharris    //bytes 8-63 are reserved
362235043Sjimharris    for(offset = 8; offset < 64; offset++)
363230557Sjimharris    {
364230557Sjimharris       sati_set_data_byte(sequence, scsi_io, offset, 0x00);
365230557Sjimharris    }
366230557Sjimharris}
367230557Sjimharris
368230557Sjimharris/**
369230557Sjimharris * @brief This method builds the SCSI data associated with a request for
370230557Sjimharris *        the device identification vital product data (VPD) page.
371230557Sjimharris *
372230557Sjimharris * @param[in]  sequence This parameter specifies the translator sequence
373230557Sjimharris *             object to be utilized during data translation.
374230557Sjimharris * @param[in]  ata_input_data This parameter specifies ata data received from
375230557Sjimharris *             the remote device.
376230557Sjimharris * @param[out] scsi_io This parameter specifies the user IO request for
377230557Sjimharris *             which to construct the device ID page.
378230557Sjimharris *
379230557Sjimharris * @return none
380230557Sjimharris */
381230557Sjimharrisvoid sati_inquiry_device_id_translate_data(
382230557Sjimharris   SATI_TRANSLATOR_SEQUENCE_T * sequence,
383230557Sjimharris   void                       * ata_input_data,
384230557Sjimharris   void                       * scsi_io
385230557Sjimharris)
386230557Sjimharris{
387230557Sjimharris   ATA_IDENTIFY_DEVICE_DATA_T * identify    = (ATA_IDENTIFY_DEVICE_DATA_T*)
388230557Sjimharris                                              ata_input_data;
389230557Sjimharris   U16                     byte_offset = 4;
390230557Sjimharris   U16                     page_length;
391230557Sjimharris
392230557Sjimharris   // Peripheral qualifier (0x0, currently connected)
393230557Sjimharris   // Peripheral device type (0x0 direct-access block device)
394230557Sjimharris   sati_set_data_byte(sequence, scsi_io, 0, 0x00);
395230557Sjimharris
396230557Sjimharris   sati_set_data_byte(sequence, scsi_io, 1, SCSI_INQUIRY_DEVICE_ID_PAGE);
397230557Sjimharris
398230557Sjimharris   /**
399230557Sjimharris    * If World Wide Names are supported by this target, then build an
400230557Sjimharris    * identification descriptor using the WWN.
401230557Sjimharris    */
402230557Sjimharris
403230557Sjimharris   if (identify->command_set_supported_extention
404230557Sjimharris       & ATA_IDENTIFY_COMMAND_SET_WWN_SUPPORT_ENABLE)
405230557Sjimharris   {
406230557Sjimharris
407230557Sjimharris      sati_set_data_byte(sequence,
408230557Sjimharris         scsi_io, 4, SCSI_FC_PROTOCOL_IDENTIFIER | SCSI_BINARY_CODE_SET
409230557Sjimharris      );
410230557Sjimharris
411230557Sjimharris
412230557Sjimharris      sati_set_data_byte(sequence,
413230557Sjimharris         scsi_io, 5, SCSI_LUN_ASSOCIATION | SCSI_NAA_IDENTIFIER_TYPE
414230557Sjimharris      );
415230557Sjimharris
416230557Sjimharris      sati_set_data_byte(sequence, scsi_io, 6, 0);
417230557Sjimharris      sati_set_data_byte(sequence, scsi_io, 7, 0x08); // WWN are 8 bytes long
418230557Sjimharris
419230557Sjimharris      // Copy data from the identify device world wide name field into the
420230557Sjimharris      // buffer.
421230557Sjimharris      sati_ata_identify_device_copy_data(
422230557Sjimharris         sequence,
423230557Sjimharris         scsi_io,
424230557Sjimharris         8,
425230557Sjimharris         ata_input_data,
426230557Sjimharris         ATA_IDENTIFY_DEVICE_GET_OFFSET(world_wide_name),
427230557Sjimharris         ATA_IDENTIFY_WWN_LEN,
428230557Sjimharris         FALSE
429230557Sjimharris      );
430230557Sjimharris
431230557Sjimharris      byte_offset = 16;
432230557Sjimharris   }
433230557Sjimharris
434230557Sjimharris   /**
435230557Sjimharris    * Build a identification descriptor using the model number & serial number.
436230557Sjimharris    */
437230557Sjimharris
438230557Sjimharris   sati_set_data_byte(sequence,
439230557Sjimharris      scsi_io, byte_offset, SCSI_FC_PROTOCOL_IDENTIFIER | SCSI_ASCII_CODE_SET
440230557Sjimharris   );
441230557Sjimharris   byte_offset++;
442230557Sjimharris   sati_set_data_byte(sequence,
443230557Sjimharris      scsi_io, byte_offset, SCSI_LUN_ASSOCIATION | SCSI_T10_IDENTIFIER_TYPE
444230557Sjimharris   );
445230557Sjimharris   byte_offset++;
446230557Sjimharris   sati_set_data_byte(sequence, scsi_io, byte_offset, 0);
447230557Sjimharris   byte_offset++;
448230557Sjimharris
449230557Sjimharris   // Identifier length (8 bytes for "ATA     " + 40 bytes from ATA IDENTIFY
450230557Sjimharris   // model number field + 20 bytes from ATA IDENTIFY serial number field.
451230557Sjimharris   sati_set_data_byte(
452230557Sjimharris      sequence,
453230557Sjimharris      scsi_io,
454230557Sjimharris      byte_offset,
455230557Sjimharris      8 + (ATA_IDENTIFY_SERIAL_NUMBER_LEN) + (ATA_IDENTIFY_MODEL_NUMBER_LEN)
456230557Sjimharris   );
457230557Sjimharris   byte_offset++;
458230557Sjimharris
459230557Sjimharris   // Per SAT, write "ATA     ".
460230557Sjimharris   sati_set_data_byte(sequence, scsi_io, byte_offset, 0x41);
461230557Sjimharris   byte_offset++;
462230557Sjimharris   sati_set_data_byte(sequence, scsi_io, byte_offset, 0x54);
463230557Sjimharris   byte_offset++;
464230557Sjimharris   sati_set_data_byte(sequence, scsi_io, byte_offset, 0x41);
465230557Sjimharris   byte_offset++;
466230557Sjimharris   sati_set_data_byte(sequence, scsi_io, byte_offset, 0x20);
467230557Sjimharris   byte_offset++;
468230557Sjimharris   sati_set_data_byte(sequence, scsi_io, byte_offset, 0x20);
469230557Sjimharris   byte_offset++;
470230557Sjimharris   sati_set_data_byte(sequence, scsi_io, byte_offset, 0x20);
471230557Sjimharris   byte_offset++;
472230557Sjimharris   sati_set_data_byte(sequence, scsi_io, byte_offset, 0x20);
473230557Sjimharris   byte_offset++;
474230557Sjimharris   sati_set_data_byte(sequence, scsi_io, byte_offset, 0x20);
475230557Sjimharris   byte_offset++;
476230557Sjimharris
477230557Sjimharris   // Copy data from the identify device model number field into the
478230557Sjimharris   // buffer and update the byte_offset.
479230557Sjimharris   sati_ata_identify_device_copy_data(
480230557Sjimharris      sequence,
481230557Sjimharris      scsi_io,
482230557Sjimharris      byte_offset,
483230557Sjimharris      ata_input_data,
484230557Sjimharris      ATA_IDENTIFY_DEVICE_GET_OFFSET(model_number),
485230557Sjimharris      ATA_IDENTIFY_MODEL_NUMBER_LEN,
486230557Sjimharris      TRUE
487230557Sjimharris   );
488230557Sjimharris
489230557Sjimharris   byte_offset += ATA_IDENTIFY_MODEL_NUMBER_LEN;
490230557Sjimharris
491230557Sjimharris   // Copy data from the identify device serial number field into the
492230557Sjimharris   // buffer and update the byte_offset.
493230557Sjimharris   sati_ata_identify_device_copy_data(
494230557Sjimharris      sequence,
495230557Sjimharris      scsi_io,
496230557Sjimharris      byte_offset,
497230557Sjimharris      ata_input_data,
498230557Sjimharris      ATA_IDENTIFY_DEVICE_GET_OFFSET(serial_number),
499230557Sjimharris      ATA_IDENTIFY_SERIAL_NUMBER_LEN,
500230557Sjimharris      TRUE
501230557Sjimharris   );
502230557Sjimharris
503230557Sjimharris   byte_offset += ATA_IDENTIFY_SERIAL_NUMBER_LEN;
504230557Sjimharris
505230557Sjimharris   /**
506230557Sjimharris    * If the target is contained in a SAS Domain, then build a target port
507230557Sjimharris    * ID descriptor using the SAS address.
508230557Sjimharris    */
509230557Sjimharris
510230557Sjimharris#if     defined(SATI_TRANSPORT_SUPPORTS_SAS)       \
511230557Sjimharris     && defined(DISABLE_MSFT_SCSI_COMPLIANCE_SUPPORT)
512230557Sjimharris   {
513230557Sjimharris      SCI_SAS_ADDRESS_T sas_address;
514230557Sjimharris
515230557Sjimharris      sati_set_data_byte(
516230557Sjimharris         sequence,
517230557Sjimharris         scsi_io,
518230557Sjimharris         byte_offset,
519230557Sjimharris         SCSI_SAS_PROTOCOL_IDENTIFIER | SCSI_BINARY_CODE_SET
520230557Sjimharris      );
521230557Sjimharris      byte_offset++;
522230557Sjimharris
523230557Sjimharris      sati_set_data_byte(
524230557Sjimharris         sequence,
525230557Sjimharris         scsi_io,
526230557Sjimharris         byte_offset,
527230557Sjimharris         SCSI_PIV_ENABLE | SCSI_TARGET_PORT_ASSOCIATION |
528230557Sjimharris         SCSI_NAA_IDENTIFIER_TYPE
529230557Sjimharris      );
530230557Sjimharris
531230557Sjimharris      byte_offset++;
532230557Sjimharris      sati_set_data_byte(sequence, scsi_io, byte_offset, 0);
533230557Sjimharris      byte_offset++;
534230557Sjimharris      sati_set_data_byte(sequence, scsi_io, byte_offset, 8); // SAS Addr=8 bytes
535230557Sjimharris      byte_offset++;
536230557Sjimharris
537230557Sjimharris      sati_cb_device_get_sas_address(scsi_io, &sas_address);
538230557Sjimharris
539230557Sjimharris      // Store the SAS address in the target port descriptor.
540230557Sjimharris      sati_set_data_dword(sequence, scsi_io, byte_offset, sas_address.high);
541230557Sjimharris      byte_offset += 4;
542230557Sjimharris      sati_set_data_dword(sequence, scsi_io, byte_offset, sas_address.low);
543230557Sjimharris      byte_offset += 4;
544230557Sjimharris   }
545230557Sjimharris#endif // SATI_TRANSPORT_SUPPORTS_SAS && DISABLE_MSFT_SCSI_COMPLIANCE_SUPPORT
546230557Sjimharris
547230557Sjimharris   /**
548230557Sjimharris    * Set the Page length field.  The page length is n-3, where n is the
549230557Sjimharris    * last offset in the page (considered page length - 4).
550230557Sjimharris    */
551230557Sjimharris
552230557Sjimharris   page_length = byte_offset - 4;
553230557Sjimharris   sati_set_data_byte(sequence, scsi_io, 2, (U8)((page_length & 0xFF00) >> 8));
554230557Sjimharris   sati_set_data_byte(sequence, scsi_io, 3, (U8)(page_length & 0x00FF));
555230557Sjimharris}
556230557Sjimharris
557230557Sjimharris/**
558230557Sjimharris* @brief This method builds the SCSI data associated with a request for
559230557Sjimharris*        the  ATA information vital product data (VPD) page.
560230557Sjimharris*
561230557Sjimharris* @param[in]  sequence This parameter specifies the translator sequence
562230557Sjimharris*             object to be utilized during data translation.
563230557Sjimharris* @param[in]  ata_input_data This parameter specifies ata data received from
564230557Sjimharris*             a identify device command processed by the remote device.
565230557Sjimharris* @param[out] scsi_io This parameter specifies the user IO request for
566230557Sjimharris*             which to construct the ATA information page.
567230557Sjimharris*
568230557Sjimharris* @return none
569230557Sjimharris*/
570230557SjimharrisSATI_STATUS sati_inquiry_ata_information_translate_data(
571230557Sjimharris   SATI_TRANSLATOR_SEQUENCE_T * sequence,
572230557Sjimharris   void                       * ata_input_data,
573230557Sjimharris   void                       * scsi_io
574230557Sjimharris)
575230557Sjimharris{
576230557Sjimharris   sati_set_data_byte(sequence, scsi_io, 0, 0x00);
577230557Sjimharris   sati_set_data_byte(sequence, scsi_io, 1, SCSI_INQUIRY_ATA_INFORMATION_PAGE);
578230557Sjimharris   sati_set_data_byte(sequence, scsi_io, 2, 0x02);
579230557Sjimharris   sati_set_data_byte(sequence, scsi_io, 3, 0x38);
580230557Sjimharris
581230557Sjimharris   //Reserved SAT2r07
582230557Sjimharris   sati_set_data_byte(sequence, scsi_io, 4, 0x00);
583230557Sjimharris   sati_set_data_byte(sequence, scsi_io, 5, 0x00);
584230557Sjimharris   sati_set_data_byte(sequence, scsi_io, 6, 0x00);
585230557Sjimharris   sati_set_data_byte(sequence, scsi_io, 7, 0x00);
586230557Sjimharris
587230557Sjimharris   // The Vender identification field is set to "ATA     "
588230557Sjimharris   sati_set_data_byte(sequence, scsi_io, 8, 0x41);
589230557Sjimharris   sati_set_data_byte(sequence, scsi_io, 9, 0x54);
590230557Sjimharris   sati_set_data_byte(sequence, scsi_io, 10, 0x41);
591230557Sjimharris   sati_set_data_byte(sequence, scsi_io, 11, 0x20);
592230557Sjimharris   sati_set_data_byte(sequence, scsi_io, 12, 0x20);
593230557Sjimharris   sati_set_data_byte(sequence, scsi_io, 13, 0x20);
594230557Sjimharris   sati_set_data_byte(sequence, scsi_io, 14, 0x20);
595230557Sjimharris   sati_set_data_byte(sequence, scsi_io, 15, 0x20);
596230557Sjimharris
597230557Sjimharris   //SAT Product identification
598230557Sjimharris   sati_ata_identify_device_copy_data(
599230557Sjimharris      sequence,
600230557Sjimharris      scsi_io,
601230557Sjimharris      16,
602230557Sjimharris      ata_input_data,
603230557Sjimharris      ATA_IDENTIFY_DEVICE_GET_OFFSET(model_number),
604230557Sjimharris      16,
605230557Sjimharris      TRUE
606230557Sjimharris   );
607230557Sjimharris
608230557Sjimharris   //SAT Product Revision level bytes 32-35
609230557Sjimharris   sati_inquiry_construct_product_revision(
610230557Sjimharris      sequence,
611230557Sjimharris      ata_input_data,
612230557Sjimharris      scsi_io
613230557Sjimharris   );
614230557Sjimharris
615230557Sjimharris   //skipping ATA device signature for now
616230557Sjimharris
617230557Sjimharris   //Command code
618230557Sjimharris   sati_set_data_byte(sequence, scsi_io, 56, 0xEC);
619230557Sjimharris
620230557Sjimharris   //Reserved SAT2r07
621230557Sjimharris   sati_set_data_byte(sequence, scsi_io, 57, 0x00);
622230557Sjimharris   sati_set_data_byte(sequence, scsi_io, 58, 0x00);
623230557Sjimharris   sati_set_data_byte(sequence, scsi_io, 59, 0x00);
624230557Sjimharris
625230557Sjimharris   //copy all ATA identify device data
626230557Sjimharris   sati_ata_identify_device_copy_data(
627230557Sjimharris      sequence,
628230557Sjimharris      scsi_io,
629230557Sjimharris      60,
630230557Sjimharris      ata_input_data,
631230557Sjimharris      0,
632230557Sjimharris      sizeof(ATA_IDENTIFY_DEVICE_DATA_T),
633230557Sjimharris      FALSE
634230557Sjimharris   );
635230557Sjimharris
636230557Sjimharris   //Need to send ATA Execute Device Diagnostic command still
637230557Sjimharris   sequence->state = SATI_SEQUENCE_STATE_INCOMPLETE;
638230557Sjimharris
639230557Sjimharris   return SATI_SEQUENCE_INCOMPLETE;
640230557Sjimharris}
641230557Sjimharris
642230557Sjimharris/**
643230557Sjimharris * @brief This method will translate the inquiry SCSI command into
644230557Sjimharris *        an ATA IDENTIFY DEVICE command.  It will handle several different
645230557Sjimharris *        VPD pages and the standard inquiry page.
646230557Sjimharris *        For more information on the parameters passed to this method,
647230557Sjimharris *        please reference sati_translate_command().
648230557Sjimharris *
649230557Sjimharris * @return Indicate if the command translation succeeded.
650230557Sjimharris * @retval SCI_SUCCESS This is returned if the command translation was
651230557Sjimharris *         successful.
652230557Sjimharris * @retval SATI_FAILURE_CHECK_RESPONSE_DATA This value is returned if
653230557Sjimharris *         the page isn't supported, or the page code
654230557Sjimharris *         field is not zero when the EVPD bit is 0.
655230557Sjimharris */
656230557SjimharrisSATI_STATUS sati_inquiry_translate_command(
657230557Sjimharris   SATI_TRANSLATOR_SEQUENCE_T * sequence,
658230557Sjimharris   void                       * scsi_io,
659230557Sjimharris   void                       * ata_io
660230557Sjimharris)
661230557Sjimharris{
662230557Sjimharris   U8 * cdb = sati_cb_get_cdb_address(scsi_io);
663230557Sjimharris
664230557Sjimharris   /**
665230557Sjimharris    * SPC dictates:
666230557Sjimharris    * - that the page code field must be 0, if VPD enable is 0.
667230557Sjimharris    */
668230557Sjimharris   if (  ((sati_get_cdb_byte(cdb, 1) & SCSI_INQUIRY_EVPD_ENABLE) == 0)
669230557Sjimharris      && (sati_get_cdb_byte(cdb, 2) != 0) )
670230557Sjimharris   {
671230557Sjimharris      sati_scsi_sense_data_construct(
672230557Sjimharris         sequence,
673230557Sjimharris         scsi_io,
674230557Sjimharris         SCSI_STATUS_CHECK_CONDITION,
675230557Sjimharris         SCSI_SENSE_ILLEGAL_REQUEST,
676230557Sjimharris         SCSI_ASC_INVALID_FIELD_IN_CDB,
677230557Sjimharris         SCSI_ASCQ_INVALID_FIELD_IN_CDB
678230557Sjimharris      );
679230557Sjimharris      return SATI_FAILURE_CHECK_RESPONSE_DATA;
680230557Sjimharris   }
681230557Sjimharris
682230557Sjimharris   // Set the data length based on the allocation length field in the CDB.
683230557Sjimharris   sequence->allocation_length = (sati_get_cdb_byte(cdb, 3) << 8) |
684230557Sjimharris                                 (sati_get_cdb_byte(cdb, 4));
685230557Sjimharris
686230557Sjimharris   // Check to see if there was a request for the vital product data or just
687230557Sjimharris   // the standard inquiry.
688230557Sjimharris   if (sati_get_cdb_byte(cdb, 1) & SCSI_INQUIRY_EVPD_ENABLE)
689230557Sjimharris   {
690230557Sjimharris      // Parse the page code to determine which translator to invoke.
691230557Sjimharris      switch (sati_get_cdb_byte(cdb, 2))
692230557Sjimharris      {
693230557Sjimharris         case SCSI_INQUIRY_SUPPORTED_PAGES_PAGE:
694230557Sjimharris            sequence->type  = SATI_SEQUENCE_INQUIRY_SUPPORTED_PAGES;
695230557Sjimharris            sati_inquiry_supported_pages_translate_data(sequence, scsi_io);
696230557Sjimharris            return SATI_COMPLETE;
697230557Sjimharris         break;
698230557Sjimharris
699230557Sjimharris         case SCSI_INQUIRY_UNIT_SERIAL_NUM_PAGE:
700230557Sjimharris            sequence->type = SATI_SEQUENCE_INQUIRY_SERIAL_NUMBER;
701230557Sjimharris         break;
702230557Sjimharris
703230557Sjimharris         case SCSI_INQUIRY_DEVICE_ID_PAGE:
704230557Sjimharris            sequence->type = SATI_SEQUENCE_INQUIRY_DEVICE_ID;
705230557Sjimharris         break;
706230557Sjimharris
707230557Sjimharris         case SCSI_INQUIRY_ATA_INFORMATION_PAGE:
708230557Sjimharris
709230557Sjimharris            if(sequence->state == SATI_SEQUENCE_STATE_INCOMPLETE)
710230557Sjimharris            {
711230557Sjimharris               sati_ata_execute_device_diagnostic_construct(
712230557Sjimharris                  ata_io,
713230557Sjimharris                  sequence
714230557Sjimharris               );
715230557Sjimharris               sequence->type = SATI_SEQUENCE_INQUIRY_EXECUTE_DEVICE_DIAG;
716230557Sjimharris            }
717230557Sjimharris            else
718230557Sjimharris            {
719230557Sjimharris               sequence->type = SATI_SEQUENCE_INQUIRY_ATA_INFORMATION;
720230557Sjimharris            }
721230557Sjimharris         break;
722230557Sjimharris
723230557Sjimharris         case SCSI_INQUIRY_BLOCK_DEVICE_PAGE:
724230557Sjimharris            sequence->type = SATI_SEQUENCE_INQUIRY_BLOCK_DEVICE;
725230557Sjimharris         break;
726230557Sjimharris
727230557Sjimharris         default:
728230557Sjimharris            sati_scsi_sense_data_construct(
729230557Sjimharris               sequence,
730230557Sjimharris               scsi_io,
731230557Sjimharris               SCSI_STATUS_CHECK_CONDITION,
732230557Sjimharris               SCSI_SENSE_ILLEGAL_REQUEST,
733230557Sjimharris               SCSI_ASC_INVALID_FIELD_IN_CDB,
734230557Sjimharris               SCSI_ASCQ_INVALID_FIELD_IN_CDB
735230557Sjimharris            );
736230557Sjimharris            return SATI_FAILURE_CHECK_RESPONSE_DATA;
737230557Sjimharris         break;
738230557Sjimharris      }
739230557Sjimharris   }
740230557Sjimharris   else
741230557Sjimharris   {
742230557Sjimharris      sequence->type = SATI_SEQUENCE_INQUIRY_STANDARD;
743230557Sjimharris   }
744230557Sjimharris
745230557Sjimharris   sati_ata_identify_device_construct(ata_io, sequence);
746230557Sjimharris
747230557Sjimharris   return SATI_SUCCESS;
748230557Sjimharris}
749230557Sjimharris
750230557Sjimharris/**
751230557Sjimharris* @brief This method finishes the construction of the SCSI data associated
752230557Sjimharris         with a request for the  ATA information vital product data (VPD) page.
753230557Sjimharris         The ATA device signature is written into the data response from the
754230557Sjimharris         task fle registers after issuing a Execute Device Diagnostic command.
755230557Sjimharris*
756230557Sjimharris* @param[in]  sequence This parameter specifies the translator sequence
757230557Sjimharris*             object to be utilized during data translation.
758230557Sjimharris* @param[out] scsi_io This parameter specifies the user IO request for
759230557Sjimharris*             which to construct the ATA information page.
760230557Sjimharris* @param[in]  ata_io This parameter specifies the ATA payload
761230557Sjimharris*             buffer location and size to be translated.
762230557Sjimharris*
763230557Sjimharris* @return none
764230557Sjimharris*/
765230557Sjimharrisvoid sati_inquiry_ata_information_finish_translation(
766230557Sjimharris   SATI_TRANSLATOR_SEQUENCE_T * sequence,
767230557Sjimharris   void                       * scsi_io,
768230557Sjimharris   void                       * ata_io
769230557Sjimharris)
770230557Sjimharris{
771230557Sjimharris   U8 * register_fis = sati_cb_get_d2h_register_fis_address(ata_io);
772230557Sjimharris   U32 offset;
773230557Sjimharris
774230557Sjimharris   //SATA transport
775230557Sjimharris   sati_set_data_byte(sequence, scsi_io, 36, 0x34);
776230557Sjimharris   sati_set_data_byte(sequence, scsi_io, 37, 0x00);
777230557Sjimharris   sati_set_data_byte(sequence, scsi_io, 38, (U8) sati_get_ata_status(register_fis));
778230557Sjimharris   sati_set_data_byte(sequence, scsi_io, 39, (U8) sati_get_ata_error(register_fis));
779230557Sjimharris   sati_set_data_byte(sequence, scsi_io, 40, sati_get_ata_lba_low(register_fis));
780230557Sjimharris   sati_set_data_byte(sequence, scsi_io, 41, sati_get_ata_lba_mid(register_fis));
781230557Sjimharris   sati_set_data_byte(sequence, scsi_io, 42, sati_get_ata_lba_high(register_fis));
782230557Sjimharris   sati_set_data_byte(sequence, scsi_io, 43, sati_get_ata_device(register_fis));
783230557Sjimharris   sati_set_data_byte(sequence, scsi_io, 44, sati_get_ata_lba_low_ext(register_fis));
784230557Sjimharris   sati_set_data_byte(sequence, scsi_io, 45, sati_get_ata_lba_mid_ext(register_fis));
785230557Sjimharris   sati_set_data_byte(sequence, scsi_io, 46, sati_get_ata_lba_high_ext(register_fis));
786230557Sjimharris   sati_set_data_byte(sequence, scsi_io, 47, 0x00);
787230557Sjimharris   sati_set_data_byte(sequence, scsi_io, 48, sati_get_ata_sector_count(register_fis));
788230557Sjimharris   sati_set_data_byte(sequence, scsi_io, 49, sati_get_ata_sector_count_exp(register_fis));
789230557Sjimharris
790230557Sjimharris   for(offset = 50; offset < 56; offset++)
791230557Sjimharris   {
792230557Sjimharris      sati_set_data_byte(sequence, scsi_io, offset, 0x00);
793230557Sjimharris   }
794230557Sjimharris
795230557Sjimharris   sequence->state = SATI_SEQUENCE_STATE_FINAL;
796230557Sjimharris}
797230557Sjimharris
798230557Sjimharris#endif // !defined(DISABLE_SATI_INQUIRY)
799230557Sjimharris
800