1230557Sjimharris/*- 2230557Sjimharris * This file is provided under a dual BSD/GPLv2 license. When using or 3230557Sjimharris * redistributing this file, you may do so under either license. 4230557Sjimharris * 5230557Sjimharris * GPL LICENSE SUMMARY 6230557Sjimharris * 7230557Sjimharris * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. 8230557Sjimharris * 9230557Sjimharris * This program is free software; you can redistribute it and/or modify 10230557Sjimharris * it under the terms of version 2 of the GNU General Public License as 11230557Sjimharris * published by the Free Software Foundation. 12230557Sjimharris * 13230557Sjimharris * This program is distributed in the hope that it will be useful, but 14230557Sjimharris * WITHOUT ANY WARRANTY; without even the implied warranty of 15230557Sjimharris * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16230557Sjimharris * General Public License for more details. 17230557Sjimharris * 18230557Sjimharris * You should have received a copy of the GNU General Public License 19230557Sjimharris * along with this program; if not, write to the Free Software 20230557Sjimharris * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. 21230557Sjimharris * The full GNU General Public License is included in this distribution 22230557Sjimharris * in the file called LICENSE.GPL. 23230557Sjimharris * 24230557Sjimharris * BSD LICENSE 25230557Sjimharris * 26230557Sjimharris * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. 27230557Sjimharris * All rights reserved. 28230557Sjimharris * 29230557Sjimharris * Redistribution and use in source and binary forms, with or without 30230557Sjimharris * modification, are permitted provided that the following conditions 31230557Sjimharris * are met: 32230557Sjimharris * 33230557Sjimharris * * Redistributions of source code must retain the above copyright 34230557Sjimharris * notice, this list of conditions and the following disclaimer. 35230557Sjimharris * * Redistributions in binary form must reproduce the above copyright 36230557Sjimharris * notice, this list of conditions and the following disclaimer in 37230557Sjimharris * the documentation and/or other materials provided with the 38230557Sjimharris * distribution. 39230557Sjimharris * 40230557Sjimharris * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 41230557Sjimharris * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 42230557Sjimharris * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 43230557Sjimharris * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 44230557Sjimharris * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 45230557Sjimharris * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 46230557Sjimharris * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 47230557Sjimharris * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 48230557Sjimharris * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 49230557Sjimharris * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 50230557Sjimharris * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 51230557Sjimharris */ 52230557Sjimharris 53230557Sjimharris#include <sys/cdefs.h> 54230557Sjimharris__FBSDID("$FreeBSD$"); 55230557Sjimharris 56230557Sjimharris/** 57230557Sjimharris * @file 58230557Sjimharris * @brief This file contains the method implementations required to 59230557Sjimharris * translate the SCSI start stop unit command. 60230557Sjimharris */ 61230557Sjimharris 62230557Sjimharris#if !defined(DISABLE_SATI_START_STOP_UNIT) 63230557Sjimharris 64230557Sjimharris#include <dev/isci/scil/sati_start_stop_unit.h> 65230557Sjimharris#include <dev/isci/scil/sati_util.h> 66230557Sjimharris#include <dev/isci/scil/sati_callbacks.h> 67230557Sjimharris#include <dev/isci/scil/intel_ata.h> 68230557Sjimharris#include <dev/isci/scil/intel_scsi.h> 69230557Sjimharris 70230557Sjimharris/** 71230557Sjimharris * @brief This method will translate the start stop unit SCSI command into 72230557Sjimharris * various ATA commands depends on the value in POWER CONTIDTION, LOEJ 73230557Sjimharris * and START fields. 74230557Sjimharris * For more information on the parameters passed to this method, 75230557Sjimharris * please reference sati_translate_command(). 76230557Sjimharris * 77230557Sjimharris * @return Indicate if the command translation succeeded. 78230557Sjimharris * @retval SCI_SUCCESS This is returned if the command translation was 79230557Sjimharris * successful. 80230557Sjimharris * @retval SATI_FAILURE_CHECK_RESPONSE_DATA Please refer to spec. 81230557Sjimharris * 82230557Sjimharris */ 83230557SjimharrisSATI_STATUS sati_start_stop_unit_translate_command( 84230557Sjimharris SATI_TRANSLATOR_SEQUENCE_T * sequence, 85230557Sjimharris void * scsi_io, 86230557Sjimharris void * ata_io 87230557Sjimharris) 88230557Sjimharris{ 89230557Sjimharris U8 * cdb = sati_cb_get_cdb_address(scsi_io); 90230557Sjimharris 91230557Sjimharris switch ( SATI_START_STOP_UNIT_POWER_CONDITION(cdb) ) 92230557Sjimharris { 93230557Sjimharris case SCSI_START_STOP_UNIT_POWER_CONDITION_START_VALID: 94230557Sjimharris if ( SATI_START_STOP_UNIT_START_BIT(cdb) == 0 95230557Sjimharris && SATI_START_STOP_UNIT_LOEJ_BIT(cdb) == 0 ) 96230557Sjimharris { 97230557Sjimharris if ( SATI_START_STOP_UNIT_NO_FLUSH_BIT(cdb) == 1 ) 98230557Sjimharris { 99230557Sjimharris //directly send ATA STANDBY_IMMEDIATE 100230557Sjimharris sati_ata_standby_immediate_construct(ata_io, sequence); 101230557Sjimharris sequence->command_specific_data.translated_command = ATA_STANDBY_IMMED; 102230557Sjimharris } 103230557Sjimharris else 104230557Sjimharris { 105230557Sjimharris if ( sequence->state != SATI_SEQUENCE_STATE_INCOMPLETE ) 106230557Sjimharris { 107230557Sjimharris //First, send ATA flush command. 108230557Sjimharris sati_ata_flush_cache_construct(ata_io, sequence); 109230557Sjimharris sequence->command_specific_data.translated_command = ATA_FLUSH_CACHE; 110230557Sjimharris 111230557Sjimharris //remember there is next step. 112230557Sjimharris sequence->state = SATI_SEQUENCE_STATE_INCOMPLETE; 113230557Sjimharris } 114230557Sjimharris else 115230557Sjimharris { 116230557Sjimharris //the first step, flush cache command, has completed. 117230557Sjimharris //Send standby immediate now. 118230557Sjimharris sati_ata_standby_immediate_construct(ata_io, sequence); 119230557Sjimharris sequence->command_specific_data.translated_command = ATA_STANDBY_IMMED; 120230557Sjimharris 121230557Sjimharris } 122230557Sjimharris } 123230557Sjimharris } 124230557Sjimharris else if ( SATI_START_STOP_UNIT_START_BIT(cdb) == 0 125230557Sjimharris && SATI_START_STOP_UNIT_LOEJ_BIT(cdb) == 1 ) 126230557Sjimharris { 127230557Sjimharris //need to know whether the device supports removable medial feature set. 128230557Sjimharris if (sequence->device->capabilities & SATI_DEVICE_CAP_REMOVABLE_MEDIA) 129230557Sjimharris { 130230557Sjimharris //send ATA MEDIA EJECT command. 131230557Sjimharris sati_ata_media_eject_construct(ata_io, sequence); 132230557Sjimharris sequence->command_specific_data.translated_command = ATA_MEDIA_EJECT; 133230557Sjimharris } 134230557Sjimharris else 135230557Sjimharris { 136230557Sjimharris sati_scsi_sense_data_construct( 137230557Sjimharris sequence, 138230557Sjimharris scsi_io, 139230557Sjimharris SCSI_STATUS_CHECK_CONDITION, 140230557Sjimharris SCSI_SENSE_ILLEGAL_REQUEST, 141230557Sjimharris SCSI_ASC_INVALID_FIELD_IN_CDB, 142230557Sjimharris SCSI_ASCQ_INVALID_FIELD_IN_CDB 143230557Sjimharris ); 144230557Sjimharris return SATI_FAILURE_CHECK_RESPONSE_DATA; 145230557Sjimharris } 146230557Sjimharris } 147230557Sjimharris else if ( SATI_START_STOP_UNIT_START_BIT(cdb) == 1 148230557Sjimharris && SATI_START_STOP_UNIT_LOEJ_BIT(cdb) == 0 ) 149230557Sjimharris { 150230557Sjimharris //send an ATA verify command 151230557Sjimharris sati_ata_read_verify_sectors_construct(ata_io, sequence); 152230557Sjimharris sequence->command_specific_data.translated_command = ATA_READ_VERIFY_SECTORS; 153230557Sjimharris } 154230557Sjimharris else if ( SATI_START_STOP_UNIT_START_BIT(cdb) == 1 155230557Sjimharris && SATI_START_STOP_UNIT_LOEJ_BIT(cdb) == 1 ) 156230557Sjimharris { 157230557Sjimharris sati_scsi_sense_data_construct( 158230557Sjimharris sequence, 159230557Sjimharris scsi_io, 160230557Sjimharris SCSI_STATUS_CHECK_CONDITION, 161230557Sjimharris SCSI_SENSE_ILLEGAL_REQUEST, 162230557Sjimharris SCSI_ASC_INVALID_FIELD_IN_CDB, 163230557Sjimharris SCSI_ASCQ_INVALID_FIELD_IN_CDB 164230557Sjimharris ); 165230557Sjimharris return SATI_FAILURE_CHECK_RESPONSE_DATA; 166230557Sjimharris } 167230557Sjimharris 168230557Sjimharris break; 169230557Sjimharris //Power Condition Field is set to 0x01(Device to transition to Active state) 170230557Sjimharris case SCSI_START_STOP_UNIT_POWER_CONDITION_ACTIVE: 171230557Sjimharris 172230557Sjimharris if( sequence->state != SATI_SEQUENCE_STATE_INCOMPLETE ) 173230557Sjimharris { 174230557Sjimharris sati_ata_idle_construct(ata_io, sequence); 175230557Sjimharris sequence->state = SATI_SEQUENCE_STATE_INCOMPLETE; 176230557Sjimharris sequence->command_specific_data.translated_command = ATA_IDLE; 177230557Sjimharris } 178230557Sjimharris else 179230557Sjimharris { 180230557Sjimharris sati_ata_read_verify_sectors_construct(ata_io, sequence); 181230557Sjimharris sequence->command_specific_data.translated_command = ATA_READ_VERIFY_SECTORS; 182230557Sjimharris } 183230557Sjimharris break; 184230557Sjimharris 185230557Sjimharris //Power Condition Field is set to 0x02(Device to transition to Idle state) 186230557Sjimharris case SCSI_START_STOP_UNIT_POWER_CONDITION_IDLE: 187230557Sjimharris 188230557Sjimharris if( SATI_START_STOP_UNIT_NO_FLUSH_BIT(cdb) == 0 && 189230557Sjimharris sequence->state != SATI_SEQUENCE_STATE_INCOMPLETE ) 190230557Sjimharris { 191230557Sjimharris sati_ata_flush_cache_construct(ata_io, sequence); 192230557Sjimharris sequence->command_specific_data.translated_command = ATA_FLUSH_CACHE; 193230557Sjimharris sequence->state = SATI_SEQUENCE_STATE_INCOMPLETE; 194230557Sjimharris } 195230557Sjimharris else 196230557Sjimharris { 197230557Sjimharris if( SATI_START_STOP_UNIT_POWER_CONDITION_MODIFIER(cdb) == 0 ) 198230557Sjimharris { 199230557Sjimharris sati_ata_idle_immediate_construct(ata_io, sequence); 200230557Sjimharris } 201230557Sjimharris else 202230557Sjimharris { 203230557Sjimharris sati_ata_idle_immediate_unload_construct(ata_io, sequence); 204230557Sjimharris } 205230557Sjimharris sequence->command_specific_data.translated_command = ATA_IDLE_IMMED; 206230557Sjimharris } 207230557Sjimharris break; 208230557Sjimharris 209230557Sjimharris //Power Condition Field is set to 0x03(Device to transition to Standby state) 210230557Sjimharris case SCSI_START_STOP_UNIT_POWER_CONDITION_STANDBY: 211230557Sjimharris if( SATI_START_STOP_UNIT_NO_FLUSH_BIT(cdb) == 0 && 212230557Sjimharris sequence->state != SATI_SEQUENCE_STATE_INCOMPLETE ) 213230557Sjimharris { 214230557Sjimharris sati_ata_flush_cache_construct(ata_io, sequence); 215230557Sjimharris sequence->command_specific_data.translated_command = ATA_FLUSH_CACHE; 216230557Sjimharris sequence->state = SATI_SEQUENCE_STATE_INCOMPLETE; 217230557Sjimharris } 218230557Sjimharris else 219230557Sjimharris { 220230557Sjimharris sati_ata_standby_immediate_construct(ata_io, sequence); 221230557Sjimharris sequence->command_specific_data.translated_command = ATA_STANDBY_IMMED; 222230557Sjimharris } 223230557Sjimharris break; 224230557Sjimharris 225230557Sjimharris //Power Condition Field is set to 0xB(force Standby state) 226230557Sjimharris case SCSI_START_STOP_UNIT_POWER_CONDITION_FORCE_S_CONTROL: 227230557Sjimharris 228230557Sjimharris if( SATI_START_STOP_UNIT_NO_FLUSH_BIT(cdb) == 0 && 229230557Sjimharris sequence->state != SATI_SEQUENCE_STATE_INCOMPLETE ) 230230557Sjimharris { 231230557Sjimharris sati_ata_flush_cache_construct(ata_io, sequence); 232230557Sjimharris sequence->command_specific_data.translated_command = ATA_FLUSH_CACHE; 233230557Sjimharris sequence->state = SATI_SEQUENCE_STATE_INCOMPLETE; 234230557Sjimharris } 235230557Sjimharris else 236230557Sjimharris { 237230557Sjimharris sati_ata_standby_construct(ata_io, sequence, 0); 238230557Sjimharris sequence->command_specific_data.translated_command = ATA_STANDBY; 239230557Sjimharris } 240230557Sjimharris break; 241230557Sjimharris 242230557Sjimharris case SCSI_START_STOP_UNIT_POWER_CONDITION_LU_CONTROL: 243230557Sjimharris default: //TBD. 244230557Sjimharris sati_scsi_sense_data_construct( 245230557Sjimharris sequence, 246230557Sjimharris scsi_io, 247230557Sjimharris SCSI_STATUS_CHECK_CONDITION, 248230557Sjimharris SCSI_SENSE_ILLEGAL_REQUEST, 249230557Sjimharris SCSI_ASC_INVALID_FIELD_IN_CDB, 250230557Sjimharris SCSI_ASCQ_INVALID_FIELD_IN_CDB 251230557Sjimharris ); 252230557Sjimharris return SATI_FAILURE_CHECK_RESPONSE_DATA; 253230557Sjimharris break; 254230557Sjimharris } 255230557Sjimharris 256230557Sjimharris if ( SATI_START_STOP_UNIT_IMMED_BIT(cdb) == 1 ) 257230557Sjimharris { 258230557Sjimharris //@todo: return good status now. 259230557Sjimharris ; 260230557Sjimharris } 261230557Sjimharris sequence->type = SATI_SEQUENCE_START_STOP_UNIT; 262230557Sjimharris return SATI_SUCCESS; 263230557Sjimharris} 264230557Sjimharris 265230557Sjimharris 266230557Sjimharris/** 267230557Sjimharris * @brief This method will translate the ATA command register FIS 268230557Sjimharris * response into an appropriate SCSI response for START STOP UNIT. 269230557Sjimharris * For more information on the parameters passed to this method, 270230557Sjimharris * please reference sati_translate_response(). 271230557Sjimharris * 272230557Sjimharris * @return Indicate if the response translation succeeded. 273230557Sjimharris * @retval SCI_SUCCESS This is returned if the data translation was 274230557Sjimharris * successful. 275230557Sjimharris */ 276230557SjimharrisSATI_STATUS sati_start_stop_unit_translate_response( 277230557Sjimharris SATI_TRANSLATOR_SEQUENCE_T * sequence, 278230557Sjimharris void * scsi_io, 279230557Sjimharris void * ata_io 280230557Sjimharris) 281230557Sjimharris{ 282230557Sjimharris U8 * register_fis = sati_cb_get_d2h_register_fis_address(ata_io); 283230557Sjimharris U8 * cdb = sati_cb_get_cdb_address(scsi_io); 284230557Sjimharris 285230557Sjimharris if (sati_get_ata_status(register_fis) & ATA_STATUS_REG_ERROR_BIT) 286230557Sjimharris { 287230557Sjimharris switch ( sequence->command_specific_data.translated_command ) 288230557Sjimharris { 289230557Sjimharris case ATA_FLUSH_CACHE: 290230557Sjimharris case ATA_STANDBY_IMMED: 291230557Sjimharris case ATA_IDLE_IMMED: 292230557Sjimharris case ATA_IDLE: 293230557Sjimharris case ATA_STANDBY: 294230557Sjimharris //Note: There is lack of reference in spec of the error handling for 295230557Sjimharris //READ_VERIFY command. 296230557Sjimharris case ATA_READ_VERIFY_SECTORS: 297230557Sjimharris sati_scsi_sense_data_construct( 298230557Sjimharris sequence, 299230557Sjimharris scsi_io, 300230557Sjimharris SCSI_STATUS_CHECK_CONDITION, 301230557Sjimharris SCSI_SENSE_ABORTED_COMMAND, 302230557Sjimharris SCSI_ASC_COMMAND_SEQUENCE_ERROR, 303230557Sjimharris SCSI_ASCQ_NO_ADDITIONAL_SENSE 304230557Sjimharris ); 305230557Sjimharris break; 306230557Sjimharris 307230557Sjimharris case ATA_MEDIA_EJECT: 308230557Sjimharris sati_scsi_sense_data_construct( 309230557Sjimharris sequence, 310230557Sjimharris scsi_io, 311230557Sjimharris SCSI_STATUS_CHECK_CONDITION, 312230557Sjimharris SCSI_SENSE_ABORTED_COMMAND, 313230557Sjimharris SCSI_ASC_MEDIA_LOAD_OR_EJECT_FAILED, 314230557Sjimharris SCSI_ASCQ_NO_ADDITIONAL_SENSE 315230557Sjimharris ); 316230557Sjimharris break; 317230557Sjimharris 318230557Sjimharris default: 319230557Sjimharris sati_scsi_sense_data_construct( 320230557Sjimharris sequence, 321230557Sjimharris scsi_io, 322230557Sjimharris SCSI_STATUS_CHECK_CONDITION, 323230557Sjimharris SCSI_SENSE_ILLEGAL_REQUEST, 324230557Sjimharris SCSI_ASC_INVALID_FIELD_IN_CDB, 325230557Sjimharris SCSI_ASCQ_INVALID_FIELD_IN_CDB 326230557Sjimharris ); 327230557Sjimharris break; 328230557Sjimharris } 329230557Sjimharris sequence->state = SATI_SEQUENCE_STATE_FINAL; 330230557Sjimharris return SATI_FAILURE_CHECK_RESPONSE_DATA; 331230557Sjimharris } 332230557Sjimharris else 333230557Sjimharris { 334230557Sjimharris switch ( sequence->command_specific_data.translated_command ) 335230557Sjimharris { 336230557Sjimharris case ATA_READ_VERIFY_SECTORS: 337230557Sjimharris 338230557Sjimharris sati_scsi_sense_data_construct( 339230557Sjimharris sequence, 340230557Sjimharris scsi_io, 341230557Sjimharris SCSI_STATUS_GOOD, 342230557Sjimharris SCSI_SENSE_NO_SENSE, 343230557Sjimharris SCSI_ASC_NO_ADDITIONAL_SENSE, 344230557Sjimharris SCSI_ASCQ_NO_ADDITIONAL_SENSE 345230557Sjimharris ); 346230557Sjimharris //device state is now operational(active) 347230557Sjimharris sequence->device->state = SATI_DEVICE_STATE_OPERATIONAL; 348230557Sjimharris sequence->state = SATI_SEQUENCE_STATE_FINAL; 349230557Sjimharris break; 350230557Sjimharris 351230557Sjimharris case ATA_IDLE_IMMED: 352230557Sjimharris 353230557Sjimharris sati_scsi_sense_data_construct( 354230557Sjimharris sequence, 355230557Sjimharris scsi_io, 356230557Sjimharris SCSI_STATUS_GOOD, 357230557Sjimharris SCSI_SENSE_NO_SENSE, 358230557Sjimharris SCSI_ASC_NO_ADDITIONAL_SENSE, 359230557Sjimharris SCSI_ASCQ_NO_ADDITIONAL_SENSE 360230557Sjimharris ); 361230557Sjimharris sequence->device->state = SATI_DEVICE_STATE_IDLE; 362230557Sjimharris sequence->state = SATI_SEQUENCE_STATE_FINAL; 363230557Sjimharris break; 364230557Sjimharris 365230557Sjimharris //These three commands will be issued when the power condition is 0x00 or 0x03 366230557Sjimharris case ATA_MEDIA_EJECT: 367230557Sjimharris case ATA_STANDBY: 368230557Sjimharris case ATA_STANDBY_IMMED: 369230557Sjimharris 370230557Sjimharris sati_scsi_sense_data_construct( 371230557Sjimharris sequence, 372230557Sjimharris scsi_io, 373230557Sjimharris SCSI_STATUS_GOOD, 374230557Sjimharris SCSI_SENSE_NO_SENSE, 375230557Sjimharris SCSI_ASC_NO_ADDITIONAL_SENSE, 376230557Sjimharris SCSI_ASCQ_NO_ADDITIONAL_SENSE 377230557Sjimharris ); 378230557Sjimharris 379230557Sjimharris if( SATI_START_STOP_UNIT_POWER_CONDITION(cdb) == 0 ) 380230557Sjimharris { 381230557Sjimharris sequence->device->state = SATI_DEVICE_STATE_STOPPED; 382230557Sjimharris } 383230557Sjimharris else 384230557Sjimharris { 385230557Sjimharris sequence->device->state = SATI_DEVICE_STATE_STANDBY; 386230557Sjimharris } 387230557Sjimharris sequence->state = SATI_SEQUENCE_STATE_FINAL; 388230557Sjimharris break; 389230557Sjimharris 390230557Sjimharris default: 391230557Sjimharris //FLUSH Cache command does not require any success handling 392230557Sjimharris break; 393230557Sjimharris } 394230557Sjimharris 395230557Sjimharris if (sequence->state == SATI_SEQUENCE_STATE_INCOMPLETE) 396230557Sjimharris { 397230557Sjimharris return SATI_SEQUENCE_INCOMPLETE; 398230557Sjimharris } 399230557Sjimharris } 400230557Sjimharris return SATI_COMPLETE; 401230557Sjimharris} 402230557Sjimharris 403230557Sjimharris#endif // !defined(DISABLE_SATI_START_STOP_UNIT) 404230557Sjimharris 405