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