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