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*/
107static
108BOOL 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 */
167static
168void 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 */
252static
253SATI_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
305SATI_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 */
383SATI_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 */
476SATI_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