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 required to 59 * translate the SCSI passthru command. 60 */ 61 62 #if !defined(DISABLE_SATI_PASSTHROUGH) 63 64 #include <dev/isci/scil/sati.h> 65 #include <dev/isci/scil/sati_passthrough.h> 66 #include <dev/isci/scil/sati_util.h> 67 #include <dev/isci/scil/sati_callbacks.h> 68 #include <dev/isci/scil/intel_ata.h> 69 70 #define PASSTHROUGH_CDB_PROTOCOL_MASK 0x1E 71 #define PASSTHROUGH_CDB_EXTEND_MASK 0x1 72 #define PASSTHROUGH_CDB_CK_COND_MASK 0x20 73 #define PASSTHROUGH_CDB_T_DIR_MASK 0x8 74 75 #define PASSTHROUGH_ISOLATE_BITS(cdb, index, mask, shift) (((sati_get_cdb_byte(cdb, index) & mask) >> shift)) 76 77 #define PASSTHROUGH_CDB_PROTOCOL(cdb) PASSTHROUGH_ISOLATE_BITS(cdb, 1, PASSTHROUGH_CDB_PROTOCOL_MASK, 1) 78 #define PASSTHROUGH_CDB_EXTEND(cdb) PASSTHROUGH_ISOLATE_BITS(cdb, 1, PASSTHROUGH_CDB_EXTEND_MASK, 0) 79 #define PASSTHROUGH_CDB_CK_COND(cdb) PASSTHROUGH_ISOLATE_BITS(cdb, 2, PASSTHROUGH_CDB_CK_COND_MASK, 5) 80 #define PASSTHROUGH_CDB_T_DIR(cdb) PASSTHROUGH_ISOLATE_BITS(cdb, 2, PASSTHROUGH_CDB_T_DIR_MASK, 3) 81 82 #define PASSTHROUGH_CDB_MULTIPLE_COUNT(cdb) (sati_get_cdb_byte(cdb, 1) >> 5) 83 #define PASSTHROUGH_CDB_COMMAND(cdb, index) sati_get_cdb_byte(cdb, index) 84 85 // Protocols 86 #define PASSTHROUGH_PIO_DATA_IN 0x4 87 #define PASSTHROUGH_PIO_DATA_OUT 0x5 88 #define PASSTHROUGH_UDMA_DATA_IN 0xA 89 #define PASSTHROUGH_UDMA_DATA_OUT 0xB 90 #define PASSTHROUGH_RETURN_RESPONSE 0xF 91 92 /** 93 * @brief This function will check the multiple_count field in the SCSI CDB 94 * and if multiple_count is nonzero the function will check the 95 * ATA command code. Only Read and Write Multiple commands are allowed 96 * when multiple_count is a nonzero value. 97 * 98 * @param[in] cdb The SCSI cdb for the ATA pass-through command 99 * 100 * @return BOOL 101 @retval TRUE - multiple_count is nonzero with a unsupported command 102 @retval FALSE - multiple_count is zero or the command supports a nonzero value 103 */ 104 static 105 BOOL sati_passthrough_multiple_count_error( 106 U8 * cdb 107 ) 108 { 109 U8 ata_command_code; 110 111 if(PASSTHROUGH_CDB_MULTIPLE_COUNT(cdb) > 0) 112 { 113 if(sati_get_cdb_byte(cdb, 0 ) == SCSI_ATA_PASSTHRU_12) 114 { 115 ata_command_code = PASSTHROUGH_CDB_COMMAND(cdb, 9); 116 } 117 else 118 { 119 ata_command_code = PASSTHROUGH_CDB_COMMAND(cdb, 14); 120 } 121 122 switch(ata_command_code) 123 { //MULTICOUNT bit is supported 124 case ATA_READ_MULTIPLE: 125 case ATA_READ_MULTIPLE_EXT: 126 case ATA_WRITE_MULTIPLE: 127 case ATA_WRITE_MULTIPLE_EXT: 128 case ATA_WRITE_MULTIPLE_FUA_EXT: 129 return FALSE; 130 break; 131 132 default: 133 return TRUE; 134 } 135 } 136 //MULTICOUNT bit is not set 137 return FALSE; 138 } 139 140 /** 141 * @brief This method will construct the sense data buffer in the user's 142 * sense data buffer location. Additionally, it will set the user's 143 * SCSI status. 144 * 145 * @param[in] sequence This parameter specifies the translation sequence 146 * for which to construct the sense data. 147 * @param[in] register_fis This parameter specifies the fis from which 148 * to get the data. 149 * @param[in,out] scsi_io This parameter specifies the user's IO request 150 * for which to construct the sense data. 151 * @param[in] scsi_status This parameter specifies the SCSI status 152 * value for the user's IO request. 153 * @param[in] sense_key This parameter specifies the sense key to 154 * be set for the user's IO request. 155 * @param[in] additional_sense_code This parameter specifies the 156 * additional sense code (ASC) key to be set for the user's 157 * IO request. 158 * @param[in] additional_sense_code_qualifier This parameter specifies 159 * the additional sense code qualifier (ASCQ) key to be set 160 * for the user's IO request. 161 * 162 * @return none 163 */ 164 static 165 void sati_passthrough_construct_sense( 166 SATI_TRANSLATOR_SEQUENCE_T * sequence, 167 U8 * register_fis, 168 void * scsi_io, 169 U8 scsi_status, 170 U8 sense_key, 171 U8 additional_sense_code, 172 U8 additional_sense_code_qualifier 173 ) 174 { 175 U8 * sense_data; 176 U32 sense_len; 177 U8 * cdb; 178 unsigned char sector_count_upper; 179 unsigned char lba_upper; 180 181 #ifdef SATI_TRANSPORT_SUPPORTS_SAS 182 SCI_SSP_RESPONSE_IU_T * rsp_iu = (SCI_SSP_RESPONSE_IU_T*) 183 sati_cb_get_response_iu_address(scsi_io); 184 185 sati_scsi_common_response_iu_construct( 186 rsp_iu, 187 scsi_status, 188 SCSI_FIXED_SENSE_DATA_BASE_LENGTH, 189 SCSI_RESPONSE_DATA_PRES_SENSE_DATA 190 ); 191 192 sense_data = (U8*) rsp_iu->data; 193 sense_len = SSP_RESPONSE_IU_MAX_DATA * 4; // dwords to bytes 194 #else 195 sense_data = sati_cb_get_sense_data_address(scsi_io); 196 sense_len = sati_cb_get_sense_data_length(scsi_io); 197 #endif // SATI_TRANSPORT_SUPPORTS_SAS 198 199 sati_scsi_sense_data_construct( 200 sequence, 201 scsi_io, 202 scsi_status, 203 sense_key, 204 additional_sense_code, 205 additional_sense_code_qualifier 206 ); 207 208 cdb = sati_cb_get_cdb_address(scsi_io); 209 210 if (sati_get_ata_sector_count_ext(register_fis) != 0) { 211 sector_count_upper = 1; 212 } else { 213 sector_count_upper = 0; 214 } 215 216 if (sati_get_ata_lba_high_ext(register_fis) != 0 || 217 sati_get_ata_lba_mid_ext(register_fis) != 0 || 218 sati_get_ata_lba_low_ext(register_fis) != 0) { 219 lba_upper = 1; 220 } else { 221 lba_upper = 0; 222 } 223 224 // Information section 225 sati_set_sense_data_byte(sense_data, sense_len, 3, (U8)sati_get_ata_error(register_fis)); 226 sati_set_sense_data_byte(sense_data, sense_len, 4, (U8)sati_get_ata_status(register_fis)); 227 sati_set_sense_data_byte(sense_data, sense_len, 5, sati_get_ata_device(register_fis)); 228 sati_set_sense_data_byte(sense_data, sense_len, 6, sati_get_ata_sector_count(register_fis)); 229 230 // Command specific section 231 sati_set_sense_data_byte(sense_data, sense_len, 8, (PASSTHROUGH_CDB_EXTEND(cdb) << 7) | (sector_count_upper << 6) | (lba_upper << 5)); 232 sati_set_sense_data_byte(sense_data, sense_len, 9, sati_get_ata_lba_high(register_fis)); 233 sati_set_sense_data_byte(sense_data, sense_len, 10, sati_get_ata_lba_mid(register_fis)); 234 sati_set_sense_data_byte(sense_data, sense_len, 11, sati_get_ata_lba_low(register_fis)); 235 236 sequence->is_sense_response_set = TRUE; 237 } 238 239 /** 240 * @brief This method will verify that the T_DIR bit matches the protocol bit. 241 * It will additionally set the direction on the sequence. 242 * 243 * @param[in,out] sequence This parameter specifies the translation sequence 244 * for which to construct the sense data. 245 * @param[in] cdb The CDB containing the passthrough command 246 * 247 * @return none 248 */ 249 static 250 SATI_STATUS sati_passthrough_check_direction( 251 SATI_TRANSLATOR_SEQUENCE_T * sequence, 252 U8 * cdb 253 ) 254 { 255 if ((PASSTHROUGH_CDB_PROTOCOL(cdb) == PASSTHROUGH_PIO_DATA_IN) || 256 (PASSTHROUGH_CDB_PROTOCOL(cdb) == PASSTHROUGH_UDMA_DATA_IN)) 257 { 258 if (PASSTHROUGH_CDB_T_DIR(cdb) == 0x0) 259 { 260 return SATI_FAILURE; 261 } 262 else 263 { 264 sequence->data_direction = SATI_DATA_DIRECTION_IN; 265 } 266 } 267 else if ((PASSTHROUGH_CDB_PROTOCOL(cdb) == PASSTHROUGH_PIO_DATA_OUT) || 268 (PASSTHROUGH_CDB_PROTOCOL(cdb) == PASSTHROUGH_UDMA_DATA_OUT)) 269 { 270 if (PASSTHROUGH_CDB_T_DIR(cdb) == 0x1) 271 { 272 return SATI_FAILURE; 273 } 274 else 275 { 276 sequence->data_direction = SATI_DATA_DIRECTION_OUT; 277 } 278 } 279 else 280 { 281 sequence->data_direction = SATI_DATA_DIRECTION_NONE; 282 } 283 284 return SATI_COMPLETE; 285 } 286 287 //****************************************************************************** 288 //* P U B L I C M E T H O D S 289 //****************************************************************************** 290 291 /** 292 * @brief This method will translate the SCSI Passthrough command 293 * into the corresponding ATA command. 294 * 295 * @return Indicate if the command translation succeeded. 296 * @retval SATI_SUCCESS This is returned if the command translation was 297 * successful. 298 * @retval SATI_FAILURE This is returned if the command translation was 299 * unsuccessful 300 */ 301 302 SATI_STATUS sati_passthrough_12_translate_command( 303 SATI_TRANSLATOR_SEQUENCE_T * sequence, 304 void * scsi_io, 305 void * ata_io 306 ) 307 { 308 SATI_STATUS status; 309 U8 * cdb; 310 U8 * register_fis; 311 312 status = SATI_FAILURE; 313 314 sequence->type = SATI_SEQUENCE_ATA_PASSTHROUGH_12; 315 sequence->state = SATI_SEQUENCE_STATE_TRANSLATE_DATA; 316 317 cdb = sati_cb_get_cdb_address(scsi_io); 318 sequence->protocol = PASSTHROUGH_CDB_PROTOCOL (cdb); 319 register_fis = sati_cb_get_h2d_register_fis_address(ata_io); 320 321 if (sati_passthrough_check_direction(sequence, cdb) != SATI_COMPLETE 322 || sati_passthrough_multiple_count_error(cdb) 323 ) 324 { 325 // Fail due to mismatch 326 sati_scsi_sense_data_construct( 327 sequence, 328 scsi_io, 329 SCSI_STATUS_CHECK_CONDITION, 330 SCSI_SENSE_ILLEGAL_REQUEST, 331 SCSI_ASC_INVALID_FIELD_IN_CDB, 332 SCSI_ASCQ_INVALID_FIELD_IN_CDB 333 ); 334 return SATI_FAILURE_CHECK_RESPONSE_DATA; 335 } 336 337 sati_set_ata_features(register_fis, sati_get_cdb_byte(cdb, 3)); 338 sati_set_ata_sector_count(register_fis, sati_get_cdb_byte(cdb, 4)); 339 sati_set_ata_lba_low(register_fis, sati_get_cdb_byte(cdb, 5)); 340 sati_set_ata_lba_mid(register_fis, sati_get_cdb_byte(cdb, 6)); 341 sati_set_ata_lba_high(register_fis, sati_get_cdb_byte(cdb, 7)); 342 sati_set_ata_device_head(register_fis, sati_get_cdb_byte(cdb, 8)); 343 sati_set_ata_command(register_fis, sati_get_cdb_byte(cdb, 9)); 344 345 sequence->state = SATI_SEQUENCE_STATE_AWAIT_RESPONSE; 346 347 return SATI_SUCCESS; 348 } 349 350 /** 351 * @brief This method will translate the SCSI Passthrough command 352 * into the corresponding ATA command. 353 * 354 * @return Indicate if the command translation succeeded. 355 * @retval SATI_SUCCESS This is returned if the command translation was 356 * successful. 357 * @retval SATI_FAILURE This is returned if the command translation was 358 * unsuccessful 359 */ 360 SATI_STATUS sati_passthrough_16_translate_command( 361 SATI_TRANSLATOR_SEQUENCE_T * sequence, 362 void * scsi_io, 363 void * ata_io 364 ) 365 { 366 SATI_STATUS status; 367 U8 * cdb; 368 U8 * register_fis; 369 370 status = SATI_FAILURE; 371 372 sequence->type = SATI_SEQUENCE_ATA_PASSTHROUGH_16; 373 sequence->state = SATI_SEQUENCE_STATE_TRANSLATE_DATA; 374 375 cdb = sati_cb_get_cdb_address(scsi_io); 376 sequence->protocol = PASSTHROUGH_CDB_PROTOCOL(cdb); 377 register_fis = sati_cb_get_h2d_register_fis_address(ata_io); 378 379 if (sati_passthrough_check_direction(sequence, cdb) != SATI_COMPLETE 380 || sati_passthrough_multiple_count_error(cdb) 381 ) 382 { 383 // Fail due to mismatch 384 sati_scsi_sense_data_construct( 385 sequence, 386 scsi_io, 387 SCSI_STATUS_CHECK_CONDITION, 388 SCSI_SENSE_ILLEGAL_REQUEST, 389 SCSI_ASC_INVALID_FIELD_IN_CDB, 390 SCSI_ASCQ_INVALID_FIELD_IN_CDB 391 ); 392 return SATI_FAILURE_CHECK_RESPONSE_DATA; 393 } 394 395 if (PASSTHROUGH_CDB_EXTEND(cdb) == 1) 396 { 397 sati_set_ata_features_exp(register_fis, sati_get_cdb_byte(cdb, 3)); 398 sati_set_ata_sector_count_exp(register_fis, sati_get_cdb_byte(cdb, 5)); 399 sati_set_ata_lba_low_exp(register_fis, sati_get_cdb_byte(cdb, 7)); 400 sati_set_ata_lba_mid_exp(register_fis, sati_get_cdb_byte(cdb, 9)); 401 sati_set_ata_lba_high_exp(register_fis, sati_get_cdb_byte(cdb, 11)); 402 } 403 sati_set_ata_features(register_fis, sati_get_cdb_byte(cdb, 4)); 404 sati_set_ata_sector_count(register_fis, sati_get_cdb_byte(cdb, 6)); 405 sati_set_ata_lba_low(register_fis, sati_get_cdb_byte(cdb, 8)); 406 sati_set_ata_lba_mid(register_fis, sati_get_cdb_byte(cdb, 10)); 407 sati_set_ata_lba_high(register_fis, sati_get_cdb_byte(cdb, 12)); 408 sati_set_ata_device_head(register_fis, sati_get_cdb_byte(cdb, 13)); 409 sati_set_ata_command(register_fis, sati_get_cdb_byte(cdb, 14)); 410 411 sequence->state = SATI_SEQUENCE_STATE_AWAIT_RESPONSE; 412 413 return SATI_SUCCESS; 414 } 415 416 /** 417 * @brief This method will translate the ATA command 418 * response 419 * 420 * @return Indicate if the command translation succeeded. 421 * @retval SATI_COMPLETE This is returned if the command translation was 422 * successful. 423 * @retval SATI_FAILURE This is returned if the command translation was 424 * unsuccessful 425 */ 426 SATI_STATUS sati_passthrough_translate_response( 427 SATI_TRANSLATOR_SEQUENCE_T * sequence, 428 void * scsi_io, 429 void * ata_io 430 ) 431 { 432 U8 * cdb; 433 U8 * register_fis; 434 435 cdb = sati_cb_get_cdb_address(scsi_io); 436 register_fis = sati_cb_get_d2h_register_fis_address(ata_io); 437 438 // Check for device errors 439 if (sati_get_ata_status(register_fis) & ATA_STATUS_REG_ERROR_BIT) 440 { 441 sati_translate_error(sequence, scsi_io, (U8)sati_get_ata_error(register_fis)); 442 return SATI_FAILURE_CHECK_RESPONSE_DATA; 443 } 444 445 // If the user set the check condition bit, fill out the sense data 446 if (PASSTHROUGH_CDB_CK_COND(cdb) || 447 PASSTHROUGH_CDB_PROTOCOL(cdb) == PASSTHROUGH_RETURN_RESPONSE) 448 { 449 sati_passthrough_construct_sense( 450 sequence, 451 register_fis, 452 scsi_io, 453 SCSI_STATUS_CHECK_CONDITION, 454 SCSI_SENSE_RECOVERED_ERROR, 455 SCSI_ASC_NO_ADDITIONAL_SENSE, 456 SCSI_ASCQ_ATA_PASS_THROUGH_INFORMATION_AVAILABLE 457 ); 458 } 459 460 sequence->state = SATI_SEQUENCE_STATE_FINAL; 461 462 return SATI_COMPLETE; 463 } 464 465 #endif // !defined(DISABLE_SATI_PASSTHROUGH) 466