1 /* 2 * PROJECT: ReactOS Kernel 3 * LICENSE: GNU GPLv2 only as published by the Free Software Foundation 4 * PURPOSE: To Implement AHCI Miniport driver targeting storport NT 5.2 5 * PROGRAMMERS: Aman Priyadarshi (aman.eureka@gmail.com) 6 */ 7 8 #include "storahci.h" 9 10 /** 11 * @name AhciPortInitialize 12 * @implemented 13 * 14 * Initialize port by setting up PxCLB & PxFB Registers 15 * 16 * @param PortExtension 17 * 18 * @return 19 * Return true if intialization was successful 20 */ 21 BOOLEAN 22 NTAPI 23 AhciPortInitialize ( 24 __in PVOID DeviceExtension 25 ) 26 { 27 PAHCI_PORT_EXTENSION PortExtension; 28 AHCI_PORT_CMD cmd; 29 PAHCI_MEMORY_REGISTERS abar; 30 ULONG mappedLength, portNumber, ticks; 31 PAHCI_ADAPTER_EXTENSION adapterExtension; 32 STOR_PHYSICAL_ADDRESS commandListPhysical, receivedFISPhysical; 33 34 AhciDebugPrint("AhciPortInitialize()\n"); 35 36 PortExtension = (PAHCI_PORT_EXTENSION)DeviceExtension; 37 adapterExtension = PortExtension->AdapterExtension; 38 abar = adapterExtension->ABAR_Address; 39 portNumber = PortExtension->PortNumber; 40 41 NT_ASSERT(abar != NULL); 42 NT_ASSERT(portNumber < adapterExtension->PortCount); 43 44 PortExtension->Port = &abar->PortList[portNumber]; 45 46 commandListPhysical = StorPortGetPhysicalAddress(adapterExtension, 47 NULL, 48 PortExtension->CommandList, 49 &mappedLength); 50 51 if ((mappedLength == 0) || ((commandListPhysical.LowPart % 1024) != 0)) 52 { 53 AhciDebugPrint("\tcommandListPhysical mappedLength:%d\n", mappedLength); 54 return FALSE; 55 } 56 57 receivedFISPhysical = StorPortGetPhysicalAddress(adapterExtension, 58 NULL, 59 PortExtension->ReceivedFIS, 60 &mappedLength); 61 62 if ((mappedLength == 0) || ((receivedFISPhysical.LowPart % 256) != 0)) 63 { 64 AhciDebugPrint("\treceivedFISPhysical mappedLength:%d\n", mappedLength); 65 return FALSE; 66 } 67 68 // Ensure that the controller is not in the running state by reading and examining each 69 // implemented port’s PxCMD register. If PxCMD.ST, PxCMD.CR, PxCMD.FRE and 70 // PxCMD.FR are all cleared, the port is in an idle state. Otherwise, the port is not idle and 71 // should be placed in the idle state prior to manipulating HBA and port specific registers. 72 // System software places a port into the idle state by clearing PxCMD.ST and waiting for 73 // PxCMD.CR to return ‘0’ when read. Software should wait at least 500 milliseconds for 74 // this to occur. If PxCMD.FRE is set to ‘1’, software should clear it to ‘0’ and wait at least 75 // 500 milliseconds for PxCMD.FR to return ‘0’ when read. If PxCMD.CR or PxCMD.FR do 76 // not clear to ‘0’ correctly, then software may attempt a port reset or a full HBA reset to recove 77 78 // TODO: Check if port is in idle state or not, if not then restart port 79 cmd.Status = StorPortReadRegisterUlong(adapterExtension, &PortExtension->Port->CMD); 80 if ((cmd.FR != 0) || (cmd.CR != 0) || (cmd.FRE != 0) || (cmd.ST != 0)) 81 { 82 cmd.ST = 0; 83 cmd.FRE = 0; 84 85 ticks = 3; 86 do 87 { 88 StorPortStallExecution(50000); 89 cmd.Status = StorPortReadRegisterUlong(adapterExtension, &PortExtension->Port->CMD); 90 if (ticks == 0) 91 { 92 AhciDebugPrint("\tAttempt to reset port failed: %x\n", cmd); 93 return FALSE; 94 } 95 ticks--; 96 } 97 while(cmd.CR != 0 || cmd.FR != 0); 98 } 99 100 // 10.1.2 For each implemented port, system software shall allocate memory for and program: 101 // ? PxCLB and PxCLBU (if CAP.S64A is set to ‘1’) 102 // ? PxFB and PxFBU (if CAP.S64A is set to ‘1’) 103 // Note: Assuming 32bit support only 104 StorPortWriteRegisterUlong(adapterExtension, &PortExtension->Port->CLB, commandListPhysical.LowPart); 105 if (IsAdapterCAPS64(adapterExtension->CAP)) 106 { 107 StorPortWriteRegisterUlong(adapterExtension, &PortExtension->Port->CLBU, commandListPhysical.HighPart); 108 } 109 110 StorPortWriteRegisterUlong(adapterExtension, &PortExtension->Port->FB, receivedFISPhysical.LowPart); 111 if (IsAdapterCAPS64(adapterExtension->CAP)) 112 { 113 StorPortWriteRegisterUlong(adapterExtension, &PortExtension->Port->FBU, receivedFISPhysical.HighPart); 114 } 115 116 PortExtension->IdentifyDeviceDataPhysicalAddress = StorPortGetPhysicalAddress(adapterExtension, 117 NULL, 118 PortExtension->IdentifyDeviceData, 119 &mappedLength); 120 121 // set device power state flag to D0 122 PortExtension->DevicePowerState = StorPowerDeviceD0; 123 124 // clear pending interrupts 125 StorPortWriteRegisterUlong(adapterExtension, &PortExtension->Port->SERR, (ULONG)~0); 126 StorPortWriteRegisterUlong(adapterExtension, &PortExtension->Port->IS, (ULONG)~0); 127 StorPortWriteRegisterUlong(adapterExtension, adapterExtension->IS, (1 << PortExtension->PortNumber)); 128 129 return TRUE; 130 }// -- AhciPortInitialize(); 131 132 /** 133 * @name AhciAllocateResourceForAdapter 134 * @implemented 135 * 136 * Allocate memory from poll for required pointers 137 * 138 * @param AdapterExtension 139 * @param ConfigInfo 140 * 141 * @return 142 * return TRUE if allocation was successful 143 */ 144 BOOLEAN 145 AhciAllocateResourceForAdapter ( 146 __in PAHCI_ADAPTER_EXTENSION AdapterExtension, 147 __in PPORT_CONFIGURATION_INFORMATION ConfigInfo 148 ) 149 { 150 PCHAR nonCachedExtension, tmp; 151 ULONG index, NCS, AlignedNCS; 152 ULONG portCount, portImplemented, nonCachedExtensionSize; 153 PAHCI_PORT_EXTENSION PortExtension; 154 155 AhciDebugPrint("AhciAllocateResourceForAdapter()\n"); 156 157 NCS = AHCI_Global_Port_CAP_NCS(AdapterExtension->CAP); 158 AlignedNCS = ROUND_UP(NCS, 8); 159 160 // get port count -- Number of set bits in `AdapterExtension->PortImplemented` 161 portCount = 0; 162 portImplemented = AdapterExtension->PortImplemented; 163 164 NT_ASSERT(portImplemented != 0); 165 for (index = MAXIMUM_AHCI_PORT_COUNT - 1; index > 0; index--) 166 if ((portImplemented & (1 << index)) != 0) 167 break; 168 169 portCount = index + 1; 170 AhciDebugPrint("\tPort Count: %d\n", portCount); 171 172 AdapterExtension->PortCount = portCount; 173 nonCachedExtensionSize = sizeof(AHCI_COMMAND_HEADER) * AlignedNCS + //should be 1K aligned 174 sizeof(AHCI_RECEIVED_FIS) + 175 sizeof(IDENTIFY_DEVICE_DATA); 176 177 // align nonCachedExtensionSize to 1024 178 nonCachedExtensionSize = ROUND_UP(nonCachedExtensionSize, 1024); 179 180 AdapterExtension->NonCachedExtension = StorPortGetUncachedExtension(AdapterExtension, 181 ConfigInfo, 182 nonCachedExtensionSize * portCount); 183 184 if (AdapterExtension->NonCachedExtension == NULL) 185 { 186 AhciDebugPrint("\tadapterExtension->NonCachedExtension == NULL\n"); 187 return FALSE; 188 } 189 190 nonCachedExtension = AdapterExtension->NonCachedExtension; 191 AhciZeroMemory(nonCachedExtension, nonCachedExtensionSize * portCount); 192 193 for (index = 0; index < portCount; index++) 194 { 195 PortExtension = &AdapterExtension->PortExtension[index]; 196 197 PortExtension->DeviceParams.IsActive = FALSE; 198 if ((AdapterExtension->PortImplemented & (1 << index)) != 0) 199 { 200 PortExtension->PortNumber = index; 201 PortExtension->DeviceParams.IsActive = TRUE; 202 PortExtension->AdapterExtension = AdapterExtension; 203 PortExtension->CommandList = (PAHCI_COMMAND_HEADER)nonCachedExtension; 204 205 tmp = (PCHAR)(nonCachedExtension + sizeof(AHCI_COMMAND_HEADER) * AlignedNCS); 206 207 PortExtension->ReceivedFIS = (PAHCI_RECEIVED_FIS)tmp; 208 PortExtension->IdentifyDeviceData = (PIDENTIFY_DEVICE_DATA)(tmp + sizeof(AHCI_RECEIVED_FIS)); 209 PortExtension->MaxPortQueueDepth = NCS; 210 nonCachedExtension += nonCachedExtensionSize; 211 } 212 } 213 214 return TRUE; 215 }// -- AhciAllocateResourceForAdapter(); 216 217 /** 218 * @name AhciStartPort 219 * @implemented 220 * 221 * Try to start the port device 222 * 223 * @param AdapterExtension 224 * @param PortExtension 225 * 226 */ 227 BOOLEAN 228 AhciStartPort ( 229 __in PAHCI_PORT_EXTENSION PortExtension 230 ) 231 { 232 ULONG index; 233 AHCI_PORT_CMD cmd; 234 AHCI_TASK_FILE_DATA tfd; 235 AHCI_INTERRUPT_ENABLE ie; 236 AHCI_SERIAL_ATA_STATUS ssts; 237 AHCI_SERIAL_ATA_CONTROL sctl; 238 PAHCI_ADAPTER_EXTENSION AdapterExtension; 239 240 AhciDebugPrint("AhciStartPort()\n"); 241 242 AdapterExtension = PortExtension->AdapterExtension; 243 cmd.Status = StorPortReadRegisterUlong(AdapterExtension, &PortExtension->Port->CMD); 244 245 if ((cmd.FR == 1) && (cmd.CR == 1) && (cmd.FRE == 1) && (cmd.ST == 1)) 246 { 247 // Already Running 248 return TRUE; 249 } 250 251 cmd.SUD = 1; 252 StorPortWriteRegisterUlong(AdapterExtension, &PortExtension->Port->CMD, cmd.Status); 253 254 if (((cmd.FR == 1) && (cmd.FRE == 0)) || 255 ((cmd.CR == 1) && (cmd.ST == 0))) 256 { 257 AhciDebugPrint("\tCOMRESET\n"); 258 // perform COMRESET 259 // section 10.4.2 260 261 // Software causes a port reset (COMRESET) by writing 1h to the PxSCTL.DET field to invoke a 262 // COMRESET on the interface and start a re-establishment of Phy layer communications. Software shall 263 // wait at least 1 millisecond before clearing PxSCTL.DET to 0h; this ensures that at least one COMRESET 264 // signal is sent over the interface. After clearing PxSCTL.DET to 0h, software should wait for 265 // communication to be re-established as indicated by PxSSTS.DET being set to 3h. Then software should 266 // write all 1s to the PxSERR register to clear any bits that were set as part of the port reset. 267 268 sctl.Status = StorPortReadRegisterUlong(AdapterExtension, &PortExtension->Port->SCTL); 269 sctl.DET = 1; 270 StorPortWriteRegisterUlong(AdapterExtension, &PortExtension->Port->SCTL, sctl.Status); 271 272 StorPortStallExecution(1000); 273 274 sctl.Status = StorPortReadRegisterUlong(AdapterExtension, &PortExtension->Port->SCTL); 275 sctl.DET = 0; 276 StorPortWriteRegisterUlong(AdapterExtension, &PortExtension->Port->SCTL, sctl.Status); 277 278 // Poll DET to verify if a device is attached to the port 279 index = 0; 280 do 281 { 282 StorPortStallExecution(1000); 283 ssts.Status = StorPortReadRegisterUlong(AdapterExtension, &PortExtension->Port->SSTS); 284 285 index++; 286 if (ssts.DET != 0) 287 { 288 break; 289 } 290 } 291 while(index < 30); 292 } 293 294 ssts.Status = StorPortReadRegisterUlong(AdapterExtension, &PortExtension->Port->SSTS); 295 switch (ssts.DET) 296 { 297 case 0x3: 298 { 299 NT_ASSERT(cmd.ST == 0); 300 301 // make sure FIS Recieve is enabled (cmd.FRE) 302 index = 0; 303 do 304 { 305 StorPortStallExecution(10000); 306 cmd.Status = StorPortReadRegisterUlong(AdapterExtension, &PortExtension->Port->CMD); 307 cmd.FRE = 1; 308 StorPortWriteRegisterUlong(AdapterExtension, &PortExtension->Port->CMD, cmd.Status); 309 index++; 310 } 311 while((cmd.FR != 1) && (index < 3)); 312 313 if (cmd.FR != 1) 314 { 315 // failed to start FIS DMA engine 316 // it can crash the driver later 317 // so better to turn this port off 318 return FALSE; 319 } 320 321 // start port channel 322 // set cmd.ST 323 324 NT_ASSERT(cmd.FRE == 1); 325 NT_ASSERT(cmd.CR == 0); 326 327 // why assert? well If we face such condition on DET = 0x3 328 // then we don't have port in idle state and hence before executing this part of code 329 // we must have restarted it. 330 tfd.Status = StorPortReadRegisterUlong(AdapterExtension, &PortExtension->Port->TFD); 331 332 if ((tfd.STS.BSY) || (tfd.STS.DRQ)) 333 { 334 AhciDebugPrint("\tUnhandled Case BSY-DRQ\n"); 335 } 336 337 // clear pending interrupts 338 StorPortWriteRegisterUlong(AdapterExtension, &PortExtension->Port->SERR, (ULONG)~0); 339 StorPortWriteRegisterUlong(AdapterExtension, &PortExtension->Port->IS, (ULONG)~0); 340 StorPortWriteRegisterUlong(AdapterExtension, AdapterExtension->IS, (1 << PortExtension->PortNumber)); 341 342 // set IE 343 ie.Status = StorPortReadRegisterUlong(AdapterExtension, &PortExtension->Port->IE); 344 /* Device to Host Register FIS Interrupt Enable */ 345 ie.DHRE = 1; 346 /* PIO Setup FIS Interrupt Enable */ 347 ie.PSE = 1; 348 /* DMA Setup FIS Interrupt Enable */ 349 ie.DSE = 1; 350 /* Set Device Bits FIS Interrupt Enable */ 351 ie.SDBE = 1; 352 /* Unknown FIS Interrupt Enable */ 353 ie.UFE = 0; 354 /* Descriptor Processed Interrupt Enable */ 355 ie.DPE = 0; 356 /* Port Change Interrupt Enable */ 357 ie.PCE = 1; 358 /* Device Mechanical Presence Enable */ 359 ie.DMPE = 0; 360 /* PhyRdy Change Interrupt Enable */ 361 ie.PRCE = 1; 362 /* Incorrect Port Multiplier Enable */ 363 ie.IPME = 0; 364 /* Overflow Enable */ 365 ie.OFE = 1; 366 /* Interface Non-fatal Error Enable */ 367 ie.INFE = 1; 368 /* Interface Fatal Error Enable */ 369 ie.IFE = 1; 370 /* Host Bus Data Error Enable */ 371 ie.HBDE = 1; 372 /* Host Bus Fatal Error Enable */ 373 ie.HBFE = 1; 374 /* Task File Error Enable */ 375 ie.TFEE = 1; 376 377 cmd.Status = StorPortReadRegisterUlong(AdapterExtension, &PortExtension->Port->CMD); 378 /* Cold Presence Detect Enable */ 379 if (cmd.CPD) // does it support CPD? 380 { 381 // disable it for now 382 ie.CPDE = 0; 383 } 384 385 // should I replace this to single line? 386 // by directly setting ie.Status? 387 388 StorPortWriteRegisterUlong(AdapterExtension, &PortExtension->Port->IE, ie.Status); 389 390 cmd.ST = 1; 391 StorPortWriteRegisterUlong(AdapterExtension, &PortExtension->Port->CMD, cmd.Status); 392 cmd.Status = StorPortReadRegisterUlong(AdapterExtension, &PortExtension->Port->CMD); 393 394 if (cmd.ST != 1) 395 { 396 AhciDebugPrint("\tFailed to start Port\n"); 397 return FALSE; 398 } 399 400 return TRUE; 401 } 402 default: 403 // unhandled case 404 AhciDebugPrint("\tDET == %x Unsupported\n", ssts.DET); 405 return FALSE; 406 } 407 }// -- AhciStartPort(); 408 409 /** 410 * @name AhciCommandCompletionDpcRoutine 411 * @implemented 412 * 413 * Handles Completed Commands 414 * 415 * @param Dpc 416 * @param AdapterExtension 417 * @param SystemArgument1 418 * @param SystemArgument2 419 */ 420 VOID 421 AhciCommandCompletionDpcRoutine ( 422 __in PSTOR_DPC Dpc, 423 __in PVOID HwDeviceExtension, 424 __in PVOID SystemArgument1, 425 __in PVOID SystemArgument2 426 ) 427 { 428 PSCSI_REQUEST_BLOCK Srb; 429 PAHCI_SRB_EXTENSION SrbExtension; 430 STOR_LOCK_HANDLE lockhandle = {0}; 431 PAHCI_COMPLETION_ROUTINE CompletionRoutine; 432 PAHCI_ADAPTER_EXTENSION AdapterExtension; 433 PAHCI_PORT_EXTENSION PortExtension; 434 435 UNREFERENCED_PARAMETER(Dpc); 436 UNREFERENCED_PARAMETER(SystemArgument2); 437 438 AhciDebugPrint("AhciCommandCompletionDpcRoutine()\n"); 439 440 AdapterExtension = (PAHCI_ADAPTER_EXTENSION)HwDeviceExtension; 441 PortExtension = (PAHCI_PORT_EXTENSION)SystemArgument1; 442 443 StorPortAcquireSpinLock(AdapterExtension, InterruptLock, NULL, &lockhandle); 444 Srb = RemoveQueue(&PortExtension->CompletionQueue); 445 StorPortReleaseSpinLock(AdapterExtension, &lockhandle); 446 447 NT_ASSERT(Srb != NULL); 448 449 if (Srb->SrbStatus == SRB_STATUS_PENDING) 450 { 451 Srb->SrbStatus = SRB_STATUS_SUCCESS; 452 } 453 else 454 { 455 return; 456 } 457 458 SrbExtension = GetSrbExtension(Srb); 459 460 CompletionRoutine = SrbExtension->CompletionRoutine; 461 NT_ASSERT(CompletionRoutine != NULL); 462 463 // now it's completion routine responsibility to set SrbStatus 464 CompletionRoutine(PortExtension, Srb); 465 466 StorPortNotification(RequestComplete, AdapterExtension, Srb); 467 468 return; 469 }// -- AhciCommandCompletionDpcRoutine(); 470 471 /** 472 * @name AhciHwPassiveInitialize 473 * @implemented 474 * 475 * initializes the HBA and finds all devices that are of interest to the miniport driver. (at PASSIVE LEVEL) 476 * 477 * @param adapterExtension 478 * 479 * @return 480 * return TRUE if intialization was successful 481 */ 482 BOOLEAN 483 AhciHwPassiveInitialize ( 484 __in PVOID DeviceExtension 485 ) 486 { 487 ULONG index; 488 PAHCI_ADAPTER_EXTENSION AdapterExtension; 489 PAHCI_PORT_EXTENSION PortExtension; 490 491 AhciDebugPrint("AhciHwPassiveInitialize()\n"); 492 493 AdapterExtension = (PAHCI_ADAPTER_EXTENSION)DeviceExtension; 494 495 for (index = 0; index < AdapterExtension->PortCount; index++) 496 { 497 if ((AdapterExtension->PortImplemented & (0x1 << index)) != 0) 498 { 499 PortExtension = &AdapterExtension->PortExtension[index]; 500 PortExtension->DeviceParams.IsActive = AhciStartPort(PortExtension); 501 StorPortInitializeDpc(AdapterExtension, &PortExtension->CommandCompletion, AhciCommandCompletionDpcRoutine); 502 } 503 } 504 505 return TRUE; 506 }// -- AhciHwPassiveInitialize(); 507 508 /** 509 * @name AhciHwInitialize 510 * @implemented 511 * 512 * initializes the HBA and finds all devices that are of interest to the miniport driver. 513 * 514 * @param adapterExtension 515 * 516 * @return 517 * return TRUE if intialization was successful 518 */ 519 BOOLEAN 520 NTAPI 521 AhciHwInitialize ( 522 __in PVOID DeviceExtension 523 ) 524 { 525 PAHCI_ADAPTER_EXTENSION AdapterExtension; 526 AHCI_GHC ghc; 527 528 AhciDebugPrint("AhciHwInitialize()\n"); 529 530 AdapterExtension = (PAHCI_ADAPTER_EXTENSION)DeviceExtension; 531 AdapterExtension->StateFlags.MessagePerPort = FALSE; 532 533 // First check what type of interrupt/synchronization device is using 534 ghc.Status = StorPortReadRegisterUlong(AdapterExtension, &AdapterExtension->ABAR_Address->GHC); 535 536 // When set to ‘1’ by hardware, indicates that the HBA requested more than one MSI vector 537 // but has reverted to using the first vector only. When this bit is cleared to ‘0’, 538 // the HBA has not reverted to single MSI mode (i.e. hardware is already in single MSI mode, 539 // software has allocated the number of messages requested 540 if (ghc.MRSM == 0) 541 { 542 AdapterExtension->StateFlags.MessagePerPort = TRUE; 543 AhciDebugPrint("\tMultiple MSI based message not supported\n"); 544 } 545 546 StorPortEnablePassiveInitialization(AdapterExtension, AhciHwPassiveInitialize); 547 548 return TRUE; 549 }// -- AhciHwInitialize(); 550 551 /** 552 * @name AhciCompleteIssuedSrb 553 * @implemented 554 * 555 * Complete issued Srbs 556 * 557 * @param PortExtension 558 * 559 */ 560 VOID 561 AhciCompleteIssuedSrb ( 562 __in PAHCI_PORT_EXTENSION PortExtension, 563 __in ULONG CommandsToComplete 564 ) 565 { 566 ULONG NCS, i; 567 PSCSI_REQUEST_BLOCK Srb; 568 PAHCI_SRB_EXTENSION SrbExtension; 569 PAHCI_ADAPTER_EXTENSION AdapterExtension; 570 571 AhciDebugPrint("AhciCompleteIssuedSrb()\n"); 572 573 NT_ASSERT(CommandsToComplete != 0); 574 575 AhciDebugPrint("\tCompleted Commands: %d\n", CommandsToComplete); 576 577 AdapterExtension = PortExtension->AdapterExtension; 578 NCS = AHCI_Global_Port_CAP_NCS(AdapterExtension->CAP); 579 580 for (i = 0; i < NCS; i++) 581 { 582 if (((1 << i) & CommandsToComplete) != 0) 583 { 584 Srb = PortExtension->Slot[i]; 585 586 if (Srb == NULL) 587 { 588 continue; 589 } 590 591 SrbExtension = GetSrbExtension(Srb); 592 NT_ASSERT(SrbExtension != NULL); 593 594 if (SrbExtension->CompletionRoutine != NULL) 595 { 596 AddQueue(&PortExtension->CompletionQueue, Srb); 597 StorPortIssueDpc(AdapterExtension, &PortExtension->CommandCompletion, PortExtension, Srb); 598 } 599 else 600 { 601 NT_ASSERT(Srb->SrbStatus == SRB_STATUS_PENDING); 602 Srb->SrbStatus = SRB_STATUS_SUCCESS; 603 StorPortNotification(RequestComplete, AdapterExtension, Srb); 604 } 605 } 606 } 607 608 return; 609 }// -- AhciCompleteIssuedSrb(); 610 611 /** 612 * @name AhciInterruptHandler 613 * @not_implemented 614 * 615 * Interrupt Handler for PortExtension 616 * 617 * @param PortExtension 618 * 619 */ 620 VOID 621 AhciInterruptHandler ( 622 __in PAHCI_PORT_EXTENSION PortExtension 623 ) 624 { 625 ULONG is, ci, sact, outstanding; 626 AHCI_INTERRUPT_STATUS PxIS; 627 AHCI_INTERRUPT_STATUS PxISMasked; 628 PAHCI_ADAPTER_EXTENSION AdapterExtension; 629 630 AhciDebugPrint("AhciInterruptHandler()\n"); 631 AhciDebugPrint("\tPort Number: %d\n", PortExtension->PortNumber); 632 633 AdapterExtension = PortExtension->AdapterExtension; 634 NT_ASSERT(IsPortValid(AdapterExtension, PortExtension->PortNumber)); 635 636 // 5.5.3 637 // 1. Software determines the cause of the interrupt by reading the PxIS register. 638 // It is possible for multiple bits to be set 639 // 2. Software clears appropriate bits in the PxIS register corresponding to the cause of the interrupt. 640 // 3. Software clears the interrupt bit in IS.IPS corresponding to the port. 641 // 4. If executing non-queued commands, software reads the PxCI register, and compares the current value to 642 // the list of commands previously issued by software that are still outstanding. 643 // If executing native queued commands, software reads the PxSACT register and compares the current 644 // value to the list of commands previously issued by software. 645 // Software completes with success any outstanding command whose corresponding bit has been cleared in 646 // the respective register. PxCI and PxSACT are volatile registers; software should only use their values 647 // to determine commands that have completed, not to determine which commands have previously been issued. 648 // 5. If there were errors, noted in the PxIS register, software performs error recovery actions (see section 6.2.2). 649 PxISMasked.Status = 0; 650 PxIS.Status = StorPortReadRegisterUlong(AdapterExtension, &PortExtension->Port->IS); 651 652 // 6.2.2 653 // Fatal Error 654 // signified by the setting of PxIS.HBFS, PxIS.HBDS, PxIS.IFS, or PxIS.TFES 655 if (PxIS.HBFS || PxIS.HBDS || PxIS.IFS || PxIS.TFES) 656 { 657 // In this state, the HBA shall not issue any new commands nor acknowledge DMA Setup FISes to process 658 // any native command queuing commands. To recover, the port must be restarted 659 // To detect an error that requires software recovery actions to be performed, 660 // software should check whether any of the following status bits are set on an interrupt: 661 // PxIS.HBFS, PxIS.HBDS, PxIS.IFS, and PxIS.TFES. If any of these bits are set, 662 // software should perform the appropriate error recovery actions based on whether 663 // non-queued commands were being issued or native command queuing commands were being issued. 664 665 AhciDebugPrint("\tFatal Error: %x\n", PxIS.Status); 666 } 667 668 // Normal Command Completion 669 // 3.3.5 670 // A D2H Register FIS has been received with the ‘I’ bit set, and has been copied into system memory. 671 PxISMasked.DHRS = PxIS.DHRS; 672 // A PIO Setup FIS has been received with the ‘I’ bit set, it has been copied into system memory. 673 PxISMasked.PSS = PxIS.PSS; 674 // A DMA Setup FIS has been received with the ‘I’ bit set and has been copied into system memory. 675 PxISMasked.DSS = PxIS.DSS; 676 // A Set Device Bits FIS has been received with the ‘I’ bit set and has been copied into system memory/ 677 PxISMasked.SDBS = PxIS.SDBS; 678 // A PRD with the ‘I’ bit set has transferred all of its data. 679 PxISMasked.DPS = PxIS.DPS; 680 681 if (PxISMasked.Status != 0) 682 { 683 StorPortWriteRegisterUlong(AdapterExtension, &PortExtension->Port->IS, PxISMasked.Status); 684 } 685 686 // 10.7.1.1 687 // Clear port interrupt 688 // It is set by the level of the virtual interrupt line being a set, and cleared by a write of ‘1’ from the software. 689 is = (1 << PortExtension->PortNumber); 690 StorPortWriteRegisterUlong(AdapterExtension, AdapterExtension->IS, is); 691 692 ci = StorPortReadRegisterUlong(AdapterExtension, &PortExtension->Port->CI); 693 sact = StorPortReadRegisterUlong(AdapterExtension, &PortExtension->Port->SACT); 694 695 outstanding = ci | sact; // NOTE: Including both non-NCQ and NCQ based commands 696 if ((PortExtension->CommandIssuedSlots & (~outstanding)) != 0) 697 { 698 AhciCompleteIssuedSrb(PortExtension, (PortExtension->CommandIssuedSlots & (~outstanding))); 699 PortExtension->CommandIssuedSlots &= outstanding; 700 } 701 702 return; 703 }// -- AhciInterruptHandler(); 704 705 /** 706 * @name AhciHwInterrupt 707 * @implemented 708 * 709 * The Storport driver calls the HwStorInterrupt routine after the HBA generates an interrupt request. 710 * 711 * @param AdapterExtension 712 * 713 * @return 714 * return TRUE Indicates that an interrupt was pending on adapter. 715 * return FALSE Indicates the interrupt was not ours. 716 */ 717 BOOLEAN 718 NTAPI 719 AhciHwInterrupt ( 720 __in PVOID DeviceExtension 721 ) 722 { 723 PAHCI_ADAPTER_EXTENSION AdapterExtension; 724 ULONG portPending, nextPort, i, portCount; 725 726 AdapterExtension = (PAHCI_ADAPTER_EXTENSION)DeviceExtension; 727 728 if (AdapterExtension->StateFlags.Removed) 729 { 730 return FALSE; 731 } 732 733 portPending = StorPortReadRegisterUlong(AdapterExtension, AdapterExtension->IS); 734 735 // we process interrupt for implemented ports only 736 portCount = AdapterExtension->PortCount; 737 portPending = portPending & AdapterExtension->PortImplemented; 738 739 if (portPending == 0) 740 { 741 return FALSE; 742 } 743 744 for (i = 1; i <= portCount; i++) 745 { 746 nextPort = (AdapterExtension->LastInterruptPort + i) % portCount; 747 if ((portPending & (0x1 << nextPort)) == 0) 748 continue; 749 750 NT_ASSERT(IsPortValid(AdapterExtension, nextPort)); 751 752 if (AdapterExtension->PortExtension[nextPort].DeviceParams.IsActive == FALSE) 753 { 754 continue; 755 } 756 757 // we can assign this interrupt to this port 758 AdapterExtension->LastInterruptPort = nextPort; 759 AhciInterruptHandler(&AdapterExtension->PortExtension[nextPort]); 760 761 portPending &= ~(1 << nextPort); 762 763 // interrupt belongs to this device 764 // should always return TRUE 765 return TRUE; 766 } 767 768 AhciDebugPrint("\tSomething went wrong"); 769 return FALSE; 770 }// -- AhciHwInterrupt(); 771 772 /** 773 * @name AhciHwStartIo 774 * @not_implemented 775 * 776 * The Storport driver calls the HwStorStartIo routine one time for each incoming I/O request. 777 * 778 * @param adapterExtension 779 * @param Srb 780 * 781 * @return 782 * return TRUE if the request was accepted 783 * return FALSE if the request must be submitted later 784 */ 785 BOOLEAN 786 NTAPI 787 AhciHwStartIo ( 788 __in PVOID DeviceExtension, 789 __in PSCSI_REQUEST_BLOCK Srb 790 ) 791 { 792 PAHCI_ADAPTER_EXTENSION AdapterExtension; 793 794 AhciDebugPrint("AhciHwStartIo()\n"); 795 796 AdapterExtension = (PAHCI_ADAPTER_EXTENSION)DeviceExtension; 797 798 if (!IsPortValid(AdapterExtension, Srb->PathId)) 799 { 800 Srb->SrbStatus = SRB_STATUS_NO_DEVICE; 801 StorPortNotification(RequestComplete, AdapterExtension, Srb); 802 return TRUE; 803 } 804 805 switch(Srb->Function) 806 { 807 case SRB_FUNCTION_PNP: 808 { 809 // https://msdn.microsoft.com/windows/hardware/drivers/storage/handling-srb-function-pnp 810 // If the function member of an SRB is set to SRB_FUNCTION_PNP, 811 // the SRB is a structure of type SCSI_PNP_REQUEST_BLOCK. 812 813 PSCSI_PNP_REQUEST_BLOCK pnpRequest; 814 pnpRequest = (PSCSI_PNP_REQUEST_BLOCK)Srb; 815 if ((pnpRequest->SrbPnPFlags & SRB_PNP_FLAGS_ADAPTER_REQUEST) != 0) 816 { 817 switch(pnpRequest->PnPAction) 818 { 819 case StorRemoveDevice: 820 case StorSurpriseRemoval: 821 { 822 Srb->SrbStatus = SRB_STATUS_SUCCESS; 823 AdapterExtension->StateFlags.Removed = 1; 824 AhciDebugPrint("\tAdapter removed\n"); 825 } 826 break; 827 case StorStopDevice: 828 { 829 Srb->SrbStatus = SRB_STATUS_SUCCESS; 830 AhciDebugPrint("\tRequested to Stop the adapter\n"); 831 } 832 break; 833 default: 834 Srb->SrbStatus = SRB_STATUS_INVALID_REQUEST; 835 break; 836 } 837 } 838 else 839 { 840 Srb->SrbStatus = SRB_STATUS_INVALID_REQUEST; 841 } 842 } 843 break; 844 case SRB_FUNCTION_EXECUTE_SCSI: 845 { 846 // https://msdn.microsoft.com/en-us/windows/hardware/drivers/storage/handling-srb-function-execute-scsi 847 // On receipt of an SRB_FUNCTION_EXECUTE_SCSI request, a miniport driver's HwScsiStartIo 848 // routine does the following: 849 // 850 // - Gets and/or sets up whatever context the miniport driver maintains in its device, 851 // logical unit, and/or SRB extensions 852 // For example, a miniport driver might set up a logical unit extension with pointers 853 // to the SRB itself and the SRB DataBuffer pointer, the SRB DataTransferLength value, 854 // and a driver-defined value (or CDB SCSIOP_XXX value) indicating the operation to be 855 // carried out on the HBA. 856 // 857 // - Calls an internal routine to program the HBA, as partially directed by the SrbFlags, 858 // for the requested operation 859 // For a device I/O operation, such an internal routine generally selects the target device 860 // and sends the CDB over the bus to the target logical unit. 861 PCDB cdb = (PCDB)&Srb->Cdb; 862 if (Srb->CdbLength == 0) 863 { 864 AhciDebugPrint("\tOperationCode: %d\n", cdb->CDB10.OperationCode); 865 Srb->SrbStatus = SRB_STATUS_BAD_FUNCTION; 866 break; 867 } 868 869 NT_ASSERT(cdb != NULL); 870 871 switch(cdb->CDB10.OperationCode) 872 { 873 case SCSIOP_INQUIRY: 874 Srb->SrbStatus = DeviceInquiryRequest(AdapterExtension, Srb, cdb); 875 break; 876 case SCSIOP_REPORT_LUNS: 877 Srb->SrbStatus = DeviceReportLuns(AdapterExtension, Srb, cdb); 878 break; 879 case SCSIOP_READ_CAPACITY: 880 Srb->SrbStatus = DeviceRequestCapacity(AdapterExtension, Srb, cdb); 881 break; 882 case SCSIOP_TEST_UNIT_READY: 883 Srb->SrbStatus = DeviceRequestComplete(AdapterExtension, Srb, cdb); 884 break; 885 case SCSIOP_MODE_SENSE: 886 Srb->SrbStatus = DeviceRequestSense(AdapterExtension, Srb, cdb); 887 break; 888 case SCSIOP_READ: 889 case SCSIOP_WRITE: 890 Srb->SrbStatus = DeviceRequestReadWrite(AdapterExtension, Srb, cdb); 891 break; 892 default: 893 AhciDebugPrint("\tOperationCode: %d\n", cdb->CDB10.OperationCode); 894 Srb->SrbStatus = SRB_STATUS_INVALID_REQUEST; 895 break; 896 } 897 } 898 break; 899 default: 900 AhciDebugPrint("\tUnknown function code recieved: %x\n", Srb->Function); 901 Srb->SrbStatus = SRB_STATUS_INVALID_REQUEST; 902 break; 903 } 904 905 if (Srb->SrbStatus != SRB_STATUS_PENDING) 906 { 907 StorPortNotification(RequestComplete, AdapterExtension, Srb); 908 } 909 else 910 { 911 AhciProcessIO(AdapterExtension, Srb->PathId, Srb); 912 } 913 return TRUE; 914 }// -- AhciHwStartIo(); 915 916 /** 917 * @name AhciHwResetBus 918 * @not_implemented 919 * 920 * The HwStorResetBus routine is called by the port driver to clear error conditions. 921 * 922 * @param adapterExtension 923 * @param PathId 924 * 925 * @return 926 * return TRUE if bus was successfully reset 927 */ 928 BOOLEAN 929 NTAPI 930 AhciHwResetBus ( 931 __in PVOID AdapterExtension, 932 __in ULONG PathId 933 ) 934 { 935 STOR_LOCK_HANDLE lockhandle = {0}; 936 // PAHCI_ADAPTER_EXTENSION adapterExtension; 937 938 AhciDebugPrint("AhciHwResetBus()\n"); 939 940 // adapterExtension = AdapterExtension; 941 942 if (IsPortValid(AdapterExtension, PathId)) 943 { 944 // Acquire Lock 945 StorPortAcquireSpinLock(AdapterExtension, InterruptLock, NULL, &lockhandle); 946 947 // TODO: Perform port reset 948 949 // Release lock 950 StorPortReleaseSpinLock(AdapterExtension, &lockhandle); 951 } 952 953 return FALSE; 954 }// -- AhciHwResetBus(); 955 956 /** 957 * @name AhciHwFindAdapter 958 * @implemented 959 * 960 * The HwStorFindAdapter routine uses the supplied configuration to determine whether a specific 961 * HBA is supported and, if it is, to return configuration information about that adapter. 962 * 963 * 10.1 Platform Communication 964 * http://www.intel.in/content/dam/www/public/us/en/documents/technical-specifications/serial-ata-ahci-spec-rev1_2.pdf 965 966 * @param DeviceExtension 967 * @param HwContext 968 * @param BusInformation 969 * @param ArgumentString 970 * @param ConfigInfo 971 * @param Reserved3 972 * 973 * @return 974 * SP_RETURN_FOUND 975 * Indicates that a supported HBA was found and that the HBA-relevant configuration information was successfully determined and set in the PORT_CONFIGURATION_INFORMATION structure. 976 * 977 * SP_RETURN_ERROR 978 * Indicates that an HBA was found but there was an error obtaining the configuration information. If possible, such an error should be logged with StorPortLogError. 979 * 980 * SP_RETURN_BAD_CONFIG 981 * Indicates that the supplied configuration information was invalid for the adapter. 982 * 983 * SP_RETURN_NOT_FOUND 984 * Indicates that no supported HBA was found for the supplied configuration information. 985 * 986 * @remarks Called by Storport. 987 */ 988 ULONG 989 NTAPI 990 AhciHwFindAdapter ( 991 __in PVOID DeviceExtension, 992 __in PVOID HwContext, 993 __in PVOID BusInformation, 994 __in PCHAR ArgumentString, 995 __inout PPORT_CONFIGURATION_INFORMATION ConfigInfo, 996 __in PBOOLEAN Reserved3 997 ) 998 { 999 AHCI_GHC ghc; 1000 ULONG index, pci_cfg_len; 1001 PACCESS_RANGE accessRange; 1002 UCHAR pci_cfg_buf[sizeof(PCI_COMMON_CONFIG)]; 1003 1004 PAHCI_MEMORY_REGISTERS abar; 1005 PPCI_COMMON_CONFIG pciConfigData; 1006 PAHCI_ADAPTER_EXTENSION adapterExtension; 1007 1008 AhciDebugPrint("AhciHwFindAdapter()\n"); 1009 1010 UNREFERENCED_PARAMETER(HwContext); 1011 UNREFERENCED_PARAMETER(BusInformation); 1012 UNREFERENCED_PARAMETER(ArgumentString); 1013 UNREFERENCED_PARAMETER(Reserved3); 1014 1015 adapterExtension = DeviceExtension; 1016 adapterExtension->SlotNumber = ConfigInfo->SlotNumber; 1017 adapterExtension->SystemIoBusNumber = ConfigInfo->SystemIoBusNumber; 1018 1019 // get PCI configuration header 1020 pci_cfg_len = StorPortGetBusData( 1021 adapterExtension, 1022 PCIConfiguration, 1023 adapterExtension->SystemIoBusNumber, 1024 adapterExtension->SlotNumber, 1025 pci_cfg_buf, 1026 sizeof(PCI_COMMON_CONFIG)); 1027 1028 if (pci_cfg_len != sizeof(PCI_COMMON_CONFIG)) 1029 { 1030 AhciDebugPrint("\tpci_cfg_len != %d :: %d", sizeof(PCI_COMMON_CONFIG), pci_cfg_len); 1031 return SP_RETURN_ERROR;//Not a valid device at the given bus number 1032 } 1033 1034 pciConfigData = (PPCI_COMMON_CONFIG)pci_cfg_buf; 1035 adapterExtension->VendorID = pciConfigData->VendorID; 1036 adapterExtension->DeviceID = pciConfigData->DeviceID; 1037 adapterExtension->RevisionID = pciConfigData->RevisionID; 1038 // The last PCI base address register (BAR[5], header offset 0x24) points to the AHCI base memory, it’s called ABAR (AHCI Base Memory Register). 1039 adapterExtension->AhciBaseAddress = pciConfigData->u.type0.BaseAddresses[5] & (0xFFFFFFF0); 1040 1041 AhciDebugPrint("\tVendorID: %04x DeviceID: %04x RevisionID: %02x\n", 1042 adapterExtension->VendorID, 1043 adapterExtension->DeviceID, 1044 adapterExtension->RevisionID); 1045 1046 // 2.1.11 1047 abar = NULL; 1048 if (ConfigInfo->NumberOfAccessRanges > 0) 1049 { 1050 accessRange = *(ConfigInfo->AccessRanges); 1051 for (index = 0; index < ConfigInfo->NumberOfAccessRanges; index++) 1052 { 1053 if (accessRange[index].RangeStart.QuadPart == adapterExtension->AhciBaseAddress) 1054 { 1055 abar = StorPortGetDeviceBase(adapterExtension, 1056 ConfigInfo->AdapterInterfaceType, 1057 ConfigInfo->SystemIoBusNumber, 1058 accessRange[index].RangeStart, 1059 accessRange[index].RangeLength, 1060 !accessRange[index].RangeInMemory); 1061 break; 1062 } 1063 } 1064 } 1065 1066 if (abar == NULL) 1067 { 1068 AhciDebugPrint("\tabar == NULL\n"); 1069 return SP_RETURN_ERROR; // corrupted information supplied 1070 } 1071 1072 adapterExtension->ABAR_Address = abar; 1073 adapterExtension->CAP = StorPortReadRegisterUlong(adapterExtension, &abar->CAP); 1074 adapterExtension->CAP2 = StorPortReadRegisterUlong(adapterExtension, &abar->CAP2); 1075 adapterExtension->Version = StorPortReadRegisterUlong(adapterExtension, &abar->VS); 1076 adapterExtension->LastInterruptPort = (ULONG)-1; 1077 1078 // 10.1.2 1079 // 1. Indicate that system software is AHCI aware by setting GHC.AE to ‘1’. 1080 // 3.1.2 -- AE bit is read-write only if CAP.SAM is '0' 1081 ghc.Status = StorPortReadRegisterUlong(adapterExtension, &abar->GHC); 1082 // AE := Highest Significant bit of GHC 1083 if (ghc.AE != 0)// Hmm, controller was already in power state 1084 { 1085 // reset controller to have it in known state 1086 AhciDebugPrint("\tAE Already set, Reset()\n"); 1087 if (!AhciAdapterReset(adapterExtension)) 1088 { 1089 AhciDebugPrint("\tReset Failed!\n"); 1090 return SP_RETURN_ERROR;// reset failed 1091 } 1092 } 1093 1094 ghc.Status = 0; 1095 ghc.AE = 1;// only AE=1 1096 // tell the controller that we know about AHCI 1097 StorPortWriteRegisterUlong(adapterExtension, &abar->GHC, ghc.Status); 1098 1099 adapterExtension->IS = &abar->IS; 1100 adapterExtension->PortImplemented = StorPortReadRegisterUlong(adapterExtension, &abar->PI); 1101 1102 if (adapterExtension->PortImplemented == 0) 1103 { 1104 AhciDebugPrint("\tadapterExtension->PortImplemented == 0\n"); 1105 return SP_RETURN_ERROR; 1106 } 1107 1108 ConfigInfo->Master = TRUE; 1109 ConfigInfo->AlignmentMask = 0x3; 1110 ConfigInfo->ScatterGather = TRUE; 1111 ConfigInfo->DmaWidth = Width32Bits; 1112 ConfigInfo->WmiDataProvider = FALSE; 1113 ConfigInfo->Dma32BitAddresses = TRUE; 1114 1115 if (IsAdapterCAPS64(adapterExtension->CAP)) 1116 { 1117 ConfigInfo->Dma64BitAddresses = TRUE; 1118 } 1119 1120 ConfigInfo->MaximumNumberOfTargets = 1; 1121 ConfigInfo->ResetTargetSupported = TRUE; 1122 ConfigInfo->NumberOfPhysicalBreaks = 0x21; 1123 ConfigInfo->MaximumNumberOfLogicalUnits = 1; 1124 ConfigInfo->NumberOfBuses = MAXIMUM_AHCI_PORT_COUNT; 1125 ConfigInfo->MaximumTransferLength = MAXIMUM_TRANSFER_LENGTH; 1126 ConfigInfo->SynchronizationModel = StorSynchronizeFullDuplex; 1127 1128 // Turn IE -- Interrupt Enabled 1129 ghc.Status = StorPortReadRegisterUlong(adapterExtension, &abar->GHC); 1130 ghc.IE = 1; 1131 StorPortWriteRegisterUlong(adapterExtension, &abar->GHC, ghc.Status); 1132 1133 // allocate necessary resource for each port 1134 if (!AhciAllocateResourceForAdapter(adapterExtension, ConfigInfo)) 1135 { 1136 NT_ASSERT(FALSE); 1137 return SP_RETURN_ERROR; 1138 } 1139 1140 for (index = 0; index < adapterExtension->PortCount; index++) 1141 { 1142 if ((adapterExtension->PortImplemented & (0x1 << index)) != 0) 1143 AhciPortInitialize(&adapterExtension->PortExtension[index]); 1144 } 1145 1146 return SP_RETURN_FOUND; 1147 }// -- AhciHwFindAdapter(); 1148 1149 /** 1150 * @name DriverEntry 1151 * @implemented 1152 * 1153 * Initial Entrypoint for storahci miniport driver 1154 * 1155 * @param DriverObject 1156 * @param RegistryPath 1157 * 1158 * @return 1159 * NT_STATUS in case of driver loaded successfully. 1160 */ 1161 ULONG 1162 NTAPI 1163 DriverEntry ( 1164 __in PVOID DriverObject, 1165 __in PVOID RegistryPath 1166 ) 1167 { 1168 ULONG status; 1169 // initialize the hardware data structure 1170 HW_INITIALIZATION_DATA hwInitializationData = {0}; 1171 1172 // set size of hardware initialization structure 1173 hwInitializationData.HwInitializationDataSize = sizeof(HW_INITIALIZATION_DATA); 1174 1175 // identity required miniport entry point routines 1176 hwInitializationData.HwStartIo = AhciHwStartIo; 1177 hwInitializationData.HwResetBus = AhciHwResetBus; 1178 hwInitializationData.HwInterrupt = AhciHwInterrupt; 1179 hwInitializationData.HwInitialize = AhciHwInitialize; 1180 hwInitializationData.HwFindAdapter = AhciHwFindAdapter; 1181 1182 // adapter specific information 1183 hwInitializationData.TaggedQueuing = TRUE; 1184 hwInitializationData.AutoRequestSense = TRUE; 1185 hwInitializationData.MultipleRequestPerLu = TRUE; 1186 hwInitializationData.NeedPhysicalAddresses = TRUE; 1187 1188 hwInitializationData.NumberOfAccessRanges = 6; 1189 hwInitializationData.AdapterInterfaceType = PCIBus; 1190 hwInitializationData.MapBuffers = STOR_MAP_NON_READ_WRITE_BUFFERS; 1191 1192 // set required extension sizes 1193 hwInitializationData.SrbExtensionSize = sizeof(AHCI_SRB_EXTENSION); 1194 hwInitializationData.DeviceExtensionSize = sizeof(AHCI_ADAPTER_EXTENSION); 1195 1196 // register our hw init data 1197 status = StorPortInitialize(DriverObject, 1198 RegistryPath, 1199 &hwInitializationData, 1200 NULL); 1201 1202 NT_ASSERT(status == STATUS_SUCCESS); 1203 return status; 1204 }// -- DriverEntry(); 1205 1206 /** 1207 * @name AhciATA_CFIS 1208 * @implemented 1209 * 1210 * create ATA CFIS from Srb 1211 * 1212 * @param PortExtension 1213 * @param Srb 1214 * 1215 * @return 1216 * Number of CFIS fields used in DWORD 1217 */ 1218 ULONG 1219 AhciATA_CFIS ( 1220 __in PAHCI_PORT_EXTENSION PortExtension, 1221 __in PAHCI_SRB_EXTENSION SrbExtension 1222 ) 1223 { 1224 PAHCI_COMMAND_TABLE cmdTable; 1225 1226 UNREFERENCED_PARAMETER(PortExtension); 1227 1228 AhciDebugPrint("AhciATA_CFIS()\n"); 1229 1230 cmdTable = (PAHCI_COMMAND_TABLE)SrbExtension; 1231 1232 AhciZeroMemory((PCHAR)cmdTable->CFIS, sizeof(cmdTable->CFIS)); 1233 1234 cmdTable->CFIS[AHCI_ATA_CFIS_FisType] = FIS_TYPE_REG_H2D; // FIS Type 1235 cmdTable->CFIS[AHCI_ATA_CFIS_PMPort_C] = (1 << 7); // PM Port & C 1236 cmdTable->CFIS[AHCI_ATA_CFIS_CommandReg] = SrbExtension->CommandReg; 1237 1238 cmdTable->CFIS[AHCI_ATA_CFIS_FeaturesLow] = SrbExtension->FeaturesLow; 1239 cmdTable->CFIS[AHCI_ATA_CFIS_LBA0] = SrbExtension->LBA0; 1240 cmdTable->CFIS[AHCI_ATA_CFIS_LBA1] = SrbExtension->LBA1; 1241 cmdTable->CFIS[AHCI_ATA_CFIS_LBA2] = SrbExtension->LBA2; 1242 cmdTable->CFIS[AHCI_ATA_CFIS_Device] = SrbExtension->Device; 1243 cmdTable->CFIS[AHCI_ATA_CFIS_LBA3] = SrbExtension->LBA3; 1244 cmdTable->CFIS[AHCI_ATA_CFIS_LBA4] = SrbExtension->LBA4; 1245 cmdTable->CFIS[AHCI_ATA_CFIS_LBA5] = SrbExtension->LBA5; 1246 cmdTable->CFIS[AHCI_ATA_CFIS_FeaturesHigh] = SrbExtension->FeaturesHigh; 1247 cmdTable->CFIS[AHCI_ATA_CFIS_SectorCountLow] = SrbExtension->SectorCountLow; 1248 cmdTable->CFIS[AHCI_ATA_CFIS_SectorCountHigh] = SrbExtension->SectorCountHigh; 1249 1250 return 5; 1251 }// -- AhciATA_CFIS(); 1252 1253 /** 1254 * @name AhciATAPI_CFIS 1255 * @not_implemented 1256 * 1257 * create ATAPI CFIS from Srb 1258 * 1259 * @param PortExtension 1260 * @param Srb 1261 * 1262 * @return 1263 * Number of CFIS fields used in DWORD 1264 */ 1265 ULONG 1266 AhciATAPI_CFIS ( 1267 __in PAHCI_PORT_EXTENSION PortExtension, 1268 __in PAHCI_SRB_EXTENSION SrbExtension 1269 ) 1270 { 1271 PAHCI_COMMAND_TABLE cmdTable; 1272 UNREFERENCED_PARAMETER(PortExtension); 1273 1274 AhciDebugPrint("AhciATAPI_CFIS()\n"); 1275 1276 cmdTable = (PAHCI_COMMAND_TABLE)SrbExtension; 1277 1278 NT_ASSERT(SrbExtension->CommandReg == IDE_COMMAND_ATAPI_PACKET); 1279 1280 AhciZeroMemory((PCHAR)cmdTable->CFIS, sizeof(cmdTable->CFIS)); 1281 1282 cmdTable->CFIS[AHCI_ATA_CFIS_FisType] = FIS_TYPE_REG_H2D; // FIS Type 1283 cmdTable->CFIS[AHCI_ATA_CFIS_PMPort_C] = (1 << 7); // PM Port & C 1284 cmdTable->CFIS[AHCI_ATA_CFIS_CommandReg] = SrbExtension->CommandReg; 1285 1286 cmdTable->CFIS[AHCI_ATA_CFIS_FeaturesLow] = SrbExtension->FeaturesLow; 1287 cmdTable->CFIS[AHCI_ATA_CFIS_LBA0] = SrbExtension->LBA0; 1288 cmdTable->CFIS[AHCI_ATA_CFIS_LBA1] = SrbExtension->LBA1; 1289 cmdTable->CFIS[AHCI_ATA_CFIS_LBA2] = SrbExtension->LBA2; 1290 cmdTable->CFIS[AHCI_ATA_CFIS_Device] = SrbExtension->Device; 1291 cmdTable->CFIS[AHCI_ATA_CFIS_LBA3] = SrbExtension->LBA3; 1292 cmdTable->CFIS[AHCI_ATA_CFIS_LBA4] = SrbExtension->LBA4; 1293 cmdTable->CFIS[AHCI_ATA_CFIS_LBA5] = SrbExtension->LBA5; 1294 cmdTable->CFIS[AHCI_ATA_CFIS_FeaturesHigh] = SrbExtension->FeaturesHigh; 1295 cmdTable->CFIS[AHCI_ATA_CFIS_SectorCountLow] = SrbExtension->SectorCountLow; 1296 cmdTable->CFIS[AHCI_ATA_CFIS_SectorCountHigh] = SrbExtension->SectorCountHigh; 1297 1298 return 5; 1299 }// -- AhciATAPI_CFIS(); 1300 1301 /** 1302 * @name AhciBuild_PRDT 1303 * @implemented 1304 * 1305 * Build PRDT for data transfer 1306 * 1307 * @param PortExtension 1308 * @param Srb 1309 * 1310 * @return 1311 * Return number of entries in PRDT. 1312 */ 1313 ULONG 1314 AhciBuild_PRDT ( 1315 __in PAHCI_PORT_EXTENSION PortExtension, 1316 __in PAHCI_SRB_EXTENSION SrbExtension 1317 ) 1318 { 1319 ULONG index; 1320 PAHCI_COMMAND_TABLE cmdTable; 1321 PLOCAL_SCATTER_GATHER_LIST sgl; 1322 PAHCI_ADAPTER_EXTENSION AdapterExtension; 1323 1324 AhciDebugPrint("AhciBuild_PRDT()\n"); 1325 1326 sgl = SrbExtension->pSgl; 1327 cmdTable = (PAHCI_COMMAND_TABLE)SrbExtension; 1328 AdapterExtension = PortExtension->AdapterExtension; 1329 1330 NT_ASSERT(sgl != NULL); 1331 NT_ASSERT(sgl->NumberOfElements < MAXIMUM_AHCI_PRDT_ENTRIES); 1332 1333 for (index = 0; index < sgl->NumberOfElements; index++) 1334 { 1335 NT_ASSERT(sgl->List[index].Length <= MAXIMUM_TRANSFER_LENGTH); 1336 1337 cmdTable->PRDT[index].DBA = sgl->List[index].PhysicalAddress.LowPart; 1338 if (IsAdapterCAPS64(AdapterExtension->CAP)) 1339 { 1340 cmdTable->PRDT[index].DBAU = sgl->List[index].PhysicalAddress.HighPart; 1341 } 1342 1343 // Data Byte Count (DBC): A ‘0’ based value that Indicates the length, in bytes, of the data block. 1344 // A maximum of length of 4MB may exist for any entry. Bit ‘0’ of this field must always be ‘1’ to 1345 // indicate an even byte count. A value of ‘1’ indicates 2 bytes, ‘3’ indicates 4 bytes, etc. 1346 cmdTable->PRDT[index].DBC = sgl->List[index].Length - 1; 1347 } 1348 1349 return sgl->NumberOfElements; 1350 }// -- AhciBuild_PRDT(); 1351 1352 /** 1353 * @name AhciProcessSrb 1354 * @implemented 1355 * 1356 * Prepare Srb for IO processing 1357 * 1358 * @param PortExtension 1359 * @param Srb 1360 * @param SlotIndex 1361 * 1362 */ 1363 VOID 1364 AhciProcessSrb ( 1365 __in PAHCI_PORT_EXTENSION PortExtension, 1366 __in PSCSI_REQUEST_BLOCK Srb, 1367 __in ULONG SlotIndex 1368 ) 1369 { 1370 ULONG prdtlen, sig, length, cfl; 1371 PAHCI_SRB_EXTENSION SrbExtension; 1372 PAHCI_COMMAND_HEADER CommandHeader; 1373 PAHCI_ADAPTER_EXTENSION AdapterExtension; 1374 STOR_PHYSICAL_ADDRESS CommandTablePhysicalAddress; 1375 1376 AhciDebugPrint("AhciProcessSrb()\n"); 1377 1378 NT_ASSERT(Srb->PathId == PortExtension->PortNumber); 1379 1380 SrbExtension = GetSrbExtension(Srb); 1381 AdapterExtension = PortExtension->AdapterExtension; 1382 1383 NT_ASSERT(SrbExtension != NULL); 1384 NT_ASSERT(SrbExtension->AtaFunction != 0); 1385 1386 if ((SrbExtension->AtaFunction == ATA_FUNCTION_ATA_IDENTIFY) && 1387 (SrbExtension->CommandReg == IDE_COMMAND_NOT_VALID)) 1388 { 1389 // Here we are safe to check SIG register 1390 sig = StorPortReadRegisterUlong(AdapterExtension, &PortExtension->Port->SIG); 1391 if (sig == 0x101) 1392 { 1393 AhciDebugPrint("\tATA Device Found!\n"); 1394 SrbExtension->CommandReg = IDE_COMMAND_IDENTIFY; 1395 } 1396 else 1397 { 1398 AhciDebugPrint("\tATAPI Device Found!\n"); 1399 SrbExtension->CommandReg = IDE_COMMAND_ATAPI_IDENTIFY; 1400 } 1401 } 1402 1403 NT_ASSERT(SlotIndex < AHCI_Global_Port_CAP_NCS(AdapterExtension->CAP)); 1404 SrbExtension->SlotIndex = SlotIndex; 1405 1406 // program the CFIS in the CommandTable 1407 CommandHeader = &PortExtension->CommandList[SlotIndex]; 1408 1409 cfl = 0; 1410 if (IsAtapiCommand(SrbExtension->AtaFunction)) 1411 { 1412 cfl = AhciATAPI_CFIS(PortExtension, SrbExtension); 1413 } 1414 else if (IsAtaCommand(SrbExtension->AtaFunction)) 1415 { 1416 cfl = AhciATA_CFIS(PortExtension, SrbExtension); 1417 } 1418 else 1419 { 1420 NT_ASSERT(FALSE); 1421 } 1422 1423 prdtlen = 0; 1424 if (IsDataTransferNeeded(SrbExtension)) 1425 { 1426 prdtlen = AhciBuild_PRDT(PortExtension, SrbExtension); 1427 NT_ASSERT(prdtlen != -1); 1428 } 1429 1430 // Program the command header 1431 CommandHeader->DI.PRDTL = prdtlen; // number of entries in PRD table 1432 CommandHeader->DI.CFL = cfl; 1433 CommandHeader->DI.A = (SrbExtension->AtaFunction & ATA_FUNCTION_ATAPI_COMMAND) ? 1 : 0; 1434 CommandHeader->DI.W = (SrbExtension->Flags & ATA_FLAGS_DATA_OUT) ? 1 : 0; 1435 CommandHeader->DI.P = 0; // ATA Specifications says so 1436 CommandHeader->DI.PMP = 0; // Port Multiplier 1437 1438 // Reset -- Manual Configuation 1439 CommandHeader->DI.R = 0; 1440 CommandHeader->DI.B = 0; 1441 CommandHeader->DI.C = 0; 1442 1443 CommandHeader->PRDBC = 0; 1444 1445 CommandHeader->Reserved[0] = 0; 1446 CommandHeader->Reserved[1] = 0; 1447 CommandHeader->Reserved[2] = 0; 1448 CommandHeader->Reserved[3] = 0; 1449 1450 // set CommandHeader CTBA 1451 CommandTablePhysicalAddress = StorPortGetPhysicalAddress(AdapterExtension, 1452 NULL, 1453 SrbExtension, 1454 &length); 1455 1456 NT_ASSERT(length != 0); 1457 1458 // command table alignment 1459 NT_ASSERT((CommandTablePhysicalAddress.LowPart % 128) == 0); 1460 1461 CommandHeader->CTBA = CommandTablePhysicalAddress.LowPart; 1462 1463 if (IsAdapterCAPS64(AdapterExtension->CAP)) 1464 { 1465 CommandHeader->CTBA_U = CommandTablePhysicalAddress.HighPart; 1466 } 1467 1468 // mark this slot 1469 PortExtension->Slot[SlotIndex] = Srb; 1470 PortExtension->QueueSlots |= 1 << SlotIndex; 1471 return; 1472 }// -- AhciProcessSrb(); 1473 1474 /** 1475 * @name AhciActivatePort 1476 * @implemented 1477 * 1478 * Program Port and populate command list 1479 * 1480 * @param PortExtension 1481 * 1482 */ 1483 1484 #ifdef _MSC_VER // avoid MSVC C4700 1485 #pragma warning(push) 1486 #pragma warning(disable: 4700) 1487 #endif 1488 1489 VOID 1490 AhciActivatePort ( 1491 __in PAHCI_PORT_EXTENSION PortExtension 1492 ) 1493 { 1494 AHCI_PORT_CMD cmd; 1495 ULONG QueueSlots, slotToActivate, tmp; 1496 PAHCI_ADAPTER_EXTENSION AdapterExtension; 1497 1498 AhciDebugPrint("AhciActivatePort()\n"); 1499 1500 AdapterExtension = PortExtension->AdapterExtension; 1501 QueueSlots = PortExtension->QueueSlots; 1502 1503 if (QueueSlots == 0) 1504 { 1505 return; 1506 } 1507 1508 // section 3.3.14 1509 // Bits in this field shall only be set to ‘1’ by software when PxCMD.ST is set to ‘1’ 1510 cmd.Status = StorPortReadRegisterUlong(AdapterExtension, &PortExtension->Port->CMD); 1511 1512 if (cmd.ST == 0) // PxCMD.ST == 0 1513 { 1514 return; 1515 } 1516 1517 // get the lowest set bit 1518 tmp = QueueSlots & (QueueSlots - 1); 1519 1520 if (tmp == 0) 1521 slotToActivate = QueueSlots; 1522 else 1523 slotToActivate = (QueueSlots & (~tmp)); 1524 1525 // mark that bit off in QueueSlots 1526 // so we can know we it is really needed to activate port or not 1527 PortExtension->QueueSlots &= ~slotToActivate; 1528 // mark this CommandIssuedSlots 1529 // to validate in completeIssuedCommand 1530 PortExtension->CommandIssuedSlots |= slotToActivate; 1531 1532 // tell the HBA to issue this Command Slot to the given port 1533 StorPortWriteRegisterUlong(AdapterExtension, &PortExtension->Port->CI, slotToActivate); 1534 1535 return; 1536 }// -- AhciActivatePort(); 1537 1538 #ifdef _MSC_VER // avoid MSVC C4700 1539 #pragma warning(pop) 1540 #endif 1541 1542 /** 1543 * @name AhciProcessIO 1544 * @implemented 1545 * 1546 * Acquire Exclusive lock to port, populate pending commands to command List 1547 * program controller's port to process new commands in command list. 1548 * 1549 * @param AdapterExtension 1550 * @param PathId 1551 * @param Srb 1552 * 1553 */ 1554 VOID 1555 AhciProcessIO ( 1556 __in PAHCI_ADAPTER_EXTENSION AdapterExtension, 1557 __in UCHAR PathId, 1558 __in PSCSI_REQUEST_BLOCK Srb 1559 ) 1560 { 1561 PSCSI_REQUEST_BLOCK tmpSrb; 1562 STOR_LOCK_HANDLE lockhandle = {0}; 1563 PAHCI_PORT_EXTENSION PortExtension; 1564 ULONG commandSlotMask, occupiedSlots, slotIndex, NCS; 1565 1566 AhciDebugPrint("AhciProcessIO()\n"); 1567 AhciDebugPrint("\tPathId: %d\n", PathId); 1568 1569 PortExtension = &AdapterExtension->PortExtension[PathId]; 1570 1571 NT_ASSERT(PathId < AdapterExtension->PortCount); 1572 1573 // Acquire Lock 1574 StorPortAcquireSpinLock(AdapterExtension, InterruptLock, NULL, &lockhandle); 1575 1576 // add Srb to queue 1577 AddQueue(&PortExtension->SrbQueue, Srb); 1578 1579 if (PortExtension->DeviceParams.IsActive == FALSE) 1580 { 1581 // Release Lock 1582 StorPortReleaseSpinLock(AdapterExtension, &lockhandle); 1583 return; // we should wait for device to get active 1584 } 1585 1586 occupiedSlots = (PortExtension->QueueSlots | PortExtension->CommandIssuedSlots); // Busy command slots for given port 1587 NCS = AHCI_Global_Port_CAP_NCS(AdapterExtension->CAP); 1588 commandSlotMask = (1 << NCS) - 1; // available slots mask 1589 1590 commandSlotMask = (commandSlotMask & ~occupiedSlots); 1591 if(commandSlotMask != 0) 1592 { 1593 // iterate over HBA port slots 1594 for (slotIndex = 0; slotIndex < NCS; slotIndex++) 1595 { 1596 // find first free slot 1597 if ((commandSlotMask & (1 << slotIndex)) != 0) 1598 { 1599 tmpSrb = RemoveQueue(&PortExtension->SrbQueue); 1600 if (tmpSrb != NULL) 1601 { 1602 NT_ASSERT(tmpSrb->PathId == PathId); 1603 AhciProcessSrb(PortExtension, tmpSrb, slotIndex); 1604 } 1605 else 1606 { 1607 break; 1608 } 1609 } 1610 else 1611 { 1612 break; 1613 } 1614 } 1615 } 1616 1617 // program HBA port 1618 AhciActivatePort(PortExtension); 1619 1620 // Release Lock 1621 StorPortReleaseSpinLock(AdapterExtension, &lockhandle); 1622 1623 return; 1624 }// -- AhciProcessIO(); 1625 1626 /** 1627 * @name AtapiInquiryCompletion 1628 * @implemented 1629 * 1630 * AtapiInquiryCompletion routine should be called after device signals 1631 * for device inquiry request is completed (through interrupt) -- ATAPI Device only 1632 * 1633 * @param PortExtension 1634 * @param Srb 1635 * 1636 */ 1637 VOID 1638 AtapiInquiryCompletion ( 1639 __in PVOID _Extension, 1640 __in PVOID _Srb 1641 ) 1642 { 1643 PAHCI_PORT_EXTENSION PortExtension; 1644 PAHCI_ADAPTER_EXTENSION AdapterExtension; 1645 PSCSI_REQUEST_BLOCK Srb; 1646 BOOLEAN status; 1647 1648 AhciDebugPrint("AtapiInquiryCompletion()\n"); 1649 1650 PortExtension = (PAHCI_PORT_EXTENSION)_Extension; 1651 Srb = (PSCSI_REQUEST_BLOCK)_Srb; 1652 1653 NT_ASSERT(Srb != NULL); 1654 NT_ASSERT(PortExtension != NULL); 1655 1656 AdapterExtension = PortExtension->AdapterExtension; 1657 1658 // send queue depth 1659 status = StorPortSetDeviceQueueDepth(PortExtension->AdapterExtension, 1660 Srb->PathId, 1661 Srb->TargetId, 1662 Srb->Lun, 1663 AHCI_Global_Port_CAP_NCS(AdapterExtension->CAP)); 1664 1665 NT_ASSERT(status == TRUE); 1666 return; 1667 }// -- AtapiInquiryCompletion(); 1668 1669 /** 1670 * @name InquiryCompletion 1671 * @implemented 1672 * 1673 * InquiryCompletion routine should be called after device signals 1674 * for device inquiry request is completed (through interrupt) 1675 * 1676 * @param PortExtension 1677 * @param Srb 1678 * 1679 */ 1680 VOID 1681 InquiryCompletion ( 1682 __in PVOID _Extension, 1683 __in PVOID _Srb 1684 ) 1685 { 1686 PAHCI_PORT_EXTENSION PortExtension; 1687 PSCSI_REQUEST_BLOCK Srb; 1688 1689 // PCDB cdb; 1690 BOOLEAN status; 1691 PINQUIRYDATA InquiryData; 1692 PAHCI_SRB_EXTENSION SrbExtension; 1693 PAHCI_ADAPTER_EXTENSION AdapterExtension; 1694 PIDENTIFY_DEVICE_DATA IdentifyDeviceData; 1695 1696 AhciDebugPrint("InquiryCompletion()\n"); 1697 1698 PortExtension = (PAHCI_PORT_EXTENSION)_Extension; 1699 Srb = (PSCSI_REQUEST_BLOCK)_Srb; 1700 1701 NT_ASSERT(Srb != NULL); 1702 NT_ASSERT(PortExtension != NULL); 1703 1704 // cdb = (PCDB)&Srb->Cdb; 1705 InquiryData = Srb->DataBuffer; 1706 SrbExtension = GetSrbExtension(Srb); 1707 AdapterExtension = PortExtension->AdapterExtension; 1708 IdentifyDeviceData = PortExtension->IdentifyDeviceData; 1709 1710 if (Srb->SrbStatus != SRB_STATUS_SUCCESS) 1711 { 1712 if (Srb->SrbStatus == SRB_STATUS_NO_DEVICE) 1713 { 1714 PortExtension->DeviceParams.DeviceType = AHCI_DEVICE_TYPE_NODEVICE; 1715 } 1716 return; 1717 } 1718 1719 NT_ASSERT(InquiryData != NULL); 1720 NT_ASSERT(Srb->SrbStatus == SRB_STATUS_SUCCESS); 1721 1722 // Device specific data 1723 PortExtension->DeviceParams.MaxLba.QuadPart = 0; 1724 1725 if (SrbExtension->CommandReg == IDE_COMMAND_IDENTIFY) 1726 { 1727 PortExtension->DeviceParams.DeviceType = AHCI_DEVICE_TYPE_ATA; 1728 if (IdentifyDeviceData->GeneralConfiguration.RemovableMedia) 1729 { 1730 PortExtension->DeviceParams.RemovableDevice = 1; 1731 } 1732 1733 if ((IdentifyDeviceData->CommandSetSupport.BigLba) && (IdentifyDeviceData->CommandSetActive.BigLba)) 1734 { 1735 PortExtension->DeviceParams.Lba48BitMode = 1; 1736 } 1737 1738 PortExtension->DeviceParams.AccessType = DIRECT_ACCESS_DEVICE; 1739 1740 /* Device max address lba */ 1741 if (PortExtension->DeviceParams.Lba48BitMode) 1742 { 1743 PortExtension->DeviceParams.MaxLba.LowPart = IdentifyDeviceData->Max48BitLBA[0]; 1744 PortExtension->DeviceParams.MaxLba.HighPart = IdentifyDeviceData->Max48BitLBA[1]; 1745 } 1746 else 1747 { 1748 PortExtension->DeviceParams.MaxLba.LowPart = IdentifyDeviceData->UserAddressableSectors; 1749 } 1750 1751 /* Bytes Per Logical Sector */ 1752 if (IdentifyDeviceData->PhysicalLogicalSectorSize.LogicalSectorLongerThan256Words) 1753 { 1754 AhciDebugPrint("\tBytesPerLogicalSector != DEVICE_ATA_BLOCK_SIZE\n"); 1755 NT_ASSERT(FALSE); 1756 } 1757 1758 PortExtension->DeviceParams.BytesPerLogicalSector = DEVICE_ATA_BLOCK_SIZE; 1759 1760 /* Bytes Per Physical Sector */ 1761 if (IdentifyDeviceData->PhysicalLogicalSectorSize.MultipleLogicalSectorsPerPhysicalSector) 1762 { 1763 AhciDebugPrint("\tBytesPerPhysicalSector != DEVICE_ATA_BLOCK_SIZE\n"); 1764 NT_ASSERT(FALSE); 1765 } 1766 1767 PortExtension->DeviceParams.BytesPerPhysicalSector = DEVICE_ATA_BLOCK_SIZE; 1768 1769 // last byte should be NULL 1770 StorPortCopyMemory(PortExtension->DeviceParams.VendorId, IdentifyDeviceData->ModelNumber, sizeof(PortExtension->DeviceParams.VendorId) - 1); 1771 StorPortCopyMemory(PortExtension->DeviceParams.RevisionID, IdentifyDeviceData->FirmwareRevision, sizeof(PortExtension->DeviceParams.RevisionID) - 1); 1772 StorPortCopyMemory(PortExtension->DeviceParams.SerialNumber, IdentifyDeviceData->SerialNumber, sizeof(PortExtension->DeviceParams.SerialNumber) - 1); 1773 1774 PortExtension->DeviceParams.VendorId[sizeof(PortExtension->DeviceParams.VendorId) - 1] = '\0'; 1775 PortExtension->DeviceParams.RevisionID[sizeof(PortExtension->DeviceParams.RevisionID) - 1] = '\0'; 1776 PortExtension->DeviceParams.SerialNumber[sizeof(PortExtension->DeviceParams.SerialNumber) - 1] = '\0'; 1777 1778 // TODO: Add other device params 1779 AhciDebugPrint("\tATA Device\n"); 1780 } 1781 else 1782 { 1783 AhciDebugPrint("\tATAPI Device\n"); 1784 PortExtension->DeviceParams.DeviceType = AHCI_DEVICE_TYPE_ATAPI; 1785 PortExtension->DeviceParams.AccessType = READ_ONLY_DIRECT_ACCESS_DEVICE; 1786 } 1787 1788 // INQUIRYDATABUFFERSIZE = 36 ; Defined in storport.h 1789 if (Srb->DataTransferLength < INQUIRYDATABUFFERSIZE) 1790 { 1791 AhciDebugPrint("\tDataBufferLength < sizeof(INQUIRYDATA), Could crash the driver.\n"); 1792 NT_ASSERT(FALSE); 1793 } 1794 1795 // update data transfer length 1796 Srb->DataTransferLength = INQUIRYDATABUFFERSIZE; 1797 1798 // prepare data to send 1799 InquiryData->Versions = 2; 1800 InquiryData->Wide32Bit = 1; 1801 InquiryData->CommandQueue = 0; // NCQ not supported 1802 InquiryData->ResponseDataFormat = 0x2; 1803 InquiryData->DeviceTypeModifier = 0; 1804 InquiryData->DeviceTypeQualifier = DEVICE_CONNECTED; 1805 InquiryData->AdditionalLength = INQUIRYDATABUFFERSIZE - 5; 1806 InquiryData->DeviceType = PortExtension->DeviceParams.AccessType; 1807 InquiryData->RemovableMedia = PortExtension->DeviceParams.RemovableDevice; 1808 1809 // Fill VendorID, Product Revision Level and other string fields 1810 StorPortCopyMemory(InquiryData->VendorId, PortExtension->DeviceParams.VendorId, sizeof(InquiryData->VendorId) - 1); 1811 StorPortCopyMemory(InquiryData->ProductId, PortExtension->DeviceParams.RevisionID, sizeof(PortExtension->DeviceParams.RevisionID)); 1812 StorPortCopyMemory(InquiryData->ProductRevisionLevel, PortExtension->DeviceParams.SerialNumber, sizeof(InquiryData->ProductRevisionLevel) - 1); 1813 1814 InquiryData->VendorId[sizeof(InquiryData->VendorId) - 1] = '\0'; 1815 InquiryData->ProductId[sizeof(InquiryData->ProductId) - 1] = '\0'; 1816 InquiryData->ProductRevisionLevel[sizeof(InquiryData->ProductRevisionLevel) - 1] = '\0'; 1817 1818 // send queue depth 1819 status = StorPortSetDeviceQueueDepth(PortExtension->AdapterExtension, 1820 Srb->PathId, 1821 Srb->TargetId, 1822 Srb->Lun, 1823 AHCI_Global_Port_CAP_NCS(AdapterExtension->CAP)); 1824 1825 NT_ASSERT(status == TRUE); 1826 return; 1827 }// -- InquiryCompletion(); 1828 1829 /** 1830 * @name AhciATAPICommand 1831 * @implemented 1832 * 1833 * Handles ATAPI Requests commands 1834 * 1835 * @param AdapterExtension 1836 * @param Srb 1837 * @param Cdb 1838 * 1839 * @return 1840 * return STOR status for AhciATAPICommand 1841 */ 1842 UCHAR 1843 AhciATAPICommand ( 1844 __in PAHCI_ADAPTER_EXTENSION AdapterExtension, 1845 __in PSCSI_REQUEST_BLOCK Srb, 1846 __in PCDB Cdb 1847 ) 1848 { 1849 ULONG SrbFlags, DataBufferLength; 1850 PAHCI_SRB_EXTENSION SrbExtension; 1851 PAHCI_PORT_EXTENSION PortExtension; 1852 1853 AhciDebugPrint("AhciATAPICommand()\n"); 1854 1855 SrbFlags = Srb->SrbFlags; 1856 SrbExtension = GetSrbExtension(Srb); 1857 DataBufferLength = Srb->DataTransferLength; 1858 PortExtension = &AdapterExtension->PortExtension[Srb->PathId]; 1859 1860 NT_ASSERT(PortExtension->DeviceParams.DeviceType == AHCI_DEVICE_TYPE_ATAPI); 1861 1862 NT_ASSERT(SrbExtension != NULL); 1863 1864 SrbExtension->AtaFunction = ATA_FUNCTION_ATAPI_COMMAND; 1865 SrbExtension->Flags = 0; 1866 1867 if (SrbFlags & SRB_FLAGS_DATA_IN) 1868 { 1869 SrbExtension->Flags |= ATA_FLAGS_DATA_IN; 1870 } 1871 1872 if (SrbFlags & SRB_FLAGS_DATA_OUT) 1873 { 1874 SrbExtension->Flags |= ATA_FLAGS_DATA_OUT; 1875 } 1876 1877 SrbExtension->FeaturesLow = 0; 1878 1879 SrbExtension->CompletionRoutine = NULL; 1880 1881 NT_ASSERT(Cdb != NULL); 1882 switch(Cdb->CDB10.OperationCode) 1883 { 1884 case SCSIOP_INQUIRY: 1885 SrbExtension->Flags |= ATA_FLAGS_DATA_IN; 1886 SrbExtension->CompletionRoutine = AtapiInquiryCompletion; 1887 break; 1888 case SCSIOP_READ: 1889 SrbExtension->Flags |= ATA_FLAGS_USE_DMA; 1890 SrbExtension->FeaturesLow = 0x5; 1891 break; 1892 case SCSIOP_WRITE: 1893 SrbExtension->Flags |= ATA_FLAGS_USE_DMA; 1894 SrbExtension->FeaturesLow = 0x1; 1895 break; 1896 } 1897 1898 SrbExtension->CommandReg = IDE_COMMAND_ATAPI_PACKET; 1899 1900 SrbExtension->LBA0 = 0; 1901 SrbExtension->LBA1 = (UCHAR)(DataBufferLength >> 0); 1902 SrbExtension->LBA2 = (UCHAR)(DataBufferLength >> 8); 1903 SrbExtension->Device = 0; 1904 SrbExtension->LBA3 = 0; 1905 SrbExtension->LBA4 = 0; 1906 SrbExtension->LBA5 = 0; 1907 SrbExtension->FeaturesHigh = 0; 1908 SrbExtension->SectorCountLow = 0; 1909 SrbExtension->SectorCountHigh = 0; 1910 1911 if ((SrbExtension->Flags & ATA_FLAGS_DATA_IN) || (SrbExtension->Flags & ATA_FLAGS_DATA_OUT)) 1912 { 1913 SrbExtension->pSgl = (PLOCAL_SCATTER_GATHER_LIST)StorPortGetScatterGatherList(AdapterExtension, Srb); 1914 } 1915 1916 return SRB_STATUS_PENDING; 1917 }// -- AhciATAPICommand(); 1918 1919 /** 1920 * @name DeviceRequestSense 1921 * @implemented 1922 * 1923 * Handle SCSIOP_MODE_SENSE OperationCode 1924 * 1925 * @param AdapterExtension 1926 * @param Srb 1927 * @param Cdb 1928 * 1929 * @return 1930 * return STOR status for DeviceRequestSense 1931 */ 1932 UCHAR 1933 DeviceRequestSense ( 1934 __in PAHCI_ADAPTER_EXTENSION AdapterExtension, 1935 __in PSCSI_REQUEST_BLOCK Srb, 1936 __in PCDB Cdb 1937 ) 1938 { 1939 PMODE_PARAMETER_HEADER ModeHeader; 1940 PAHCI_PORT_EXTENSION PortExtension; 1941 1942 AhciDebugPrint("DeviceRequestSense()\n"); 1943 1944 NT_ASSERT(IsPortValid(AdapterExtension, Srb->PathId)); 1945 NT_ASSERT(Cdb->CDB10.OperationCode == SCSIOP_MODE_SENSE); 1946 1947 PortExtension = &AdapterExtension->PortExtension[Srb->PathId]; 1948 1949 if (PortExtension->DeviceParams.DeviceType == AHCI_DEVICE_TYPE_ATAPI) 1950 { 1951 return AhciATAPICommand(AdapterExtension, Srb, Cdb); 1952 } 1953 1954 ModeHeader = (PMODE_PARAMETER_HEADER)Srb->DataBuffer; 1955 1956 NT_ASSERT(ModeHeader != NULL); 1957 1958 AhciZeroMemory((PCHAR)ModeHeader, Srb->DataTransferLength); 1959 1960 ModeHeader->ModeDataLength = sizeof(MODE_PARAMETER_HEADER); 1961 ModeHeader->MediumType = 0; 1962 ModeHeader->DeviceSpecificParameter = 0; 1963 ModeHeader->BlockDescriptorLength = 0; 1964 1965 if (Cdb->MODE_SENSE.PageCode == MODE_SENSE_CURRENT_VALUES) 1966 { 1967 ModeHeader->ModeDataLength = sizeof(MODE_PARAMETER_HEADER) + sizeof(MODE_PARAMETER_BLOCK); 1968 ModeHeader->BlockDescriptorLength = sizeof(MODE_PARAMETER_BLOCK); 1969 } 1970 1971 return SRB_STATUS_SUCCESS; 1972 }// -- DeviceRequestSense(); 1973 1974 /** 1975 * @name DeviceRequestReadWrite 1976 * @implemented 1977 * 1978 * Handle SCSIOP_READ SCSIOP_WRITE OperationCode 1979 * 1980 * @param AdapterExtension 1981 * @param Srb 1982 * @param Cdb 1983 * 1984 * @return 1985 * return STOR status for DeviceRequestReadWrite 1986 */ 1987 UCHAR 1988 DeviceRequestReadWrite ( 1989 __in PAHCI_ADAPTER_EXTENSION AdapterExtension, 1990 __in PSCSI_REQUEST_BLOCK Srb, 1991 __in PCDB Cdb 1992 ) 1993 { 1994 BOOLEAN IsReading; 1995 ULONG64 StartOffset; 1996 PAHCI_SRB_EXTENSION SrbExtension; 1997 PAHCI_PORT_EXTENSION PortExtension; 1998 ULONG DataTransferLength, BytesPerSector, SectorCount; 1999 2000 AhciDebugPrint("DeviceRequestReadWrite()\n"); 2001 2002 NT_ASSERT(IsPortValid(AdapterExtension, Srb->PathId)); 2003 NT_ASSERT((Cdb->CDB10.OperationCode == SCSIOP_READ) || (Cdb->CDB10.OperationCode == SCSIOP_WRITE)); 2004 2005 SrbExtension = GetSrbExtension(Srb); 2006 PortExtension = &AdapterExtension->PortExtension[Srb->PathId]; 2007 2008 if (PortExtension->DeviceParams.DeviceType == AHCI_DEVICE_TYPE_ATAPI) 2009 { 2010 return AhciATAPICommand(AdapterExtension, Srb, Cdb); 2011 } 2012 2013 DataTransferLength = Srb->DataTransferLength; 2014 BytesPerSector = PortExtension->DeviceParams.BytesPerLogicalSector; 2015 2016 NT_ASSERT(BytesPerSector > 0); 2017 2018 //ROUND_UP(DataTransferLength, BytesPerSector); 2019 2020 SectorCount = DataTransferLength / BytesPerSector; 2021 2022 Srb->DataTransferLength = SectorCount * BytesPerSector; 2023 2024 StartOffset = AhciGetLba(Cdb, Srb->CdbLength); 2025 IsReading = (Cdb->CDB10.OperationCode == SCSIOP_READ); 2026 2027 NT_ASSERT(SectorCount > 0); 2028 2029 SrbExtension->AtaFunction = ATA_FUNCTION_ATA_READ; 2030 SrbExtension->Flags |= ATA_FLAGS_USE_DMA; 2031 SrbExtension->CompletionRoutine = NULL; 2032 2033 if (IsReading) 2034 { 2035 SrbExtension->Flags |= ATA_FLAGS_DATA_IN; 2036 SrbExtension->CommandReg = IDE_COMMAND_READ_DMA; 2037 } 2038 else 2039 { 2040 SrbExtension->Flags |= ATA_FLAGS_DATA_OUT; 2041 SrbExtension->CommandReg = IDE_COMMAND_WRITE_DMA; 2042 } 2043 2044 SrbExtension->FeaturesLow = 0; 2045 SrbExtension->LBA0 = (StartOffset >> 0) & 0xFF; 2046 SrbExtension->LBA1 = (StartOffset >> 8) & 0xFF; 2047 SrbExtension->LBA2 = (StartOffset >> 16) & 0xFF; 2048 2049 SrbExtension->Device = (0xA0 | IDE_LBA_MODE); 2050 2051 if (PortExtension->DeviceParams.Lba48BitMode) 2052 { 2053 SrbExtension->Flags |= ATA_FLAGS_48BIT_COMMAND; 2054 2055 if (IsReading) 2056 { 2057 SrbExtension->CommandReg = IDE_COMMAND_READ_DMA_EXT; 2058 } 2059 else 2060 { 2061 SrbExtension->CommandReg = IDE_COMMAND_WRITE_DMA_EXT; 2062 } 2063 2064 SrbExtension->LBA3 = (StartOffset >> 24) & 0xFF; 2065 SrbExtension->LBA4 = (StartOffset >> 32) & 0xFF; 2066 SrbExtension->LBA5 = (StartOffset >> 40) & 0xFF; 2067 } 2068 else 2069 { 2070 NT_ASSERT(FALSE); 2071 } 2072 2073 SrbExtension->FeaturesHigh = 0; 2074 SrbExtension->SectorCountLow = (SectorCount >> 0) & 0xFF; 2075 SrbExtension->SectorCountHigh = (SectorCount >> 8) & 0xFF; 2076 2077 NT_ASSERT(SectorCount < 0x100); 2078 2079 SrbExtension->pSgl = (PLOCAL_SCATTER_GATHER_LIST)StorPortGetScatterGatherList(AdapterExtension, Srb); 2080 2081 return SRB_STATUS_PENDING; 2082 }// -- DeviceRequestReadWrite(); 2083 2084 /** 2085 * @name DeviceRequestCapacity 2086 * @implemented 2087 * 2088 * Handle SCSIOP_READ_CAPACITY OperationCode 2089 * 2090 * @param AdapterExtension 2091 * @param Srb 2092 * @param Cdb 2093 * 2094 * @return 2095 * return STOR status for DeviceRequestCapacity 2096 */ 2097 UCHAR 2098 DeviceRequestCapacity ( 2099 __in PAHCI_ADAPTER_EXTENSION AdapterExtension, 2100 __in PSCSI_REQUEST_BLOCK Srb, 2101 __in PCDB Cdb 2102 ) 2103 { 2104 ULONG MaxLba, BytesPerLogicalSector; 2105 PREAD_CAPACITY_DATA ReadCapacity; 2106 PAHCI_PORT_EXTENSION PortExtension; 2107 2108 AhciDebugPrint("DeviceRequestCapacity()\n"); 2109 2110 UNREFERENCED_PARAMETER(AdapterExtension); 2111 UNREFERENCED_PARAMETER(Cdb); 2112 2113 NT_ASSERT(Srb->DataBuffer != NULL); 2114 NT_ASSERT(IsPortValid(AdapterExtension, Srb->PathId)); 2115 2116 2117 PortExtension = &AdapterExtension->PortExtension[Srb->PathId]; 2118 2119 if (PortExtension->DeviceParams.DeviceType == AHCI_DEVICE_TYPE_ATAPI) 2120 { 2121 return AhciATAPICommand(AdapterExtension, Srb, Cdb); 2122 } 2123 2124 if (Cdb->CDB10.OperationCode == SCSIOP_READ_CAPACITY) 2125 { 2126 ReadCapacity = (PREAD_CAPACITY_DATA)Srb->DataBuffer; 2127 2128 BytesPerLogicalSector = PortExtension->DeviceParams.BytesPerLogicalSector; 2129 MaxLba = (ULONG)PortExtension->DeviceParams.MaxLba.QuadPart - 1; 2130 2131 // I trust you windows :D 2132 NT_ASSERT(Srb->DataTransferLength >= sizeof(READ_CAPACITY_DATA)); 2133 2134 // I trust you user :D 2135 NT_ASSERT(PortExtension->DeviceParams.MaxLba.QuadPart < (ULONG)-1); 2136 2137 // Actually I don't trust anyone :p 2138 Srb->DataTransferLength = sizeof(READ_CAPACITY_DATA); 2139 2140 REVERSE_BYTES(&ReadCapacity->BytesPerBlock, &BytesPerLogicalSector); 2141 REVERSE_BYTES(&ReadCapacity->LogicalBlockAddress, &MaxLba); 2142 } 2143 else 2144 { 2145 AhciDebugPrint("\tSCSIOP_READ_CAPACITY16 not supported\n"); 2146 NT_ASSERT(FALSE); 2147 } 2148 2149 return SRB_STATUS_SUCCESS; 2150 }// -- DeviceRequestCapacity(); 2151 2152 /** 2153 * @name DeviceRequestComplete 2154 * @implemented 2155 * 2156 * Handle UnHandled Requests 2157 * 2158 * @param AdapterExtension 2159 * @param Srb 2160 * @param Cdb 2161 * 2162 * @return 2163 * return STOR status for DeviceRequestComplete 2164 */ 2165 UCHAR 2166 DeviceRequestComplete ( 2167 __in PAHCI_ADAPTER_EXTENSION AdapterExtension, 2168 __in PSCSI_REQUEST_BLOCK Srb, 2169 __in PCDB Cdb 2170 ) 2171 { 2172 AhciDebugPrint("DeviceRequestComplete()\n"); 2173 2174 UNREFERENCED_PARAMETER(AdapterExtension); 2175 UNREFERENCED_PARAMETER(Cdb); 2176 2177 Srb->ScsiStatus = SCSISTAT_GOOD; 2178 2179 return SRB_STATUS_SUCCESS; 2180 }// -- DeviceRequestComplete(); 2181 2182 /** 2183 * @name DeviceReportLuns 2184 * @implemented 2185 * 2186 * Handle SCSIOP_REPORT_LUNS OperationCode 2187 * 2188 * @param AdapterExtension 2189 * @param Srb 2190 * @param Cdb 2191 * 2192 * @return 2193 * return STOR status for DeviceReportLuns 2194 */ 2195 UCHAR 2196 DeviceReportLuns ( 2197 __in PAHCI_ADAPTER_EXTENSION AdapterExtension, 2198 __in PSCSI_REQUEST_BLOCK Srb, 2199 __in PCDB Cdb 2200 ) 2201 { 2202 PLUN_LIST LunList; 2203 PAHCI_PORT_EXTENSION PortExtension; 2204 2205 AhciDebugPrint("DeviceReportLuns()\n"); 2206 2207 UNREFERENCED_PARAMETER(Cdb); 2208 2209 PortExtension = &AdapterExtension->PortExtension[Srb->PathId]; 2210 2211 NT_ASSERT(Srb->DataTransferLength >= sizeof(LUN_LIST)); 2212 NT_ASSERT(Cdb->CDB10.OperationCode == SCSIOP_REPORT_LUNS); 2213 2214 if (PortExtension->DeviceParams.DeviceType == AHCI_DEVICE_TYPE_ATAPI) 2215 { 2216 return AhciATAPICommand(AdapterExtension, Srb, Cdb); 2217 } 2218 2219 LunList = (PLUN_LIST)Srb->DataBuffer; 2220 2221 NT_ASSERT(LunList != NULL); 2222 2223 AhciZeroMemory((PCHAR)LunList, sizeof(LUN_LIST)); 2224 2225 LunList->LunListLength[3] = 8; 2226 2227 Srb->ScsiStatus = SCSISTAT_GOOD; 2228 Srb->DataTransferLength = sizeof(LUN_LIST); 2229 2230 return SRB_STATUS_SUCCESS; 2231 }// -- DeviceReportLuns(); 2232 2233 /** 2234 * @name DeviceInquiryRequest 2235 * @implemented 2236 * 2237 * Tells wheather given port is implemented or not 2238 * 2239 * @param AdapterExtension 2240 * @param Srb 2241 * @param Cdb 2242 * 2243 * @return 2244 * return STOR status for DeviceInquiryRequest 2245 * 2246 * @remark 2247 * http://www.seagate.com/staticfiles/support/disc/manuals/Interface%20manuals/100293068c.pdf 2248 */ 2249 UCHAR 2250 DeviceInquiryRequest ( 2251 __in PAHCI_ADAPTER_EXTENSION AdapterExtension, 2252 __in PSCSI_REQUEST_BLOCK Srb, 2253 __in PCDB Cdb 2254 ) 2255 { 2256 PVOID DataBuffer; 2257 PAHCI_SRB_EXTENSION SrbExtension; 2258 PAHCI_PORT_EXTENSION PortExtension; 2259 PVPD_SUPPORTED_PAGES_PAGE VpdOutputBuffer; 2260 ULONG DataBufferLength, RequiredDataBufferLength; 2261 2262 AhciDebugPrint("DeviceInquiryRequest()\n"); 2263 2264 NT_ASSERT(Cdb->CDB10.OperationCode == SCSIOP_INQUIRY); 2265 NT_ASSERT(IsPortValid(AdapterExtension, Srb->PathId)); 2266 2267 SrbExtension = GetSrbExtension(Srb); 2268 PortExtension = &AdapterExtension->PortExtension[Srb->PathId]; 2269 2270 if (PortExtension->DeviceParams.DeviceType == AHCI_DEVICE_TYPE_ATAPI) 2271 { 2272 return AhciATAPICommand(AdapterExtension, Srb, Cdb); 2273 } 2274 2275 if (Srb->Lun != 0) 2276 { 2277 return SRB_STATUS_SELECTION_TIMEOUT; 2278 } 2279 else if (Cdb->CDB6INQUIRY3.EnableVitalProductData == 0) 2280 { 2281 // 3.6.1 2282 // If the EVPD bit is set to zero, the device server shall return the standard INQUIRY data 2283 AhciDebugPrint("\tEVPD Inquired\n"); 2284 NT_ASSERT(SrbExtension != NULL); 2285 2286 SrbExtension->AtaFunction = ATA_FUNCTION_ATA_IDENTIFY; 2287 SrbExtension->Flags |= ATA_FLAGS_DATA_IN; 2288 SrbExtension->CompletionRoutine = InquiryCompletion; 2289 SrbExtension->CommandReg = IDE_COMMAND_NOT_VALID; 2290 2291 // TODO: Should use AhciZeroMemory 2292 SrbExtension->FeaturesLow = 0; 2293 SrbExtension->LBA0 = 0; 2294 SrbExtension->LBA1 = 0; 2295 SrbExtension->LBA2 = 0; 2296 SrbExtension->Device = 0xA0; 2297 SrbExtension->LBA3 = 0; 2298 SrbExtension->LBA4 = 0; 2299 SrbExtension->LBA5 = 0; 2300 SrbExtension->FeaturesHigh = 0; 2301 SrbExtension->SectorCountLow = 0; 2302 SrbExtension->SectorCountHigh = 0; 2303 2304 SrbExtension->Sgl.NumberOfElements = 1; 2305 SrbExtension->Sgl.List[0].PhysicalAddress.LowPart = PortExtension->IdentifyDeviceDataPhysicalAddress.LowPart; 2306 SrbExtension->Sgl.List[0].PhysicalAddress.HighPart = PortExtension->IdentifyDeviceDataPhysicalAddress.HighPart; 2307 SrbExtension->Sgl.List[0].Length = sizeof(IDENTIFY_DEVICE_DATA); 2308 2309 SrbExtension->pSgl = &SrbExtension->Sgl; 2310 return SRB_STATUS_PENDING; 2311 } 2312 else 2313 { 2314 AhciDebugPrint("\tVPD Inquired\n"); 2315 2316 DataBuffer = Srb->DataBuffer; 2317 DataBufferLength = Srb->DataTransferLength; 2318 RequiredDataBufferLength = DataBufferLength; // make the compiler happy :p 2319 2320 if (DataBuffer == NULL) 2321 { 2322 return SRB_STATUS_INVALID_REQUEST; 2323 } 2324 2325 AhciZeroMemory(DataBuffer, DataBufferLength); 2326 2327 switch(Cdb->CDB6INQUIRY3.PageCode) 2328 { 2329 case VPD_SUPPORTED_PAGES: 2330 { 2331 AhciDebugPrint("\tVPD_SUPPORTED_PAGES\n"); 2332 RequiredDataBufferLength = sizeof(VPD_SUPPORTED_PAGES_PAGE) + 1; 2333 2334 if (DataBufferLength < RequiredDataBufferLength) 2335 { 2336 AhciDebugPrint("\tDataBufferLength: %d Required: %d\n", DataBufferLength, RequiredDataBufferLength); 2337 return SRB_STATUS_INVALID_REQUEST; 2338 } 2339 2340 VpdOutputBuffer = (PVPD_SUPPORTED_PAGES_PAGE)DataBuffer; 2341 2342 VpdOutputBuffer->DeviceType = PortExtension->DeviceParams.AccessType; 2343 VpdOutputBuffer->DeviceTypeQualifier = 0; 2344 VpdOutputBuffer->PageCode = VPD_SUPPORTED_PAGES; 2345 VpdOutputBuffer->PageLength = 1; 2346 VpdOutputBuffer->SupportedPageList[0] = VPD_SUPPORTED_PAGES; 2347 //VpdOutputBuffer->SupportedPageList[1] = VPD_SERIAL_NUMBER; 2348 //VpdOutputBuffer->SupportedPageList[2] = VPD_DEVICE_IDENTIFIERS; 2349 2350 NT_ASSERT(VpdOutputBuffer->DeviceType == DIRECT_ACCESS_DEVICE); 2351 } 2352 break; 2353 case VPD_SERIAL_NUMBER: 2354 { 2355 AhciDebugPrint("\tVPD_SERIAL_NUMBER\n"); 2356 } 2357 break; 2358 case VPD_DEVICE_IDENTIFIERS: 2359 { 2360 AhciDebugPrint("\tVPD_DEVICE_IDENTIFIERS\n"); 2361 } 2362 break; 2363 default: 2364 AhciDebugPrint("\tPageCode: %x\n", Cdb->CDB6INQUIRY3.PageCode); 2365 return SRB_STATUS_INVALID_REQUEST; 2366 } 2367 2368 Srb->DataTransferLength = RequiredDataBufferLength; 2369 return SRB_STATUS_SUCCESS; 2370 } 2371 }// -- DeviceInquiryRequest(); 2372 2373 /** 2374 * @name AhciAdapterReset 2375 * @implemented 2376 * 2377 * 10.4.3 HBA Reset 2378 * If the HBA becomes unusable for multiple ports, and a software reset or port reset does not correct the 2379 * problem, software may reset the entire HBA by setting GHC.HR to ‘1’. When software sets the GHC.HR 2380 * bit to ‘1’, the HBA shall perform an internal reset action. The bit shall be cleared to ‘0’ by the HBA when 2381 * the reset is complete. A software write of ‘0’ to GHC.HR shall have no effect. To perform the HBA reset, 2382 * software sets GHC.HR to ‘1’ and may poll until this bit is read to be ‘0’, at which point software knows that 2383 * the HBA reset has completed. 2384 * If the HBA has not cleared GHC.HR to ‘0’ within 1 second of software setting GHC.HR to ‘1’, the HBA is in 2385 * a hung or locked state. 2386 * 2387 * @param AdapterExtension 2388 * 2389 * @return 2390 * TRUE in case AHCI Controller RESTARTED successfully. i.e GHC.HR == 0 2391 */ 2392 BOOLEAN 2393 AhciAdapterReset ( 2394 __in PAHCI_ADAPTER_EXTENSION AdapterExtension 2395 ) 2396 { 2397 ULONG ticks; 2398 AHCI_GHC ghc; 2399 PAHCI_MEMORY_REGISTERS abar = NULL; 2400 2401 AhciDebugPrint("AhciAdapterReset()\n"); 2402 2403 abar = AdapterExtension->ABAR_Address; 2404 if (abar == NULL) // basic sanity 2405 { 2406 return FALSE; 2407 } 2408 2409 // HR -- Very first bit (lowest significant) 2410 ghc.HR = 1; 2411 StorPortWriteRegisterUlong(AdapterExtension, &abar->GHC, ghc.Status); 2412 2413 for (ticks = 0; ticks < 50; ++ticks) 2414 { 2415 ghc.Status = StorPortReadRegisterUlong(AdapterExtension, &abar->GHC); 2416 if (ghc.HR == 0) 2417 { 2418 break; 2419 } 2420 StorPortStallExecution(20000); 2421 } 2422 2423 if (ticks == 50)// 1 second 2424 { 2425 AhciDebugPrint("\tDevice Timeout\n"); 2426 return FALSE; 2427 } 2428 2429 return TRUE; 2430 }// -- AhciAdapterReset(); 2431 2432 /** 2433 * @name AhciZeroMemory 2434 * @implemented 2435 * 2436 * Clear buffer by filling zeros 2437 * 2438 * @param Buffer 2439 * @param BufferSize 2440 */ 2441 FORCEINLINE 2442 VOID 2443 AhciZeroMemory ( 2444 __out PCHAR Buffer, 2445 __in ULONG BufferSize 2446 ) 2447 { 2448 ULONG i; 2449 for (i = 0; i < BufferSize; i++) 2450 { 2451 Buffer[i] = 0; 2452 } 2453 2454 return; 2455 }// -- AhciZeroMemory(); 2456 2457 /** 2458 * @name IsPortValid 2459 * @implemented 2460 * 2461 * Tells wheather given port is implemented or not 2462 * 2463 * @param AdapterExtension 2464 * @param PathId 2465 * 2466 * @return 2467 * return TRUE if provided port is valid (implemented) or not 2468 */ 2469 FORCEINLINE 2470 BOOLEAN 2471 IsPortValid ( 2472 __in PAHCI_ADAPTER_EXTENSION AdapterExtension, 2473 __in ULONG pathId 2474 ) 2475 { 2476 NT_ASSERT(pathId < MAXIMUM_AHCI_PORT_COUNT); 2477 2478 if (pathId >= AdapterExtension->PortCount) 2479 { 2480 return FALSE; 2481 } 2482 2483 return AdapterExtension->PortExtension[pathId].DeviceParams.IsActive; 2484 }// -- IsPortValid() 2485 2486 /** 2487 * @name AddQueue 2488 * @implemented 2489 * 2490 * Add Srb to Queue 2491 * 2492 * @param Queue 2493 * @param Srb 2494 * 2495 * @return 2496 * return TRUE if Srb is successfully added to Queue 2497 * 2498 */ 2499 FORCEINLINE 2500 BOOLEAN 2501 AddQueue ( 2502 __inout PAHCI_QUEUE Queue, 2503 __in PVOID Srb 2504 ) 2505 { 2506 NT_ASSERT(Queue->Head < MAXIMUM_QUEUE_BUFFER_SIZE); 2507 NT_ASSERT(Queue->Tail < MAXIMUM_QUEUE_BUFFER_SIZE); 2508 2509 if (Queue->Tail == ((Queue->Head + 1) % MAXIMUM_QUEUE_BUFFER_SIZE)) 2510 return FALSE; 2511 2512 Queue->Buffer[Queue->Head++] = Srb; 2513 Queue->Head %= MAXIMUM_QUEUE_BUFFER_SIZE; 2514 2515 return TRUE; 2516 }// -- AddQueue(); 2517 2518 /** 2519 * @name RemoveQueue 2520 * @implemented 2521 * 2522 * Remove and return Srb from Queue 2523 * 2524 * @param Queue 2525 * 2526 * @return 2527 * return Srb 2528 * 2529 */ 2530 FORCEINLINE 2531 PVOID 2532 RemoveQueue ( 2533 __inout PAHCI_QUEUE Queue 2534 ) 2535 { 2536 PVOID Srb; 2537 2538 NT_ASSERT(Queue->Head < MAXIMUM_QUEUE_BUFFER_SIZE); 2539 NT_ASSERT(Queue->Tail < MAXIMUM_QUEUE_BUFFER_SIZE); 2540 2541 if (Queue->Head == Queue->Tail) 2542 return NULL; 2543 2544 Srb = Queue->Buffer[Queue->Tail++]; 2545 Queue->Tail %= MAXIMUM_QUEUE_BUFFER_SIZE; 2546 2547 return Srb; 2548 }// -- RemoveQueue(); 2549 2550 /** 2551 * @name GetSrbExtension 2552 * @implemented 2553 * 2554 * GetSrbExtension from Srb make sure It is properly aligned 2555 * 2556 * @param Srb 2557 * 2558 * @return 2559 * return SrbExtension 2560 * 2561 */ 2562 FORCEINLINE 2563 PAHCI_SRB_EXTENSION 2564 GetSrbExtension ( 2565 __in PSCSI_REQUEST_BLOCK Srb 2566 ) 2567 { 2568 ULONG Offset; 2569 ULONG_PTR SrbExtension; 2570 2571 SrbExtension = (ULONG_PTR)Srb->SrbExtension; 2572 Offset = SrbExtension % 128; 2573 2574 // CommandTable should be 128 byte aligned 2575 if (Offset != 0) 2576 Offset = 128 - Offset; 2577 2578 return (PAHCI_SRB_EXTENSION)(SrbExtension + Offset); 2579 }// -- PAHCI_SRB_EXTENSION(); 2580 2581 /** 2582 * @name AhciGetLba 2583 * @implemented 2584 * 2585 * Find the logical address of demand block from Cdb 2586 * 2587 * @param Srb 2588 * 2589 * @return 2590 * return Logical Address of the block 2591 * 2592 */ 2593 FORCEINLINE 2594 ULONG64 2595 AhciGetLba ( 2596 __in PCDB Cdb, 2597 __in ULONG CdbLength 2598 ) 2599 { 2600 ULONG64 lba = 0; 2601 2602 NT_ASSERT(Cdb != NULL); 2603 NT_ASSERT(CdbLength != 0); 2604 2605 if (CdbLength == 0x10) 2606 { 2607 REVERSE_BYTES_QUAD(&lba, Cdb->CDB16.LogicalBlock); 2608 } 2609 else 2610 { 2611 lba |= Cdb->CDB10.LogicalBlockByte3 << 0; 2612 lba |= Cdb->CDB10.LogicalBlockByte2 << 8; 2613 lba |= Cdb->CDB10.LogicalBlockByte1 << 16; 2614 lba |= Cdb->CDB10.LogicalBlockByte0 << 24; 2615 } 2616 2617 return lba; 2618 }// -- AhciGetLba(); 2619