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