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