Update UniATA to Version 0.39j Credits go to Samuel Serapion
[reactos.git] / reactos / drivers / storage / ide / uniata / id_sata.cpp
1 #include "stdafx.h"
2
3 UCHAR
4 UniataSataConnect(
5 IN PVOID HwDeviceExtension,
6 IN ULONG lChannel // logical channel
7 )
8 {
9 PHW_DEVICE_EXTENSION deviceExtension = (PHW_DEVICE_EXTENSION)HwDeviceExtension;
10 ULONG Channel = deviceExtension->Channel + lChannel;
11 PHW_CHANNEL chan = &deviceExtension->chan[lChannel];
12 SATA_SSTATUS_REG SStatus;
13 ULONG i;
14 /*
15 UCHAR signatureLow,
16 signatureHigh;
17 */
18 UCHAR Status;
19
20 KdPrint2((PRINT_PREFIX "UniataSataConnect:\n"));
21
22 if(!UniataIsSATARangeAvailable(deviceExtension, lChannel)) {
23 KdPrint2((PRINT_PREFIX " no I/O range\n"));
24 return IDE_STATUS_IDLE;
25 }
26
27 /* clear SATA error register, some controllers need this */
28 AtapiWritePort4(chan, IDX_SATA_SError,
29 AtapiReadPort4(chan, IDX_SATA_SError));
30 /* wait up to 1 second for "connect well" */
31 for(i=0; i<100; i++) {
32 SStatus.Reg = AtapiReadPort4(chan, IDX_SATA_SStatus);
33 if(SStatus.SPD == SStatus_SPD_Gen1 ||
34 SStatus.SPD == SStatus_SPD_Gen2) {
35 deviceExtension->lun[lChannel*2].TransferMode = ATA_SA150 + (UCHAR)(SStatus.SPD - 1);
36 break;
37 }
38 AtapiStallExecution(10000);
39 }
40 if(i >= 100) {
41 KdPrint2((PRINT_PREFIX "UniataSataConnect: SStatus %8.8x\n", SStatus.Reg));
42 return 0xff;
43 }
44 /* clear SATA error register */
45 AtapiWritePort4(chan, IDX_SATA_SError,
46 AtapiReadPort4(chan, IDX_SATA_SError));
47
48 Status = WaitOnBaseBusyLong(chan);
49 if(Status & IDE_STATUS_BUSY) {
50 return Status;
51 }
52 /*
53 signatureLow = AtapiReadPort1(chan, &deviceExtension->BaseIoAddress1[lChannel].i.CylinderLow);
54 signatureHigh = AtapiReadPort1(chan, &deviceExtension->baseIoAddress1[lChannel].i.CylinderHigh);
55
56 if (signatureLow == ATAPI_MAGIC_LSB && signatureHigh == ATAPI_MAGIC_MSB) {
57 }
58 */
59 KdPrint2((PRINT_PREFIX "UniataSataConnect: OK, ATA status %x\n", Status));
60 return IDE_STATUS_IDLE;
61 } // end UniataSataConnect()
62
63 UCHAR
64 UniataSataPhyEnable(
65 IN PVOID HwDeviceExtension,
66 IN ULONG lChannel // logical channel
67 )
68 {
69 PHW_DEVICE_EXTENSION deviceExtension = (PHW_DEVICE_EXTENSION)HwDeviceExtension;
70 PHW_CHANNEL chan = &deviceExtension->chan[lChannel];
71 SATA_SCONTROL_REG SControl;
72 int loop, retry;
73
74 KdPrint2((PRINT_PREFIX "UniataSataPhyEnable:\n"));
75
76 if(!UniataIsSATARangeAvailable(deviceExtension, lChannel)) {
77 KdPrint2((PRINT_PREFIX " no I/O range\n"));
78 return IDE_STATUS_IDLE;
79 }
80
81 SControl.Reg = AtapiReadPort4(chan, IDX_SATA_SControl);
82 KdPrint2((PRINT_PREFIX "SControl %x\n", SControl.Reg));
83 if(SControl.DET == SControl_DET_Idle) {
84 return UniataSataConnect(HwDeviceExtension, lChannel);
85 }
86
87 for (retry = 0; retry < 10; retry++) {
88 KdPrint2((PRINT_PREFIX "UniataSataPhyEnable: retry init %d\n", retry));
89 for (loop = 0; loop < 10; loop++) {
90 SControl.Reg = 0;
91 SControl.DET = SControl_DET_Init;
92 AtapiWritePort4(chan, IDX_SATA_SControl, SControl.Reg);
93 AtapiStallExecution(100);
94 SControl.Reg = AtapiReadPort4(chan, IDX_SATA_SControl);
95 KdPrint2((PRINT_PREFIX " SControl %8.8%x\n", SControl.Reg));
96 if(SControl.DET == SControl_DET_Init) {
97 break;
98 }
99 }
100 AtapiStallExecution(5000);
101 KdPrint2((PRINT_PREFIX "UniataSataPhyEnable: retry idle %d\n", retry));
102 for (loop = 0; loop < 10; loop++) {
103 SControl.Reg = 0;
104 SControl.DET = SControl_DET_DoNothing;
105 SControl.IPM = SControl_IPM_NoPartialSlumber;
106 AtapiWritePort4(chan, IDX_SATA_SControl, SControl.Reg);
107 AtapiStallExecution(100);
108 SControl.Reg = AtapiReadPort4(chan, IDX_SATA_SControl);
109 KdPrint2((PRINT_PREFIX " SControl %8.8%x\n", SControl.Reg));
110 if(SControl.DET == SControl_DET_Idle) {
111 return UniataSataConnect(HwDeviceExtension, lChannel);
112 }
113 }
114 }
115
116 KdPrint2((PRINT_PREFIX "UniataSataPhyEnable: failed\n"));
117 return 0xff;
118 } // end UniataSataPhyEnable()
119
120 BOOLEAN
121 UniataSataClearErr(
122 IN PVOID HwDeviceExtension,
123 IN ULONG lChannel, // logical channel
124 IN BOOLEAN do_connect
125 )
126 {
127 PHW_DEVICE_EXTENSION deviceExtension = (PHW_DEVICE_EXTENSION)HwDeviceExtension;
128 PHW_CHANNEL chan = &deviceExtension->chan[lChannel];
129 ULONG ChipFlags = deviceExtension->HwFlags & CHIPFLAG_MASK;
130 SATA_SSTATUS_REG SStatus;
131 SATA_SERROR_REG SError;
132
133 if(UniataIsSATARangeAvailable(deviceExtension, lChannel)) {
134 //if(ChipFlags & UNIATA_SATA) {
135
136 SStatus.Reg = AtapiReadPort4(chan, IDX_SATA_SStatus);
137 SError.Reg = AtapiReadPort4(chan, IDX_SATA_SError);
138
139 if(SStatus.Reg) {
140 KdPrint2((PRINT_PREFIX " SStatus %x\n", SStatus.Reg));
141 }
142 if(SError.Reg) {
143 KdPrint2((PRINT_PREFIX " SError %x\n", SError.Reg));
144 /* clear error bits/interrupt */
145 AtapiWritePort4(chan, IDX_SATA_SError, SError.Reg);
146
147 if(do_connect) {
148 /* if we have a connection event deal with it */
149 if(SError.DIAG.N) {
150 KdPrint2((PRINT_PREFIX " catch SATA connect/disconnect\n"));
151 if(SStatus.SPD >= SStatus_SPD_Gen1) {
152 UniataSataEvent(deviceExtension, lChannel, UNIATA_SATA_EVENT_ATTACH);
153 } else {
154 UniataSataEvent(deviceExtension, lChannel, UNIATA_SATA_EVENT_DETACH);
155 }
156 return TRUE;
157 }
158 }
159 }
160 }
161 return FALSE;
162 } // end UniataSataClearErr()
163
164 BOOLEAN
165 UniataSataEvent(
166 IN PVOID HwDeviceExtension,
167 IN ULONG lChannel, // logical channel
168 IN ULONG Action
169 )
170 {
171 PHW_DEVICE_EXTENSION deviceExtension = (PHW_DEVICE_EXTENSION)HwDeviceExtension;
172 UCHAR Status;
173 ULONG ldev = lChannel*2;
174
175 if(!UniataIsSATARangeAvailable(deviceExtension, lChannel)) {
176 return FALSE;
177 }
178
179 switch(Action) {
180 case UNIATA_SATA_EVENT_ATTACH:
181 KdPrint2((PRINT_PREFIX " CONNECTED\n"));
182 Status = UniataSataConnect(HwDeviceExtension, lChannel);
183 KdPrint2((PRINT_PREFIX " Status %x\n", Status));
184 if(Status != IDE_STATUS_IDLE) {
185 return FALSE;
186 }
187 CheckDevice(HwDeviceExtension, lChannel, 0 /*dev*/, FALSE);
188 return TRUE;
189 break;
190 case UNIATA_SATA_EVENT_DETACH:
191 KdPrint2((PRINT_PREFIX " DISCONNECTED\n"));
192 UniataForgetDevice(&(deviceExtension->lun[ldev]));
193 return TRUE;
194 break;
195 }
196 return FALSE;
197 } // end UniataSataEvent()
198
199 BOOLEAN
200 UniataAhciInit(
201 IN PVOID HwDeviceExtension
202 )
203 {
204 PHW_DEVICE_EXTENSION deviceExtension = (PHW_DEVICE_EXTENSION)HwDeviceExtension;
205 ULONG version;
206 ULONG c, i, n;
207 PHW_CHANNEL chan;
208 ULONG offs;
209 ULONG BaseMemAddress;
210 ULONG PI;
211 ULONG CAP;
212 BOOLEAN MemIo;
213 ULONGLONG base;
214
215 /* reset AHCI controller */
216 AtapiWritePortEx4(NULL, (ULONG)&deviceExtension->BaseIoAHCI_0, IDX_AHCI_GHC,
217 AtapiReadPortEx4(NULL, (ULONG)&deviceExtension->BaseIoAHCI_0, IDX_AHCI_GHC) | AHCI_GHC_HR);
218 AtapiStallExecution(1000000);
219 if(AtapiReadPortEx4(NULL, (ULONG)&deviceExtension->BaseIoAHCI_0, IDX_AHCI_GHC) & AHCI_GHC_HR) {
220 KdPrint2((PRINT_PREFIX " AHCI reset failed\n"));
221 return FALSE;
222 }
223
224 /* enable AHCI mode */
225 AtapiWritePortEx4(NULL, (ULONG)&deviceExtension->BaseIoAHCI_0, IDX_AHCI_GHC,
226 AtapiReadPortEx4(NULL, (ULONG)&deviceExtension->BaseIoAHCI_0, IDX_AHCI_GHC) | AHCI_GHC_AE);
227
228 CAP = AtapiReadPortEx4(NULL, (ULONG)&deviceExtension->BaseIoAHCI_0, IDX_AHCI_CAP);
229 PI = AtapiReadPortEx4(NULL, (ULONG)&deviceExtension->BaseIoAHCI_0, IDX_AHCI_PI);
230 /* get the number of HW channels */
231 for(i=PI, n=0; i; n++, i=i>>1);
232 deviceExtension->NumberChannels =
233 max((CAP & AHCI_CAP_NOP_MASK)+1, n);
234 if(CAP & AHCI_CAP_S64A) {
235 KdPrint2((PRINT_PREFIX " AHCI 64bit\n"));
236 deviceExtension->Host64 = TRUE;
237 }
238
239 /* clear interrupts */
240 AtapiWritePortEx4(NULL, (ULONG)&deviceExtension->BaseIoAHCI_0, IDX_AHCI_IS,
241 AtapiReadPortEx4(NULL, (ULONG)&deviceExtension->BaseIoAHCI_0, IDX_AHCI_IS));
242
243 /* enable AHCI interrupts */
244 AtapiWritePortEx4(NULL, (ULONG)&deviceExtension->BaseIoAHCI_0, IDX_AHCI_GHC,
245 AtapiReadPortEx4(NULL, (ULONG)&deviceExtension->BaseIoAHCI_0, IDX_AHCI_GHC) | AHCI_GHC_IE);
246
247 version = AtapiReadPortEx4(NULL, (ULONG)&deviceExtension->BaseIoAHCI_0, IDX_AHCI_VS);
248 KdPrint2((PRINT_PREFIX " AHCI version %x%x.%x%x controller with %d ports (mask %x) detected\n",
249 (version >> 24) & 0xff, (version >> 16) & 0xff,
250 (version >> 8) & 0xff, version & 0xff, deviceExtension->NumberChannels, PI));
251
252
253 deviceExtension->HwFlags |= UNIATA_SATA;
254 deviceExtension->HwFlags |= UNIATA_AHCI;
255
256 BaseMemAddress = deviceExtension->BaseIoAHCI_0.Addr;
257 MemIo = deviceExtension->BaseIoAHCI_0.MemIo;
258
259 for(c=0; c<deviceExtension->NumberChannels; c++) {
260 chan = &deviceExtension->chan[c];
261 offs = sizeof(IDE_AHCI_REGISTERS) + c*sizeof(IDE_AHCI_PORT_REGISTERS);
262
263 chan->RegTranslation[IDX_IO1_i_Status ].Addr = BaseMemAddress + offs + FIELD_OFFSET(IDE_AHCI_PORT_REGISTERS, TFD.STS);
264 chan->RegTranslation[IDX_IO1_i_Status ].MemIo = MemIo;
265 chan->RegTranslation[IDX_IO2_AltStatus] = chan->RegTranslation[IDX_IO1_i_Status];
266 chan->RegTranslation[IDX_IO1_i_Error ].Addr = BaseMemAddress + offs + FIELD_OFFSET(IDE_AHCI_PORT_REGISTERS, TFD.ERR);
267 chan->RegTranslation[IDX_IO1_i_Error ].MemIo = MemIo;
268 chan->RegTranslation[IDX_IO1_i_CylinderLow ].Addr = BaseMemAddress + offs + FIELD_OFFSET(IDE_AHCI_PORT_REGISTERS, SIG.LbaLow);
269 chan->RegTranslation[IDX_IO1_i_CylinderLow ].MemIo = MemIo;
270 chan->RegTranslation[IDX_IO1_i_CylinderHigh].Addr = BaseMemAddress + offs + FIELD_OFFSET(IDE_AHCI_PORT_REGISTERS, SIG.LbaHigh);
271 chan->RegTranslation[IDX_IO1_i_CylinderHigh].MemIo = MemIo;
272 chan->RegTranslation[IDX_IO1_i_BlockCount ].Addr = BaseMemAddress + offs + FIELD_OFFSET(IDE_AHCI_PORT_REGISTERS, SIG.SectorCount);
273 chan->RegTranslation[IDX_IO1_i_BlockCount ].MemIo = MemIo;
274
275 UniataInitSyncBaseIO(chan);
276
277 chan->RegTranslation[IDX_SATA_SStatus].Addr = BaseMemAddress + offs + FIELD_OFFSET(IDE_AHCI_PORT_REGISTERS, SSTS);
278 chan->RegTranslation[IDX_SATA_SStatus].MemIo = MemIo;
279 chan->RegTranslation[IDX_SATA_SError].Addr = BaseMemAddress + offs + FIELD_OFFSET(IDE_AHCI_PORT_REGISTERS, SERR);
280 chan->RegTranslation[IDX_SATA_SError].MemIo = MemIo;
281 chan->RegTranslation[IDX_SATA_SControl].Addr = BaseMemAddress + offs + FIELD_OFFSET(IDE_AHCI_PORT_REGISTERS, SCTL);
282 chan->RegTranslation[IDX_SATA_SControl].MemIo = MemIo;
283 chan->RegTranslation[IDX_SATA_SActive].Addr = BaseMemAddress + offs + FIELD_OFFSET(IDE_AHCI_PORT_REGISTERS, SACT);
284 chan->RegTranslation[IDX_SATA_SActive].MemIo = MemIo;
285
286 AtapiDmaAlloc(HwDeviceExtension, NULL, c);
287
288 base = chan->AHCI_CL_PhAddr;
289 if(!base) {
290 KdPrint2((PRINT_PREFIX " AHCI buffer allocation failed\n"));
291 return FALSE;
292 }
293 AtapiWritePortEx4(NULL, (ULONG)&deviceExtension->BaseIoAHCI_0, offs + IDX_AHCI_P_CLB,
294 (ULONG)(base & 0xffffffff));
295 AtapiWritePortEx4(NULL, (ULONG)&deviceExtension->BaseIoAHCI_0, offs + IDX_AHCI_P_CLB + 4,
296 (ULONG)((base >> 32) & 0xffffffff));
297
298 base = chan->AHCI_CL_PhAddr + ATA_AHCI_MAX_TAGS;
299 AtapiWritePortEx4(NULL, (ULONG)&deviceExtension->BaseIoAHCI_0, offs + IDX_AHCI_P_FB,
300 (ULONG)(base & 0xffffffff));
301 AtapiWritePortEx4(NULL, (ULONG)&deviceExtension->BaseIoAHCI_0, offs + IDX_AHCI_P_FB + 4,
302 (ULONG)((base >> 32) & 0xffffffff));
303
304 chan->ChannelCtrlFlags |= CTRFLAGS_NO_SLAVE;
305 }
306
307 return TRUE;
308 } // end UniataAhciInit()
309
310 UCHAR
311 UniataAhciStatus(
312 IN PVOID HwDeviceExtension,
313 IN ULONG lChannel
314 )
315 {
316 PHW_DEVICE_EXTENSION deviceExtension = (PHW_DEVICE_EXTENSION)HwDeviceExtension;
317 PHW_CHANNEL chan = &deviceExtension->chan[lChannel];
318 ULONG Channel = deviceExtension->Channel + lChannel;
319 ULONG hIS;
320 ULONG CI;
321 AHCI_IS_REG IS;
322 SATA_SSTATUS_REG SStatus;
323 SATA_SERROR_REG SError;
324 ULONG offs = sizeof(IDE_AHCI_REGISTERS) + Channel*sizeof(IDE_AHCI_PORT_REGISTERS);
325 ULONG base;
326 ULONG tag=0;
327
328 KdPrint(("UniataAhciStatus:\n"));
329
330 hIS = AtapiReadPortEx4(NULL, (ULONG)&deviceExtension->BaseIoAHCI_0, IDX_AHCI_IS);
331 KdPrint((" hIS %x\n", hIS));
332 hIS &= (1 << Channel);
333 if(!hIS) {
334 return 0;
335 }
336 base = (ULONG)&deviceExtension->BaseIoAHCI_0 + offs;
337 IS.Reg = AtapiReadPort4(chan, base + IDX_AHCI_P_IS);
338 CI = AtapiReadPort4(chan, base + IDX_AHCI_P_CI);
339 SStatus.Reg = AtapiReadPort4(chan, IDX_SATA_SStatus);
340 SError.Reg = AtapiReadPort4(chan, IDX_SATA_SError);
341
342 /* clear interrupt(s) */
343 AtapiWritePortEx4(NULL, (ULONG)&deviceExtension->BaseIoAHCI_0, IDX_AHCI_IS, hIS);
344 AtapiWritePort4(chan, base + IDX_AHCI_P_IS, IS.Reg);
345 AtapiWritePort4(chan, IDX_SATA_SError, SError.Reg);
346
347 KdPrint((" AHCI: status=%08x sstatus=%08x error=%08x CI=%08x\n",
348 IS.Reg, SStatus.Reg, SError.Reg, CI));
349
350 /* do we have cold connect surprise */
351 if(IS.CPDS) {
352 }
353
354 /* check for and handle connect events */
355 if(IS.PCS) {
356 UniataSataEvent(HwDeviceExtension, lChannel, UNIATA_SATA_EVENT_ATTACH);
357 }
358 if(IS.PRCS) {
359 UniataSataEvent(HwDeviceExtension, lChannel, UNIATA_SATA_EVENT_DETACH);
360 }
361 if(CI & (1 << tag)) {
362 return 1;
363 }
364 KdPrint((" AHCI: unexpected\n"));
365 return 2;
366
367 } // end UniataAhciStatus()
368
369 ULONG
370 UniataAhciSetupFIS(
371 IN PHW_DEVICE_EXTENSION deviceExtension,
372 IN ULONG DeviceNumber,
373 IN ULONG lChannel,
374 OUT PUCHAR fis,
375 IN UCHAR command,
376 IN ULONGLONG lba,
377 IN USHORT count,
378 IN USHORT feature,
379 IN ULONG flags
380 )
381 {
382 ULONG ldev = lChannel*2 + DeviceNumber;
383 ULONG i;
384 PUCHAR plba;
385
386 KdPrint2((PRINT_PREFIX " AHCI setup FIS\n" ));
387 i = 0;
388 plba = (PUCHAR)&lba;
389
390 if((AtaCommandFlags[command] & ATA_CMD_FLAG_LBAIOsupp) &&
391 CheckIfBadBlock(&(deviceExtension->lun[ldev]), lba, count)) {
392 KdPrint3((PRINT_PREFIX ": artificial bad block, lba %#I64x count %#x\n", lba, count));
393 return IDE_STATUS_ERROR;
394 //return SRB_STATUS_ERROR;
395 }
396
397 /* translate command into 48bit version */
398 if ((lba >= ATA_MAX_LBA28 || count > 256) &&
399 deviceExtension->lun[ldev].IdentifyData.FeaturesSupport.Address48) {
400 if(AtaCommandFlags[command] & ATA_CMD_FLAG_48supp) {
401 command = AtaCommands48[command];
402 } else {
403 KdPrint2((PRINT_PREFIX " unhandled LBA48 command\n"));
404 return 0;
405 }
406 }
407
408 fis[0] = 0x27; /* host to device */
409 fis[1] = 0x80; /* command FIS (note PM goes here) */
410 fis[2] = command;
411 fis[3] = (UCHAR)feature;
412
413 fis[4] = plba[0];
414 fis[5] = plba[1];
415 fis[6] = plba[2];
416 fis[7] = IDE_USE_LBA | (DeviceNumber ? IDE_DRIVE_2 : IDE_DRIVE_1);
417 if ((lba >= ATA_MAX_LBA28 || count > 256) &&
418 deviceExtension->lun[ldev].IdentifyData.FeaturesSupport.Address48) {
419 i++;
420 } else {
421 fis[7] |= (plba[3] >> 24) & 0x0f;
422 }
423
424 fis[8] = plba[3];
425 fis[9] = plba[4];
426 fis[10] = plba[5];
427 fis[11] = (UCHAR)(feature>>8) & 0xff;
428
429 fis[12] = (UCHAR)count & 0xff;
430 fis[13] = (UCHAR)(count>>8) & 0xff;
431 fis[14] = 0x00;
432 fis[15] = IDE_DC_A_4BIT;
433
434 fis[16] = 0x00;
435 fis[17] = 0x00;
436 fis[18] = 0x00;
437 fis[19] = 0x00;
438 return 20;
439 } // end UniataAhciSetupFIS()
440