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