//////////////////////////////////////////////////////////////////////////////// // // Microsoft Research Singularity // // Copyright (c) Microsoft Corporation. All rights reserved. // // File: ATA6.cs // // Base Classes and Interfaces for interacting with ATA // // References used: // "AT Attachment with Packet Interface with Extension 6 (ATA/ATAPI-6-)", // ISO Working Group T13, http://www.t13.org/ // using System; using System.Text; using System.Threading; using Microsoft.SingSharp; using Microsoft.Singularity; using Microsoft.Singularity.Io; using Microsoft.Singularity.Drivers.IDE; using Microsoft.Singularity.V1.Services; using Microsoft.Contracts; namespace Microsoft.Singularity.Drivers.IDE { [CLSCompliant(false)] public class IdeDiskConfig { public IdeConfig ControllerConfig; public byte DiskNumber; public bool Atapi; public String! DeviceName; public String! Id; public IdeDiskConfig(IdeConfig config, byte num, String! deviceName, bool atapi) { ControllerConfig = config; DiskNumber = num; Atapi = atapi; Id = "/ata/disk"; DeviceName = deviceName; // Used to be "/dev/disk0", but now we use the instance name. base(); } } public class IdeConfig { public IoIrqRange Interrupt; public bool UseDma; public IoPortRange DmaBase; public IoPortRange CommandBase; public IoPortRange ControlBase; public IdeController! IdeController; public BusMasterDma BusMasterDma; public IoIrq/*[!]*/ Irq; public AutoResetEvent/*[!]*/ CommandEndEvent; public AutoResetEvent/*[!]*/ IdentifyEndEvent; public String Id; public IdeConfig(IoIrqRange! interrupt, IoPortRange! command, IoPortRange! control, bool useDma, IoPortRange! bmBaseAddr, [Delayed] IdeController! ideController ) { Interrupt = interrupt; CommandBase = command; ControlBase = control; UseDma = useDma; DmaBase = bmBaseAddr; IdeController = ideController; Id = "/ata/controller"; Tracing.Log(Tracing.Debug,"IdeConfig: INT={1} cmd={2:x4}, ctrl={3:x4}, DMA@{4:x4}\n", (UIntPtr)interrupt.Irq, (UIntPtr)command.Port, (UIntPtr)control.Port, (UIntPtr)bmBaseAddr.Port); } } [CLSCompliant(false)] public struct IdentifyDeviceInformation // Information Returned to host via the IdentifyDeviceInformation command { public bool RemovableMediaDevice; // Word 0, Bit 7 public bool RemovableController; // Word 0, Bit 6 public ushort CylinderCount; // word 1 public ushort HeadCount; // word 3 public ushort SectorCountPerTrack; // Word 6 public string SerialNumber; // Words 10 to 19 public ushort NumberOfBytesAvailInVendorCommand; // Word 22 public string FirmwareRevision; // Words 23 to 26 public string ModelNumber; // Words 27 to 47 public bool SupportsMultiple; // Word 47, bits 7 to 0 == 0 public ushort MaximumMultipleSectorCount; // Word 47, bits 7 to 0 public bool StandbyTimer; // Word 49, bit 13 public bool IORDYSupported; // Word 49, bit 11 public bool IORDYDisableable; // Word 49, bit 10 public bool LBASupported; // Word 49, bit 9 public bool DMASupported; // Word 49, bit 8 public bool Word88Valid; // Word 53, bit 2 public bool UltraDmaSupported; // Word 53, bit 2 (same) public bool Words64to70Valid; // Word 53, bit 1 public bool Words54to58Valid; // Word 53, bit 0 // Words 54-58 are valid if word 53, bit 0 is set. public ushort CurrentLogicalCylinderCount; // Word 54 public ushort CurrentLogicalHeadCount; // Word 55 public ushort CurrentLogicalSectorCount; // Word 56 public uint CurrentCapacityInSectors; // Word 57-58 public bool MultipleSectorSettingValid; // Word 59, bits 8 public ushort CurrentSectorCountPerInterrupt; // Word 59 public uint TotalAddressableSectors; // Word 60-61 public ushort MultiwordDMATransferMode; // Word 63, 15-8 public ushort MultiwordDMATransferModes; // Word 63, 7-0 // Words 64-70 are valid if word 53, bit 1 is set. public ushort PIODMATransferModes; // Word 64, bits 7-0 public ushort MinimumMultiwordDMACycleTime; // in nanoseconds Word 65 public ushort RecommendedMultiwordDMACycleTime; // in nanoseconds Word 66 public ushort MinimumPIOCycleTimeWithFlowControl; // in nanoseconds Word 67 public ushort MinimumPIOCycleTimeWithIORDY; // in nanoseconds Word 68 public ushort QueueDepth; // word 75, value == depth-1 public ushort MajorVersion; //word 80 public ushort MinorVersion; //word 81 public ushort FeatureSet1Supported; public bool NOPSupported; // word 82, bit 14 public bool ReadBufferSupported; // word 82, bit 13 public bool WriteBufferSupported; // word 82, bit 12 public bool HostProtectedAreaSupported; // word 82, bit 10 public bool DeviceResetSupported; // word 82, bit 9 public bool ServiceInterruptSupported; // word 82, bit 8 public bool ReleaseInterruptSupported; // word 82, bit 7 public bool LookAheadSupported; // word 82, bit 6 public bool WriteCacheSupported; // word 82, bit 5 public bool PacketSupported; // word 82, bit 4 public bool PowerManagementSupported; // word 82, bit 3 public bool RemovableMediaSupported; // word 82, bit 2 public bool SecurityModeSupported; // word 82, bit 1 public bool SmartSupported; // word 82, bit 0 public ushort FeatureSet2Supported; public bool FlushCacheExtSupported; // word 83, bit 13 public bool FlushCacheSupported; // word 83, bit 12 public bool DeviceConfigurationOverlaySupported; // word 83, bit 11 public bool LBA48Supported; // word 83, bit 10 public bool AutomaticAcousticManagementSupported; // word 83, bit 9 public bool SetMaxSecuritySupported; // word 83, bit 8 public bool AddressOffsetrAreaBootSupported; // word 83, bit 7 public bool SetFeaturesSupported; // word 83, bit 6 public bool PowerUpInStandbySupported; // word 83, bit 5 public bool RemovableMediaStatusNotificationSupported; // word 83, bit 4 public bool APMSupported; // word 83, bit 3 public bool CFASupported; // word 83, bit 2 public bool QueuedDMASupported; // word 83, bit 1 public bool DownloadMicrocodeSupported; // word 83, bit 0 public ushort FeatureSet3Supported; public bool GeneralPurposeLoggingSupported; // word 83, bit 5 public bool MediaCardPssThroughSupported; // word 83, bit 3 public bool MediaSerialNumberSupported; // word 83, bit 2 public bool SmartSelfTestSupported; // word 83, bit 1 public bool SmartErrorLogSupported; // word 83, bit 0 public bool EnabledDataValid; // word 87, bits 15,14 (0x8000) public ushort FeatureSet1Enabled; public bool NOPEnabled; // word 85, bit 14 public bool ReadBufferEnabled; // word 85, bit 13 public bool WriteBufferEnabled; // word 85, bit 12 public bool HostProtectedAreaEnabled; // word 85, bit 10 public bool DeviceResetEnabled; // word 85, bit 9 public bool ServiceInterruptEnabled; // word 85, bit 8 public bool ReleaseInterruptEnabled; // word 85, bit 7 public bool LookAheadEnabled; // word 85, bit 6 public bool WriteCacheEnabled; // word 85, bit 5 public bool PacketEnabled; // word 85, bit 4 public bool PowerManagementEnabled; // word 85, bit 3 public bool RemovableMediaEnabled; // word 85, bit 2 public bool SecurityModeEnabled; // word 85, bit 1 public bool SmartEnabled; // word 85, bit 0 public ushort FeatureSet2Enabled; public bool FlushCacheExtEnabled; // word 86, bit 13 public bool FlushCacheEnabled; // word 86, bit 12 public bool DeviceConfigurationOverlayEnabled; // word 86, bit 11 public bool LBA48Enabled; // word 86, bit 10 public bool AutomaticAcousticManagementEnabled; // word 86, bit 9 public bool SetMaxSecurityEnabled; // word 86, bit 8 public bool AddressOffsetrAreaBootEnabled; // word 86, bit 7 public bool SetFeaturesEnabled; // word 86, bit 6 public bool PowerUpInStandbyEnabled; // word 86, bit 5 public bool RemovableMediaStatusNotificationEnabled; // word 86, bit 4 public bool APMEnabled; // word 86, bit 3 public bool CFAEnabled; // word 86, bit 2 public bool QueuedDMAEnabled; // word 86, bit 1 public bool DownloadMicrocodeEnabled; // word 86, bit 0 public ushort FeatureSet3Enabled; public bool GeneralPurposeLoggingEnabled; // word 87, bit 5 public bool MediaCardPssThroughEnabled; // word 87, bit 3 public bool MediaSerialNumberEnabled; // word 87, bit 2 public bool SmartSelfTestEnabled; // word 87, bit 1 public bool SmartErrorLogEnabled; // word 87, bit 0 //word 88 UltraDMA public ushort UltraDmaModes; //word 88 public byte HighestUltraDmaMode; // Highest UDMA mode supported; public bool UltraDmaMode5Selected; //word 88. bit 13 public bool UltraDmaMode4Selected; //word 88. bit 12 public bool UltraDmaMode3Selected; //word 88. bit 11 public bool UltraDmaMode2Selected; //word 88. bit 10 public bool UltraDmaMode1Selected; //word 88. bit 9 public bool UltraDmaMode0Selected; //word 88. bit 8 public bool UltraDmaMode5Supported; //word 88. bit 5 public bool UltraDmaMode4Supported; //word 88. bit 4 public bool UltraDmaMode3Supported; //word 88. bit 3 public bool UltraDmaMode2Supported; //word 88. bit 2 public bool UltraDmaMode1Supported; //word 88. bit 1 public bool UltraDmaMode0Supported; //word 88. bit 0 public ulong MaxLBASectors; //words 100-103 } #region ATA6 public class ATA6 { internal static string WordsToString(ushort[]! DriveData, int Start, int End) { int iter; int length = End - Start; ASCIIEncoding xlate = new ASCIIEncoding(); byte[] tempBuffer = new byte[(End - Start) * 2]; for (iter = 0; iter < length; iter++) { tempBuffer[iter * 2 + 1] = (byte)(DriveData[Start + iter] & (ushort)0xFF); tempBuffer[iter * 2] = (byte)((DriveData[Start + iter] >> 8) & (ushort)0xFF); } string ret = xlate.GetString(tempBuffer); if (ret != null) { ret = ret.Trim(); } return ret; } static byte HighestBitSet(ushort uiBits) { ushort uiMask = 0x80; for (ushort nBit = 8; nBit > 0; nBit--, uiMask >>= 1) { if ( (uiBits & uiMask) > 0 ) { return (byte)nBit; } } return 0; } //public static uint MAX_SUPPORTED_SECTORS = 2048 * 128; //public static uint MAX_SUPPORTED_SECTORS = 16383 * 16 * 63; public static IdentifyDeviceInformation ParseIdentifyInformation(ushort[]! DriveData) { IdentifyDeviceInformation temp = new IdentifyDeviceInformation(); temp.RemovableMediaDevice = (DriveData[0] & (1<<7)) > 0; temp.CylinderCount = DriveData[1]; temp.HeadCount = DriveData[3]; temp.SectorCountPerTrack = DriveData[6]; temp.SerialNumber = WordsToString(DriveData, 10, 19); temp.NumberOfBytesAvailInVendorCommand = DriveData[22]; temp.FirmwareRevision = WordsToString(DriveData, 23, 26); temp.ModelNumber = WordsToString(DriveData, 27, 46); if ((DriveData[47] & (0xFF)) == 0) { temp.SupportsMultiple = false; } else { temp.SupportsMultiple = true; temp.MaximumMultipleSectorCount = (ushort)(DriveData[47] & 0xFF); } temp.StandbyTimer = ((DriveData[49] & (1 << 13))) > 0; temp.IORDYSupported = ((DriveData[49] & (1 << 11))) > 0; temp.IORDYDisableable = ((DriveData[49] & (1 << 10))) > 0; temp.LBASupported = ((DriveData[49] & (1 << 9))) > 0; temp.DMASupported = ((DriveData[49] & (1 << 8))) > 0; //UltraDMA supported temp.Word88Valid = ((DriveData[53] & (1 << 2))) > 0; temp.UltraDmaSupported = temp.Word88Valid; //this bit should always be true unless device is CFA or PCMCIA temp.Words64to70Valid = ((DriveData[53] & (1 << 1))) > 0; //obsolete temp.Words54to58Valid = ((DriveData[53] & (1 << 0))) > 0; // word 59: multiple sector setting temp.MultipleSectorSettingValid = (DriveData[59] & (1 << 8)) > 0; temp.CurrentSectorCountPerInterrupt = (ushort)(DriveData[59] & 0xFF); // words 60,61: Total # of addressable sectors (+1) temp.TotalAddressableSectors = ((uint)DriveData[61] << 16) | (uint)DriveData[60]; #if obsolete if (temp.TotalAddressableSectors > MAX_SUPPORTED_SECTORS) { temp.TotalAddressableSectors = MAX_SUPPORTED_SECTORS; } #endif // word 63: should be 0 if UltraDMA is supported // bit 10: MDMA mode 2 selected // bit 09: MDMA mode 1 selected // bit 08: MDMA mode 0 selected // bit 02: MDMA mode 2 supported // bit 01: MDMA mode 1 supported // bit 00: MDMA mode 0 supported temp.MultiwordDMATransferMode = (ushort)((DriveData[63] & 0xFF00) >> 8); temp.MultiwordDMATransferModes = (ushort)(DriveData[63] & 0xFF); temp.PIODMATransferModes = (ushort)(DriveData[64] & 0xFF); temp.MinimumMultiwordDMACycleTime = DriveData[65]; temp.RecommendedMultiwordDMACycleTime = DriveData[66]; temp.MinimumPIOCycleTimeWithFlowControl = DriveData[67]; temp.MinimumPIOCycleTimeWithIORDY = DriveData[68]; // value == maximum queue depth -1 (max = 31 +1) temp.QueueDepth = (ushort)(DriveData[75] & 0x1F); temp.MajorVersion = DriveData[80]; temp.MinorVersion = DriveData[81]; //Feature sets temp.FeatureSet1Supported = DriveData[82]; temp.FeatureSet2Supported = DriveData[83]; temp.FeatureSet3Supported = DriveData[84]; temp.FeatureSet1Enabled = DriveData[85]; temp.FeatureSet2Enabled = DriveData[86]; temp.FeatureSet3Enabled = DriveData[87]; temp.LBA48Supported = ((DriveData[83] & (1 << 10))) > 0; temp.LBA48Enabled = ((DriveData[86] & (1 << 10))) > 0; temp.QueuedDMASupported = ((DriveData[83] & (1 << 1))) > 0; temp.QueuedDMAEnabled = ((DriveData[86] & (1 << 1))) > 0; if (temp.UltraDmaSupported) { temp.UltraDmaModes = DriveData[88]; temp.HighestUltraDmaMode = (byte) (HighestBitSet((ushort)(temp.UltraDmaModes & 0x3f)) - (byte) 1); } if (temp.LBA48Supported) { temp.MaxLBASectors = ((ulong)DriveData[103] << 48) | ((ulong)DriveData[102] << 32) | ((ulong)DriveData[101] << 16) | (ulong)DriveData[100]; DebugStub.WriteLine("Disk Device supports LBA 48\n"); DebugStub.WriteLine("Total LBA sectors ={0}",__arglist(temp.MaxLBASectors)); //controller.WriteCommandPort( (byte) ATA6.IdeCommand.ReadNativeMaxAddressExt); //controller.Delay400ns(); //DebugStub.WriteLine("ReadNativeMaxAddressExt:"); //ShowOffsetAndCount(); } else { temp.MaxLBASectors = temp.TotalAddressableSectors; } if (temp.UltraDmaSupported) { DebugStub.WriteLine("Disk Device supports Ultra DMA modes={0:x4},highest={1}", __arglist(temp.UltraDmaModes,temp.HighestUltraDmaMode)); } return temp; } public static IdentifyDeviceInformation GetDeviceIdentification(IdeController! controller, int devsel, bool atapi) { ushort[] identifyData = new ushort[256]; if (!controller.PollBSY(false)) { // should fail here. } controller.SelectDevice(devsel, atapi); //DebugStub.Print(" IDE GetDeviceIdentification starting\n"); bool iflag = Processor.DisableInterrupts(); try { controller.SetIdentifyInProgress(true); controller.PollDRDY(true); byte cmd = (atapi)? (byte)IdeCommand.IdentifyPacketDevice: (byte)IdeCommand.IdentifyDevice; controller.WriteCommandPort(cmd); //will post interrupt controller.Delay400ns(); Tracing.Log(Tracing.Debug,"status={0}",(UIntPtr) controller.ReadFullStatus()); controller.PollDRDY(true); // Device indicates ready. } finally { Processor.RestoreInterrupts(iflag); } IdeConfig config = controller.GetConfig(); bool success = (config != null) && config.IdentifyEndEvent.WaitOne(TimeSpan.FromMilliseconds(250)); if (!success) { //DebugStub.Break(); Tracing.Log(Tracing.Debug," IDE GetDeviceIdentification did NOT receive interrupt\n"); controller.SetIdentifyInProgress(false); } //DebugStub.Print(" IDE GetDeviceIdentification received interrupt\n"); // XXX: We should check for an Error condition here. // XXX: We should check for the ATAPI signature here. byte statusBits = controller.ReadAlternateStatusPort(); if ((statusBits & (byte)ATA6.IdeStatus.ERR) > 0) { Tracing.Log(Tracing.Debug,"ERR reported in status after IdentifyDevice!\n"); DebugStub.Break(); } for (int i = 0; i < 256; i++) { identifyData[i] = controller.ReadDataPort(); } IdentifyDeviceInformation ident = ParseIdentifyInformation(identifyData); //// if (atapi) if (ident.ModelNumber == "Virtual CD") // SECTOR_SIZE is actually 2048 ident.MaxLBASectors = 650 * 1024 * 1024 / IdeRequest.SECTOR_SIZE; // for IdeDisk::ReadWrite tests return ident; } public static void DebugQueryStatus(IdeController! controller) { byte statusBits = controller.ReadAlternateStatusPort(); byte errorBits = controller.ReadErrorPort(); Tracing.Log(Tracing.Debug,"ATAcontroller: Status Register({0:x2}): ",statusBits); Tracing.Log(Tracing.Debug, ((statusBits & (byte) ATA6.IdeStatus.BSY) > 0) ? "BSY " : "!bsy "); Tracing.Log(Tracing.Debug, ((statusBits & (byte)ATA6.IdeStatus.DRDY) > 0) ? "DRDY " : "!drdy "); Tracing.Log(Tracing.Debug, ((statusBits & (byte)ATA6.IdeStatus.DWF) > 0) ? "DWF " : "!dwf "); Tracing.Log(Tracing.Debug, ((statusBits & (byte)ATA6.IdeStatus.DSC) > 0) ? "DSC " : "!dsc "); Tracing.Log(Tracing.Debug, ((statusBits & (byte)ATA6.IdeStatus.DRQ) > 0) ? "DRQ " : "!drq "); Tracing.Log(Tracing.Debug, ((statusBits & (byte)ATA6.IdeStatus.CORR) > 0) ? "CORR " : "!corr "); Tracing.Log(Tracing.Debug, ((statusBits & (byte)ATA6.IdeStatus.IDX) > 0) ? "IDX " : "!idx"); Tracing.Log(Tracing.Debug, ((statusBits & (byte)ATA6.IdeStatus.ERR) > 0) ? "ERR " : "!err "); Tracing.Log(Tracing.Debug,"\n"); Tracing.Log(Tracing.Debug,"ATAcontroller: Error Register:({0:x2}): ",errorBits); Tracing.Log(Tracing.Debug, ((errorBits & (byte)ATA6.IdeError.UNC) > 0) ? "UNC " : "!unc "); Tracing.Log(Tracing.Debug, ((errorBits & (byte)ATA6.IdeError.MC) > 0) ? "MC " : "!mc "); Tracing.Log(Tracing.Debug, ((errorBits & (byte)ATA6.IdeError.IDNF) > 0) ? "IDNF " : "!idnf "); Tracing.Log(Tracing.Debug, ((errorBits & (byte)ATA6.IdeError.ABRT) > 0) ? "ABRT " : "!abrt "); Tracing.Log(Tracing.Debug, ((errorBits & (byte)ATA6.IdeError.MCR) > 0) ? "MCR " : "!mcr "); Tracing.Log(Tracing.Debug, ((errorBits & (byte)ATA6.IdeError.TK0NF) > 0) ? "TK0NF " : "!tk0nf "); Tracing.Log(Tracing.Debug, ((errorBits & (byte)ATA6.IdeError.AMNF) > 0) ? "AMNF " : "!amnf "); Tracing.Log(Tracing.Debug,"\n"); ushort lbaLow = controller.ReadLBALowPort(); ushort lbaMid = controller.ReadLBAMidPort(); ushort lbaHigh = controller.ReadLBAHighPort(); Tracing.Log(Tracing.Debug,"LBA={0:x2},{1:x2},{2:x2}\n", (UIntPtr)lbaHigh, (UIntPtr)lbaMid, (UIntPtr)lbaLow); } public enum IdeCommand { Nop = 0x00, Read = 0x20, ReadNoRetry = 0x21, ReadLong = 0x22, ReadLongNoRetry = 0x23, ReadDmaExt = 0x25, ReadDmaQueuedExt = 0x26, ReadNativeMaxAddressExt = 0x27, Write = 0x30, WriteNoRetry = 0x31, WriteLong = 0x32, WriteLongNoRetry = 0x33, WriteDmaExt = 0x35, WriteDmaQueuedExt = 0x36, WriteVerify = 0x3C, ReadVerify = 0x40, ReadVerifyNoRetry = 0x41, FormatTrack = 0x50, Seek = 0x70, ExecuteDeviceDiagnostic = 0x90, InitializeDeviceParameters = 0x91, DownloadMicrocode = 0x92, AtapiPacket = 0xA0, IdentifyPacketDevice = 0xA1, ReadMultiple = 0xC4, WriteMultiple = 0xC5, SetMultipleMode = 0xC6, ReadDmaQueued = 0xC7, ReadDmaRetry = 0xC8, ReadDmaNoRetry = 0xC9, WriteDmaRetry = 0xCA, WriteDmaNoRetry = 0xCB, WriteDmaQueued = 0xCC, AcknowledgeMediaChange = 0xDB, BootPostBoot = 0xDC, BootPreBoot = 0xDD, DoorLock = 0xDE, DoorUnLock = 0xDF, ReadBuffer = 0xE4, WriteBuffer = 0xE8, WriteSame = 0xE9, IdentifyDevice = 0xEC, MediaEject = 0xED, SetFeature = 0xEF, } public enum Atapi : byte { DMA = 0x01, Read = 0x28, } public enum IdeStatus : byte { BSY = 0x80, DRDY = 0x40, DWF = 0x20, DSC = 0x10, DRQ = 0x08, CORR = 0x04, IDX = 0x02, ERR = 0x01, } public enum IdeError { UNC = 0x40, MC = 0x20, IDNF = 0x10, ABRT = 0x08, MCR = 0x04, TK0NF = 0x02, AMNF = 0x01, } public const byte DriveSelect = 0x10; // Low = Master, High = Slave public const bool High = true; public const bool Low = false; public const byte DeviceControlSRST = 0x04; public const byte DeviceControlnIEN = 0x02; // note active low // High Order Bit, used to read LBA 48 "previous" values in low,mid,and high port queues public const byte DeviceControlHOB = 0x80; } #endregion }