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 start stop unit command.
60 */
61
62#if !defined(DISABLE_SATI_START_STOP_UNIT)
63
64#include <dev/isci/scil/sati_start_stop_unit.h>
65#include <dev/isci/scil/sati_util.h>
66#include <dev/isci/scil/sati_callbacks.h>
67#include <dev/isci/scil/intel_ata.h>
68#include <dev/isci/scil/intel_scsi.h>
69
70/**
71 * @brief This method will translate the start stop unit SCSI command into
72 *        various ATA commands depends on the value in POWER CONTIDTION, LOEJ
73 *        and START fields.
74 *        For more information on the parameters passed to this method,
75 *        please reference sati_translate_command().
76 *
77 * @return Indicate if the command translation succeeded.
78 * @retval SCI_SUCCESS This is returned if the command translation was
79 *         successful.
80 * @retval SATI_FAILURE_CHECK_RESPONSE_DATA Please refer to spec.
81 *
82 */
83SATI_STATUS sati_start_stop_unit_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
91   switch ( SATI_START_STOP_UNIT_POWER_CONDITION(cdb) )
92   {
93      case SCSI_START_STOP_UNIT_POWER_CONDITION_START_VALID:
94         if ( SATI_START_STOP_UNIT_START_BIT(cdb) == 0
95             && SATI_START_STOP_UNIT_LOEJ_BIT(cdb) == 0 )
96         {
97            if ( SATI_START_STOP_UNIT_NO_FLUSH_BIT(cdb) == 1 )
98            {
99               //directly send ATA STANDBY_IMMEDIATE
100               sati_ata_standby_immediate_construct(ata_io, sequence);
101               sequence->command_specific_data.translated_command = ATA_STANDBY_IMMED;
102            }
103            else
104            {
105               if ( sequence->state != SATI_SEQUENCE_STATE_INCOMPLETE )
106               {
107                  //First, send ATA flush command.
108                  sati_ata_flush_cache_construct(ata_io, sequence);
109                  sequence->command_specific_data.translated_command = ATA_FLUSH_CACHE;
110
111                  //remember there is next step.
112                  sequence->state = SATI_SEQUENCE_STATE_INCOMPLETE;
113               }
114               else
115               {
116                  //the first step, flush cache command, has completed.
117                  //Send standby immediate now.
118                  sati_ata_standby_immediate_construct(ata_io, sequence);
119                  sequence->command_specific_data.translated_command = ATA_STANDBY_IMMED;
120
121               }
122            }
123         }
124         else if ( SATI_START_STOP_UNIT_START_BIT(cdb) == 0
125                  && SATI_START_STOP_UNIT_LOEJ_BIT(cdb) == 1 )
126         {
127            //need to know whether the device supports removable medial feature set.
128            if (sequence->device->capabilities & SATI_DEVICE_CAP_REMOVABLE_MEDIA)
129            {
130               //send ATA MEDIA EJECT command.
131               sati_ata_media_eject_construct(ata_io, sequence);
132               sequence->command_specific_data.translated_command = ATA_MEDIA_EJECT;
133            }
134            else
135            {
136               sati_scsi_sense_data_construct(
137                  sequence,
138                  scsi_io,
139                  SCSI_STATUS_CHECK_CONDITION,
140                  SCSI_SENSE_ILLEGAL_REQUEST,
141                  SCSI_ASC_INVALID_FIELD_IN_CDB,
142                  SCSI_ASCQ_INVALID_FIELD_IN_CDB
143               );
144               return SATI_FAILURE_CHECK_RESPONSE_DATA;
145            }
146         }
147         else if ( SATI_START_STOP_UNIT_START_BIT(cdb) == 1
148                  && SATI_START_STOP_UNIT_LOEJ_BIT(cdb) == 0 )
149         {
150            //send an ATA verify command
151            sati_ata_read_verify_sectors_construct(ata_io, sequence);
152            sequence->command_specific_data.translated_command = ATA_READ_VERIFY_SECTORS;
153         }
154         else if ( SATI_START_STOP_UNIT_START_BIT(cdb) == 1
155                  && SATI_START_STOP_UNIT_LOEJ_BIT(cdb) == 1 )
156         {
157            sati_scsi_sense_data_construct(
158               sequence,
159               scsi_io,
160               SCSI_STATUS_CHECK_CONDITION,
161               SCSI_SENSE_ILLEGAL_REQUEST,
162               SCSI_ASC_INVALID_FIELD_IN_CDB,
163               SCSI_ASCQ_INVALID_FIELD_IN_CDB
164            );
165            return SATI_FAILURE_CHECK_RESPONSE_DATA;
166         }
167
168         break;
169      //Power Condition Field is set to 0x01(Device to transition to Active state)
170      case SCSI_START_STOP_UNIT_POWER_CONDITION_ACTIVE:
171
172         if( sequence->state != SATI_SEQUENCE_STATE_INCOMPLETE )
173         {
174            sati_ata_idle_construct(ata_io, sequence);
175            sequence->state = SATI_SEQUENCE_STATE_INCOMPLETE;
176            sequence->command_specific_data.translated_command = ATA_IDLE;
177         }
178         else
179         {
180            sati_ata_read_verify_sectors_construct(ata_io, sequence);
181            sequence->command_specific_data.translated_command = ATA_READ_VERIFY_SECTORS;
182         }
183         break;
184
185      //Power Condition Field is set to 0x02(Device to transition to Idle state)
186      case SCSI_START_STOP_UNIT_POWER_CONDITION_IDLE:
187
188         if( SATI_START_STOP_UNIT_NO_FLUSH_BIT(cdb) == 0 &&
189             sequence->state != SATI_SEQUENCE_STATE_INCOMPLETE )
190         {
191            sati_ata_flush_cache_construct(ata_io, sequence);
192            sequence->command_specific_data.translated_command = ATA_FLUSH_CACHE;
193            sequence->state = SATI_SEQUENCE_STATE_INCOMPLETE;
194         }
195         else
196         {
197            if( SATI_START_STOP_UNIT_POWER_CONDITION_MODIFIER(cdb) == 0 )
198            {
199               sati_ata_idle_immediate_construct(ata_io, sequence);
200            }
201            else
202            {
203               sati_ata_idle_immediate_unload_construct(ata_io, sequence);
204            }
205            sequence->command_specific_data.translated_command = ATA_IDLE_IMMED;
206         }
207         break;
208
209      //Power Condition Field is set to 0x03(Device to transition to Standby state)
210      case SCSI_START_STOP_UNIT_POWER_CONDITION_STANDBY:
211         if( SATI_START_STOP_UNIT_NO_FLUSH_BIT(cdb) == 0 &&
212            sequence->state != SATI_SEQUENCE_STATE_INCOMPLETE )
213         {
214            sati_ata_flush_cache_construct(ata_io, sequence);
215            sequence->command_specific_data.translated_command = ATA_FLUSH_CACHE;
216            sequence->state = SATI_SEQUENCE_STATE_INCOMPLETE;
217         }
218         else
219         {
220            sati_ata_standby_immediate_construct(ata_io, sequence);
221            sequence->command_specific_data.translated_command = ATA_STANDBY_IMMED;
222         }
223         break;
224
225      //Power Condition Field is set to 0xB(force Standby state)
226      case SCSI_START_STOP_UNIT_POWER_CONDITION_FORCE_S_CONTROL:
227
228         if( SATI_START_STOP_UNIT_NO_FLUSH_BIT(cdb) == 0 &&
229            sequence->state != SATI_SEQUENCE_STATE_INCOMPLETE )
230         {
231            sati_ata_flush_cache_construct(ata_io, sequence);
232            sequence->command_specific_data.translated_command = ATA_FLUSH_CACHE;
233            sequence->state = SATI_SEQUENCE_STATE_INCOMPLETE;
234         }
235         else
236         {
237            sati_ata_standby_construct(ata_io, sequence, 0);
238            sequence->command_specific_data.translated_command = ATA_STANDBY;
239         }
240         break;
241
242      case SCSI_START_STOP_UNIT_POWER_CONDITION_LU_CONTROL:
243      default:  //TBD.
244         sati_scsi_sense_data_construct(
245            sequence,
246            scsi_io,
247            SCSI_STATUS_CHECK_CONDITION,
248            SCSI_SENSE_ILLEGAL_REQUEST,
249            SCSI_ASC_INVALID_FIELD_IN_CDB,
250            SCSI_ASCQ_INVALID_FIELD_IN_CDB
251         );
252         return SATI_FAILURE_CHECK_RESPONSE_DATA;
253         break;
254   }
255
256   if ( SATI_START_STOP_UNIT_IMMED_BIT(cdb) == 1 )
257   {
258      //@todo: return good status now.
259      ;
260   }
261   sequence->type = SATI_SEQUENCE_START_STOP_UNIT;
262   return SATI_SUCCESS;
263}
264
265
266/**
267 * @brief This method will translate the ATA command register FIS
268 *        response into an appropriate SCSI response for START STOP UNIT.
269 *        For more information on the parameters passed to this method,
270 *        please reference sati_translate_response().
271 *
272 * @return Indicate if the response translation succeeded.
273 * @retval SCI_SUCCESS This is returned if the data translation was
274 *         successful.
275 */
276SATI_STATUS sati_start_stop_unit_translate_response(
277   SATI_TRANSLATOR_SEQUENCE_T * sequence,
278   void                       * scsi_io,
279   void                       * ata_io
280)
281{
282   U8 * register_fis = sati_cb_get_d2h_register_fis_address(ata_io);
283   U8 * cdb = sati_cb_get_cdb_address(scsi_io);
284
285   if (sati_get_ata_status(register_fis) & ATA_STATUS_REG_ERROR_BIT)
286   {
287      switch ( sequence->command_specific_data.translated_command )
288      {
289         case ATA_FLUSH_CACHE:
290         case ATA_STANDBY_IMMED:
291         case ATA_IDLE_IMMED:
292         case ATA_IDLE:
293         case ATA_STANDBY:
294            //Note: There is lack of reference in spec of the error handling for
295            //READ_VERIFY command.
296         case ATA_READ_VERIFY_SECTORS:
297            sati_scsi_sense_data_construct(
298               sequence,
299               scsi_io,
300               SCSI_STATUS_CHECK_CONDITION,
301               SCSI_SENSE_ABORTED_COMMAND,
302               SCSI_ASC_COMMAND_SEQUENCE_ERROR,
303               SCSI_ASCQ_NO_ADDITIONAL_SENSE
304            );
305            break;
306
307         case ATA_MEDIA_EJECT:
308            sati_scsi_sense_data_construct(
309               sequence,
310               scsi_io,
311               SCSI_STATUS_CHECK_CONDITION,
312               SCSI_SENSE_ABORTED_COMMAND,
313               SCSI_ASC_MEDIA_LOAD_OR_EJECT_FAILED,
314               SCSI_ASCQ_NO_ADDITIONAL_SENSE
315            );
316            break;
317
318         default:
319            sati_scsi_sense_data_construct(
320               sequence,
321               scsi_io,
322               SCSI_STATUS_CHECK_CONDITION,
323               SCSI_SENSE_ILLEGAL_REQUEST,
324               SCSI_ASC_INVALID_FIELD_IN_CDB,
325               SCSI_ASCQ_INVALID_FIELD_IN_CDB
326            );
327            break;
328      }
329      sequence->state = SATI_SEQUENCE_STATE_FINAL;
330      return SATI_FAILURE_CHECK_RESPONSE_DATA;
331   }
332   else
333   {
334      switch ( sequence->command_specific_data.translated_command )
335      {
336         case ATA_READ_VERIFY_SECTORS:
337
338            sati_scsi_sense_data_construct(
339               sequence,
340               scsi_io,
341               SCSI_STATUS_GOOD,
342               SCSI_SENSE_NO_SENSE,
343               SCSI_ASC_NO_ADDITIONAL_SENSE,
344               SCSI_ASCQ_NO_ADDITIONAL_SENSE
345            );
346            //device state is now operational(active)
347            sequence->device->state = SATI_DEVICE_STATE_OPERATIONAL;
348            sequence->state = SATI_SEQUENCE_STATE_FINAL;
349            break;
350
351         case ATA_IDLE_IMMED:
352
353            sati_scsi_sense_data_construct(
354               sequence,
355               scsi_io,
356               SCSI_STATUS_GOOD,
357               SCSI_SENSE_NO_SENSE,
358               SCSI_ASC_NO_ADDITIONAL_SENSE,
359               SCSI_ASCQ_NO_ADDITIONAL_SENSE
360            );
361            sequence->device->state = SATI_DEVICE_STATE_IDLE;
362            sequence->state = SATI_SEQUENCE_STATE_FINAL;
363            break;
364
365         //These three commands will be issued when the power condition is 0x00 or 0x03
366         case ATA_MEDIA_EJECT:
367         case ATA_STANDBY:
368         case ATA_STANDBY_IMMED:
369
370            sati_scsi_sense_data_construct(
371               sequence,
372               scsi_io,
373               SCSI_STATUS_GOOD,
374               SCSI_SENSE_NO_SENSE,
375               SCSI_ASC_NO_ADDITIONAL_SENSE,
376               SCSI_ASCQ_NO_ADDITIONAL_SENSE
377            );
378
379            if( SATI_START_STOP_UNIT_POWER_CONDITION(cdb) == 0 )
380            {
381               sequence->device->state = SATI_DEVICE_STATE_STOPPED;
382            }
383            else
384            {
385               sequence->device->state = SATI_DEVICE_STATE_STANDBY;
386            }
387            sequence->state = SATI_SEQUENCE_STATE_FINAL;
388            break;
389
390         default:
391            //FLUSH Cache command does not require any success handling
392            break;
393      }
394
395      if (sequence->state == SATI_SEQUENCE_STATE_INCOMPLETE)
396      {
397         return SATI_SEQUENCE_INCOMPLETE;
398      }
399   }
400   return SATI_COMPLETE;
401}
402
403#endif // !defined(DISABLE_SATI_START_STOP_UNIT)
404
405