xref: /freebsd/sys/dev/isci/scil/sati_passthrough.c (revision c697fb7f)
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause OR GPL-2.0
3  *
4  * This file is provided under a dual BSD/GPLv2 license.  When using or
5  * redistributing this file, you may do so under either license.
6  *
7  * GPL LICENSE SUMMARY
8  *
9  * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
10  *
11  * This program is free software; you can redistribute it and/or modify
12  * it under the terms of version 2 of the GNU General Public License as
13  * published by the Free Software Foundation.
14  *
15  * This program is distributed in the hope that it will be useful, but
16  * WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18  * General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
23  * The full GNU General Public License is included in this distribution
24  * in the file called LICENSE.GPL.
25  *
26  * BSD LICENSE
27  *
28  * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
29  * All rights reserved.
30  *
31  * Redistribution and use in source and binary forms, with or without
32  * modification, are permitted provided that the following conditions
33  * are met:
34  *
35  *   * Redistributions of source code must retain the above copyright
36  *     notice, this list of conditions and the following disclaimer.
37  *   * Redistributions in binary form must reproduce the above copyright
38  *     notice, this list of conditions and the following disclaimer in
39  *     the documentation and/or other materials provided with the
40  *     distribution.
41  *
42  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
43  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
44  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
45  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
46  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
47  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
48  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
49  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
50  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
51  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
52  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
53  */
54 
55 #include <sys/cdefs.h>
56 __FBSDID("$FreeBSD$");
57 
58 /**
59  * @file
60  * @brief This file contains the method implementations required to
61  *        translate the SCSI passthru command.
62  */
63 
64 #if !defined(DISABLE_SATI_PASSTHROUGH)
65 
66 #include <dev/isci/scil/sati.h>
67 #include <dev/isci/scil/sati_passthrough.h>
68 #include <dev/isci/scil/sati_util.h>
69 #include <dev/isci/scil/sati_callbacks.h>
70 #include <dev/isci/scil/intel_ata.h>
71 
72 #define PASSTHROUGH_CDB_PROTOCOL_MASK       0x1E
73 #define PASSTHROUGH_CDB_EXTEND_MASK         0x1
74 #define PASSTHROUGH_CDB_CK_COND_MASK        0x20
75 #define PASSTHROUGH_CDB_T_DIR_MASK          0x8
76 
77 #define PASSTHROUGH_ISOLATE_BITS(cdb, index, mask, shift) (((sati_get_cdb_byte(cdb, index) & mask) >> shift))
78 
79 #define PASSTHROUGH_CDB_PROTOCOL(cdb)      PASSTHROUGH_ISOLATE_BITS(cdb, 1, PASSTHROUGH_CDB_PROTOCOL_MASK, 1)
80 #define PASSTHROUGH_CDB_EXTEND(cdb)        PASSTHROUGH_ISOLATE_BITS(cdb, 1, PASSTHROUGH_CDB_EXTEND_MASK, 0)
81 #define PASSTHROUGH_CDB_CK_COND(cdb)       PASSTHROUGH_ISOLATE_BITS(cdb, 2, PASSTHROUGH_CDB_CK_COND_MASK, 5)
82 #define PASSTHROUGH_CDB_T_DIR(cdb)         PASSTHROUGH_ISOLATE_BITS(cdb, 2, PASSTHROUGH_CDB_T_DIR_MASK, 3)
83 
84 #define PASSTHROUGH_CDB_MULTIPLE_COUNT(cdb)         (sati_get_cdb_byte(cdb, 1) >> 5)
85 #define PASSTHROUGH_CDB_COMMAND(cdb, index)         sati_get_cdb_byte(cdb, index)
86 
87 // Protocols
88 #define PASSTHROUGH_PIO_DATA_IN            0x4
89 #define PASSTHROUGH_PIO_DATA_OUT           0x5
90 #define PASSTHROUGH_DMA                    0x6
91 #define PASSTHROUGH_UDMA_DATA_IN           0xA
92 #define PASSTHROUGH_UDMA_DATA_OUT          0xB
93 #define PASSTHROUGH_RETURN_RESPONSE        0xF
94 
95 /**
96 * @brief This function will check the multiple_count field in the SCSI CDB
97 *        and if multiple_count is nonzero the function will check the
98 *        ATA command code. Only Read and Write Multiple commands are allowed
99 *        when multiple_count is a nonzero value.
100 *
101 * @param[in]     cdb The SCSI cdb for the ATA pass-through command
102 *
103 * @return BOOL
104   @retval TRUE - multiple_count is nonzero with a unsupported command
105   @retval FALSE - multiple_count is zero or the command supports a nonzero value
106 */
107 static
108 BOOL sati_passthrough_multiple_count_error(
109    U8 *     cdb
110 )
111 {
112    U8 ata_command_code;
113 
114    if(PASSTHROUGH_CDB_MULTIPLE_COUNT(cdb) > 0)
115    {
116       if(sati_get_cdb_byte(cdb, 0 ) == SCSI_ATA_PASSTHRU_12)
117       {
118          ata_command_code = PASSTHROUGH_CDB_COMMAND(cdb, 9);
119       }
120       else
121       {
122          ata_command_code = PASSTHROUGH_CDB_COMMAND(cdb, 14);
123       }
124 
125       switch(ata_command_code)
126       {  //MULTICOUNT bit is supported
127          case ATA_READ_MULTIPLE:
128          case ATA_READ_MULTIPLE_EXT:
129          case ATA_WRITE_MULTIPLE:
130          case ATA_WRITE_MULTIPLE_EXT:
131          case ATA_WRITE_MULTIPLE_FUA_EXT:
132             return FALSE;
133          break;
134 
135          default:
136             return TRUE;
137       }
138    }
139    //MULTICOUNT bit is not set
140    return FALSE;
141 }
142 
143 /**
144  * @brief This method will construct the sense data buffer in the user's
145  *        sense data buffer location.  Additionally, it will set the user's
146  *        SCSI status.
147  *
148  * @param[in]     sequence This parameter specifies the translation sequence
149  *                for which to construct the sense data.
150  * @param[in]     register_fis This parameter specifies the fis from which
151  *                to get the data.
152  * @param[in,out] scsi_io This parameter specifies the user's IO request
153  *                for which to construct the sense data.
154  * @param[in]     scsi_status This parameter specifies the SCSI status
155  *                value for the user's IO request.
156  * @param[in]     sense_key This parameter specifies the sense key to
157  *                be set for the user's IO request.
158  * @param[in]     additional_sense_code This parameter specifies the
159  *                additional sense code (ASC) key to be set for the user's
160  *                IO request.
161  * @param[in]     additional_sense_code_qualifier This parameter specifies
162  *                the additional sense code qualifier (ASCQ) key to be set
163  *                for the user's IO request.
164  *
165  * @return none
166  */
167 static
168 void sati_passthrough_construct_sense(
169    SATI_TRANSLATOR_SEQUENCE_T * sequence,
170    U8                         * register_fis,
171    void                       * scsi_io,
172    U8                           scsi_status,
173    U8                           sense_key,
174    U8                           additional_sense_code,
175    U8                           additional_sense_code_qualifier
176 )
177 {
178    U8                    * sense_data;
179    U32                     sense_len;
180    U8                    * cdb;
181    unsigned char           sector_count_upper;
182    unsigned char           lba_upper;
183 
184 #ifdef SATI_TRANSPORT_SUPPORTS_SAS
185    SCI_SSP_RESPONSE_IU_T * rsp_iu = (SCI_SSP_RESPONSE_IU_T*)
186                                     sati_cb_get_response_iu_address(scsi_io);
187 
188    sati_scsi_common_response_iu_construct(
189       rsp_iu,
190       scsi_status,
191       SCSI_FIXED_SENSE_DATA_BASE_LENGTH,
192       SCSI_RESPONSE_DATA_PRES_SENSE_DATA
193    );
194 
195    sense_data                   = (U8*) rsp_iu->data;
196    sense_len                    = SSP_RESPONSE_IU_MAX_DATA * 4;  // dwords to bytes
197 #else
198    sense_data = sati_cb_get_sense_data_address(scsi_io);
199    sense_len  = sati_cb_get_sense_data_length(scsi_io);
200 #endif // SATI_TRANSPORT_SUPPORTS_SAS
201 
202    sati_scsi_sense_data_construct(
203       sequence,
204       scsi_io,
205       scsi_status,
206       sense_key,
207       additional_sense_code,
208       additional_sense_code_qualifier
209    );
210 
211    cdb = sati_cb_get_cdb_address(scsi_io);
212 
213    if (sati_get_ata_sector_count_ext(register_fis) != 0) {
214       sector_count_upper = 1;
215    } else {
216        sector_count_upper = 0;
217    }
218 
219    if (sati_get_ata_lba_high_ext(register_fis) != 0 ||
220        sati_get_ata_lba_mid_ext(register_fis) != 0 ||
221        sati_get_ata_lba_low_ext(register_fis) != 0) {
222       lba_upper = 1;
223    } else {
224        lba_upper = 0;
225    }
226 
227    // Information section
228    sati_set_sense_data_byte(sense_data, sense_len, 3,  (U8)sati_get_ata_error(register_fis));
229    sati_set_sense_data_byte(sense_data, sense_len, 4,  (U8)sati_get_ata_status(register_fis));
230    sati_set_sense_data_byte(sense_data, sense_len, 5,  sati_get_ata_device(register_fis));
231    sati_set_sense_data_byte(sense_data, sense_len, 6,  sati_get_ata_sector_count(register_fis));
232 
233    // Command specific section
234    sati_set_sense_data_byte(sense_data, sense_len, 8,  (PASSTHROUGH_CDB_EXTEND(cdb) << 7) | (sector_count_upper << 6) | (lba_upper << 5));
235    sati_set_sense_data_byte(sense_data, sense_len, 9,  sati_get_ata_lba_low(register_fis));
236    sati_set_sense_data_byte(sense_data, sense_len, 10, sati_get_ata_lba_mid(register_fis));
237    sati_set_sense_data_byte(sense_data, sense_len, 11, sati_get_ata_lba_high(register_fis));
238 
239    sequence->is_sense_response_set = TRUE;
240 }
241 
242 /**
243  * @brief This method will verify that the T_DIR bit matches the protocol bit.
244  *        It will additionally set the direction on the sequence.
245  *
246  * @param[in,out] sequence This parameter specifies the translation sequence
247  *                for which to construct the sense data.
248  * @param[in]     cdb The CDB containing the passthrough command
249  *
250  * @return none
251  */
252 static
253 SATI_STATUS sati_passthrough_check_direction(
254    SATI_TRANSLATOR_SEQUENCE_T * sequence,
255    U8           * cdb
256 )
257 {
258    if ((sequence->protocol == PASSTHROUGH_PIO_DATA_IN) ||
259        (sequence->protocol == PASSTHROUGH_UDMA_DATA_IN))
260    {
261       if (PASSTHROUGH_CDB_T_DIR(cdb) == 0x0)
262       {
263          return SATI_FAILURE;
264       }
265       else
266       {
267          sequence->data_direction = SATI_DATA_DIRECTION_IN;
268       }
269    }
270    else if ((sequence->protocol == PASSTHROUGH_PIO_DATA_OUT) ||
271             (sequence->protocol == PASSTHROUGH_UDMA_DATA_OUT))
272    {
273       if (PASSTHROUGH_CDB_T_DIR(cdb) == 0x1)
274       {
275          return SATI_FAILURE;
276       }
277       else
278       {
279          sequence->data_direction = SATI_DATA_DIRECTION_OUT;
280       }
281    }
282    else
283    {
284       sequence->data_direction = SATI_DATA_DIRECTION_NONE;
285    }
286 
287    return SATI_COMPLETE;
288 }
289 
290 //******************************************************************************
291 //* P U B L I C   M E T H O D S
292 //******************************************************************************
293 
294 /**
295  * @brief This method will translate the SCSI Passthrough command
296  *        into the corresponding ATA command.
297  *
298  * @return Indicate if the command translation succeeded.
299  * @retval SATI_SUCCESS This is returned if the command translation was
300  *         successful.
301  * @retval SATI_FAILURE This is returned if the command translation was
302  *         unsuccessful
303  */
304 
305 SATI_STATUS sati_passthrough_12_translate_command(
306    SATI_TRANSLATOR_SEQUENCE_T * sequence,
307    void                       * scsi_io,
308    void                       * ata_io
309 )
310 {
311    SATI_STATUS   status;
312    U8          * cdb;
313    U8          * register_fis;
314 
315    status = SATI_FAILURE;
316 
317    sequence->type = SATI_SEQUENCE_ATA_PASSTHROUGH_12;
318    sequence->state = SATI_SEQUENCE_STATE_TRANSLATE_DATA;
319 
320    cdb = sati_cb_get_cdb_address(scsi_io);
321    sequence->protocol = PASSTHROUGH_CDB_PROTOCOL (cdb);
322    register_fis = sati_cb_get_h2d_register_fis_address(ata_io);
323 
324    /*
325     * CAM will send passthrough commands with protocol set to multiword
326     * DMA even though no multiword DMA mode is selected on the device.
327     * This is because some controllers (LSI) will only accept
328     * ATA_PASSTHROUGH commands with DMA mode - not UDMA_IN/OUT.
329     *
330     * Since isci does not support multiword DMA, fix this up here.
331     */
332    if (sequence->protocol == PASSTHROUGH_DMA)
333    {
334       if (PASSTHROUGH_CDB_T_DIR(cdb) == 0x1)
335       {
336          sequence->protocol = PASSTHROUGH_UDMA_DATA_IN;
337       }
338       else
339       {
340          sequence->protocol = PASSTHROUGH_UDMA_DATA_OUT;
341       }
342    }
343 
344    if (sati_passthrough_check_direction(sequence, cdb) != SATI_COMPLETE
345        || sati_passthrough_multiple_count_error(cdb)
346       )
347    {
348       // Fail due to mismatch
349       sati_scsi_sense_data_construct(
350          sequence,
351          scsi_io,
352          SCSI_STATUS_CHECK_CONDITION,
353          SCSI_SENSE_ILLEGAL_REQUEST,
354          SCSI_ASC_INVALID_FIELD_IN_CDB,
355          SCSI_ASCQ_INVALID_FIELD_IN_CDB
356       );
357       return SATI_FAILURE_CHECK_RESPONSE_DATA;
358    }
359 
360    sati_set_ata_features(register_fis, sati_get_cdb_byte(cdb, 3));
361    sati_set_ata_sector_count(register_fis, sati_get_cdb_byte(cdb, 4));
362    sati_set_ata_lba_low(register_fis, sati_get_cdb_byte(cdb, 5));
363    sati_set_ata_lba_mid(register_fis, sati_get_cdb_byte(cdb, 6));
364    sati_set_ata_lba_high(register_fis, sati_get_cdb_byte(cdb, 7));
365    sati_set_ata_device_head(register_fis, sati_get_cdb_byte(cdb, 8));
366    sati_set_ata_command(register_fis, sati_get_cdb_byte(cdb, 9));
367 
368    sequence->state = SATI_SEQUENCE_STATE_AWAIT_RESPONSE;
369 
370    return SATI_SUCCESS;
371 }
372 
373 /**
374  * @brief This method will translate the SCSI Passthrough command
375  *        into the corresponding ATA command.
376  *
377  * @return Indicate if the command translation succeeded.
378  * @retval SATI_SUCCESS This is returned if the command translation was
379  *         successful.
380  * @retval SATI_FAILURE This is returned if the command translation was
381  *         unsuccessful
382  */
383 SATI_STATUS sati_passthrough_16_translate_command(
384    SATI_TRANSLATOR_SEQUENCE_T * sequence,
385    void                       * scsi_io,
386    void                       * ata_io
387 )
388 {
389    SATI_STATUS   status;
390    U8          * cdb;
391    U8          * register_fis;
392 
393    status = SATI_FAILURE;
394 
395    sequence->type = SATI_SEQUENCE_ATA_PASSTHROUGH_16;
396    sequence->state = SATI_SEQUENCE_STATE_TRANSLATE_DATA;
397 
398    cdb = sati_cb_get_cdb_address(scsi_io);
399    sequence->protocol = PASSTHROUGH_CDB_PROTOCOL(cdb);
400    register_fis = sati_cb_get_h2d_register_fis_address(ata_io);
401 
402    /*
403     * CAM will send passthrough commands with protocol set to multiword
404     * DMA even though no multiword DMA mode is selected on the device.
405     * This is because some controllers (LSI) will only accept
406     * ATA_PASSTHROUGH commands with DMA mode - not UDMA_IN/OUT.
407     *
408     * Since isci does not support multiword DMA, fix this up here.
409     */
410    if (sequence->protocol == PASSTHROUGH_DMA)
411    {
412       if (PASSTHROUGH_CDB_T_DIR(cdb) == 0x1)
413       {
414          sequence->protocol = PASSTHROUGH_UDMA_DATA_IN;
415       }
416       else
417       {
418          sequence->protocol = PASSTHROUGH_UDMA_DATA_OUT;
419       }
420    }
421 
422    if (sati_passthrough_check_direction(sequence, cdb) != SATI_COMPLETE
423        || sati_passthrough_multiple_count_error(cdb)
424       )
425    {
426       // Fail due to mismatch
427       sati_scsi_sense_data_construct(
428          sequence,
429          scsi_io,
430          SCSI_STATUS_CHECK_CONDITION,
431          SCSI_SENSE_ILLEGAL_REQUEST,
432          SCSI_ASC_INVALID_FIELD_IN_CDB,
433          SCSI_ASCQ_INVALID_FIELD_IN_CDB
434       );
435       return SATI_FAILURE_CHECK_RESPONSE_DATA;
436    }
437 
438    if (PASSTHROUGH_CDB_EXTEND(cdb) == 1)
439    {
440       sati_set_ata_features_exp(register_fis, sati_get_cdb_byte(cdb, 3));
441       sati_set_ata_sector_count_exp(register_fis, sati_get_cdb_byte(cdb, 5));
442       sati_set_ata_lba_low_exp(register_fis, sati_get_cdb_byte(cdb, 7));
443       sati_set_ata_lba_mid_exp(register_fis, sati_get_cdb_byte(cdb, 9));
444       sati_set_ata_lba_high_exp(register_fis, sati_get_cdb_byte(cdb, 11));
445    }
446 
447    if (PASSTHROUGH_CDB_CK_COND(cdb) ||
448        PASSTHROUGH_CDB_PROTOCOL(cdb) == PASSTHROUGH_RETURN_RESPONSE)
449    {
450       sequence->is_translate_response_required = TRUE;
451    }
452 
453    sati_set_ata_features(register_fis, sati_get_cdb_byte(cdb, 4));
454    sati_set_ata_sector_count(register_fis, sati_get_cdb_byte(cdb, 6));
455    sati_set_ata_lba_low(register_fis, sati_get_cdb_byte(cdb, 8));
456    sati_set_ata_lba_mid(register_fis, sati_get_cdb_byte(cdb, 10));
457    sati_set_ata_lba_high(register_fis, sati_get_cdb_byte(cdb, 12));
458    sati_set_ata_device_head(register_fis, sati_get_cdb_byte(cdb, 13));
459    sati_set_ata_command(register_fis, sati_get_cdb_byte(cdb, 14));
460 
461    sequence->state = SATI_SEQUENCE_STATE_AWAIT_RESPONSE;
462 
463    return SATI_SUCCESS;
464 }
465 
466 /**
467  * @brief This method will translate the ATA command
468  *        response
469  *
470  * @return Indicate if the command translation succeeded.
471  * @retval SATI_COMPLETE This is returned if the command translation was
472  *         successful.
473  * @retval SATI_FAILURE This is returned if the command translation was
474  *         unsuccessful
475  */
476 SATI_STATUS sati_passthrough_translate_response(
477    SATI_TRANSLATOR_SEQUENCE_T * sequence,
478    void                       * scsi_io,
479    void                       * ata_io
480 )
481 {
482    U8 * cdb;
483    U8 * register_fis;
484 
485    cdb = sati_cb_get_cdb_address(scsi_io);
486    register_fis = sati_cb_get_d2h_register_fis_address(ata_io);
487 
488    // Check for device errors
489    if (sati_get_ata_status(register_fis) & ATA_STATUS_REG_ERROR_BIT)
490    {
491       sati_translate_error(sequence, scsi_io, (U8)sati_get_ata_error(register_fis));
492       return SATI_FAILURE_CHECK_RESPONSE_DATA;
493    }
494 
495    sequence->state = SATI_SEQUENCE_STATE_FINAL;
496 
497    // If the user set the check condition bit, fill out the sense data
498    if (PASSTHROUGH_CDB_CK_COND(cdb) ||
499        PASSTHROUGH_CDB_PROTOCOL(cdb) == PASSTHROUGH_RETURN_RESPONSE)
500    {
501       sati_passthrough_construct_sense(
502          sequence,
503          register_fis,
504          scsi_io,
505          SCSI_STATUS_CHECK_CONDITION,
506          SCSI_SENSE_RECOVERED_ERROR,
507          SCSI_ASC_NO_ADDITIONAL_SENSE,
508          SCSI_ASCQ_ATA_PASS_THROUGH_INFORMATION_AVAILABLE
509       );
510       return SATI_FAILURE_CHECK_RESPONSE_DATA;
511    }
512 
513    return SATI_COMPLETE;
514 }
515 
516 #endif // !defined(DISABLE_SATI_PASSTHROUGH)
517