c6dd47df6d0897e2e3ce0f0639cc8531ec9e876a
[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 BOOLEAN MemIo;
384 ULONGLONG base;
385
386 /* reset AHCI controller */
387 AtapiWritePortEx4(NULL, (ULONG_PTR)(&deviceExtension->BaseIoAHCI_0), IDX_AHCI_GHC,
388 AtapiReadPortEx4(NULL, (ULONG_PTR)(&deviceExtension->BaseIoAHCI_0), IDX_AHCI_GHC) | AHCI_GHC_HR);
389 AtapiStallExecution(1000000);
390 if(AtapiReadPortEx4(NULL, (ULONG_PTR)(&deviceExtension->BaseIoAHCI_0), IDX_AHCI_GHC) & AHCI_GHC_HR) {
391 KdPrint2((PRINT_PREFIX " AHCI reset failed\n"));
392 return FALSE;
393 }
394
395 /* enable AHCI mode */
396 AtapiWritePortEx4(NULL, (ULONG_PTR)(&deviceExtension->BaseIoAHCI_0), IDX_AHCI_GHC,
397 AtapiReadPortEx4(NULL, (ULONG_PTR)(&deviceExtension->BaseIoAHCI_0), IDX_AHCI_GHC) | AHCI_GHC_AE);
398
399 CAP = AtapiReadPortEx4(NULL, (ULONG_PTR)(&deviceExtension->BaseIoAHCI_0), IDX_AHCI_CAP);
400 PI = AtapiReadPortEx4(NULL, (ULONG_PTR)(&deviceExtension->BaseIoAHCI_0), IDX_AHCI_PI);
401 /* get the number of HW channels */
402 for(i=PI, n=0; i; n++, i=i>>1);
403 deviceExtension->NumberChannels =
404 max((CAP & AHCI_CAP_NOP_MASK)+1, n);
405 if(CAP & AHCI_CAP_S64A) {
406 KdPrint2((PRINT_PREFIX " AHCI 64bit\n"));
407 deviceExtension->Host64 = TRUE;
408 }
409
410 /* clear interrupts */
411 AtapiWritePortEx4(NULL, (ULONG_PTR)(&deviceExtension->BaseIoAHCI_0), IDX_AHCI_IS,
412 AtapiReadPortEx4(NULL, (ULONG_PTR)(&deviceExtension->BaseIoAHCI_0), IDX_AHCI_IS));
413
414 /* enable AHCI interrupts */
415 AtapiWritePortEx4(NULL, (ULONG_PTR)(&deviceExtension->BaseIoAHCI_0), IDX_AHCI_GHC,
416 AtapiReadPortEx4(NULL, (ULONG_PTR)(&deviceExtension->BaseIoAHCI_0), IDX_AHCI_GHC) | AHCI_GHC_IE);
417
418 version = AtapiReadPortEx4(NULL, (ULONG_PTR)(&deviceExtension->BaseIoAHCI_0), IDX_AHCI_VS);
419 KdPrint2((PRINT_PREFIX " AHCI version %x%x.%x%x controller with %d ports (mask %x) detected\n",
420 (version >> 24) & 0xff, (version >> 16) & 0xff,
421 (version >> 8) & 0xff, version & 0xff, deviceExtension->NumberChannels, PI));
422
423
424 deviceExtension->HwFlags |= UNIATA_SATA;
425 deviceExtension->HwFlags |= UNIATA_AHCI;
426
427 BaseMemAddress = deviceExtension->BaseIoAHCI_0.Addr;
428 MemIo = deviceExtension->BaseIoAHCI_0.MemIo;
429
430 for(c=0; c<deviceExtension->NumberChannels; c++) {
431 chan = &deviceExtension->chan[c];
432 offs = sizeof(IDE_AHCI_REGISTERS) + c*sizeof(IDE_AHCI_PORT_REGISTERS);
433
434 chan->RegTranslation[IDX_IO1_i_Status ].Addr = BaseMemAddress + offs + FIELD_OFFSET(IDE_AHCI_PORT_REGISTERS, TFD.STS);
435 chan->RegTranslation[IDX_IO1_i_Status ].MemIo = MemIo;
436 chan->RegTranslation[IDX_IO2_AltStatus] = chan->RegTranslation[IDX_IO1_i_Status];
437 chan->RegTranslation[IDX_IO1_i_Error ].Addr = BaseMemAddress + offs + FIELD_OFFSET(IDE_AHCI_PORT_REGISTERS, TFD.ERR);
438 chan->RegTranslation[IDX_IO1_i_Error ].MemIo = MemIo;
439 chan->RegTranslation[IDX_IO1_i_CylinderLow ].Addr = BaseMemAddress + offs + FIELD_OFFSET(IDE_AHCI_PORT_REGISTERS, SIG.LbaLow);
440 chan->RegTranslation[IDX_IO1_i_CylinderLow ].MemIo = MemIo;
441 chan->RegTranslation[IDX_IO1_i_CylinderHigh].Addr = BaseMemAddress + offs + FIELD_OFFSET(IDE_AHCI_PORT_REGISTERS, SIG.LbaHigh);
442 chan->RegTranslation[IDX_IO1_i_CylinderHigh].MemIo = MemIo;
443 chan->RegTranslation[IDX_IO1_i_BlockCount ].Addr = BaseMemAddress + offs + FIELD_OFFSET(IDE_AHCI_PORT_REGISTERS, SIG.SectorCount);
444 chan->RegTranslation[IDX_IO1_i_BlockCount ].MemIo = MemIo;
445
446 UniataInitSyncBaseIO(chan);
447
448 chan->RegTranslation[IDX_SATA_SStatus].Addr = BaseMemAddress + offs + FIELD_OFFSET(IDE_AHCI_PORT_REGISTERS, SSTS);
449 chan->RegTranslation[IDX_SATA_SStatus].MemIo = MemIo;
450 chan->RegTranslation[IDX_SATA_SError].Addr = BaseMemAddress + offs + FIELD_OFFSET(IDE_AHCI_PORT_REGISTERS, SERR);
451 chan->RegTranslation[IDX_SATA_SError].MemIo = MemIo;
452 chan->RegTranslation[IDX_SATA_SControl].Addr = BaseMemAddress + offs + FIELD_OFFSET(IDE_AHCI_PORT_REGISTERS, SCTL);
453 chan->RegTranslation[IDX_SATA_SControl].MemIo = MemIo;
454 chan->RegTranslation[IDX_SATA_SActive].Addr = BaseMemAddress + offs + FIELD_OFFSET(IDE_AHCI_PORT_REGISTERS, SACT);
455 chan->RegTranslation[IDX_SATA_SActive].MemIo = MemIo;
456
457 AtapiDmaAlloc(HwDeviceExtension, NULL, c);
458
459 base = chan->AHCI_CL_PhAddr;
460 if(!base) {
461 KdPrint2((PRINT_PREFIX " AHCI buffer allocation failed\n"));
462 return FALSE;
463 }
464 AtapiWritePortEx4(NULL, (ULONG_PTR)(&deviceExtension->BaseIoAHCI_0), offs + IDX_AHCI_P_CLB,
465 (ULONG)(base & 0xffffffff));
466 AtapiWritePortEx4(NULL, (ULONG_PTR)(&deviceExtension->BaseIoAHCI_0), offs + IDX_AHCI_P_CLB + 4,
467 (ULONG)((base >> 32) & 0xffffffff));
468
469 base = chan->AHCI_CL_PhAddr + ATA_AHCI_MAX_TAGS;
470 AtapiWritePortEx4(NULL, (ULONG_PTR)(&deviceExtension->BaseIoAHCI_0), offs + IDX_AHCI_P_FB,
471 (ULONG)(base & 0xffffffff));
472 AtapiWritePortEx4(NULL, (ULONG_PTR)(&deviceExtension->BaseIoAHCI_0), offs + IDX_AHCI_P_FB + 4,
473 (ULONG)((base >> 32) & 0xffffffff));
474
475 chan->ChannelCtrlFlags |= CTRFLAGS_NO_SLAVE;
476 }
477
478 return TRUE;
479 } // end UniataAhciInit()
480
481 UCHAR
482 NTAPI
483 UniataAhciStatus(
484 IN PVOID HwDeviceExtension,
485 IN ULONG lChannel,
486 IN ULONG DeviceNumber
487 )
488 {
489 PHW_DEVICE_EXTENSION deviceExtension = (PHW_DEVICE_EXTENSION)HwDeviceExtension;
490 PHW_CHANNEL chan = &deviceExtension->chan[lChannel];
491 ULONG Channel = deviceExtension->Channel + lChannel;
492 ULONG hIS;
493 ULONG CI;
494 AHCI_IS_REG IS;
495 SATA_SSTATUS_REG SStatus;
496 SATA_SERROR_REG SError;
497 ULONG offs = sizeof(IDE_AHCI_REGISTERS) + Channel*sizeof(IDE_AHCI_PORT_REGISTERS);
498 ULONG_PTR base;
499 ULONG tag=0;
500
501 KdPrint(("UniataAhciStatus:\n"));
502
503 hIS = AtapiReadPortEx4(NULL, (ULONG_PTR)(&deviceExtension->BaseIoAHCI_0), IDX_AHCI_IS);
504 KdPrint((" hIS %x\n", hIS));
505 hIS &= (1 << Channel);
506 if(!hIS) {
507 return 0;
508 }
509 base = (ULONG_PTR)(&deviceExtension->BaseIoAHCI_0 + offs);
510 IS.Reg = AtapiReadPort4(chan, base + IDX_AHCI_P_IS);
511 CI = AtapiReadPort4(chan, base + IDX_AHCI_P_CI);
512 SStatus.Reg = AtapiReadPort4(chan, IDX_SATA_SStatus);
513 SError.Reg = AtapiReadPort4(chan, IDX_SATA_SError);
514
515 /* clear interrupt(s) */
516 AtapiWritePortEx4(NULL, (ULONG_PTR)(&deviceExtension->BaseIoAHCI_0), IDX_AHCI_IS, hIS);
517 AtapiWritePort4(chan, base + IDX_AHCI_P_IS, IS.Reg);
518 AtapiWritePort4(chan, IDX_SATA_SError, SError.Reg);
519
520 KdPrint((" AHCI: status=%08x sstatus=%08x error=%08x CI=%08x\n",
521 IS.Reg, SStatus.Reg, SError.Reg, CI));
522
523 /* do we have cold connect surprise */
524 if(IS.CPDS) {
525 }
526
527 /* check for and handle connect events */
528 if(IS.PCS) {
529 UniataSataEvent(HwDeviceExtension, lChannel, UNIATA_SATA_EVENT_ATTACH);
530 }
531 if(IS.PRCS) {
532 UniataSataEvent(HwDeviceExtension, lChannel, UNIATA_SATA_EVENT_DETACH);
533 }
534 if(CI & (1 << tag)) {
535 return 1;
536 }
537 KdPrint((" AHCI: unexpected\n"));
538 return 2;
539
540 } // end UniataAhciStatus()
541
542 ULONG
543 NTAPI
544 UniataAhciSetupFIS(
545 IN PHW_DEVICE_EXTENSION deviceExtension,
546 IN ULONG DeviceNumber,
547 IN ULONG lChannel,
548 OUT PUCHAR fis,
549 IN UCHAR command,
550 IN ULONGLONG lba,
551 IN USHORT count,
552 IN USHORT feature,
553 IN ULONG flags
554 )
555 {
556 ULONG ldev = lChannel*2 + DeviceNumber;
557 ULONG i;
558 PUCHAR plba;
559
560 KdPrint2((PRINT_PREFIX " AHCI setup FIS\n" ));
561 i = 0;
562 plba = (PUCHAR)&lba;
563
564 if((AtaCommandFlags[command] & ATA_CMD_FLAG_LBAIOsupp) &&
565 CheckIfBadBlock(&(deviceExtension->lun[ldev]), lba, count)) {
566 KdPrint3((PRINT_PREFIX ": artificial bad block, lba %#I64x count %#x\n", lba, count));
567 return IDE_STATUS_ERROR;
568 //return SRB_STATUS_ERROR;
569 }
570
571 /* translate command into 48bit version */
572 if ((lba >= ATA_MAX_LBA28 || count > 256) &&
573 deviceExtension->lun[ldev].IdentifyData.FeaturesSupport.Address48) {
574 if(AtaCommandFlags[command] & ATA_CMD_FLAG_48supp) {
575 command = AtaCommands48[command];
576 } else {
577 KdPrint2((PRINT_PREFIX " unhandled LBA48 command\n"));
578 return 0;
579 }
580 }
581
582 fis[0] = 0x27; /* host to device */
583 fis[1] = 0x80; /* command FIS (note PM goes here) */
584 fis[2] = command;
585 fis[3] = (UCHAR)feature;
586
587 fis[4] = plba[0];
588 fis[5] = plba[1];
589 fis[6] = plba[2];
590 fis[7] = IDE_USE_LBA | (DeviceNumber ? IDE_DRIVE_2 : IDE_DRIVE_1);
591 if ((lba >= ATA_MAX_LBA28 || count > 256) &&
592 deviceExtension->lun[ldev].IdentifyData.FeaturesSupport.Address48) {
593 i++;
594 } else {
595 #ifdef _MSC_VER
596 #pragma warning(push)
597 #pragma warning(disable:4333) // right shift by too large amount, data loss
598 #endif
599 fis[7] |= (plba[3] >> 24) & 0x0f;
600 #ifdef _MSC_VER
601 #pragma warning(pop)
602 #endif
603 }
604
605 fis[8] = plba[3];
606 fis[9] = plba[4];
607 fis[10] = plba[5];
608 fis[11] = (UCHAR)(feature>>8) & 0xff;
609
610 fis[12] = (UCHAR)count & 0xff;
611 fis[13] = (UCHAR)(count>>8) & 0xff;
612 fis[14] = 0x00;
613 fis[15] = IDE_DC_A_4BIT;
614
615 fis[16] = 0x00;
616 fis[17] = 0x00;
617 fis[18] = 0x00;
618 fis[19] = 0x00;
619 return 20;
620 } // end UniataAhciSetupFIS()