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