ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

id_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 doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.