/
pnppower.c
3123 lines (2495 loc) · 128 KB
/
pnppower.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/*++
Copyright (C) Microsoft Corporation, 2009
Module Name:
pnppower.c
Abstract:
This file contains function of pnp and power process of the AHCI miniport.
Notes:
Revision History:
--*/
#pragma warning(push)
#pragma warning(disable:26015) //26015: "Potential overflow using expression 'outParams->DriverStatus.bDriverError'. Buffer access is apparently unbounded by the buffer size.
//Output buffer cannot be checked for size. ATAport provides this validation check as the input buffer size and output buffer size are 2 of the 4 parameters passed in on the SMART IRP. Storport doesn’t do this and the miniport doesn’t get the IRP so it cannot do this for itself. This is just the condition of a legacy IOCTL.
//26015: "Potential overflow using expression 'nRB->NRBStatus' Buffer access is apparently unbounded by the buffer size.
//The same is true for the NVCache IOCTL. Instead of the output buffer, this time it is the NVCache_Request_Block.
#pragma warning(disable:4214) // bit field types other than int
#pragma warning(disable:4201) // nameless struct/union
#include "generic.h"
#include "acpiioct.h"
//_DSM for Link Power is uniquely identified by the following UUID:
// E4DB149B-FCFE-425B-A6D8-92357D78FC7F
static const GUID LINK_POWER_ACPI_DSM_GUID = {
0xE4DB149B,
0xFCFE,
0x425B,
{ 0xA6,0xD8,0x92,0x35,0x7D,0x78,0xFC,0x7F }
};
VOID
LogPageDiscoveryCompletion (
_In_ PAHCI_CHANNEL_EXTENSION ChannelExtension,
_In_ PSTORAGE_REQUEST_BLOCK Srb
);
BOOLEAN
AhciPortInitialize(
_In_ PAHCI_CHANNEL_EXTENSION ChannelExtension
)
{
/*++
This function is used to start an AHCI port
It assumes:
Called By:
HwFindAdapter
Affected Variables/Registers:
ChannelExtension->StateFlags
ChannelExtension->CommandList
ChannelExtension->ReceivedFIS
PX.CLB,PX.CLBU
PX.FB,PX.FBU
CMD.ST
It performs:
(overview)
1. Start with some defensive structure checking and variable initialization
2. Initialize the ChannelConfiguration structure (final steps)
3. Enable the AHCI interface as per AHCI 1.1 section 10.1.2 (final steps)
4. Allocate memory for the CommandList, the Receive FIS buffer, and SRB Extension.
5. Start the channel processing commands.
(details)
1.1 Initialize variables
1.2 Verify the Channel Configuration
2.1 Initialize the ChannelConfiguration structure
2.2 Initialize the Channel's base address and the controller's Interrupt Status register address
3.1 Enable the AHCI interface
AHCI 1.1 Section 10.1.2 - 5.
"For each implemented port, system software shall allocate memory for and program:
• PxCLB and PxCLBU (if CAP.S64A is set to ‘1’)
• PxFB and PxFBU (if CAP.S64A is set to ‘1’)
It is good practice for system software to ‘zero-out’ the memory allocated and referenced by PxCLB and PxFB. After setting PxFB and PxFBU to the physical address of the FIS receive area, system software shall set PxCMD.FRE to ‘1’."
3.2 Enable Interrupts on the Channel
AHCI 1.1 Section 10.1.2 - 7.
"Determine which events should cause an interrupt, and set each implemented port’s PxIE register with the appropriate enables."
Note: Due to the multi-tiered nature of the AHCI HBA’s interrupt architecture, system software must always ensure that the PxIS (clear this first) and IS.IPS (clear this second) registers are cleared to ‘0’ before programming the PxIE and GHC.IE registers. This will prevent any residual bits set in these registers from causing an interrupt to be asserted.
4.1 Allocate memory for the CommandList, the Receive FIS buffer and SRB Extension
Now is the time to allocate memory that will be used for controller and per request structures.
In AHCI, the controller structures are both the command header list and the received FIS buffer.
The per request structure will be received through the SRB and will be used to make a Command Table
The mechanism for requesting all of this memory is AtaPortGetUnCachedExtension.
NOTE! AtaPortGetUnCachedExtension can only be called while processing a HwControl IdeStart.
Also NOTE! In order to perform crashdump/hibernate the UncachedExtensionSize cannot be larger than 30K.
The call to AtaPortGetUnCachedExtension is complicated by alignment restrictions that an AHCI controller has so here are the rules:
- Command List Base Addresses must be 1K aligned, and the Command list is (sizeof (AHCI_COMMAND_HEADER) * cap.NCS), which is some multiple of 32 bytes in length.
- The FIS Base Address must be 256 aligned, and the FIS Receive buffer is sizeof (AHCI_RECEIVED_FIS), 256 bytes in length.
- The Command Table must be 128 aligned, and is sizeof(AHCI_COMMAND_TABLE), 1280 bytes in length thanks to some padding in the AHCI_COMMAND_TABLE structure.
The alignment of the addresses (virtual and physical) returned by the function follow these rules
- the address returned by AtaPortGetUnCachedExtension will have both its virtual and physical addresses page aligned
- the memory received through the SRB will either be physically and virtually 4K aligned or SRBExtensionSize aligned. The first allocation will be on a 4K boundary the address of the second will be SRBExtensionSize larger than the first, the third will be SRBExtensionSize larger than the second, etc.
Since the Command Header must be 1K aligned and the uncached extension starts 4K aligned, this works.
However, the Command Header is variable and must be padded so the Received FIS is on a 256 boundary.
Therefore the number of Command Headers must be 256/32 = 8. Round cap.NCS to the next multiple of 8
4.2 Setup the CommandList
Although the pointer returned from AtaPortGetUnCachedExtension is useful to this driver, it does the controller no good and can't be used in CLB. The VIRTUAL address must be translated into the PHYSICAL address before being written to the CLB register as the controller doesn't have the CPU's virtual address translation tables. AtaPortGetPhysicalAddress Returns the physical address for the given Va. The va has to be an offset into any one of the following buffers.
- SRB's data buffer
- SRB's SrbExtension
- Miniport's uncached extension
4.3 Setup the Receive FIS buffer
Handle the Receive FIS buffer the same as 4.2 Command List
4.4 Setup the Local SRB Extension
5.1 Enable Command Processing
5.2 Initialize the ChannelConfiguration structure
ChannelConfiguration->ChannelNumber and ChannelConfiguration->ChannelResources are kept default values.
If it is found that CI and/or SACT can be changed from a 1 to 0, Number of overlapped requests becomes 1.
Number of overlapped requests is a 1 based number (1=1, 2=2, etc.), CAP.NCS is a 0 based number.
5.3 START COMMAND PROCESSING
Return Values:
The miniport driver returns TRUE if it successfully execute the whole function.
Any errors causes the function to return FALSE and prevents the channel from loading. This ultimately causes a yellow '!' to show up on the channel in device manager.
NOTE: as this routine is invoked from FindAdapter where the adapter might not be fully initialized, do not retrieve registry information.
--*/
PAHCI_ADAPTER_EXTENSION adapterExtension = NULL;
PAHCI_MEMORY_REGISTERS abar = NULL;
//these are throw away variables
ULONG mappedLength = 0;
//1.1 Initialize variables
adapterExtension = ChannelExtension->AdapterExtension;
if (LogExecuteFullDetail(adapterExtension->LogFlags)) {
RecordExecutionHistory(ChannelExtension, 0x00000024);//AhciPortInitialize
}
ChannelExtension->CurrentCommandSlot = 1; //slot 0 is reserved for internal commands,
ChannelExtension->StateFlags.IgnoreHotplugInterrupt = TRUE;
abar = (PAHCI_MEMORY_REGISTERS)adapterExtension->ABAR_Address;
ChannelExtension->Px = &abar->PortList[ChannelExtension->PortNumber];
// NonCachedExtension is for CommandList, Receive FIS, SRB Extension for Local SRB and Sense SRB., READ_LOG/IDENTIFY buffer
// (sizeof(AHCI_COMMAND_HEADER) * paddedNCS) + sizeof(AHCI_RECEIVED_FIS) + 2*sizeof(AHCI_SRB_EXTENSION) + sizeof(AHCI_READ_LOG_EXT_DATA);
//4.2 Setup the CommandList
ChannelExtension->CommandListPhysicalAddress = StorPortGetPhysicalAddress(adapterExtension, NULL, (PVOID)ChannelExtension->CommandList, &mappedLength);
if (ChannelExtension->CommandListPhysicalAddress.QuadPart == 0) {
RecordExecutionHistory(ChannelExtension, 0xff02);//Command List Failed
return FALSE;
}
//3.1.1 PxCLB and PxCLBU (AHCI 1.1 Section 10.1.2 - 5)
if ( (ChannelExtension->CommandListPhysicalAddress.LowPart % 1024) == 0 ) {
// validate the alignment is fine
StorPortWriteRegisterUlong(adapterExtension, &ChannelExtension->Px->CLB.AsUlong, ChannelExtension->CommandListPhysicalAddress.LowPart);
}else{
RecordExecutionHistory(ChannelExtension, 0xff03);//Command List alignment failed
return FALSE;
}
if (adapterExtension->CAP.S64A) { //If the controller supports 64 bits, write the high part too
StorPortWriteRegisterUlong(adapterExtension, &ChannelExtension->Px->CLBU, ChannelExtension->CommandListPhysicalAddress.HighPart);
}
//4.3 Setup the Receive FIS buffer
ChannelExtension->ReceivedFisPhysicalAddress = StorPortGetPhysicalAddress(adapterExtension, NULL, (PVOID)ChannelExtension->ReceivedFIS, &mappedLength);
if (ChannelExtension->ReceivedFisPhysicalAddress.QuadPart == 0) {
RecordExecutionHistory(ChannelExtension, 0xff04);//Receive FIS failed
return FALSE;
}
//3.1.2 PxFB and PxFBU (AHCI 1.1 Section 10.1.2 - 5)
if ((ChannelExtension->ReceivedFisPhysicalAddress.LowPart % 256) == 0) {
// validate the alignment is fine
StorPortWriteRegisterUlong(adapterExtension, &ChannelExtension->Px->FB.AsUlong, ChannelExtension->ReceivedFisPhysicalAddress.LowPart);
} else {
RecordExecutionHistory(ChannelExtension, 0xff05);//Receive FIS alignment failed
return FALSE;
}
if (adapterExtension->CAP.S64A) { //If the controller supports 64 bits, write the high part too
StorPortWriteRegisterUlong(adapterExtension, &ChannelExtension->Px->FBU, ChannelExtension->ReceivedFisPhysicalAddress.HighPart);
}
//4.4 Setup the Local SRB Extension
ChannelExtension->Local.SrbExtensionPhysicalAddress = StorPortGetPhysicalAddress(adapterExtension, NULL, (PVOID)ChannelExtension->Local.SrbExtension, &mappedLength);
ChannelExtension->Sense.SrbExtensionPhysicalAddress = StorPortGetPhysicalAddress(adapterExtension, NULL, (PVOID)ChannelExtension->Sense.SrbExtension, &mappedLength);
//4.6 Setup Device Identify Data and Inquiry Data buffers
ChannelExtension->DeviceExtension[0].IdentifyDataPhysicalAddress = StorPortGetPhysicalAddress(adapterExtension, NULL, (PVOID)ChannelExtension->DeviceExtension[0].IdentifyDeviceData, &mappedLength);
ChannelExtension->DeviceExtension[0].InquiryDataPhysicalAddress = StorPortGetPhysicalAddress(adapterExtension, NULL, (PVOID)ChannelExtension->DeviceExtension[0].InquiryData, &mappedLength);
//4.8 Setup STOR_ADDRESS for the device. StorAHCI uses Bus/Target/Lun addressing model, thus uses STOR_ADDRESS_TYPE_BTL8.
// Port - not need to be set by miniport, Storport has this knowledge. miniport can get the value by calling StorPortGetSystemPortNumber().
// Path - StorAHCI reports (highest implemented port number + 1) as bus number, thus "port number" will be "Path" value.
// Target - StorAHCI only supports single device on each port, the "Target" value will be 0.
// Lun - StorAHCI only supports single device on each port, the "Lun" value will be 0.
ChannelExtension->DeviceExtension[0].DeviceAddress.Type = STOR_ADDRESS_TYPE_BTL8;
ChannelExtension->DeviceExtension[0].DeviceAddress.Port = 0;
ChannelExtension->DeviceExtension[0].DeviceAddress.AddressLength = STOR_ADDR_BTL8_ADDRESS_LENGTH;
ChannelExtension->DeviceExtension[0].DeviceAddress.Path = (UCHAR)ChannelExtension->PortNumber;
ChannelExtension->DeviceExtension[0].DeviceAddress.Target = 0;
ChannelExtension->DeviceExtension[0].DeviceAddress.Lun = 0;
//
// Initialize device power state to D0.
//
ChannelExtension->DevicePowerState = StorPowerDeviceD0;
//3.2 Clear Enable Interrupts on the Channel (AHCI 1.1 Section 10.1.2 - 7)
//We will enable interrupt after channel started
PortClearPendingInterrupt(ChannelExtension);
//5.1 Enable Command Processing
ChannelExtension->StateFlags.Initialized = TRUE;
if (adapterExtension->CAP.NCS > 0) { //this leaves one emergency slot free if possible, as CAP.NCS is 0-based.
ChannelExtension->MaxPortQueueDepth = (UCHAR)adapterExtension->CAP.NCS;
} else {
ChannelExtension->MaxPortQueueDepth = 1;
}
if ( IsSingleIoDevice(adapterExtension) || IsDumpMode(adapterExtension) ) {
ChannelExtension->MaxPortQueueDepth = 1;
}
ChannelExtension->LastActiveSlot = 0;
ChannelExtension->DeviceExtension[0].DeviceParameters.MaxDeviceQueueDepth = ChannelExtension->MaxPortQueueDepth;
if (!IsDumpMode(adapterExtension)) {
if (AdapterResetInInit(adapterExtension)) {
P_NotRunning(ChannelExtension, ChannelExtension->Px);
AhciCOMRESET(ChannelExtension, ChannelExtension->Px);
}
}
RecordExecutionHistory(ChannelExtension, 0x10000024);//Exit AhciPortInitialize
return TRUE;
}
BOOLEAN
AhciAdapterPowerUp(
_In_ PAHCI_ADAPTER_EXTENSION AdapterExtension
)
/*++
Indicates that the adapter is being powered up.
Anything that doesn't persist across a power cycle needs to be done here.
It assumes:
PCI Ensures the HBA is in D0 (Offset PMCAP + 4h: PMCS[0,1])
Called by:
AhciAdapterControl
It performs:
Enables the AHCI Interface and global Interrupts
Affected Variables/Registers:
GHC.AE, GHC.IE
Return Values:
TRUE always.
--*/
{
ULONG i;
AHCI_Global_HBA_CONTROL ghc;
PAHCI_MEMORY_REGISTERS abar = (PAHCI_MEMORY_REGISTERS)AdapterExtension->ABAR_Address;
AdapterExtension->StateFlags.PowerDown = 0;
// adapter is on its way power up. there will be no power down request coming in before this function finishes.
// thus there is no need to call AdapterAcquireActiveReference;
ghc.AsUlong = StorPortReadRegisterUlong(AdapterExtension, &abar->GHC.AsUlong);
if (ghc.AE == 0) {
ghc.AsUlong = 0;
ghc.AE = 1;
StorPortWriteRegisterUlong(AdapterExtension, &abar->GHC.AsUlong, ghc.AsUlong);
}
if (ghc.IE == 0) {
ghc.IE = 1;
StorPortWriteRegisterUlong(AdapterExtension, &abar->GHC.AsUlong, ghc.AsUlong);
}
// Power up all ports that don't have a device present.
// There is protection method in AhciPortPowerUp() to only allow it run once.
for (i = 0; i <= AdapterExtension->HighestPort; i++) {
if ((AdapterExtension->PortExtension[i] != NULL) &&
(AdapterExtension->PortExtension[i]->StateFlags.PowerDown == TRUE) &&
(AdapterExtension->PortExtension[i]->DeviceExtension[0].DeviceParameters.AtaDeviceType == DeviceNotExist)) {
AhciPortPowerUp(AdapterExtension->PortExtension[i]);
}
}
return TRUE;
}
BOOLEAN
AhciAdapterPowerDown(
_In_ PAHCI_ADAPTER_EXTENSION AdapterExtension
)
/*++
Indicates that the adapter is being powered down.
It assumes:
PCI powers down the HBA after this function returns: D3 Offset PMCAP + 4h: PMCS[0,1]
Called by:
AhciAdapterControl
It performs:
1. Clear GHC.IE
AHCI 1.1 Section 8.3.3
"Software must disable interrupts (GHC.IE must be cleared to ‘0’) prior to requesting a transition of the HBA to the D3 state. This precaution by software avoids an interrupt storm if an interrupt occurs during the transition to the D3 state."
Affected Variables/Registers:
GHC.IE
Return Values:
TRUE always.
--*/
{
ULONG i;
AHCI_Global_HBA_CONTROL ghc;
PAHCI_MEMORY_REGISTERS abar = (PAHCI_MEMORY_REGISTERS)AdapterExtension->ABAR_Address;
// Power down all ports that don't have a device present.
for (i = 0; i <= AdapterExtension->HighestPort; i++) {
if ((AdapterExtension->PortExtension[i] != NULL) &&
(AdapterExtension->PortExtension[i]->StateFlags.PowerDown == FALSE) &&
(AdapterExtension->PortExtension[i]->DeviceExtension[0].DeviceParameters.AtaDeviceType == DeviceNotExist)) {
AhciPortPowerDown(AdapterExtension->PortExtension[i]);
}
}
ghc.AsUlong = StorPortReadRegisterUlong(AdapterExtension, &abar->GHC.AsUlong);
ghc.IE = 0;
StorPortWriteRegisterUlong(AdapterExtension, &abar->GHC.AsUlong, ghc.AsUlong);
AdapterExtension->StateFlags.PowerDown = 1;
return TRUE;
}
VOID
AhciPortStop(
_In_ PAHCI_CHANNEL_EXTENSION ChannelExtension
)
{
/*++
The miniport driver should stop using the resources allocated for this port.
It assumes:
AhciAdapterStop is called after all the ports are stopped.
StartIo spin lock must be held before this function is invoked.
Note:
Currently this function has only one caller - AdapterStop, which has the
following callers. Every respective code path has StartIo spin lock acquired.
1. AhciAdapterStop.
It has one caller - AhciHwStartIo. Storport has already acquired StartIo spin lock
before calling AhciHwStartIo.
2. AhciHwAdapterControl.
AhciHwAdapterControl has already acquired StartIo spin lock before calling AdapterStop.
Called by:
It performs:
(overview)
1. Stop the channel
2. Undefine all references to anything within the Uncached Extension
Affected Variables/Registers:
CMD.ST, CMD.CR, CMD.FRE, CMD.FR
Return Values:
TRUE if the function executed completely.
FALSE if the channel could not be stopped.
--*/
if (LogExecuteFullDetail(ChannelExtension->AdapterExtension->LogFlags)) {
RecordExecutionHistory(ChannelExtension, 0x00000025);//AhciPortStop
}
//1. Stop the channel
if ( !P_NotRunning(ChannelExtension, ChannelExtension->Px) ) {
// don't need RESET, the port will be tried to start when processing start device request
RecordExecutionHistory(ChannelExtension, 0xff08); //AhciPortStop Failed
}
//2. Disable Interrupt and disconnect with Port resources
StorPortWriteRegisterUlong(ChannelExtension->AdapterExtension, &ChannelExtension->Px->IE.AsUlong, 0); //disabling interrupts
PortClearPendingInterrupt(ChannelExtension);
ChannelExtension->Px = 0;
ChannelExtension->StateFlags.Initialized = FALSE;
ChannelExtension->StateFlags.NoMoreIO = FALSE;
RecordExecutionHistory(ChannelExtension, 0x10000025);//Exit AhciPortStop
return;
}
VOID
AhciPortPowerUp(
_In_ PAHCI_CHANNEL_EXTENSION ChannelExtension
)
{
/*++
Indicates that the channel is being powered up.
Called by:
AhciHwStartIo
It performs:
(overview)
1. Start the Port.
2. If APM is supported, make sure the Link is Active as defined in AHCI1.0 8.3.1.2.
3. If Port Multiplier is supported, powered it up.
(details)
1.1 Reload the CLB,CBU,FLB,FBU stored in the channel extension
1.3 Reinitialize the StateFlags
1.4 Start the channel
Affected Variables/Registers:
PxCMD.ST, PxCMD.ICC
PxCLB,PxCLBU,PxFB,PxFBU
PxIE
Return Values:
none
--*/
AHCI_LPM_POWER_SETTINGS userLpmSettings;
BOOLEAN portPowerDown;
AHCI_INTERRUPT_STATUS pxis = { 0 };
RecordExecutionHistory(ChannelExtension, 0x00000026);//Enter AhciPortPowerUp
++(ChannelExtension->TotalCountPowerUp);
pxis.AsUlong = StorPortReadRegisterUlong(ChannelExtension->AdapterExtension, &ChannelExtension->Px->IS.AsUlong);
// 1.0 Reinitialize the StateFlags. e.g. ChannelExtension->StateFlags.PowerDown = FALSE;
portPowerDown = InterlockedBitTestAndReset((LONG*)&ChannelExtension->StateFlags, 12); //StateFlags.PownDown field is at bit 12
if (portPowerDown == FALSE) {
RecordExecutionHistory(ChannelExtension, 0x00010026);//AhciPortPowerUp: port already powered up.
return;
}
// 1.1 Reload the CLB,CBU,FLB,FBU
StorPortWriteRegisterUlong(ChannelExtension->AdapterExtension, &ChannelExtension->Px->CLB.AsUlong, ChannelExtension->CommandListPhysicalAddress.LowPart);
if (ChannelExtension->AdapterExtension->CAP.S64A) { //If the controller supports 64 bits, write high part
StorPortWriteRegisterUlong(ChannelExtension->AdapterExtension, &ChannelExtension->Px->CLBU, ChannelExtension->CommandListPhysicalAddress.HighPart);
}
StorPortWriteRegisterUlong(ChannelExtension->AdapterExtension, &ChannelExtension->Px->FB.AsUlong, ChannelExtension->ReceivedFisPhysicalAddress.LowPart);
if (ChannelExtension->AdapterExtension->CAP.S64A) { //If the controller supports 64 bits, write high part
StorPortWriteRegisterUlong(ChannelExtension->AdapterExtension, &ChannelExtension->Px->FBU, ChannelExtension->ReceivedFisPhysicalAddress.HighPart);
}
//
// If D3 Cold is enabled and we are being powered up from D3, we need to be
// a bit heavy-handed with powering up the port due to loss of context.
//
if (ChannelExtension->DevicePowerState == StorPowerDeviceD3 && IsPortD3ColdEnabled(ChannelExtension)) {
STOR_LOCK_HANDLE lockhandle = { InterruptLock, 0 };
BOOLEAN powerUpInitializationInProgress = 0;
// 1.4.1 Re-issue init commands (this will also restore preserved settings).
AhciPortIssueInitCommands(ChannelExtension);
// Set PowerUpInitializationInProgress flag, which will be cleared when preserved settings command done.
powerUpInitializationInProgress = InterlockedBitTestAndSet((LONG*)&ChannelExtension->StateFlags, 22); //PowerUpInitializationInProgress field is at bit 22
if (powerUpInitializationInProgress == 1) {
// PowerUpInitializationInProgress flag was not cleared properly, which is not expected to happen, but not a fatal issue.
RecordExecutionHistory(ChannelExtension, 0x10020026); // AhciPortPowerUp: PowerUpInitializationInProgress flag was not cleared properly.
}
// 1.4.2 Restore LPM settings
userLpmSettings.AsUlong = ChannelExtension->LastUserLpmPowerSetting;
AhciLpmSettingsModes(ChannelExtension, userLpmSettings); //ignore the returned value, IO will be restarted anyway.
// 1.5 Start the channel by issuing a reset to restore PHY communication.
AhciInterruptSpinlockAcquire(ChannelExtension->AdapterExtension, ChannelExtension->PortNumber, &lockhandle);
AhciPortReset(ChannelExtension, FALSE);
AhciInterruptSpinlockRelease(ChannelExtension->AdapterExtension, ChannelExtension->PortNumber, &lockhandle);
} else {
//
// If there is change in Current Connect Status(PCS:1), then QDR is needed.
//
if ((pxis.PCS == 1) &&
(ChannelExtension->StartState.ChannelNextStartState == StartFailed)) {
ChannelExtension->StateFlags.NeedQDR = TRUE;
}
// 1.4.1 Restore Preserved Settings
if (NeedToSetTransferMode(ChannelExtension)) {
RestorePreservedSettings(ChannelExtension, FALSE);
}
// 1.5 Start the channel
P_Running_StartAttempt(ChannelExtension, FALSE);
}
RecordExecutionHistory(ChannelExtension, 0x10000026);//Exit AhciPortPowerUp
return;
}
VOID
AhciPortPowerDown(
_In_ PAHCI_CHANNEL_EXTENSION ChannelExtension
)
{
/*++
Indicates that the channel is being powered down.
It assumes:
the device has been powered down through ATA commands
All outstanding IO will be complete before the first power request is sent to the miniport
Called by:
AhciHwStartIo
It performs:
Then each port must be stopped. PxCMD.ST
If APM is supported, the Link need to be put into Slumber as defined in AHCI 1.1 Section 8.3.1.2
If Port Multiplier is support, it would need to be powered down next.
Affected Variables/Registers:
none
Return Values:
TRUE if the function executed completely.
FALSE if the channel could not be stopped for Power Down.
Neither return value is used by ATAport.
--*/
ChannelExtension->StateFlags.PowerDown = TRUE;
++(ChannelExtension->TotalCountPowerDown);
//
// Cancel the StartPortTimer since we're going into a lower power state.
//
StorPortRequestTimer(ChannelExtension->AdapterExtension,
ChannelExtension->StartPortTimer,
P_Running_Callback,
ChannelExtension,
0, 0);
if (ChannelExtension->StateFlags.PoFxEnabled == 1) {
if (IsPortD3ColdEnabled(ChannelExtension)) {
// the link will be inactive, ignore the hot plug noise.
ChannelExtension->StateFlags.IgnoreHotplugInterrupt = TRUE;
}
}
RecordExecutionHistory(ChannelExtension, 0x10000027);//Exit AhciPortPowerDown
}
VOID
ReportLunsComplete(
_In_ PAHCI_CHANNEL_EXTENSION ChannelExtension,
_In_ PSTORAGE_REQUEST_BLOCK Srb
)
{
//Port start completed. Prepare device list.
ULONG lunCount;
ULONG lunLength;
PLUN_LIST lunList;
ULONG i;
PAHCI_SRB_EXTENSION srbExtension;
ULONG srbDataBufferLength = SrbGetDataTransferLength(Srb);
srbExtension = GetSrbExtension(Srb);
// clean up callback fields so that the SRB can be completed.
srbExtension->AtaFunction = 0;
srbExtension->CompletionRoutine = NULL;
// report error back so that Storport may retry the command.
// tolerate failure from IDE_COMMAND_READ_LOG_EXT during device enumeration as it's not part of device enumeration commands.
if ( (srbExtension->TaskFile.Current.bCommandReg != IDE_COMMAND_READ_LOG_EXT) &&
(Srb->SrbStatus != SRB_STATUS_PENDING) &&
(Srb->SrbStatus != SRB_STATUS_SUCCESS) &&
(Srb->SrbStatus != SRB_STATUS_NO_DEVICE) ) {
return;
}
Srb->SrbStatus = SRB_STATUS_SUCCESS;
SrbSetScsiStatus(Srb, SCSISTAT_GOOD);
lunList = (PLUN_LIST)SrbGetDataBuffer(Srb);
if ( ChannelExtension->DeviceExtension->DeviceParameters.AtaDeviceType == DeviceNotExist ) {
lunCount = 0;
} else {
//lunCount = ChannelExtension->DeviceExtension->DeviceParameters.MaximumLun + 1;
lunCount = 1;
}
lunLength = lunCount * 8;
if ( srbDataBufferLength < (sizeof(LUN_LIST) + lunLength) ) {
Srb->SrbStatus = SRB_STATUS_DATA_OVERRUN;
if (srbDataBufferLength >= sizeof(ULONG)) {
//fill in required buffer size
lunList->LunListLength[0] = (UCHAR)(lunLength >> (8*3));
lunList->LunListLength[1] = (UCHAR)(lunLength >> (8*2));
lunList->LunListLength[2] = (UCHAR)(lunLength >> (8*1));
lunList->LunListLength[3] = (UCHAR)(lunLength >> (8*0));
}
} else {
lunList->LunListLength[0] = (UCHAR)(lunLength >> (8*3));
lunList->LunListLength[1] = (UCHAR)(lunLength >> (8*2));
lunList->LunListLength[2] = (UCHAR)(lunLength >> (8*1));
lunList->LunListLength[3] = (UCHAR)(lunLength >> (8*0));
for (i = 0; i < lunCount; i++) {
lunList->Lun[i][0] = 0;
lunList->Lun[i][1] = (UCHAR)i;
lunList->Lun[i][2] = 0;
lunList->Lun[i][3] = 0;
lunList->Lun[i][4] = 0;
lunList->Lun[i][5] = 0;
lunList->Lun[i][6] = 0;
lunList->Lun[i][7] = 0;
}
}
return;
}
__inline
VOID
GetLogInfoRegValueName(
_In_ PAHCI_CHANNEL_EXTENSION ChannelExtension,
_Out_writes_(ValueNameLength) PCHAR ValueName,
_In_ ULONG ValueNameLength
)
/*++
Routine Description:
This function append Port Number to "LogPageInfo" as name of registry value.
This is a work around as StorAHCI doesn't have access to RtlStringCbPrintfA().
Arguments:
ChannelExtension - Pointer to the device extension for channel.
ValueName - Registry name to be written.
ValueNameLength - Registry name length.
Return Value:
None.
--*/
{
NT_ASSERT(ChannelExtension->PortNumber <= 255);
if (ValueNameLength >= 14) {
ULONG portNumber = ChannelExtension->PortNumber;
ULONG remainder = 0;
StorPortCopyMemory(ValueName, "LogPageInfo", 12);
ValueName[13] = '\0';
remainder = portNumber % 16; // use HEX value, base is 16.
ValueName[12] = (CHAR)((remainder < 10) ? (remainder + '0') : (remainder - 10 + 'A'));
portNumber /= 16;
remainder = portNumber % 16;
ValueName[11] = (CHAR)((remainder < 10) ? (remainder + '0') : (remainder - 10 + 'A'));
}
return;
}
_Function_class_(HW_WORKITEM)
VOID
AhciRegistryWriteWorker(
_In_ PAHCI_ADAPTER_EXTENSION AdapterExtension,
_In_ PVOID Context,
_In_ PVOID WorkItem
)
/*++
Routine Description:
This function runs in the context of a work item. It performs writting registry with data
from Log Pages that needs to be cached.
Arguments:
AdapterExtension - Pointer to the device extension for adapter.
Context - The AHCI_CHANNEL_EXTENSION we specified when we queued this work item.
WorkItem - The work item object.
Return Value:
None.
--*/
{
PAHCI_CHANNEL_EXTENSION channelExtension = (PAHCI_CHANNEL_EXTENSION)Context;
ULONG storStatus;
CHAR valueName[16] = { 0 };
AHCI_DEVICE_LOG_PAGE_INFO logPageInfo = { 0 };
NT_ASSERT(Context != NULL);
NT_ASSERT(WorkItem != NULL);
GetLogInfoRegValueName(channelExtension, valueName, sizeof(valueName));
StorPortCopyMemory((PVOID)&logPageInfo.QueryLogPages, &channelExtension->DeviceExtension[0].QueryLogPages, sizeof(ATA_GPL_PAGES_TO_QUERY));
StorPortCopyMemory((PVOID)&logPageInfo.SupportedGPLPages, &channelExtension->DeviceExtension[0].SupportedGPLPages, sizeof(ATA_SUPPORTED_GPL_PAGES));
StorPortCopyMemory((PVOID)&logPageInfo.SupportedCommands, &channelExtension->DeviceExtension[0].SupportedCommands, sizeof(ATA_COMMAND_SUPPORTED));
StorPortCopyMemory((PVOID)&logPageInfo.FirmwareUpdate, &channelExtension->DeviceExtension[0].FirmwareUpdate, sizeof(DOWNLOAD_MICROCODE_CAPABILITIES));
storStatus = StorPortRegistryWriteAdapterKey(AdapterExtension,
(PUCHAR)"StorAHCI",
(PUCHAR)valueName,
MINIPORT_REG_BINARY,
&logPageInfo,
sizeof(AHCI_DEVICE_LOG_PAGE_INFO));
if (storStatus == STOR_STATUS_SUCCESS) {
channelExtension->DeviceExtension[0].UpdateCachedLogPageInfo = FALSE;
} else {
NT_ASSERT(FALSE);
}
//
// Call the callback routine if there is one.
//
if (WorkItem != NULL) {
StorPortFreeWorker(AdapterExtension, WorkItem);
}
return;
}
VOID
PreserveLogPageInformation(
_In_ PAHCI_CHANNEL_EXTENSION ChannelExtension
)
/*++
This routine allocates a work item and schedule it for saving information retrieved from Log Pages.
Parameters:
ChannelExtension - port and device that log pages are retrieved from.
Return Values:
None
--*/
{
ULONG storStatus;
PVOID workItem = NULL;
storStatus = StorPortInitializeWorker(ChannelExtension->AdapterExtension, &workItem);
if (storStatus == STOR_STATUS_SUCCESS) {
storStatus = StorPortQueueWorkItem(ChannelExtension->AdapterExtension, AhciRegistryWriteWorker, workItem, ChannelExtension);
}
NT_ASSERT(storStatus == STOR_STATUS_SUCCESS);
if ((storStatus != STOR_STATUS_SUCCESS) && (workItem != NULL)) {
// Free the work item as it cannot be scheduled to run.
StorPortFreeWorker(ChannelExtension->AdapterExtension, workItem);
}
return;
}
VOID
InitQueryLogPages(
_In_ PAHCI_CHANNEL_EXTENSION ChannelExtension
)
/*++
Initialize Log Pages to Read.
Note that this functions should only be called after Identify Device Data is retrieved.
Parameters:
ChannelExtension - port that log-pages-to-query should be inited.
Return Values:
None
--*/
{
PUSHORT index = &ChannelExtension->DeviceExtension->QueryLogPages.TotalPageCount;
//
// Log Page only applies to ATA device; General Purpose Logging feature should be supported;
// 48bit command should be supported as READ LOG EXT is a 48bit command.
//
if (!IsDeviceGeneralPurposeLoggingSupported(ChannelExtension)) {
return;
}
AhciZeroMemory((PCHAR)&ChannelExtension->DeviceExtension->QueryLogPages, sizeof(ATA_GPL_PAGES_TO_QUERY));
// Read Log Directory
ChannelExtension->DeviceExtension->QueryLogPages.LogPage[*index].Query = TRUE;
ChannelExtension->DeviceExtension->QueryLogPages.LogPage[*index].LogAddress = IDE_GP_LOG_DIRECTORY_ADDRESS;
ChannelExtension->DeviceExtension->QueryLogPages.LogPage[*index].PageNumber = 0;
ChannelExtension->DeviceExtension->QueryLogPages.LogPage[*index].BlockCount = 1;
ChannelExtension->DeviceExtension->QueryLogPages.LogPage[*index].FeatureField = 0;
*index = *index + 1;
// Read Device Statistics log - supported page
ChannelExtension->DeviceExtension->QueryLogPages.LogPage[*index].Query = TRUE;
ChannelExtension->DeviceExtension->QueryLogPages.LogPage[*index].LogAddress = IDE_GP_LOG_DEVICE_STATISTICS_ADDRESS;
ChannelExtension->DeviceExtension->QueryLogPages.LogPage[*index].PageNumber = IDE_GP_LOG_SUPPORTED_PAGES;
ChannelExtension->DeviceExtension->QueryLogPages.LogPage[*index].BlockCount = 1;
ChannelExtension->DeviceExtension->QueryLogPages.LogPage[*index].FeatureField = 0;
*index = *index + 1;
// Read Device Statistics log - general page
ChannelExtension->DeviceExtension->QueryLogPages.LogPage[*index].Query = TRUE;
ChannelExtension->DeviceExtension->QueryLogPages.LogPage[*index].LogAddress = IDE_GP_LOG_DEVICE_STATISTICS_ADDRESS;
ChannelExtension->DeviceExtension->QueryLogPages.LogPage[*index].PageNumber = IDE_GP_LOG_DEVICE_STATISTICS_GENERAL_PAGE;
ChannelExtension->DeviceExtension->QueryLogPages.LogPage[*index].BlockCount = 1;
ChannelExtension->DeviceExtension->QueryLogPages.LogPage[*index].FeatureField = 0;
*index = *index + 1;
// Read Identify Device Data log - supported page
ChannelExtension->DeviceExtension->QueryLogPages.LogPage[*index].Query = TRUE;
ChannelExtension->DeviceExtension->QueryLogPages.LogPage[*index].LogAddress = IDE_GP_LOG_IDENTIFY_DEVICE_DATA_ADDRESS;
ChannelExtension->DeviceExtension->QueryLogPages.LogPage[*index].PageNumber = IDE_GP_LOG_SUPPORTED_PAGES;
ChannelExtension->DeviceExtension->QueryLogPages.LogPage[*index].BlockCount = 1;
ChannelExtension->DeviceExtension->QueryLogPages.LogPage[*index].FeatureField = 0;
*index = *index + 1;
// Read Identify Device Data log - Supported Capabilities page
ChannelExtension->DeviceExtension->QueryLogPages.LogPage[*index].Query = TRUE;
ChannelExtension->DeviceExtension->QueryLogPages.LogPage[*index].LogAddress = IDE_GP_LOG_IDENTIFY_DEVICE_DATA_ADDRESS;
ChannelExtension->DeviceExtension->QueryLogPages.LogPage[*index].PageNumber = IDE_GP_LOG_IDENTIFY_DEVICE_DATA_SUPPORTED_CAPABILITIES_PAGE;
ChannelExtension->DeviceExtension->QueryLogPages.LogPage[*index].BlockCount = 1;
ChannelExtension->DeviceExtension->QueryLogPages.LogPage[*index].FeatureField = 0;
*index = *index + 1;
// Read Identify Device Data log - SATA page
ChannelExtension->DeviceExtension->QueryLogPages.LogPage[*index].Query = TRUE;
ChannelExtension->DeviceExtension->QueryLogPages.LogPage[*index].LogAddress = IDE_GP_LOG_IDENTIFY_DEVICE_DATA_ADDRESS;
ChannelExtension->DeviceExtension->QueryLogPages.LogPage[*index].PageNumber = IDE_GP_LOG_IDENTIFY_DEVICE_DATA_SATA_PAGE;
ChannelExtension->DeviceExtension->QueryLogPages.LogPage[*index].BlockCount = 1;
ChannelExtension->DeviceExtension->QueryLogPages.LogPage[*index].FeatureField = 0;
*index = *index + 1;
// Read Saved Device Internal log
ChannelExtension->DeviceExtension->QueryLogPages.LogPage[*index].Query = TRUE;
ChannelExtension->DeviceExtension->QueryLogPages.LogPage[*index].LogAddress = IDE_GP_LOG_SAVED_DEVICE_INTERNAL_STATUS;
ChannelExtension->DeviceExtension->QueryLogPages.LogPage[*index].PageNumber = 0;
ChannelExtension->DeviceExtension->QueryLogPages.LogPage[*index].BlockCount = 1;
ChannelExtension->DeviceExtension->QueryLogPages.LogPage[*index].FeatureField = 0;
*index = *index + 1;
// Read NCQ non-Data log
if ((ChannelExtension->DeviceExtension->IdentifyDeviceData->SerialAtaCapabilities.NCQ == 1) &&
(ChannelExtension->DeviceExtension->IdentifyDeviceData->SerialAtaCapabilities.NcqQueueMgmt == 1)) {
ChannelExtension->DeviceExtension->QueryLogPages.LogPage[*index].Query = TRUE;
} else {
ChannelExtension->DeviceExtension->QueryLogPages.LogPage[*index].Query = FALSE;
}
ChannelExtension->DeviceExtension->QueryLogPages.LogPage[*index].LogAddress = IDE_GP_LOG_NCQ_NON_DATA_ADDRESS;
ChannelExtension->DeviceExtension->QueryLogPages.LogPage[*index].PageNumber = 0;
ChannelExtension->DeviceExtension->QueryLogPages.LogPage[*index].BlockCount = 1;
ChannelExtension->DeviceExtension->QueryLogPages.LogPage[*index].FeatureField = 0;
*index = *index + 1;
// Read NCQ Send Receive log
if ((ChannelExtension->DeviceExtension->IdentifyDeviceData->SerialAtaCapabilities.NCQ == 1) &&
(ChannelExtension->DeviceExtension->IdentifyDeviceData->SerialAtaCapabilities.NcqReceiveSend == 1)) {
ChannelExtension->DeviceExtension->QueryLogPages.LogPage[*index].Query = TRUE;
} else {
ChannelExtension->DeviceExtension->QueryLogPages.LogPage[*index].Query = FALSE;
}
ChannelExtension->DeviceExtension->QueryLogPages.LogPage[*index].LogAddress = IDE_GP_LOG_NCQ_SEND_RECEIVE_ADDRESS;
ChannelExtension->DeviceExtension->QueryLogPages.LogPage[*index].PageNumber = 0;
ChannelExtension->DeviceExtension->QueryLogPages.LogPage[*index].BlockCount = 1;
ChannelExtension->DeviceExtension->QueryLogPages.LogPage[*index].FeatureField = 0;
*index = *index + 1;
NT_ASSERT(*index <= ATA_GPL_PAGES_QUERY_COUNT);
return;
}
VOID
IssueReadLogExtCommand(
_In_ PAHCI_CHANNEL_EXTENSION ChannelExtension,
_In_ PSTORAGE_REQUEST_BLOCK Srb,
_In_ UCHAR LogAddress,
_In_ USHORT PageNumber,
_In_ USHORT BlockCount,
_In_ USHORT FeatureField,
_In_opt_ PSTOR_PHYSICAL_ADDRESS PhysicalAddress,
_In_ PVOID DataBuffer,
_In_opt_ PSRB_COMPLETION_ROUTINE CompletionRoutine
)
/*++
Issue READ LOG EXT command to device
Parameters:
ChannelExtension - port that the command should be sent to
Srb - Srb that carries READ LOG EXT command in SrbExtension
LogAddress - Log address
PageNumber - Page# of the log
BlockCount - How many blocks (in 512 bytes)
FeatureField - log specific value
PhysicalAddress - Buffer physical address
DataBuffer - Buffer
CompletionRoutine - Routine that needs to be executed after READ LOG EXT command completed
Return Values:
None
--*/
{
PAHCI_SRB_EXTENSION srbExtension = GetSrbExtension(Srb);
UNREFERENCED_PARAMETER(ChannelExtension);
//1 Fills in the local SRB
srbExtension->AtaFunction = ATA_FUNCTION_ATA_COMMAND;
srbExtension->Flags |= ATA_FLAGS_DATA_IN ;
srbExtension->Flags |= ATA_FLAGS_48BIT_COMMAND ;
srbExtension->CompletionRoutine = CompletionRoutine;
//setup TaskFile
srbExtension->TaskFile.Current.bFeaturesReg = (UCHAR)(FeatureField & 0xFF); //FeatureField, low part
srbExtension->TaskFile.Current.bSectorCountReg = (UCHAR)(BlockCount & 0xFF); //Number of blocks to read, low part
srbExtension->TaskFile.Current.bSectorNumberReg = LogAddress; //Log address
srbExtension->TaskFile.Current.bCylLowReg = (UCHAR)(PageNumber & 0xFF); //Page#, low part
srbExtension->TaskFile.Current.bCylHighReg = 0;
srbExtension->TaskFile.Current.bDriveHeadReg = 0xA0 | IDE_LBA_MODE;
srbExtension->TaskFile.Current.bCommandReg = IDE_COMMAND_READ_LOG_EXT;
srbExtension->TaskFile.Current.bReserved = 0;
srbExtension->TaskFile.Previous.bFeaturesReg = (UCHAR)((FeatureField >> 8) & 0xFF); //FeatureField, high part
srbExtension->TaskFile.Previous.bSectorCountReg = (UCHAR)((BlockCount >> 8) & 0xFF); //Number of blocks to read, high part
srbExtension->TaskFile.Previous.bSectorNumberReg = 0;
srbExtension->TaskFile.Previous.bCylLowReg = (UCHAR)((PageNumber >> 8) & 0xFF); //Page#, high part
srbExtension->TaskFile.Previous.bCylHighReg = 0;
srbExtension->TaskFile.Previous.bDriveHeadReg = 0;
srbExtension->TaskFile.Previous.bCommandReg = 0;
srbExtension->TaskFile.Previous.bReserved = 0;
Srb->SrbStatus = SRB_STATUS_PENDING;
srbExtension->DataBuffer = DataBuffer;
if ( PhysicalAddress ) {
srbExtension->DataBufferPhysicalAddress.QuadPart = PhysicalAddress->QuadPart;
}
//setup SGL
if ( PhysicalAddress ) {
srbExtension->LocalSgl.NumberOfElements = 1;
srbExtension->LocalSgl.List[0].PhysicalAddress.LowPart = PhysicalAddress->LowPart;
srbExtension->LocalSgl.List[0].PhysicalAddress.HighPart = PhysicalAddress->HighPart;
srbExtension->LocalSgl.List[0].Length = ATA_BLOCK_SIZE * (ULONG)BlockCount;
srbExtension->Sgl = &srbExtension->LocalSgl;
srbExtension->DataTransferLength = ATA_BLOCK_SIZE * (ULONG)BlockCount;
}
return;
}
__inline
USHORT
GetNextQueryLogPageIndex (
_In_ PAHCI_CHANNEL_EXTENSION ChannelExtension
)
/*++
Get an Index value that log page should be queried.