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 mode sense 6-byte commands. 60 */ 61 62 #if !defined(DISABLE_SATI_MODE_SENSE) 63 64 #include <dev/isci/scil/sati_mode_sense.h> 65 #include <dev/isci/scil/sati_mode_sense_6.h> 66 #include <dev/isci/scil/sati_mode_pages.h> 67 #include <dev/isci/scil/sati_callbacks.h> 68 #include <dev/isci/scil/sati_util.h> 69 #include <dev/isci/scil/intel_scsi.h> 70 #include <dev/isci/scil/intel_ata.h> 71 72 //****************************************************************************** 73 //* P R I V A T E M E T H O D S 74 //****************************************************************************** 75 76 /** 77 * @brief This method builds the mode parameter header for a 6-byte SCSI 78 * mode sense data response. The parameter header is 4 bytes in 79 * size. 80 * For more information on the parameters passed to this method, 81 * please reference sati_translate_command(). 82 * 83 * @param[in] identify This parameter specifies the ATA remote device's 84 * received IDENTIFY DEVICE data. 85 * @param[in] mode_data_length This parameter specifies the amount of data 86 * to be returned as part of this mode sense request. 87 * 88 * @return This method returns the number of bytes written into the 89 * data buffer. 90 */ 91 static 92 U32 sati_mode_sense_6_build_header( 93 SATI_TRANSLATOR_SEQUENCE_T * sequence, 94 void * scsi_io, 95 ATA_IDENTIFY_DEVICE_DATA_T * identify, 96 U8 mode_data_length 97 ) 98 { 99 U8 * cdb = sati_cb_get_cdb_address(scsi_io); 100 101 // Fill in the length of the mode parameter data returned (do not include 102 // the size of the mode data length field in the total). 103 sati_set_data_byte(sequence, scsi_io, 0, (U8)mode_data_length-1); 104 105 // Medium Type is 0 for SBC devices 106 sati_set_data_byte(sequence, scsi_io, 1, SCSI_MODE_HEADER_MEDIUM_TYPE_SBC); 107 108 // Write Protect (WP), Rsvd, DPOFUA, Rsvd 109 if (sequence->device->capabilities & SATI_DEVICE_CAP_DMA_FUA_ENABLE) 110 sati_set_data_byte(sequence,scsi_io,2,SCSI_MODE_SENSE_HEADER_FUA_ENABLE); 111 else 112 sati_set_data_byte(sequence, scsi_io, 2, 0); 113 114 // Set the block descriptor length if block descriptors are utilized. 115 if (sati_get_cdb_byte(cdb, 1) & SCSI_MODE_SENSE_DBD_ENABLE) 116 sati_set_data_byte(sequence, scsi_io, 3, 0); 117 else 118 sati_set_data_byte( 119 sequence, scsi_io, 3, SCSI_MODE_SENSE_STD_BLOCK_DESCRIPTOR_LENGTH 120 ); 121 122 return SCSI_MODE_SENSE_6_HEADER_LENGTH; 123 } 124 125 /** 126 * @brief This method perform the data translation common to all SCSI MODE 127 * SENSE 6 byte commands. This includes building the mode page 128 * header and block descriptor (if requested). 129 * For more information on the parameters passed to this method, 130 * please reference sati_translate_command(). 131 * 132 * @param[in] identify This parameter specifies the remote device's IDENTIFY 133 * DEVICE data to be used during translation. 134 * @param[in] transfer_length This parameter specifies the size of the 135 * mode page (including header & block descriptor). 136 * 137 * @return This method returns the number of bytes written into the user's 138 * mode page data buffer. 139 */ 140 static 141 U32 sati_mode_sense_6_translate_data( 142 SATI_TRANSLATOR_SEQUENCE_T * sequence, 143 ATA_IDENTIFY_DEVICE_DATA_T * identify, 144 void * scsi_io, 145 U8 transfer_length 146 ) 147 { 148 U8 * cdb = sati_cb_get_cdb_address(scsi_io); 149 U32 offset; 150 151 offset = sati_mode_sense_6_build_header( 152 sequence, scsi_io, identify, transfer_length 153 ); 154 155 // Determine if the caller disabled block descriptors (DBD). If not, 156 // then generate a block descriptor. 157 if ((sati_get_cdb_byte(cdb, 1) & SCSI_MODE_SENSE_DBD_ENABLE) == 0) 158 offset += sati_mode_sense_build_std_block_descriptor( 159 sequence, scsi_io, identify, offset 160 ); 161 162 return offset; 163 } 164 165 //****************************************************************************** 166 //* P R O T E C T E D M E T H O D S 167 //****************************************************************************** 168 169 /** 170 * @brief This method will translate the SCSI mode sense 6 byte command 171 * into corresponding ATA commands. If the command is well-formed, 172 * then the translation will result in an ATA IDENTIFY DEVICE 173 * command. 174 * For more information on the parameters passed to this method, 175 * please reference sati_translate_command(). 176 * 177 * @return Indicate if the command translation succeeded. 178 * @retval SCI_SUCCESS This is returned if the command translation was 179 * successful. 180 * @retval SATI_FAILURE_CHECK_RESPONSE_DATA This value is returned if 181 * sense data has been created as a result of something specified 182 * in the CDB. 183 */ 184 SATI_STATUS sati_mode_sense_6_translate_command( 185 SATI_TRANSLATOR_SEQUENCE_T * sequence, 186 void * scsi_io, 187 void * ata_io 188 ) 189 { 190 U8 * cdb = sati_cb_get_cdb_address(scsi_io); 191 192 // Set the data length based on the allocation length field in the CDB. 193 sequence->allocation_length = sati_get_cdb_byte(cdb, 4); 194 195 return sati_mode_sense_translate_command(sequence, scsi_io, ata_io, 6); 196 } 197 198 /** 199 * @brief This method will perform data translation from the supplied ATA 200 * input data (i.e. an ATA IDENTIFY DEVICE block) into a CACHING 201 * mode page format. The data will be written into the user's mode 202 * page data buffer. This function operates specifically for MODE 203 * SENSE 6 commands. 204 * For more information on the parameters passed to this method, 205 * please reference sati_translate_data(). 206 * 207 * @return none. 208 */ 209 void sati_mode_sense_6_caching_translate_data( 210 SATI_TRANSLATOR_SEQUENCE_T * sequence, 211 void * ata_input_data, 212 void * scsi_io 213 ) 214 { 215 ATA_IDENTIFY_DEVICE_DATA_T * identify = (ATA_IDENTIFY_DEVICE_DATA_T*) 216 ata_input_data; 217 U8 data_length = (U8) sati_mode_sense_calculate_page_header(scsi_io, 6) 218 + SCSI_MODE_PAGE_08_LENGTH; 219 U32 page_offset = sati_mode_sense_6_translate_data( 220 sequence, identify, scsi_io, data_length 221 ); 222 223 sati_mode_sense_caching_translate_data( 224 sequence, scsi_io, identify, page_offset 225 ); 226 } 227 228 /** 229 * @brief This method will perform data translation from the supplied ATA 230 * input data (i.e. an ATA IDENTIFY DEVICE block) into a INFORMATIONAL 231 * EXCEPTIONS CONTROL mode page format. The data will be written 232 * into the user's mode page data buffer. This function operates 233 * specifically for MODE SENSE 6 commands. 234 * For more information on the parameters passed to this method, 235 * please reference sati_translate_data(). 236 * 237 * @return none. 238 */ 239 void sati_mode_sense_6_informational_excp_control_translate_data( 240 SATI_TRANSLATOR_SEQUENCE_T * sequence, 241 void * ata_input_data, 242 void * scsi_io 243 ) 244 { 245 ATA_IDENTIFY_DEVICE_DATA_T * identify = (ATA_IDENTIFY_DEVICE_DATA_T*) 246 ata_input_data; 247 U8 data_length = (U8) sati_mode_sense_calculate_page_header(scsi_io, 6) 248 + SCSI_MODE_PAGE_1C_LENGTH; 249 U32 page_offset = sati_mode_sense_6_translate_data( 250 sequence, identify, scsi_io, data_length 251 ); 252 253 sati_mode_sense_informational_excp_control_translate_data( 254 sequence, scsi_io, identify, page_offset 255 ); 256 } 257 258 /** 259 * @brief This method will perform data translation from the supplied ATA 260 * input data (i.e. an ATA IDENTIFY DEVICE block) into a DISCONNECT 261 * RECONNECT mode page format. The data will be written 262 * into the user's mode page data buffer. This function operates 263 * specifically for MODE SENSE 6 commands. 264 * For more information on the parameters passed to this method, 265 * please reference sati_translate_data(). 266 * 267 * @return none. 268 */ 269 void sati_mode_sense_6_disconnect_reconnect_translate_data( 270 SATI_TRANSLATOR_SEQUENCE_T * sequence, 271 void * ata_input_data, 272 void * scsi_io 273 ) 274 { 275 ATA_IDENTIFY_DEVICE_DATA_T * identify = (ATA_IDENTIFY_DEVICE_DATA_T*) 276 ata_input_data; 277 278 U8 data_length = (U8) sati_mode_sense_calculate_page_header(scsi_io, 6) 279 + SCSI_MODE_PAGE_02_LENGTH ; 280 281 U32 page_offset = sati_mode_sense_6_translate_data( 282 sequence, identify, scsi_io, data_length 283 ); 284 285 sati_mode_sense_disconnect_reconnect_translate_data( 286 sequence, scsi_io, identify, page_offset 287 ); 288 } 289 290 /** 291 * @brief This method will perform data translation from the supplied ATA 292 * input data (i.e. an ATA IDENTIFY DEVICE block) into a READ WRITE ERROR 293 * mode page format. The data will be written 294 * into the user's mode page data buffer. This function operates 295 * specifically for MODE SENSE 6 commands. 296 * For more information on the parameters passed to this method, 297 * please reference sati_translate_data(). 298 * 299 * @return none. 300 */ 301 void sati_mode_sense_6_read_write_error_translate_data( 302 SATI_TRANSLATOR_SEQUENCE_T * sequence, 303 void * ata_input_data, 304 void * scsi_io 305 ) 306 { 307 ATA_IDENTIFY_DEVICE_DATA_T * identify = (ATA_IDENTIFY_DEVICE_DATA_T*) 308 ata_input_data; 309 310 U8 data_length = (U8) sati_mode_sense_calculate_page_header(scsi_io, 6) 311 + SCSI_MODE_PAGE_01_LENGTH; 312 313 U32 page_offset = sati_mode_sense_6_translate_data( 314 sequence, identify, scsi_io, data_length 315 ); 316 317 sati_mode_sense_read_write_error_translate_data( 318 sequence, scsi_io, identify, page_offset 319 ); 320 } 321 322 /** 323 * @brief This method will perform data translation from the supplied ATA 324 * input data (i.e. an ATA IDENTIFY DEVICE block) into a CONTROL 325 * mode page format. The data will be written 326 * into the user's mode page data buffer. This function operates 327 * specifically for MODE SENSE 6 commands. 328 * For more information on the parameters passed to this method, 329 * please reference sati_translate_data(). 330 * 331 * @return none. 332 */ 333 void sati_mode_sense_6_control_translate_data( 334 SATI_TRANSLATOR_SEQUENCE_T * sequence, 335 void * ata_input_data, 336 void * scsi_io 337 ) 338 { 339 ATA_IDENTIFY_DEVICE_DATA_T * identify = (ATA_IDENTIFY_DEVICE_DATA_T*) 340 ata_input_data; 341 342 U8 data_length = (U8) sati_mode_sense_calculate_page_header(scsi_io, 6) 343 + SCSI_MODE_PAGE_0A_LENGTH; 344 345 U32 page_offset = sati_mode_sense_6_translate_data( 346 sequence, identify, scsi_io, data_length 347 ); 348 349 sati_mode_sense_control_translate_data( 350 sequence, scsi_io, identify, page_offset 351 ); 352 } 353 354 /** 355 * @brief This method will perform data translation from the supplied ATA 356 * input data (i.e. an ATA IDENTIFY DEVICE block) into a Power 357 * Condition mode page format. The data will be written 358 * into the user's mode page data buffer. This function operates 359 * specifically for MODE SENSE 6 commands. 360 * For more information on the parameters passed to this method, 361 * please reference sati_translate_data(). 362 * 363 * @return none. 364 */ 365 void sati_mode_sense_6_power_condition_translate_data( 366 SATI_TRANSLATOR_SEQUENCE_T * sequence, 367 void * ata_input_data, 368 void * scsi_io 369 ) 370 { 371 ATA_IDENTIFY_DEVICE_DATA_T * identify = (ATA_IDENTIFY_DEVICE_DATA_T*) 372 ata_input_data; 373 374 U8 data_length; 375 U32 page_offset; 376 377 data_length = (U8) sati_mode_sense_calculate_page_header(scsi_io, 6) 378 + SCSI_MODE_PAGE_1A_LENGTH; 379 380 page_offset = sati_mode_sense_6_translate_data( 381 sequence, identify, scsi_io, data_length 382 ); 383 384 sati_mode_sense_power_condition_translate_data( 385 sequence, scsi_io, identify, page_offset 386 ); 387 } 388 389 390 391 /** 392 * @brief This method will perform data translation from the supplied ATA 393 * input data (i.e. an ATA IDENTIFY DEVICE block) into an ALL 394 * PAGES mode page format. The ALL PAGES mode page is basically a 395 * conglomeration of all mode pages and sub-pages into a single 396 * page. The data will be written into the user's mode page 397 * data buffer. This function operates specifically for MODE 398 * SENSE 6 commands. 399 * For more information on the parameters passed to this method, 400 * please reference sati_translate_data(). 401 * 402 * @return none. 403 */ 404 void sati_mode_sense_6_all_pages_translate_data( 405 SATI_TRANSLATOR_SEQUENCE_T * sequence, 406 void * ata_input_data, 407 void * scsi_io 408 ) 409 { 410 ATA_IDENTIFY_DEVICE_DATA_T * identify = (ATA_IDENTIFY_DEVICE_DATA_T*) 411 ata_input_data; 412 U8 data_length = (U8) sati_mode_sense_calculate_page_header(scsi_io, 6) 413 + SCSI_MODE_PAGE_01_LENGTH 414 + SCSI_MODE_PAGE_02_LENGTH 415 + SCSI_MODE_PAGE_08_LENGTH 416 + SCSI_MODE_PAGE_0A_LENGTH 417 + SCSI_MODE_PAGE_1C_LENGTH; 418 419 U32 page_offset = sati_mode_sense_6_translate_data( 420 sequence, identify, scsi_io, data_length 421 ); 422 423 sati_mode_sense_all_pages_translate_data( 424 sequence, scsi_io, identify, page_offset 425 ); 426 } 427 428 #endif // !defined(DISABLE_SATI_MODE_SENSE) 429 430