1292932Sdim/*- 2292932Sdim * This file is provided under a dual BSD/GPLv2 license. When using or 3292932Sdim * redistributing this file, you may do so under either license. 4292932Sdim* 5292932Sdim* GPL LICENSE SUMMARY 6292932Sdim* 7292932Sdim* Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. 8292932Sdim* 9292932Sdim* This program is free software; you can redistribute it and/or modify 10292932Sdim* it under the terms of version 2 of the GNU General Public License as 11292932Sdim* published by the Free Software Foundation. 12292932Sdim* 13292932Sdim* This program is distributed in the hope that it will be useful, but 14309124Sdim* WITHOUT ANY WARRANTY; without even the implied warranty of 15309124Sdim* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16309124Sdim* General Public License for more details. 17309124Sdim* 18309124Sdim* You should have received a copy of the GNU General Public License 19292932Sdim* along with this program; if not, write to the Free Software 20292932Sdim* Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. 21292932Sdim* The full GNU General Public License is included in this distribution 22292932Sdim* in the file called LICENSE.GPL. 23292932Sdim* 24292932Sdim* BSD LICENSE 25292932Sdim* 26292932Sdim* Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. 27292932Sdim* All rights reserved. 28292932Sdim* 29292932Sdim* Redistribution and use in source and binary forms, with or without 30292932Sdim* modification, are permitted provided that the following conditions 31292932Sdim* are met: 32292932Sdim* 33292932Sdim* * Redistributions of source code must retain the above copyright 34292932Sdim* notice, this list of conditions and the following disclaimer. 35292932Sdim* * Redistributions in binary form must reproduce the above copyright 36309124Sdim* notice, this list of conditions and the following disclaimer in 37309124Sdim* the documentation and/or other materials provided with the 38309124Sdim* distribution. 39309124Sdim* 40309124Sdim* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 41309124Sdim* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 42309124Sdim* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 43292932Sdim* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 44292932Sdim* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 45292932Sdim* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 46292932Sdim* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 47292932Sdim* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 48292932Sdim* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 49292932Sdim* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 50292932Sdim* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 51292932Sdim */ 52292932Sdim 53292932Sdim#include <sys/cdefs.h> 54292932Sdim__FBSDID("$FreeBSD$"); 55292932Sdim 56292932Sdim/** 57292932Sdim* @file 58292932Sdim* @brief This file contains the method implementations to translate 59292932Sdim* SCSI Write Buffer command based of the SAT2v07 spec. 60292932Sdim*/ 61292932Sdim 62292932Sdim#include <dev/isci/scil/sati_write_buffer.h> 63292932Sdim#include <dev/isci/scil/sati_callbacks.h> 64292932Sdim#include <dev/isci/scil/sati_util.h> 65292932Sdim 66292932Sdim#define WRITE_BUFFER_WRITE_DATA 0x02 67292932Sdim#define WRITE_BUFFER_DOWNLOAD_SAVE 0x05 68292932Sdim#define WRITE_BUFFER_OFFSET_DOWNLOAD_SAVE 0x07 69292932Sdim#define DOWNLOAD_MICROCODE_BLOCK_SIZE 512 70292932Sdim 71292932Sdim/** 72292932Sdim* @brief This method will translate the SCSI Write Buffer command 73292932Sdim* into a corresponding ATA Write Buffer and Download Microcode commands. 74292932Sdim* For more information on the parameters passed to this method, 75292932Sdim* please reference sati_translate_command(). 76292932Sdim* 77292932Sdim* @return Indicates if the command translation succeeded. 78292932Sdim* @retval SATI_SUCCESS indicates that the translation was supported and occurred 79292932Sdim* without error. 80309124Sdim* @retval SATI_FAILURE_CHECK_RESPONSE_DATA This value is returned if 81309124Sdim* there is a translation failure. 82309124Sdim*/ 83309124SdimSATI_STATUS sati_write_buffer_translate_command( 84292932Sdim SATI_TRANSLATOR_SEQUENCE_T * sequence, 85292932Sdim void * scsi_io, 86292932Sdim void * ata_io 87292932Sdim) 88292932Sdim{ 89292932Sdim U8 * cdb = sati_cb_get_cdb_address(scsi_io); 90292932Sdim SATI_STATUS status = SATI_FAILURE; 91292932Sdim U32 allocation_length; 92292932Sdim U32 allocation_blocks; 93292932Sdim U32 buffer_offset; 94292932Sdim 95292932Sdim allocation_length = ((sati_get_cdb_byte(cdb, 6) << 16) | 96292932Sdim (sati_get_cdb_byte(cdb, 7) << 8) | 97309124Sdim (sati_get_cdb_byte(cdb, 8))); 98292932Sdim 99309124Sdim buffer_offset = ((sati_get_cdb_byte(cdb, 3) << 16) | 100292932Sdim (sati_get_cdb_byte(cdb, 4) << 8) | 101309124Sdim (sati_get_cdb_byte(cdb, 5))); 102309124Sdim 103309124Sdim sequence->allocation_length = allocation_length; 104309124Sdim allocation_blocks = allocation_length / DOWNLOAD_MICROCODE_BLOCK_SIZE; 105309124Sdim 106292932Sdim switch(sati_get_cdb_byte(cdb, 1)) 107309124Sdim { 108292932Sdim case WRITE_BUFFER_WRITE_DATA: 109309124Sdim if((allocation_length == DOWNLOAD_MICROCODE_BLOCK_SIZE) && 110309124Sdim (buffer_offset == 0) && 111309124Sdim (sati_get_cdb_byte(cdb, 2) == 0)) 112309124Sdim { 113309124Sdim sati_ata_write_buffer_construct(ata_io, sequence); 114292932Sdim sequence->type = SATI_SEQUENCE_WRITE_BUFFER; 115292932Sdim sequence->state = SATI_SEQUENCE_STATE_AWAIT_RESPONSE; 116292932Sdim status = SATI_SUCCESS; 117292932Sdim } 118292932Sdim else 119292932Sdim { 120292932Sdim sati_scsi_sense_data_construct( 121292932Sdim sequence, 122292932Sdim scsi_io, 123292932Sdim SCSI_STATUS_CHECK_CONDITION, 124292932Sdim SCSI_SENSE_ILLEGAL_REQUEST, 125292932Sdim SCSI_ASC_INVALID_FIELD_IN_CDB, 126292932Sdim SCSI_ASCQ_INVALID_FIELD_IN_CDB 127292932Sdim ); 128292932Sdim 129292932Sdim sequence->state = SATI_SEQUENCE_STATE_FINAL; 130292932Sdim status = SATI_FAILURE_CHECK_RESPONSE_DATA; 131292932Sdim } 132292932Sdim break; 133292932Sdim 134292932Sdim case WRITE_BUFFER_DOWNLOAD_SAVE: 135292932Sdim 136292932Sdim sati_ata_download_microcode_construct( 137292932Sdim ata_io, 138292932Sdim sequence, 139292932Sdim ATA_MICROCODE_DOWNLOAD_SAVE, 140292932Sdim allocation_length, 141292932Sdim buffer_offset 142292932Sdim ); 143292932Sdim 144292932Sdim sequence->type = SATI_SEQUENCE_WRITE_BUFFER_MICROCODE; 145292932Sdim sequence->state = SATI_SEQUENCE_STATE_AWAIT_RESPONSE; 146292932Sdim status = SATI_SUCCESS; 147292932Sdim break; 148292932Sdim 149292932Sdim case WRITE_BUFFER_OFFSET_DOWNLOAD_SAVE: 150292932Sdim if(((allocation_length & 0x000001FF) == 0) && //Bits 08:00 need to be zero per SAT2v7 151292932Sdim ((buffer_offset & 0x000001FF) == 0) && 152292932Sdim (allocation_blocks <= sequence->device->max_blocks_per_microcode_command) && 153292932Sdim ((allocation_blocks >= sequence->device->min_blocks_per_microcode_command) || 154292932Sdim (allocation_length == 0))) 155292932Sdim { 156292932Sdim sati_ata_download_microcode_construct( 157292932Sdim ata_io, 158292932Sdim sequence, 159292932Sdim ATA_MICROCODE_OFFSET_DOWNLOAD, 160292932Sdim allocation_length, 161292932Sdim buffer_offset 162292932Sdim ); 163292932Sdim 164292932Sdim sequence->type = SATI_SEQUENCE_WRITE_BUFFER_MICROCODE; 165292932Sdim sequence->state = SATI_SEQUENCE_STATE_AWAIT_RESPONSE; 166292932Sdim status = SATI_SUCCESS; 167292932Sdim } 168292932Sdim else 169292932Sdim { 170292932Sdim sati_scsi_sense_data_construct( 171292932Sdim sequence, 172292932Sdim scsi_io, 173292932Sdim SCSI_STATUS_CHECK_CONDITION, 174292932Sdim SCSI_SENSE_ILLEGAL_REQUEST, 175292932Sdim SCSI_ASC_INVALID_FIELD_IN_CDB, 176292932Sdim SCSI_ASCQ_INVALID_FIELD_IN_CDB 177292932Sdim ); 178292932Sdim 179292932Sdim sequence->state = SATI_SEQUENCE_STATE_FINAL; 180292932Sdim status = SATI_FAILURE_CHECK_RESPONSE_DATA; 181292932Sdim } 182292932Sdim break; 183292932Sdim 184292932Sdim default: //unsupported Write Buffer Mode 185292932Sdim sati_scsi_sense_data_construct( 186292932Sdim sequence, 187292932Sdim scsi_io, 188292932Sdim SCSI_STATUS_CHECK_CONDITION, 189292932Sdim SCSI_SENSE_ILLEGAL_REQUEST, 190292932Sdim SCSI_ASC_INVALID_FIELD_IN_CDB, 191292932Sdim SCSI_ASCQ_INVALID_FIELD_IN_CDB 192292932Sdim ); 193292932Sdim 194292932Sdim sequence->state = SATI_SEQUENCE_STATE_FINAL; 195292932Sdim status = SATI_FAILURE_CHECK_RESPONSE_DATA; 196292932Sdim break; 197292932Sdim } 198292932Sdim return status; 199292932Sdim} 200292932Sdim 201292932Sdim/** 202292932Sdim* @brief This method will complete the Write Buffer Translation by checking 203292932Sdim* for ATA errors and then creating a unit attention condition for 204292932Sdim* changed microcode. 205292932Sdim* 206292932Sdim* @return Indicates if the command translation succeeded. 207292932Sdim* @retval SATI_FAILURE_CHECK_RESPONSE_DATA This value is returned if 208292932Sdim* there is a translation failure. 209292932Sdim* @retval SATI_COMPLETE indicates that the translation was supported, occurred without 210292932Sdim* error, and no additional translation is necessary. 211292932Sdim*/ 212292932SdimSATI_STATUS sati_write_buffer_translate_response( 213292932Sdim SATI_TRANSLATOR_SEQUENCE_T * sequence, 214292932Sdim void * scsi_io, 215292932Sdim void * ata_io 216292932Sdim) 217292932Sdim{ 218292932Sdim U8 * register_fis = sati_cb_get_d2h_register_fis_address(ata_io); 219292932Sdim U8 ata_status = (U8) sati_get_ata_status(register_fis); 220292932Sdim SATI_STATUS status = SATI_FAILURE; 221292932Sdim 222292932Sdim if (ata_status & ATA_STATUS_REG_ERROR_BIT) 223292932Sdim { 224292932Sdim sati_scsi_sense_data_construct( 225292932Sdim sequence, 226292932Sdim scsi_io, 227292932Sdim SCSI_STATUS_CHECK_CONDITION, 228292932Sdim SCSI_SENSE_ABORTED_COMMAND, 229292932Sdim SCSI_ASC_NO_ADDITIONAL_SENSE, 230292932Sdim SCSI_ASCQ_NO_ADDITIONAL_SENSE 231292932Sdim ); 232292932Sdim status = SATI_FAILURE_CHECK_RESPONSE_DATA; 233292932Sdim } 234292932Sdim else 235292932Sdim { 236292932Sdim switch(sequence->type) 237292932Sdim { 238292932Sdim case SATI_SEQUENCE_WRITE_BUFFER_MICROCODE: 239292932Sdim sati_scsi_sense_data_construct( 240292932Sdim sequence, 241292932Sdim scsi_io, 242292932Sdim SCSI_STATUS_GOOD, 243292932Sdim SCSI_SENSE_UNIT_ATTENTION, 244292932Sdim SCSI_ASC_MICROCODE_HAS_CHANGED, 245292932Sdim SCSI_ASCQ_MICROCODE_HAS_CHANGED 246292932Sdim ); 247292932Sdim status = SATI_COMPLETE; 248292932Sdim break; 249292932Sdim 250292932Sdim default: 251292932Sdim status = SATI_COMPLETE; 252292932Sdim break; 253292932Sdim } 254292932Sdim } 255292932Sdim 256292932Sdim sequence->state = SATI_SEQUENCE_STATE_FINAL; 257292932Sdim return status; 258292932Sdim} 259292932Sdim