BarryServer : Git

All the code for all my projects
// BarryServer : Git / Orion / blob / 1628fcfdfdf2978ed9ccac96ee7d13bb3dc43a01 / drivers / ide / ide.c

// Related

Orion

Barry Importing existing Orion kernel d41a53c (2 years, 4 months ago)
/*
 * This file is the driver for the PCI IDE devices, which handles access to
 * ATA/ATAPI devices.  It detects the drives connected to the system, and
 * handles any access to them - with the ability to do DMA if possible.  This
 * driver will access the drives in the best available way, presenting a uniform
 * interface for any other code to use.  It also adds a device node to the DevFS
 * mount for every device, to provide access to the rest of the OS easily.
 */

#include <stdint.h>
#include <stddef.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <string.h>
#include <errno.h>
#include <time.h>
#include "../drivers.h"
#include "../pci.h"
#include "../../mem/frame.h"
#include "../../proc/proc.h"
#include "../../vfs/vfs.h"
#include "../../io.h"
#include "../../screen.h"

struct partition {
	uint8_t drive;
	uint8_t shead, ssect, scyl;
	uint8_t type;
	uint8_t ehead, esect, ecyl;
	uint32_t lba;
	uint32_t size;
};

size_t ata_read(File *file, char *buf, size_t size, off_t offset);
size_t ata_write(File *file, char *buf, size_t size, off_t offset);
int ata_open(File *file);

FileOps ideFileOps = {
	.read = ata_read,
	.write = ata_write,
	.open = ata_open,
};

Driver ideDriver = {
	.major = 2,
	.ops = &ideFileOps,
	.next = NULL,
};

page_t ataDmaArea;

uint8_t ide_read(uint8_t chan, uint8_t reg);
void ide_write(uint8_t chan, uint8_t reg, uint8_t data);

/* Status */
#define ATA_SR_BSY  0x80 /* Busy */
#define ATA_SR_DRDY 0x40 /* Drive ready */
#define ATA_SR_DF   0x20 /* Drive write fault */
#define ATA_SR_DSC  0x10 /* Drive seek complete */
#define ATA_SR_DRQ  0x08 /* Data request ready */
#define ATA_SR_CORR 0x04 /* Corrected data */
#define ATA_SR_IDX  0x02 /* Index */
#define ATA_SR_ERR  0x01 /* Error */

/* Error */
#define ATA_ER_BBK  0x80 /* Bad block */
#define ATA_ER_UNC  0x40 /* Uncorrectable data */
#define ATA_ER_MC   0x20 /* Media changed */
#define ATA_ER_IDNF 0x10 /* ID mark not found */
#define ATA_ER_MCR  0x08 /* Media change request */
#define ATA_ER_ABRT 0x04 /* Command aborted */
#define ATA_ER_T0NF 0x02 /* Track 0 not found */
#define ATA_ER_AMNF 0x01 /* No address mark */

/* Command */
#define ATA_CMD_READ_PIO        0x20
#define ATA_CMD_READ_PIO_EXT    0x24
#define ATA_CMD_READ_DMA        0xC8
#define ATA_CMD_READ_DMA_EXT    0x25
#define ATA_CMD_WRITE_PIO       0x30
#define ATA_CMD_WRITE_PIO_EXT   0x34
#define ATA_CMD_WRITE_DMA       0xCA
#define ATA_CMD_WRITE_DMA_EXT   0x35
#define ATA_CMD_CACHE_FLUSH     0xE7
#define ATA_CMD_CACHE_FLUSH_EXT 0xEA
#define ATA_CMD_PACKET          0xA0
#define ATA_CMD_IDENTIFY_PACKET 0xA1
#define ATA_CMD_IDENTIFY        0xEC

#define ATAPI_CMD_READ  0xA8
#define ATAPI_CMD_EJECT 0x1B

#define ATA_IDENT_DEVICETYPE     0
#define ATA_IDENT_CYLINDERS      2
#define ATA_IDENT_HEADS          6
#define ATA_IDENT_SECTORS       12
#define ATA_IDENT_SERIAL        20
#define ATA_IDENT_MODEL         54
#define ATA_IDENT_CAPABILITIES  98
#define ATA_IDENT_FIELDVALID   106
#define ATA_IDENT_MAX_LBA      120
#define ATA_IDENT_COMMANDSETS  164
#define ATA_IDENT_MAX_LBA_EXT  200

#define IDE_ATA       0
#define IDE_ATAPI     1
#define ATA_MASTER    0
#define ATA_SLAVE     1
#define ATA_PRIMARY   0
#define ATA_SECONDARY 1
#define ATA_READ      0
#define ATA_WRITE     1

/* Registers */
#define ATA_REG_DATA       0x0
#define ATA_REG_ERROR      0x1
#define ATA_REG_FEATURES   0x1
#define ATA_REG_SECCOUNT0  0x2
#define ATA_REG_LBA0       0x3
#define ATA_REG_LBA1       0x4
#define ATA_REG_LBA2       0x5
#define ATA_REG_HDDEVSEL   0x6
#define ATA_REG_COMMAND    0x7
#define ATA_REG_STATUS     0x7
#define ATA_REG_SECCOUNT1  0x8
#define ATA_REG_LBA3       0x9
#define ATA_REG_LBA4       0xA
#define ATA_REG_LBA5       0xB
#define ATA_REG_CONTROL    0xC
#define ATA_REG_ALTSTATUS  0xC
#define ATA_REG_DEVADDRESS 0xD

struct IDEChanRegs {
	uint16_t base;  /* IO base */
	uint16_t ctrl;  /* Control base */
	uint16_t bmide; /* Bus Master IDE */
	uint8_t noint;  /* No interrupt */
} channels[2];

uint8_t ideBuf[2048] = {0};
volatile unsigned static char ideIrqInvoked = 0;
unsigned static char atapiPacket[12] = {0xA8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};

struct IDEDevice {
	uint8_t reserved;
	uint8_t channel;
	uint8_t drive;
	uint16_t type;
	uint16_t signature;
	uint16_t capabilities;
	uint32_t commandSets;
	uint32_t size;
	uint8_t model[41];
} ideDevices[4];

/* Read channel */
uint8_t
ide_read(uint8_t chan, uint8_t reg)
{
	uint8_t result;
	if (reg > 0x07 && reg < 0x0C)
		ide_write(chan, ATA_REG_CONTROL, 0x80 | channels[chan].noint);
	if (reg < 0x08)
		result = inb(channels[chan].base + reg - 0x00);
	else if (reg < 0x0C)
		result = inb(channels[chan].base + reg - 0x06);
	else if (reg < 0x0E)
		result = inb(channels[chan].ctrl + reg - 0x0A);
	else if (reg < 0x16)
		result = inb(channels[chan].bmide + reg - 0x0E);
	if (reg > 0x07 && reg < 0x0C)
		ide_write(chan, ATA_REG_CONTROL, channels[chan].noint);
	return result;
}

/* Write channel */
void
ide_write(uint8_t chan, uint8_t reg, uint8_t data)
{
	if (reg > 0x07 && reg < 0x0C)
		ide_write(chan, ATA_REG_CONTROL, 0x80 | channels[chan].noint);
	if (reg < 0x08)
		outb(channels[chan].base + reg - 0x00, data);
	else if (reg < 0x0C)
		outb(channels[chan].base + reg - 0x06, data);
	else if (reg < 0x0E)
		outb(channels[chan].ctrl + reg - 0x0A, data);
	else if (reg < 0x16)
		outb(channels[chan].bmide + reg - 0x0E, data);
	if (reg > 0x07 && reg < 0x0C)
		ide_write(chan, ATA_REG_CONTROL, channels[chan].noint);
}

/* Read identification space */
void
ide_read_buffer(uint8_t chan, uint8_t reg, void *buffer, uint32_t quads)
{
	if (reg > 0x07 && reg < 0x0C)
		ide_write(chan, ATA_REG_CONTROL, 0x80 | channels[chan].noint);
	asm volatile("pushw %es; movw %ds, %ax; movw %ax, %es");
	if (reg < 0x08)
		insl(channels[chan].base + reg - 0x00, buffer, quads);
	else if (reg < 0x0C)
		insl(channels[chan].base + reg - 0x06, buffer, quads);
	else if (reg < 0x0E)
		insl(channels[chan].ctrl + reg - 0x0A, buffer, quads);
	else if (reg < 0x16)
		insl(channels[chan].bmide + reg - 0x0E, buffer, quads);
	asm volatile("popw %es");
	if (reg > 0x07 && reg < 0x0C)
		ide_write(chan, ATA_REG_CONTROL, channels[chan].noint);
}

/* Poll for status after command */
uint8_t
ide_polling(uint8_t chan, uint32_t check)
{
	uint8_t i, state;
	/* Wait for BSY to set */
	for (i = 0; i < 4; i++)
		ide_read(chan, ATA_REG_ALTSTATUS);
	/* Wait for BSY to clear */
	while (ide_read(chan, ATA_REG_STATUS) & ATA_SR_BSY);

	if (check) {
		state = ide_read(chan, ATA_REG_STATUS);
		if (state & ATA_SR_ERR)
			return 2;
		if (state & ATA_SR_DF)
			return 1;
		if ((state & ATA_SR_DRQ) == 0)
			return 3;
	}

	return 0;
}

/* Print an IDE error */
uint8_t
ide_print_error(uint32_t drive, uint8_t err)
{
	if (err == 0)
		return err;

	uint8_t st;
	kprintf("IDE:");
	if (err == 1) {
		kprintf(" - Device fault");
		err = 19;
	} else if (err == 2) {
		st = ide_read(ideDevices[drive].channel, ATA_REG_ERROR);
		if (st & ATA_ER_AMNF) {
			kprintf(" - No address mark found");
			err = 7;
		}
		if (st & ATA_ER_T0NF) {
			kprintf(" - No media or media error");
			err = 3;
		}
		if (st & ATA_ER_ABRT) {
			kprintf(" - Command aborted");
			err = 20;
		}
		if (st & ATA_ER_MCR) {
			kprintf(" - No media or media error");
			err = 3;
		}
		if (st & ATA_ER_IDNF) {
			kprintf(" - ID mark not found");
			err = 21;
		}
		if (st & ATA_ER_MC) {
			kprintf(" - No media or media error");
			err = 3;
		}
		if (st & ATA_ER_UNC) {
			kprintf(" - Uncorrectable data error");
			err = 22;
		}
		if (st & ATA_ER_BBK) {
			kprintf(" - Bad sectors");
			err = 13;
		}
	} else if (err == 3) {
		kprintf(" - Read nothing");
		err = 23;
	} else if (err == 4) {
		kprintf(" - Write protected");
		err = 8;
	}
	kprintf(" - [%s %s] %s",
	        (char *[]){"Primary","Secondary"}[ideDevices[drive].channel],
	        (char *[]){"Master","Slave"}[ideDevices[drive].drive],
	        ideDevices[drive].model);
	return err;
}

/* Initialise an IDE drive */
void
ide_drive_init(uint32_t bar0, uint32_t bar1, uint32_t bar2,
               uint32_t bar3, uint32_t bar4)
{
	channels[ATA_PRIMARY].base = (bar0 & ~3) + 0x1F0 * (!bar0);
	channels[ATA_PRIMARY].ctrl = (bar1 & ~3) + 0x3F6 * (!bar1);
	channels[ATA_SECONDARY].base = (bar2 & ~3) + 0x170 * (!bar2);
	channels[ATA_SECONDARY].ctrl = (bar3 & ~3) + 0x376 * (!bar3);
	channels[ATA_PRIMARY].bmide = (bar4 & ~3) + 0;
	channels[ATA_SECONDARY].bmide = (bar4 & ~3) + 8;
	/* Disable IRQs */
	ide_write(ATA_PRIMARY, ATA_REG_CONTROL, 2);
	ide_write(ATA_SECONDARY, ATA_REG_CONTROL, 2);

	uint32_t count = 0;
	uint8_t i, j, k, err, type, status;
	for (i = 0; i < 2; i++)
	for (j = 0; j < 2; j++) {
		err = 0;
		type = IDE_ATA;
		ideDevices[count].reserved = 0;
		ide_write(i, ATA_REG_HDDEVSEL, 0xA0 | (j << 4));
		sleep(1);
		ide_write(i, ATA_REG_COMMAND, ATA_CMD_IDENTIFY);
		sleep(1);
		if (ide_read(i, ATA_REG_STATUS) == 0)
			continue;

		while (1) {
			status = ide_read(i, ATA_REG_STATUS);
			if ((status & ATA_SR_ERR)) {
				err = 1;
				break;
			}
			if (!(status & ATA_SR_BSY) && (status & ATA_SR_DRQ))
				break;
		}

		if (err) {
			uint8_t cl = ide_read(i, ATA_REG_LBA1);
			uint8_t ch = ide_read(i, ATA_REG_LBA2);

			if (cl == 0x14 && ch == 0xEB)
				type = IDE_ATAPI;
			else if (cl == 0x69 && ch == 0x96)
				type = IDE_ATAPI;
			else
				continue;

			ide_write(i, ATA_REG_COMMAND, ATA_CMD_IDENTIFY_PACKET);
			sleep(1);
		}

		ide_read_buffer(i, ATA_REG_DATA, ideBuf, 128);

		uint16_t sig, cap, set;
		sig = *((uint16_t *) (ideBuf + ATA_IDENT_DEVICETYPE));
		cap = *((uint16_t *) (ideBuf + ATA_IDENT_CAPABILITIES));
		set = *((uint16_t *) (ideBuf + ATA_IDENT_COMMANDSETS));
		ideDevices[count].reserved = 1;
		ideDevices[count].type = type;
		ideDevices[count].channel = i;
		ideDevices[count].drive = j;
		ideDevices[count].signature = sig;
		ideDevices[count].capabilities = cap;
		ideDevices[count].commandSets = set;

		uint32_t size;
		if (ideDevices[count].commandSets & (1 << 26))
			size = *((uint32_t *) (ideBuf + ATA_IDENT_MAX_LBA_EXT));
		else
			size = *((uint32_t *) (ideBuf + ATA_IDENT_MAX_LBA));
		ideDevices[count].size = size;
		for (k = 0; k < 40; k += 2) {
			ideDevices[count].model[k] =
				ideBuf[ATA_IDENT_MODEL + k + 1];
			ideDevices[count].model[k + 1] =
				ideBuf[ATA_IDENT_MODEL + k];
		}
		ideDevices[count].model[40] = 0;
		count++;
	}
}

/* Wait for an IRQ to arrive */
void
ide_wait_irq(void)
{
	while (!ideIrqInvoked);
	ideIrqInvoked = 0;
}

/* Access an ATA drive */
uint8_t
ide_ata_access(uint8_t write, uint8_t drive, uint32_t lba, uint8_t sectors,
               uint16_t selector, uint32_t edi)
{
	uint8_t lbaMode, dma, cmd;
	uint8_t lbaIO[6];
	uint32_t chan = ideDevices[drive].channel;
	uint32_t slave = ideDevices[drive].drive;
	uint32_t bus = channels[chan].base;
	uint32_t words = 256;
	uint16_t cyl, i;
	uint8_t head, sect, err;

	ide_write(chan, ATA_REG_CONTROL,
	          channels[chan].noint = (ideIrqInvoked = 0) + 2);

	if (lba >= 0x10000000) {
		/* LBA48 */
		lbaMode = 2;
		lbaIO[0] = (lba & 0x000000FF) >> 0;
		lbaIO[1] = (lba & 0x0000FF00) >> 8;
		lbaIO[2] = (lba & 0x00FF0000) >> 16;
		lbaIO[3] = (lba & 0xFF000000) >> 24;
		lbaIO[4] = 0;
		lbaIO[5] = 0;
		head = 0;
	} else if (ideDevices[drive].capabilities & 0x200) {
		/* LBA28 */
		lbaMode = 1;
		lbaIO[0] = (lba & 0x000000FF) >> 0;
		lbaIO[1] = (lba & 0x0000FF00) >> 8;
		lbaIO[2] = (lba & 0x00FF0000) >> 16;
		lbaIO[3] = 0;
		lbaIO[4] = 0;
		lbaIO[5] = 0;
		head = (lba & 0x0F000000) >> 24;
	} else {
		/* CHS */
		lbaMode = 0;
		sect = (lba % 63) + 1;
		cyl = (lba + 1 - sect) / (16 * 63);
		lbaIO[0] = sect;
		lbaIO[1] = (cyl >> 0) & 0xFF;
		lbaIO[2] = (cyl >> 8) & 0xFF;
		lbaIO[3] = 0;
		lbaIO[4] = 0;
		lbaIO[5] = 0;
		head = (lba + 1 - sect) % (16 * 63) / 63;
	}

	dma = 0; /* XXX */

	while (ide_read(chan, ATA_REG_STATUS) & ATA_SR_BSY);

	if (lbaMode == 0)
		ide_write(chan, ATA_REG_HDDEVSEL, 0xA0 | (slave << 4) | head);
	else
		ide_write(chan, ATA_REG_HDDEVSEL, 0xE0 | (slave << 4) | head);

	if (lbaMode == 2) {
		ide_write(chan, ATA_REG_SECCOUNT1, 0);
		ide_write(chan, ATA_REG_LBA3, lbaIO[3]);
		ide_write(chan, ATA_REG_LBA4, lbaIO[4]);
		ide_write(chan, ATA_REG_LBA5, lbaIO[5]);
	}
	ide_write(chan, ATA_REG_SECCOUNT0, sectors);
	ide_write(chan, ATA_REG_LBA0, lbaIO[0]);
	ide_write(chan, ATA_REG_LBA1, lbaIO[1]);
	ide_write(chan, ATA_REG_LBA2, lbaIO[2]);

	if (lbaMode == 0 && !dma && !write) cmd = ATA_CMD_READ_PIO;
	if (lbaMode == 1 && !dma && !write) cmd = ATA_CMD_READ_PIO;
	if (lbaMode == 2 && !dma && !write) cmd = ATA_CMD_READ_PIO_EXT;
	if (lbaMode == 0 &&  dma && !write) cmd = ATA_CMD_READ_DMA;
	if (lbaMode == 1 &&  dma && !write) cmd = ATA_CMD_READ_DMA;
	if (lbaMode == 2 &&  dma && !write) cmd = ATA_CMD_READ_DMA_EXT;
	if (lbaMode == 0 && !dma &&  write) cmd = ATA_CMD_WRITE_PIO;
	if (lbaMode == 1 && !dma &&  write) cmd = ATA_CMD_WRITE_PIO;
	if (lbaMode == 2 && !dma &&  write) cmd = ATA_CMD_WRITE_PIO_EXT;
	if (lbaMode == 0 &&  dma &&  write) cmd = ATA_CMD_WRITE_DMA;
	if (lbaMode == 1 &&  dma &&  write) cmd = ATA_CMD_WRITE_DMA;
	if (lbaMode == 2 &&  dma &&  write) cmd = ATA_CMD_WRITE_DMA_EXT;
	ide_write(chan, ATA_REG_COMMAND, cmd);

	if (dma) {
		if (write) {
			/* TODO */
		} else {
			/* TODO */
		}
	} else {
		if (write) {
			for (i = 0; i < sectors; i++) {
				ide_polling(chan, 0);
				outsw(bus, (void *) edi, words);
			}
			ide_write(chan, ATA_REG_COMMAND, (uint8_t []) {
				ATA_CMD_CACHE_FLUSH,
				ATA_CMD_CACHE_FLUSH,
				ATA_CMD_CACHE_FLUSH_EXT,
			}[lbaMode]);
			ide_polling(chan, 0);
		} else {
			for (i = 0; i < sectors; i++) {
				if (err = ide_polling(chan, 1))
					return err;
				insw(bus, (void *) edi, words);
				edi += words * 2;
			}
		}
	}

	return 0;
}

/* IDE IRQ handler */
void
ide_irq(InterruptFrame *frame)
{
	ideIrqInvoked = 1;
}

/* Initialise an IDE drive */
void
ide_init(uint8_t bus, uint8_t slot, uint8_t func)
{
	register_driver(&ideDriver);

	uint8_t class, subclass, progif, header;
	class = pci_read_byte(bus, slot, func, 11);
	subclass = pci_read_byte(bus, slot, func, 10);
	progif = pci_read_byte(bus, slot, func, 9);
	header = pci_read_byte(bus, slot, func, 14);

	uint8_t primaryNative = 0, primaryChange = 0,
	        secondaryNative = 0, secondaryChange = 0,
	        busMaster = 0;
	if (progif & (1 << 0))
		primaryNative = 1;
	if (progif & (1 << 1))
		primaryChange = 1;
	if (progif & (1 << 2))
		secondaryNative = 1;
	if (progif & (1 << 3))
		secondaryChange = 1;
	if (progif & (1 << 7))
		busMaster = 1;

	uint32_t bar0 = 0x1F0, bar1 = 0x3F6,
	         bar2 = 0x170, bar3 = 0x376,
	         bar4 = 0x00;

	if (primaryNative) {
		bar0 = pci_read_dword(bus, slot, func, 0x10);
		bar1 = pci_read_dword(bus, slot, func, 0x14);
	}
	if (secondaryNative) {
		bar2 = pci_read_dword(bus, slot, func, 0x18);
		bar3 = pci_read_dword(bus, slot, func, 0x1C);
	}
	if (busMaster)
		bar4 = pci_read_dword(bus, slot, func, 0x20);

	register_interrupt(14, ide_irq);
	ataDmaArea = alloc_frames(1);

	ide_drive_init(0x1F0, 0x3F6, 0x170, 0x376, 0x00);
	uint8_t i, j;
	char name[16];
	for (i = 0; i < 4; i++) {
		if (!ideDevices[i].reserved)
			continue;
		sprintf(name, "/dev/%cd%c",
		        (char []){'h','c'}[ideDevices[i].type],
		        (char []){'a','b'}[ideDevices[i].channel]);
		mknod(name, S_IFBLK | 0600, MKDEV(ideDriver.major, i * 16));
		kprintf("    %s drive [%s] %d MB - %s",
		        (char *[]){"ATA", "ATAPI"}[ideDevices[i].type],
		        name, ideDevices[i].size / 1024 / 2,
		        ideDevices[i].model);
		/* Attempt to read partition table */
		if (ideDevices[i].type != 0)
			continue;
		ide_ata_access(0, i, 0, 0x02, 1, ataDmaArea);
		struct partition *part;
		for (j = 0; j < 4; j++) {
			part = (void *) ataDmaArea + 446 + (j * 16);
			if (!part->type)
				continue;
			sprintf(name, "/dev/%cd%c%d",
			        (char []){'h','c'}[ideDevices[i].type],
			        (char []){'a','b'}[ideDevices[i].channel],
			        j + 1);
			int asdf = mknod(name, S_IFBLK | 0600,
			      MKDEV(ideDriver.major, (i * 16) + (j + 1)));
			kprintf("      Partition %d: %#.8x - %#.8x",
			        j+1, part->lba*512,
			        (part->lba + part->size) * 512);
		}
	}
}

/* Read a drive */
size_t
ata_read(File *file, char *buf, size_t size, off_t offset)
{
	uint16_t min, bufOffset = offset % 512;
	size_t count = 0;
	uint16_t dev = MINOR(file->inode->dev) / 16,
	         parti = MINOR(file->inode->dev) % 16;
	uint32_t lba;
	struct partition *part;
	if (parti) {
		ide_ata_access(0, dev, 0, 1, 0x02, ataDmaArea);
		part = (void *) ataDmaArea + 446 + ((parti - 1) * 16);
		if (offset > (part->lba + part->size) * 512)
			return 0;
		if (offset + size > (part->lba + part->size) * 512)
			size = ((part->lba + part->size) * 512) - offset;
	} else {
		if (offset > ideDevices[dev].size * 512)
			return 0;
		if (offset + size > ideDevices[dev].size * 512)
			size = (ideDevices[dev].size * 512) - offset;
	}
	while (size + bufOffset) {
		min = (size > 0x1000) ? 0x1000 : size;
		lba = (parti ? part->lba : 0) + ((offset + count) / 512);
		ide_ata_access(0, dev, lba, 8, 0x02, ataDmaArea);
		memcpy((void *) (buf + count),
		       (void *) ataDmaArea + bufOffset,
		       min);
		size -= min;
		count += min;
		bufOffset = 0;
	}
	return count;
}

/* Write a drive */
size_t
ata_write(File *file, char *buf, size_t size, off_t offset)
{
	uint16_t min;
	size_t count = 0;
	uint16_t dev = MINOR(file->inode->dev) / 16,
	         parti = MINOR(file->inode->dev) % 16;
	uint32_t lba;
	struct partition *part;
	if (parti) {
		ide_ata_access(0, dev, 0, 1, 0x02, ataDmaArea);
		part = (void *) ataDmaArea + 446 + ((parti - 1) * 16);
		if (offset > (part->lba + part->size) * 512)
			return 0;
		if (offset + size > (part->lba + part->size) * 512)
			size = ((part->lba + part->size) * 512) - offset;
	} else {
		if (offset > ideDevices[dev].size * 512)
			return 0;
		if (offset + size > ideDevices[dev].size * 512)
			size = (ideDevices[dev].size * 512) - offset;
	}
	while (size) {
		min = (size > 0x1000) ? 0x1000 : size;
		memcpy((void *) ataDmaArea,
//		       (void *) (((uint32_t) (buf + count) / 512) * 512),
		       (void *) (buf + count),
		       min);
		lba = (parti ? part->lba : 0) + ((offset + count) / 512);
		ide_ata_access(1, dev, lba, 8, 0x02, ataDmaArea);
		size -= min;
		count += min;
	}
	return count;
	/*
	 * TODO: Currently, offset is sector-aligned, which we don't always
	 *       want.  This should be fixed by basically checking the offset
	 *       for this and reading into the dma buffer before we write to the
	 *       adjusted offset in the buffer, this way the surrounding data
	 *       isn't deleted by accident with bad alignment.
	 */
}

/* Open a drive */
int
ata_open(File *file)
{
	if (ideDevices[MINOR(file->inode->dev)/16].reserved)
		return 0;
	if (ideDevices[MINOR(file->inode->dev)/16].type != 0)
		return -EINVAL;
	return -ENODEV;
}