8.1 KiB
ATA, NVMe, SATA, Floppy Disks and Optical Drives; Storing my own personal hell
A storage media would reasonably have two features
Store
or write
Load
or read
depending on your favored terminology.
Alright let us learn about ATA first because it is alphabetically first!
ATA
IDE is used mostly interchangably with ATA but IDE is the physical transmission not the protocol name. Subtle but important difference here down at the bottom.
ATA seems to have multiple ways of Store
ing and Load
ing data.
Oh joy!
SATA and PATA
SATA is a new standard for data transmission it stands for Serial AT Attachment All old ATA devices are retroactively named PATA and it stands for (Parallel) ATA
The vast majority of SATA devices also support AHCI. AHCI was developed by intel to help handle SATA devices
To determine if an ATA device is a SATA device you send a standard IDENTIFY command (as specified by P/ATA) to the drive (0xEC) it responds with an ERR and a status pair...
Ok thats insane but sure...
It also seems there are 2-3 different standards for Store
ing and Load
ing data in SATA mode.
Lets assume for my sake and yours, dear reader, that the API is identical for these modes.
Let us define a simple API to interact with these devices.
pub struct DiskIO {
@documentation("The pointer is a pointer into the DISK addressing")
read: function(pointer: u64, length: u64) -> Vector<u8>;
@validator(data: data.len() > 0)
@documentation("The pointer is a pointer into the DISK addressing, the Vector must be u8s and must atleast have one u8")
write: function(pointer: u64, data: Vector<u8>) -> None;
}
Lets move on to the older more legacy saner(?) ATA PIO Mode
ATA PIO Mode
ATA is a hack on an older specification named ST506 (Side note: I WILL NOT be addressing this)
The only difference anyways is the controller being moved on board and one less cable.
When accessing a disk the cpu shorts a pin and sets which disk of the master/slave pair is being accessed
Once a command has been submitted you may poll the drive to check the status of the command. You MUST poll 15 times OR delay by 400 nanoseconds after a command is submitted for it to complete. If you send a command to a drive before 400ns are up you can destroy the controller on badly made drives or just mess up the previous command on better behaving more lieniant devices.
On some drives it is a requirement to flush the hardware cache after each write if this is not done you can create bad sectors until the drive is powercycled.
This is insane and should not be the case... A cache that is flushed after every write is not a cache that is worth using...
But! None-the-less we have a new concept called a hardware cache, and it has to sometimes be flushed by the driver.
Another API
pub struct DiskIO {
@documentation("Set this to false any time we write")
flushed_hw_cache: bool,
@documentation("The pointer is a pointer into the DISK addressing")
read: function(pointer: u64, length: u64) -> Vector<u8>;
@validator(data: data.len() > 0)
@documentation("The pointer is a pointer into the DISK addressing, the Vector must be u8s and must atleast have one u8")
write: function(pointer: u64, data: Vector<u8>) -> None;
@validator(flushed: false)
@documentation("Only to be called if we have not flushed yet")
flush_hw_cache: function(None) -> None;
}
Well that is less than ideal but atleast it gives us more control! EXCEPT on drives where we MUST flush after every write.
We will not be learning about addressing modes because I gave myself a headache looking at them.
Next!
ATAPI
ATAPI; Adding a lil SCSI to your ATA. Typically CD-ROM, CD-RW, DVD, or tape drive attatched to the ATA Bus use ATAPI.
This is included in drives that are ATA Version 6 or greater. We will not be adding an API to get the version as any file system interacting with the disk driver would presumably not need to know about the disk.
More magical methods of identification..
A new ATA Packet type.
And finally getting Disc Contents!
First we must ensure that the disk is readable.
This will be handled by the disk driver and will not be reported by the API as the device cannot be used by a filesystem driver if it is not readable.
secondly we check if the disk is writable.
This will be included in the API because CD-ROM media can be read only for example
Previously we assumed that disks had infinite storage because in the modern day disks are infinitly big compared to a CD-ROM. We will add in the api for getting size now. We will also add a free space for convenience
pub struct DiskIO {
@documentation("Set this to false any time we write")
flushed_hw_cache: bool,
@validator(size > 0)
@documentation("Size is in bytes and must be greater than zero")
size: u64,
@validator(size >= free_space)
free_space: u64,
@documentation("The pointer is a pointer into the DISK addressing")
read: function(pointer: u64, length: u64) -> Vector<u8>;
@validator(data: data.len() > 0)
@documentation("The pointer is a pointer into the DISK addressing, the Vector must be u8s and must atleast have one u8")
write: function(pointer: u64, data: Vector<u8>) -> None;
@validator(flushed: false)
@documentation("Only to be called if we have not flushed yet")
flush_hw_cache: function(None) -> None;
@documentation("Returns True if the disk is writeable.")
is_writeable: function(None) -> Bool;
}
ATA/ATAPI using DMA
There is no noticable API change here but therre is a noticable speed up over previous modes.
ATA in x86 RealMode (BIOS)
This adds nothing interesting and is only useful if you rely on BIOS calls. We do not.
Intermission One Act One
Well that was hell! Luckily thats over with and we move onto the simple things.
NVMe's!
NVMes
NVMes use the PCI bus to communicate.
Lets just check the spec real quick...
oh 458 pages
...dear me... and thats only for the Base specification. What ever that means Lets not look at that actually and glance over at the OSDev wiki, my favorite misinformed shit-show forum wiki combo.
NVMes :(
NVMes have a few registers to communicate back and forth with the driver.
11 registers of which 2 are static so 9 registers
with these registers you create an admin queue to create submission buffers to feed commands to the NVMe drive
The NVMe controller may process commands in any order it likes. oh dear
so you must figure out which commands cannot yet be submitted do to dependence on data from other commands yourself and have a second submission buffer queue....
What the FUCK! Please give me back any of the ATA modes.
Floppy Disks
3 modes because of different chipsets
most commands are silent, ala no status updates when complete. Great! more active polling, of the data this time not the disk
floppy disk controllers are configured via 9 registers that are IO memory mapped
depending on if you read or write to them you are accessing different registers FUCK THIS PLEASE BE NORMAL FOR ONE MINUTE
In real hardware floppies are incredibly unrealiable
so you are recommended to (write
then read
and compare) twice...
Intermission One Act Two
DiskIO.write(0, Vector("I am living in hell"));
// Oh and don't forget to flush the fucking cache
DiskIO.flush();
Optical Drives
Ahh back to the good old SCSI of the ATAPI minus the ATAPI packets alright.
So implement optical drives first
Random R+W operations on DVD and Bluray
Its just fucking magic ok.
SD Cards
SD Cards are predictably just as scuffed
Vendor Enhancements
Integrated Wi-Fi
No this cannot be real. We have to support Wi-Fi over DiskIO???????????? No We WILL not. Sorry the one person who needs this
Pre-loaded Content
What the actual fuck? Pre-loaded reserved content that is write protected...
oh and lets not forget DRM
Integrated USB Connector
This is just a built in sdcard reader usb combo
The sanest extension yet
Different colors
Similar to USB colors to identify card types
I actually like this and suggest others do this as well
Integrated display
Ok well thats it fools.