xref: /freebsd/sys/dev/isci/scil/sati_mode_sense_6.c (revision fed1ca4b719c56c930f2259d80663cd34be812bb)
1 /*-
2  * This file is provided under a dual BSD/GPLv2 license.  When using or
3  * redistributing this file, you may do so under either license.
4  *
5  * GPL LICENSE SUMMARY
6  *
7  * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of version 2 of the GNU General Public License as
11  * published by the Free Software Foundation.
12  *
13  * This program is distributed in the hope that it will be useful, but
14  * WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
21  * The full GNU General Public License is included in this distribution
22  * in the file called LICENSE.GPL.
23  *
24  * BSD LICENSE
25  *
26  * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
27  * All rights reserved.
28  *
29  * Redistribution and use in source and binary forms, with or without
30  * modification, are permitted provided that the following conditions
31  * are met:
32  *
33  *   * Redistributions of source code must retain the above copyright
34  *     notice, this list of conditions and the following disclaimer.
35  *   * Redistributions in binary form must reproduce the above copyright
36  *     notice, this list of conditions and the following disclaimer in
37  *     the documentation and/or other materials provided with the
38  *     distribution.
39  *
40  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
41  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
42  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
43  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
44  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
45  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
46  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
47  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
48  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
49  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
50  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
51  */
52 
53 #include <sys/cdefs.h>
54 __FBSDID("$FreeBSD$");
55 
56 /**
57  * @file
58  * @brief This file contains the method implementations required to
59  *        translate the SCSI mode sense 6-byte commands.
60  */
61 
62 #if !defined(DISABLE_SATI_MODE_SENSE)
63 
64 #include <dev/isci/scil/sati_mode_sense.h>
65 #include <dev/isci/scil/sati_mode_sense_6.h>
66 #include <dev/isci/scil/sati_mode_pages.h>
67 #include <dev/isci/scil/sati_callbacks.h>
68 #include <dev/isci/scil/sati_util.h>
69 #include <dev/isci/scil/intel_scsi.h>
70 #include <dev/isci/scil/intel_ata.h>
71 
72 //******************************************************************************
73 //* P R I V A T E   M E T H O D S
74 //******************************************************************************
75 
76 /**
77  * @brief This method builds the mode parameter header for a 6-byte SCSI
78  *        mode sense data response.  The parameter header is 4 bytes in
79  *        size.
80  *        For more information on the parameters passed to this method,
81  *        please reference sati_translate_command().
82  *
83  * @param[in] identify This parameter specifies the ATA remote device's
84  *            received IDENTIFY DEVICE data.
85  * @param[in] mode_data_length This parameter specifies the amount of data
86  *            to be returned as part of this mode sense request.
87  *
88  * @return This method returns the number of bytes written into the
89  *         data buffer.
90  */
91 static
92 U32 sati_mode_sense_6_build_header(
93    SATI_TRANSLATOR_SEQUENCE_T * sequence,
94    void                       * scsi_io,
95    ATA_IDENTIFY_DEVICE_DATA_T * identify,
96    U8                           mode_data_length
97 )
98 {
99    U8 * cdb = sati_cb_get_cdb_address(scsi_io);
100 
101    // Fill in the length of the mode parameter data returned (do not include
102    // the size of the mode data length field in the total).
103    sati_set_data_byte(sequence, scsi_io, 0, (U8)mode_data_length-1);
104 
105    // Medium Type is 0 for SBC devices
106    sati_set_data_byte(sequence, scsi_io, 1, SCSI_MODE_HEADER_MEDIUM_TYPE_SBC);
107 
108    // Write Protect (WP), Rsvd, DPOFUA, Rsvd
109    if (sequence->device->capabilities & SATI_DEVICE_CAP_DMA_FUA_ENABLE)
110       sati_set_data_byte(sequence,scsi_io,2,SCSI_MODE_SENSE_HEADER_FUA_ENABLE);
111    else
112       sati_set_data_byte(sequence, scsi_io, 2, 0);
113 
114    // Set the block descriptor length if block descriptors are utilized.
115    if (sati_get_cdb_byte(cdb, 1) & SCSI_MODE_SENSE_DBD_ENABLE)
116       sati_set_data_byte(sequence, scsi_io, 3, 0);
117    else
118       sati_set_data_byte(
119          sequence, scsi_io, 3, SCSI_MODE_SENSE_STD_BLOCK_DESCRIPTOR_LENGTH
120       );
121 
122    return SCSI_MODE_SENSE_6_HEADER_LENGTH;
123 }
124 
125 /**
126  * @brief This method perform the data translation common to all SCSI MODE
127  *        SENSE 6 byte commands.  This includes building the mode page
128  *        header and block descriptor (if requested).
129  *        For more information on the parameters passed to this method,
130  *        please reference sati_translate_command().
131  *
132  * @param[in] identify This parameter specifies the remote device's IDENTIFY
133  *            DEVICE data to be used during translation.
134  * @param[in] transfer_length This parameter specifies the size of the
135  *            mode page (including header & block descriptor).
136  *
137  * @return This method returns the number of bytes written into the user's
138  *         mode page data buffer.
139  */
140 static
141 U32 sati_mode_sense_6_translate_data(
142    SATI_TRANSLATOR_SEQUENCE_T * sequence,
143    ATA_IDENTIFY_DEVICE_DATA_T * identify,
144    void                       * scsi_io,
145    U8                           transfer_length
146 )
147 {
148    U8  * cdb = sati_cb_get_cdb_address(scsi_io);
149    U32   offset;
150 
151    offset = sati_mode_sense_6_build_header(
152                sequence, scsi_io, identify, transfer_length
153             );
154 
155    // Determine if the caller disabled block descriptors (DBD).  If not,
156    // then generate a block descriptor.
157    if ((sati_get_cdb_byte(cdb, 1) & SCSI_MODE_SENSE_DBD_ENABLE) == 0)
158       offset += sati_mode_sense_build_std_block_descriptor(
159                    sequence, scsi_io, identify, offset
160                 );
161 
162    return offset;
163 }
164 
165 //******************************************************************************
166 //* P R O T E C T E D   M E T H O D S
167 //******************************************************************************
168 
169 /**
170  * @brief This method will translate the SCSI mode sense 6 byte command
171  *        into corresponding ATA commands.  If the command is well-formed,
172  *        then the translation will result in an ATA IDENTIFY DEVICE
173  *        command.
174  *        For more information on the parameters passed to this method,
175  *        please reference sati_translate_command().
176  *
177  * @return Indicate if the command translation succeeded.
178  * @retval SCI_SUCCESS This is returned if the command translation was
179  *         successful.
180  * @retval SATI_FAILURE_CHECK_RESPONSE_DATA This value is returned if
181  *         sense data has been created as a result of something specified
182  *         in the CDB.
183  */
184 SATI_STATUS sati_mode_sense_6_translate_command(
185    SATI_TRANSLATOR_SEQUENCE_T * sequence,
186    void                       * scsi_io,
187    void                       * ata_io
188 )
189 {
190    U8 * cdb = sati_cb_get_cdb_address(scsi_io);
191 
192    // Set the data length based on the allocation length field in the CDB.
193    sequence->allocation_length = sati_get_cdb_byte(cdb, 4);
194 
195    return sati_mode_sense_translate_command(sequence, scsi_io, ata_io, 6);
196 }
197 
198 /**
199  * @brief This method will perform data translation from the supplied ATA
200  *        input data (i.e. an ATA IDENTIFY DEVICE block) into a CACHING
201  *        mode page format.  The data will be written into the user's mode
202  *        page data buffer.  This function operates specifically for MODE
203  *        SENSE 6 commands.
204  *        For more information on the parameters passed to this method,
205  *        please reference sati_translate_data().
206  *
207  * @return none.
208  */
209 void sati_mode_sense_6_caching_translate_data(
210    SATI_TRANSLATOR_SEQUENCE_T * sequence,
211    void                       * ata_input_data,
212    void                       * scsi_io
213 )
214 {
215    ATA_IDENTIFY_DEVICE_DATA_T * identify = (ATA_IDENTIFY_DEVICE_DATA_T*)
216                                            ata_input_data;
217    U8   data_length = (U8) sati_mode_sense_calculate_page_header(scsi_io, 6)
218                            + SCSI_MODE_PAGE_08_LENGTH;
219    U32  page_offset = sati_mode_sense_6_translate_data(
220                          sequence, identify, scsi_io, data_length
221                       );
222 
223    sati_mode_sense_caching_translate_data(
224       sequence, scsi_io, identify, page_offset
225    );
226 }
227 
228 /**
229  * @brief This method will perform data translation from the supplied ATA
230  *        input data (i.e. an ATA IDENTIFY DEVICE block) into a INFORMATIONAL
231  *        EXCEPTIONS CONTROL mode page format.  The data will be written
232  *        into the user's mode page data buffer.  This function operates
233  *        specifically for MODE SENSE 6 commands.
234  *        For more information on the parameters passed to this method,
235  *        please reference sati_translate_data().
236  *
237  * @return none.
238  */
239 void sati_mode_sense_6_informational_excp_control_translate_data(
240    SATI_TRANSLATOR_SEQUENCE_T * sequence,
241    void                       * ata_input_data,
242    void                       * scsi_io
243 )
244 {
245    ATA_IDENTIFY_DEVICE_DATA_T * identify = (ATA_IDENTIFY_DEVICE_DATA_T*)
246                                            ata_input_data;
247    U8   data_length = (U8) sati_mode_sense_calculate_page_header(scsi_io, 6)
248                            + SCSI_MODE_PAGE_1C_LENGTH;
249    U32  page_offset = sati_mode_sense_6_translate_data(
250                          sequence, identify, scsi_io, data_length
251                       );
252 
253    sati_mode_sense_informational_excp_control_translate_data(
254       sequence, scsi_io, identify, page_offset
255    );
256 }
257 
258 /**
259 * @brief This method will perform data translation from the supplied ATA
260 *        input data (i.e. an ATA IDENTIFY DEVICE block) into a DISCONNECT
261 *        RECONNECT mode page format.  The data will be written
262 *        into the user's mode page data buffer.  This function operates
263 *        specifically for MODE SENSE 6 commands.
264 *        For more information on the parameters passed to this method,
265 *        please reference sati_translate_data().
266 *
267 * @return none.
268 */
269 void sati_mode_sense_6_disconnect_reconnect_translate_data(
270    SATI_TRANSLATOR_SEQUENCE_T * sequence,
271    void                       * ata_input_data,
272    void                       * scsi_io
273 )
274 {
275    ATA_IDENTIFY_DEVICE_DATA_T * identify = (ATA_IDENTIFY_DEVICE_DATA_T*)
276       ata_input_data;
277 
278    U8   data_length = (U8) sati_mode_sense_calculate_page_header(scsi_io, 6)
279       + SCSI_MODE_PAGE_02_LENGTH ;
280 
281    U32  page_offset = sati_mode_sense_6_translate_data(
282                          sequence, identify, scsi_io, data_length
283                       );
284 
285    sati_mode_sense_disconnect_reconnect_translate_data(
286       sequence, scsi_io, identify, page_offset
287    );
288 }
289 
290 /**
291 * @brief This method will perform data translation from the supplied ATA
292 *        input data (i.e. an ATA IDENTIFY DEVICE block) into a READ WRITE ERROR
293 *        mode page format.  The data will be written
294 *        into the user's mode page data buffer.  This function operates
295 *        specifically for MODE SENSE 6 commands.
296 *        For more information on the parameters passed to this method,
297 *        please reference sati_translate_data().
298 *
299 * @return none.
300 */
301 void sati_mode_sense_6_read_write_error_translate_data(
302    SATI_TRANSLATOR_SEQUENCE_T * sequence,
303    void                       * ata_input_data,
304    void                       * scsi_io
305 )
306 {
307    ATA_IDENTIFY_DEVICE_DATA_T * identify = (ATA_IDENTIFY_DEVICE_DATA_T*)
308       ata_input_data;
309 
310    U8   data_length = (U8) sati_mode_sense_calculate_page_header(scsi_io, 6)
311       + SCSI_MODE_PAGE_01_LENGTH;
312 
313    U32  page_offset = sati_mode_sense_6_translate_data(
314                          sequence, identify, scsi_io, data_length
315                       );
316 
317    sati_mode_sense_read_write_error_translate_data(
318       sequence, scsi_io, identify, page_offset
319    );
320 }
321 
322 /**
323 * @brief This method will perform data translation from the supplied ATA
324 *        input data (i.e. an ATA IDENTIFY DEVICE block) into a CONTROL
325 *        mode page format.  The data will be written
326 *        into the user's mode page data buffer.  This function operates
327 *        specifically for MODE SENSE 6 commands.
328 *        For more information on the parameters passed to this method,
329 *        please reference sati_translate_data().
330 *
331 * @return none.
332 */
333 void sati_mode_sense_6_control_translate_data(
334    SATI_TRANSLATOR_SEQUENCE_T * sequence,
335    void                       * ata_input_data,
336    void                       * scsi_io
337 )
338 {
339    ATA_IDENTIFY_DEVICE_DATA_T * identify = (ATA_IDENTIFY_DEVICE_DATA_T*)
340       ata_input_data;
341 
342    U8   data_length = (U8) sati_mode_sense_calculate_page_header(scsi_io, 6)
343       + SCSI_MODE_PAGE_0A_LENGTH;
344 
345    U32  page_offset = sati_mode_sense_6_translate_data(
346                          sequence, identify, scsi_io, data_length
347                       );
348 
349    sati_mode_sense_control_translate_data(
350       sequence, scsi_io, identify, page_offset
351    );
352 }
353 
354 /**
355 * @brief This method will perform data translation from the supplied ATA
356 *        input data (i.e. an ATA IDENTIFY DEVICE block) into a Power
357 *        Condition mode page format.  The data will be written
358 *        into the user's mode page data buffer.  This function operates
359 *        specifically for MODE SENSE 6 commands.
360 *        For more information on the parameters passed to this method,
361 *        please reference sati_translate_data().
362 *
363 * @return none.
364 */
365 void sati_mode_sense_6_power_condition_translate_data(
366    SATI_TRANSLATOR_SEQUENCE_T * sequence,
367    void                       * ata_input_data,
368    void                       * scsi_io
369 )
370 {
371    ATA_IDENTIFY_DEVICE_DATA_T * identify = (ATA_IDENTIFY_DEVICE_DATA_T*)
372       ata_input_data;
373 
374    U8 data_length;
375    U32  page_offset;
376 
377    data_length = (U8) sati_mode_sense_calculate_page_header(scsi_io, 6)
378          + SCSI_MODE_PAGE_1A_LENGTH;
379 
380    page_offset = sati_mode_sense_6_translate_data(
381          sequence, identify, scsi_io, data_length
382    );
383 
384    sati_mode_sense_power_condition_translate_data(
385       sequence, scsi_io, identify, page_offset
386    );
387 }
388 
389 
390 
391 /**
392  * @brief This method will perform data translation from the supplied ATA
393  *        input data (i.e. an ATA IDENTIFY DEVICE block) into an ALL
394  *        PAGES mode page format.  The ALL PAGES mode page is basically a
395  *        conglomeration of all mode pages and sub-pages into a single
396  *        page.  The data will be written into the user's mode page
397  *        data buffer.  This function operates specifically for MODE
398  *        SENSE 6 commands.
399  *        For more information on the parameters passed to this method,
400  *        please reference sati_translate_data().
401  *
402  * @return none.
403  */
404 void sati_mode_sense_6_all_pages_translate_data(
405    SATI_TRANSLATOR_SEQUENCE_T * sequence,
406    void                       * ata_input_data,
407    void                       * scsi_io
408 )
409 {
410    ATA_IDENTIFY_DEVICE_DATA_T * identify = (ATA_IDENTIFY_DEVICE_DATA_T*)
411                                            ata_input_data;
412    U8   data_length = (U8) sati_mode_sense_calculate_page_header(scsi_io, 6)
413                            + SCSI_MODE_PAGE_01_LENGTH
414                            + SCSI_MODE_PAGE_02_LENGTH
415                            + SCSI_MODE_PAGE_08_LENGTH
416                            + SCSI_MODE_PAGE_0A_LENGTH
417                            + SCSI_MODE_PAGE_1C_LENGTH;
418 
419    U32  page_offset = sati_mode_sense_6_translate_data(
420                          sequence, identify, scsi_io, data_length
421                       );
422 
423    sati_mode_sense_all_pages_translate_data(
424       sequence, scsi_io, identify, page_offset
425    );
426 }
427 
428 #endif // !defined(DISABLE_SATI_MODE_SENSE)
429 
430