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