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 implementation to translate
59 *        SCSI Write Long 10 and 16 commands based on the SAT spec.
60 */
61
62#if !defined(DISABLE_SATI_WRITE_LONG)
63
64#include <dev/isci/scil/sati_write_long.h>
65#include <dev/isci/scil/sati_device.h>
66#include <dev/isci/scil/sati_util.h>
67#include <dev/isci/scil/intel_scsi.h>
68#include <dev/isci/scil/intel_ata.h>
69#include <dev/isci/scil/intel_sat.h>
70#include <dev/isci/scil/sati_callbacks.h>
71#include <dev/isci/scil/sati_move.h>
72
73#define LOGICAL_PER_PHYSICAL_SECTOR 0xF
74
75#define WR_UNCOR_BIT          0x02
76#define WR_UNCOR_PBLOCK_BIT   0x03
77#define COR_DIS_WR_UNCORR_BIT 0x06
78
79
80/**
81 * @brief This method will translate the write long 10 & 16 SCSI commands into
82 *        ATA write uncorrectable commands. For more information on the
83 *        parameters passed to this method, please reference
84 *        sati_translate_command().
85 *
86 * @return Indicate if the command translation succeeded.
87 * @retval SCI_SUCCESS This is returned if the command translation was
88 *         successful.
89 * @retval SATI_FAILURE_CHECK_RESPONSE_DATA is returned if there was
90 *         a problem with the translation of write long.
91 *
92 */
93SATI_STATUS sati_write_long_translate_command(
94   SATI_TRANSLATOR_SEQUENCE_T * sequence,
95   void                       * scsi_io,
96   void                       * ata_io
97)
98{
99   U8 * cdb = sati_cb_get_cdb_address(scsi_io);
100   SATI_STATUS status = SATI_FAILURE;
101   U16 byte_transfer_length;
102   U8 device_head  = 0;
103
104   if((sequence->device->capabilities &
105       SATI_DEVICE_CAP_WRITE_UNCORRECTABLE_ENABLE) == 0)
106   {
107      sati_scsi_sense_data_construct(
108         sequence,
109         scsi_io,
110         SCSI_STATUS_CHECK_CONDITION,
111         SCSI_SENSE_ILLEGAL_REQUEST,
112         SCSI_ASC_INVALID_COMMAND_OPERATION_CODE,
113         SCSI_ASCQ_INVALID_COMMAND_OPERATION_CODE
114      );
115      return SATI_FAILURE_CHECK_RESPONSE_DATA;
116   }
117
118   //Write Long 10
119   if(sati_get_cdb_byte(cdb, 0) == SCSI_WRITE_LONG_10)
120   {
121      byte_transfer_length = (sati_get_cdb_byte(cdb, 7) << 8) |
122                             (sati_get_cdb_byte(cdb, 8));
123
124      sati_move_translate_32_bit_lba(sequence, scsi_io, ata_io);
125   }
126   else //Write Long 16
127   {
128      byte_transfer_length = (sati_get_cdb_byte(cdb, 12) << 8) |
129                             (sati_get_cdb_byte(cdb, 13));
130
131      status = sati_move_translate_64_bit_lba(sequence, scsi_io, ata_io);
132
133      if( status == SATI_FAILURE_CHECK_RESPONSE_DATA)
134      {
135         return status;
136      }
137   }
138
139
140   sati_move_translate_command(sequence, scsi_io, ata_io, device_head);
141
142   if( byte_transfer_length != 0 )
143   {
144      sati_scsi_sense_data_construct(
145         sequence,
146         scsi_io,
147         SCSI_STATUS_CHECK_CONDITION,
148         SCSI_SENSE_ILLEGAL_REQUEST,
149         SCSI_ASC_INVALID_FIELD_IN_CDB,
150         SCSI_ASCQ_INVALID_FIELD_IN_CDB
151      );
152      return SATI_FAILURE_CHECK_RESPONSE_DATA;
153   }
154
155   switch(SATI_WRITE_LONG_GET_COR_WR_PB_BITS(cdb))
156   {
157      case WR_UNCOR_BIT :
158
159         if( (sequence->device->capabilities &
160              SATI_DEVICE_CAP_MULTIPLE_SECTORS_PER_PHYSCIAL_SECTOR) != 0 )
161         {
162            sati_scsi_sense_data_construct(
163               sequence,
164               scsi_io,
165               SCSI_STATUS_CHECK_CONDITION,
166               SCSI_SENSE_ILLEGAL_REQUEST,
167               SCSI_ASC_INVALID_FIELD_IN_CDB,
168               SCSI_ASCQ_INVALID_FIELD_IN_CDB
169            );
170            return SATI_FAILURE_CHECK_RESPONSE_DATA;
171         }
172         else
173         {
174            sati_ata_write_uncorrectable_construct(
175               ata_io,
176               sequence,
177               ATA_WRITE_UNCORRECTABLE_PSUEDO
178            );
179            sequence->type = SATI_SEQUENCE_WRITE_LONG;
180            status = SATI_SUCCESS;
181         }
182         break;
183
184      case WR_UNCOR_PBLOCK_BIT :
185
186         sati_ata_write_uncorrectable_construct(
187            ata_io,
188            sequence,
189            ATA_WRITE_UNCORRECTABLE_PSUEDO
190         );
191         sequence->type = SATI_SEQUENCE_WRITE_LONG;
192         status = SATI_SUCCESS;
193         break;
194
195      case COR_DIS_WR_UNCORR_BIT :
196
197         sati_ata_write_uncorrectable_construct(
198            ata_io,
199            sequence,
200            ATA_WRITE_UNCORRECTABLE_FLAGGED
201         );
202         sequence->type = SATI_SEQUENCE_WRITE_LONG;
203         status = SATI_SUCCESS;
204         break;
205
206      default :
207
208         sati_scsi_sense_data_construct(
209            sequence,
210            scsi_io,
211            SCSI_STATUS_CHECK_CONDITION,
212            SCSI_SENSE_ILLEGAL_REQUEST,
213            SCSI_ASC_INVALID_FIELD_IN_CDB,
214            SCSI_ASCQ_INVALID_FIELD_IN_CDB
215         );
216         return SATI_FAILURE_CHECK_RESPONSE_DATA;
217         break;
218   }
219   return status;
220}
221
222/**
223 * @brief This method will translate the response to the SATI Write Long
224 *        translation. This response is only error checking the
225 *        ATA Write Uncorrectable command.
226 *
227 * @return SATI_STATUS Indicates if the response translation succeeded.
228 * @retval SCI_COMPLETE This is returned if the command translation was
229 *         successful.
230 * @retval SATI_FAILURE_CHECK_RESPONSE_DATA is returned if there was
231 *         a problem with the translation of write long.
232 */
233SATI_STATUS sati_write_long_translate_response(
234   SATI_TRANSLATOR_SEQUENCE_T * sequence,
235   void                       * scsi_io,
236   void                       * ata_io
237)
238{
239   U8 * register_fis = sati_cb_get_d2h_register_fis_address(ata_io);
240
241   if (sati_get_ata_status(register_fis) & ATA_STATUS_REG_ERROR_BIT)
242   {
243      sati_scsi_sense_data_construct(
244         sequence,
245         scsi_io,
246         SCSI_STATUS_CHECK_CONDITION,
247         SCSI_SENSE_ABORTED_COMMAND,
248         SCSI_ASC_COMMAND_SEQUENCE_ERROR,
249         SCSI_ASCQ_NO_ADDITIONAL_SENSE
250      );
251      return SATI_FAILURE_CHECK_RESPONSE_DATA;
252   }
253   else
254   {
255      return SATI_COMPLETE;
256   }
257}
258
259#endif // !defined(DISABLE_SATI_WRITE_LONG)
260