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