Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenid_sata.cpp
Go to the documentation of this file.
00001 /*++ 00002 00003 Copyright (c) 2008-2011 Alexandr A. Telyatnikov (Alter) 00004 00005 Module Name: 00006 id_probe.cpp 00007 00008 Abstract: 00009 This module handles SATA-related staff 00010 00011 Author: 00012 Alexander A. Telyatnikov (Alter) 00013 00014 Environment: 00015 kernel mode only 00016 00017 Notes: 00018 00019 THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 00020 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 00021 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 00022 IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 00023 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 00024 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 00025 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 00026 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 00027 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 00028 THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 00029 00030 Revision History: 00031 00032 --*/ 00033 00034 #include "stdafx.h" 00035 00036 UCHAR 00037 NTAPI 00038 UniataSataConnect( 00039 IN PVOID HwDeviceExtension, 00040 IN ULONG lChannel, // logical channel 00041 IN ULONG pm_port /* for port multipliers */ 00042 ) 00043 { 00044 PHW_DEVICE_EXTENSION deviceExtension = (PHW_DEVICE_EXTENSION)HwDeviceExtension; 00045 //ULONG Channel = deviceExtension->Channel + lChannel; 00046 PHW_CHANNEL chan = &deviceExtension->chan[lChannel]; 00047 SATA_SSTATUS_REG SStatus; 00048 ULONG i; 00049 /* 00050 UCHAR signatureLow, 00051 signatureHigh; 00052 */ 00053 UCHAR Status; 00054 00055 KdPrint2((PRINT_PREFIX "UniataSataConnect:\n")); 00056 00057 if(!UniataIsSATARangeAvailable(deviceExtension, lChannel)) { 00058 KdPrint2((PRINT_PREFIX " no I/O range\n")); 00059 return IDE_STATUS_IDLE; 00060 } 00061 00062 /* clear SATA error register, some controllers need this */ 00063 UniataSataWritePort4(chan, IDX_SATA_SError, 00064 UniataSataReadPort4(chan, IDX_SATA_SError, pm_port), pm_port); 00065 /* wait up to 1 second for "connect well" */ 00066 for(i=0; i<100; i++) { 00067 SStatus.Reg = UniataSataReadPort4(chan, IDX_SATA_SStatus, pm_port); 00068 if(SStatus.SPD == SStatus_SPD_Gen1 || 00069 SStatus.SPD == SStatus_SPD_Gen2 || 00070 SStatus.SPD == SStatus_SPD_Gen3) { 00071 chan->lun[0]->TransferMode = ATA_SA150 + (UCHAR)(SStatus.SPD - 1); 00072 KdPrint2((PRINT_PREFIX "SATA TransferMode %#x\n", chan->lun[0]->TransferMode)); 00073 break; 00074 } 00075 AtapiStallExecution(10000); 00076 } 00077 if(i >= 100) { 00078 KdPrint2((PRINT_PREFIX "UniataSataConnect: SStatus %8.8x\n", SStatus.Reg)); 00079 return 0xff; 00080 } 00081 /* clear SATA error register */ 00082 UniataSataWritePort4(chan, IDX_SATA_SError, 00083 UniataSataReadPort4(chan, IDX_SATA_SError, pm_port), pm_port); 00084 00085 Status = WaitOnBaseBusyLong(chan); 00086 if(Status & IDE_STATUS_BUSY) { 00087 return Status; 00088 } 00089 /* 00090 signatureLow = AtapiReadPort1(chan, &deviceExtension->BaseIoAddress1[lChannel].i.CylinderLow); 00091 signatureHigh = AtapiReadPort1(chan, &deviceExtension->baseIoAddress1[lChannel].i.CylinderHigh); 00092 00093 if (signatureLow == ATAPI_MAGIC_LSB && signatureHigh == ATAPI_MAGIC_MSB) { 00094 } 00095 */ 00096 KdPrint2((PRINT_PREFIX "UniataSataConnect: OK, ATA status %#x\n", Status)); 00097 return IDE_STATUS_IDLE; 00098 } // end UniataSataConnect() 00099 00100 UCHAR 00101 NTAPI 00102 UniataSataPhyEnable( 00103 IN PVOID HwDeviceExtension, 00104 IN ULONG lChannel, // logical channel 00105 IN ULONG pm_port, /* for port multipliers */ 00106 IN BOOLEAN doReset 00107 ) 00108 { 00109 PHW_DEVICE_EXTENSION deviceExtension = (PHW_DEVICE_EXTENSION)HwDeviceExtension; 00110 PHW_CHANNEL chan = &deviceExtension->chan[lChannel]; 00111 SATA_SCONTROL_REG SControl; 00112 int loop, retry; 00113 00114 KdPrint2((PRINT_PREFIX "UniataSataPhyEnable:\n")); 00115 00116 if(!UniataIsSATARangeAvailable(deviceExtension, lChannel)) { 00117 KdPrint2((PRINT_PREFIX " no I/O range\n")); 00118 return IDE_STATUS_IDLE; 00119 } 00120 00121 SControl.Reg = UniataSataReadPort4(chan, IDX_SATA_SControl, pm_port); 00122 KdPrint2((PRINT_PREFIX "SControl %#x\n", SControl.Reg)); 00123 if(SControl.DET == SControl_DET_Idle) { 00124 if(!doReset) { 00125 return UniataSataConnect(HwDeviceExtension, lChannel, pm_port); 00126 } 00127 } 00128 00129 for (retry = 0; retry < 10; retry++) { 00130 KdPrint2((PRINT_PREFIX "UniataSataPhyEnable: retry init %d\n", retry)); 00131 for (loop = 0; loop < 10; loop++) { 00132 SControl.Reg = 0; 00133 SControl.DET = SControl_DET_Init; 00134 UniataSataWritePort4(chan, IDX_SATA_SControl, SControl.Reg, pm_port); 00135 AtapiStallExecution(100); 00136 SControl.Reg = UniataSataReadPort4(chan, IDX_SATA_SControl, pm_port); 00137 KdPrint2((PRINT_PREFIX " SControl %8.8x\n", SControl.Reg)); 00138 if(SControl.DET == SControl_DET_Init) { 00139 break; 00140 } 00141 } 00142 AtapiStallExecution(5000); 00143 KdPrint2((PRINT_PREFIX "UniataSataPhyEnable: retry idle %d\n", retry)); 00144 for (loop = 0; loop < 10; loop++) { 00145 SControl.Reg = 0; 00146 SControl.DET = SControl_DET_DoNothing; 00147 SControl.IPM = SControl_IPM_NoPartialSlumber; 00148 UniataSataWritePort4(chan, IDX_SATA_SControl, SControl.Reg, pm_port); 00149 AtapiStallExecution(100); 00150 SControl.Reg = UniataSataReadPort4(chan, IDX_SATA_SControl, pm_port); 00151 KdPrint2((PRINT_PREFIX " SControl %8.8x\n", SControl.Reg)); 00152 if(SControl.DET == SControl_DET_Idle) { 00153 return UniataSataConnect(HwDeviceExtension, lChannel, pm_port); 00154 } 00155 } 00156 } 00157 00158 KdPrint2((PRINT_PREFIX "UniataSataPhyEnable: failed\n")); 00159 return 0xff; 00160 } // end UniataSataPhyEnable() 00161 00162 BOOLEAN 00163 NTAPI 00164 UniataSataClearErr( 00165 IN PVOID HwDeviceExtension, 00166 IN ULONG lChannel, // logical channel 00167 IN BOOLEAN do_connect, 00168 IN ULONG pm_port /* for port multipliers */ 00169 ) 00170 { 00171 PHW_DEVICE_EXTENSION deviceExtension = (PHW_DEVICE_EXTENSION)HwDeviceExtension; 00172 PHW_CHANNEL chan = &deviceExtension->chan[lChannel]; 00173 //ULONG ChipFlags = deviceExtension->HwFlags & CHIPFLAG_MASK; 00174 SATA_SSTATUS_REG SStatus; 00175 SATA_SERROR_REG SError; 00176 00177 if(UniataIsSATARangeAvailable(deviceExtension, lChannel)) { 00178 //if(ChipFlags & UNIATA_SATA) { 00179 00180 SStatus.Reg = UniataSataReadPort4(chan, IDX_SATA_SStatus, pm_port); 00181 SError.Reg = UniataSataReadPort4(chan, IDX_SATA_SError, pm_port); 00182 00183 if(SStatus.Reg) { 00184 KdPrint2((PRINT_PREFIX " SStatus %#x\n", SStatus.Reg)); 00185 } 00186 if(SError.Reg) { 00187 KdPrint2((PRINT_PREFIX " SError %#x\n", SError.Reg)); 00188 /* clear error bits/interrupt */ 00189 UniataSataWritePort4(chan, IDX_SATA_SError, SError.Reg, pm_port); 00190 00191 if(do_connect) { 00192 /* if we have a connection event deal with it */ 00193 if(SError.DIAG.N) { 00194 KdPrint2((PRINT_PREFIX " catch SATA connect/disconnect\n")); 00195 if(SStatus.SPD >= SStatus_SPD_Gen1) { 00196 UniataSataEvent(deviceExtension, lChannel, UNIATA_SATA_EVENT_ATTACH, pm_port); 00197 } else { 00198 UniataSataEvent(deviceExtension, lChannel, UNIATA_SATA_EVENT_DETACH, pm_port); 00199 } 00200 return TRUE; 00201 } 00202 } 00203 } 00204 } 00205 return FALSE; 00206 } // end UniataSataClearErr() 00207 00208 BOOLEAN 00209 NTAPI 00210 UniataSataEvent( 00211 IN PVOID HwDeviceExtension, 00212 IN ULONG lChannel, // logical channel 00213 IN ULONG Action, 00214 IN ULONG pm_port /* for port multipliers */ 00215 ) 00216 { 00217 PHW_DEVICE_EXTENSION deviceExtension = (PHW_DEVICE_EXTENSION)HwDeviceExtension; 00218 UCHAR Status; 00219 ULONG DeviceNumber = (pm_port ? 1 : 0); 00220 00221 if(!UniataIsSATARangeAvailable(deviceExtension, lChannel)) { 00222 return FALSE; 00223 } 00224 00225 switch(Action) { 00226 case UNIATA_SATA_EVENT_ATTACH: 00227 KdPrint2((PRINT_PREFIX " CONNECTED\n")); 00228 Status = UniataSataConnect(HwDeviceExtension, lChannel, pm_port); 00229 KdPrint2((PRINT_PREFIX " Status %#x\n", Status)); 00230 if(Status != IDE_STATUS_IDLE) { 00231 return FALSE; 00232 } 00233 CheckDevice(HwDeviceExtension, lChannel, DeviceNumber /*dev*/, FALSE); 00234 return TRUE; 00235 break; 00236 case UNIATA_SATA_EVENT_DETACH: 00237 KdPrint2((PRINT_PREFIX " DISCONNECTED\n")); 00238 UniataForgetDevice(deviceExtension->chan[lChannel].lun[DeviceNumber]); 00239 return TRUE; 00240 break; 00241 } 00242 return FALSE; 00243 } // end UniataSataEvent() 00244 00245 ULONG 00246 NTAPI 00247 UniataSataReadPort4( 00248 IN PHW_CHANNEL chan, 00249 IN ULONG io_port_ndx, 00250 IN ULONG pm_port /* for port multipliers */ 00251 ) 00252 { 00253 if(chan && (io_port_ndx < IDX_MAX_REG) && 00254 chan->RegTranslation[io_port_ndx].Proc) { 00255 00256 KdPrint3((PRINT_PREFIX " UniataSataReadPort4 %#x[%d]\n", io_port_ndx, pm_port)); 00257 00258 PHW_DEVICE_EXTENSION deviceExtension = chan->DeviceExtension; 00259 PVOID HwDeviceExtension = (PVOID)deviceExtension; 00260 ULONG slotNumber = deviceExtension->slotNumber; 00261 ULONG SystemIoBusNumber = deviceExtension->SystemIoBusNumber; 00262 ULONG VendorID = deviceExtension->DevID & 0xffff; 00263 ULONG offs; 00264 ULONG p; 00265 00266 switch(VendorID) { 00267 case ATA_INTEL_ID: { 00268 p = pm_port ? 1 : 0; 00269 if(deviceExtension->HwFlags & ICH5) { 00270 offs = 0x50+chan->lun[p]->SATA_lun_map*0x10; 00271 KdPrint3((PRINT_PREFIX " ICH5 way, offs %#x\n", offs)); 00272 switch(io_port_ndx) { 00273 case IDX_SATA_SStatus: 00274 offs += 0; 00275 break; 00276 case IDX_SATA_SError: 00277 offs += 1*4; 00278 break; 00279 case IDX_SATA_SControl: 00280 offs += 2*4; 00281 break; 00282 default: 00283 return -1; 00284 } 00285 SetPciConfig4(0xa0, offs); 00286 GetPciConfig4(0xa4, offs); 00287 return offs; 00288 } else { 00289 offs = ((deviceExtension->Channel+chan->lChannel)*2+p) * 0x100; 00290 KdPrint3((PRINT_PREFIX " def way, offs %#x\n", offs)); 00291 switch(io_port_ndx) { 00292 case IDX_SATA_SStatus: 00293 offs += 0; 00294 break; 00295 case IDX_SATA_SControl: 00296 offs += 1; 00297 break; 00298 case IDX_SATA_SError: 00299 offs += 2; 00300 break; 00301 default: 00302 return -1; 00303 } 00304 AtapiWritePort4(chan, IDX_INDEXED_ADDR, offs); 00305 return AtapiReadPort4(chan, IDX_INDEXED_DATA); 00306 } 00307 } // ATA_INTEL_ID 00308 } // end switch(VendorID) 00309 return -1; 00310 } 00311 return AtapiReadPort4(chan, io_port_ndx); 00312 } // end UniataSataReadPort4() 00313 00314 VOID 00315 NTAPI 00316 UniataSataWritePort4( 00317 IN PHW_CHANNEL chan, 00318 IN ULONG io_port_ndx, 00319 IN ULONG data, 00320 IN ULONG pm_port /* for port multipliers */ 00321 ) 00322 { 00323 if(chan && (io_port_ndx < IDX_MAX_REG) && 00324 chan->RegTranslation[io_port_ndx].Proc) { 00325 00326 KdPrint3((PRINT_PREFIX " UniataSataWritePort4 %#x[%d]\n", io_port_ndx, pm_port)); 00327 00328 PHW_DEVICE_EXTENSION deviceExtension = chan->DeviceExtension; 00329 PVOID HwDeviceExtension = (PVOID)deviceExtension; 00330 ULONG slotNumber = deviceExtension->slotNumber; 00331 ULONG SystemIoBusNumber = deviceExtension->SystemIoBusNumber; 00332 ULONG VendorID = deviceExtension->DevID & 0xffff; 00333 ULONG offs; 00334 ULONG p; 00335 00336 switch(VendorID) { 00337 case ATA_INTEL_ID: { 00338 p = pm_port ? 1 : 0; 00339 if(deviceExtension->HwFlags & ICH5) { 00340 offs = 0x50+chan->lun[p]->SATA_lun_map*0x10; 00341 KdPrint3((PRINT_PREFIX " ICH5 way, offs %#x\n", offs)); 00342 switch(io_port_ndx) { 00343 case IDX_SATA_SStatus: 00344 offs += 0; 00345 break; 00346 case IDX_SATA_SError: 00347 offs += 1*4; 00348 break; 00349 case IDX_SATA_SControl: 00350 offs += 2*4; 00351 break; 00352 default: 00353 return; 00354 } 00355 SetPciConfig4(0xa0, offs); 00356 SetPciConfig4(0xa4, data); 00357 return; 00358 } else { 00359 offs = ((deviceExtension->Channel+chan->lChannel)*2+p) * 0x100; 00360 KdPrint3((PRINT_PREFIX " def way, offs %#x\n", offs)); 00361 switch(io_port_ndx) { 00362 case IDX_SATA_SStatus: 00363 offs += 0; 00364 break; 00365 case IDX_SATA_SControl: 00366 offs += 1; 00367 break; 00368 case IDX_SATA_SError: 00369 offs += 2; 00370 break; 00371 default: 00372 return; 00373 } 00374 AtapiWritePort4(chan, IDX_INDEXED_ADDR, offs); 00375 AtapiWritePort4(chan, IDX_INDEXED_DATA, data); 00376 } 00377 } // ATA_INTEL_ID 00378 } // end switch(VendorID) 00379 return; 00380 } 00381 AtapiWritePort4(chan, io_port_ndx, data); 00382 } // end UniataSataWritePort4() 00383 00384 BOOLEAN 00385 NTAPI 00386 UniataSataReadPM( 00387 IN PHW_CHANNEL chan, 00388 IN ULONG DeviceNumber, 00389 IN ULONG Reg, 00390 OUT PULONG result 00391 ) 00392 { 00393 if(chan->DeviceExtension->HwFlags & UNIATA_AHCI) { 00394 return UniataAhciReadPM(chan, DeviceNumber, Reg, result); 00395 } 00396 return FALSE; 00397 } // end UniataSataReadPM() 00398 00399 UCHAR 00400 NTAPI 00401 UniataSataWritePM( 00402 IN PHW_CHANNEL chan, 00403 IN ULONG DeviceNumber, 00404 IN ULONG Reg, 00405 IN ULONG value 00406 ) 00407 { 00408 if(chan->DeviceExtension->HwFlags & UNIATA_AHCI) { 00409 return UniataAhciWritePM(chan, DeviceNumber, Reg, value); 00410 } 00411 return 0xff; 00412 } // end UniataSataWritePM() 00413 00414 ULONG 00415 NTAPI 00416 UniataSataSoftReset( 00417 IN PVOID HwDeviceExtension, 00418 IN ULONG lChannel, 00419 IN ULONG DeviceNumber 00420 ) 00421 { 00422 PHW_DEVICE_EXTENSION deviceExtension = (PHW_DEVICE_EXTENSION)HwDeviceExtension; 00423 00424 if(deviceExtension->HwFlags & UNIATA_AHCI) { 00425 return UniataAhciSoftReset(HwDeviceExtension, lChannel, DeviceNumber); 00426 } 00427 return 0xffffffff; 00428 } // end UniataSataSoftReset() 00429 00430 VOID 00431 UniataSataIdentifyPM( 00432 IN PHW_CHANNEL chan 00433 ) 00434 { 00435 ULONG PM_DeviceId; 00436 ULONG PM_RevId; 00437 ULONG PM_Ports; 00438 UCHAR i; 00439 ULONG signature; 00440 PHW_LU_EXTENSION LunExt; 00441 00442 KdPrint((PRINT_PREFIX "UniataSataIdentifyPM:\n")); 00443 00444 chan->PmLunMap = 0; 00445 00446 /* get PM vendor & product data */ 00447 if(!UniataSataReadPM(chan, AHCI_DEV_SEL_PM, 0, &PM_DeviceId)) { 00448 KdPrint2((PRINT_PREFIX " error getting PM vendor data\n")); 00449 return; 00450 } 00451 /* get PM revision data */ 00452 if(!UniataSataReadPM(chan, AHCI_DEV_SEL_PM, 1, &PM_RevId)) { 00453 KdPrint2((PRINT_PREFIX " error getting PM revison data\n")); 00454 return; 00455 } 00456 /* get number of HW ports on the PM */ 00457 if(!UniataSataReadPM(chan, AHCI_DEV_SEL_PM, 2, &PM_Ports)) { 00458 KdPrint2((PRINT_PREFIX " error getting PM port info\n")); 00459 return; 00460 } 00461 00462 PM_Ports &= 0x0000000f; 00463 00464 switch(PM_DeviceId) { 00465 case 0x37261095: 00466 /* This PM declares 6 ports, while only 5 of them are real. 00467 * Port 5 is enclosure management bridge port, which has implementation 00468 * problems, causing probe faults. Hide it for now. */ 00469 KdPrint2((PRINT_PREFIX " SiI 3726 (rev=%#x) Port Multiplier with %d (5) ports\n", 00470 PM_RevId, PM_Ports)); 00471 PM_Ports = 5; 00472 break; 00473 case 0x47261095: 00474 /* This PM declares 7 ports, while only 5 of them are real. 00475 * Port 5 is some fake "Config Disk" with 640 sectors size, 00476 * port 6 is enclosure management bridge port. 00477 * Both fake ports has implementation problems, causing 00478 * probe faults. Hide them for now. */ 00479 KdPrint2((PRINT_PREFIX " SiI 4726 (rev=%#x) Port Multiplier with %d (5) ports\n", 00480 PM_RevId, PM_Ports)); 00481 PM_Ports = 5; 00482 break; 00483 default: 00484 KdPrint2((PRINT_PREFIX " Port Multiplier (id=%08x rev=%#x) with %d ports\n", 00485 PM_DeviceId, PM_RevId, PM_Ports)); 00486 break; 00487 } 00488 00489 // reset 00490 for(i=0; i<PM_Ports; i++) { 00491 00492 LunExt = chan->lun[i]; 00493 00494 KdPrint2((PRINT_PREFIX " Port %d\n", i)); 00495 if(UniataSataPhyEnable(chan->DeviceExtension, chan->lChannel, i, UNIATA_SATA_RESET_ENABLE) != IDE_STATUS_IDLE) { 00496 LunExt->DeviceFlags &= ~DFLAGS_DEVICE_PRESENT; 00497 continue; 00498 } 00499 /* 00500 * XXX: I have no idea how to properly wait for PMP port hardreset 00501 * completion. Without this delay soft reset does not completes 00502 * successfully. 00503 */ 00504 AtapiStallExecution(1000000); 00505 00506 signature = UniataSataSoftReset(chan->DeviceExtension, chan->lChannel, i); 00507 KdPrint2((PRINT_PREFIX " signature %#x\n", signature)); 00508 00509 LunExt->DeviceFlags |= DFLAGS_DEVICE_PRESENT; 00510 chan->PmLunMap |= (1 << i); 00511 /* figure out whats there */ 00512 switch (signature >> 16) { 00513 case 0x0000: 00514 LunExt->DeviceFlags &= ~DFLAGS_ATAPI_DEVICE; 00515 continue; 00516 case 0xeb14: 00517 LunExt->DeviceFlags |= DFLAGS_ATAPI_DEVICE; 00518 continue; 00519 } 00520 00521 } 00522 00523 } // end UniataSataIdentifyPM() 00524 00525 #ifdef DBG 00526 VOID 00527 NTAPI 00528 UniataDumpAhciRegs( 00529 IN PHW_DEVICE_EXTENSION deviceExtension 00530 ) 00531 { 00532 ULONG j; 00533 ULONG xReg; 00534 00535 KdPrint2((PRINT_PREFIX 00536 " AHCI Base: %#x MemIo %d Proc %d\n", 00537 deviceExtension->BaseIoAHCI_0.Addr, 00538 deviceExtension->BaseIoAHCI_0.MemIo, 00539 deviceExtension->BaseIoAHCI_0.Proc)); 00540 00541 for(j=0; j<=IDX_AHCI_VS; j+=sizeof(ULONG)) { 00542 xReg = AtapiReadPortEx4(NULL, (ULONGIO_PTR)&deviceExtension->BaseIoAHCI_0, j); 00543 KdPrint2((PRINT_PREFIX 00544 " AHCI_%#x (%#x) = %#x\n", 00545 j, 00546 (deviceExtension->BaseIoAHCI_0.Addr+j), 00547 xReg)); 00548 } 00549 return; 00550 } // end UniataDumpAhciRegs() 00551 00552 00553 VOID 00554 NTAPI 00555 UniataDumpAhciPortRegs( 00556 IN PHW_CHANNEL chan 00557 ) 00558 { 00559 ULONG j; 00560 ULONG xReg; 00561 00562 KdPrint2((PRINT_PREFIX 00563 " AHCI port %d Base: %#x MemIo %d Proc %d\n", 00564 chan->lChannel, 00565 chan->BaseIoAHCI_Port.Addr, 00566 chan->BaseIoAHCI_Port.MemIo, 00567 chan->BaseIoAHCI_Port.Proc)); 00568 00569 for(j=0; j<=IDX_AHCI_P_SNTF; j+=sizeof(ULONG)) { 00570 xReg = AtapiReadPortEx4(NULL, (ULONGIO_PTR)&chan->BaseIoAHCI_Port, j); 00571 KdPrint2((PRINT_PREFIX 00572 " AHCI%d_%#x (%#x) = %#x\n", 00573 chan->lChannel, 00574 j, 00575 (chan->BaseIoAHCI_Port.Addr+j), 00576 xReg)); 00577 } 00578 return; 00579 } // end UniataDumpAhciPortRegs() 00580 #endif //DBG 00581 00582 00583 BOOLEAN 00584 NTAPI 00585 UniataAhciInit( 00586 IN PVOID HwDeviceExtension 00587 ) 00588 { 00589 PHW_DEVICE_EXTENSION deviceExtension = (PHW_DEVICE_EXTENSION)HwDeviceExtension; 00590 ULONG c, i; 00591 PHW_CHANNEL chan; 00592 ULONG offs; 00593 ULONG BaseMemAddress; 00594 ULONG PI; 00595 ULONG CAP; 00596 ULONG GHC; 00597 BOOLEAN MemIo = FALSE; 00598 00599 KdPrint2((PRINT_PREFIX " UniataAhciInit:\n")); 00600 00601 #ifdef DBG 00602 UniataDumpAhciRegs(deviceExtension); 00603 #endif //DBG 00604 00605 /* reset AHCI controller */ 00606 GHC = UniataAhciReadHostPort4(deviceExtension, IDX_AHCI_GHC); 00607 KdPrint2((PRINT_PREFIX " reset AHCI controller, GHC %#x\n", GHC)); 00608 UniataAhciWriteHostPort4(deviceExtension, IDX_AHCI_GHC, 00609 GHC | AHCI_GHC_HR); 00610 00611 for(i=0; i<1000; i++) { 00612 AtapiStallExecution(1000); 00613 GHC = UniataAhciReadHostPort4(deviceExtension, IDX_AHCI_GHC); 00614 KdPrint2((PRINT_PREFIX " AHCI GHC %#x\n", GHC)); 00615 if(!(GHC & AHCI_GHC_HR)) { 00616 break; 00617 } 00618 } 00619 if(GHC & AHCI_GHC_HR) { 00620 KdPrint2((PRINT_PREFIX " AHCI reset failed\n")); 00621 return FALSE; 00622 } 00623 00624 /* enable AHCI mode */ 00625 GHC = UniataAhciReadHostPort4(deviceExtension, IDX_AHCI_GHC); 00626 KdPrint2((PRINT_PREFIX " enable AHCI mode, GHC %#x\n", GHC)); 00627 UniataAhciWriteHostPort4(deviceExtension, IDX_AHCI_GHC, 00628 GHC | AHCI_GHC_AE); 00629 GHC = UniataAhciReadHostPort4(deviceExtension, IDX_AHCI_GHC); 00630 KdPrint2((PRINT_PREFIX " AHCI GHC %#x\n", GHC)); 00631 00632 deviceExtension->AHCI_CAP = 00633 CAP = UniataAhciReadHostPort4(deviceExtension, IDX_AHCI_CAP); 00634 PI = UniataAhciReadHostPort4(deviceExtension, IDX_AHCI_PI); 00635 KdPrint2((PRINT_PREFIX " AHCI CAP %#x\n", CAP)); 00636 if(CAP & AHCI_CAP_S64A) { 00637 KdPrint2((PRINT_PREFIX " AHCI 64bit\n")); 00638 deviceExtension->Host64 = TRUE; 00639 } 00640 KdPrint2((PRINT_PREFIX " AHCI %d CMD slots\n", (CAP & AHCI_CAP_NCS_MASK) >> 8 )); 00641 if(CAP & AHCI_CAP_PMD) { 00642 KdPrint2((PRINT_PREFIX " AHCI multi-block PIO\n")); 00643 } 00644 if(CAP & AHCI_CAP_SAM) { 00645 KdPrint2((PRINT_PREFIX " AHCI legasy SATA\n")); 00646 } 00647 /* get the number of HW channels */ 00648 PI = UniataAhciReadHostPort4(deviceExtension, IDX_AHCI_PI); 00649 KdPrint2((PRINT_PREFIX " AHCI PI %#x\n", PI)); 00650 00651 /* clear interrupts */ 00652 UniataAhciWriteHostPort4(deviceExtension, IDX_AHCI_IS, 00653 UniataAhciReadHostPort4(deviceExtension, IDX_AHCI_IS)); 00654 00655 /* enable AHCI interrupts */ 00656 UniataAhciWriteHostPort4(deviceExtension, IDX_AHCI_GHC, 00657 UniataAhciReadHostPort4(deviceExtension, IDX_AHCI_GHC) | AHCI_GHC_IE); 00658 00659 BaseMemAddress = deviceExtension->BaseIoAHCI_0.Addr; 00660 MemIo = deviceExtension->BaseIoAHCI_0.MemIo; 00661 00662 for(c=0; c<deviceExtension->NumberChannels; c++) { 00663 chan = &deviceExtension->chan[c]; 00664 offs = sizeof(IDE_AHCI_REGISTERS) + c*sizeof(IDE_AHCI_PORT_REGISTERS); 00665 00666 KdPrint2((PRINT_PREFIX " chan %d, offs %#x\n", c, offs)); 00667 00668 AtapiSetupLunPtrs(chan, deviceExtension, c); 00669 00670 chan->BaseIoAHCI_Port = deviceExtension->BaseIoAHCI_0; 00671 chan->BaseIoAHCI_Port.Addr = BaseMemAddress + offs; 00672 00673 chan->RegTranslation[IDX_IO1_i_Status ].Addr = BaseMemAddress + offs + FIELD_OFFSET(IDE_AHCI_PORT_REGISTERS, TFD.STS); 00674 chan->RegTranslation[IDX_IO1_i_Status ].MemIo = MemIo; 00675 chan->RegTranslation[IDX_IO2_AltStatus] = chan->RegTranslation[IDX_IO1_i_Status]; 00676 chan->RegTranslation[IDX_IO1_i_Error ].Addr = BaseMemAddress + offs + FIELD_OFFSET(IDE_AHCI_PORT_REGISTERS, TFD.ERR); 00677 chan->RegTranslation[IDX_IO1_i_Error ].MemIo = MemIo; 00678 chan->RegTranslation[IDX_IO1_i_CylinderLow ].Addr = BaseMemAddress + offs + FIELD_OFFSET(IDE_AHCI_PORT_REGISTERS, SIG.LbaLow); 00679 chan->RegTranslation[IDX_IO1_i_CylinderLow ].MemIo = MemIo; 00680 chan->RegTranslation[IDX_IO1_i_CylinderHigh].Addr = BaseMemAddress + offs + FIELD_OFFSET(IDE_AHCI_PORT_REGISTERS, SIG.LbaHigh); 00681 chan->RegTranslation[IDX_IO1_i_CylinderHigh].MemIo = MemIo; 00682 chan->RegTranslation[IDX_IO1_i_BlockCount ].Addr = BaseMemAddress + offs + FIELD_OFFSET(IDE_AHCI_PORT_REGISTERS, SIG.SectorCount); 00683 chan->RegTranslation[IDX_IO1_i_BlockCount ].MemIo = MemIo; 00684 00685 UniataInitSyncBaseIO(chan); 00686 00687 chan->RegTranslation[IDX_SATA_SStatus].Addr = BaseMemAddress + offs + FIELD_OFFSET(IDE_AHCI_PORT_REGISTERS, SSTS); 00688 chan->RegTranslation[IDX_SATA_SStatus].MemIo = MemIo; 00689 chan->RegTranslation[IDX_SATA_SError].Addr = BaseMemAddress + offs + FIELD_OFFSET(IDE_AHCI_PORT_REGISTERS, SERR); 00690 chan->RegTranslation[IDX_SATA_SError].MemIo = MemIo; 00691 chan->RegTranslation[IDX_SATA_SControl].Addr = BaseMemAddress + offs + FIELD_OFFSET(IDE_AHCI_PORT_REGISTERS, SCTL); 00692 chan->RegTranslation[IDX_SATA_SControl].MemIo = MemIo; 00693 chan->RegTranslation[IDX_SATA_SActive].Addr = BaseMemAddress + offs + FIELD_OFFSET(IDE_AHCI_PORT_REGISTERS, SACT); 00694 chan->RegTranslation[IDX_SATA_SActive].MemIo = MemIo; 00695 00696 AtapiDmaAlloc(HwDeviceExtension, NULL, c); 00697 00698 UniataAhciResume(chan); 00699 00700 chan->ChannelCtrlFlags |= CTRFLAGS_NO_SLAVE; 00701 } 00702 00703 return TRUE; 00704 } // end UniataAhciInit() 00705 00706 BOOLEAN 00707 NTAPI 00708 UniataAhciDetect( 00709 IN PVOID HwDeviceExtension, 00710 IN PPCI_COMMON_CONFIG pciData, // optional 00711 IN OUT PPORT_CONFIGURATION_INFORMATION ConfigInfo 00712 ) 00713 { 00714 PHW_DEVICE_EXTENSION deviceExtension = (PHW_DEVICE_EXTENSION)HwDeviceExtension; 00715 //ULONG slotNumber = deviceExtension->slotNumber; 00716 ULONG SystemIoBusNumber = deviceExtension->SystemIoBusNumber; 00717 ULONG version; 00718 ULONG i, n; 00719 ULONG PI; 00720 ULONG CAP; 00721 ULONG GHC; 00722 ULONG NumberChannels; 00723 ULONG v_Mn, v_Mj; 00724 ULONG BaseMemAddress; 00725 BOOLEAN MemIo; 00726 00727 KdPrint2((PRINT_PREFIX " UniataAhciDetect:\n")); 00728 00729 if(AtapiRegCheckDevValue(deviceExtension, CHAN_NOT_SPECIFIED, DEVNUM_NOT_SPECIFIED, L"IgnoreAhci", 1 /* DEBUG */)) { 00730 KdPrint((" AHCI excluded\n")); 00731 return FALSE; 00732 } 00733 BaseMemAddress = AtapiGetIoRange(HwDeviceExtension, ConfigInfo, pciData, SystemIoBusNumber, 00734 5, 0, 0x10); 00735 if(!BaseMemAddress) { 00736 KdPrint2((PRINT_PREFIX " AHCI init failed - no IoRange\n")); 00737 return FALSE; 00738 } 00739 if(BaseMemAddress && (*ConfigInfo->AccessRanges)[5].RangeInMemory) { 00740 KdPrint2((PRINT_PREFIX "MemIo\n")); 00741 MemIo = TRUE; 00742 } 00743 deviceExtension->BaseIoAHCI_0.Addr = BaseMemAddress; 00744 deviceExtension->BaseIoAHCI_0.MemIo = MemIo; 00745 00746 #ifdef DBG 00747 UniataDumpAhciRegs(deviceExtension); 00748 #endif //DBG 00749 00750 GHC = UniataAhciReadHostPort4(deviceExtension, IDX_AHCI_GHC); 00751 if(GHC & AHCI_GHC_HR) { 00752 KdPrint2((PRINT_PREFIX " AHCI in reset state\n")); 00753 return FALSE; 00754 } 00755 00756 /* enable AHCI mode */ 00757 GHC = UniataAhciReadHostPort4(deviceExtension, IDX_AHCI_GHC); 00758 KdPrint2((PRINT_PREFIX " check AHCI mode, GHC %#x\n", GHC)); 00759 if(!(GHC & AHCI_GHC_AE)) { 00760 KdPrint2((PRINT_PREFIX " Non-AHCI GHC (!AE)\n")); 00761 return FALSE; 00762 } 00763 00764 CAP = UniataAhciReadHostPort4(deviceExtension, IDX_AHCI_CAP); 00765 KdPrint2((PRINT_PREFIX " AHCI CAP %#x\n", CAP)); 00766 if(CAP & AHCI_CAP_S64A) { 00767 KdPrint2((PRINT_PREFIX " AHCI 64bit\n")); 00768 //deviceExtension->Host64 = TRUE; 00769 } 00770 00771 /* get the number of HW channels */ 00772 PI = UniataAhciReadHostPort4(deviceExtension, IDX_AHCI_PI); 00773 KdPrint2((PRINT_PREFIX " AHCI PI %#x\n", PI)); 00774 for(i=PI, n=0; i; n++, i=i>>1); 00775 NumberChannels = 00776 max((CAP & AHCI_CAP_NOP_MASK)+1, n); 00777 00778 KdPrint2((PRINT_PREFIX " Channels %d\n", n)); 00779 00780 switch(deviceExtension->DevID) { 00781 case ATA_M88SX6111: 00782 NumberChannels = 1; 00783 break; 00784 case ATA_M88SX6121: 00785 NumberChannels = 2; 00786 break; 00787 case ATA_M88SX6141: 00788 case ATA_M88SX6145: 00789 NumberChannels = 4; 00790 break; 00791 } // switch() 00792 00793 if(!NumberChannels) { 00794 KdPrint2((PRINT_PREFIX " Non-AHCI - NumberChannels=0\n")); 00795 return FALSE; 00796 } 00797 00798 version = UniataAhciReadHostPort4(deviceExtension, IDX_AHCI_VS); 00799 v_Mj = ((version >> 20) & 0xf0) + ((version >> 16) & 0x0f); 00800 v_Mn = ((version >> 4) & 0xf0) + (version & 0x0f); 00801 00802 KdPrint2((PRINT_PREFIX " AHCI version %#x.%02x controller with %d ports (mask %#x) detected\n", 00803 v_Mj, v_Mn, 00804 NumberChannels, PI)); 00805 00806 if(CAP & AHCI_CAP_SPM) { 00807 KdPrint2((PRINT_PREFIX " PM supported\n")); 00808 if(AtapiRegCheckDevValue(deviceExtension, CHAN_NOT_SPECIFIED, DEVNUM_NOT_SPECIFIED, L"IgnoreAhciPM", 1 /* DEBUG */)) { 00809 KdPrint2((PRINT_PREFIX "SATA/AHCI w/o PM, max luns 1\n")); 00810 deviceExtension->NumberLuns = 2; 00811 //chan->ChannelCtrlFlags |= CTRFLAGS_NO_SLAVE; 00812 } else { 00813 KdPrint2((PRINT_PREFIX "SATA/AHCI -> possible PM, max luns %d\n", SATA_MAX_PM_UNITS)); 00814 deviceExtension->NumberLuns = SATA_MAX_PM_UNITS; 00815 //deviceExtension->NumberLuns = 1; 00816 } 00817 } else { 00818 KdPrint2((PRINT_PREFIX " PM not supported -> 1 lun/chan\n")); 00819 deviceExtension->NumberLuns = 1; 00820 } 00821 00822 if((v_Mj != 0x01) || (v_Mn > 0x20)) { 00823 KdPrint2((PRINT_PREFIX " Unknown AHCI revision\n")); 00824 if(AtapiRegCheckDevValue(deviceExtension, CHAN_NOT_SPECIFIED, DEVNUM_NOT_SPECIFIED, L"CheckAhciRevision", 1)) { 00825 KdPrint((" AHCI revision excluded\n")); 00826 return FALSE; 00827 } 00828 } 00829 00830 deviceExtension->HwFlags |= UNIATA_SATA; 00831 deviceExtension->HwFlags |= UNIATA_AHCI; 00832 if(deviceExtension->NumberChannels < NumberChannels) { 00833 deviceExtension->NumberChannels = NumberChannels; 00834 } 00835 00836 return TRUE; 00837 } // end UniataAhciDetect() 00838 00839 UCHAR 00840 NTAPI 00841 UniataAhciStatus( 00842 IN PVOID HwDeviceExtension, 00843 IN ULONG lChannel, 00844 IN ULONG DeviceNumber 00845 ) 00846 { 00847 PHW_DEVICE_EXTENSION deviceExtension = (PHW_DEVICE_EXTENSION)HwDeviceExtension; 00848 PHW_CHANNEL chan = &deviceExtension->chan[lChannel]; 00849 ULONG Channel = deviceExtension->Channel + lChannel; 00850 ULONG hIS; 00851 ULONG CI; 00852 AHCI_IS_REG IS; 00853 SATA_SSTATUS_REG SStatus; 00854 SATA_SERROR_REG SError; 00855 //ULONG offs = sizeof(IDE_AHCI_REGISTERS) + Channel*sizeof(IDE_AHCI_PORT_REGISTERS); 00856 ULONG tag=0; 00857 00858 KdPrint(("UniataAhciStatus:\n")); 00859 00860 hIS = UniataAhciReadHostPort4(deviceExtension, IDX_AHCI_IS); 00861 KdPrint((" hIS %#x\n", hIS)); 00862 hIS &= (1 << Channel); 00863 if(!hIS) { 00864 return INTERRUPT_REASON_IGNORE; 00865 } 00866 IS.Reg = UniataAhciReadChannelPort4(chan, IDX_AHCI_P_IS); 00867 CI = UniataAhciReadChannelPort4(chan, IDX_AHCI_P_CI); 00868 SStatus.Reg = AtapiReadPort4(chan, IDX_SATA_SStatus); 00869 SError.Reg = AtapiReadPort4(chan, IDX_SATA_SError); 00870 00871 /* clear interrupt(s) */ 00872 UniataAhciWriteHostPort4(deviceExtension, IDX_AHCI_IS, hIS); 00873 UniataAhciWriteChannelPort4(chan, IDX_AHCI_P_IS, IS.Reg); 00874 AtapiWritePort4(chan, IDX_SATA_SError, SError.Reg); 00875 00876 KdPrint((" AHCI: status=%08x sstatus=%08x error=%08x CI=%08x\n", 00877 IS.Reg, SStatus.Reg, SError.Reg, CI)); 00878 00879 /* do we have cold connect surprise */ 00880 if(IS.CPDS) { 00881 } 00882 00883 /* check for and handle connect events */ 00884 if(IS.PCS) { 00885 UniataSataEvent(HwDeviceExtension, lChannel, UNIATA_SATA_EVENT_ATTACH); 00886 } 00887 if(IS.PRCS) { 00888 UniataSataEvent(HwDeviceExtension, lChannel, UNIATA_SATA_EVENT_DETACH); 00889 } 00890 if(CI & (1 << tag)) { 00891 return INTERRUPT_REASON_OUR; 00892 } 00893 KdPrint((" AHCI: unexpected\n")); 00894 return INTERRUPT_REASON_UNEXPECTED; 00895 00896 } // end UniataAhciStatus() 00897 00898 ULONG 00899 NTAPI 00900 UniataAhciSetupFIS_H2D( 00901 IN PHW_DEVICE_EXTENSION deviceExtension, 00902 IN ULONG DeviceNumber, 00903 IN ULONG lChannel, 00904 OUT PUCHAR fis, 00905 IN UCHAR command, 00906 IN ULONGLONG lba, 00907 IN USHORT count, 00908 IN USHORT feature, 00909 IN ULONG flags 00910 ) 00911 { 00912 ULONG i; 00913 PUCHAR plba; 00914 BOOLEAN need48; 00915 PHW_CHANNEL chan = &deviceExtension->chan[lChannel]; 00916 00917 KdPrint2((PRINT_PREFIX " AHCI setup FIS ch %d, dev %d\n", lChannel, DeviceNumber)); 00918 i = 0; 00919 plba = (PUCHAR)&lba; 00920 00921 fis[0] = AHCI_FIS_TYPE_ATA_H2D; /* host to device */ 00922 fis[1] = 0x80 | ((UCHAR)DeviceNumber & 0x0f); /* command FIS (note PM goes here) */ 00923 fis[7] = IDE_USE_LBA; 00924 fis[15] = IDE_DC_A_4BIT; 00925 00926 if(chan->lun[DeviceNumber]->DeviceFlags & DFLAGS_ATAPI_DEVICE) { 00927 fis[2] = IDE_COMMAND_ATAPI_PACKET; 00928 if(feature & ATA_F_DMA) { 00929 fis[3] = (UCHAR)(feature & 0xff); 00930 } else { 00931 fis[5] = (UCHAR)(count & 0xff); 00932 fis[6] = (UCHAR)(count>>8) & 0xff; 00933 } 00934 } else { 00935 00936 if((AtaCommandFlags[command] & ATA_CMD_FLAG_LBAIOsupp) && 00937 CheckIfBadBlock(chan->lun[DeviceNumber], lba, count)) { 00938 KdPrint3((PRINT_PREFIX ": artificial bad block, lba %#I64x count %#x\n", lba, count)); 00939 //return IDE_STATUS_ERROR; 00940 //return SRB_STATUS_ERROR; 00941 return 0; 00942 } 00943 00944 need48 = UniAta_need_lba48(command, lba, count, 00945 chan->lun[DeviceNumber]->IdentifyData.FeaturesSupport.Address48); 00946 00947 /* translate command into 48bit version */ 00948 if(need48) { 00949 if(AtaCommandFlags[command] & ATA_CMD_FLAG_48supp) { 00950 command = AtaCommands48[command]; 00951 } else { 00952 KdPrint2((PRINT_PREFIX " unhandled LBA48 command\n")); 00953 return 0; 00954 } 00955 } 00956 00957 fis[2] = command; 00958 fis[3] = (UCHAR)feature; 00959 00960 fis[4] = plba[0]; 00961 fis[5] = plba[1]; 00962 fis[6] = plba[2]; 00963 if(need48) { 00964 i++; 00965 } else { 00966 #ifdef _MSC_VER 00967 #pragma warning(push) 00968 #pragma warning(disable:4333) // right shift by too large amount, data loss 00969 #endif 00970 fis[7] |= IDE_DRIVE_1 | ((plba[3] >> 24) & 0x0f); 00971 #ifdef _MSC_VER 00972 #pragma warning(pop) 00973 #endif 00974 } 00975 00976 fis[8] = plba[3]; 00977 fis[9] = plba[4]; 00978 fis[10] = plba[5]; 00979 fis[11] = (UCHAR)(feature>>8) & 0xff; 00980 00981 fis[12] = (UCHAR)count & 0xff; 00982 fis[13] = (UCHAR)(count>>8) & 0xff; 00983 //fis[14] = 0x00; 00984 00985 } 00986 00987 KdDump(fis, 20); 00988 00989 return 20; 00990 } // end UniataAhciSetupFIS_H2D() 00991 00992 UCHAR 00993 NTAPI 00994 UniataAhciSendCommand( 00995 IN PVOID HwDeviceExtension, 00996 IN ULONG lChannel, 00997 IN ULONG DeviceNumber, 00998 IN ULONG flags, 00999 IN ULONG timeout 01000 ) 01001 { 01002 PHW_DEVICE_EXTENSION deviceExtension = (PHW_DEVICE_EXTENSION)HwDeviceExtension; 01003 PHW_CHANNEL chan = &deviceExtension->chan[lChannel]; 01004 //ULONG Channel = deviceExtension->Channel + lChannel; 01005 //ULONG hIS; 01006 ULONG CI = 0; 01007 AHCI_IS_REG IS; 01008 ULONG SError; 01009 //SATA_SSTATUS_REG SStatus; 01010 //SATA_SERROR_REG SError; 01011 //ULONG offs = sizeof(IDE_AHCI_REGISTERS) + Channel*sizeof(IDE_AHCI_PORT_REGISTERS); 01012 //ULONGIO_PTR base; 01013 ULONG tag=0; 01014 ULONG i; 01015 01016 PIDE_AHCI_CMD_LIST AHCI_CL = &(chan->AhciCtlBlock->cmd_list[tag]); 01017 01018 KdPrint(("UniataAhciSendCommand: lChan %d\n", chan->lChannel)); 01019 01020 AHCI_CL->prd_length = 0; 01021 AHCI_CL->cmd_flags = (20 / sizeof(ULONG)) | flags | (DeviceNumber << 12); 01022 AHCI_CL->bytecount = 0; 01023 AHCI_CL->cmd_table_phys = chan->AHCI_CTL_PhAddr + FIELD_OFFSET(IDE_AHCI_CHANNEL_CTL_BLOCK, cmd); 01024 if(AHCI_CL->cmd_table_phys & AHCI_CMD_ALIGNEMENT_MASK) { 01025 KdPrint2((PRINT_PREFIX " AHCI CMD address is not aligned (mask %#x)\n", (ULONG)AHCI_CMD_ALIGNEMENT_MASK)); 01026 } 01027 01028 UniataAhciWriteChannelPort4(chan, IDX_AHCI_P_CI, ATA_AHCI_P_CMD_ST); 01029 01030 for (i=0; i<timeout; i++) { 01031 AtapiStallExecution(1000); 01032 CI = UniataAhciReadChannelPort4(chan, IDX_AHCI_P_CI); 01033 if (!(CI & ATA_AHCI_P_CMD_ST)) { 01034 break; 01035 } 01036 } 01037 KdPrint((" CI %#x\n", CI)); 01038 01039 //SStatus.Reg = AtapiReadPort4(chan, IDX_SATA_SStatus); 01040 //SError.Reg = AtapiReadPort4(chan, IDX_SATA_SError); 01041 01042 /* clear interrupt(s) */ 01043 IS.Reg = UniataAhciReadChannelPort4(chan, IDX_AHCI_P_IS); 01044 KdPrint((" IS %#x\n", IS.Reg)); 01045 UniataAhciWriteChannelPort4(chan, IDX_AHCI_P_IS, IS.Reg); 01046 01047 if (timeout && (i >= timeout)) { 01048 SError = AtapiReadPort4(chan, IDX_SATA_SError); 01049 KdPrint((" AHCI: timeout, SError %#x\n", SError)); 01050 return 0xff; 01051 } 01052 01053 return IDE_STATUS_IDLE; 01054 01055 } // end UniataAhciSendCommand() 01056 01057 ULONG 01058 NTAPI 01059 UniataAhciSoftReset( 01060 IN PVOID HwDeviceExtension, 01061 IN ULONG lChannel, 01062 IN ULONG DeviceNumber 01063 ) 01064 { 01065 PHW_DEVICE_EXTENSION deviceExtension = (PHW_DEVICE_EXTENSION)HwDeviceExtension; 01066 PHW_CHANNEL chan = &deviceExtension->chan[lChannel]; 01067 //ULONG Channel = deviceExtension->Channel + lChannel; 01068 //ULONG hIS; 01069 //ULONG CI; 01070 //AHCI_IS_REG IS; 01071 //ULONG tag=0; 01072 01073 KdPrint(("UniataAhciSoftReset: lChan %d\n", chan->lChannel)); 01074 01075 PIDE_AHCI_CMD AHCI_CMD = &(chan->AhciCtlBlock->cmd); 01076 PUCHAR RCV_FIS = &(chan->AhciCtlBlock->rcv_fis.rfis[0]); 01077 01078 #ifdef DBG 01079 UniataDumpAhciPortRegs(chan); 01080 #endif // DBG 01081 01082 /* kick controller into sane state */ 01083 UniataAhciStop(chan); 01084 UniataAhciCLO(chan); 01085 UniataAhciStart(chan); 01086 01087 #ifdef DBG 01088 UniataDumpAhciPortRegs(chan); 01089 #endif // DBG 01090 01091 /* pull reset active */ 01092 RtlZeroMemory(AHCI_CMD->cfis, sizeof(AHCI_CMD->cfis)); 01093 AHCI_CMD->cfis[0] = AHCI_FIS_TYPE_ATA_H2D; 01094 AHCI_CMD->cfis[1] = (UCHAR)DeviceNumber & 0x0f; 01095 //AHCI_CMD->cfis[7] = IDE_USE_LBA | IDE_DRIVE_SELECT; 01096 AHCI_CMD->cfis[15] = (IDE_DC_A_4BIT | IDE_DC_RESET_CONTROLLER); 01097 01098 if(UniataAhciSendCommand(HwDeviceExtension, lChannel, DeviceNumber, ATA_AHCI_CMD_RESET | ATA_AHCI_CMD_CLR_BUSY, 100) == 0xff) { 01099 KdPrint2((" timeout\n")); 01100 return (ULONG)(-1); 01101 } 01102 AtapiStallExecution(50); 01103 01104 /* pull reset inactive */ 01105 RtlZeroMemory(AHCI_CMD->cfis, sizeof(AHCI_CMD->cfis)); 01106 AHCI_CMD->cfis[0] = AHCI_FIS_TYPE_ATA_H2D; 01107 AHCI_CMD->cfis[1] = (UCHAR)DeviceNumber & 0x0f; 01108 //AHCI_CMD->cfis[7] = IDE_USE_LBA | IDE_DRIVE_SELECT; 01109 AHCI_CMD->cfis[15] = (IDE_DC_A_4BIT); 01110 if(UniataAhciSendCommand(HwDeviceExtension, lChannel, DeviceNumber, 0, 3000) == 0xff) { 01111 KdPrint2((" timeout (2)\n")); 01112 return (ULONG)(-1); 01113 } 01114 01115 UniataAhciWaitReady(chan, 1); 01116 01117 KdDump(RCV_FIS, sizeof(chan->AhciCtlBlock->rcv_fis.rfis)); 01118 01119 return UniataAhciUlongFromRFIS(RCV_FIS); 01120 01121 } // end UniataAhciSoftReset() 01122 01123 ULONG 01124 NTAPI 01125 UniataAhciWaitReady( 01126 IN PHW_CHANNEL chan, 01127 IN ULONG timeout 01128 ) 01129 { 01130 ULONG TFD; 01131 ULONG i; 01132 01133 KdPrint2(("UniataAhciWaitReady: lChan %d\n", chan->lChannel)); 01134 01135 //base = (ULONGIO_PTR)(&deviceExtension->BaseIoAHCI_0 + offs); 01136 01137 TFD = UniataAhciReadChannelPort4(chan, IDX_AHCI_P_TFD); 01138 for(i=0; i<timeout && (TFD & 01139 (IDE_STATUS_DRQ | IDE_STATUS_BUSY)); i++) { 01140 AtapiStallExecution(1000); 01141 TFD = UniataAhciReadChannelPort4(chan, IDX_AHCI_P_TFD); 01142 } 01143 01144 KdPrint2((" TFD %#x\n", TFD)); 01145 01146 return TFD; 01147 01148 } // end UniataAhciWaitReady() 01149 01150 ULONG 01151 NTAPI 01152 UniataAhciHardReset( 01153 IN PVOID HwDeviceExtension, 01154 IN ULONG lChannel, 01155 OUT PULONG signature 01156 ) 01157 { 01158 PHW_DEVICE_EXTENSION deviceExtension = (PHW_DEVICE_EXTENSION)HwDeviceExtension; 01159 PHW_CHANNEL chan = &deviceExtension->chan[lChannel]; 01160 //ULONG Channel = deviceExtension->Channel + lChannel; 01161 ULONG TFD; 01162 01163 01164 KdPrint(("UniataAhciHardReset: lChan %d\n", chan->lChannel)); 01165 01166 (*signature) = 0xffffffff; 01167 01168 UniataAhciStop(chan); 01169 if(UniataSataPhyEnable(HwDeviceExtension, lChannel, 0/* dev0*/, UNIATA_SATA_RESET_ENABLE) == 0xff) { 01170 KdPrint((" no PHY\n")); 01171 return 0xff; 01172 } 01173 01174 /* Wait for clearing busy status. */ 01175 TFD = UniataAhciWaitReady(chan, 15000); 01176 if(TFD & (IDE_STATUS_DRQ | IDE_STATUS_BUSY)) { 01177 KdPrint((" busy: TFD %#x\n", TFD)); 01178 return TFD; 01179 } 01180 KdPrint((" TFD %#x\n", TFD)); 01181 01182 #ifdef DBG 01183 UniataDumpAhciPortRegs(chan); 01184 #endif // DBG 01185 01186 (*signature) = UniataAhciReadChannelPort4(chan, IDX_AHCI_P_SIG); 01187 KdPrint((" sig: %#x\n", *signature)); 01188 01189 UniataAhciStart(chan); 01190 01191 return 0; 01192 01193 } // end UniataAhciHardReset() 01194 01195 VOID 01196 NTAPI 01197 UniataAhciReset( 01198 IN PVOID HwDeviceExtension, 01199 IN ULONG lChannel 01200 ) 01201 { 01202 PHW_DEVICE_EXTENSION deviceExtension = (PHW_DEVICE_EXTENSION)HwDeviceExtension; 01203 PHW_CHANNEL chan = &deviceExtension->chan[lChannel]; 01204 //ULONG Channel = deviceExtension->Channel + lChannel; 01205 //ULONG offs = sizeof(IDE_AHCI_REGISTERS) + Channel*sizeof(IDE_AHCI_PORT_REGISTERS); 01206 ULONG CAP; 01207 //ULONGIO_PTR base; 01208 ULONG signature; 01209 ULONG i; 01210 ULONG VendorID = deviceExtension->DevID & 0xffff; 01211 01212 KdPrint(("UniataAhciReset: lChan %d\n", chan->lChannel)); 01213 01214 //base = (ULONGIO_PTR)(&deviceExtension->BaseIoAHCI_0 + offs); 01215 01216 /* Disable port interrupts */ 01217 UniataAhciWriteChannelPort4(chan, IDX_AHCI_P_IE, 0); 01218 01219 if(UniataAhciHardReset(HwDeviceExtension, lChannel, &signature)) { 01220 01221 KdPrint((" No devices in all LUNs\n")); 01222 for (i=0; i<deviceExtension->NumberLuns; i++) { 01223 // Zero device fields to ensure that if earlier devices were found, 01224 // but not claimed, the fields are cleared. 01225 UniataForgetDevice(chan->lun[i]); 01226 } 01227 01228 /* enable wanted port interrupts */ 01229 UniataAhciWriteChannelPort4(chan, IDX_AHCI_P_IE, 01230 ATA_AHCI_P_IX_CPD | ATA_AHCI_P_IX_PRC | ATA_AHCI_P_IX_PC); 01231 return; 01232 } 01233 01234 /* enable wanted port interrupts */ 01235 UniataAhciWriteChannelPort4(chan, IDX_AHCI_P_IE, 01236 (ATA_AHCI_P_IX_CPD | ATA_AHCI_P_IX_TFE | ATA_AHCI_P_IX_HBF | 01237 ATA_AHCI_P_IX_HBD | ATA_AHCI_P_IX_IF | ATA_AHCI_P_IX_OF | 01238 ((/*ch->pm_level == */0) ? (ATA_AHCI_P_IX_PRC | ATA_AHCI_P_IX_PC) : 0) | 01239 ATA_AHCI_P_IX_DP | ATA_AHCI_P_IX_UF | ATA_AHCI_P_IX_SDB | 01240 ATA_AHCI_P_IX_DS | ATA_AHCI_P_IX_PS | ATA_AHCI_P_IX_DHR) ); 01241 01242 /* 01243 * Only probe for PortMultiplier if HW has support. 01244 * Ignore Marvell, which is not working, 01245 */ 01246 CAP = UniataAhciReadHostPort4(deviceExtension, IDX_AHCI_CAP); 01247 if ((CAP & AHCI_CAP_SPM) && 01248 (VendorID != ATA_MARVELL_ID)) { 01249 KdPrint((" check PM\n")); 01250 signature = UniataAhciSoftReset(HwDeviceExtension, lChannel, AHCI_DEV_SEL_PM); 01251 /* Workaround for some ATI chips, failing to soft-reset 01252 * when port multiplicator supported, but absent. 01253 * XXX: We can also check PxIS.IPMS==1 here to be sure. */ 01254 if (signature == 0xffffffff) { 01255 KdPrint((" re-check PM\n")); 01256 signature = UniataAhciSoftReset(HwDeviceExtension, lChannel, 0); 01257 } 01258 } else { 01259 signature = UniataAhciSoftReset(HwDeviceExtension, lChannel, 0); 01260 } 01261 01262 KdPrint((" signature %#x\n", signature)); 01263 chan->lun[0]->DeviceFlags &= ~(DFLAGS_ATAPI_DEVICE | DFLAGS_DEVICE_PRESENT | CTRFLAGS_AHCI_PM); 01264 switch (signature >> 16) { 01265 case 0x0000: 01266 KdPrint((" ATA dev\n")); 01267 chan->lun[0]->DeviceFlags |= DFLAGS_DEVICE_PRESENT; 01268 chan->PmLunMap = 0; 01269 break; 01270 case 0x9669: 01271 KdPrint((" PM\n")); 01272 if(deviceExtension->NumberLuns > 1) { 01273 chan->ChannelCtrlFlags |= CTRFLAGS_AHCI_PM; 01274 UniataSataIdentifyPM(chan); 01275 } else { 01276 KdPrint((" no PM supported (1 lun/chan)\n")); 01277 } 01278 break; 01279 case 0xeb14: 01280 KdPrint((" ATAPI dev\n")); 01281 chan->lun[0]->DeviceFlags |= (DFLAGS_ATAPI_DEVICE | DFLAGS_DEVICE_PRESENT); 01282 chan->PmLunMap = 0; 01283 break; 01284 default: /* SOS XXX */ 01285 KdPrint((" default to ATA ???\n")); 01286 chan->lun[0]->DeviceFlags |= DFLAGS_DEVICE_PRESENT; 01287 chan->PmLunMap = 0; 01288 } 01289 01290 return; 01291 01292 } // end UniataAhciReset() 01293 01294 VOID 01295 NTAPI 01296 UniataAhciStartFR( 01297 IN PHW_CHANNEL chan 01298 ) 01299 { 01300 ULONG CMD; 01301 01302 KdPrint2(("UniataAhciStartFR: lChan %d\n", chan->lChannel)); 01303 01304 CMD = UniataAhciReadChannelPort4(chan, IDX_AHCI_P_CMD); 01305 KdPrint2((" CMD %#x\n", CMD)); 01306 UniataAhciWriteChannelPort4(chan, IDX_AHCI_P_CMD, CMD | ATA_AHCI_P_CMD_FRE); 01307 01308 return; 01309 } // end UniataAhciStartFR() 01310 01311 VOID 01312 NTAPI 01313 UniataAhciStopFR( 01314 IN PHW_CHANNEL chan 01315 ) 01316 { 01317 ULONG CMD; 01318 ULONG i; 01319 01320 KdPrint2(("UniataAhciStopFR: lChan %d\n", chan->lChannel)); 01321 01322 CMD = UniataAhciReadChannelPort4(chan, IDX_AHCI_P_CMD); 01323 KdPrint2((" CMD %#x\n", CMD)); 01324 UniataAhciWriteChannelPort4(chan, IDX_AHCI_P_CMD, CMD & ~ATA_AHCI_P_CMD_FRE); 01325 01326 for(i=0; i<1000; i++) { 01327 CMD = UniataAhciReadChannelPort4(chan, IDX_AHCI_P_CMD); 01328 if(!(CMD & ATA_AHCI_P_CMD_FR)) { 01329 KdPrint2((" final CMD %#x\n", CMD)); 01330 return; 01331 } 01332 AtapiStallExecution(1000); 01333 } 01334 KdPrint2((" CMD %#x\n", CMD)); 01335 KdPrint((" SError %#x\n", AtapiReadPort4(chan, IDX_SATA_SError))); 01336 KdPrint2(("UniataAhciStopFR: timeout\n")); 01337 return; 01338 } // end UniataAhciStopFR() 01339 01340 VOID 01341 NTAPI 01342 UniataAhciStart( 01343 IN PHW_CHANNEL chan 01344 ) 01345 { 01346 ULONG IS, CMD; 01347 SATA_SERROR_REG SError; 01348 01349 KdPrint2(("UniataAhciStart: lChan %d\n", chan->lChannel)); 01350 01351 /* clear SATA error register */ 01352 SError.Reg = AtapiReadPort4(chan, IDX_SATA_SError); 01353 01354 /* clear any interrupts pending on this channel */ 01355 IS = UniataAhciReadChannelPort4(chan, IDX_AHCI_P_IS); 01356 UniataAhciWriteChannelPort4(chan, IDX_AHCI_P_IS, IS); 01357 01358 KdPrint2((" SError %#x, IS %#x\n", SError.Reg, IS)); 01359 01360 CMD = UniataAhciReadChannelPort4(chan, IDX_AHCI_P_CMD); 01361 KdPrint2((" CMD %#x\n", CMD)); 01362 UniataAhciWriteChannelPort4(chan, IDX_AHCI_P_CMD, 01363 CMD | 01364 ATA_AHCI_P_CMD_ST | 01365 ((chan->ChannelCtrlFlags & CTRFLAGS_AHCI_PM) ? ATA_AHCI_P_CMD_PMA : 0)); 01366 01367 return; 01368 } // end UniataAhciStart() 01369 01370 VOID 01371 NTAPI 01372 UniataAhciCLO( 01373 IN PHW_CHANNEL chan 01374 ) 01375 { 01376 //PHW_DEVICE_EXTENSION deviceExtension = (PHW_DEVICE_EXTENSION)HwDeviceExtension; 01377 //PHW_CHANNEL chan = &deviceExtension->chan[lChannel]; 01378 ULONG CAP, CMD; 01379 //SATA_SERROR_REG SError; 01380 ULONG i; 01381 01382 KdPrint2(("UniataAhciCLO: lChan %d\n", chan->lChannel)); 01383 01384 /* issue Command List Override if supported */ 01385 //CAP = UniataAhciReadHostPort4(deviceExtension, IDX_AHCI_CAP); 01386 CAP = chan->DeviceExtension->AHCI_CAP; 01387 if(!(CAP & AHCI_CAP_SCLO)) { 01388 return; 01389 } 01390 KdPrint2((" send CLO\n")); 01391 CMD = UniataAhciReadChannelPort4(chan, IDX_AHCI_P_CMD); 01392 CMD |= ATA_AHCI_P_CMD_CLO; 01393 UniataAhciWriteChannelPort4(chan, IDX_AHCI_P_CMD, CMD); 01394 01395 for(i=0; i<1000; i++) { 01396 CMD = UniataAhciReadChannelPort4(chan, IDX_AHCI_P_CMD); 01397 if(!(CMD & ATA_AHCI_P_CMD_CLO)) { 01398 KdPrint2((" final CMD %#x\n", CMD)); 01399 return; 01400 } 01401 AtapiStallExecution(1000); 01402 } 01403 KdPrint2((" CMD %#x\n", CMD)); 01404 KdPrint2(("UniataAhciCLO: timeout\n")); 01405 return; 01406 } // end UniataAhciCLO() 01407 01408 VOID 01409 NTAPI 01410 UniataAhciStop( 01411 IN PHW_CHANNEL chan 01412 ) 01413 { 01414 ULONG CMD; 01415 //SATA_SERROR_REG SError; 01416 ULONG i; 01417 01418 KdPrint2(("UniataAhciStop: lChan %d\n", chan->lChannel)); 01419 01420 /* issue Command List Override if supported */ 01421 CMD = UniataAhciReadChannelPort4(chan, IDX_AHCI_P_CMD); 01422 CMD &= ~ATA_AHCI_P_CMD_ST; 01423 UniataAhciWriteChannelPort4(chan, IDX_AHCI_P_CMD, CMD); 01424 01425 for(i=0; i<1000; i++) { 01426 CMD = UniataAhciReadChannelPort4(chan, IDX_AHCI_P_CMD); 01427 if(!(CMD & ATA_AHCI_P_CMD_CR)) { 01428 KdPrint2((" final CMD %#x\n", CMD)); 01429 return; 01430 } 01431 AtapiStallExecution(1000); 01432 } 01433 KdPrint2((" CMD %#x\n", CMD)); 01434 KdPrint((" SError %#x\n", AtapiReadPort4(chan, IDX_SATA_SError))); 01435 KdPrint2(("UniataAhciStop: timeout\n")); 01436 return; 01437 } // end UniataAhciStop() 01438 01439 UCHAR 01440 NTAPI 01441 UniataAhciBeginTransaction( 01442 IN PVOID HwDeviceExtension, 01443 IN ULONG lChannel, 01444 IN ULONG DeviceNumber, 01445 IN PSCSI_REQUEST_BLOCK Srb 01446 ) 01447 { 01448 PHW_DEVICE_EXTENSION deviceExtension = (PHW_DEVICE_EXTENSION)HwDeviceExtension; 01449 PHW_CHANNEL chan = &deviceExtension->chan[lChannel]; 01450 //ULONG Channel = deviceExtension->Channel + lChannel; 01451 //ULONG hIS; 01452 ULONG CMD; 01453 //AHCI_IS_REG IS; 01454 PATA_REQ AtaReq = (PATA_REQ)(Srb->SrbExtension); 01455 //SATA_SSTATUS_REG SStatus; 01456 //SATA_SERROR_REG SError; 01457 //ULONG offs = sizeof(IDE_AHCI_REGISTERS) + Channel*sizeof(IDE_AHCI_PORT_REGISTERS); 01458 //ULONGIO_PTR base; 01459 ULONG tag=0; 01460 //ULONG i; 01461 01462 PIDE_AHCI_CMD_LIST AHCI_CL = &(chan->AhciCtlBlock->cmd_list[tag]); 01463 01464 KdPrint2(("UniataAhciBeginTransaction: lChan %d\n", chan->lChannel)); 01465 01466 if(AtaReq->dma_entries > (USHORT)0xffff) { 01467 KdPrint2(("UniataAhciBeginTransaction too long DMA tab\n")); 01468 return 0; 01469 } 01470 01471 AHCI_CL->prd_length = (USHORT)AtaReq->dma_entries; 01472 AHCI_CL->cmd_flags = AtaReq->ahci.io_cmd_flags; 01473 AHCI_CL->bytecount = 0; 01474 AHCI_CL->cmd_table_phys = AtaReq->ahci.ahci_base64; 01475 if(AHCI_CL->cmd_table_phys & AHCI_CMD_ALIGNEMENT_MASK) { 01476 KdPrint2((PRINT_PREFIX " AHCI CMD address is not aligned (mask %#x)\n", (ULONG)AHCI_CMD_ALIGNEMENT_MASK)); 01477 } 01478 01479 CMD = UniataAhciReadChannelPort4(chan, IDX_AHCI_P_CMD); 01480 KdPrint2((" CMD %#x\n", CMD)); 01481 CMD &= ~ATA_AHCI_P_CMD_ATAPI; 01482 KdPrint2((" send CMD %#x\n", CMD)); 01483 UniataAhciWriteChannelPort4(chan, IDX_AHCI_P_CMD, CMD); 01484 01485 /* issue command to controller */ 01486 UniataAhciWriteChannelPort4(chan, IDX_AHCI_P_CI, ATA_AHCI_P_CMD_ST); 01487 01488 if(!(chan->lun[DeviceNumber]->DeviceFlags & DFLAGS_ATAPI_DEVICE)) { 01489 // TODO: check if we send ATA_RESET and wait for ready of so. 01490 if(AtaReq->ahci.ahci_cmd_ptr->cfis[2] == IDE_COMMAND_ATAPI_RESET) { 01491 ULONG TFD; 01492 ULONG i; 01493 01494 for(i=0; i<1000000; i++) { 01495 TFD = UniataAhciReadChannelPort4(chan, IDX_AHCI_P_TFD); 01496 if(!(TFD & IDE_STATUS_BUSY)) { 01497 break; 01498 } 01499 } 01500 if(TFD & IDE_STATUS_BUSY) { 01501 KdPrint2((" timeout\n")); 01502 } 01503 if(TFD & IDE_STATUS_ERROR) { 01504 KdPrint2((" ERROR %#x\n", (UCHAR)(TFD >> 8))); 01505 } 01506 AtaReq->ahci.in_status = TFD; 01507 01508 return 0x00; 01509 } 01510 } 01511 01512 return IDE_STATUS_IDLE; 01513 01514 } // end UniataAhciBeginTransaction() 01515 01516 UCHAR 01517 NTAPI 01518 UniataAhciEndTransaction( 01519 IN PVOID HwDeviceExtension, 01520 IN ULONG lChannel, 01521 IN ULONG DeviceNumber, 01522 IN PSCSI_REQUEST_BLOCK Srb 01523 ) 01524 { 01525 PHW_DEVICE_EXTENSION deviceExtension = (PHW_DEVICE_EXTENSION)HwDeviceExtension; 01526 PHW_CHANNEL chan = &deviceExtension->chan[lChannel]; 01527 //ULONG Channel = deviceExtension->Channel + lChannel; 01528 //ULONG hIS; 01529 PATA_REQ AtaReq = (PATA_REQ)(Srb->SrbExtension); 01530 ULONG TFD; 01531 PUCHAR RCV_FIS = &(chan->AhciCtlBlock->rcv_fis.rfis[0]); 01532 01533 KdPrint2(("UniataAhciEndTransaction: lChan %d\n", chan->lChannel)); 01534 01535 TFD = UniataAhciReadChannelPort4(chan, IDX_AHCI_P_TFD); 01536 KdPrint2((" TFD %#x\n", TFD)); 01537 01538 if(TFD & IDE_STATUS_ERROR) { 01539 KdPrint2((" ERROR %#x\n", (UCHAR)(TFD >> 8))); 01540 } 01541 AtaReq->ahci.in_status = TFD; 01542 01543 //if (request->flags & ATA_R_CONTROL) { 01544 01545 AtaReq->ahci.in_bcount = (ULONG)(RCV_FIS[12]) | ((ULONG)(RCV_FIS[13]) << 8); 01546 AtaReq->ahci.in_lba = (ULONG)(RCV_FIS[4]) | ((ULONGLONG)(RCV_FIS[5]) << 8) | 01547 ((ULONGLONG)(RCV_FIS[6]) << 16); 01548 if(chan->ChannelCtrlFlags & CTRFLAGS_LBA48) { 01549 AtaReq->ahci.in_lba |= ((ULONGLONG)(RCV_FIS[8]) << 24) | 01550 ((ULONGLONG)(RCV_FIS[9]) << 32) | 01551 ((ULONGLONG)(RCV_FIS[10]) << 40); 01552 } else { 01553 AtaReq->ahci.in_lba |= ((ULONGLONG)(RCV_FIS[8]) << 24) | 01554 ((ULONGLONG)(RCV_FIS[9]) << 32) | 01555 ((ULONGLONG)(RCV_FIS[7] & 0x0f) << 24); 01556 } 01557 01558 //} 01559 01560 return 0; 01561 01562 } // end UniataAhciEndTransaction() 01563 01564 VOID 01565 NTAPI 01566 UniataAhciResume( 01567 IN PHW_CHANNEL chan 01568 ) 01569 { 01570 ULONGLONG base; 01571 01572 KdPrint2(("UniataAhciResume: lChan %d\n", chan->lChannel)); 01573 01574 #ifdef DBG 01575 UniataDumpAhciPortRegs(chan); 01576 #endif // DBG 01577 01578 /* Disable port interrupts */ 01579 UniataAhciWriteChannelPort4(chan, IDX_AHCI_P_IE, 0); 01580 01581 /* setup work areas */ 01582 base = chan->AHCI_CTL_PhAddr; 01583 if(!base) { 01584 KdPrint2((PRINT_PREFIX " AHCI buffer allocation failed\n")); 01585 return; 01586 } 01587 KdPrint2((PRINT_PREFIX " AHCI CLB setup\n")); 01588 if(base & AHCI_CLB_ALIGNEMENT_MASK) { 01589 KdPrint2((PRINT_PREFIX " AHCI CLB address is not aligned (mask %#x)\n", (ULONG)AHCI_FIS_ALIGNEMENT_MASK)); 01590 } 01591 UniataAhciWriteChannelPort4(chan, IDX_AHCI_P_CLB, 01592 (ULONG)(base & 0xffffffff)); 01593 UniataAhciWriteChannelPort4(chan, IDX_AHCI_P_CLB + 4, 01594 (ULONG)((base >> 32) & 0xffffffff)); 01595 01596 KdPrint2((PRINT_PREFIX " AHCI RCV FIS setup\n")); 01597 base = chan->AHCI_CTL_PhAddr + FIELD_OFFSET(IDE_AHCI_CHANNEL_CTL_BLOCK, rcv_fis); 01598 if(base & AHCI_FIS_ALIGNEMENT_MASK) { 01599 KdPrint2((PRINT_PREFIX " AHCI FIS address is not aligned (mask %#x)\n", (ULONG)AHCI_FIS_ALIGNEMENT_MASK)); 01600 } 01601 UniataAhciWriteChannelPort4(chan, IDX_AHCI_P_FB, 01602 (ULONG)(base & 0xffffffff)); 01603 UniataAhciWriteChannelPort4(chan, IDX_AHCI_P_FB + 4, 01604 (ULONG)((base >> 32) & 0xffffffff)); 01605 01606 /* activate the channel and power/spin up device */ 01607 UniataAhciWriteChannelPort4(chan, IDX_AHCI_P_CMD, 01608 (ATA_AHCI_P_CMD_ACTIVE | ATA_AHCI_P_CMD_POD | ATA_AHCI_P_CMD_SUD | 01609 (((chan->ChannelCtrlFlags & CTRFLAGS_AHCI_PM)) ? ATA_AHCI_P_CMD_ALPE : 0) | 01610 (((chan->ChannelCtrlFlags & CTRFLAGS_AHCI_PM2)) ? ATA_AHCI_P_CMD_ASP : 0 )) 01611 ); 01612 01613 #ifdef DBG 01614 UniataDumpAhciPortRegs(chan); 01615 #endif // DBG 01616 01617 UniataAhciStartFR(chan); 01618 UniataAhciStart(chan); 01619 01620 #ifdef DBG 01621 UniataDumpAhciPortRegs(chan); 01622 #endif // DBG 01623 01624 return; 01625 } // end UniataAhciResume() 01626 01627 #if 0 01628 VOID 01629 NTAPI 01630 UniataAhciSuspend( 01631 IN PHW_CHANNEL chan 01632 ) 01633 { 01634 ULONGLONG base; 01635 SATA_SCONTROL_REG SControl; 01636 01637 KdPrint2(("UniataAhciSuspend:\n")); 01638 01639 /* Disable port interrupts */ 01640 UniataAhciWriteChannelPort4(chan, IDX_AHCI_P_IE, 0); 01641 01642 /* Reset command register. */ 01643 UniataAhciStop(chan); 01644 UniataAhciStopFR(chan); 01645 UniataAhciWriteChannelPort4(chan, IDX_AHCI_P_CMD, 0); 01646 01647 /* Allow everything including partial and slumber modes. */ 01648 UniataSataWritePort4(chan, IDX_SATA_SControl, 0, 0); 01649 01650 /* Request slumber mode transition and give some time to get there. */ 01651 UniataAhciWriteChannelPort4(chan, IDX_AHCI_P_CMD, ATA_AHCI_P_CMD_SLUMBER); 01652 AtapiStallExecution(100); 01653 01654 /* Disable PHY. */ 01655 SControl.Reg = 0; 01656 SControl.DET = SStatus_DET_Offline; 01657 UniataSataWritePort4(chan, IDX_SATA_SControl, SControl.Reg, 0); 01658 01659 return; 01660 } // end UniataAhciSuspend() 01661 #endif 01662 01663 BOOLEAN 01664 NTAPI 01665 UniataAhciReadPM( 01666 IN PHW_CHANNEL chan, 01667 IN ULONG DeviceNumber, 01668 IN ULONG Reg, 01669 OUT PULONG result 01670 ) 01671 { 01672 //ULONG Channel = deviceExtension->Channel + lChannel; 01673 //ULONG hIS; 01674 //ULONG CI; 01675 //AHCI_IS_REG IS; 01676 //ULONG tag=0; 01677 PIDE_AHCI_CMD AHCI_CMD = &(chan->AhciCtlBlock->cmd); 01678 PUCHAR RCV_FIS = &(chan->AhciCtlBlock->rcv_fis.rfis[0]); 01679 01680 KdPrint(("UniataAhciReadPM: lChan %d [%#x]\n", chan->lChannel, DeviceNumber)); 01681 01682 if(DeviceNumber == DEVNUM_NOT_SPECIFIED) { 01683 (*result) = UniataSataReadPort4(chan, Reg, 0); 01684 return TRUE; 01685 } 01686 if(DeviceNumber < AHCI_DEV_SEL_PM) { 01687 switch(Reg) { 01688 case IDX_SATA_SStatus: 01689 Reg = 0; break; 01690 case IDX_SATA_SError: 01691 Reg = 1; break; 01692 case IDX_SATA_SControl: 01693 Reg = 2; break; 01694 default: 01695 return FALSE; 01696 } 01697 } 01698 01699 RtlZeroMemory(AHCI_CMD->cfis, sizeof(AHCI_CMD->cfis)); 01700 AHCI_CMD->cfis[0] = AHCI_FIS_TYPE_ATA_H2D; 01701 AHCI_CMD->cfis[1] = AHCI_FIS_COMM_PM; 01702 AHCI_CMD->cfis[2] = IDE_COMMAND_READ_PM; 01703 AHCI_CMD->cfis[3] = (UCHAR)Reg; 01704 AHCI_CMD->cfis[7] = (UCHAR)(IDE_USE_LBA | DeviceNumber); 01705 AHCI_CMD->cfis[15] = IDE_DC_A_4BIT; 01706 01707 if(UniataAhciSendCommand(chan->DeviceExtension, chan->lChannel, DeviceNumber, 0, 10) == 0xff) { 01708 KdPrint2((" PM read failed\n")); 01709 return FALSE; 01710 } 01711 01712 KdDump(RCV_FIS, sizeof(chan->AhciCtlBlock->rcv_fis.rfis)); 01713 01714 (*result) = UniataAhciUlongFromRFIS(RCV_FIS); 01715 return TRUE; 01716 01717 } // end UniataAhciReadPM() 01718 01719 UCHAR 01720 NTAPI 01721 UniataAhciWritePM( 01722 IN PHW_CHANNEL chan, 01723 IN ULONG DeviceNumber, 01724 IN ULONG Reg, 01725 IN ULONG value 01726 ) 01727 { 01728 //ULONG Channel = deviceExtension->Channel + lChannel; 01729 //ULONG hIS; 01730 //ULONG CI; 01731 //AHCI_IS_REG IS; 01732 //ULONG tag=0; 01733 ULONG TFD; 01734 PIDE_AHCI_CMD AHCI_CMD = &(chan->AhciCtlBlock->cmd); 01735 //PUCHAR RCV_FIS = &(chan->AhciCtlBlock->rcv_fis.rfis[0]); 01736 01737 KdPrint(("UniataAhciWritePM: lChan %d [%#x] %#x\n", chan->lChannel, DeviceNumber, value)); 01738 01739 if(DeviceNumber == DEVNUM_NOT_SPECIFIED) { 01740 UniataSataWritePort4(chan, Reg, value, 0); 01741 return 0; 01742 } 01743 if(DeviceNumber < AHCI_DEV_SEL_PM) { 01744 switch(Reg) { 01745 case IDX_SATA_SStatus: 01746 Reg = 0; break; 01747 case IDX_SATA_SError: 01748 Reg = 1; break; 01749 case IDX_SATA_SControl: 01750 Reg = 2; break; 01751 default: 01752 return 0xff; 01753 } 01754 } 01755 01756 RtlZeroMemory(AHCI_CMD->cfis, sizeof(AHCI_CMD->cfis)); 01757 AHCI_CMD->cfis[0] = AHCI_FIS_TYPE_ATA_H2D; 01758 AHCI_CMD->cfis[1] = AHCI_FIS_COMM_PM; 01759 AHCI_CMD->cfis[2] = IDE_COMMAND_WRITE_PM; 01760 AHCI_CMD->cfis[3] = (UCHAR)Reg; 01761 AHCI_CMD->cfis[7] = (UCHAR)(IDE_USE_LBA | DeviceNumber); 01762 01763 AHCI_CMD->cfis[12] = (UCHAR)(value & 0xff); 01764 AHCI_CMD->cfis[4] = (UCHAR)((value >> 8) & 0xff); 01765 AHCI_CMD->cfis[5] = (UCHAR)((value >> 16) & 0xff); 01766 AHCI_CMD->cfis[6] = (UCHAR)((value >> 24) & 0xff); 01767 01768 AHCI_CMD->cfis[15] = IDE_DC_A_4BIT; 01769 01770 if(UniataAhciSendCommand(chan->DeviceExtension, chan->lChannel, DeviceNumber, 0, 100) == 0xff) { 01771 KdPrint2((" PM write failed\n")); 01772 return 0xff; 01773 } 01774 01775 TFD = UniataAhciReadChannelPort4(chan, IDX_AHCI_P_TFD); 01776 01777 if(TFD & IDE_STATUS_ERROR) { 01778 KdPrint2((" ERROR %#x\n", (UCHAR)(TFD >> 8))); 01779 } 01780 return (UCHAR)(TFD >> 8); 01781 01782 } // end UniataAhciWritePM() 01783 01784 VOID 01785 UniataAhciSetupCmdPtr( 01786 IN OUT PATA_REQ AtaReq 01787 ) 01788 { 01789 union { 01790 PUCHAR prd_base; 01791 ULONGLONG prd_base64; 01792 }; 01793 union { 01794 PUCHAR prd_base0; 01795 ULONGLONG prd_base64_0; 01796 }; 01797 ULONG d; 01798 01799 prd_base64_0 = prd_base64 = 0; 01800 prd_base = (PUCHAR)(&AtaReq->ahci_cmd0); 01801 prd_base0 = prd_base; 01802 01803 prd_base64 = (prd_base64 + max(FIELD_OFFSET(ATA_REQ, ahci_cmd0), AHCI_CMD_ALIGNEMENT_MASK)) & ~AHCI_CMD_ALIGNEMENT_MASK; 01804 01805 d = (ULONG)(prd_base64 - prd_base64_0); 01806 KdPrint2((PRINT_PREFIX " aligned %I64x, d=%x\n", prd_base64, d)); 01807 01808 AtaReq->ahci.ahci_cmd_ptr = (PIDE_AHCI_CMD)prd_base64; 01809 KdPrint2((PRINT_PREFIX " ahci_cmd_ptr %#x\n", AtaReq->ahci.ahci_cmd_ptr)); 01810 } // end UniataAhciSetupCmdPtr() Generated on Sun May 27 2012 04:28:26 for ReactOS by
1.7.6.1
|