[CLT2012]
[reactos.git] / drivers / storage / ide / uniata / id_sata.cpp
1 /*++
2
3 Copyright (c) 2008-2011 Alexandr A. Telyatnikov (Alter)
4
5 Module Name:
6 id_probe.cpp
7
8 Abstract:
9 This module handles SATA-related staff
10
11 Author:
12 Alexander A. Telyatnikov (Alter)
13
14 Environment:
15 kernel mode only
16
17 Notes:
18
19 THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22 IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28 THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
30 Revision History:
31
32 --*/
33
34 #include "stdafx.h"
35
36 UCHAR
37 NTAPI
38 UniataSataConnect(
39 IN PVOID HwDeviceExtension,
40 IN ULONG lChannel, // logical channel
41 IN ULONG pm_port /* for port multipliers */
42 )
43 {
44 PHW_DEVICE_EXTENSION deviceExtension = (PHW_DEVICE_EXTENSION)HwDeviceExtension;
45 //ULONG Channel = deviceExtension->Channel + lChannel;
46 PHW_CHANNEL chan = &deviceExtension->chan[lChannel];
47 SATA_SSTATUS_REG SStatus;
48 ULONG i;
49 /*
50 UCHAR signatureLow,
51 signatureHigh;
52 */
53 UCHAR Status;
54
55 KdPrint2((PRINT_PREFIX "UniataSataConnect:\n"));
56
57 if(!UniataIsSATARangeAvailable(deviceExtension, lChannel)) {
58 KdPrint2((PRINT_PREFIX " no I/O range\n"));
59 return IDE_STATUS_IDLE;
60 }
61
62 /* clear SATA error register, some controllers need this */
63 UniataSataWritePort4(chan, IDX_SATA_SError,
64 UniataSataReadPort4(chan, IDX_SATA_SError, pm_port), pm_port);
65 /* wait up to 1 second for "connect well" */
66 for(i=0; i<100; i++) {
67 SStatus.Reg = UniataSataReadPort4(chan, IDX_SATA_SStatus, pm_port);
68 if(SStatus.SPD == SStatus_SPD_Gen1 ||
69 SStatus.SPD == SStatus_SPD_Gen2 ||
70 SStatus.SPD == SStatus_SPD_Gen3) {
71 chan->lun[0]->TransferMode = ATA_SA150 + (UCHAR)(SStatus.SPD - 1);
72 KdPrint2((PRINT_PREFIX "SATA TransferMode %#x\n", chan->lun[0]->TransferMode));
73 break;
74 }
75 AtapiStallExecution(10000);
76 }
77 if(i >= 100) {
78 KdPrint2((PRINT_PREFIX "UniataSataConnect: SStatus %8.8x\n", SStatus.Reg));
79 return 0xff;
80 }
81 /* clear SATA error register */
82 UniataSataWritePort4(chan, IDX_SATA_SError,
83 UniataSataReadPort4(chan, IDX_SATA_SError, pm_port), pm_port);
84
85 Status = WaitOnBaseBusyLong(chan);
86 if(Status & IDE_STATUS_BUSY) {
87 return Status;
88 }
89 /*
90 signatureLow = AtapiReadPort1(chan, &deviceExtension->BaseIoAddress1[lChannel].i.CylinderLow);
91 signatureHigh = AtapiReadPort1(chan, &deviceExtension->baseIoAddress1[lChannel].i.CylinderHigh);
92
93 if (signatureLow == ATAPI_MAGIC_LSB && signatureHigh == ATAPI_MAGIC_MSB) {
94 }
95 */
96 KdPrint2((PRINT_PREFIX "UniataSataConnect: OK, ATA status %#x\n", Status));
97 return IDE_STATUS_IDLE;
98 } // end UniataSataConnect()
99
100 UCHAR
101 NTAPI
102 UniataSataPhyEnable(
103 IN PVOID HwDeviceExtension,
104 IN ULONG lChannel, // logical channel
105 IN ULONG pm_port, /* for port multipliers */
106 IN BOOLEAN doReset
107 )
108 {
109 PHW_DEVICE_EXTENSION deviceExtension = (PHW_DEVICE_EXTENSION)HwDeviceExtension;
110 PHW_CHANNEL chan = &deviceExtension->chan[lChannel];
111 SATA_SCONTROL_REG SControl;
112 int loop, retry;
113
114 KdPrint2((PRINT_PREFIX "UniataSataPhyEnable:\n"));
115
116 if(!UniataIsSATARangeAvailable(deviceExtension, lChannel)) {
117 KdPrint2((PRINT_PREFIX " no I/O range\n"));
118 return IDE_STATUS_IDLE;
119 }
120
121 SControl.Reg = UniataSataReadPort4(chan, IDX_SATA_SControl, pm_port);
122 KdPrint2((PRINT_PREFIX "SControl %#x\n", SControl.Reg));
123 if(SControl.DET == SControl_DET_Idle) {
124 if(!doReset) {
125 return UniataSataConnect(HwDeviceExtension, lChannel, pm_port);
126 }
127 }
128
129 for (retry = 0; retry < 10; retry++) {
130 KdPrint2((PRINT_PREFIX "UniataSataPhyEnable: retry init %d\n", retry));
131 for (loop = 0; loop < 10; loop++) {
132 SControl.Reg = 0;
133 SControl.DET = SControl_DET_Init;
134 UniataSataWritePort4(chan, IDX_SATA_SControl, SControl.Reg, pm_port);
135 AtapiStallExecution(100);
136 SControl.Reg = UniataSataReadPort4(chan, IDX_SATA_SControl, pm_port);
137 KdPrint2((PRINT_PREFIX " SControl %8.8x\n", SControl.Reg));
138 if(SControl.DET == SControl_DET_Init) {
139 break;
140 }
141 }
142 AtapiStallExecution(5000);
143 KdPrint2((PRINT_PREFIX "UniataSataPhyEnable: retry idle %d\n", retry));
144 for (loop = 0; loop < 10; loop++) {
145 SControl.Reg = 0;
146 SControl.DET = SControl_DET_DoNothing;
147 SControl.IPM = SControl_IPM_NoPartialSlumber;
148 UniataSataWritePort4(chan, IDX_SATA_SControl, SControl.Reg, pm_port);
149 AtapiStallExecution(100);
150 SControl.Reg = UniataSataReadPort4(chan, IDX_SATA_SControl, pm_port);
151 KdPrint2((PRINT_PREFIX " SControl %8.8x\n", SControl.Reg));
152 if(SControl.DET == SControl_DET_Idle) {
153 return UniataSataConnect(HwDeviceExtension, lChannel, pm_port);
154 }
155 }
156 }
157
158 KdPrint2((PRINT_PREFIX "UniataSataPhyEnable: failed\n"));
159 return 0xff;
160 } // end UniataSataPhyEnable()
161
162 BOOLEAN
163 NTAPI
164 UniataSataClearErr(
165 IN PVOID HwDeviceExtension,
166 IN ULONG lChannel, // logical channel
167 IN BOOLEAN do_connect,
168 IN ULONG pm_port /* for port multipliers */
169 )
170 {
171 PHW_DEVICE_EXTENSION deviceExtension = (PHW_DEVICE_EXTENSION)HwDeviceExtension;
172 PHW_CHANNEL chan = &deviceExtension->chan[lChannel];
173 //ULONG ChipFlags = deviceExtension->HwFlags & CHIPFLAG_MASK;
174 SATA_SSTATUS_REG SStatus;
175 SATA_SERROR_REG SError;
176
177 if(UniataIsSATARangeAvailable(deviceExtension, lChannel)) {
178 //if(ChipFlags & UNIATA_SATA) {
179
180 SStatus.Reg = UniataSataReadPort4(chan, IDX_SATA_SStatus, pm_port);
181 SError.Reg = UniataSataReadPort4(chan, IDX_SATA_SError, pm_port);
182
183 if(SStatus.Reg) {
184 KdPrint2((PRINT_PREFIX " SStatus %#x\n", SStatus.Reg));
185 }
186 if(SError.Reg) {
187 KdPrint2((PRINT_PREFIX " SError %#x\n", SError.Reg));
188 /* clear error bits/interrupt */
189 UniataSataWritePort4(chan, IDX_SATA_SError, SError.Reg, pm_port);
190
191 if(do_connect) {
192 /* if we have a connection event deal with it */
193 if(SError.DIAG.N) {
194 KdPrint2((PRINT_PREFIX " catch SATA connect/disconnect\n"));
195 if(SStatus.SPD >= SStatus_SPD_Gen1) {
196 UniataSataEvent(deviceExtension, lChannel, UNIATA_SATA_EVENT_ATTACH, pm_port);
197 } else {
198 UniataSataEvent(deviceExtension, lChannel, UNIATA_SATA_EVENT_DETACH, pm_port);
199 }
200 return TRUE;
201 }
202 }
203 }
204 }
205 return FALSE;
206 } // end UniataSataClearErr()
207
208 BOOLEAN
209 NTAPI
210 UniataSataEvent(
211 IN PVOID HwDeviceExtension,
212 IN ULONG lChannel, // logical channel
213 IN ULONG Action,
214 IN ULONG pm_port /* for port multipliers */
215 )
216 {
217 PHW_DEVICE_EXTENSION deviceExtension = (PHW_DEVICE_EXTENSION)HwDeviceExtension;
218 UCHAR Status;
219 ULONG DeviceNumber = (pm_port ? 1 : 0);
220
221 if(!UniataIsSATARangeAvailable(deviceExtension, lChannel)) {
222 return FALSE;
223 }
224
225 switch(Action) {
226 case UNIATA_SATA_EVENT_ATTACH:
227 KdPrint2((PRINT_PREFIX " CONNECTED\n"));
228 Status = UniataSataConnect(HwDeviceExtension, lChannel, pm_port);
229 KdPrint2((PRINT_PREFIX " Status %#x\n", Status));
230 if(Status != IDE_STATUS_IDLE) {
231 return FALSE;
232 }
233 CheckDevice(HwDeviceExtension, lChannel, DeviceNumber /*dev*/, FALSE);
234 return TRUE;
235 break;
236 case UNIATA_SATA_EVENT_DETACH:
237 KdPrint2((PRINT_PREFIX " DISCONNECTED\n"));
238 UniataForgetDevice(deviceExtension->chan[lChannel].lun[DeviceNumber]);
239 return TRUE;
240 break;
241 }
242 return FALSE;
243 } // end UniataSataEvent()
244
245 ULONG
246 NTAPI
247 UniataSataReadPort4(
248 IN PHW_CHANNEL chan,
249 IN ULONG io_port_ndx,
250 IN ULONG pm_port /* for port multipliers */
251 )
252 {
253 if(chan && (io_port_ndx < IDX_MAX_REG) &&
254 chan->RegTranslation[io_port_ndx].Proc) {
255
256 KdPrint3((PRINT_PREFIX " UniataSataReadPort4 %#x[%d]\n", io_port_ndx, pm_port));
257
258 PHW_DEVICE_EXTENSION deviceExtension = chan->DeviceExtension;
259 PVOID HwDeviceExtension = (PVOID)deviceExtension;
260 ULONG slotNumber = deviceExtension->slotNumber;
261 ULONG SystemIoBusNumber = deviceExtension->SystemIoBusNumber;
262 ULONG VendorID = deviceExtension->DevID & 0xffff;
263 ULONG offs;
264 ULONG p;
265
266 switch(VendorID) {
267 case ATA_INTEL_ID: {
268 p = pm_port ? 1 : 0;
269 if(deviceExtension->HwFlags & ICH5) {
270 offs = 0x50+chan->lun[p]->SATA_lun_map*0x10;
271 KdPrint3((PRINT_PREFIX " ICH5 way, offs %#x\n", offs));
272 switch(io_port_ndx) {
273 case IDX_SATA_SStatus:
274 offs += 0;
275 break;
276 case IDX_SATA_SError:
277 offs += 1*4;
278 break;
279 case IDX_SATA_SControl:
280 offs += 2*4;
281 break;
282 default:
283 return -1;
284 }
285 SetPciConfig4(0xa0, offs);
286 GetPciConfig4(0xa4, offs);
287 return offs;
288 } else {
289 offs = ((deviceExtension->Channel+chan->lChannel)*2+p) * 0x100;
290 KdPrint3((PRINT_PREFIX " def way, offs %#x\n", offs));
291 switch(io_port_ndx) {
292 case IDX_SATA_SStatus:
293 offs += 0;
294 break;
295 case IDX_SATA_SControl:
296 offs += 1;
297 break;
298 case IDX_SATA_SError:
299 offs += 2;
300 break;
301 default:
302 return -1;
303 }
304 AtapiWritePort4(chan, IDX_INDEXED_ADDR, offs);
305 return AtapiReadPort4(chan, IDX_INDEXED_DATA);
306 }
307 } // ATA_INTEL_ID
308 } // end switch(VendorID)
309 return -1;
310 }
311 return AtapiReadPort4(chan, io_port_ndx);
312 } // end UniataSataReadPort4()
313
314 VOID
315 NTAPI
316 UniataSataWritePort4(
317 IN PHW_CHANNEL chan,
318 IN ULONG io_port_ndx,
319 IN ULONG data,
320 IN ULONG pm_port /* for port multipliers */
321 )
322 {
323 if(chan && (io_port_ndx < IDX_MAX_REG) &&
324 chan->RegTranslation[io_port_ndx].Proc) {
325
326 KdPrint3((PRINT_PREFIX " UniataSataWritePort4 %#x[%d]\n", io_port_ndx, pm_port));
327
328 PHW_DEVICE_EXTENSION deviceExtension = chan->DeviceExtension;
329 PVOID HwDeviceExtension = (PVOID)deviceExtension;
330 ULONG slotNumber = deviceExtension->slotNumber;
331 ULONG SystemIoBusNumber = deviceExtension->SystemIoBusNumber;
332 ULONG VendorID = deviceExtension->DevID & 0xffff;
333 ULONG offs;
334 ULONG p;
335
336 switch(VendorID) {
337 case ATA_INTEL_ID: {
338 p = pm_port ? 1 : 0;
339 if(deviceExtension->HwFlags & ICH5) {
340 offs = 0x50+chan->lun[p]->SATA_lun_map*0x10;
341 KdPrint3((PRINT_PREFIX " ICH5 way, offs %#x\n", offs));
342 switch(io_port_ndx) {
343 case IDX_SATA_SStatus:
344 offs += 0;
345 break;
346 case IDX_SATA_SError:
347 offs += 1*4;
348 break;
349 case IDX_SATA_SControl:
350 offs += 2*4;
351 break;
352 default:
353 return;
354 }
355 SetPciConfig4(0xa0, offs);
356 SetPciConfig4(0xa4, data);
357 return;
358 } else {
359 offs = ((deviceExtension->Channel+chan->lChannel)*2+p) * 0x100;
360 KdPrint3((PRINT_PREFIX " def way, offs %#x\n", offs));
361 switch(io_port_ndx) {
362 case IDX_SATA_SStatus:
363 offs += 0;
364 break;
365 case IDX_SATA_SControl:
366 offs += 1;
367 break;
368 case IDX_SATA_SError:
369 offs += 2;
370 break;
371 default:
372 return;
373 }
374 AtapiWritePort4(chan, IDX_INDEXED_ADDR, offs);
375 AtapiWritePort4(chan, IDX_INDEXED_DATA, data);
376 }
377 } // ATA_INTEL_ID
378 } // end switch(VendorID)
379 return;
380 }
381 AtapiWritePort4(chan, io_port_ndx, data);
382 } // end UniataSataWritePort4()
383
384 BOOLEAN
385 NTAPI
386 UniataSataReadPM(
387 IN PHW_CHANNEL chan,
388 IN ULONG DeviceNumber,
389 IN ULONG Reg,
390 OUT PULONG result
391 )
392 {
393 if(chan->DeviceExtension->HwFlags & UNIATA_AHCI) {
394 return UniataAhciReadPM(chan, DeviceNumber, Reg, result);
395 }
396 return FALSE;
397 } // end UniataSataReadPM()
398
399 UCHAR
400 NTAPI
401 UniataSataWritePM(
402 IN PHW_CHANNEL chan,
403 IN ULONG DeviceNumber,
404 IN ULONG Reg,
405 IN ULONG value
406 )
407 {
408 if(chan->DeviceExtension->HwFlags & UNIATA_AHCI) {
409 return UniataAhciWritePM(chan, DeviceNumber, Reg, value);
410 }
411 return 0xff;
412 } // end UniataSataWritePM()
413
414 ULONG
415 NTAPI
416 UniataSataSoftReset(
417 IN PVOID HwDeviceExtension,
418 IN ULONG lChannel,
419 IN ULONG DeviceNumber
420 )
421 {
422 PHW_DEVICE_EXTENSION deviceExtension = (PHW_DEVICE_EXTENSION)HwDeviceExtension;
423
424 if(deviceExtension->HwFlags & UNIATA_AHCI) {
425 return UniataAhciSoftReset(HwDeviceExtension, lChannel, DeviceNumber);
426 }
427 return 0xffffffff;
428 } // end UniataSataSoftReset()
429
430 VOID
431 UniataSataIdentifyPM(
432 IN PHW_CHANNEL chan
433 )
434 {
435 ULONG PM_DeviceId;
436 ULONG PM_RevId;
437 ULONG PM_Ports;
438 UCHAR i;
439 ULONG signature;
440 PHW_LU_EXTENSION LunExt;
441
442 KdPrint((PRINT_PREFIX "UniataSataIdentifyPM:\n"));
443
444 chan->PmLunMap = 0;
445
446 /* get PM vendor & product data */
447 if(!UniataSataReadPM(chan, AHCI_DEV_SEL_PM, 0, &PM_DeviceId)) {
448 KdPrint2((PRINT_PREFIX " error getting PM vendor data\n"));
449 return;
450 }
451 /* get PM revision data */
452 if(!UniataSataReadPM(chan, AHCI_DEV_SEL_PM, 1, &PM_RevId)) {
453 KdPrint2((PRINT_PREFIX " error getting PM revison data\n"));
454 return;
455 }
456 /* get number of HW ports on the PM */
457 if(!UniataSataReadPM(chan, AHCI_DEV_SEL_PM, 2, &PM_Ports)) {
458 KdPrint2((PRINT_PREFIX " error getting PM port info\n"));
459 return;
460 }
461
462 PM_Ports &= 0x0000000f;
463
464 switch(PM_DeviceId) {
465 case 0x37261095:
466 /* This PM declares 6 ports, while only 5 of them are real.
467 * Port 5 is enclosure management bridge port, which has implementation
468 * problems, causing probe faults. Hide it for now. */
469 KdPrint2((PRINT_PREFIX " SiI 3726 (rev=%#x) Port Multiplier with %d (5) ports\n",
470 PM_RevId, PM_Ports));
471 PM_Ports = 5;
472 break;
473 case 0x47261095:
474 /* This PM declares 7 ports, while only 5 of them are real.
475 * Port 5 is some fake "Config Disk" with 640 sectors size,
476 * port 6 is enclosure management bridge port.
477 * Both fake ports has implementation problems, causing
478 * probe faults. Hide them for now. */
479 KdPrint2((PRINT_PREFIX " SiI 4726 (rev=%#x) Port Multiplier with %d (5) ports\n",
480 PM_RevId, PM_Ports));
481 PM_Ports = 5;
482 break;
483 default:
484 KdPrint2((PRINT_PREFIX " Port Multiplier (id=%08x rev=%#x) with %d ports\n",
485 PM_DeviceId, PM_RevId, PM_Ports));
486 break;
487 }
488
489 // reset
490 for(i=0; i<PM_Ports; i++) {
491
492 LunExt = chan->lun[i];
493
494 KdPrint2((PRINT_PREFIX " Port %d\n", i));
495 if(UniataSataPhyEnable(chan->DeviceExtension, chan->lChannel, i, UNIATA_SATA_RESET_ENABLE) != IDE_STATUS_IDLE) {
496 LunExt->DeviceFlags &= ~DFLAGS_DEVICE_PRESENT;
497 continue;
498 }
499 /*
500 * XXX: I have no idea how to properly wait for PMP port hardreset
501 * completion. Without this delay soft reset does not completes
502 * successfully.
503 */
504 AtapiStallExecution(1000000);
505
506 signature = UniataSataSoftReset(chan->DeviceExtension, chan->lChannel, i);
507 KdPrint2((PRINT_PREFIX " signature %#x\n", signature));
508
509 LunExt->DeviceFlags |= DFLAGS_DEVICE_PRESENT;
510 chan->PmLunMap |= (1 << i);
511 /* figure out whats there */
512 switch (signature >> 16) {
513 case 0x0000:
514 LunExt->DeviceFlags &= ~DFLAGS_ATAPI_DEVICE;
515 continue;
516 case 0xeb14:
517 LunExt->DeviceFlags |= DFLAGS_ATAPI_DEVICE;
518 continue;
519 }
520
521 }
522
523 } // end UniataSataIdentifyPM()
524
525 #ifdef DBG
526 VOID
527 NTAPI
528 UniataDumpAhciRegs(
529 IN PHW_DEVICE_EXTENSION deviceExtension
530 )
531 {
532 ULONG j;
533 ULONG xReg;
534
535 KdPrint2((PRINT_PREFIX
536 " AHCI Base: %#x MemIo %d Proc %d\n",
537 deviceExtension->BaseIoAHCI_0.Addr,
538 deviceExtension->BaseIoAHCI_0.MemIo,
539 deviceExtension->BaseIoAHCI_0.Proc));
540
541 for(j=0; j<=IDX_AHCI_VS; j+=sizeof(ULONG)) {
542 xReg = AtapiReadPortEx4(NULL, (ULONGIO_PTR)&deviceExtension->BaseIoAHCI_0, j);
543 KdPrint2((PRINT_PREFIX
544 " AHCI_%#x (%#x) = %#x\n",
545 j,
546 (deviceExtension->BaseIoAHCI_0.Addr+j),
547 xReg));
548 }
549 return;
550 } // end UniataDumpAhciRegs()
551
552
553 VOID
554 NTAPI
555 UniataDumpAhciPortRegs(
556 IN PHW_CHANNEL chan
557 )
558 {
559 ULONG j;
560 ULONG xReg;
561
562 KdPrint2((PRINT_PREFIX
563 " AHCI port %d Base: %#x MemIo %d Proc %d\n",
564 chan->lChannel,
565 chan->BaseIoAHCI_Port.Addr,
566 chan->BaseIoAHCI_Port.MemIo,
567 chan->BaseIoAHCI_Port.Proc));
568
569 for(j=0; j<=IDX_AHCI_P_SNTF; j+=sizeof(ULONG)) {
570 xReg = AtapiReadPortEx4(NULL, (ULONGIO_PTR)&chan->BaseIoAHCI_Port, j);
571 KdPrint2((PRINT_PREFIX
572 " AHCI%d_%#x (%#x) = %#x\n",
573 chan->lChannel,
574 j,
575 (chan->BaseIoAHCI_Port.Addr+j),
576 xReg));
577 }
578 return;
579 } // end UniataDumpAhciPortRegs()
580 #endif //DBG
581
582
583 BOOLEAN
584 NTAPI
585 UniataAhciInit(
586 IN PVOID HwDeviceExtension
587 )
588 {
589 PHW_DEVICE_EXTENSION deviceExtension = (PHW_DEVICE_EXTENSION)HwDeviceExtension;
590 ULONG c, i;
591 PHW_CHANNEL chan;
592 ULONG offs;
593 ULONG BaseMemAddress;
594 ULONG PI;
595 ULONG CAP;
596 ULONG GHC;
597 BOOLEAN MemIo = FALSE;
598
599 KdPrint2((PRINT_PREFIX " UniataAhciInit:\n"));
600
601 #ifdef DBG
602 UniataDumpAhciRegs(deviceExtension);
603 #endif //DBG
604
605 /* reset AHCI controller */
606 GHC = UniataAhciReadHostPort4(deviceExtension, IDX_AHCI_GHC);
607 KdPrint2((PRINT_PREFIX " reset AHCI controller, GHC %#x\n", GHC));
608 UniataAhciWriteHostPort4(deviceExtension, IDX_AHCI_GHC,
609 GHC | AHCI_GHC_HR);
610
611 for(i=0; i<1000; i++) {
612 AtapiStallExecution(1000);
613 GHC = UniataAhciReadHostPort4(deviceExtension, IDX_AHCI_GHC);
614 KdPrint2((PRINT_PREFIX " AHCI GHC %#x\n", GHC));
615 if(!(GHC & AHCI_GHC_HR)) {
616 break;
617 }
618 }
619 if(GHC & AHCI_GHC_HR) {
620 KdPrint2((PRINT_PREFIX " AHCI reset failed\n"));
621 return FALSE;
622 }
623
624 /* enable AHCI mode */
625 GHC = UniataAhciReadHostPort4(deviceExtension, IDX_AHCI_GHC);
626 KdPrint2((PRINT_PREFIX " enable AHCI mode, GHC %#x\n", GHC));
627 UniataAhciWriteHostPort4(deviceExtension, IDX_AHCI_GHC,
628 GHC | AHCI_GHC_AE);
629 GHC = UniataAhciReadHostPort4(deviceExtension, IDX_AHCI_GHC);
630 KdPrint2((PRINT_PREFIX " AHCI GHC %#x\n", GHC));
631
632 deviceExtension->AHCI_CAP =
633 CAP = UniataAhciReadHostPort4(deviceExtension, IDX_AHCI_CAP);
634 PI = UniataAhciReadHostPort4(deviceExtension, IDX_AHCI_PI);
635 KdPrint2((PRINT_PREFIX " AHCI CAP %#x\n", CAP));
636 if(CAP & AHCI_CAP_S64A) {
637 KdPrint2((PRINT_PREFIX " AHCI 64bit\n"));
638 deviceExtension->Host64 = TRUE;
639 }
640 KdPrint2((PRINT_PREFIX " AHCI %d CMD slots\n", (CAP & AHCI_CAP_NCS_MASK) >> 8 ));
641 if(CAP & AHCI_CAP_PMD) {
642 KdPrint2((PRINT_PREFIX " AHCI multi-block PIO\n"));
643 }
644 if(CAP & AHCI_CAP_SAM) {
645 KdPrint2((PRINT_PREFIX " AHCI legasy SATA\n"));
646 }
647 /* get the number of HW channels */
648 PI = UniataAhciReadHostPort4(deviceExtension, IDX_AHCI_PI);
649 KdPrint2((PRINT_PREFIX " AHCI PI %#x\n", PI));
650
651 /* clear interrupts */
652 UniataAhciWriteHostPort4(deviceExtension, IDX_AHCI_IS,
653 UniataAhciReadHostPort4(deviceExtension, IDX_AHCI_IS));
654
655 /* enable AHCI interrupts */
656 UniataAhciWriteHostPort4(deviceExtension, IDX_AHCI_GHC,
657 UniataAhciReadHostPort4(deviceExtension, IDX_AHCI_GHC) | AHCI_GHC_IE);
658
659 BaseMemAddress = deviceExtension->BaseIoAHCI_0.Addr;
660 MemIo = deviceExtension->BaseIoAHCI_0.MemIo;
661
662 for(c=0; c<deviceExtension->NumberChannels; c++) {
663 chan = &deviceExtension->chan[c];
664 offs = sizeof(IDE_AHCI_REGISTERS) + c*sizeof(IDE_AHCI_PORT_REGISTERS);
665
666 KdPrint2((PRINT_PREFIX " chan %d, offs %#x\n", c, offs));
667
668 AtapiSetupLunPtrs(chan, deviceExtension, c);
669
670 chan->BaseIoAHCI_Port = deviceExtension->BaseIoAHCI_0;
671 chan->BaseIoAHCI_Port.Addr = BaseMemAddress + offs;
672
673 chan->RegTranslation[IDX_IO1_i_Status ].Addr = BaseMemAddress + offs + FIELD_OFFSET(IDE_AHCI_PORT_REGISTERS, TFD.STS);
674 chan->RegTranslation[IDX_IO1_i_Status ].MemIo = MemIo;
675 chan->RegTranslation[IDX_IO2_AltStatus] = chan->RegTranslation[IDX_IO1_i_Status];
676 chan->RegTranslation[IDX_IO1_i_Error ].Addr = BaseMemAddress + offs + FIELD_OFFSET(IDE_AHCI_PORT_REGISTERS, TFD.ERR);
677 chan->RegTranslation[IDX_IO1_i_Error ].MemIo = MemIo;
678 chan->RegTranslation[IDX_IO1_i_CylinderLow ].Addr = BaseMemAddress + offs + FIELD_OFFSET(IDE_AHCI_PORT_REGISTERS, SIG.LbaLow);
679 chan->RegTranslation[IDX_IO1_i_CylinderLow ].MemIo = MemIo;
680 chan->RegTranslation[IDX_IO1_i_CylinderHigh].Addr = BaseMemAddress + offs + FIELD_OFFSET(IDE_AHCI_PORT_REGISTERS, SIG.LbaHigh);
681 chan->RegTranslation[IDX_IO1_i_CylinderHigh].MemIo = MemIo;
682 chan->RegTranslation[IDX_IO1_i_BlockCount ].Addr = BaseMemAddress + offs + FIELD_OFFSET(IDE_AHCI_PORT_REGISTERS, SIG.SectorCount);
683 chan->RegTranslation[IDX_IO1_i_BlockCount ].MemIo = MemIo;
684
685 UniataInitSyncBaseIO(chan);
686
687 chan->RegTranslation[IDX_SATA_SStatus].Addr = BaseMemAddress + offs + FIELD_OFFSET(IDE_AHCI_PORT_REGISTERS, SSTS);
688 chan->RegTranslation[IDX_SATA_SStatus].MemIo = MemIo;
689 chan->RegTranslation[IDX_SATA_SError].Addr = BaseMemAddress + offs + FIELD_OFFSET(IDE_AHCI_PORT_REGISTERS, SERR);
690 chan->RegTranslation[IDX_SATA_SError].MemIo = MemIo;
691 chan->RegTranslation[IDX_SATA_SControl].Addr = BaseMemAddress + offs + FIELD_OFFSET(IDE_AHCI_PORT_REGISTERS, SCTL);
692 chan->RegTranslation[IDX_SATA_SControl].MemIo = MemIo;
693 chan->RegTranslation[IDX_SATA_SActive].Addr = BaseMemAddress + offs + FIELD_OFFSET(IDE_AHCI_PORT_REGISTERS, SACT);
694 chan->RegTranslation[IDX_SATA_SActive].MemIo = MemIo;
695
696 AtapiDmaAlloc(HwDeviceExtension, NULL, c);
697
698 UniataAhciResume(chan);
699
700 chan->ChannelCtrlFlags |= CTRFLAGS_NO_SLAVE;
701 }
702
703 return TRUE;
704 } // end UniataAhciInit()
705
706 BOOLEAN
707 NTAPI
708 UniataAhciDetect(
709 IN PVOID HwDeviceExtension,
710 IN PPCI_COMMON_CONFIG pciData, // optional
711 IN OUT PPORT_CONFIGURATION_INFORMATION ConfigInfo
712 )
713 {
714 PHW_DEVICE_EXTENSION deviceExtension = (PHW_DEVICE_EXTENSION)HwDeviceExtension;
715 //ULONG slotNumber = deviceExtension->slotNumber;
716 ULONG SystemIoBusNumber = deviceExtension->SystemIoBusNumber;
717 ULONG version;
718 ULONG i, n;
719 ULONG PI;
720 ULONG CAP;
721 ULONG GHC;
722 ULONG NumberChannels;
723 ULONG v_Mn, v_Mj;
724 ULONG BaseMemAddress;
725 BOOLEAN MemIo;
726
727 KdPrint2((PRINT_PREFIX " UniataAhciDetect:\n"));
728
729 if(AtapiRegCheckDevValue(deviceExtension, CHAN_NOT_SPECIFIED, DEVNUM_NOT_SPECIFIED, L"IgnoreAhci", 1 /* DEBUG */)) {
730 KdPrint((" AHCI excluded\n"));
731 return FALSE;
732 }
733 BaseMemAddress = AtapiGetIoRange(HwDeviceExtension, ConfigInfo, pciData, SystemIoBusNumber,
734 5, 0, 0x10);
735 if(!BaseMemAddress) {
736 KdPrint2((PRINT_PREFIX " AHCI init failed - no IoRange\n"));
737 return FALSE;
738 }
739 if(BaseMemAddress && (*ConfigInfo->AccessRanges)[5].RangeInMemory) {
740 KdPrint2((PRINT_PREFIX "MemIo\n"));
741 MemIo = TRUE;
742 }
743 deviceExtension->BaseIoAHCI_0.Addr = BaseMemAddress;
744 deviceExtension->BaseIoAHCI_0.MemIo = MemIo;
745
746 #ifdef DBG
747 UniataDumpAhciRegs(deviceExtension);
748 #endif //DBG
749
750 GHC = UniataAhciReadHostPort4(deviceExtension, IDX_AHCI_GHC);
751 if(GHC & AHCI_GHC_HR) {
752 KdPrint2((PRINT_PREFIX " AHCI in reset state\n"));
753 return FALSE;
754 }
755
756 /* enable AHCI mode */
757 GHC = UniataAhciReadHostPort4(deviceExtension, IDX_AHCI_GHC);
758 KdPrint2((PRINT_PREFIX " check AHCI mode, GHC %#x\n", GHC));
759 if(!(GHC & AHCI_GHC_AE)) {
760 KdPrint2((PRINT_PREFIX " Non-AHCI GHC (!AE)\n"));
761 return FALSE;
762 }
763
764 CAP = UniataAhciReadHostPort4(deviceExtension, IDX_AHCI_CAP);
765 KdPrint2((PRINT_PREFIX " AHCI CAP %#x\n", CAP));
766 if(CAP & AHCI_CAP_S64A) {
767 KdPrint2((PRINT_PREFIX " AHCI 64bit\n"));
768 //deviceExtension->Host64 = TRUE;
769 }
770
771 /* get the number of HW channels */
772 PI = UniataAhciReadHostPort4(deviceExtension, IDX_AHCI_PI);
773 KdPrint2((PRINT_PREFIX " AHCI PI %#x\n", PI));
774 for(i=PI, n=0; i; n++, i=i>>1);
775 NumberChannels =
776 max((CAP & AHCI_CAP_NOP_MASK)+1, n);
777
778 KdPrint2((PRINT_PREFIX " Channels %d\n", n));
779
780 switch(deviceExtension->DevID) {
781 case ATA_M88SX6111:
782 NumberChannels = 1;
783 break;
784 case ATA_M88SX6121:
785 NumberChannels = 2;
786 break;
787 case ATA_M88SX6141:
788 case ATA_M88SX6145:
789 NumberChannels = 4;
790 break;
791 } // switch()
792
793 if(!NumberChannels) {
794 KdPrint2((PRINT_PREFIX " Non-AHCI - NumberChannels=0\n"));
795 return FALSE;
796 }
797
798 version = UniataAhciReadHostPort4(deviceExtension, IDX_AHCI_VS);
799 v_Mj = ((version >> 20) & 0xf0) + ((version >> 16) & 0x0f);
800 v_Mn = ((version >> 4) & 0xf0) + (version & 0x0f);
801
802 KdPrint2((PRINT_PREFIX " AHCI version %#x.%02x controller with %d ports (mask %#x) detected\n",
803 v_Mj, v_Mn,
804 NumberChannels, PI));
805
806 if(CAP & AHCI_CAP_SPM) {
807 KdPrint2((PRINT_PREFIX " PM supported\n"));
808 if(AtapiRegCheckDevValue(deviceExtension, CHAN_NOT_SPECIFIED, DEVNUM_NOT_SPECIFIED, L"IgnoreAhciPM", 1 /* DEBUG */)) {
809 KdPrint2((PRINT_PREFIX "SATA/AHCI w/o PM, max luns 1\n"));
810 deviceExtension->NumberLuns = 2;
811 //chan->ChannelCtrlFlags |= CTRFLAGS_NO_SLAVE;
812 } else {
813 KdPrint2((PRINT_PREFIX "SATA/AHCI -> possible PM, max luns %d\n", SATA_MAX_PM_UNITS));
814 deviceExtension->NumberLuns = SATA_MAX_PM_UNITS;
815 //deviceExtension->NumberLuns = 1;
816 }
817 } else {
818 KdPrint2((PRINT_PREFIX " PM not supported -> 1 lun/chan\n"));
819 deviceExtension->NumberLuns = 1;
820 }
821
822 if((v_Mj != 0x01) || (v_Mn > 0x20)) {
823 KdPrint2((PRINT_PREFIX " Unknown AHCI revision\n"));
824 if(AtapiRegCheckDevValue(deviceExtension, CHAN_NOT_SPECIFIED, DEVNUM_NOT_SPECIFIED, L"CheckAhciRevision", 1)) {
825 KdPrint((" AHCI revision excluded\n"));
826 return FALSE;
827 }
828 }
829
830 deviceExtension->HwFlags |= UNIATA_SATA;
831 deviceExtension->HwFlags |= UNIATA_AHCI;
832 if(deviceExtension->NumberChannels < NumberChannels) {
833 deviceExtension->NumberChannels = NumberChannels;
834 }
835
836 return TRUE;
837 } // end UniataAhciDetect()
838
839 UCHAR
840 NTAPI
841 UniataAhciStatus(
842 IN PVOID HwDeviceExtension,
843 IN ULONG lChannel,
844 IN ULONG DeviceNumber
845 )
846 {
847 PHW_DEVICE_EXTENSION deviceExtension = (PHW_DEVICE_EXTENSION)HwDeviceExtension;
848 PHW_CHANNEL chan = &deviceExtension->chan[lChannel];
849 ULONG Channel = deviceExtension->Channel + lChannel;
850 ULONG hIS;
851 ULONG CI;
852 AHCI_IS_REG IS;
853 SATA_SSTATUS_REG SStatus;
854 SATA_SERROR_REG SError;
855 //ULONG offs = sizeof(IDE_AHCI_REGISTERS) + Channel*sizeof(IDE_AHCI_PORT_REGISTERS);
856 ULONG tag=0;
857
858 KdPrint(("UniataAhciStatus:\n"));
859
860 hIS = UniataAhciReadHostPort4(deviceExtension, IDX_AHCI_IS);
861 KdPrint((" hIS %#x\n", hIS));
862 hIS &= (1 << Channel);
863 if(!hIS) {
864 return INTERRUPT_REASON_IGNORE;
865 }
866 IS.Reg = UniataAhciReadChannelPort4(chan, IDX_AHCI_P_IS);
867 CI = UniataAhciReadChannelPort4(chan, IDX_AHCI_P_CI);
868 SStatus.Reg = AtapiReadPort4(chan, IDX_SATA_SStatus);
869 SError.Reg = AtapiReadPort4(chan, IDX_SATA_SError);
870
871 /* clear interrupt(s) */
872 UniataAhciWriteHostPort4(deviceExtension, IDX_AHCI_IS, hIS);
873 UniataAhciWriteChannelPort4(chan, IDX_AHCI_P_IS, IS.Reg);
874 AtapiWritePort4(chan, IDX_SATA_SError, SError.Reg);
875
876 KdPrint((" AHCI: status=%08x sstatus=%08x error=%08x CI=%08x\n",
877 IS.Reg, SStatus.Reg, SError.Reg, CI));
878
879 /* do we have cold connect surprise */
880 if(IS.CPDS) {
881 }
882
883 /* check for and handle connect events */
884 if(IS.PCS) {
885 UniataSataEvent(HwDeviceExtension, lChannel, UNIATA_SATA_EVENT_ATTACH);
886 }
887 if(IS.PRCS) {
888 UniataSataEvent(HwDeviceExtension, lChannel, UNIATA_SATA_EVENT_DETACH);
889 }
890 if(CI & (1 << tag)) {
891 return INTERRUPT_REASON_OUR;
892 }
893 KdPrint((" AHCI: unexpected\n"));
894 return INTERRUPT_REASON_UNEXPECTED;
895
896 } // end UniataAhciStatus()
897
898 ULONG
899 NTAPI
900 UniataAhciSetupFIS_H2D(
901 IN PHW_DEVICE_EXTENSION deviceExtension,
902 IN ULONG DeviceNumber,
903 IN ULONG lChannel,
904 OUT PUCHAR fis,
905 IN UCHAR command,
906 IN ULONGLONG lba,
907 IN USHORT count,
908 IN USHORT feature,
909 IN ULONG flags
910 )
911 {
912 ULONG i;
913 PUCHAR plba;
914 BOOLEAN need48;
915 PHW_CHANNEL chan = &deviceExtension->chan[lChannel];
916
917 KdPrint2((PRINT_PREFIX " AHCI setup FIS ch %d, dev %d\n", lChannel, DeviceNumber));
918 i = 0;
919 plba = (PUCHAR)&lba;
920
921 fis[0] = AHCI_FIS_TYPE_ATA_H2D; /* host to device */
922 fis[1] = 0x80 | ((UCHAR)DeviceNumber & 0x0f); /* command FIS (note PM goes here) */
923 fis[7] = IDE_USE_LBA;
924 fis[15] = IDE_DC_A_4BIT;
925
926 if(chan->lun[DeviceNumber]->DeviceFlags & DFLAGS_ATAPI_DEVICE) {
927 fis[2] = IDE_COMMAND_ATAPI_PACKET;
928 if(feature & ATA_F_DMA) {
929 fis[3] = (UCHAR)(feature & 0xff);
930 } else {
931 fis[5] = (UCHAR)(count & 0xff);
932 fis[6] = (UCHAR)(count>>8) & 0xff;
933 }
934 } else {
935
936 if((AtaCommandFlags[command] & ATA_CMD_FLAG_LBAIOsupp) &&
937 CheckIfBadBlock(chan->lun[DeviceNumber], lba, count)) {
938 KdPrint3((PRINT_PREFIX ": artificial bad block, lba %#I64x count %#x\n", lba, count));
939 //return IDE_STATUS_ERROR;
940 //return SRB_STATUS_ERROR;
941 return 0;
942 }
943
944 need48 = UniAta_need_lba48(command, lba, count,
945 chan->lun[DeviceNumber]->IdentifyData.FeaturesSupport.Address48);
946
947 /* translate command into 48bit version */
948 if(need48) {
949 if(AtaCommandFlags[command] & ATA_CMD_FLAG_48supp) {
950 command = AtaCommands48[command];
951 } else {
952 KdPrint2((PRINT_PREFIX " unhandled LBA48 command\n"));
953 return 0;
954 }
955 }
956
957 fis[2] = command;
958 fis[3] = (UCHAR)feature;
959
960 fis[4] = plba[0];
961 fis[5] = plba[1];
962 fis[6] = plba[2];
963 if(need48) {
964 i++;
965 } else {
966 #ifdef _MSC_VER
967 #pragma warning(push)
968 #pragma warning(disable:4333) // right shift by too large amount, data loss
969 #endif
970 fis[7] |= IDE_DRIVE_1 | ((plba[3] >> 24) & 0x0f);
971 #ifdef _MSC_VER
972 #pragma warning(pop)
973 #endif
974 }
975
976 fis[8] = plba[3];
977 fis[9] = plba[4];
978 fis[10] = plba[5];
979 fis[11] = (UCHAR)(feature>>8) & 0xff;
980
981 fis[12] = (UCHAR)count & 0xff;
982 fis[13] = (UCHAR)(count>>8) & 0xff;
983 //fis[14] = 0x00;
984
985 }
986
987 KdDump(fis, 20);
988
989 return 20;
990 } // end UniataAhciSetupFIS_H2D()
991
992 UCHAR
993 NTAPI
994 UniataAhciSendCommand(
995 IN PVOID HwDeviceExtension,
996 IN ULONG lChannel,
997 IN ULONG DeviceNumber,
998 IN ULONG flags,
999 IN ULONG timeout
1000 )
1001 {
1002 PHW_DEVICE_EXTENSION deviceExtension = (PHW_DEVICE_EXTENSION)HwDeviceExtension;
1003 PHW_CHANNEL chan = &deviceExtension->chan[lChannel];
1004 //ULONG Channel = deviceExtension->Channel + lChannel;
1005 //ULONG hIS;
1006 ULONG CI = 0;
1007 AHCI_IS_REG IS;
1008 ULONG SError;
1009 //SATA_SSTATUS_REG SStatus;
1010 //SATA_SERROR_REG SError;
1011 //ULONG offs = sizeof(IDE_AHCI_REGISTERS) + Channel*sizeof(IDE_AHCI_PORT_REGISTERS);
1012 //ULONGIO_PTR base;
1013 ULONG tag=0;
1014 ULONG i;
1015
1016 PIDE_AHCI_CMD_LIST AHCI_CL = &(chan->AhciCtlBlock->cmd_list[tag]);
1017
1018 KdPrint(("UniataAhciSendCommand: lChan %d\n", chan->lChannel));
1019
1020 AHCI_CL->prd_length = 0;
1021 AHCI_CL->cmd_flags = (20 / sizeof(ULONG)) | flags | (DeviceNumber << 12);
1022 AHCI_CL->bytecount = 0;
1023 AHCI_CL->cmd_table_phys = chan->AHCI_CTL_PhAddr + FIELD_OFFSET(IDE_AHCI_CHANNEL_CTL_BLOCK, cmd);
1024 if(AHCI_CL->cmd_table_phys & AHCI_CMD_ALIGNEMENT_MASK) {
1025 KdPrint2((PRINT_PREFIX " AHCI CMD address is not aligned (mask %#x)\n", (ULONG)AHCI_CMD_ALIGNEMENT_MASK));
1026 }
1027
1028 UniataAhciWriteChannelPort4(chan, IDX_AHCI_P_CI, ATA_AHCI_P_CMD_ST);
1029
1030 for (i=0; i<timeout; i++) {
1031 AtapiStallExecution(1000);
1032 CI = UniataAhciReadChannelPort4(chan, IDX_AHCI_P_CI);
1033 if (!(CI & ATA_AHCI_P_CMD_ST)) {
1034 break;
1035 }
1036 }
1037 KdPrint((" CI %#x\n", CI));
1038
1039 //SStatus.Reg = AtapiReadPort4(chan, IDX_SATA_SStatus);
1040 //SError.Reg = AtapiReadPort4(chan, IDX_SATA_SError);
1041
1042 /* clear interrupt(s) */
1043 IS.Reg = UniataAhciReadChannelPort4(chan, IDX_AHCI_P_IS);
1044 KdPrint((" IS %#x\n", IS.Reg));
1045 UniataAhciWriteChannelPort4(chan, IDX_AHCI_P_IS, IS.Reg);
1046
1047 if (timeout && (i >= timeout)) {
1048 SError = AtapiReadPort4(chan, IDX_SATA_SError);
1049 KdPrint((" AHCI: timeout, SError %#x\n", SError));
1050 return 0xff;
1051 }
1052
1053 return IDE_STATUS_IDLE;
1054
1055 } // end UniataAhciSendCommand()
1056
1057 ULONG
1058 NTAPI
1059 UniataAhciSoftReset(
1060 IN PVOID HwDeviceExtension,
1061 IN ULONG lChannel,
1062 IN ULONG DeviceNumber
1063 )
1064 {
1065 PHW_DEVICE_EXTENSION deviceExtension = (PHW_DEVICE_EXTENSION)HwDeviceExtension;
1066 PHW_CHANNEL chan = &deviceExtension->chan[lChannel];
1067 //ULONG Channel = deviceExtension->Channel + lChannel;
1068 //ULONG hIS;
1069 //ULONG CI;
1070 //AHCI_IS_REG IS;
1071 //ULONG tag=0;
1072
1073 KdPrint(("UniataAhciSoftReset: lChan %d\n", chan->lChannel));
1074
1075 PIDE_AHCI_CMD AHCI_CMD = &(chan->AhciCtlBlock->cmd);
1076 PUCHAR RCV_FIS = &(chan->AhciCtlBlock->rcv_fis.rfis[0]);
1077
1078 #ifdef DBG
1079 UniataDumpAhciPortRegs(chan);
1080 #endif // DBG
1081
1082 /* kick controller into sane state */
1083 UniataAhciStop(chan);
1084 UniataAhciCLO(chan);
1085 UniataAhciStart(chan);
1086
1087 #ifdef DBG
1088 UniataDumpAhciPortRegs(chan);
1089 #endif // DBG
1090
1091 /* pull reset active */
1092 RtlZeroMemory(AHCI_CMD->cfis, sizeof(AHCI_CMD->cfis));
1093 AHCI_CMD->cfis[0] = AHCI_FIS_TYPE_ATA_H2D;
1094 AHCI_CMD->cfis[1] = (UCHAR)DeviceNumber & 0x0f;
1095 //AHCI_CMD->cfis[7] = IDE_USE_LBA | IDE_DRIVE_SELECT;
1096 AHCI_CMD->cfis[15] = (IDE_DC_A_4BIT | IDE_DC_RESET_CONTROLLER);
1097
1098 if(UniataAhciSendCommand(HwDeviceExtension, lChannel, DeviceNumber, ATA_AHCI_CMD_RESET | ATA_AHCI_CMD_CLR_BUSY, 100) == 0xff) {
1099 KdPrint2((" timeout\n"));
1100 return (ULONG)(-1);
1101 }
1102 AtapiStallExecution(50);
1103
1104 /* pull reset inactive */
1105 RtlZeroMemory(AHCI_CMD->cfis, sizeof(AHCI_CMD->cfis));
1106 AHCI_CMD->cfis[0] = AHCI_FIS_TYPE_ATA_H2D;
1107 AHCI_CMD->cfis[1] = (UCHAR)DeviceNumber & 0x0f;
1108 //AHCI_CMD->cfis[7] = IDE_USE_LBA | IDE_DRIVE_SELECT;
1109 AHCI_CMD->cfis[15] = (IDE_DC_A_4BIT);
1110 if(UniataAhciSendCommand(HwDeviceExtension, lChannel, DeviceNumber, 0, 3000) == 0xff) {
1111 KdPrint2((" timeout (2)\n"));
1112 return (ULONG)(-1);
1113 }
1114
1115 UniataAhciWaitReady(chan, 1);
1116
1117 KdDump(RCV_FIS, sizeof(chan->AhciCtlBlock->rcv_fis.rfis));
1118
1119 return UniataAhciUlongFromRFIS(RCV_FIS);
1120
1121 } // end UniataAhciSoftReset()
1122
1123 ULONG
1124 NTAPI
1125 UniataAhciWaitReady(
1126 IN PHW_CHANNEL chan,
1127 IN ULONG timeout
1128 )
1129 {
1130 ULONG TFD;
1131 ULONG i;
1132
1133 KdPrint2(("UniataAhciWaitReady: lChan %d\n", chan->lChannel));
1134
1135 //base = (ULONGIO_PTR)(&deviceExtension->BaseIoAHCI_0 + offs);
1136
1137 TFD = UniataAhciReadChannelPort4(chan, IDX_AHCI_P_TFD);
1138 for(i=0; i<timeout && (TFD &
1139 (IDE_STATUS_DRQ | IDE_STATUS_BUSY)); i++) {
1140 AtapiStallExecution(1000);
1141 TFD = UniataAhciReadChannelPort4(chan, IDX_AHCI_P_TFD);
1142 }
1143
1144 KdPrint2((" TFD %#x\n", TFD));
1145
1146 return TFD;
1147
1148 } // end UniataAhciWaitReady()
1149
1150 ULONG
1151 NTAPI
1152 UniataAhciHardReset(
1153 IN PVOID HwDeviceExtension,
1154 IN ULONG lChannel,
1155 OUT PULONG signature
1156 )
1157 {
1158 PHW_DEVICE_EXTENSION deviceExtension = (PHW_DEVICE_EXTENSION)HwDeviceExtension;
1159 PHW_CHANNEL chan = &deviceExtension->chan[lChannel];
1160 //ULONG Channel = deviceExtension->Channel + lChannel;
1161 ULONG TFD;
1162
1163
1164 KdPrint(("UniataAhciHardReset: lChan %d\n", chan->lChannel));
1165
1166 (*signature) = 0xffffffff;
1167
1168 UniataAhciStop(chan);
1169 if(UniataSataPhyEnable(HwDeviceExtension, lChannel, 0/* dev0*/, UNIATA_SATA_RESET_ENABLE) == 0xff) {
1170 KdPrint((" no PHY\n"));
1171 return 0xff;
1172 }
1173
1174 /* Wait for clearing busy status. */
1175 TFD = UniataAhciWaitReady(chan, 15000);
1176 if(TFD & (IDE_STATUS_DRQ | IDE_STATUS_BUSY)) {
1177 KdPrint((" busy: TFD %#x\n", TFD));
1178 return TFD;
1179 }
1180 KdPrint((" TFD %#x\n", TFD));
1181
1182 #ifdef DBG
1183 UniataDumpAhciPortRegs(chan);
1184 #endif // DBG
1185
1186 (*signature) = UniataAhciReadChannelPort4(chan, IDX_AHCI_P_SIG);
1187 KdPrint((" sig: %#x\n", *signature));
1188
1189 UniataAhciStart(chan);
1190
1191 return 0;
1192
1193 } // end UniataAhciHardReset()
1194
1195 VOID
1196 NTAPI
1197 UniataAhciReset(
1198 IN PVOID HwDeviceExtension,
1199 IN ULONG lChannel
1200 )
1201 {
1202 PHW_DEVICE_EXTENSION deviceExtension = (PHW_DEVICE_EXTENSION)HwDeviceExtension;
1203 PHW_CHANNEL chan = &deviceExtension->chan[lChannel];
1204 //ULONG Channel = deviceExtension->Channel + lChannel;
1205 //ULONG offs = sizeof(IDE_AHCI_REGISTERS) + Channel*sizeof(IDE_AHCI_PORT_REGISTERS);
1206 ULONG CAP;
1207 //ULONGIO_PTR base;
1208 ULONG signature;
1209 ULONG i;
1210 ULONG VendorID = deviceExtension->DevID & 0xffff;
1211
1212 KdPrint(("UniataAhciReset: lChan %d\n", chan->lChannel));
1213
1214 //base = (ULONGIO_PTR)(&deviceExtension->BaseIoAHCI_0 + offs);
1215
1216 /* Disable port interrupts */
1217 UniataAhciWriteChannelPort4(chan, IDX_AHCI_P_IE, 0);
1218
1219 if(UniataAhciHardReset(HwDeviceExtension, lChannel, &signature)) {
1220
1221 KdPrint((" No devices in all LUNs\n"));
1222 for (i=0; i<deviceExtension->NumberLuns; i++) {
1223 // Zero device fields to ensure that if earlier devices were found,
1224 // but not claimed, the fields are cleared.
1225 UniataForgetDevice(chan->lun[i]);
1226 }
1227
1228 /* enable wanted port interrupts */
1229 UniataAhciWriteChannelPort4(chan, IDX_AHCI_P_IE,
1230 ATA_AHCI_P_IX_CPD | ATA_AHCI_P_IX_PRC | ATA_AHCI_P_IX_PC);
1231 return;
1232 }
1233
1234 /* enable wanted port interrupts */
1235 UniataAhciWriteChannelPort4(chan, IDX_AHCI_P_IE,
1236 (ATA_AHCI_P_IX_CPD | ATA_AHCI_P_IX_TFE | ATA_AHCI_P_IX_HBF |
1237 ATA_AHCI_P_IX_HBD | ATA_AHCI_P_IX_IF | ATA_AHCI_P_IX_OF |
1238 ((/*ch->pm_level == */0) ? (ATA_AHCI_P_IX_PRC | ATA_AHCI_P_IX_PC) : 0) |
1239 ATA_AHCI_P_IX_DP | ATA_AHCI_P_IX_UF | ATA_AHCI_P_IX_SDB |
1240 ATA_AHCI_P_IX_DS | ATA_AHCI_P_IX_PS | ATA_AHCI_P_IX_DHR) );
1241
1242 /*
1243 * Only probe for PortMultiplier if HW has support.
1244 * Ignore Marvell, which is not working,
1245 */
1246 CAP = UniataAhciReadHostPort4(deviceExtension, IDX_AHCI_CAP);
1247 if ((CAP & AHCI_CAP_SPM) &&
1248 (VendorID != ATA_MARVELL_ID)) {
1249 KdPrint((" check PM\n"));
1250 signature = UniataAhciSoftReset(HwDeviceExtension, lChannel, AHCI_DEV_SEL_PM);
1251 /* Workaround for some ATI chips, failing to soft-reset
1252 * when port multiplicator supported, but absent.
1253 * XXX: We can also check PxIS.IPMS==1 here to be sure. */
1254 if (signature == 0xffffffff) {
1255 KdPrint((" re-check PM\n"));
1256 signature = UniataAhciSoftReset(HwDeviceExtension, lChannel, 0);
1257 }
1258 } else {
1259 signature = UniataAhciSoftReset(HwDeviceExtension, lChannel, 0);
1260 }
1261
1262 KdPrint((" signature %#x\n", signature));
1263 chan->lun[0]->DeviceFlags &= ~(DFLAGS_ATAPI_DEVICE | DFLAGS_DEVICE_PRESENT | CTRFLAGS_AHCI_PM);
1264 switch (signature >> 16) {
1265 case 0x0000:
1266 KdPrint((" ATA dev\n"));
1267 chan->lun[0]->DeviceFlags |= DFLAGS_DEVICE_PRESENT;
1268 chan->PmLunMap = 0;
1269 break;
1270 case 0x9669:
1271 KdPrint((" PM\n"));
1272 if(deviceExtension->NumberLuns > 1) {
1273 chan->ChannelCtrlFlags |= CTRFLAGS_AHCI_PM;
1274 UniataSataIdentifyPM(chan);
1275 } else {
1276 KdPrint((" no PM supported (1 lun/chan)\n"));
1277 }
1278 break;
1279 case 0xeb14:
1280 KdPrint((" ATAPI dev\n"));
1281 chan->lun[0]->DeviceFlags |= (DFLAGS_ATAPI_DEVICE | DFLAGS_DEVICE_PRESENT);
1282 chan->PmLunMap = 0;
1283 break;
1284 default: /* SOS XXX */
1285 KdPrint((" default to ATA ???\n"));
1286 chan->lun[0]->DeviceFlags |= DFLAGS_DEVICE_PRESENT;
1287 chan->PmLunMap = 0;
1288 }
1289
1290 return;
1291
1292 } // end UniataAhciReset()
1293
1294 VOID
1295 NTAPI
1296 UniataAhciStartFR(
1297 IN PHW_CHANNEL chan
1298 )
1299 {
1300 ULONG CMD;
1301
1302 KdPrint2(("UniataAhciStartFR: lChan %d\n", chan->lChannel));
1303
1304 CMD = UniataAhciReadChannelPort4(chan, IDX_AHCI_P_CMD);
1305 KdPrint2((" CMD %#x\n", CMD));
1306 UniataAhciWriteChannelPort4(chan, IDX_AHCI_P_CMD, CMD | ATA_AHCI_P_CMD_FRE);
1307
1308 return;
1309 } // end UniataAhciStartFR()
1310
1311 VOID
1312 NTAPI
1313 UniataAhciStopFR(
1314 IN PHW_CHANNEL chan
1315 )
1316 {
1317 ULONG CMD;
1318 ULONG i;
1319
1320 KdPrint2(("UniataAhciStopFR: lChan %d\n", chan->lChannel));
1321
1322 CMD = UniataAhciReadChannelPort4(chan, IDX_AHCI_P_CMD);
1323 KdPrint2((" CMD %#x\n", CMD));
1324 UniataAhciWriteChannelPort4(chan, IDX_AHCI_P_CMD, CMD & ~ATA_AHCI_P_CMD_FRE);
1325
1326 for(i=0; i<1000; i++) {
1327 CMD = UniataAhciReadChannelPort4(chan, IDX_AHCI_P_CMD);
1328 if(!(CMD & ATA_AHCI_P_CMD_FR)) {
1329 KdPrint2((" final CMD %#x\n", CMD));
1330 return;
1331 }
1332 AtapiStallExecution(1000);
1333 }
1334 KdPrint2((" CMD %#x\n", CMD));
1335 KdPrint((" SError %#x\n", AtapiReadPort4(chan, IDX_SATA_SError)));
1336 KdPrint2(("UniataAhciStopFR: timeout\n"));
1337 return;
1338 } // end UniataAhciStopFR()
1339
1340 VOID
1341 NTAPI
1342 UniataAhciStart(
1343 IN PHW_CHANNEL chan
1344 )
1345 {
1346 ULONG IS, CMD;
1347 SATA_SERROR_REG SError;
1348
1349 KdPrint2(("UniataAhciStart: lChan %d\n", chan->lChannel));
1350
1351 /* clear SATA error register */
1352 SError.Reg = AtapiReadPort4(chan, IDX_SATA_SError);
1353
1354 /* clear any interrupts pending on this channel */
1355 IS = UniataAhciReadChannelPort4(chan, IDX_AHCI_P_IS);
1356 UniataAhciWriteChannelPort4(chan, IDX_AHCI_P_IS, IS);
1357
1358 KdPrint2((" SError %#x, IS %#x\n", SError.Reg, IS));
1359
1360 CMD = UniataAhciReadChannelPort4(chan, IDX_AHCI_P_CMD);
1361 KdPrint2((" CMD %#x\n", CMD));
1362 UniataAhciWriteChannelPort4(chan, IDX_AHCI_P_CMD,
1363 CMD |
1364 ATA_AHCI_P_CMD_ST |
1365 ((chan->ChannelCtrlFlags & CTRFLAGS_AHCI_PM) ? ATA_AHCI_P_CMD_PMA : 0));
1366
1367 return;
1368 } // end UniataAhciStart()
1369
1370 VOID
1371 NTAPI
1372 UniataAhciCLO(
1373 IN PHW_CHANNEL chan
1374 )
1375 {
1376 //PHW_DEVICE_EXTENSION deviceExtension = (PHW_DEVICE_EXTENSION)HwDeviceExtension;
1377 //PHW_CHANNEL chan = &deviceExtension->chan[lChannel];
1378 ULONG CAP, CMD;
1379 //SATA_SERROR_REG SError;
1380 ULONG i;
1381
1382 KdPrint2(("UniataAhciCLO: lChan %d\n", chan->lChannel));
1383
1384 /* issue Command List Override if supported */
1385 //CAP = UniataAhciReadHostPort4(deviceExtension, IDX_AHCI_CAP);
1386 CAP = chan->DeviceExtension->AHCI_CAP;
1387 if(!(CAP & AHCI_CAP_SCLO)) {
1388 return;
1389 }
1390 KdPrint2((" send CLO\n"));
1391 CMD = UniataAhciReadChannelPort4(chan, IDX_AHCI_P_CMD);
1392 CMD |= ATA_AHCI_P_CMD_CLO;
1393 UniataAhciWriteChannelPort4(chan, IDX_AHCI_P_CMD, CMD);
1394
1395 for(i=0; i<1000; i++) {
1396 CMD = UniataAhciReadChannelPort4(chan, IDX_AHCI_P_CMD);
1397 if(!(CMD & ATA_AHCI_P_CMD_CLO)) {
1398 KdPrint2((" final CMD %#x\n", CMD));
1399 return;
1400 }
1401 AtapiStallExecution(1000);
1402 }
1403 KdPrint2((" CMD %#x\n", CMD));
1404 KdPrint2(("UniataAhciCLO: timeout\n"));
1405 return;
1406 } // end UniataAhciCLO()
1407
1408 VOID
1409 NTAPI
1410 UniataAhciStop(
1411 IN PHW_CHANNEL chan
1412 )
1413 {
1414 ULONG CMD;
1415 //SATA_SERROR_REG SError;
1416 ULONG i;
1417
1418 KdPrint2(("UniataAhciStop: lChan %d\n", chan->lChannel));
1419
1420 /* issue Command List Override if supported */
1421 CMD = UniataAhciReadChannelPort4(chan, IDX_AHCI_P_CMD);
1422 CMD &= ~ATA_AHCI_P_CMD_ST;
1423 UniataAhciWriteChannelPort4(chan, IDX_AHCI_P_CMD, CMD);
1424
1425 for(i=0; i<1000; i++) {
1426 CMD = UniataAhciReadChannelPort4(chan, IDX_AHCI_P_CMD);
1427 if(!(CMD & ATA_AHCI_P_CMD_CR)) {
1428 KdPrint2((" final CMD %#x\n", CMD));
1429 return;
1430 }
1431 AtapiStallExecution(1000);
1432 }
1433 KdPrint2((" CMD %#x\n", CMD));
1434 KdPrint((" SError %#x\n", AtapiReadPort4(chan, IDX_SATA_SError)));
1435 KdPrint2(("UniataAhciStop: timeout\n"));
1436 return;
1437 } // end UniataAhciStop()
1438
1439 UCHAR
1440 NTAPI
1441 UniataAhciBeginTransaction(
1442 IN PVOID HwDeviceExtension,
1443 IN ULONG lChannel,
1444 IN ULONG DeviceNumber,
1445 IN PSCSI_REQUEST_BLOCK Srb
1446 )
1447 {
1448 PHW_DEVICE_EXTENSION deviceExtension = (PHW_DEVICE_EXTENSION)HwDeviceExtension;
1449 PHW_CHANNEL chan = &deviceExtension->chan[lChannel];
1450 //ULONG Channel = deviceExtension->Channel + lChannel;
1451 //ULONG hIS;
1452 ULONG CMD;
1453 //AHCI_IS_REG IS;
1454 PATA_REQ AtaReq = (PATA_REQ)(Srb->SrbExtension);
1455 //SATA_SSTATUS_REG SStatus;
1456 //SATA_SERROR_REG SError;
1457 //ULONG offs = sizeof(IDE_AHCI_REGISTERS) + Channel*sizeof(IDE_AHCI_PORT_REGISTERS);
1458 //ULONGIO_PTR base;
1459 ULONG tag=0;
1460 //ULONG i;
1461
1462 PIDE_AHCI_CMD_LIST AHCI_CL = &(chan->AhciCtlBlock->cmd_list[tag]);
1463
1464 KdPrint2(("UniataAhciBeginTransaction: lChan %d\n", chan->lChannel));
1465
1466 if(AtaReq->dma_entries > (USHORT)0xffff) {
1467 KdPrint2(("UniataAhciBeginTransaction too long DMA tab\n"));
1468 return 0;
1469 }
1470
1471 AHCI_CL->prd_length = (USHORT)AtaReq->dma_entries;
1472 AHCI_CL->cmd_flags = AtaReq->ahci.io_cmd_flags;
1473 AHCI_CL->bytecount = 0;
1474 AHCI_CL->cmd_table_phys = AtaReq->ahci.ahci_base64;
1475 if(AHCI_CL->cmd_table_phys & AHCI_CMD_ALIGNEMENT_MASK) {
1476 KdPrint2((PRINT_PREFIX " AHCI CMD address is not aligned (mask %#x)\n", (ULONG)AHCI_CMD_ALIGNEMENT_MASK));
1477 }
1478
1479 CMD = UniataAhciReadChannelPort4(chan, IDX_AHCI_P_CMD);
1480 KdPrint2((" CMD %#x\n", CMD));
1481 CMD &= ~ATA_AHCI_P_CMD_ATAPI;
1482 KdPrint2((" send CMD %#x\n", CMD));
1483 UniataAhciWriteChannelPort4(chan, IDX_AHCI_P_CMD, CMD);
1484
1485 /* issue command to controller */
1486 UniataAhciWriteChannelPort4(chan, IDX_AHCI_P_CI, ATA_AHCI_P_CMD_ST);
1487
1488 if(!(chan->lun[DeviceNumber]->DeviceFlags & DFLAGS_ATAPI_DEVICE)) {
1489 // TODO: check if we send ATA_RESET and wait for ready of so.
1490 if(AtaReq->ahci.ahci_cmd_ptr->cfis[2] == IDE_COMMAND_ATAPI_RESET) {
1491 ULONG TFD;
1492 ULONG i;
1493
1494 for(i=0; i<1000000; i++) {
1495 TFD = UniataAhciReadChannelPort4(chan, IDX_AHCI_P_TFD);
1496 if(!(TFD & IDE_STATUS_BUSY)) {
1497 break;
1498 }
1499 }
1500 if(TFD & IDE_STATUS_BUSY) {
1501 KdPrint2((" timeout\n"));
1502 }
1503 if(TFD & IDE_STATUS_ERROR) {
1504 KdPrint2((" ERROR %#x\n", (UCHAR)(TFD >> 8)));
1505 }
1506 AtaReq->ahci.in_status = TFD;
1507
1508 return 0x00;
1509 }
1510 }
1511
1512 return IDE_STATUS_IDLE;
1513
1514 } // end UniataAhciBeginTransaction()
1515
1516 UCHAR
1517 NTAPI
1518 UniataAhciEndTransaction(
1519 IN PVOID HwDeviceExtension,
1520 IN ULONG lChannel,
1521 IN ULONG DeviceNumber,
1522 IN PSCSI_REQUEST_BLOCK Srb
1523 )
1524 {
1525 PHW_DEVICE_EXTENSION deviceExtension = (PHW_DEVICE_EXTENSION)HwDeviceExtension;
1526 PHW_CHANNEL chan = &deviceExtension->chan[lChannel];
1527 //ULONG Channel = deviceExtension->Channel + lChannel;
1528 //ULONG hIS;
1529 PATA_REQ AtaReq = (PATA_REQ)(Srb->SrbExtension);
1530 ULONG TFD;
1531 PUCHAR RCV_FIS = &(chan->AhciCtlBlock->rcv_fis.rfis[0]);
1532
1533 KdPrint2(("UniataAhciEndTransaction: lChan %d\n", chan->lChannel));
1534
1535 TFD = UniataAhciReadChannelPort4(chan, IDX_AHCI_P_TFD);
1536 KdPrint2((" TFD %#x\n", TFD));
1537
1538 if(TFD & IDE_STATUS_ERROR) {
1539 KdPrint2((" ERROR %#x\n", (UCHAR)(TFD >> 8)));
1540 }
1541 AtaReq->ahci.in_status = TFD;
1542
1543 //if (request->flags & ATA_R_CONTROL) {
1544
1545 AtaReq->ahci.in_bcount = (ULONG)(RCV_FIS[12]) | ((ULONG)(RCV_FIS[13]) << 8);
1546 AtaReq->ahci.in_lba = (ULONG)(RCV_FIS[4]) | ((ULONGLONG)(RCV_FIS[5]) << 8) |
1547 ((ULONGLONG)(RCV_FIS[6]) << 16);
1548 if(chan->ChannelCtrlFlags & CTRFLAGS_LBA48) {
1549 AtaReq->ahci.in_lba |= ((ULONGLONG)(RCV_FIS[8]) << 24) |
1550 ((ULONGLONG)(RCV_FIS[9]) << 32) |
1551 ((ULONGLONG)(RCV_FIS[10]) << 40);
1552 } else {
1553 AtaReq->ahci.in_lba |= ((ULONGLONG)(RCV_FIS[8]) << 24) |
1554 ((ULONGLONG)(RCV_FIS[9]) << 32) |
1555 ((ULONGLONG)(RCV_FIS[7] & 0x0f) << 24);
1556 }
1557
1558 //}
1559
1560 return 0;
1561
1562 } // end UniataAhciEndTransaction()
1563
1564 VOID
1565 NTAPI
1566 UniataAhciResume(
1567 IN PHW_CHANNEL chan
1568 )
1569 {
1570 ULONGLONG base;
1571
1572 KdPrint2(("UniataAhciResume: lChan %d\n", chan->lChannel));
1573
1574 #ifdef DBG
1575 UniataDumpAhciPortRegs(chan);
1576 #endif // DBG
1577
1578 /* Disable port interrupts */
1579 UniataAhciWriteChannelPort4(chan, IDX_AHCI_P_IE, 0);
1580
1581 /* setup work areas */
1582 base = chan->AHCI_CTL_PhAddr;
1583 if(!base) {
1584 KdPrint2((PRINT_PREFIX " AHCI buffer allocation failed\n"));
1585 return;
1586 }
1587 KdPrint2((PRINT_PREFIX " AHCI CLB setup\n"));
1588 if(base & AHCI_CLB_ALIGNEMENT_MASK) {
1589 KdPrint2((PRINT_PREFIX " AHCI CLB address is not aligned (mask %#x)\n", (ULONG)AHCI_FIS_ALIGNEMENT_MASK));
1590 }
1591 UniataAhciWriteChannelPort4(chan, IDX_AHCI_P_CLB,
1592 (ULONG)(base & 0xffffffff));
1593 UniataAhciWriteChannelPort4(chan, IDX_AHCI_P_CLB + 4,
1594 (ULONG)((base >> 32) & 0xffffffff));
1595
1596 KdPrint2((PRINT_PREFIX " AHCI RCV FIS setup\n"));
1597 base = chan->AHCI_CTL_PhAddr + FIELD_OFFSET(IDE_AHCI_CHANNEL_CTL_BLOCK, rcv_fis);
1598 if(base & AHCI_FIS_ALIGNEMENT_MASK) {
1599 KdPrint2((PRINT_PREFIX " AHCI FIS address is not aligned (mask %#x)\n", (ULONG)AHCI_FIS_ALIGNEMENT_MASK));
1600 }
1601 UniataAhciWriteChannelPort4(chan, IDX_AHCI_P_FB,
1602 (ULONG)(base & 0xffffffff));
1603 UniataAhciWriteChannelPort4(chan, IDX_AHCI_P_FB + 4,
1604 (ULONG)((base >> 32) & 0xffffffff));
1605
1606 /* activate the channel and power/spin up device */
1607 UniataAhciWriteChannelPort4(chan, IDX_AHCI_P_CMD,
1608 (ATA_AHCI_P_CMD_ACTIVE | ATA_AHCI_P_CMD_POD | ATA_AHCI_P_CMD_SUD |
1609 (((chan->ChannelCtrlFlags & CTRFLAGS_AHCI_PM)) ? ATA_AHCI_P_CMD_ALPE : 0) |
1610 (((chan->ChannelCtrlFlags & CTRFLAGS_AHCI_PM2)) ? ATA_AHCI_P_CMD_ASP : 0 ))
1611 );
1612
1613 #ifdef DBG
1614 UniataDumpAhciPortRegs(chan);
1615 #endif // DBG
1616
1617 UniataAhciStartFR(chan);
1618 UniataAhciStart(chan);
1619
1620 #ifdef DBG
1621 UniataDumpAhciPortRegs(chan);
1622 #endif // DBG
1623
1624 return;
1625 } // end UniataAhciResume()
1626
1627 #if 0
1628 VOID
1629 NTAPI
1630 UniataAhciSuspend(
1631 IN PHW_CHANNEL chan
1632 )
1633 {
1634 ULONGLONG base;
1635 SATA_SCONTROL_REG SControl;
1636
1637 KdPrint2(("UniataAhciSuspend:\n"));
1638
1639 /* Disable port interrupts */
1640 UniataAhciWriteChannelPort4(chan, IDX_AHCI_P_IE, 0);
1641
1642 /* Reset command register. */
1643 UniataAhciStop(chan);
1644 UniataAhciStopFR(chan);
1645 UniataAhciWriteChannelPort4(chan, IDX_AHCI_P_CMD, 0);
1646
1647 /* Allow everything including partial and slumber modes. */
1648 UniataSataWritePort4(chan, IDX_SATA_SControl, 0, 0);
1649
1650 /* Request slumber mode transition and give some time to get there. */
1651 UniataAhciWriteChannelPort4(chan, IDX_AHCI_P_CMD, ATA_AHCI_P_CMD_SLUMBER);
1652 AtapiStallExecution(100);
1653
1654 /* Disable PHY. */
1655 SControl.Reg = 0;
1656 SControl.DET = SStatus_DET_Offline;
1657 UniataSataWritePort4(chan, IDX_SATA_SControl, SControl.Reg, 0);
1658
1659 return;
1660 } // end UniataAhciSuspend()
1661 #endif
1662
1663 BOOLEAN
1664 NTAPI
1665 UniataAhciReadPM(
1666 IN PHW_CHANNEL chan,
1667 IN ULONG DeviceNumber,
1668 IN ULONG Reg,
1669 OUT PULONG result
1670 )
1671 {
1672 //ULONG Channel = deviceExtension->Channel + lChannel;
1673 //ULONG hIS;
1674 //ULONG CI;
1675 //AHCI_IS_REG IS;
1676 //ULONG tag=0;
1677 PIDE_AHCI_CMD AHCI_CMD = &(chan->AhciCtlBlock->cmd);
1678 PUCHAR RCV_FIS = &(chan->AhciCtlBlock->rcv_fis.rfis[0]);
1679
1680 KdPrint(("UniataAhciReadPM: lChan %d [%#x]\n", chan->lChannel, DeviceNumber));
1681
1682 if(DeviceNumber == DEVNUM_NOT_SPECIFIED) {
1683 (*result) = UniataSataReadPort4(chan, Reg, 0);
1684 return TRUE;
1685 }
1686 if(DeviceNumber < AHCI_DEV_SEL_PM) {
1687 switch(Reg) {
1688 case IDX_SATA_SStatus:
1689 Reg = 0; break;
1690 case IDX_SATA_SError:
1691 Reg = 1; break;
1692 case IDX_SATA_SControl:
1693 Reg = 2; break;
1694 default:
1695 return FALSE;
1696 }
1697 }
1698
1699 RtlZeroMemory(AHCI_CMD->cfis, sizeof(AHCI_CMD->cfis));
1700 AHCI_CMD->cfis[0] = AHCI_FIS_TYPE_ATA_H2D;
1701 AHCI_CMD->cfis[1] = AHCI_FIS_COMM_PM;
1702 AHCI_CMD->cfis[2] = IDE_COMMAND_READ_PM;
1703 AHCI_CMD->cfis[3] = (UCHAR)Reg;
1704 AHCI_CMD->cfis[7] = (UCHAR)(IDE_USE_LBA | DeviceNumber);
1705 AHCI_CMD->cfis[15] = IDE_DC_A_4BIT;
1706
1707 if(UniataAhciSendCommand(chan->DeviceExtension, chan->lChannel, DeviceNumber, 0, 10) == 0xff) {
1708 KdPrint2((" PM read failed\n"));
1709 return FALSE;
1710 }
1711
1712 KdDump(RCV_FIS, sizeof(chan->AhciCtlBlock->rcv_fis.rfis));
1713
1714 (*result) = UniataAhciUlongFromRFIS(RCV_FIS);
1715 return TRUE;
1716
1717 } // end UniataAhciReadPM()
1718
1719 UCHAR
1720 NTAPI
1721 UniataAhciWritePM(
1722 IN PHW_CHANNEL chan,
1723 IN ULONG DeviceNumber,
1724 IN ULONG Reg,
1725 IN ULONG value
1726 )
1727 {
1728 //ULONG Channel = deviceExtension->Channel + lChannel;
1729 //ULONG hIS;
1730 //ULONG CI;
1731 //AHCI_IS_REG IS;
1732 //ULONG tag=0;
1733 ULONG TFD;
1734 PIDE_AHCI_CMD AHCI_CMD = &(chan->AhciCtlBlock->cmd);
1735 //PUCHAR RCV_FIS = &(chan->AhciCtlBlock->rcv_fis.rfis[0]);
1736
1737 KdPrint(("UniataAhciWritePM: lChan %d [%#x] %#x\n", chan->lChannel, DeviceNumber, value));
1738
1739 if(DeviceNumber == DEVNUM_NOT_SPECIFIED) {
1740 UniataSataWritePort4(chan, Reg, value, 0);
1741 return 0;
1742 }
1743 if(DeviceNumber < AHCI_DEV_SEL_PM) {
1744 switch(Reg) {
1745 case IDX_SATA_SStatus:
1746 Reg = 0; break;
1747 case IDX_SATA_SError:
1748 Reg = 1; break;
1749 case IDX_SATA_SControl:
1750 Reg = 2; break;
1751 default:
1752 return 0xff;
1753 }
1754 }
1755
1756 RtlZeroMemory(AHCI_CMD->cfis, sizeof(AHCI_CMD->cfis));
1757 AHCI_CMD->cfis[0] = AHCI_FIS_TYPE_ATA_H2D;
1758 AHCI_CMD->cfis[1] = AHCI_FIS_COMM_PM;
1759 AHCI_CMD->cfis[2] = IDE_COMMAND_WRITE_PM;
1760 AHCI_CMD->cfis[3] = (UCHAR)Reg;
1761 AHCI_CMD->cfis[7] = (UCHAR)(IDE_USE_LBA | DeviceNumber);
1762
1763 AHCI_CMD->cfis[12] = (UCHAR)(value & 0xff);
1764 AHCI_CMD->cfis[4] = (UCHAR)((value >> 8) & 0xff);
1765 AHCI_CMD->cfis[5] = (UCHAR)((value >> 16) & 0xff);
1766 AHCI_CMD->cfis[6] = (UCHAR)((value >> 24) & 0xff);
1767
1768 AHCI_CMD->cfis[15] = IDE_DC_A_4BIT;
1769
1770 if(UniataAhciSendCommand(chan->DeviceExtension, chan->lChannel, DeviceNumber, 0, 100) == 0xff) {
1771 KdPrint2((" PM write failed\n"));
1772 return 0xff;
1773 }
1774
1775 TFD = UniataAhciReadChannelPort4(chan, IDX_AHCI_P_TFD);
1776
1777 if(TFD & IDE_STATUS_ERROR) {
1778 KdPrint2((" ERROR %#x\n", (UCHAR)(TFD >> 8)));
1779 }
1780 return (UCHAR)(TFD >> 8);
1781
1782 } // end UniataAhciWritePM()
1783
1784 VOID
1785 UniataAhciSetupCmdPtr(
1786 IN OUT PATA_REQ AtaReq
1787 )
1788 {
1789 union {
1790 PUCHAR prd_base;
1791 ULONGLONG prd_base64;
1792 };
1793 union {
1794 PUCHAR prd_base0;
1795 ULONGLONG prd_base64_0;
1796 };
1797 ULONG d;
1798
1799 prd_base64_0 = prd_base64 = 0;
1800 prd_base = (PUCHAR)(&AtaReq->ahci_cmd0);
1801 prd_base0 = prd_base;
1802
1803 prd_base64 = (prd_base64 + max(FIELD_OFFSET(ATA_REQ, ahci_cmd0), AHCI_CMD_ALIGNEMENT_MASK)) & ~AHCI_CMD_ALIGNEMENT_MASK;
1804
1805 d = (ULONG)(prd_base64 - prd_base64_0);
1806 KdPrint2((PRINT_PREFIX " aligned %I64x, d=%x\n", prd_base64, d));
1807
1808 AtaReq->ahci.ahci_cmd_ptr = (PIDE_AHCI_CMD)prd_base64;
1809 KdPrint2((PRINT_PREFIX " ahci_cmd_ptr %#x\n", AtaReq->ahci.ahci_cmd_ptr));
1810 } // end UniataAhciSetupCmdPtr()