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