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