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