1/* 2 * Copyright 2004-2007, Haiku, Inc. All RightsReserved. 3 * Copyright 2002/03, Thomas Kurschel. All rights reserved. 4 * 5 * Distributed under the terms of the MIT License. 6 */ 7 8/* 9 Part of Open IDE bus manager 10 11 Converts SCSI commands to ATA commands. 12*/ 13 14 15#include "ide_internal.h" 16#include "ide_sim.h" 17#include "ide_cmds.h" 18 19#include <string.h> 20 21 22/** emulate MODE SENSE 10 command */ 23 24static void 25ata_mode_sense_10(ide_device_info *device, ide_qrequest *qrequest) 26{ 27 scsi_ccb *request = qrequest->request; 28 scsi_cmd_mode_sense_10 *cmd = (scsi_cmd_mode_sense_10 *)request->cdb; 29 scsi_mode_param_header_10 param_header; 30 scsi_modepage_control control; 31 scsi_mode_param_block_desc block_desc; 32 size_t totalLength = sizeof(scsi_mode_param_header_10) 33 + sizeof(scsi_mode_param_block_desc) 34 + sizeof(scsi_modepage_control); 35 scsi_mode_param_dev_spec_da devspec = { 36 _res0_0 : 0, 37 dpo_fua : 0, 38 _res0_6 : 0, 39 write_protected : 0 40 }; 41 uint32 allocationLength; 42 43 SHOW_FLOW0(1, "Hi!"); 44 45 allocationLength = B_BENDIAN_TO_HOST_INT16(cmd->allocation_length); 46 47 // we answer control page requests and "all pages" requests 48 // (as the latter are the same as the first) 49 if ((cmd->page_code != SCSI_MODEPAGE_CONTROL && cmd->page_code != SCSI_MODEPAGE_ALL) 50 || (cmd->page_control != SCSI_MODE_SENSE_PC_CURRENT 51 && cmd->page_control != SCSI_MODE_SENSE_PC_SAVED)) { 52 set_sense(device, SCSIS_KEY_ILLEGAL_REQUEST, SCSIS_ASC_INV_CDB_FIELD); 53 return; 54 } 55 56 //param_header = (scsi_mode_param_header_10 *)request->data; 57 param_header.mode_data_length = B_HOST_TO_BENDIAN_INT16(totalLength - 1); 58 param_header.medium_type = 0; // XXX standard is a bit vague here 59 param_header.dev_spec_parameter = *(uint8 *)&devspec; 60 param_header.block_desc_length 61 = B_HOST_TO_BENDIAN_INT16(sizeof(scsi_mode_param_block_desc)); 62 63 copy_sg_data(request, 0, allocationLength, ¶m_header, 64 sizeof(param_header), false); 65 66 /*block_desc = (scsi_mode_param_block_desc *)(request->data 67 + sizeof(*param_header));*/ 68 memset(&block_desc, 0, sizeof(block_desc)); 69 // density is reserved (0), descriptor apply to entire medium (num_blocks=0) 70 // remains the blocklen to be set 71 block_desc.high_blocklen = 0; 72 block_desc.med_blocklen = 512 >> 8; 73 block_desc.low_blocklen = 512 & 0xff; 74 75 copy_sg_data(request, sizeof(param_header), allocationLength, 76 &block_desc, sizeof(block_desc), false); 77 78 /*contr = (scsi_modepage_contr *)(request->data 79 + sizeof(*param_header) 80 + ((uint16)param_header->high_block_desc_len << 8) 81 + param_header->low_block_desc_len);*/ 82 83 memset(&control, 0, sizeof(control)); 84 control.RLEC = false; 85 control.DQue = !device->CQ_enabled; 86 control.QErr = false; 87 // when a command fails we requeue all 88 // lost commands automagically 89 control.QAM = SCSI_QAM_UNRESTRICTED; 90 91 copy_sg_data(request, sizeof(param_header) 92 + B_BENDIAN_TO_HOST_INT16(param_header.block_desc_length), 93 allocationLength, &control, sizeof(control), false); 94 95 // the number of bytes that were transferred to buffer is 96 // restricted by allocation length and by request data buffer size 97 totalLength = min(totalLength, allocationLength); 98 totalLength = min(totalLength, request->data_length); 99 100 request->data_resid = request->data_length - totalLength; 101} 102 103 104/*! Emulate modifying control page */ 105static bool 106ata_mode_select_control_page(ide_device_info *device, ide_qrequest *qrequest, 107 scsi_modepage_control *page) 108{ 109 if (page->header.page_length != sizeof(*page) - sizeof(page->header)) { 110 set_sense(device, SCSIS_KEY_ILLEGAL_REQUEST, SCSIS_ASC_PARAM_LIST_LENGTH_ERR); 111 return false; 112 } 113 114 // we only support enabling/disabling command queuing 115 enable_CQ(device, !page->DQue); 116 return true; 117} 118 119 120/*! Emulate MODE SELECT 10 command */ 121static void 122ata_mode_select_10(ide_device_info *device, ide_qrequest *qrequest) 123{ 124 scsi_ccb *request = qrequest->request; 125 scsi_cmd_mode_select_10 *cmd = (scsi_cmd_mode_select_10 *)request->cdb; 126 scsi_mode_param_header_10 param_header; 127 scsi_modepage_header page_header; 128 uint32 totalLength; 129 uint32 modepageOffset; 130 char modepage_buffer[64]; // !!! enlarge this to support longer mode pages 131 132 if (cmd->save_pages || cmd->pf != 1) { 133 set_sense(device, SCSIS_KEY_ILLEGAL_REQUEST, SCSIS_ASC_INV_CDB_FIELD); 134 return; 135 } 136 137 totalLength = min(request->data_length, 138 B_BENDIAN_TO_HOST_INT16(cmd->param_list_length)); 139 140 // first, retrieve page header to get size of different chunks 141 //param_header = (scsi_mode_param_header_10 *)request->data; 142 if (!copy_sg_data(request, 0, totalLength, ¶m_header, sizeof(param_header), true)) 143 goto err; 144 145 totalLength = min(totalLength, 146 B_BENDIAN_TO_HOST_INT16(param_header.mode_data_length) + 1UL); 147 148 // this is the start of the first mode page; 149 // we ignore the block descriptor silently 150 modepageOffset = sizeof(param_header) 151 + B_BENDIAN_TO_HOST_INT16(param_header.block_desc_length); 152 153 // go through list of pages 154 while (modepageOffset < totalLength) { 155 uint32 pageLength; 156 157 // get header to know how long page is 158 if (!copy_sg_data(request, modepageOffset, totalLength, 159 &page_header, sizeof(page_header), true)) 160 goto err; 161 162 // get size of one page and copy it to buffer 163 pageLength = page_header.page_length + sizeof(scsi_modepage_header); 164 165 // the buffer has a maximum size - this is really standard compliant but 166 // sufficient for our needs 167 if (pageLength > sizeof(modepage_buffer)) 168 goto err; 169 170 if (!copy_sg_data(request, modepageOffset, totalLength, 171 &modepage_buffer, min(pageLength, sizeof(modepage_buffer)), true)) 172 goto err; 173 174 // modify page; 175 // currently, we only support the control mode page 176 switch (page_header.page_code) { 177 case SCSI_MODEPAGE_CONTROL: 178 if (!ata_mode_select_control_page(device, qrequest, 179 (scsi_modepage_control *)modepage_buffer)) 180 return; 181 break; 182 183 default: 184 set_sense(device, SCSIS_KEY_ILLEGAL_REQUEST, 185 SCSIS_ASC_INV_PARAM_LIST_FIELD); 186 return; 187 } 188 189 modepageOffset += pageLength; 190 } 191 192 if (modepageOffset != totalLength) 193 goto err; 194 195 request->data_resid = request->data_length - totalLength; 196 return; 197 198 // if we arrive here, data length was incorrect 199err: 200 set_sense(device, SCSIS_KEY_ILLEGAL_REQUEST, SCSIS_ASC_PARAM_LIST_LENGTH_ERR); 201} 202 203 204/*! Emulate TEST UNIT READY */ 205static bool 206ata_test_unit_ready(ide_device_info *device, ide_qrequest *qrequest) 207{ 208 SHOW_FLOW0(3, ""); 209 210 if (!device->infoblock.RMSN_supported 211 || device->infoblock._127_RMSN_support != 1) 212 return true; 213 214 // ask device about status 215 device->tf_param_mask = 0; 216 device->tf.write.command = IDE_CMD_GET_MEDIA_STATUS; 217 218 if (!send_command(device, qrequest, true, 15, ide_state_sync_waiting)) 219 return false; 220 221 // bits ide_error_mcr | ide_error_mc | ide_error_wp are also valid 222 // but not requested by TUR; ide_error_wp can safely be ignored, but 223 // we don't want to loose media change (request) reports 224 if (!check_output(device, true, 225 ide_error_nm | ide_error_abrt | ide_error_mcr | ide_error_mc, 226 false)) { 227 // SCSI spec is unclear here: we shouldn't report "media change (request)" 228 // but what to do if there is one? anyway - we report them 229 ; 230 } 231 232 return true; 233} 234 235 236/*! Flush internal device cache */ 237static bool 238ata_flush_cache(ide_device_info *device, ide_qrequest *qrequest) 239{ 240 // we should also ask for FLUSH CACHE support, but everyone denies it 241 // (looks like they cheat to gain some performance advantage, but 242 // that's pretty useless: everyone does it...) 243 if (!device->infoblock.write_cache_supported) 244 return true; 245 246 device->tf_param_mask = 0; 247 device->tf.lba.command = device->use_48bits ? IDE_CMD_FLUSH_CACHE_EXT 248 : IDE_CMD_FLUSH_CACHE; 249 250 // spec says that this may take more then 30s, how much more? 251 if (!send_command(device, qrequest, true, 60, ide_state_sync_waiting)) 252 return false; 253 254 wait_for_sync(device->bus); 255 256 return check_output(device, true, ide_error_abrt, false); 257} 258 259 260/*! Load or eject medium 261 load = true - load medium 262*/ 263static bool 264ata_load_eject(ide_device_info *device, ide_qrequest *qrequest, bool load) 265{ 266 if (load) { 267 // ATA doesn't support loading 268 set_sense(device, SCSIS_KEY_ILLEGAL_REQUEST, SCSIS_ASC_PARAM_NOT_SUPPORTED); 269 return false; 270 } 271 272 device->tf_param_mask = 0; 273 device->tf.lba.command = IDE_CMD_MEDIA_EJECT; 274 275 if (!send_command(device, qrequest, true, 15, ide_state_sync_waiting)) 276 return false; 277 278 wait_for_sync(device->bus); 279 280 return check_output(device, true, ide_error_abrt | ide_error_nm, false); 281} 282 283 284/*! Emulate PREVENT ALLOW command */ 285static bool 286ata_prevent_allow(ide_device_info *device, bool prevent) 287{ 288 set_sense(device, SCSIS_KEY_ILLEGAL_REQUEST, SCSIS_ASC_ILL_FUNCTION); 289 return false; 290} 291 292 293/*! Emulate INQUIRY command */ 294static void 295ata_inquiry(ide_device_info *device, ide_qrequest *qrequest) 296{ 297 scsi_ccb *request = qrequest->request; 298 scsi_res_inquiry data; 299 scsi_cmd_inquiry *cmd = (scsi_cmd_inquiry *)request->cdb; 300 uint32 allocation_length = cmd->allocation_length; 301 uint32 transfer_size; 302 303 if (cmd->evpd || cmd->page_code) { 304 set_sense(device, SCSIS_KEY_ILLEGAL_REQUEST, SCSIS_ASC_INV_CDB_FIELD); 305 return; 306 } 307 308 memset(&data, 0, sizeof(data)); 309 310 data.device_type = scsi_dev_direct_access; 311 data.device_qualifier = scsi_periph_qual_connected; 312 313 data.device_type_modifier = 0; 314 data.removable_medium = false; 315 316 data.ansi_version = 2; 317 data.ecma_version = 0; 318 data.iso_version = 0; 319 320 data.response_data_format = 2; 321 data.term_iop = false; 322 // to be changed if we support TERM I/O 323 324 data.additional_length = sizeof(scsi_res_inquiry) - 4; 325 326 data.soft_reset = false; 327 data.cmd_queue = device->queue_depth > 1; 328 data.linked = false; 329 330 // these values are free-style 331 data.sync = false; 332 data.write_bus16 = true; 333 data.write_bus32 = false; 334 335 data.relative_address = false; 336 337 // the following fields are *much* to small, sigh... 338 memcpy(data.vendor_ident, device->infoblock.model_number, 339 sizeof(data.vendor_ident)); 340 memcpy(data.product_ident, device->infoblock.model_number + 8, 341 sizeof(data.product_ident)); 342 memcpy(data.product_rev, " ", sizeof(data.product_rev)); 343 344 copy_sg_data(request, 0, allocation_length, &data, sizeof(data), false); 345 346 transfer_size = min(sizeof(data), allocation_length); 347 transfer_size = min(transfer_size, request->data_length); 348 349 request->data_resid = request->data_length - transfer_size; 350} 351 352 353/*! Emulate READ CAPACITY command */ 354static void 355read_capacity(ide_device_info *device, ide_qrequest *qrequest) 356{ 357 scsi_ccb *request = qrequest->request; 358 scsi_res_read_capacity data; 359 scsi_cmd_read_capacity *cmd = (scsi_cmd_read_capacity *)request->cdb; 360 uint32 lastBlock; 361 362 if (cmd->pmi || cmd->lba) { 363 set_sense(device, SCSIS_KEY_ILLEGAL_REQUEST, SCSIS_ASC_INV_CDB_FIELD); 364 return; 365 } 366 367 // TODO: 512 bytes fixed block size? 368 data.block_size = B_HOST_TO_BENDIAN_INT32(512); 369 370 lastBlock = device->total_sectors - 1; 371 data.lba = B_HOST_TO_BENDIAN_INT32(lastBlock); 372 373 copy_sg_data(request, 0, request->data_length, &data, sizeof(data), false); 374 request->data_resid = max(request->data_length - sizeof(data), 0); 375} 376 377 378/*! Execute SCSI command */ 379void 380ata_exec_io(ide_device_info *device, ide_qrequest *qrequest) 381{ 382 scsi_ccb *request = qrequest->request; 383 384 SHOW_FLOW(3, "command=%x", request->cdb[0]); 385 386 // ATA devices have one LUN only 387 if (request->target_lun != 0) { 388 request->subsys_status = SCSI_SEL_TIMEOUT; 389 finish_request(qrequest, false); 390 return; 391 } 392 393 // starting a request means deleting sense, so don't do it if 394 // the command wants to read it 395 if (request->cdb[0] != SCSI_OP_REQUEST_SENSE) 396 start_request(device, qrequest); 397 398 switch (request->cdb[0]) { 399 case SCSI_OP_TEST_UNIT_READY: 400 ata_test_unit_ready(device, qrequest); 401 break; 402 403 case SCSI_OP_REQUEST_SENSE: 404 ide_request_sense(device, qrequest); 405 return; 406 407 case SCSI_OP_FORMAT: /* FORMAT UNIT */ 408 // we could forward request to disk, but modern disks cannot 409 // be formatted anyway, so we just refuse request 410 // (exceptions are removable media devices, but to my knowledge 411 // they don't have to be formatted as well) 412 set_sense(device, SCSIS_KEY_ILLEGAL_REQUEST, SCSIS_ASC_INV_OPCODE); 413 break; 414 415 case SCSI_OP_INQUIRY: 416 ata_inquiry(device, qrequest); 417 break; 418 419 case SCSI_OP_MODE_SELECT_10: 420 ata_mode_select_10(device, qrequest); 421 break; 422 423 case SCSI_OP_MODE_SENSE_10: 424 ata_mode_sense_10(device, qrequest); 425 break; 426 427 case SCSI_OP_MODE_SELECT_6: 428 case SCSI_OP_MODE_SENSE_6: 429 // we've told SCSI bus manager to emulates these commands 430 set_sense(device, SCSIS_KEY_ILLEGAL_REQUEST, SCSIS_ASC_INV_OPCODE); 431 break; 432 433 case SCSI_OP_RESERVE: 434 case SCSI_OP_RELEASE: 435 // though mandatory, this doesn't make much sense in a 436 // single initiator environment; so what 437 set_sense(device, SCSIS_KEY_ILLEGAL_REQUEST, SCSIS_ASC_INV_OPCODE); 438 break; 439 440 case SCSI_OP_START_STOP: { 441 scsi_cmd_ssu *cmd = (scsi_cmd_ssu *)request->cdb; 442 443 // with no LoEj bit set, we should only allow/deny further access 444 // we ignore that (unsupported for ATA) 445 // with LoEj bit set, we should additionally either load or eject the medium 446 // (start = 0 - eject; start = 1 - load) 447 448 if (!cmd->start) 449 // we must always flush cache if start = 0 450 ata_flush_cache(device, qrequest); 451 452 if (cmd->load_eject) 453 ata_load_eject(device, qrequest, cmd->start); 454 455 break; 456 } 457 458 case SCSI_OP_PREVENT_ALLOW: { 459 scsi_cmd_prevent_allow *cmd = (scsi_cmd_prevent_allow *)request->cdb; 460 461 ata_prevent_allow(device, cmd->prevent); 462 break; 463 } 464 465 case SCSI_OP_READ_CAPACITY: 466 read_capacity(device, qrequest); 467 break; 468 469 case SCSI_OP_VERIFY_6: 470 // does anyone uses this function? 471 // effectly, it does a read-and-compare, which IDE doesn't support 472 set_sense(device, SCSIS_KEY_ILLEGAL_REQUEST, SCSIS_ASC_INV_OPCODE); 473 break; 474 475 case SCSI_OP_SYNCHRONIZE_CACHE: 476 // we ignore range and immediate bit, we always immediately flush everything 477 ata_flush_cache(device, qrequest); 478 break; 479 480 // sadly, there are two possible read/write operation codes; 481 // at least, the third one, read/write(12), is not valid for DAS 482 case SCSI_OP_READ_6: 483 case SCSI_OP_WRITE_6: 484 { 485 scsi_cmd_rw_6 *cmd = (scsi_cmd_rw_6 *)request->cdb; 486 uint32 pos; 487 size_t length; 488 489 pos = ((uint32)cmd->high_lba << 16) | ((uint32)cmd->mid_lba << 8) 490 | (uint32)cmd->low_lba; 491 length = cmd->length != 0 ? cmd->length : 256; 492 493 SHOW_FLOW(3, "READ6/WRITE6 pos=%lx, length=%lx", pos, length); 494 495 ata_send_rw(device, qrequest, pos, length, cmd->opcode == SCSI_OP_WRITE_6); 496 return; 497 } 498 499 case SCSI_OP_READ_10: 500 case SCSI_OP_WRITE_10: 501 { 502 scsi_cmd_rw_10 *cmd = (scsi_cmd_rw_10 *)request->cdb; 503 uint32 pos; 504 size_t length; 505 506 pos = B_BENDIAN_TO_HOST_INT32(cmd->lba); 507 length = B_BENDIAN_TO_HOST_INT16(cmd->length); 508 509 if (length != 0) { 510 ata_send_rw(device, qrequest, pos, length, cmd->opcode == SCSI_OP_WRITE_10); 511 } else { 512 // we cannot transfer zero blocks (apart from LBA48) 513 finish_request(qrequest, false); 514 } 515 return; 516 } 517 518 default: 519 set_sense(device, SCSIS_KEY_ILLEGAL_REQUEST, SCSIS_ASC_INV_OPCODE); 520 } 521 522 finish_checksense(qrequest); 523} 524