xref: /freebsd/sys/dev/isci/scil/sati_passthrough.c (revision ddd5b8e9b4d8957fce018c520657cdfa4ecffad3)
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 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_UDMA_DATA_IN           0xA
89 #define PASSTHROUGH_UDMA_DATA_OUT          0xB
90 #define PASSTHROUGH_RETURN_RESPONSE        0xF
91 
92 /**
93 * @brief This function will check the multiple_count field in the SCSI CDB
94 *        and if multiple_count is nonzero the function will check the
95 *        ATA command code. Only Read and Write Multiple commands are allowed
96 *        when multiple_count is a nonzero value.
97 *
98 * @param[in]     cdb The SCSI cdb for the ATA pass-through command
99 *
100 * @return BOOL
101   @retval TRUE - multiple_count is nonzero with a unsupported command
102   @retval FALSE - multiple_count is zero or the command supports a nonzero value
103 */
104 static
105 BOOL sati_passthrough_multiple_count_error(
106    U8 *     cdb
107 )
108 {
109    U8 ata_command_code;
110 
111    if(PASSTHROUGH_CDB_MULTIPLE_COUNT(cdb) > 0)
112    {
113       if(sati_get_cdb_byte(cdb, 0 ) == SCSI_ATA_PASSTHRU_12)
114       {
115          ata_command_code = PASSTHROUGH_CDB_COMMAND(cdb, 9);
116       }
117       else
118       {
119          ata_command_code = PASSTHROUGH_CDB_COMMAND(cdb, 14);
120       }
121 
122       switch(ata_command_code)
123       {  //MULTICOUNT bit is supported
124          case ATA_READ_MULTIPLE:
125          case ATA_READ_MULTIPLE_EXT:
126          case ATA_WRITE_MULTIPLE:
127          case ATA_WRITE_MULTIPLE_EXT:
128          case ATA_WRITE_MULTIPLE_FUA_EXT:
129             return FALSE;
130          break;
131 
132          default:
133             return TRUE;
134       }
135    }
136    //MULTICOUNT bit is not set
137    return FALSE;
138 }
139 
140 /**
141  * @brief This method will construct the sense data buffer in the user's
142  *        sense data buffer location.  Additionally, it will set the user's
143  *        SCSI status.
144  *
145  * @param[in]     sequence This parameter specifies the translation sequence
146  *                for which to construct the sense data.
147  * @param[in]     register_fis This parameter specifies the fis from which
148  *                to get the data.
149  * @param[in,out] scsi_io This parameter specifies the user's IO request
150  *                for which to construct the sense data.
151  * @param[in]     scsi_status This parameter specifies the SCSI status
152  *                value for the user's IO request.
153  * @param[in]     sense_key This parameter specifies the sense key to
154  *                be set for the user's IO request.
155  * @param[in]     additional_sense_code This parameter specifies the
156  *                additional sense code (ASC) key to be set for the user's
157  *                IO request.
158  * @param[in]     additional_sense_code_qualifier This parameter specifies
159  *                the additional sense code qualifier (ASCQ) key to be set
160  *                for the user's IO request.
161  *
162  * @return none
163  */
164 static
165 void sati_passthrough_construct_sense(
166    SATI_TRANSLATOR_SEQUENCE_T * sequence,
167    U8                         * register_fis,
168    void                       * scsi_io,
169    U8                           scsi_status,
170    U8                           sense_key,
171    U8                           additional_sense_code,
172    U8                           additional_sense_code_qualifier
173 )
174 {
175    U8                    * sense_data;
176    U32                     sense_len;
177    U8                    * cdb;
178    unsigned char           sector_count_upper;
179    unsigned char           lba_upper;
180 
181 #ifdef SATI_TRANSPORT_SUPPORTS_SAS
182    SCI_SSP_RESPONSE_IU_T * rsp_iu = (SCI_SSP_RESPONSE_IU_T*)
183                                     sati_cb_get_response_iu_address(scsi_io);
184 
185    sati_scsi_common_response_iu_construct(
186       rsp_iu,
187       scsi_status,
188       SCSI_FIXED_SENSE_DATA_BASE_LENGTH,
189       SCSI_RESPONSE_DATA_PRES_SENSE_DATA
190    );
191 
192    sense_data                   = (U8*) rsp_iu->data;
193    sense_len                    = SSP_RESPONSE_IU_MAX_DATA * 4;  // dwords to bytes
194 #else
195    sense_data = sati_cb_get_sense_data_address(scsi_io);
196    sense_len  = sati_cb_get_sense_data_length(scsi_io);
197 #endif // SATI_TRANSPORT_SUPPORTS_SAS
198 
199    sati_scsi_sense_data_construct(
200       sequence,
201       scsi_io,
202       scsi_status,
203       sense_key,
204       additional_sense_code,
205       additional_sense_code_qualifier
206    );
207 
208    cdb = sati_cb_get_cdb_address(scsi_io);
209 
210    if (sati_get_ata_sector_count_ext(register_fis) != 0) {
211       sector_count_upper = 1;
212    } else {
213        sector_count_upper = 0;
214    }
215 
216    if (sati_get_ata_lba_high_ext(register_fis) != 0 ||
217        sati_get_ata_lba_mid_ext(register_fis) != 0 ||
218        sati_get_ata_lba_low_ext(register_fis) != 0) {
219       lba_upper = 1;
220    } else {
221        lba_upper = 0;
222    }
223 
224    // Information section
225    sati_set_sense_data_byte(sense_data, sense_len, 3,  (U8)sati_get_ata_error(register_fis));
226    sati_set_sense_data_byte(sense_data, sense_len, 4,  (U8)sati_get_ata_status(register_fis));
227    sati_set_sense_data_byte(sense_data, sense_len, 5,  sati_get_ata_device(register_fis));
228    sati_set_sense_data_byte(sense_data, sense_len, 6,  sati_get_ata_sector_count(register_fis));
229 
230    // Command specific section
231    sati_set_sense_data_byte(sense_data, sense_len, 8,  (PASSTHROUGH_CDB_EXTEND(cdb) << 7) | (sector_count_upper << 6) | (lba_upper << 5));
232    sati_set_sense_data_byte(sense_data, sense_len, 9,  sati_get_ata_lba_high(register_fis));
233    sati_set_sense_data_byte(sense_data, sense_len, 10, sati_get_ata_lba_mid(register_fis));
234    sati_set_sense_data_byte(sense_data, sense_len, 11, sati_get_ata_lba_low(register_fis));
235 
236    sequence->is_sense_response_set = TRUE;
237 }
238 
239 /**
240  * @brief This method will verify that the T_DIR bit matches the protocol bit.
241  *        It will additionally set the direction on the sequence.
242  *
243  * @param[in,out] sequence This parameter specifies the translation sequence
244  *                for which to construct the sense data.
245  * @param[in]     cdb The CDB containing the passthrough command
246  *
247  * @return none
248  */
249 static
250 SATI_STATUS sati_passthrough_check_direction(
251    SATI_TRANSLATOR_SEQUENCE_T * sequence,
252    U8           * cdb
253 )
254 {
255    if ((PASSTHROUGH_CDB_PROTOCOL(cdb) == PASSTHROUGH_PIO_DATA_IN) ||
256        (PASSTHROUGH_CDB_PROTOCOL(cdb) == PASSTHROUGH_UDMA_DATA_IN))
257    {
258       if (PASSTHROUGH_CDB_T_DIR(cdb) == 0x0)
259       {
260          return SATI_FAILURE;
261       }
262       else
263       {
264          sequence->data_direction = SATI_DATA_DIRECTION_IN;
265       }
266    }
267    else if ((PASSTHROUGH_CDB_PROTOCOL(cdb) == PASSTHROUGH_PIO_DATA_OUT) ||
268             (PASSTHROUGH_CDB_PROTOCOL(cdb) == PASSTHROUGH_UDMA_DATA_OUT))
269    {
270       if (PASSTHROUGH_CDB_T_DIR(cdb) == 0x1)
271       {
272          return SATI_FAILURE;
273       }
274       else
275       {
276          sequence->data_direction = SATI_DATA_DIRECTION_OUT;
277       }
278    }
279    else
280    {
281       sequence->data_direction = SATI_DATA_DIRECTION_NONE;
282    }
283 
284    return SATI_COMPLETE;
285 }
286 
287 //******************************************************************************
288 //* P U B L I C   M E T H O D S
289 //******************************************************************************
290 
291 /**
292  * @brief This method will translate the SCSI Passthrough command
293  *        into the corresponding ATA command.
294  *
295  * @return Indicate if the command translation succeeded.
296  * @retval SATI_SUCCESS This is returned if the command translation was
297  *         successful.
298  * @retval SATI_FAILURE This is returned if the command translation was
299  *         unsuccessful
300  */
301 
302 SATI_STATUS sati_passthrough_12_translate_command(
303    SATI_TRANSLATOR_SEQUENCE_T * sequence,
304    void                       * scsi_io,
305    void                       * ata_io
306 )
307 {
308    SATI_STATUS   status;
309    U8          * cdb;
310    U8          * register_fis;
311 
312    status = SATI_FAILURE;
313 
314    sequence->type = SATI_SEQUENCE_ATA_PASSTHROUGH_12;
315    sequence->state = SATI_SEQUENCE_STATE_TRANSLATE_DATA;
316 
317    cdb = sati_cb_get_cdb_address(scsi_io);
318    sequence->protocol = PASSTHROUGH_CDB_PROTOCOL (cdb);
319    register_fis = sati_cb_get_h2d_register_fis_address(ata_io);
320 
321    if (sati_passthrough_check_direction(sequence, cdb) != SATI_COMPLETE
322        || sati_passthrough_multiple_count_error(cdb)
323       )
324    {
325       // Fail due to mismatch
326       sati_scsi_sense_data_construct(
327          sequence,
328          scsi_io,
329          SCSI_STATUS_CHECK_CONDITION,
330          SCSI_SENSE_ILLEGAL_REQUEST,
331          SCSI_ASC_INVALID_FIELD_IN_CDB,
332          SCSI_ASCQ_INVALID_FIELD_IN_CDB
333       );
334       return SATI_FAILURE_CHECK_RESPONSE_DATA;
335    }
336 
337    sati_set_ata_features(register_fis, sati_get_cdb_byte(cdb, 3));
338    sati_set_ata_sector_count(register_fis, sati_get_cdb_byte(cdb, 4));
339    sati_set_ata_lba_low(register_fis, sati_get_cdb_byte(cdb, 5));
340    sati_set_ata_lba_mid(register_fis, sati_get_cdb_byte(cdb, 6));
341    sati_set_ata_lba_high(register_fis, sati_get_cdb_byte(cdb, 7));
342    sati_set_ata_device_head(register_fis, sati_get_cdb_byte(cdb, 8));
343    sati_set_ata_command(register_fis, sati_get_cdb_byte(cdb, 9));
344 
345    sequence->state = SATI_SEQUENCE_STATE_AWAIT_RESPONSE;
346 
347    return SATI_SUCCESS;
348 }
349 
350 /**
351  * @brief This method will translate the SCSI Passthrough command
352  *        into the corresponding ATA command.
353  *
354  * @return Indicate if the command translation succeeded.
355  * @retval SATI_SUCCESS This is returned if the command translation was
356  *         successful.
357  * @retval SATI_FAILURE This is returned if the command translation was
358  *         unsuccessful
359  */
360 SATI_STATUS sati_passthrough_16_translate_command(
361    SATI_TRANSLATOR_SEQUENCE_T * sequence,
362    void                       * scsi_io,
363    void                       * ata_io
364 )
365 {
366    SATI_STATUS   status;
367    U8          * cdb;
368    U8          * register_fis;
369 
370    status = SATI_FAILURE;
371 
372    sequence->type = SATI_SEQUENCE_ATA_PASSTHROUGH_16;
373    sequence->state = SATI_SEQUENCE_STATE_TRANSLATE_DATA;
374 
375    cdb = sati_cb_get_cdb_address(scsi_io);
376    sequence->protocol = PASSTHROUGH_CDB_PROTOCOL(cdb);
377    register_fis = sati_cb_get_h2d_register_fis_address(ata_io);
378 
379    if (sati_passthrough_check_direction(sequence, cdb) != SATI_COMPLETE
380        || sati_passthrough_multiple_count_error(cdb)
381       )
382    {
383       // Fail due to mismatch
384       sati_scsi_sense_data_construct(
385          sequence,
386          scsi_io,
387          SCSI_STATUS_CHECK_CONDITION,
388          SCSI_SENSE_ILLEGAL_REQUEST,
389          SCSI_ASC_INVALID_FIELD_IN_CDB,
390          SCSI_ASCQ_INVALID_FIELD_IN_CDB
391       );
392       return SATI_FAILURE_CHECK_RESPONSE_DATA;
393    }
394 
395    if (PASSTHROUGH_CDB_EXTEND(cdb) == 1)
396    {
397       sati_set_ata_features_exp(register_fis, sati_get_cdb_byte(cdb, 3));
398       sati_set_ata_sector_count_exp(register_fis, sati_get_cdb_byte(cdb, 5));
399       sati_set_ata_lba_low_exp(register_fis, sati_get_cdb_byte(cdb, 7));
400       sati_set_ata_lba_mid_exp(register_fis, sati_get_cdb_byte(cdb, 9));
401       sati_set_ata_lba_high_exp(register_fis, sati_get_cdb_byte(cdb, 11));
402    }
403    sati_set_ata_features(register_fis, sati_get_cdb_byte(cdb, 4));
404    sati_set_ata_sector_count(register_fis, sati_get_cdb_byte(cdb, 6));
405    sati_set_ata_lba_low(register_fis, sati_get_cdb_byte(cdb, 8));
406    sati_set_ata_lba_mid(register_fis, sati_get_cdb_byte(cdb, 10));
407    sati_set_ata_lba_high(register_fis, sati_get_cdb_byte(cdb, 12));
408    sati_set_ata_device_head(register_fis, sati_get_cdb_byte(cdb, 13));
409    sati_set_ata_command(register_fis, sati_get_cdb_byte(cdb, 14));
410 
411    sequence->state = SATI_SEQUENCE_STATE_AWAIT_RESPONSE;
412 
413    return SATI_SUCCESS;
414 }
415 
416 /**
417  * @brief This method will translate the ATA command
418  *        response
419  *
420  * @return Indicate if the command translation succeeded.
421  * @retval SATI_COMPLETE This is returned if the command translation was
422  *         successful.
423  * @retval SATI_FAILURE This is returned if the command translation was
424  *         unsuccessful
425  */
426 SATI_STATUS sati_passthrough_translate_response(
427    SATI_TRANSLATOR_SEQUENCE_T * sequence,
428    void                       * scsi_io,
429    void                       * ata_io
430 )
431 {
432    U8 * cdb;
433    U8 * register_fis;
434 
435    cdb = sati_cb_get_cdb_address(scsi_io);
436    register_fis = sati_cb_get_d2h_register_fis_address(ata_io);
437 
438    // Check for device errors
439    if (sati_get_ata_status(register_fis) & ATA_STATUS_REG_ERROR_BIT)
440    {
441       sati_translate_error(sequence, scsi_io, (U8)sati_get_ata_error(register_fis));
442       return SATI_FAILURE_CHECK_RESPONSE_DATA;
443    }
444 
445    // If the user set the check condition bit, fill out the sense data
446    if (PASSTHROUGH_CDB_CK_COND(cdb) ||
447        PASSTHROUGH_CDB_PROTOCOL(cdb) == PASSTHROUGH_RETURN_RESPONSE)
448    {
449       sati_passthrough_construct_sense(
450          sequence,
451          register_fis,
452          scsi_io,
453          SCSI_STATUS_CHECK_CONDITION,
454          SCSI_SENSE_RECOVERED_ERROR,
455          SCSI_ASC_NO_ADDITIONAL_SENSE,
456          SCSI_ASCQ_ATA_PASS_THROUGH_INFORMATION_AVAILABLE
457       );
458    }
459 
460    sequence->state = SATI_SEQUENCE_STATE_FINAL;
461 
462    return SATI_COMPLETE;
463 }
464 
465 #endif // !defined(DISABLE_SATI_PASSTHROUGH)
466