1 /* 2 * Copyright 2008-2014 Haiku, Inc. All rights reserved. 3 * Copyright 2007-2009, Marcus Overhagen. All rights reserved. 4 * Distributed under the terms of the MIT License. 5 */ 6 7 8 #include "ahci_port.h" 9 10 #include <new> 11 #include <stdio.h> 12 #include <string.h> 13 14 #include <ByteOrder.h> 15 #include <KernelExport.h> 16 17 #include <ATACommands.h> 18 #include <ATAInfoBlock.h> 19 #include <AutoDeleter.h> 20 21 #include "ahci_controller.h" 22 #include "ahci_tracing.h" 23 #include "sata_request.h" 24 #include "scsi_cmds.h" 25 #include "util.h" 26 27 28 #define TRACE_AHCI 29 #ifdef TRACE_AHCI 30 # define TRACE(a...) dprintf("ahci: " a) 31 #else 32 # define TRACE(a...) 33 #endif 34 //#define FLOW(a...) dprintf("ahci: " a) 35 //#define RWTRACE(a...) dprintf("ahci: " a) 36 #define FLOW(a...) 37 #define RWTRACE(a...) 38 39 40 AHCIPort::AHCIPort(AHCIController* controller, int index) 41 : 42 fController(controller), 43 fIndex(index), 44 fRegs(&controller->fRegs->port[index]), 45 fArea(-1), 46 fCommandsActive(0), 47 fRequestSem(-1), 48 fResponseSem(-1), 49 fDevicePresent(false), 50 fUse48BitCommands(false), 51 fSectorSize(0), 52 fSectorCount(0), 53 fIsATAPI(false), 54 fTestUnitReadyActive(false), 55 fResetPort(false), 56 fError(false), 57 fTrimSupported(false) 58 { 59 B_INITIALIZE_SPINLOCK(&fSpinlock); 60 fRequestSem = create_sem(1, "ahci request"); 61 fResponseSem = create_sem(0, "ahci response"); 62 } 63 64 65 AHCIPort::~AHCIPort() 66 { 67 delete_sem(fRequestSem); 68 delete_sem(fResponseSem); 69 } 70 71 72 status_t 73 AHCIPort::Init1() 74 { 75 TRACE("AHCIPort::Init1 port %d\n", fIndex); 76 77 size_t size = sizeof(command_list_entry) * COMMAND_LIST_ENTRY_COUNT 78 + sizeof(fis) + sizeof(command_table) 79 + sizeof(prd) * PRD_TABLE_ENTRY_COUNT; 80 81 char* virtAddr; 82 phys_addr_t physAddr; 83 char name[32]; 84 snprintf(name, sizeof(name), "AHCI port %d", fIndex); 85 86 fArea = alloc_mem((void**)&virtAddr, &physAddr, size, 0, name); 87 if (fArea < B_OK) { 88 TRACE("failed allocating memory for port %d\n", fIndex); 89 return fArea; 90 } 91 memset(virtAddr, 0, size); 92 93 fCommandList = (command_list_entry*)virtAddr; 94 virtAddr += sizeof(command_list_entry) * COMMAND_LIST_ENTRY_COUNT; 95 fFIS = (fis*)virtAddr; 96 virtAddr += sizeof(fis); 97 fCommandTable = (command_table*)virtAddr; 98 virtAddr += sizeof(command_table); 99 fPRDTable = (prd*)virtAddr; 100 TRACE("PRD table is at %p\n", fPRDTable); 101 102 fRegs->clb = LO32(physAddr); 103 fRegs->clbu = HI32(physAddr); 104 physAddr += sizeof(command_list_entry) * COMMAND_LIST_ENTRY_COUNT; 105 fRegs->fb = LO32(physAddr); 106 fRegs->fbu = HI32(physAddr); 107 physAddr += sizeof(fis); 108 fCommandList[0].ctba = LO32(physAddr); 109 fCommandList[0].ctbau = HI32(physAddr); 110 // prdt follows after command table 111 112 // disable transitions to partial or slumber state 113 fRegs->sctl |= 0x300; 114 115 // clear IRQ status bits 116 fRegs->is = fRegs->is; 117 118 // clear error bits 119 fRegs->serr = fRegs->serr; 120 121 // power up device 122 fRegs->cmd |= PORT_CMD_POD; 123 124 // spin up device 125 fRegs->cmd |= PORT_CMD_SUD; 126 127 // activate link 128 fRegs->cmd = (fRegs->cmd & ~PORT_CMD_ICC_MASK) | PORT_CMD_ICC_ACTIVE; 129 130 // enable FIS receive 131 fRegs->cmd |= PORT_CMD_FER; 132 133 FlushPostedWrites(); 134 135 return B_OK; 136 } 137 138 139 // called with global interrupts enabled 140 status_t 141 AHCIPort::Init2() 142 { 143 TRACE("AHCIPort::Init2 port %d\n", fIndex); 144 145 // start DMA engine 146 fRegs->cmd |= PORT_CMD_ST; 147 148 // enable interrupts 149 fRegs->ie = PORT_INT_MASK; 150 151 FlushPostedWrites(); 152 153 ResetPort(true); 154 155 TRACE("ie 0x%08" B_PRIx32 "\n", fRegs->ie); 156 TRACE("is 0x%08" B_PRIx32 "\n", fRegs->is); 157 TRACE("cmd 0x%08" B_PRIx32 "\n", fRegs->cmd); 158 TRACE("ssts 0x%08" B_PRIx32 "\n", fRegs->ssts); 159 TRACE("sctl 0x%08" B_PRIx32 "\n", fRegs->sctl); 160 TRACE("serr 0x%08" B_PRIx32 "\n", fRegs->serr); 161 TRACE("sact 0x%08" B_PRIx32 "\n", fRegs->sact); 162 TRACE("tfd 0x%08" B_PRIx32 "\n", fRegs->tfd); 163 164 fDevicePresent = (fRegs->ssts & 0xf) == 0x3; 165 166 return B_OK; 167 } 168 169 170 void 171 AHCIPort::Uninit() 172 { 173 TRACE("AHCIPort::Uninit port %d\n", fIndex); 174 175 // disable FIS receive 176 fRegs->cmd &= ~PORT_CMD_FER; 177 178 // wait for receive completion, up to 500ms 179 if (wait_until_clear(&fRegs->cmd, PORT_CMD_FR, 500000) < B_OK) { 180 TRACE("AHCIPort::Uninit port %d error FIS rx still running\n", fIndex); 181 } 182 183 // stop DMA engine 184 fRegs->cmd &= ~PORT_CMD_ST; 185 186 // wait for DMA completion 187 if (wait_until_clear(&fRegs->cmd, PORT_CMD_CR, 500000) < B_OK) { 188 TRACE("AHCIPort::Uninit port %d error DMA engine still running\n", 189 fIndex); 190 } 191 192 // disable interrupts 193 fRegs->ie = 0; 194 195 // clear pending interrupts 196 fRegs->is = fRegs->is; 197 198 // invalidate DMA addresses 199 fRegs->clb = 0; 200 fRegs->clbu = 0; 201 fRegs->fb = 0; 202 fRegs->fbu = 0; 203 204 delete_area(fArea); 205 } 206 207 208 void 209 AHCIPort::ResetDevice() 210 { 211 if (fRegs->cmd & PORT_CMD_ST) 212 TRACE("AHCIPort::ResetDevice PORT_CMD_ST set, behaviour undefined\n"); 213 214 // perform a hard reset 215 fRegs->sctl = (fRegs->sctl & ~0xf) | 1; 216 FlushPostedWrites(); 217 spin(1100); 218 fRegs->sctl &= ~0xf; 219 FlushPostedWrites(); 220 221 if (wait_until_set(&fRegs->ssts, 0x1, 100000) < B_OK) { 222 TRACE("AHCIPort::ResetDevice port %d no device detected\n", fIndex); 223 } 224 225 // clear error bits 226 fRegs->serr = fRegs->serr; 227 FlushPostedWrites(); 228 229 if (fRegs->ssts & 1) { 230 if (wait_until_set(&fRegs->ssts, 0x3, 500000) < B_OK) { 231 TRACE("AHCIPort::ResetDevice port %d device present but no phy " 232 "communication\n", fIndex); 233 } 234 } 235 236 // clear error bits 237 fRegs->serr = fRegs->serr; 238 FlushPostedWrites(); 239 } 240 241 242 243 status_t 244 AHCIPort::ResetPort(bool forceDeviceReset) 245 { 246 if (!fTestUnitReadyActive) 247 TRACE("AHCIPort::ResetPort port %d\n", fIndex); 248 249 // stop DMA engine 250 fRegs->cmd &= ~PORT_CMD_ST; 251 FlushPostedWrites(); 252 253 if (wait_until_clear(&fRegs->cmd, PORT_CMD_CR, 500000) < B_OK) { 254 TRACE("AHCIPort::ResetPort port %d error DMA engine doesn't stop\n", 255 fIndex); 256 } 257 258 bool deviceBusy = fRegs->tfd & (ATA_BSY | ATA_DRQ); 259 260 if (!fTestUnitReadyActive) { 261 TRACE("AHCIPort::ResetPort port %d, deviceBusy %d, " 262 "forceDeviceReset %d\n", fIndex, deviceBusy, forceDeviceReset); 263 } 264 265 if (deviceBusy || forceDeviceReset) 266 ResetDevice(); 267 268 // start DMA engine 269 fRegs->cmd |= PORT_CMD_ST; 270 FlushPostedWrites(); 271 272 return PostReset(); 273 } 274 275 276 status_t 277 AHCIPort::PostReset() 278 { 279 if (!fTestUnitReadyActive) 280 TRACE("AHCIPort::PostReset port %d\n", fIndex); 281 282 if ((fRegs->ssts & 0xf) != 0x3 || (fRegs->tfd & 0xff) == 0x7f) { 283 TRACE("AHCIPort::PostReset port %d: no device\n", fIndex); 284 return B_OK; 285 } 286 287 if ((fRegs->tfd & 0xff) == 0xff) 288 snooze(200000); 289 290 if ((fRegs->tfd & 0xff) == 0xff) { 291 TRACE("AHCIPort::PostReset port %d: invalid task file status 0xff\n", 292 fIndex); 293 return B_ERROR; 294 } 295 296 wait_until_clear(&fRegs->tfd, ATA_BSY, 31000000); 297 298 fIsATAPI = fRegs->sig == 0xeb140101; 299 300 if (fIsATAPI) 301 fRegs->cmd |= PORT_CMD_ATAPI; 302 else 303 fRegs->cmd &= ~PORT_CMD_ATAPI; 304 FlushPostedWrites(); 305 306 if (!fTestUnitReadyActive) { 307 TRACE("device signature 0x%08" B_PRIx32 " (%s)\n", fRegs->sig, 308 fRegs->sig == 0xeb140101 ? "ATAPI" : fRegs->sig == 0x00000101 309 ? "ATA" : "unknown"); 310 } 311 312 return B_OK; 313 } 314 315 316 void 317 AHCIPort::DumpD2HFis() 318 { 319 TRACE("D2H FIS:\n"); 320 TRACE(" DW0 %02x %02x %02x %02x\n", fFIS->rfis[3], fFIS->rfis[2], 321 fFIS->rfis[1], fFIS->rfis[0]); 322 TRACE(" DW1 %02x %02x %02x %02x\n", fFIS->rfis[7], fFIS->rfis[6], 323 fFIS->rfis[5], fFIS->rfis[4]); 324 TRACE(" DW2 %02x %02x %02x %02x\n", fFIS->rfis[11], fFIS->rfis[10], 325 fFIS->rfis[9], fFIS->rfis[8]); 326 TRACE(" DW3 %02x %02x %02x %02x\n", fFIS->rfis[15], fFIS->rfis[14], 327 fFIS->rfis[13], fFIS->rfis[12]); 328 TRACE(" DW4 %02x %02x %02x %02x\n", fFIS->rfis[19], fFIS->rfis[18], 329 fFIS->rfis[17], fFIS->rfis[16]); 330 } 331 332 333 void 334 AHCIPort::Interrupt() 335 { 336 uint32 is = fRegs->is; 337 fRegs->is = is; // clear interrupts 338 339 if (is & PORT_INT_ERROR) { 340 InterruptErrorHandler(is); 341 return; 342 } 343 344 uint32 ci = fRegs->ci; 345 346 RWTRACE("[%lld] %ld AHCIPort::Interrupt port %d, fCommandsActive 0x%08" 347 B_PRIx32 ", is 0x%08" B_PRIx32 ", ci 0x%08" B_PRIx32 "\n", 348 system_time(), find_thread(NULL), fIndex, fCommandsActive, is, ci); 349 350 acquire_spinlock(&fSpinlock); 351 if ((fCommandsActive & 1) && !(ci & 1)) { 352 fCommandsActive &= ~1; 353 release_sem_etc(fResponseSem, 1, B_DO_NOT_RESCHEDULE); 354 } 355 release_spinlock(&fSpinlock); 356 } 357 358 359 void 360 AHCIPort::InterruptErrorHandler(uint32 is) 361 { 362 uint32 ci = fRegs->ci; 363 364 if (!fTestUnitReadyActive) { 365 TRACE("AHCIPort::InterruptErrorHandler port %d, fCommandsActive 0x%08" 366 B_PRIx32 ", is 0x%08" B_PRIx32 ", ci 0x%08" B_PRIx32 "\n", fIndex, 367 fCommandsActive, is, ci); 368 369 TRACE("ssts 0x%08" B_PRIx32 "\n", fRegs->ssts); 370 TRACE("sctl 0x%08" B_PRIx32 "\n", fRegs->sctl); 371 TRACE("serr 0x%08" B_PRIx32 "\n", fRegs->serr); 372 TRACE("sact 0x%08" B_PRIx32 "\n", fRegs->sact); 373 } 374 375 // read and clear SError 376 uint32 serr = fRegs->serr; 377 fRegs->serr = serr; 378 379 if (is & PORT_INT_TFE) { 380 if (!fTestUnitReadyActive) 381 TRACE("Task File Error\n"); 382 383 fResetPort = true; 384 fError = true; 385 } 386 if (is & PORT_INT_HBF) { 387 TRACE("Host Bus Fatal Error\n"); 388 fResetPort = true; 389 fError = true; 390 } 391 if (is & PORT_INT_HBD) { 392 TRACE("Host Bus Data Error\n"); 393 fResetPort = true; 394 fError = true; 395 } 396 if (is & PORT_INT_IF) { 397 TRACE("Interface Fatal Error\n"); 398 fResetPort = true; 399 fError = true; 400 } 401 if (is & PORT_INT_INF) { 402 TRACE("Interface Non Fatal Error\n"); 403 } 404 if (is & PORT_INT_OF) { 405 TRACE("Overflow\n"); 406 fResetPort = true; 407 fError = true; 408 } 409 if (is & PORT_INT_IPM) { 410 TRACE("Incorrect Port Multiplier Status\n"); 411 } 412 if (is & PORT_INT_PRC) { 413 TRACE("PhyReady Change\n"); 414 // fResetPort = true; 415 } 416 if (is & PORT_INT_PC) { 417 TRACE("Port Connect Change\n"); 418 // fResetPort = true; 419 } 420 if (is & PORT_INT_UF) { 421 TRACE("Unknown FIS\n"); 422 fResetPort = true; 423 } 424 425 if (fError) { 426 acquire_spinlock(&fSpinlock); 427 if ((fCommandsActive & 1)) { 428 fCommandsActive &= ~1; 429 release_sem_etc(fResponseSem, 1, B_DO_NOT_RESCHEDULE); 430 } 431 release_spinlock(&fSpinlock); 432 } 433 } 434 435 436 status_t 437 AHCIPort::FillPrdTable(volatile prd* prdTable, int* prdCount, int prdMax, 438 const void* data, size_t dataSize) 439 { 440 int maxEntries = prdMax + 1; 441 physical_entry entries[maxEntries]; 442 uint32 entriesUsed = maxEntries; 443 444 status_t status = get_memory_map_etc(B_CURRENT_TEAM, data, dataSize, 445 entries, &entriesUsed); 446 if (status != B_OK) { 447 TRACE("AHCIPort::FillPrdTable get_memory_map() failed: %s\n", 448 strerror(status)); 449 return B_ERROR; 450 } 451 452 return FillPrdTable(prdTable, prdCount, prdMax, entries, entriesUsed, 453 dataSize); 454 } 455 456 457 status_t 458 AHCIPort::FillPrdTable(volatile prd* prdTable, int* prdCount, int prdMax, 459 const physical_entry* sgTable, int sgCount, size_t dataSize) 460 { 461 *prdCount = 0; 462 while (sgCount > 0 && dataSize > 0) { 463 size_t size = min_c(sgTable->size, dataSize); 464 phys_addr_t address = sgTable->address; 465 T_PORT(AHCIPortPrdTable(fController, fIndex, address, size)); 466 FLOW("FillPrdTable: sg-entry addr %#" B_PRIxPHYSADDR ", size %lu\n", 467 address, size); 468 if (address & 1) { 469 TRACE("AHCIPort::FillPrdTable: data alignment error\n"); 470 return B_ERROR; 471 } 472 dataSize -= size; 473 while (size > 0) { 474 size_t bytes = min_c(size, PRD_MAX_DATA_LENGTH); 475 if (*prdCount == prdMax) { 476 TRACE("AHCIPort::FillPrdTable: prd table exhausted\n"); 477 return B_ERROR; 478 } 479 FLOW("FillPrdTable: prd-entry %u, addr %p, size %lu\n", 480 *prdCount, address, bytes); 481 482 prdTable->dba = LO32(address); 483 prdTable->dbau = HI32(address); 484 prdTable->res = 0; 485 prdTable->dbc = bytes - 1; 486 *prdCount += 1; 487 prdTable++; 488 address = address + bytes; 489 size -= bytes; 490 } 491 sgTable++; 492 sgCount--; 493 } 494 if (*prdCount == 0) { 495 TRACE("AHCIPort::FillPrdTable: count is 0\n"); 496 return B_ERROR; 497 } 498 if (dataSize > 0) { 499 TRACE("AHCIPort::FillPrdTable: sg table %ld bytes too small\n", 500 dataSize); 501 return B_ERROR; 502 } 503 return B_OK; 504 } 505 506 507 void 508 AHCIPort::StartTransfer() 509 { 510 acquire_sem(fRequestSem); 511 } 512 513 514 status_t 515 AHCIPort::WaitForTransfer(int* tfd, bigtime_t timeout) 516 { 517 status_t result = acquire_sem_etc(fResponseSem, 1, B_RELATIVE_TIMEOUT, 518 timeout); 519 if (result < B_OK) { 520 cpu_status cpu = disable_interrupts(); 521 acquire_spinlock(&fSpinlock); 522 fCommandsActive &= ~1; 523 release_spinlock(&fSpinlock); 524 restore_interrupts(cpu); 525 526 result = B_TIMED_OUT; 527 } else if (fError) { 528 *tfd = fRegs->tfd; 529 result = B_ERROR; 530 fError = false; 531 } else { 532 *tfd = fRegs->tfd; 533 } 534 return result; 535 } 536 537 538 void 539 AHCIPort::FinishTransfer() 540 { 541 release_sem(fRequestSem); 542 } 543 544 545 void 546 AHCIPort::ScsiTestUnitReady(scsi_ccb* request) 547 { 548 TRACE("AHCIPort::ScsiTestUnitReady port %d\n", fIndex); 549 request->subsys_status = SCSI_REQ_CMP; 550 gSCSI->finished(request, 1); 551 } 552 553 554 void 555 AHCIPort::ScsiInquiry(scsi_ccb* request) 556 { 557 TRACE("AHCIPort::ScsiInquiry port %d\n", fIndex); 558 559 const scsi_cmd_inquiry* cmd = (const scsi_cmd_inquiry*)request->cdb; 560 scsi_res_inquiry scsiData; 561 ata_device_infoblock ataData; 562 563 ASSERT(sizeof(ataData) == 512); 564 565 if (cmd->evpd || cmd->page_code 566 || request->data_length < sizeof(scsiData)) { 567 TRACE("invalid request\n"); 568 request->subsys_status = SCSI_REQ_ABORTED; 569 gSCSI->finished(request, 1); 570 return; 571 } 572 573 sata_request sreq; 574 sreq.SetData(&ataData, sizeof(ataData)); 575 sreq.SetATACommand(fIsATAPI 576 ? ATA_COMMAND_IDENTIFY_PACKET_DEVICE : ATA_COMMAND_IDENTIFY_DEVICE); 577 ExecuteSataRequest(&sreq); 578 sreq.WaitForCompletion(); 579 580 if ((sreq.CompletionStatus() & ATA_ERR) != 0) { 581 TRACE("identify device failed\n"); 582 request->subsys_status = SCSI_REQ_CMP_ERR; 583 gSCSI->finished(request, 1); 584 return; 585 } 586 587 /* 588 uint8* data = (uint8*)&ataData; 589 for (int i = 0; i < 512; i += 8) { 590 TRACE(" %02x %02x %02x %02x %02x %02x %02x %02x\n", data[i], data[i+1], 591 data[i+2], data[i+3], data[i+4], data[i+5], data[i+6], data[i+7]); 592 } 593 */ 594 595 scsiData.device_type = fIsATAPI 596 ? ataData.word_0.atapi.command_packet_set : scsi_dev_direct_access; 597 scsiData.device_qualifier = scsi_periph_qual_connected; 598 scsiData.device_type_modifier = 0; 599 scsiData.removable_medium = ataData.word_0.ata.removable_media_device; 600 scsiData.ansi_version = 2; 601 scsiData.ecma_version = 0; 602 scsiData.iso_version = 0; 603 scsiData.response_data_format = 2; 604 scsiData.term_iop = false; 605 scsiData.additional_length = sizeof(scsi_res_inquiry) - 4; 606 scsiData.soft_reset = false; 607 scsiData.cmd_queue = false; 608 scsiData.linked = false; 609 scsiData.sync = false; 610 scsiData.write_bus16 = true; 611 scsiData.write_bus32 = false; 612 scsiData.relative_address = false; 613 614 if (!fIsATAPI) { 615 fSectorCount = ataData.SectorCount(fUse48BitCommands, true); 616 fSectorSize = ataData.SectorSize(); 617 fTrimSupported = ataData.data_set_management_support; 618 fMaxTrimRangeBlocks = B_LENDIAN_TO_HOST_INT16( 619 ataData.max_data_set_management_lba_range_blocks); 620 TRACE("lba %d, lba48 %d, fUse48BitCommands %d, sectors %" B_PRIu32 621 ", sectors48 %" B_PRIu64 ", size %" B_PRIu64 "\n", 622 ataData.dma_supported != 0, ataData.lba48_supported != 0, 623 fUse48BitCommands, ataData.lba_sector_count, 624 ataData.lba48_sector_count, fSectorCount * fSectorSize); 625 if (fTrimSupported) { 626 if (fMaxTrimRangeBlocks == 0) 627 fMaxTrimRangeBlocks = 1; 628 629 bool deterministic = ataData.supports_deterministic_read_after_trim; 630 TRACE("trim supported, %" B_PRIu32 " ranges blocks, reads are " 631 "%sdeterministic%s.\n", fMaxTrimRangeBlocks, 632 deterministic ? "" : "non-", deterministic 633 ? (ataData.supports_read_zero_after_trim 634 ? ", zero" : ", random") : ""); 635 } 636 } 637 638 #if 0 639 if (fSectorCount < 0x0fffffff) { 640 TRACE("disabling 48 bit commands\n"); 641 fUse48BitCommands = 0; 642 } 643 #endif 644 645 char modelNumber[sizeof(ataData.model_number) + 1]; 646 char serialNumber[sizeof(ataData.serial_number) + 1]; 647 char firmwareRev[sizeof(ataData.firmware_revision) + 1]; 648 649 strlcpy(modelNumber, ataData.model_number, sizeof(modelNumber)); 650 strlcpy(serialNumber, ataData.serial_number, sizeof(serialNumber)); 651 strlcpy(firmwareRev, ataData.firmware_revision, sizeof(firmwareRev)); 652 653 swap_words(modelNumber, sizeof(modelNumber) - 1); 654 swap_words(serialNumber, sizeof(serialNumber) - 1); 655 swap_words(firmwareRev, sizeof(firmwareRev) - 1); 656 657 TRACE("model number: %s\n", modelNumber); 658 TRACE("serial number: %s\n", serialNumber); 659 TRACE("firmware rev.: %s\n", firmwareRev); 660 661 // There's not enough space to fit all of the data in. ATA has 40 bytes for 662 // the model number, 20 for the serial number and another 8 for the 663 // firmware revision. SCSI has room for 8 for vendor ident, 16 for product 664 // ident and another 4 for product revision. We just try and fit in as much 665 // as possible of the model number into the vendor and product ident fields 666 // and put a little of the serial number into the product revision field. 667 memcpy(scsiData.vendor_ident, modelNumber, sizeof(scsiData.vendor_ident)); 668 memcpy(scsiData.product_ident, modelNumber + 8, 669 sizeof(scsiData.product_ident)); 670 memcpy(scsiData.product_rev, serialNumber, sizeof(scsiData.product_rev)); 671 672 if (sg_memcpy(request->sg_list, request->sg_count, &scsiData, 673 sizeof(scsiData)) < B_OK) { 674 request->subsys_status = SCSI_DATA_RUN_ERR; 675 } else { 676 request->subsys_status = SCSI_REQ_CMP; 677 request->data_resid = request->data_length - sizeof(scsiData); 678 } 679 gSCSI->finished(request, 1); 680 } 681 682 683 void 684 AHCIPort::ScsiSynchronizeCache(scsi_ccb* request) 685 { 686 //TRACE("AHCIPort::ScsiSynchronizeCache port %d\n", fIndex); 687 688 sata_request* sreq = new(std::nothrow) sata_request(request); 689 if (sreq == NULL) { 690 TRACE("out of memory when allocating sync request\n"); 691 request->subsys_status = SCSI_REQ_ABORTED; 692 gSCSI->finished(request, 1); 693 return; 694 } 695 696 sreq->SetATACommand(fUse48BitCommands 697 ? ATA_COMMAND_FLUSH_CACHE_EXT : ATA_COMMAND_FLUSH_CACHE); 698 ExecuteSataRequest(sreq); 699 } 700 701 702 void 703 AHCIPort::ScsiReadCapacity(scsi_ccb* request) 704 { 705 TRACE("AHCIPort::ScsiReadCapacity port %d\n", fIndex); 706 707 const scsi_cmd_read_capacity* cmd 708 = (const scsi_cmd_read_capacity*)request->cdb; 709 scsi_res_read_capacity scsiData; 710 711 if (cmd->pmi || cmd->lba || request->data_length < sizeof(scsiData)) { 712 TRACE("invalid request\n"); 713 request->subsys_status = SCSI_REQ_ABORTED; 714 gSCSI->finished(request, 1); 715 return; 716 } 717 718 TRACE("SectorSize %" B_PRIu32 ", SectorCount 0x%" B_PRIx64 "\n", 719 fSectorSize, fSectorCount); 720 721 scsiData.block_size = B_HOST_TO_BENDIAN_INT32(fSectorSize); 722 723 if (fSectorCount <= 0xffffffff) 724 scsiData.lba = B_HOST_TO_BENDIAN_INT32(fSectorCount - 1); 725 else 726 scsiData.lba = 0xffffffff; 727 728 if (sg_memcpy(request->sg_list, request->sg_count, &scsiData, 729 sizeof(scsiData)) < B_OK) { 730 request->subsys_status = SCSI_DATA_RUN_ERR; 731 } else { 732 request->subsys_status = SCSI_REQ_CMP; 733 request->data_resid = request->data_length - sizeof(scsiData); 734 } 735 gSCSI->finished(request, 1); 736 } 737 738 739 void 740 AHCIPort::ScsiReadCapacity16(scsi_ccb* request) 741 { 742 TRACE("AHCIPort::ScsiReadCapacity16 port %d\n", fIndex); 743 744 scsi_res_read_capacity_long scsiData; 745 746 TRACE("SectorSize %" B_PRIu32 ", SectorCount 0x%" B_PRIx64 "\n", 747 fSectorSize, fSectorCount); 748 749 scsiData.block_size = B_HOST_TO_BENDIAN_INT32(fSectorSize); 750 scsiData.lba = B_HOST_TO_BENDIAN_INT64(fSectorCount - 1); 751 752 if (sg_memcpy(request->sg_list, request->sg_count, &scsiData, 753 sizeof(scsiData)) < B_OK) { 754 request->subsys_status = SCSI_DATA_RUN_ERR; 755 } else { 756 request->subsys_status = SCSI_REQ_CMP; 757 request->data_resid = request->data_length - sizeof(scsiData); 758 } 759 gSCSI->finished(request, 1); 760 } 761 762 763 void 764 AHCIPort::ScsiReadWrite(scsi_ccb* request, uint64 lba, size_t sectorCount, 765 bool isWrite) 766 { 767 RWTRACE("[%lld] %ld ScsiReadWrite: position %llu, size %lu, isWrite %d\n", 768 system_time(), find_thread(NULL), lba * 512, sectorCount * 512, 769 isWrite); 770 771 #if 0 772 if (isWrite) { 773 TRACE("write request ignored\n"); 774 request->subsys_status = SCSI_REQ_CMP; 775 request->data_resid = 0; 776 gSCSI->finished(request, 1); 777 return; 778 } 779 #endif 780 781 ASSERT(request->data_length == sectorCount * 512); 782 sata_request* sreq = new(std::nothrow) sata_request(request); 783 if (sreq == NULL) { 784 TRACE("out of memory when allocating read/write request\n"); 785 request->subsys_status = SCSI_REQ_ABORTED; 786 gSCSI->finished(request, 1); 787 return; 788 } 789 790 if (fUse48BitCommands) { 791 if (sectorCount > 65536) { 792 panic("ahci: ScsiReadWrite length too large, %lu sectors", 793 sectorCount); 794 } 795 if (lba > MAX_SECTOR_LBA_48) 796 panic("achi: ScsiReadWrite position too large for 48-bit LBA\n"); 797 sreq->SetATA48Command( 798 isWrite ? ATA_COMMAND_WRITE_DMA_EXT : ATA_COMMAND_READ_DMA_EXT, 799 lba, sectorCount); 800 } else { 801 if (sectorCount > 256) { 802 panic("ahci: ScsiReadWrite length too large, %lu sectors", 803 sectorCount); 804 } 805 if (lba > MAX_SECTOR_LBA_28) 806 panic("achi: ScsiReadWrite position too large for normal LBA\n"); 807 sreq->SetATA28Command(isWrite 808 ? ATA_COMMAND_WRITE_DMA : ATA_COMMAND_READ_DMA, lba, sectorCount); 809 } 810 811 ExecuteSataRequest(sreq, isWrite); 812 } 813 814 815 void 816 AHCIPort::ScsiUnmap(scsi_ccb* request, scsi_unmap_parameter_list* unmapBlocks) 817 { 818 // Determine how many blocks are supposed to be trimmed in total 819 uint32 scsiRangeCount = B_BENDIAN_TO_HOST_INT16( 820 unmapBlocks->block_data_length) / sizeof(scsi_unmap_block_descriptor); 821 822 dprintf("TRIM SCSI:\n"); 823 for (uint32 i = 0; i < scsiRangeCount; i++) { 824 dprintf("[%3" B_PRIu32 "] %" B_PRIu64 " : %" B_PRIu32 "\n", i, 825 (uint64)B_BENDIAN_TO_HOST_INT64(unmapBlocks->blocks[i].lba), 826 (uint32)B_BENDIAN_TO_HOST_INT32(unmapBlocks->blocks[i].block_count)); 827 } 828 829 uint32 scsiIndex = 0; 830 uint32 scsiLastBlocks = 0; 831 uint32 maxLBARangeCount = fMaxTrimRangeBlocks * 512 / 8; 832 // 512 bytes per range block, 8 bytes per range 833 834 // Split the SCSI ranges into ATA ranges as large as allowed. 835 // We assume that the SCSI unmap ranges cannot be merged together 836 837 while (scsiIndex < scsiRangeCount) { 838 // Determine how many LBA ranges we need for the next chunk 839 uint32 lbaRangeCount = 0; 840 for (uint32 i = scsiIndex; i < scsiRangeCount; i++) { 841 uint32 scsiBlocks = B_BENDIAN_TO_HOST_INT32( 842 unmapBlocks->blocks[i].block_count); 843 if (scsiBlocks == 0) 844 break; 845 if (i == scsiIndex) 846 scsiBlocks -= scsiLastBlocks; 847 848 lbaRangeCount += (scsiBlocks + 65534) / 65535; 849 if (lbaRangeCount >= maxLBARangeCount) { 850 lbaRangeCount = maxLBARangeCount; 851 break; 852 } 853 } 854 if (lbaRangeCount == 0) 855 break; 856 857 uint32 lbaRangesSize = lbaRangeCount * sizeof(uint64); 858 uint64* lbaRanges = (uint64*)malloc(lbaRangesSize); 859 if (lbaRanges == NULL) { 860 TRACE("out of memory when allocating %" B_PRIu32 " unmap ranges\n", 861 lbaRangeCount); 862 request->subsys_status = SCSI_REQ_ABORTED; 863 gSCSI->finished(request, 1); 864 return; 865 } 866 867 MemoryDeleter deleter(lbaRanges); 868 869 for (uint32 lbaIndex = 0; 870 scsiIndex < scsiRangeCount && lbaIndex < lbaRangeCount;) { 871 uint64 scsiOffset = B_BENDIAN_TO_HOST_INT64( 872 unmapBlocks->blocks[scsiIndex].lba) + scsiLastBlocks; 873 uint32 scsiBlocksLeft = B_BENDIAN_TO_HOST_INT32( 874 unmapBlocks->blocks[scsiIndex].block_count) - scsiLastBlocks; 875 876 if (scsiBlocksLeft == 0) { 877 // Ignore the rest of the ranges (they are empty) 878 scsiIndex = scsiRangeCount; 879 break; 880 } 881 882 while (scsiBlocksLeft > 0 && lbaIndex < lbaRangeCount) { 883 uint16 blocks = scsiBlocksLeft > 65535 884 ? 65535 : (uint16)scsiBlocksLeft; 885 lbaRanges[lbaIndex++] = B_HOST_TO_LENDIAN_INT64( 886 ((uint64)blocks << 48) | scsiOffset); 887 888 scsiOffset += blocks; 889 scsiLastBlocks += blocks; 890 scsiBlocksLeft -= blocks; 891 } 892 893 if (scsiBlocksLeft == 0) { 894 scsiLastBlocks = 0; 895 scsiIndex++; 896 } 897 } 898 899 dprintf("TRIM AHCI:\n"); 900 for (uint32 i = 0; i < lbaRangeCount; i++) { 901 uint64 value = B_HOST_TO_LENDIAN_INT64(lbaRanges[i]); 902 dprintf("[%3" B_PRIu32 "] %" B_PRIu64 " : %" B_PRIu64 "\n", i, 903 value & (((uint64)1 << 48) - 1), value >> 48); 904 } 905 906 sata_request sreq; 907 sreq.SetATA48Command(ATA_COMMAND_DATA_SET_MANAGEMENT, 0, 908 (lbaRangesSize + 511) / 512); 909 sreq.SetFeature(1); 910 sreq.SetData(lbaRanges, lbaRangesSize); 911 912 ExecuteSataRequest(&sreq); 913 sreq.WaitForCompletion(); 914 915 if ((sreq.CompletionStatus() & ATA_ERR) != 0) { 916 TRACE("trim failed (%" B_PRIu32 " ranges)!\n", lbaRangeCount); 917 request->subsys_status = SCSI_REQ_CMP_ERR; 918 } else 919 request->subsys_status = SCSI_REQ_CMP; 920 } 921 922 request->data_resid = 0; 923 request->device_status = SCSI_STATUS_GOOD; 924 gSCSI->finished(request, 1); 925 } 926 927 928 void 929 AHCIPort::ExecuteSataRequest(sata_request* request, bool isWrite) 930 { 931 FLOW("ExecuteAtaRequest port %d\n", fIndex); 932 933 StartTransfer(); 934 935 int prdEntrys; 936 937 if (request->CCB() && request->CCB()->data_length) { 938 FillPrdTable(fPRDTable, &prdEntrys, PRD_TABLE_ENTRY_COUNT, 939 request->CCB()->sg_list, request->CCB()->sg_count, 940 request->CCB()->data_length); 941 } else if (request->Data() && request->Size()) { 942 FillPrdTable(fPRDTable, &prdEntrys, PRD_TABLE_ENTRY_COUNT, 943 request->Data(), request->Size()); 944 } else 945 prdEntrys = 0; 946 947 FLOW("prdEntrys %d\n", prdEntrys); 948 949 fCommandList->prdtl_flags_cfl = 0; 950 fCommandList->cfl = 5; // 20 bytes, length in DWORDS 951 memcpy((char*)fCommandTable->cfis, request->FIS(), 20); 952 953 fTestUnitReadyActive = request->IsTestUnitReady(); 954 if (request->IsATAPI()) { 955 // ATAPI PACKET is a 12 or 16 byte SCSI command 956 memset((char*)fCommandTable->acmd, 0, 32); 957 memcpy((char*)fCommandTable->acmd, request->CCB()->cdb, 958 request->CCB()->cdb_length); 959 fCommandList->a = 1; 960 } 961 962 if (isWrite) 963 fCommandList->w = 1; 964 fCommandList->prdtl = prdEntrys; 965 fCommandList->prdbc = 0; 966 967 if (wait_until_clear(&fRegs->tfd, ATA_BSY | ATA_DRQ, 1000000) < B_OK) { 968 TRACE("ExecuteAtaRequest port %d: device is busy\n", fIndex); 969 ResetPort(); 970 FinishTransfer(); 971 request->Abort(); 972 return; 973 } 974 975 cpu_status cpu = disable_interrupts(); 976 acquire_spinlock(&fSpinlock); 977 fCommandsActive |= 1; 978 fRegs->ci = 1; 979 FlushPostedWrites(); 980 release_spinlock(&fSpinlock); 981 restore_interrupts(cpu); 982 983 int tfd; 984 status_t status = WaitForTransfer(&tfd, 20000000); 985 986 FLOW("tfd %#x\n", tfd); 987 FLOW("prdbc %ld\n", fCommandList->prdbc); 988 FLOW("ci 0x%08" B_PRIx32 "\n", fRegs->ci); 989 FLOW("is 0x%08" B_PRIx32 "\n", fRegs->is); 990 FLOW("serr 0x%08" B_PRIx32 "\n", fRegs->serr); 991 992 /* 993 TRACE("ci 0x%08" B_PRIx32 "\n", fRegs->ci); 994 TRACE("ie 0x%08" B_PRIx32 "\n", fRegs->ie); 995 TRACE("is 0x%08" B_PRIx32 "\n", fRegs->is); 996 TRACE("cmd 0x%08" B_PRIx32 "\n", fRegs->cmd); 997 TRACE("ssts 0x%08" B_PRIx32 "\n", fRegs->ssts); 998 TRACE("sctl 0x%08" B_PRIx32 "\n", fRegs->sctl); 999 TRACE("serr 0x%08" B_PRIx32 "\n", fRegs->serr); 1000 TRACE("sact 0x%08" B_PRIx32 "\n", fRegs->sact); 1001 TRACE("tfd 0x%08" B_PRIx32 "\n", fRegs->tfd); 1002 */ 1003 1004 if (fResetPort || status == B_TIMED_OUT) { 1005 fResetPort = false; 1006 ResetPort(); 1007 } 1008 1009 size_t bytesTransfered = fCommandList->prdbc; 1010 1011 FinishTransfer(); 1012 1013 if (status == B_TIMED_OUT) { 1014 TRACE("ExecuteAtaRequest port %d: device timeout\n", fIndex); 1015 request->Abort(); 1016 return; 1017 } 1018 1019 request->Finish(tfd, bytesTransfered); 1020 } 1021 1022 1023 void 1024 AHCIPort::ScsiExecuteRequest(scsi_ccb* request) 1025 { 1026 // TRACE("AHCIPort::ScsiExecuteRequest port %d, opcode 0x%02x, length %u\n", fIndex, request->cdb[0], request->cdb_length); 1027 1028 if (fIsATAPI) { 1029 bool isWrite = false; 1030 switch (request->flags & SCSI_DIR_MASK) { 1031 case SCSI_DIR_NONE: 1032 ASSERT(request->data_length == 0); 1033 break; 1034 case SCSI_DIR_IN: 1035 ASSERT(request->data_length > 0); 1036 break; 1037 case SCSI_DIR_OUT: 1038 isWrite = true; 1039 ASSERT(request->data_length > 0); 1040 break; 1041 default: 1042 panic("CDB has invalid direction mask"); 1043 } 1044 1045 // TRACE("AHCIPort::ScsiExecuteRequest ATAPI: port %d, opcode 0x%02x, length %u\n", fIndex, request->cdb[0], request->cdb_length); 1046 1047 sata_request* sreq = new(std::nothrow) sata_request(request); 1048 if (sreq == NULL) { 1049 TRACE("out of memory when allocating atapi request\n"); 1050 request->subsys_status = SCSI_REQ_ABORTED; 1051 gSCSI->finished(request, 1); 1052 return; 1053 } 1054 1055 sreq->SetATAPICommand(request->data_length); 1056 // uint8* data = (uint8*) sreq->ccb()->cdb; 1057 // for (int i = 0; i < 16; i += 8) { 1058 // TRACE(" %02x %02x %02x %02x %02x %02x %02x %02x\n", data[i], data[i+1], data[i+2], data[i+3], data[i+4], data[i+5], data[i+6], data[i+7]); 1059 // } 1060 ExecuteSataRequest(sreq, isWrite); 1061 return; 1062 } 1063 1064 if (request->cdb[0] == SCSI_OP_REQUEST_SENSE) { 1065 panic("ahci: SCSI_OP_REQUEST_SENSE not yet supported\n"); 1066 return; 1067 } 1068 1069 if (!fDevicePresent) { 1070 TRACE("no device present on port %d\n", fIndex); 1071 request->subsys_status = SCSI_DEV_NOT_THERE; 1072 gSCSI->finished(request, 1); 1073 return; 1074 } 1075 1076 request->subsys_status = SCSI_REQ_CMP; 1077 1078 switch (request->cdb[0]) { 1079 case SCSI_OP_TEST_UNIT_READY: 1080 ScsiTestUnitReady(request); 1081 break; 1082 case SCSI_OP_INQUIRY: 1083 ScsiInquiry(request); 1084 break; 1085 case SCSI_OP_READ_CAPACITY: 1086 ScsiReadCapacity(request); 1087 break; 1088 case SCSI_OP_SERVICE_ACTION_IN: 1089 if ((request->cdb[1] & 0x1f) == SCSI_SAI_READ_CAPACITY_16) 1090 ScsiReadCapacity16(request); 1091 else { 1092 request->subsys_status = SCSI_REQ_INVALID; 1093 gSCSI->finished(request, 1); 1094 } 1095 break; 1096 case SCSI_OP_SYNCHRONIZE_CACHE: 1097 ScsiSynchronizeCache(request); 1098 break; 1099 case SCSI_OP_READ_6: 1100 case SCSI_OP_WRITE_6: 1101 { 1102 const scsi_cmd_rw_6* cmd = (const scsi_cmd_rw_6*)request->cdb; 1103 uint32 position = ((uint32)cmd->high_lba << 16) 1104 | ((uint32)cmd->mid_lba << 8) | (uint32)cmd->low_lba; 1105 size_t length = cmd->length != 0 ? cmd->length : 256; 1106 bool isWrite = request->cdb[0] == SCSI_OP_WRITE_6; 1107 ScsiReadWrite(request, position, length, isWrite); 1108 break; 1109 } 1110 case SCSI_OP_READ_10: 1111 case SCSI_OP_WRITE_10: 1112 { 1113 const scsi_cmd_rw_10* cmd = (const scsi_cmd_rw_10*)request->cdb; 1114 uint32 position = B_BENDIAN_TO_HOST_INT32(cmd->lba); 1115 size_t length = B_BENDIAN_TO_HOST_INT16(cmd->length); 1116 bool isWrite = request->cdb[0] == SCSI_OP_WRITE_10; 1117 if (length) { 1118 ScsiReadWrite(request, position, length, isWrite); 1119 } else { 1120 TRACE("AHCIPort::ScsiExecuteRequest error: transfer without " 1121 "data!\n"); 1122 request->subsys_status = SCSI_REQ_INVALID; 1123 gSCSI->finished(request, 1); 1124 } 1125 break; 1126 } 1127 case SCSI_OP_READ_12: 1128 case SCSI_OP_WRITE_12: 1129 { 1130 const scsi_cmd_rw_12* cmd = (const scsi_cmd_rw_12*)request->cdb; 1131 uint32 position = B_BENDIAN_TO_HOST_INT32(cmd->lba); 1132 size_t length = B_BENDIAN_TO_HOST_INT32(cmd->length); 1133 bool isWrite = request->cdb[0] == SCSI_OP_WRITE_12; 1134 if (length) { 1135 ScsiReadWrite(request, position, length, isWrite); 1136 } else { 1137 TRACE("AHCIPort::ScsiExecuteRequest error: transfer without " 1138 "data!\n"); 1139 request->subsys_status = SCSI_REQ_INVALID; 1140 gSCSI->finished(request, 1); 1141 } 1142 break; 1143 } 1144 case SCSI_OP_READ_16: 1145 case SCSI_OP_WRITE_16: 1146 { 1147 const scsi_cmd_rw_16* cmd = (const scsi_cmd_rw_16*)request->cdb; 1148 uint64 position = B_BENDIAN_TO_HOST_INT64(cmd->lba); 1149 size_t length = B_BENDIAN_TO_HOST_INT32(cmd->length); 1150 bool isWrite = request->cdb[0] == SCSI_OP_WRITE_16; 1151 if (length) { 1152 ScsiReadWrite(request, position, length, isWrite); 1153 } else { 1154 TRACE("AHCIPort::ScsiExecuteRequest error: transfer without " 1155 "data!\n"); 1156 request->subsys_status = SCSI_REQ_INVALID; 1157 gSCSI->finished(request, 1); 1158 } 1159 break; 1160 } 1161 case SCSI_OP_UNMAP: 1162 { 1163 const scsi_cmd_unmap* cmd = (const scsi_cmd_unmap*)request->cdb; 1164 1165 if (!fTrimSupported) { 1166 TRACE("%s port %d: unsupported request opcode 0x%02x\n", 1167 __func__, fIndex, request->cdb[0]); 1168 request->subsys_status = SCSI_REQ_ABORTED; 1169 gSCSI->finished(request, 1); 1170 break; 1171 } 1172 1173 scsi_unmap_parameter_list* unmapBlocks 1174 = (scsi_unmap_parameter_list*)request->data; 1175 if (unmapBlocks == NULL 1176 || B_BENDIAN_TO_HOST_INT16(cmd->length) != request->data_length 1177 || B_BENDIAN_TO_HOST_INT16(unmapBlocks->data_length) 1178 != request->data_length - 1) { 1179 TRACE("%s port %d: invalid unmap parameter data length\n", 1180 __func__, fIndex); 1181 request->subsys_status = SCSI_REQ_ABORTED; 1182 gSCSI->finished(request, 1); 1183 } else { 1184 ScsiUnmap(request, unmapBlocks); 1185 } 1186 break; 1187 } 1188 default: 1189 TRACE("AHCIPort::ScsiExecuteRequest port %d unsupported request " 1190 "opcode 0x%02x\n", fIndex, request->cdb[0]); 1191 request->subsys_status = SCSI_REQ_ABORTED; 1192 gSCSI->finished(request, 1); 1193 } 1194 } 1195 1196 1197 uchar 1198 AHCIPort::ScsiAbortRequest(scsi_ccb* request) 1199 { 1200 return SCSI_REQ_CMP; 1201 } 1202 1203 1204 uchar 1205 AHCIPort::ScsiTerminateRequest(scsi_ccb* request) 1206 { 1207 return SCSI_REQ_CMP; 1208 } 1209 1210 1211 uchar 1212 AHCIPort::ScsiResetDevice() 1213 { 1214 return SCSI_REQ_CMP; 1215 } 1216 1217 1218 void 1219 AHCIPort::ScsiGetRestrictions(bool* isATAPI, bool* noAutoSense, 1220 uint32* maxBlocks) 1221 { 1222 *isATAPI = fIsATAPI; 1223 *noAutoSense = fIsATAPI; // emulated auto sense for ATA, but not ATAPI 1224 *maxBlocks = fUse48BitCommands ? 65536 : 256; 1225 TRACE("AHCIPort::ScsiGetRestrictions port %d: isATAPI %d, noAutoSense %d, " 1226 "maxBlocks %" B_PRIu32 "\n", fIndex, *isATAPI, *noAutoSense, 1227 *maxBlocks); 1228 } 1229