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 to translate 61 * SCSI Write Buffer command based of the SAT2v07 spec. 62 */ 63 64 #include <dev/isci/scil/sati_write_buffer.h> 65 #include <dev/isci/scil/sati_callbacks.h> 66 #include <dev/isci/scil/sati_util.h> 67 68 #define WRITE_BUFFER_WRITE_DATA 0x02 69 #define WRITE_BUFFER_DOWNLOAD_SAVE 0x05 70 #define WRITE_BUFFER_OFFSET_DOWNLOAD_SAVE 0x07 71 #define DOWNLOAD_MICROCODE_BLOCK_SIZE 512 72 73 /** 74 * @brief This method will translate the SCSI Write Buffer command 75 * into a corresponding ATA Write Buffer and Download Microcode commands. 76 * For more information on the parameters passed to this method, 77 * please reference sati_translate_command(). 78 * 79 * @return Indicates if the command translation succeeded. 80 * @retval SATI_SUCCESS indicates that the translation was supported and occurred 81 * without error. 82 * @retval SATI_FAILURE_CHECK_RESPONSE_DATA This value is returned if 83 * there is a translation failure. 84 */ 85 SATI_STATUS sati_write_buffer_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 SATI_STATUS status = SATI_FAILURE; 93 U32 allocation_length; 94 U32 allocation_blocks; 95 U32 buffer_offset; 96 97 allocation_length = ((sati_get_cdb_byte(cdb, 6) << 16) | 98 (sati_get_cdb_byte(cdb, 7) << 8) | 99 (sati_get_cdb_byte(cdb, 8))); 100 101 buffer_offset = ((sati_get_cdb_byte(cdb, 3) << 16) | 102 (sati_get_cdb_byte(cdb, 4) << 8) | 103 (sati_get_cdb_byte(cdb, 5))); 104 105 sequence->allocation_length = allocation_length; 106 allocation_blocks = allocation_length / DOWNLOAD_MICROCODE_BLOCK_SIZE; 107 108 switch(sati_get_cdb_byte(cdb, 1)) 109 { 110 case WRITE_BUFFER_WRITE_DATA: 111 if((allocation_length == DOWNLOAD_MICROCODE_BLOCK_SIZE) && 112 (buffer_offset == 0) && 113 (sati_get_cdb_byte(cdb, 2) == 0)) 114 { 115 sati_ata_write_buffer_construct(ata_io, sequence); 116 sequence->type = SATI_SEQUENCE_WRITE_BUFFER; 117 sequence->state = SATI_SEQUENCE_STATE_AWAIT_RESPONSE; 118 status = SATI_SUCCESS; 119 } 120 else 121 { 122 sati_scsi_sense_data_construct( 123 sequence, 124 scsi_io, 125 SCSI_STATUS_CHECK_CONDITION, 126 SCSI_SENSE_ILLEGAL_REQUEST, 127 SCSI_ASC_INVALID_FIELD_IN_CDB, 128 SCSI_ASCQ_INVALID_FIELD_IN_CDB 129 ); 130 131 sequence->state = SATI_SEQUENCE_STATE_FINAL; 132 status = SATI_FAILURE_CHECK_RESPONSE_DATA; 133 } 134 break; 135 136 case WRITE_BUFFER_DOWNLOAD_SAVE: 137 138 sati_ata_download_microcode_construct( 139 ata_io, 140 sequence, 141 ATA_MICROCODE_DOWNLOAD_SAVE, 142 allocation_length, 143 buffer_offset 144 ); 145 146 sequence->type = SATI_SEQUENCE_WRITE_BUFFER_MICROCODE; 147 sequence->state = SATI_SEQUENCE_STATE_AWAIT_RESPONSE; 148 status = SATI_SUCCESS; 149 break; 150 151 case WRITE_BUFFER_OFFSET_DOWNLOAD_SAVE: 152 if(((allocation_length & 0x000001FF) == 0) && //Bits 08:00 need to be zero per SAT2v7 153 ((buffer_offset & 0x000001FF) == 0) && 154 (allocation_blocks <= sequence->device->max_blocks_per_microcode_command) && 155 ((allocation_blocks >= sequence->device->min_blocks_per_microcode_command) || 156 (allocation_length == 0))) 157 { 158 sati_ata_download_microcode_construct( 159 ata_io, 160 sequence, 161 ATA_MICROCODE_OFFSET_DOWNLOAD, 162 allocation_length, 163 buffer_offset 164 ); 165 166 sequence->type = SATI_SEQUENCE_WRITE_BUFFER_MICROCODE; 167 sequence->state = SATI_SEQUENCE_STATE_AWAIT_RESPONSE; 168 status = SATI_SUCCESS; 169 } 170 else 171 { 172 sati_scsi_sense_data_construct( 173 sequence, 174 scsi_io, 175 SCSI_STATUS_CHECK_CONDITION, 176 SCSI_SENSE_ILLEGAL_REQUEST, 177 SCSI_ASC_INVALID_FIELD_IN_CDB, 178 SCSI_ASCQ_INVALID_FIELD_IN_CDB 179 ); 180 181 sequence->state = SATI_SEQUENCE_STATE_FINAL; 182 status = SATI_FAILURE_CHECK_RESPONSE_DATA; 183 } 184 break; 185 186 default: //unsupported Write Buffer Mode 187 sati_scsi_sense_data_construct( 188 sequence, 189 scsi_io, 190 SCSI_STATUS_CHECK_CONDITION, 191 SCSI_SENSE_ILLEGAL_REQUEST, 192 SCSI_ASC_INVALID_FIELD_IN_CDB, 193 SCSI_ASCQ_INVALID_FIELD_IN_CDB 194 ); 195 196 sequence->state = SATI_SEQUENCE_STATE_FINAL; 197 status = SATI_FAILURE_CHECK_RESPONSE_DATA; 198 break; 199 } 200 return status; 201 } 202 203 /** 204 * @brief This method will complete the Write Buffer Translation by checking 205 * for ATA errors and then creating a unit attention condition for 206 * changed microcode. 207 * 208 * @return Indicates if the command translation succeeded. 209 * @retval SATI_FAILURE_CHECK_RESPONSE_DATA This value is returned if 210 * there is a translation failure. 211 * @retval SATI_COMPLETE indicates that the translation was supported, occurred without 212 * error, and no additional translation is necessary. 213 */ 214 SATI_STATUS sati_write_buffer_translate_response( 215 SATI_TRANSLATOR_SEQUENCE_T * sequence, 216 void * scsi_io, 217 void * ata_io 218 ) 219 { 220 U8 * register_fis = sati_cb_get_d2h_register_fis_address(ata_io); 221 U8 ata_status = (U8) sati_get_ata_status(register_fis); 222 SATI_STATUS status = SATI_FAILURE; 223 224 if (ata_status & ATA_STATUS_REG_ERROR_BIT) 225 { 226 sati_scsi_sense_data_construct( 227 sequence, 228 scsi_io, 229 SCSI_STATUS_CHECK_CONDITION, 230 SCSI_SENSE_ABORTED_COMMAND, 231 SCSI_ASC_NO_ADDITIONAL_SENSE, 232 SCSI_ASCQ_NO_ADDITIONAL_SENSE 233 ); 234 status = SATI_FAILURE_CHECK_RESPONSE_DATA; 235 } 236 else 237 { 238 switch(sequence->type) 239 { 240 case SATI_SEQUENCE_WRITE_BUFFER_MICROCODE: 241 sati_scsi_sense_data_construct( 242 sequence, 243 scsi_io, 244 SCSI_STATUS_GOOD, 245 SCSI_SENSE_UNIT_ATTENTION, 246 SCSI_ASC_MICROCODE_HAS_CHANGED, 247 SCSI_ASCQ_MICROCODE_HAS_CHANGED 248 ); 249 status = SATI_COMPLETE; 250 break; 251 252 default: 253 status = SATI_COMPLETE; 254 break; 255 } 256 } 257 258 sequence->state = SATI_SEQUENCE_STATE_FINAL; 259 return status; 260 } 261