[FREELDR] Add ATA/ATAPI driver. (#2167)
[reactos.git] / boot / freeldr / freeldr / arch / i386 / xboxdisk.c
index e1e4d35..26a00e1 100644 (file)
 /*
- *  FreeLoader
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License along
- *  with this program; if not, write to the Free Software Foundation, Inc.,
- *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Note: mostly ripped from atapi.c
- *       Some of this code was based on knowledge and/or code developed
- *       by the Xbox Linux group: http://www.xbox-linux.org
- *
+ * PROJECT:     FreeLoader
+ * LICENSE:     GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
+ * PURPOSE:     Xbox specific disk access routines
+ * COPYRIGHT:   Copyright 2004 Gé van Geldorp (gvg@reactos.com)
+ *              Copyright 2019 Dmitry Borisov (di.sean@protonmail.com)
  */
 
+/* INCLUDES *******************************************************************/
+
 #include <freeldr.h>
+#include <hwide.h>
 
 #include <debug.h>
-
 DBG_DEFAULT_CHANNEL(DISK);
 
-#define XBOX_IDE_COMMAND_PORT 0x1f0
-#define XBOX_IDE_CONTROL_PORT 0x170
-
-#define  IDE_SECTOR_BUF_SZ      512
-#define  IDE_MAX_POLL_RETRIES   100000
-#define  IDE_MAX_BUSY_RETRIES   50000
-
-/* Control Block offsets and masks */
-#define  IDE_REG_ALT_STATUS     0x0000
-#define  IDE_REG_DEV_CNTRL      0x0000  /* device control register */
-#define    IDE_DC_SRST            0x04  /* drive reset (both drives) */
-#define    IDE_DC_nIEN            0x02  /* IRQ enable (active low) */
-#define  IDE_REG_DRV_ADDR       0x0001
-
-/* Command Block offsets and masks */
-#define  IDE_REG_DATA_PORT      0x0000
-#define  IDE_REG_ERROR          0x0001  /* error register */
-#define    IDE_ER_AMNF            0x01  /* addr mark not found */
-#define    IDE_ER_TK0NF           0x02  /* track 0 not found */
-#define    IDE_ER_ABRT            0x04  /* command aborted */
-#define    IDE_ER_MCR             0x08  /* media change requested */
-#define    IDE_ER_IDNF            0x10  /* ID not found */
-#define    IDE_ER_MC              0x20  /* Media changed */
-#define    IDE_ER_UNC             0x40  /* Uncorrectable data error */
-#define  IDE_REG_PRECOMP        0x0001
-#define  IDE_REG_SECTOR_CNT     0x0002
-#define  IDE_REG_SECTOR_NUM     0x0003
-#define  IDE_REG_CYL_LOW        0x0004
-#define  IDE_REG_CYL_HIGH       0x0005
-#define  IDE_REG_DRV_HEAD       0x0006
-#define    IDE_DH_FIXED           0xA0
-#define    IDE_DH_LBA             0x40
-#define    IDE_DH_HDMASK          0x0F
-#define    IDE_DH_DRV0            0x00
-#define    IDE_DH_DRV1            0x10
-#define  IDE_REG_STATUS           0x0007
-#define    IDE_SR_BUSY              0x80
-#define    IDE_SR_DRDY              0x40
-#define    IDE_SR_WERR              0x20
-#define    IDE_SR_DRQ               0x08
-#define    IDE_SR_ERR               0x01
-#define  IDE_REG_COMMAND          0x0007
-
-/* IDE/ATA commands */
-#define    IDE_CMD_RESET            0x08
-#define    IDE_CMD_READ             0x20
-#define    IDE_CMD_READ_RETRY       0x21
-#define    IDE_CMD_WRITE            0x30
-#define    IDE_CMD_WRITE_RETRY      0x31
-#define    IDE_CMD_PACKET           0xA0
-#define    IDE_CMD_READ_MULTIPLE    0xC4
-#define    IDE_CMD_WRITE_MULTIPLE   0xC5
-#define    IDE_CMD_READ_DMA         0xC8
-#define    IDE_CMD_WRITE_DMA        0xCA
-#define    IDE_CMD_FLUSH_CACHE      0xE7
-#define    IDE_CMD_FLUSH_CACHE_EXT  0xEA
-#define    IDE_CMD_IDENT_ATA_DRV    0xEC
-#define    IDE_CMD_IDENT_ATAPI_DRV  0xA1
-#define    IDE_CMD_GET_MEDIA_STATUS 0xDA
-
-/*
- *  Access macros for command registers
- *  Each macro takes an address of the command port block, and data
- */
-#define IDEReadError(Address) \
-    (READ_PORT_UCHAR((PUCHAR)((Address) + IDE_REG_ERROR)))
-#define IDEWritePrecomp(Address, Data) \
-    (WRITE_PORT_UCHAR((PUCHAR)((Address) + IDE_REG_PRECOMP), (Data)))
-#define IDEReadSectorCount(Address) \
-    (READ_PORT_UCHAR((PUCHAR)((Address) + IDE_REG_SECTOR_CNT)))
-#define IDEWriteSectorCount(Address, Data) \
-    (WRITE_PORT_UCHAR((PUCHAR)((Address) + IDE_REG_SECTOR_CNT), (Data)))
-#define IDEReadSectorNum(Address) \
-    (READ_PORT_UCHAR((PUCHAR)((Address) + IDE_REG_SECTOR_NUM)))
-#define IDEWriteSectorNum(Address, Data) \
-    (WRITE_PORT_UCHAR((PUCHAR)((Address) + IDE_REG_SECTOR_NUM), (Data)))
-#define IDEReadCylinderLow(Address) \
-    (READ_PORT_UCHAR((PUCHAR)((Address) + IDE_REG_CYL_LOW)))
-#define IDEWriteCylinderLow(Address, Data) \
-    (WRITE_PORT_UCHAR((PUCHAR)((Address) + IDE_REG_CYL_LOW), (Data)))
-#define IDEReadCylinderHigh(Address) \
-    (READ_PORT_UCHAR((PUCHAR)((Address) + IDE_REG_CYL_HIGH)))
-#define IDEWriteCylinderHigh(Address, Data) \
-    (WRITE_PORT_UCHAR((PUCHAR)((Address) + IDE_REG_CYL_HIGH), (Data)))
-#define IDEReadDriveHead(Address) \
-    (READ_PORT_UCHAR((PUCHAR)((Address) + IDE_REG_DRV_HEAD)))
-#define IDEWriteDriveHead(Address, Data) \
-    (WRITE_PORT_UCHAR((PUCHAR)((Address) + IDE_REG_DRV_HEAD), (Data)))
-#define IDEReadStatus(Address) \
-    (READ_PORT_UCHAR((PUCHAR)((Address) + IDE_REG_STATUS)))
-#define IDEWriteCommand(Address, Data) \
-    (WRITE_PORT_UCHAR((PUCHAR)((Address) + IDE_REG_COMMAND), (Data)))
-#define IDEReadDMACommand(Address) \
-    (READ_PORT_UCHAR((PUCHAR)((Address))))
-#define IDEWriteDMACommand(Address, Data) \
-    (WRITE_PORT_UCHAR((PUCHAR)((Address)), (Data)))
-#define IDEReadDMAStatus(Address) \
-    (READ_PORT_UCHAR((PUCHAR)((Address) + 2)))
-#define IDEWriteDMAStatus(Address, Data) \
-    (WRITE_PORT_UCHAR((PUCHAR)((Address) + 2), (Data)))
-#define IDEWritePRDTable(Address, Data) \
-    (WRITE_PORT_ULONG((PULONG)((Address) + 4), (Data)))
-
-/*
- *  Data block read and write commands
- */
-#define IDEReadBlock(Address, Buffer, Count) \
-    (READ_PORT_BUFFER_USHORT((PUSHORT)((Address) + IDE_REG_DATA_PORT), (PUSHORT)(Buffer), (Count) / 2))
-#define IDEWriteBlock(Address, Buffer, Count) \
-    (WRITE_PORT_BUFFER_USHORT((PUSHORT)((Address) + IDE_REG_DATA_PORT), (PUSHORT)(Buffer), (Count) / 2))
-
-#define IDEReadBlock32(Address, Buffer, Count) \
-    (READ_PORT_BUFFER_ULONG((PULONG)((Address) + IDE_REG_DATA_PORT), (PULONG)(Buffer), (Count) / 4))
-#define IDEWriteBlock32(Address, Buffer, Count) \
-    (WRITE_PORT_BUFFER_ULONG((PULONG)((Address) + IDE_REG_DATA_PORT), (PULONG)(Buffer), (Count) / 4))
+/* GLOBALS ********************************************************************/
 
-#define IDEReadWord(Address) \
-    (READ_PORT_USHORT((PUSHORT)((Address) + IDE_REG_DATA_PORT)))
+static PDEVICE_UNIT HardDrive = NULL;
+static PDEVICE_UNIT CdDrive = NULL;
+static BOOLEAN AtaInitialized = FALSE;
 
-/*
- *  Access macros for control registers
- *  Each macro takes an address of the control port blank and data
- */
-#define IDEReadAltStatus(Address) \
-    (READ_PORT_UCHAR((PUCHAR)((Address) + IDE_REG_ALT_STATUS)))
-#define IDEWriteDriveControl(Address, Data) \
-    (WRITE_PORT_UCHAR((PUCHAR)((Address) + IDE_REG_DEV_CNTRL), (Data)))
+/* FUNCTIONS ******************************************************************/
 
-/* IDE_DRIVE_IDENTIFY */
-typedef struct _IDE_DRIVE_IDENTIFY
+VOID
+XboxDiskInit(BOOLEAN Init)
 {
-    USHORT   ConfigBits;          /*00*/
-    USHORT   LogicalCyls;         /*01*/
-    USHORT   Reserved02;          /*02*/
-    USHORT   LogicalHeads;        /*03*/
-    USHORT   BytesPerTrack;       /*04*/
-    USHORT   BytesPerSector;      /*05*/
-    USHORT   SectorsPerTrack;     /*06*/
-    UCHAR    InterSectorGap;      /*07*/
-    UCHAR    InterSectorGapSize;
-    UCHAR    Reserved08H;         /*08*/
-    UCHAR    BytesInPLO;
-    USHORT   VendorUniqueCnt;     /*09*/
-    UCHAR    SerialNumber[20];    /*10*/
-    USHORT   ControllerType;      /*20*/
-    USHORT   BufferSize;          /*21*/
-    USHORT   ECCByteCnt;          /*22*/
-    UCHAR    FirmwareRev[8];      /*23*/
-    UCHAR    ModelNumber[40];     /*27*/
-    USHORT   RWMultImplemented;   /*47*/
-    USHORT   DWordIo;             /*48*/
-    USHORT   Capabilities;        /*49*/
-#define IDE_DRID_STBY_SUPPORTED   0x2000
-#define IDE_DRID_IORDY_SUPPORTED  0x0800
-#define IDE_DRID_IORDY_DISABLE    0x0400
-#define IDE_DRID_LBA_SUPPORTED    0x0200
-#define IDE_DRID_DMA_SUPPORTED    0x0100
-    USHORT   Reserved50;          /*50*/
-    USHORT   MinPIOTransTime;     /*51*/
-    USHORT   MinDMATransTime;     /*52*/
-    USHORT   TMFieldsValid;       /*53*/
-    USHORT   TMCylinders;         /*54*/
-    USHORT   TMHeads;             /*55*/
-    USHORT   TMSectorsPerTrk;     /*56*/
-    USHORT   TMCapacityLo;        /*57*/
-    USHORT   TMCapacityHi;        /*58*/
-    USHORT   RWMultCurrent;       /*59*/
-    USHORT   TMSectorCountLo;     /*60*/
-    USHORT   TMSectorCountHi;     /*61*/
-    USHORT   DmaModes;            /*62*/
-    USHORT   MultiDmaModes;       /*63*/
-    USHORT   Reserved64[5];       /*64*/
-    USHORT   Reserved69[2];       /*69*/
-    USHORT   Reserved71[4];       /*71*/
-    USHORT   MaxQueueDepth;       /*75*/
-    USHORT   Reserved76[4];       /*76*/
-    USHORT   MajorRevision;       /*80*/
-    USHORT   MinorRevision;       /*81*/
-    USHORT   SupportedFeatures82; /*82*/
-    USHORT   SupportedFeatures83; /*83*/
-    USHORT   SupportedFeatures84; /*84*/
-    USHORT   EnabledFeatures85;   /*85*/
-    USHORT   EnabledFeatures86;   /*86*/
-    USHORT   EnabledFeatures87;   /*87*/
-    USHORT   UltraDmaModes;       /*88*/
-    USHORT   Reserved89[11];      /*89*/
-    USHORT   Max48BitAddress[4];  /*100*/
-    USHORT   Reserved104[151];    /*104*/
-    USHORT   Checksum;            /*255*/
-} IDE_DRIVE_IDENTIFY, *PIDE_DRIVE_IDENTIFY;
-
-/*  XboxDiskPolledRead
- *
- *  DESCRIPTION:
- *    Read a sector of data from the drive in a polled fashion.
- *
- *  RUN LEVEL:
- *    PASSIVE_LEVEL
- *
- *  ARGUMENTS:
- *    ULONG CommandPort     Address of command port for drive
- *    ULONG ControlPort     Address of control port for drive
- *    UCHAR PreComp         Value to write to precomp register
- *    UCHAR SectorCnt       Value to write to sectorCnt register
- *    UCHAR SectorNum       Value to write to sectorNum register
- *    UCHAR CylinderLow     Value to write to CylinderLow register
- *    UCHAR CylinderHigh    Value to write to CylinderHigh register
- *    UCHAR DrvHead         Value to write to Drive/Head register
- *    UCHAR Command         Value to write to Command register
- *    PVOID Buffer          Buffer for output data
- *
- *  RETURNS:
- *    BOOLEAN: TRUE success, FALSE error
- */
-static BOOLEAN
-XboxDiskPolledRead(ULONG CommandPort,
-                   ULONG ControlPort,
-                   UCHAR PreComp,
-                   UCHAR SectorCnt,
-                   UCHAR SectorNum,
-                   UCHAR CylinderLow,
-                   UCHAR CylinderHigh,
-                   UCHAR DrvHead,
-                   UCHAR Command,
-                   PVOID Buffer)
-{
-    ULONG SectorCount = 0;
-    ULONG RetryCount;
-    BOOLEAN Junk = FALSE;
-    UCHAR Status;
-
-    /* Wait for BUSY to clear */
-    for (RetryCount = 0; RetryCount < IDE_MAX_BUSY_RETRIES; RetryCount++)
-    {
-        Status = IDEReadStatus(CommandPort);
-        if (!(Status & IDE_SR_BUSY))
-            break;
-
-        StallExecutionProcessor(10);
-    }
-    TRACE("status=0x%x\n", Status);
-    TRACE("waited %d usecs for busy to clear\n", RetryCount * 10);
-    if (RetryCount >= IDE_MAX_BUSY_RETRIES)
-    {
-        WARN("Drive is BUSY for too long\n");
-        return FALSE;
-    }
-
-    /* Write Drive/Head to select drive */
-    IDEWriteDriveHead(CommandPort, IDE_DH_FIXED | DrvHead);
-    StallExecutionProcessor(500);
-
-    /* Disable interrupts */
-    IDEWriteDriveControl(ControlPort, IDE_DC_nIEN);
-    StallExecutionProcessor(500);
-
-    /* Issue command to drive */
-    if (DrvHead & IDE_DH_LBA)
-    {
-        TRACE("READ:DRV=%d:LBA=1:BLK=%d:SC=0x%x:CM=0x%x\n",
-              DrvHead & IDE_DH_DRV1 ? 1 : 0,
-              ((DrvHead & 0x0f) << 24) + (CylinderHigh << 16) + (CylinderLow << 8) + SectorNum,
-              SectorCnt,
-              Command);
-    }
-    else
-    {
-        TRACE("READ:DRV=%d:LBA=0:CH=0x%x:CL=0x%x:HD=0x%x:SN=0x%x:SC=0x%x:CM=0x%x\n",
-              DrvHead & IDE_DH_DRV1 ? 1 : 0,
-              CylinderHigh,
-              CylinderLow,
-              DrvHead & 0x0f,
-              SectorNum,
-              SectorCnt,
-              Command);
-    }
-
-    /* Setup command parameters */
-    IDEWritePrecomp(CommandPort, PreComp);
-    IDEWriteSectorCount(CommandPort, SectorCnt);
-    IDEWriteSectorNum(CommandPort, SectorNum);
-    IDEWriteCylinderHigh(CommandPort, CylinderHigh);
-    IDEWriteCylinderLow(CommandPort, CylinderLow);
-    IDEWriteDriveHead(CommandPort, IDE_DH_FIXED | DrvHead);
-
-    /* Issue the command */
-    IDEWriteCommand(CommandPort, Command);
-    StallExecutionProcessor(50);
-
-    /* Wait for DRQ or error */
-    for (RetryCount = 0; RetryCount < IDE_MAX_POLL_RETRIES; RetryCount++)
-    {
-        Status = IDEReadStatus(CommandPort);
-        if (!(Status & IDE_SR_BUSY))
-        {
-            if (Status & IDE_SR_ERR)
-            {
-                IDEWriteDriveControl(ControlPort, 0);
-                StallExecutionProcessor(50);
-                IDEReadStatus(CommandPort);
-                return FALSE;
-            }
-
-            if (Status & IDE_SR_DRQ)
-            {
-                break;
-            }
-            else
-            {
-                IDEWriteDriveControl(ControlPort, 0);
-                StallExecutionProcessor(50);
-                IDEReadStatus(CommandPort);
-                return FALSE;
-            }
-        }
-        StallExecutionProcessor(10);
-    }
-
-    /* Timed out */
-    if (RetryCount >= IDE_MAX_POLL_RETRIES)
-    {
-        IDEWriteDriveControl(ControlPort, 0);
-        StallExecutionProcessor(50);
-        IDEReadStatus(CommandPort);
-        return FALSE;
-    }
+    UCHAR DetectedCount;
+    UCHAR UnitNumber;
+    PDEVICE_UNIT DeviceUnit = NULL;
 
-    while (1)
+    if (Init & !AtaInitialized)
     {
-        /* Read data into buffer */
-        if (Junk == FALSE)
+        /* Find first HDD and CD */
+        AtaInit(&DetectedCount);
+        for (UnitNumber = 0; UnitNumber <= DetectedCount; UnitNumber++)
         {
-            IDEReadBlock(CommandPort, Buffer, IDE_SECTOR_BUF_SZ);
-            Buffer = (PVOID)((ULONG_PTR)Buffer + IDE_SECTOR_BUF_SZ);
-        }
-        else
-        {
-            UCHAR JunkBuffer[IDE_SECTOR_BUF_SZ];
-            IDEReadBlock(CommandPort, JunkBuffer, IDE_SECTOR_BUF_SZ);
-        }
-        SectorCount++;
-
-        /* Check for error or more sectors to read */
-        for (RetryCount = 0; RetryCount < IDE_MAX_BUSY_RETRIES; RetryCount++)
-        {
-            Status = IDEReadStatus(CommandPort);
-            if (!(Status & IDE_SR_BUSY))
+            DeviceUnit = AtaGetDevice(UnitNumber);
+            if (DeviceUnit)
             {
-                if (Status & IDE_SR_ERR)
-                {
-                    IDEWriteDriveControl(ControlPort, 0);
-                    StallExecutionProcessor(50);
-                    IDEReadStatus(CommandPort);
-                    return FALSE;
-                }
-                if (Status & IDE_SR_DRQ)
+                if (DeviceUnit->Flags & ATA_DEVICE_ATAPI)
                 {
-                    if (SectorCount >= SectorCnt)
-                    {
-                        TRACE("Buffer size exceeded!\n");
-                        Junk = TRUE;
-                    }
-                    break;
+                    if (!CdDrive)
+                        CdDrive = DeviceUnit;
                 }
                 else
                 {
-                    if (SectorCount > SectorCnt)
-                    {
-                        TRACE("Read %lu sectors of junk!\n",
-                              SectorCount - SectorCnt);
-                    }
-
-                    IDEWriteDriveControl(ControlPort, 0);
-                    StallExecutionProcessor(50);
-                    IDEReadStatus(CommandPort);
-                    return TRUE;
+                    if (!HardDrive)
+                        HardDrive = DeviceUnit;
                 }
             }
         }
+        AtaInitialized = TRUE;
+    }
+    else
+    {
+        AtaFree();
     }
 }
 
+static
+inline
 BOOLEAN
-XboxDiskReadLogicalSectors(UCHAR DriveNumber, ULONGLONG SectorNumber, ULONG SectorCount, PVOID Buffer)
+XboxDiskDriveNumberToDeviceUnit(UCHAR DriveNumber, PDEVICE_UNIT *DeviceUnit)
 {
-    ULONG StartSector;
-    UCHAR Count;
-
-    if (DriveNumber < 0x80 || (DriveNumber & 0x0f) >= 2)
-    {
-        /* Xbox has only 1 IDE controller and no floppy */
-        WARN("Invalid drive number\n");
+    /* Xbox has only 1 IDE controller and no floppy */
+    if (DriveNumber < 0x80 || (DriveNumber & 0x0F) >= 2)
         return FALSE;
-    }
 
-    if (((SectorNumber + SectorCount) & UINT64_C(0xfffffffff0000000)) != UINT64_C(0))
+    if (!AtaInitialized)
+        XboxDiskInit(TRUE);
+
+    /* HDD */
+    if ((DriveNumber == 0x80) && HardDrive)
     {
-        FIXME("48bit LBA required but not implemented\n");
-        return FALSE;
+        *DeviceUnit = HardDrive;
+        return TRUE;
     }
 
-    StartSector = (ULONG) SectorNumber;
-    while (SectorCount > 0)
+    /* CD */
+    if ((DriveNumber & 0xF0) > 0x80 && CdDrive)
     {
-        Count = (SectorCount <= 255 ? (UCHAR)SectorCount : 255);
-        if (!XboxDiskPolledRead(XBOX_IDE_COMMAND_PORT,
-                                XBOX_IDE_CONTROL_PORT,
-                                0, Count,
-                                StartSector & 0xff,
-                                (StartSector >> 8) & 0xff,
-                                (StartSector >> 16) & 0xff,
-                                ((StartSector >> 24) & 0x0f) | IDE_DH_LBA |
-                                ((DriveNumber & 0x0f) == 0 ? IDE_DH_DRV0 : IDE_DH_DRV1),
-                                IDE_CMD_READ,
-                                Buffer))
-        {
-            return FALSE;
-        }
-        SectorCount -= Count;
-        Buffer = (PVOID) ((PCHAR) Buffer + Count * IDE_SECTOR_BUF_SZ);
+        *DeviceUnit = CdDrive;
+        return TRUE;
     }
 
-    return TRUE;
+    return FALSE;
 }
 
 BOOLEAN
-XboxDiskGetDriveGeometry(UCHAR DriveNumber, PGEOMETRY Geometry)
+XboxDiskReadLogicalSectors(UCHAR DriveNumber, ULONGLONG SectorNumber, ULONG SectorCount, PVOID Buffer)
 {
-    IDE_DRIVE_IDENTIFY DrvParms;
-    ULONG i;
-    BOOLEAN Atapi;
+    PDEVICE_UNIT DeviceUnit = NULL;
 
-    Atapi = FALSE; /* FIXME */
-    /* Get the Drive Identify block from drive or die */
-    if (!XboxDiskPolledRead(XBOX_IDE_COMMAND_PORT,
-                            XBOX_IDE_CONTROL_PORT,
-                            0,
-                            1,
-                            0,
-                            0,
-                            0,
-                            ((DriveNumber & 0x0f) == 0 ? IDE_DH_DRV0 : IDE_DH_DRV1),
-                            (Atapi ? IDE_CMD_IDENT_ATAPI_DRV : IDE_CMD_IDENT_ATA_DRV),
-                            (PUCHAR) &DrvParms))
-    {
-        ERR("XboxDiskPolledRead() failed\n");
+    TRACE("XboxDiskReadLogicalSectors() DriveNumber: 0x%x SectorNumber: %I64d SectorCount: %d Buffer: 0x%x\n",
+          DriveNumber, SectorNumber, SectorCount, Buffer);
+
+    if (!XboxDiskDriveNumberToDeviceUnit(DriveNumber, &DeviceUnit))
         return FALSE;
-    }
 
-    Geometry->Cylinders = DrvParms.LogicalCyls;
-    Geometry->Heads = DrvParms.LogicalHeads;
-    Geometry->Sectors = DrvParms.SectorsPerTrack;
+    return AtaAtapiReadLogicalSectorsLBA(DeviceUnit, SectorNumber, SectorCount, Buffer);
+}
 
-    if (!Atapi && (DrvParms.Capabilities & IDE_DRID_LBA_SUPPORTED) != 0)
-    {
-        /* LBA ATA drives always have a sector size of 512 */
-        Geometry->BytesPerSector = 512;
-    }
-    else
-    {
-        TRACE("BytesPerSector %d\n", DrvParms.BytesPerSector);
-        if (DrvParms.BytesPerSector == 0)
-        {
-            Geometry->BytesPerSector = 512;
-        }
-        else
-        {
-            for (i = 1 << 15; i; i /= 2)
-            {
-                if ((DrvParms.BytesPerSector & i) != 0)
-                {
-                    Geometry->BytesPerSector = i;
-                    break;
-                }
-            }
-        }
-    }
-    TRACE("Cylinders %d\n", Geometry->Cylinders);
-    TRACE("Heads %d\n", Geometry->Heads);
-    TRACE("Sectors %d\n", Geometry->Sectors);
-    TRACE("BytesPerSector %d\n", Geometry->BytesPerSector);
+BOOLEAN
+XboxDiskGetDriveGeometry(UCHAR DriveNumber, PGEOMETRY Geometry)
+{
+    PDEVICE_UNIT DeviceUnit = NULL;
+
+    TRACE("XboxDiskGetDriveGeometry(0x%x)\n", DriveNumber);
+
+    if (!XboxDiskDriveNumberToDeviceUnit(DriveNumber, &DeviceUnit))
+        return FALSE;
+
+    Geometry->Cylinders = DeviceUnit->Cylinders;
+    Geometry->Heads = DeviceUnit->Heads;
+    Geometry->Sectors = DeviceUnit->Sectors;
+    Geometry->BytesPerSector = DeviceUnit->SectorSize;
 
     return TRUE;
 }
@@ -515,8 +122,19 @@ XboxDiskGetDriveGeometry(UCHAR DriveNumber, PGEOMETRY Geometry)
 ULONG
 XboxDiskGetCacheableBlockCount(UCHAR DriveNumber)
 {
-    /* 64 seems a nice number, it is used by the machpc code for LBA devices */
-    return 64;
-}
+    PDEVICE_UNIT DeviceUnit = NULL;
+
+    TRACE("XboxDiskGetCacheableBlockCount(0x%x)\n", DriveNumber);
 
-/* EOF */
+    if (!XboxDiskDriveNumberToDeviceUnit(DriveNumber, &DeviceUnit))
+        return 0;
+
+    /*
+     * If LBA is supported then the block size will be 64 sectors (32k)
+     * If not then the block size is the size of one track.
+     */
+    if (DeviceUnit->Flags & ATA_DEVICE_LBA)
+        return 64;
+    else
+        return DeviceUnit->Sectors;
+}