[UNIATA]
[reactos.git] / reactos / drivers / storage / ide / uniata / id_sata.cpp
1 /*++
2
3 Copyright (c) 2008-2010 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 deviceExtension->lun[lChannel*2].TransferMode = ATA_SA150 + (UCHAR)(SStatus.SPD - 1);
71 break;
72 }
73 AtapiStallExecution(10000);
74 }
75 if(i >= 100) {
76 KdPrint2((PRINT_PREFIX "UniataSataConnect: SStatus %8.8x\n", SStatus.Reg));
77 return 0xff;
78 }
79 /* clear SATA error register */
80 UniataSataWritePort4(chan, IDX_SATA_SError,
81 UniataSataReadPort4(chan, IDX_SATA_SError, pm_port), pm_port);
82
83 Status = WaitOnBaseBusyLong(chan);
84 if(Status & IDE_STATUS_BUSY) {
85 return Status;
86 }
87 /*
88 signatureLow = AtapiReadPort1(chan, &deviceExtension->BaseIoAddress1[lChannel].i.CylinderLow);
89 signatureHigh = AtapiReadPort1(chan, &deviceExtension->baseIoAddress1[lChannel].i.CylinderHigh);
90
91 if (signatureLow == ATAPI_MAGIC_LSB && signatureHigh == ATAPI_MAGIC_MSB) {
92 }
93 */
94 KdPrint2((PRINT_PREFIX "UniataSataConnect: OK, ATA status %x\n", Status));
95 return IDE_STATUS_IDLE;
96 } // end UniataSataConnect()
97
98 UCHAR
99 NTAPI
100 UniataSataPhyEnable(
101 IN PVOID HwDeviceExtension,
102 IN ULONG lChannel, // logical channel
103 IN ULONG pm_port /* for port multipliers */
104 )
105 {
106 PHW_DEVICE_EXTENSION deviceExtension = (PHW_DEVICE_EXTENSION)HwDeviceExtension;
107 PHW_CHANNEL chan = &deviceExtension->chan[lChannel];
108 SATA_SCONTROL_REG SControl;
109 int loop, retry;
110
111 KdPrint2((PRINT_PREFIX "UniataSataPhyEnable:\n"));
112
113 if(!UniataIsSATARangeAvailable(deviceExtension, lChannel)) {
114 KdPrint2((PRINT_PREFIX " no I/O range\n"));
115 return IDE_STATUS_IDLE;
116 }
117
118 SControl.Reg = UniataSataReadPort4(chan, IDX_SATA_SControl, pm_port);
119 KdPrint2((PRINT_PREFIX "SControl %x\n", SControl.Reg));
120 if(SControl.DET == SControl_DET_Idle) {
121 return UniataSataConnect(HwDeviceExtension, lChannel, pm_port);
122 }
123
124 for (retry = 0; retry < 10; retry++) {
125 KdPrint2((PRINT_PREFIX "UniataSataPhyEnable: retry init %d\n", retry));
126 for (loop = 0; loop < 10; loop++) {
127 SControl.Reg = 0;
128 SControl.DET = SControl_DET_Init;
129 UniataSataWritePort4(chan, IDX_SATA_SControl, SControl.Reg, pm_port);
130 AtapiStallExecution(100);
131 SControl.Reg = UniataSataReadPort4(chan, IDX_SATA_SControl, pm_port);
132 KdPrint2((PRINT_PREFIX " SControl %8.8%x\n", SControl.Reg));
133 if(SControl.DET == SControl_DET_Init) {
134 break;
135 }
136 }
137 AtapiStallExecution(5000);
138 KdPrint2((PRINT_PREFIX "UniataSataPhyEnable: retry idle %d\n", retry));
139 for (loop = 0; loop < 10; loop++) {
140 SControl.Reg = 0;
141 SControl.DET = SControl_DET_DoNothing;
142 SControl.IPM = SControl_IPM_NoPartialSlumber;
143 UniataSataWritePort4(chan, IDX_SATA_SControl, SControl.Reg, pm_port);
144 AtapiStallExecution(100);
145 SControl.Reg = UniataSataReadPort4(chan, IDX_SATA_SControl, pm_port);
146 KdPrint2((PRINT_PREFIX " SControl %8.8%x\n", SControl.Reg));
147 if(SControl.DET == SControl_DET_Idle) {
148 return UniataSataConnect(HwDeviceExtension, lChannel, pm_port);
149 }
150 }
151 }
152
153 KdPrint2((PRINT_PREFIX "UniataSataPhyEnable: failed\n"));
154 return 0xff;
155 } // end UniataSataPhyEnable()
156
157 BOOLEAN
158 NTAPI
159 UniataSataClearErr(
160 IN PVOID HwDeviceExtension,
161 IN ULONG lChannel, // logical channel
162 IN BOOLEAN do_connect,
163 IN ULONG pm_port /* for port multipliers */
164 )
165 {
166 PHW_DEVICE_EXTENSION deviceExtension = (PHW_DEVICE_EXTENSION)HwDeviceExtension;
167 PHW_CHANNEL chan = &deviceExtension->chan[lChannel];
168 //ULONG ChipFlags = deviceExtension->HwFlags & CHIPFLAG_MASK;
169 SATA_SSTATUS_REG SStatus;
170 SATA_SERROR_REG SError;
171
172 if(UniataIsSATARangeAvailable(deviceExtension, lChannel)) {
173 //if(ChipFlags & UNIATA_SATA) {
174
175 SStatus.Reg = UniataSataReadPort4(chan, IDX_SATA_SStatus, pm_port);
176 SError.Reg = UniataSataReadPort4(chan, IDX_SATA_SError, pm_port);
177
178 if(SStatus.Reg) {
179 KdPrint2((PRINT_PREFIX " SStatus %x\n", SStatus.Reg));
180 }
181 if(SError.Reg) {
182 KdPrint2((PRINT_PREFIX " SError %x\n", SError.Reg));
183 /* clear error bits/interrupt */
184 UniataSataWritePort4(chan, IDX_SATA_SError, SError.Reg, pm_port);
185
186 if(do_connect) {
187 /* if we have a connection event deal with it */
188 if(SError.DIAG.N) {
189 KdPrint2((PRINT_PREFIX " catch SATA connect/disconnect\n"));
190 if(SStatus.SPD >= SStatus_SPD_Gen1) {
191 UniataSataEvent(deviceExtension, lChannel, UNIATA_SATA_EVENT_ATTACH, pm_port);
192 } else {
193 UniataSataEvent(deviceExtension, lChannel, UNIATA_SATA_EVENT_DETACH, pm_port);
194 }
195 return TRUE;
196 }
197 }
198 }
199 }
200 return FALSE;
201 } // end UniataSataClearErr()
202
203 BOOLEAN
204 NTAPI
205 UniataSataEvent(
206 IN PVOID HwDeviceExtension,
207 IN ULONG lChannel, // logical channel
208 IN ULONG Action,
209 IN ULONG pm_port /* for port multipliers */
210 )
211 {
212 PHW_DEVICE_EXTENSION deviceExtension = (PHW_DEVICE_EXTENSION)HwDeviceExtension;
213 UCHAR Status;
214 ULONG ldev = lChannel*2 + (pm_port ? 1 : 0);
215
216 if(!UniataIsSATARangeAvailable(deviceExtension, lChannel)) {
217 return FALSE;
218 }
219
220 switch(Action) {
221 case UNIATA_SATA_EVENT_ATTACH:
222 KdPrint2((PRINT_PREFIX " CONNECTED\n"));
223 Status = UniataSataConnect(HwDeviceExtension, lChannel, pm_port);
224 KdPrint2((PRINT_PREFIX " Status %x\n", Status));
225 if(Status != IDE_STATUS_IDLE) {
226 return FALSE;
227 }
228 CheckDevice(HwDeviceExtension, lChannel, pm_port ? 1 : 0 /*dev*/, FALSE);
229 return TRUE;
230 break;
231 case UNIATA_SATA_EVENT_DETACH:
232 KdPrint2((PRINT_PREFIX " DISCONNECTED\n"));
233 UniataForgetDevice(&(deviceExtension->lun[ldev]));
234 return TRUE;
235 break;
236 }
237 return FALSE;
238 } // end UniataSataEvent()
239
240 ULONG
241 UniataSataReadPort4(
242 IN PHW_CHANNEL chan,
243 IN ULONG io_port_ndx,
244 IN ULONG pm_port /* for port multipliers */
245 )
246 {
247 if(chan && (io_port_ndx < IDX_MAX_REG) &&
248 chan->RegTranslation[io_port_ndx].Proc) {
249
250 PHW_DEVICE_EXTENSION deviceExtension = chan->DeviceExtension;
251 PVOID HwDeviceExtension = (PVOID)deviceExtension;
252 ULONG slotNumber = deviceExtension->slotNumber;
253 ULONG SystemIoBusNumber = deviceExtension->SystemIoBusNumber;
254 ULONG VendorID = deviceExtension->DevID & 0xffff;
255 ULONG offs;
256 ULONG p;
257
258 switch(VendorID) {
259 case ATA_INTEL_ID: {
260 p = pm_port ? 1 : 0;
261 if(deviceExtension->HwFlags & ICH5) {
262 offs = 0x50+chan->lun[p]->SATA_lun_map*0x10;
263 switch(io_port_ndx) {
264 case IDX_SATA_SStatus:
265 offs += 0;
266 break;
267 case IDX_SATA_SError:
268 offs += 1*4;
269 break;
270 case IDX_SATA_SControl:
271 offs += 2*4;
272 break;
273 default:
274 return -1;
275 }
276 SetPciConfig4(0xa0, offs);
277 GetPciConfig4(0xa4, offs);
278 return offs;
279 } else {
280 offs = ((deviceExtension->Channel+chan->lChannel)*2+p) * 0x100;
281 switch(io_port_ndx) {
282 case IDX_SATA_SStatus:
283 offs += 0;
284 break;
285 case IDX_SATA_SControl:
286 offs += 1;
287 break;
288 case IDX_SATA_SError:
289 offs += 2;
290 break;
291 default:
292 return -1;
293 }
294 AtapiWritePort4(chan, IDX_INDEXED_ADDR, offs);
295 return AtapiReadPort4(chan, IDX_INDEXED_DATA);
296 }
297 } // ATA_INTEL_ID
298 } // end switch(VendorID)
299 return -1;
300 }
301 return AtapiReadPort4(chan, io_port_ndx);
302 } // end UniataSataReadPort4()
303
304 VOID
305 UniataSataWritePort4(
306 IN PHW_CHANNEL chan,
307 IN ULONG io_port_ndx,
308 IN ULONG data,
309 IN ULONG pm_port /* for port multipliers */
310 )
311 {
312 if(chan && (io_port_ndx < IDX_MAX_REG) &&
313 chan->RegTranslation[io_port_ndx].Proc) {
314
315 PHW_DEVICE_EXTENSION deviceExtension = chan->DeviceExtension;
316 PVOID HwDeviceExtension = (PVOID)deviceExtension;
317 ULONG slotNumber = deviceExtension->slotNumber;
318 ULONG SystemIoBusNumber = deviceExtension->SystemIoBusNumber;
319 ULONG VendorID = deviceExtension->DevID & 0xffff;
320 ULONG offs;
321 ULONG p;
322
323 switch(VendorID) {
324 case ATA_INTEL_ID: {
325 p = pm_port ? 1 : 0;
326 if(deviceExtension->HwFlags & ICH5) {
327 offs = 0x50+chan->lun[p]->SATA_lun_map*0x10;
328 switch(io_port_ndx) {
329 case IDX_SATA_SStatus:
330 offs += 0;
331 break;
332 case IDX_SATA_SError:
333 offs += 1*4;
334 break;
335 case IDX_SATA_SControl:
336 offs += 2*4;
337 break;
338 default:
339 return;
340 }
341 SetPciConfig4(0xa0, offs);
342 SetPciConfig4(0xa4, data);
343 return;
344 } else {
345 offs = ((deviceExtension->Channel+chan->lChannel)*2+p) * 0x100;
346 switch(io_port_ndx) {
347 case IDX_SATA_SStatus:
348 offs += 0;
349 break;
350 case IDX_SATA_SControl:
351 offs += 1;
352 break;
353 case IDX_SATA_SError:
354 offs += 2;
355 break;
356 default:
357 return;
358 }
359 AtapiWritePort4(chan, IDX_INDEXED_ADDR, offs);
360 AtapiWritePort4(chan, IDX_INDEXED_DATA, data);
361 }
362 } // ATA_INTEL_ID
363 } // end switch(VendorID)
364 return;
365 }
366 AtapiWritePort4(chan, io_port_ndx, data);
367 } // end UniataSataWritePort4()
368
369 BOOLEAN
370 NTAPI
371 UniataAhciInit(
372 IN PVOID HwDeviceExtension
373 )
374 {
375 PHW_DEVICE_EXTENSION deviceExtension = (PHW_DEVICE_EXTENSION)HwDeviceExtension;
376 ULONG version;
377 ULONG c, i, n;
378 PHW_CHANNEL chan;
379 ULONG offs;
380 ULONG BaseMemAddress;
381 ULONG PI;
382 ULONG CAP;
383 ULONG GHC;
384 BOOLEAN MemIo;
385 ULONGLONG base;
386
387 /* reset AHCI controller */
388 GHC = AtapiReadPortEx4(NULL, (ULONG_PTR)&deviceExtension->BaseIoAHCI_0, IDX_AHCI_GHC);
389 KdPrint2((PRINT_PREFIX " reset AHCI controller, GHC %x\n", GHC));
390 AtapiWritePortEx4(NULL, (ULONG_PTR)&deviceExtension->BaseIoAHCI_0, IDX_AHCI_GHC,
391 GHC | AHCI_GHC_HR);
392
393 for(i=0; i<1000; i++) {
394 AtapiStallExecution(1000);
395 GHC = AtapiReadPortEx4(NULL, (ULONG_PTR)&deviceExtension->BaseIoAHCI_0, IDX_AHCI_GHC);
396 KdPrint2((PRINT_PREFIX " AHCI GHC %x\n", GHC));
397 if(!(GHC & AHCI_GHC_HR)) {
398 break;
399 }
400 }
401 if(GHC & AHCI_GHC_HR) {
402 KdPrint2((PRINT_PREFIX " AHCI reset failed\n"));
403 return FALSE;
404 }
405
406 /* enable AHCI mode */
407 GHC = AtapiReadPortEx4(NULL, (ULONG_PTR)&deviceExtension->BaseIoAHCI_0, IDX_AHCI_GHC);
408 KdPrint2((PRINT_PREFIX " enable AHCI mode, GHC %x\n", GHC));
409 AtapiWritePortEx4(NULL, (ULONG_PTR)&deviceExtension->BaseIoAHCI_0, IDX_AHCI_GHC,
410 GHC | AHCI_GHC_AE);
411 GHC = AtapiReadPortEx4(NULL, (ULONG_PTR)&deviceExtension->BaseIoAHCI_0, IDX_AHCI_GHC);
412 KdPrint2((PRINT_PREFIX " AHCI GHC %x\n", GHC));
413
414
415 CAP = AtapiReadPortEx4(NULL, (ULONG_PTR)(&deviceExtension->BaseIoAHCI_0), IDX_AHCI_CAP);
416 PI = AtapiReadPortEx4(NULL, (ULONG_PTR)(&deviceExtension->BaseIoAHCI_0), IDX_AHCI_PI);
417 KdPrint2((PRINT_PREFIX " AHCI CAP %x\n", CAP));
418 if(CAP & AHCI_CAP_S64A) {
419 KdPrint2((PRINT_PREFIX " AHCI 64bit\n"));
420 deviceExtension->Host64 = TRUE;
421 }
422 /* get the number of HW channels */
423 PI = AtapiReadPortEx4(NULL, (ULONG)&deviceExtension->BaseIoAHCI_0, IDX_AHCI_PI);
424 KdPrint2((PRINT_PREFIX " AHCI PI %x\n", PI));
425 for(i=PI, n=0; i; n++, i=i>>1);
426 deviceExtension->NumberChannels =
427 max((CAP & AHCI_CAP_NOP_MASK)+1, n);
428
429 switch(deviceExtension->DevID) {
430 case ATA_M88SX6111:
431 deviceExtension->NumberChannels = 1;
432 break;
433 case ATA_M88SX6121:
434 deviceExtension->NumberChannels = 2;
435 break;
436 case ATA_M88SX6141:
437 case ATA_M88SX6145:
438 deviceExtension->NumberChannels = 4;
439 break;
440 } // switch()
441
442 /* clear interrupts */
443 AtapiWritePortEx4(NULL, (ULONG_PTR)(&deviceExtension->BaseIoAHCI_0), IDX_AHCI_IS,
444 AtapiReadPortEx4(NULL, (ULONG_PTR)(&deviceExtension->BaseIoAHCI_0), IDX_AHCI_IS));
445
446 /* enable AHCI interrupts */
447 AtapiWritePortEx4(NULL, (ULONG_PTR)(&deviceExtension->BaseIoAHCI_0), IDX_AHCI_GHC,
448 AtapiReadPortEx4(NULL, (ULONG_PTR)(&deviceExtension->BaseIoAHCI_0), IDX_AHCI_GHC) | AHCI_GHC_IE);
449
450 version = AtapiReadPortEx4(NULL, (ULONG_PTR)(&deviceExtension->BaseIoAHCI_0), IDX_AHCI_VS);
451 KdPrint2((PRINT_PREFIX " AHCI version %x.%02x controller with %d ports (mask %x) detected\n",
452 ((version >> 20) & 0xf0) + ((version >> 16) & 0x0f),
453 ((version >> 4) & 0xf0) + (version & 0x0f),
454 deviceExtension->NumberChannels, PI));
455
456 KdPrint2((PRINT_PREFIX " PM%s supported\n",
457 CAP & AHCI_CAP_SPM ? "" : " not"));
458
459 deviceExtension->HwFlags |= UNIATA_SATA;
460 deviceExtension->HwFlags |= UNIATA_AHCI;
461
462 BaseMemAddress = deviceExtension->BaseIoAHCI_0.Addr;
463 MemIo = deviceExtension->BaseIoAHCI_0.MemIo;
464
465 for(c=0; c<deviceExtension->NumberChannels; c++) {
466 chan = &deviceExtension->chan[c];
467 offs = sizeof(IDE_AHCI_REGISTERS) + c*sizeof(IDE_AHCI_PORT_REGISTERS);
468
469 chan->RegTranslation[IDX_IO1_i_Status ].Addr = BaseMemAddress + offs + FIELD_OFFSET(IDE_AHCI_PORT_REGISTERS, TFD.STS);
470 chan->RegTranslation[IDX_IO1_i_Status ].MemIo = MemIo;
471 chan->RegTranslation[IDX_IO2_AltStatus] = chan->RegTranslation[IDX_IO1_i_Status];
472 chan->RegTranslation[IDX_IO1_i_Error ].Addr = BaseMemAddress + offs + FIELD_OFFSET(IDE_AHCI_PORT_REGISTERS, TFD.ERR);
473 chan->RegTranslation[IDX_IO1_i_Error ].MemIo = MemIo;
474 chan->RegTranslation[IDX_IO1_i_CylinderLow ].Addr = BaseMemAddress + offs + FIELD_OFFSET(IDE_AHCI_PORT_REGISTERS, SIG.LbaLow);
475 chan->RegTranslation[IDX_IO1_i_CylinderLow ].MemIo = MemIo;
476 chan->RegTranslation[IDX_IO1_i_CylinderHigh].Addr = BaseMemAddress + offs + FIELD_OFFSET(IDE_AHCI_PORT_REGISTERS, SIG.LbaHigh);
477 chan->RegTranslation[IDX_IO1_i_CylinderHigh].MemIo = MemIo;
478 chan->RegTranslation[IDX_IO1_i_BlockCount ].Addr = BaseMemAddress + offs + FIELD_OFFSET(IDE_AHCI_PORT_REGISTERS, SIG.SectorCount);
479 chan->RegTranslation[IDX_IO1_i_BlockCount ].MemIo = MemIo;
480
481 UniataInitSyncBaseIO(chan);
482
483 chan->RegTranslation[IDX_SATA_SStatus].Addr = BaseMemAddress + offs + FIELD_OFFSET(IDE_AHCI_PORT_REGISTERS, SSTS);
484 chan->RegTranslation[IDX_SATA_SStatus].MemIo = MemIo;
485 chan->RegTranslation[IDX_SATA_SError].Addr = BaseMemAddress + offs + FIELD_OFFSET(IDE_AHCI_PORT_REGISTERS, SERR);
486 chan->RegTranslation[IDX_SATA_SError].MemIo = MemIo;
487 chan->RegTranslation[IDX_SATA_SControl].Addr = BaseMemAddress + offs + FIELD_OFFSET(IDE_AHCI_PORT_REGISTERS, SCTL);
488 chan->RegTranslation[IDX_SATA_SControl].MemIo = MemIo;
489 chan->RegTranslation[IDX_SATA_SActive].Addr = BaseMemAddress + offs + FIELD_OFFSET(IDE_AHCI_PORT_REGISTERS, SACT);
490 chan->RegTranslation[IDX_SATA_SActive].MemIo = MemIo;
491
492 AtapiDmaAlloc(HwDeviceExtension, NULL, c);
493
494 base = chan->AHCI_CL_PhAddr;
495 if(!base) {
496 KdPrint2((PRINT_PREFIX " AHCI buffer allocation failed\n"));
497 return FALSE;
498 }
499 AtapiWritePortEx4(NULL, (ULONG_PTR)(&deviceExtension->BaseIoAHCI_0), offs + IDX_AHCI_P_CLB,
500 (ULONG)(base & 0xffffffff));
501 AtapiWritePortEx4(NULL, (ULONG_PTR)(&deviceExtension->BaseIoAHCI_0), offs + IDX_AHCI_P_CLB + 4,
502 (ULONG)((base >> 32) & 0xffffffff));
503
504 base = chan->AHCI_CL_PhAddr + ATA_AHCI_MAX_TAGS;
505 AtapiWritePortEx4(NULL, (ULONG_PTR)(&deviceExtension->BaseIoAHCI_0), offs + IDX_AHCI_P_FB,
506 (ULONG)(base & 0xffffffff));
507 AtapiWritePortEx4(NULL, (ULONG_PTR)(&deviceExtension->BaseIoAHCI_0), offs + IDX_AHCI_P_FB + 4,
508 (ULONG)((base >> 32) & 0xffffffff));
509
510 chan->ChannelCtrlFlags |= CTRFLAGS_NO_SLAVE;
511 }
512
513 return TRUE;
514 } // end UniataAhciInit()
515
516 UCHAR
517 NTAPI
518 UniataAhciStatus(
519 IN PVOID HwDeviceExtension,
520 IN ULONG lChannel,
521 IN ULONG DeviceNumber
522 )
523 {
524 PHW_DEVICE_EXTENSION deviceExtension = (PHW_DEVICE_EXTENSION)HwDeviceExtension;
525 PHW_CHANNEL chan = &deviceExtension->chan[lChannel];
526 ULONG Channel = deviceExtension->Channel + lChannel;
527 ULONG hIS;
528 ULONG CI;
529 AHCI_IS_REG IS;
530 SATA_SSTATUS_REG SStatus;
531 SATA_SERROR_REG SError;
532 ULONG offs = sizeof(IDE_AHCI_REGISTERS) + Channel*sizeof(IDE_AHCI_PORT_REGISTERS);
533 ULONG_PTR base;
534 ULONG tag=0;
535
536 KdPrint(("UniataAhciStatus:\n"));
537
538 hIS = AtapiReadPortEx4(NULL, (ULONG_PTR)(&deviceExtension->BaseIoAHCI_0), IDX_AHCI_IS);
539 KdPrint((" hIS %x\n", hIS));
540 hIS &= (1 << Channel);
541 if(!hIS) {
542 return 0;
543 }
544 base = (ULONG_PTR)(&deviceExtension->BaseIoAHCI_0 + offs);
545 IS.Reg = AtapiReadPort4(chan, base + IDX_AHCI_P_IS);
546 CI = AtapiReadPort4(chan, base + IDX_AHCI_P_CI);
547 SStatus.Reg = AtapiReadPort4(chan, IDX_SATA_SStatus);
548 SError.Reg = AtapiReadPort4(chan, IDX_SATA_SError);
549
550 /* clear interrupt(s) */
551 AtapiWritePortEx4(NULL, (ULONG_PTR)(&deviceExtension->BaseIoAHCI_0), IDX_AHCI_IS, hIS);
552 AtapiWritePort4(chan, base + IDX_AHCI_P_IS, IS.Reg);
553 AtapiWritePort4(chan, IDX_SATA_SError, SError.Reg);
554
555 KdPrint((" AHCI: status=%08x sstatus=%08x error=%08x CI=%08x\n",
556 IS.Reg, SStatus.Reg, SError.Reg, CI));
557
558 /* do we have cold connect surprise */
559 if(IS.CPDS) {
560 }
561
562 /* check for and handle connect events */
563 if(IS.PCS) {
564 UniataSataEvent(HwDeviceExtension, lChannel, UNIATA_SATA_EVENT_ATTACH);
565 }
566 if(IS.PRCS) {
567 UniataSataEvent(HwDeviceExtension, lChannel, UNIATA_SATA_EVENT_DETACH);
568 }
569 if(CI & (1 << tag)) {
570 return 1;
571 }
572 KdPrint((" AHCI: unexpected\n"));
573 return 2;
574
575 } // end UniataAhciStatus()
576
577 ULONG
578 NTAPI
579 UniataAhciSetupFIS(
580 IN PHW_DEVICE_EXTENSION deviceExtension,
581 IN ULONG DeviceNumber,
582 IN ULONG lChannel,
583 OUT PUCHAR fis,
584 IN UCHAR command,
585 IN ULONGLONG lba,
586 IN USHORT count,
587 IN USHORT feature,
588 IN ULONG flags
589 )
590 {
591 ULONG ldev = lChannel*2 + DeviceNumber;
592 ULONG i;
593 PUCHAR plba;
594
595 KdPrint2((PRINT_PREFIX " AHCI setup FIS\n" ));
596 i = 0;
597 plba = (PUCHAR)&lba;
598
599 if((AtaCommandFlags[command] & ATA_CMD_FLAG_LBAIOsupp) &&
600 CheckIfBadBlock(&(deviceExtension->lun[ldev]), lba, count)) {
601 KdPrint3((PRINT_PREFIX ": artificial bad block, lba %#I64x count %#x\n", lba, count));
602 return IDE_STATUS_ERROR;
603 //return SRB_STATUS_ERROR;
604 }
605
606 /* translate command into 48bit version */
607 if ((lba >= ATA_MAX_LBA28 || count > 256) &&
608 deviceExtension->lun[ldev].IdentifyData.FeaturesSupport.Address48) {
609 if(AtaCommandFlags[command] & ATA_CMD_FLAG_48supp) {
610 command = AtaCommands48[command];
611 } else {
612 KdPrint2((PRINT_PREFIX " unhandled LBA48 command\n"));
613 return 0;
614 }
615 }
616
617 fis[0] = 0x27; /* host to device */
618 fis[1] = 0x80; /* command FIS (note PM goes here) */
619 fis[2] = command;
620 fis[3] = (UCHAR)feature;
621
622 fis[4] = plba[0];
623 fis[5] = plba[1];
624 fis[6] = plba[2];
625 fis[7] = IDE_USE_LBA | (DeviceNumber ? IDE_DRIVE_2 : IDE_DRIVE_1);
626 if ((lba >= ATA_MAX_LBA28 || count > 256) &&
627 deviceExtension->lun[ldev].IdentifyData.FeaturesSupport.Address48) {
628 i++;
629 } else {
630 #ifdef _MSC_VER
631 #pragma warning(push)
632 #pragma warning(disable:4333) // right shift by too large amount, data loss
633 #endif
634 fis[7] |= (plba[3] >> 24) & 0x0f;
635 #ifdef _MSC_VER
636 #pragma warning(pop)
637 #endif
638 }
639
640 fis[8] = plba[3];
641 fis[9] = plba[4];
642 fis[10] = plba[5];
643 fis[11] = (UCHAR)(feature>>8) & 0xff;
644
645 fis[12] = (UCHAR)count & 0xff;
646 fis[13] = (UCHAR)(count>>8) & 0xff;
647 fis[14] = 0x00;
648 fis[15] = IDE_DC_A_4BIT;
649
650 fis[16] = 0x00;
651 fis[17] = 0x00;
652 fis[18] = 0x00;
653 fis[19] = 0x00;
654 return 20;
655 } // end UniataAhciSetupFIS()