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 Read Buffer command based on the SAT spec.
60*/
61
62#if !defined(DISABLE_SATI_READ_BUFFER)
63
64#include <dev/isci/scil/sati_read_buffer.h>
65#include <dev/isci/scil/sati_callbacks.h>
66#include <dev/isci/scil/sati_util.h>
67
68
69/**
70* @brief This method will translate the SCSI Read Buffer command
71*        into a corresponding ATA Read Buffer command.
72*        For more information on the parameters passed to this method,
73*        please reference sati_translate_command().
74*
75* @return Indicates if the command translation succeeded.
76* @retval SATI_SUCCESS indicates that the translation was supported and occurred
77*         without error.
78* @retval SATI_FAILURE_CHECK_RESPONSE_DATA This value is returned if
79*         there is a translation failure.
80* @retval SATI_COMPLETE indicates that the translation was supported, occurred without
81*         error, and no additional translation is necessary.
82*/
83SATI_STATUS sati_read_buffer_translate_command(
84   SATI_TRANSLATOR_SEQUENCE_T * sequence,
85   void                       * scsi_io,
86   void                       * ata_io
87)
88{
89   U8 * cdb = sati_cb_get_cdb_address(scsi_io);
90   SATI_STATUS status = SATI_FAILURE;
91   U32 allocation_length;
92   U32 buffer_offset;
93
94   allocation_length = ((sati_get_cdb_byte(cdb, 6) << 16) |
95                        (sati_get_cdb_byte(cdb, 7) << 8)  |
96                        (sati_get_cdb_byte(cdb, 8)));
97
98   buffer_offset = ((sati_get_cdb_byte(cdb, 3) << 16) |
99                    (sati_get_cdb_byte(cdb, 4) << 8)  |
100                    (sati_get_cdb_byte(cdb, 5)));
101
102   sequence->allocation_length = allocation_length;
103
104   switch(sati_get_cdb_byte(cdb, 1))
105   {
106      case SATI_READ_BUFFER_MODE_DATA:
107         if((allocation_length == 512) && (buffer_offset == 0) &&
108            (sati_get_cdb_byte(cdb, 2) == 0))
109         {
110            sati_ata_read_buffer_construct(ata_io, sequence);
111            sequence->type = SATI_SEQUENCE_READ_BUFFER;
112            sequence->state = SATI_SEQUENCE_STATE_AWAIT_RESPONSE;
113            status = SATI_SUCCESS;
114         }
115         else
116         {
117            sati_scsi_sense_data_construct(
118               sequence,
119               scsi_io,
120               SCSI_STATUS_CHECK_CONDITION,
121               SCSI_SENSE_ILLEGAL_REQUEST,
122               SCSI_ASC_INVALID_FIELD_IN_CDB,
123               SCSI_ASCQ_INVALID_FIELD_IN_CDB
124            );
125            sequence->state = SATI_SEQUENCE_STATE_FINAL;
126            status = SATI_FAILURE_CHECK_RESPONSE_DATA;
127         }
128      break;
129
130      case SATI_READ_BUFFER_MODE_DESCRIPTOR:
131
132         //allocation legnth must be at least four to return translated data
133         if(allocation_length < 4)
134         {
135            sati_scsi_sense_data_construct(
136               sequence,
137               scsi_io,
138               SCSI_STATUS_CHECK_CONDITION,
139               SCSI_SENSE_ILLEGAL_REQUEST,
140               SCSI_ASC_INVALID_FIELD_IN_CDB,
141               SCSI_ASCQ_INVALID_FIELD_IN_CDB
142            );
143            sequence->state = SATI_SEQUENCE_STATE_FINAL;
144            status = SATI_FAILURE_CHECK_RESPONSE_DATA;
145         }
146         else
147         {
148            //figure out if we support other buffer id's
149            sati_set_data_byte(sequence, scsi_io, 0, 0x09); //offset boundary
150            sati_set_data_byte(sequence, scsi_io, 1, 0x00);
151            sati_set_data_byte(sequence, scsi_io, 2, 0x02); //buffer capacity 0x200
152            sati_set_data_byte(sequence, scsi_io, 3, 0x00);
153            sequence->state = SATI_SEQUENCE_STATE_FINAL;
154            status = SATI_COMPLETE;
155         }
156      break;
157
158      default:
159         //Unspecified sat2v7, returning invalid cdb
160         sati_scsi_sense_data_construct(
161            sequence,
162            scsi_io,
163            SCSI_STATUS_CHECK_CONDITION,
164            SCSI_SENSE_ILLEGAL_REQUEST,
165            SCSI_ASC_INVALID_FIELD_IN_CDB,
166            SCSI_ASCQ_INVALID_FIELD_IN_CDB
167         );
168         sequence->state = SATI_SEQUENCE_STATE_FINAL;
169         status = SATI_FAILURE_CHECK_RESPONSE_DATA;
170   }
171   return status;
172}
173
174/**
175* @brief This method will complete the Read Buffer Translation by copying the
176         ATA response data into the SCSI request DATA buffer.
177*        For more information on the parameters passed to this method,
178*        please reference sati_translate_command().
179*
180* @return Indicates if the command translation succeeded.
181* @retval SATI_FAILURE_CHECK_RESPONSE_DATA This value is returned if
182*         there is a translation failure.
183* @retval SATI_COMPLETE indicates that the translation was supported, occurred without
184*         error, and no additional translation is necessary.
185*/
186SATI_STATUS sati_read_buffer_translate_response(
187   SATI_TRANSLATOR_SEQUENCE_T * sequence,
188   void                       * scsi_io,
189   void                       * ata_io
190)
191{
192   U8 * register_fis = sati_cb_get_d2h_register_fis_address(ata_io);
193   U8   ata_status = (U8) sati_get_ata_status(register_fis);
194   SATI_STATUS status = SATI_COMPLETE;
195
196   if (ata_status & ATA_STATUS_REG_ERROR_BIT)
197   {
198      sati_scsi_sense_data_construct(
199         sequence,
200         scsi_io,
201         SCSI_STATUS_CHECK_CONDITION,
202         SCSI_SENSE_ABORTED_COMMAND,
203         SCSI_ASC_NO_ADDITIONAL_SENSE,
204         SCSI_ASCQ_NO_ADDITIONAL_SENSE
205      );
206
207      status = SATI_FAILURE_CHECK_RESPONSE_DATA;
208   }
209   else
210   {
211      void * ata_data = sati_cb_get_ata_data_address(ata_io);
212
213      if(ata_data == NULL)
214      {
215         status = SATI_FAILURE;
216      }
217      else
218      {
219         //copy ATA data into SCSI data buffer
220         sati_copy_data(
221            sequence,
222            scsi_io,
223            0,
224            ata_data,
225            512
226         );
227      }
228   }
229
230   sequence->state = SATI_SEQUENCE_STATE_FINAL;
231   return status;
232}
233
234
235#endif //!defined(DISABLE_SATI_READ_BUFFER)
236