248 lines
8.1 KiB
Markdown
248 lines
8.1 KiB
Markdown
# 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.
|
|
|
|
```rust
|
|
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
|
|
|
|
|
|
```rust
|
|
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
|
|
|
|
|
|
```rust
|
|
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
|
|
```rust
|
|
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. |