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