summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--kernel/drivers/ata.c58
-rw-r--r--kernel/include/comus/drivers/ata.h1
2 files changed, 34 insertions, 25 deletions
diff --git a/kernel/drivers/ata.c b/kernel/drivers/ata.c
index 6f53d04..2fc059f 100644
--- a/kernel/drivers/ata.c
+++ b/kernel/drivers/ata.c
@@ -252,6 +252,7 @@ static enum ide_error ide_channel_poll(struct ide_channel *channel,
if (advanced_check) {
uint8_t state = ide_channel_read(channel, ATA_REG_STATUS);
+ // check for errors or faults
if (state & ATA_SR_ERROR) {
return IDE_ERROR_POLL_STATUS_REGISTER_ERROR;
}
@@ -260,7 +261,7 @@ static enum ide_error ide_channel_poll(struct ide_channel *channel,
return IDE_ERROR_POLL_DEVICE_FAULT;
}
- // BSY = 0; DF = 0; ERR = 0 so we should check for DRQ now.
+ // then check if drive is ready
if ((state & ATA_SR_DRIVEREQUESTREADY) == 0) {
return IDE_ERROR_POLL_DRIVE_REQUEST_NOT_READY;
}
@@ -322,7 +323,7 @@ static void ide_error_print(struct ide_device *dev, const enum ide_error err)
static void ide_initialize(uint32_t BAR0, uint32_t BAR1, uint32_t BAR2,
uint32_t BAR3, uint32_t BAR4)
{
- // 1- Detect I/O Ports which interface IDE Controller:
+ // calculate which io ports interface with the IDE controller
ide_channels[ATA_PRIMARY] = (struct ide_channel){
.io_base = (BAR0 & 0xFFFFFFFC) + 0x1F0 * (!BAR0),
.control_base = (BAR1 & 0xFFFFFFFC) + 0x3F6 * (!BAR1),
@@ -334,11 +335,13 @@ static void ide_initialize(uint32_t BAR0, uint32_t BAR1, uint32_t BAR2,
.bus_master_ide_base = (BAR4 & 0xFFFFFFFC) + 8,
};
- // 2- Disable IRQs:
+ // disable irqs
ide_channel_write(channel(ATA_PRIMARY), ATA_REG_CONTROL, 2);
ide_channel_write(channel(ATA_SECONDARY), ATA_REG_CONTROL, 2);
- // 3- Detect ATA-ATAPI Devices:
+ // detect disks by writing CMD_IDENTIFY to each one and checking for err.
+ // if device exists, ask for its ID space and copy out info about the
+ // device into the ide_device struct
uint32_t device_count = 0;
for (uint8_t channel_idx = 0; channel_idx < 2; channel_idx++) {
// drive idx is like device_count but it starts at 0 per channel
@@ -362,7 +365,7 @@ static void ide_initialize(uint32_t BAR0, uint32_t BAR1, uint32_t BAR2,
kspin_milliseconds(1);
if (ide_channel_read(chan, ATA_REG_STATUS) == 0) {
- continue; // if status == 0, no device.
+ continue; // if status == 0, no device
}
bool ata_err = false;
@@ -383,7 +386,7 @@ static void ide_initialize(uint32_t BAR0, uint32_t BAR1, uint32_t BAR2,
}
}
- // probe for ATAPI devices, if needed
+ // probe for ATAPI devices, though they aren't implemented
uint8_t type = IDE_ATA;
if (ata_err) {
uint8_t cl = ide_channel_read(chan, ATA_REG_LBA1);
@@ -396,7 +399,7 @@ static void ide_initialize(uint32_t BAR0, uint32_t BAR1, uint32_t BAR2,
WARN("ATAPI device found but ATAPI is not supported");
type = IDE_ATAPI;
} else {
- // unknown type (may not be a device).
+ // unknown type (may not be a device?)
continue;
}
@@ -425,16 +428,16 @@ static void ide_initialize(uint32_t BAR0, uint32_t BAR1, uint32_t BAR2,
// get size (depends on address mode):
if (dev->supported_command_sets & (1 << 26)) {
- // device uses 48-bit addressing:
+ // lba48
dev->size_in_sectors =
*((uint32_t *)(id_space_buf + ATA_IDENT_MAX_LBA_EXT));
} else {
- // device uses CHS or 28-bit dddressing:
+ // lba28
dev->size_in_sectors =
*((uint32_t *)(id_space_buf + ATA_IDENT_MAX_LBA));
}
- // string indicates model of device (Western Digital HDD, SONY DVD-RW...)
+ // string indicates model of device like "Western Digital HDD" etc
for (uint8_t i = 0; i < 40; i += 2) {
dev->model_str[i] = id_space_buf[ATA_IDENT_MODEL + i + 1];
dev->model_str[i + 1] = id_space_buf[ATA_IDENT_MODEL + i];
@@ -460,13 +463,13 @@ enum access_mode {
static uint8_t get_ata_cmd_for_access(enum lba_mode lba_mode,
enum access_mode mode)
{
- // routine that is followed:
- // If ( DMA & LBA48) DO_DMA_EXT;
- // If ( DMA & LBA28) DO_DMA_LBA;
- // If ( DMA & LBA28) DO_DMA_CHS;
- // If (!DMA & LBA48) DO_PIO_EXT;
- // If (!DMA & LBA28) DO_PIO_LBA;
- // If (!DMA & !LBA#) DO_PIO_CHS;
+ // outline of the algorithm:
+ // If ( dma & lba48) DO_DMA_EXT;
+ // If ( dma & lba28) DO_DMA_LBA;
+ // If ( dma & lba28) DO_DMA_CHS;
+ // If (!dma & lba48) DO_PIO_EXT;
+ // If (!dma & lba28) DO_PIO_LBA;
+ // If (!dma & !lba#) DO_PIO_CHS;
if (mode == READ) {
switch (lba_mode) {
@@ -500,7 +503,7 @@ static uint8_t get_ata_cmd_for_access(enum lba_mode lba_mode,
// if (lba_mode == 2 && dma == 1 && direction == 1)
// cmd = ATA_CMD_WRITE_DMA_EXT;
}
- // NOTE: unreachable
+ panic("unreachable");
return -1;
}
@@ -520,7 +523,8 @@ static enum ide_error ide_device_ata_access(struct ide_device *dev,
ide_channel_write(chan, ATA_REG_CONTROL,
chan->no_interrupt = (ide_irq_invoked = 0x0) + 0x02);
- // select one from LBA28, LBA48 or CHS
+ // select one from lba28, lba48 or CHS, and fill lba_io with the parameters
+ // for the disk access command
if (lba >= 0x10000000 || numsects > UINT8_MAX) {
// drive should support LBA in this case, or you are giving a bad LBA
lba_mode = LBA48;
@@ -561,7 +565,7 @@ static enum ide_error ide_device_ata_access(struct ide_device *dev,
if (dev->drive_idx > 1)
panic("unexpected drive_idx");
- // select Drive from the controller
+ // select our drive
if (lba_mode == CHS) {
ide_channel_write(chan, ATA_REG_HDDEVSEL,
0xA0 | (dev->drive_idx << 4) | head);
@@ -572,7 +576,7 @@ static enum ide_error ide_device_ata_access(struct ide_device *dev,
ide_channel_write(chan, ATA_REG_HDDEVSEL, 0x40 | (dev->drive_idx << 4));
}
- // write Parameters
+ // actually write the parameters
if (lba_mode == LBA48) {
ide_channel_write(chan, ATA_REG_SECCOUNT1, (numsects >> 8) & 0xff);
ide_channel_write(chan, ATA_REG_LBA3, lba_io[3]);
@@ -589,7 +593,7 @@ static enum ide_error ide_device_ata_access(struct ide_device *dev,
// TODO: if (dma) { ... } else {
if (mode == READ) {
- // PIO read
+ // just read all the bytes of the sectors out of the io port
for (size_t i = 0; i < numsects; i++) {
enum ide_error ret = ide_channel_poll(chan, 1);
if (ret)
@@ -599,7 +603,7 @@ static enum ide_error ide_device_ata_access(struct ide_device *dev,
rep_inw(chan->io_base, &buf[i * 256], 256);
}
} else {
- // PIO write
+ // just write all the bytes of the sectors into the io port
for (size_t i = 0; i < numsects; i++) {
enum ide_error err = ide_channel_poll(chan, 0);
#if LOG_LEVEL >= LOG_LVL_WARN
@@ -610,13 +614,15 @@ static enum ide_error ide_device_ata_access(struct ide_device *dev,
#endif
rep_outw(chan->io_base, &buf[i * 256], 256);
}
+
+ // flush the cache to fully complete the write
ide_channel_write(chan, ATA_REG_COMMAND,
(uint8_t[]){ ATA_CMD_CACHE_FLUSH, ATA_CMD_CACHE_FLUSH,
ATA_CMD_CACHE_FLUSH_EXT }[lba_mode]);
enum ide_error err = ide_channel_poll(chan, 0);
#if LOG_LEVEL >= LOG_LVL_WARN
if (err) {
- WARN("DRIVE WRITE FAILED:");
+ WARN("DRIVE WRITE FAILED, CACHE FLUSH ERR:");
ide_error_print(dev, err);
}
#endif
@@ -647,7 +653,9 @@ enum ide_error ide_device_read_sectors(ide_device_t dev_identifier,
// for (i = 0; i < numsects; i++)
// err = ide_atapi_read(drive, lba + i, 1, es, edi + (i*2048));
//panic("atapi unimplemented- todo");
- return 1;
+
+ // soft error instead of panic
+ return IDE_ERROR_UNIMPLEMENTED;
}
if (err) {
diff --git a/kernel/include/comus/drivers/ata.h b/kernel/include/comus/drivers/ata.h
index c404d84..c9ef207 100644
--- a/kernel/include/comus/drivers/ata.h
+++ b/kernel/include/comus/drivers/ata.h
@@ -27,6 +27,7 @@ enum ide_error {
IDE_ERROR_POLL_DEVICE_FAULT,
IDE_ERROR_POLL_STATUS_REGISTER_ERROR,
IDE_ERROR_POLL_WRITE_PROTECTED,
+ IDE_ERROR_UNIMPLEMENTED,
};
struct ide_devicelist {