2008-08-05 Marco Gerards <marco@gnu.org>
* disk/ata.c: Include <grub/pci.h>. (enum grub_ata_commands): Add `GRUB_ATA_CMD_EXEC_DEV_DIAGNOSTICS'. (grub_ata_initialize): Rewritten. (grub_ata_device_initialize): New function.
This commit is contained in:
parent
8d23f50773
commit
9ec92aaf1f
2 changed files with 150 additions and 60 deletions
|
@ -1,3 +1,10 @@
|
|||
2008-08-05 Marco Gerards <marco@gnu.org>
|
||||
|
||||
* disk/ata.c: Include <grub/pci.h>.
|
||||
(enum grub_ata_commands): Add `GRUB_ATA_CMD_EXEC_DEV_DIAGNOSTICS'.
|
||||
(grub_ata_initialize): Rewritten.
|
||||
(grub_ata_device_initialize): New function.
|
||||
|
||||
2008-08-04 Pavel Roskin <proski@gnu.org>
|
||||
|
||||
* kern/main.c: Include grub/mm.h.
|
||||
|
|
203
disk/ata.c
203
disk/ata.c
|
@ -22,6 +22,7 @@
|
|||
#include <grub/disk.h>
|
||||
#include <grub/mm.h>
|
||||
#include <grub/time.h>
|
||||
#include <grub/pci.h>
|
||||
/* XXX: For now this only works on i386. */
|
||||
#include <grub/cpu/io.h>
|
||||
|
||||
|
@ -71,7 +72,8 @@ enum grub_ata_commands
|
|||
GRUB_ATA_CMD_WRITE_SECTORS_EXT = 0x34,
|
||||
GRUB_ATA_CMD_IDENTIFY_DEVICE = 0xEC,
|
||||
GRUB_ATA_CMD_IDENTIFY_PACKET_DEVICE = 0xA1,
|
||||
GRUB_ATA_CMD_PACKET = 0xA0
|
||||
GRUB_ATA_CMD_PACKET = 0xA0,
|
||||
GRUB_ATA_CMD_EXEC_DEV_DIAGNOSTICS = 0x90
|
||||
};
|
||||
|
||||
struct grub_ata_device
|
||||
|
@ -344,82 +346,163 @@ grub_ata_identify (struct grub_ata_device *dev)
|
|||
}
|
||||
|
||||
static grub_err_t
|
||||
grub_ata_initialize (void)
|
||||
grub_ata_device_initialize (int port, int device, int addr, int addr2)
|
||||
{
|
||||
struct grub_ata_device *dev;
|
||||
struct grub_ata_device **devp;
|
||||
int port;
|
||||
int device;
|
||||
|
||||
for (port = 0; port <= 1; port++)
|
||||
grub_dprintf ("ata", "detecting device %d,%d (0x%x, 0x%x)\n",
|
||||
port, device, addr, addr2);
|
||||
|
||||
dev = grub_malloc (sizeof(*dev));
|
||||
if (! dev)
|
||||
return grub_errno;
|
||||
|
||||
/* Setup the device information. */
|
||||
dev->port = port;
|
||||
dev->device = device;
|
||||
dev->ioaddress = grub_ata_ioaddress[dev->port];
|
||||
dev->ioaddress2 = grub_ata_ioaddress2[dev->port];
|
||||
dev->next = NULL;
|
||||
|
||||
/* Try to detect if the port is in use by writing to it,
|
||||
waiting for a while and reading it again. If the value
|
||||
was preserved, there is a device connected. */
|
||||
grub_ata_regset (dev, GRUB_ATA_REG_DISK, dev->device << 4);
|
||||
grub_ata_wait ();
|
||||
grub_ata_regset (dev, GRUB_ATA_REG_SECTORS, 0x5A);
|
||||
grub_ata_wait ();
|
||||
if (grub_ata_regget (dev, GRUB_ATA_REG_SECTORS) != 0x5A)
|
||||
{
|
||||
for (device = 0; device <= 1; device++)
|
||||
grub_free(dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Detect if the device is present by issuing a EXECUTE
|
||||
DEVICE DIAGNOSTICS command. */
|
||||
grub_ata_regset (dev, GRUB_ATA_REG_DISK, dev->device << 4);
|
||||
grub_ata_regset (dev, GRUB_ATA_REG_CMD,
|
||||
GRUB_ATA_CMD_EXEC_DEV_DIAGNOSTICS);
|
||||
grub_ata_wait ();
|
||||
|
||||
grub_dprintf ("ata", "Registers: %x %x %x %x\n",
|
||||
grub_ata_regget (dev, GRUB_ATA_REG_SECTORS),
|
||||
grub_ata_regget (dev, GRUB_ATA_REG_LBALOW),
|
||||
grub_ata_regget (dev, GRUB_ATA_REG_LBAMID),
|
||||
grub_ata_regget (dev, GRUB_ATA_REG_LBAHIGH));
|
||||
|
||||
/* Check some registers to see if the channel is used. */
|
||||
if (grub_ata_regget (dev, GRUB_ATA_REG_SECTORS) == 0x01
|
||||
&& grub_ata_regget (dev, GRUB_ATA_REG_LBALOW) == 0x01
|
||||
&& grub_ata_regget (dev, GRUB_ATA_REG_LBAMID) == 0x14
|
||||
&& grub_ata_regget (dev, GRUB_ATA_REG_LBAHIGH) == 0xeb)
|
||||
{
|
||||
grub_dprintf ("ata", "ATAPI signature detected\n");
|
||||
}
|
||||
else if (! (grub_ata_regget (dev, GRUB_ATA_REG_SECTORS) == 0x01
|
||||
&& grub_ata_regget (dev, GRUB_ATA_REG_LBALOW) == 0x01
|
||||
&& grub_ata_regget (dev, GRUB_ATA_REG_LBAMID) == 0x00
|
||||
&& grub_ata_regget (dev, GRUB_ATA_REG_LBAHIGH) == 0x00))
|
||||
{
|
||||
grub_dprintf ("ata", "incorrect signature\n");
|
||||
grub_free (dev);
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
grub_dprintf ("ata", "ATA detected\n");
|
||||
}
|
||||
|
||||
|
||||
/* Use the IDENTIFY DEVICE command to query the device. */
|
||||
if (grub_ata_identify (dev))
|
||||
{
|
||||
grub_free (dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Register the device. */
|
||||
for (devp = &grub_ata_devices; *devp; devp = &(*devp)->next);
|
||||
*devp = dev;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
grub_ata_pciinit (int bus, int device, int func, grub_pci_id_t pciid)
|
||||
{
|
||||
static int compat_use[2] = { 0 };
|
||||
grub_pci_address_t addr;
|
||||
grub_uint32_t class;
|
||||
grub_uint32_t bar1;
|
||||
grub_uint32_t bar2;
|
||||
int rega;
|
||||
int regb;
|
||||
int i;
|
||||
|
||||
/* Read class. */
|
||||
addr = grub_pci_make_address (bus, device, func, 2);
|
||||
class = grub_pci_read (addr);
|
||||
|
||||
/* Check if this class ID matches that of a PCI IDE Controller. */
|
||||
if (class >> 16 != 0x0101)
|
||||
return 0;
|
||||
|
||||
for (i = 0; i < 2; i++)
|
||||
{
|
||||
/* Set to 0 when the channel operated in compatibility mode. */
|
||||
int compat = (class >> (2 * i)) & 1;
|
||||
|
||||
rega = 0;
|
||||
regb = 0;
|
||||
|
||||
/* If the channel is in compatibility mode, just assign the
|
||||
default registers. */
|
||||
if (compat == 0 && !compat_use[i])
|
||||
{
|
||||
dev = grub_malloc (sizeof(*dev));
|
||||
if (! dev)
|
||||
return grub_errno;
|
||||
rega = grub_ata_ioaddress[i];
|
||||
regb = grub_ata_ioaddress2[i];
|
||||
compat_use[i] = 0;
|
||||
}
|
||||
else if (compat)
|
||||
{
|
||||
/* Read the BARs, which either contain a mmapped IO address
|
||||
or the IO port address. */
|
||||
addr = grub_pci_make_address (bus, device, func, 4 + 2 * i);
|
||||
bar1 = grub_pci_read (addr);
|
||||
addr = grub_pci_make_address (bus, device, func, 5 + 2 * i);
|
||||
bar2 = grub_pci_read (addr);
|
||||
|
||||
/* Setup the device information. */
|
||||
dev->port = port;
|
||||
dev->device = device;
|
||||
dev->ioaddress = grub_ata_ioaddress[dev->port];
|
||||
dev->ioaddress2 = grub_ata_ioaddress2[dev->port];
|
||||
dev->next = NULL;
|
||||
|
||||
/* Try to detect if the port is in use by writing to it,
|
||||
waiting for a while and reading it again. If the value
|
||||
was preserved, there is a device connected. */
|
||||
grub_ata_regset (dev, GRUB_ATA_REG_DISK, dev->device << 4);
|
||||
grub_ata_wait ();
|
||||
grub_ata_regset (dev, GRUB_ATA_REG_SECTORS, 0x5A);
|
||||
grub_ata_wait ();
|
||||
if (grub_ata_regget (dev, GRUB_ATA_REG_SECTORS) != 0x5A)
|
||||
/* Check if the BARs describe an IO region. */
|
||||
if ((bar1 & 1) && (bar2 & 1))
|
||||
{
|
||||
grub_free(dev);
|
||||
continue;
|
||||
rega = bar1 & ~3;
|
||||
regb = bar2 & ~3;
|
||||
}
|
||||
}
|
||||
|
||||
/* Detect if the device is present by issuing a reset. */
|
||||
grub_ata_regset2 (dev, GRUB_ATA_REG2_CONTROL, 6);
|
||||
grub_ata_wait ();
|
||||
grub_ata_regset2 (dev, GRUB_ATA_REG2_CONTROL, 2);
|
||||
grub_ata_wait ();
|
||||
grub_ata_regset (dev, GRUB_ATA_REG_DISK, dev->device << 4);
|
||||
grub_ata_wait ();
|
||||
grub_dprintf ("ata",
|
||||
"PCI dev (%d,%d,%d) compat=%d rega=0x%x regb=0x%x\n",
|
||||
bus, device, func, compat, rega, regb);
|
||||
|
||||
/* XXX: Check some registers to see if the reset worked as
|
||||
expected for this device. */
|
||||
#if 1
|
||||
/* Enable for ATAPI . */
|
||||
if (grub_ata_regget (dev, GRUB_ATA_REG_CYLLSB) != 0x14
|
||||
|| grub_ata_regget (dev, GRUB_ATA_REG_CYLMSB) != 0xeb)
|
||||
#endif
|
||||
if (grub_ata_regget (dev, GRUB_ATA_REG_STATUS) == 0
|
||||
|| (grub_ata_regget (dev, GRUB_ATA_REG_CYLLSB) != 0
|
||||
&& grub_ata_regget (dev, GRUB_ATA_REG_CYLMSB) != 0
|
||||
&& grub_ata_regget (dev, GRUB_ATA_REG_CYLLSB) != 0x3c
|
||||
&& grub_ata_regget (dev, GRUB_ATA_REG_CYLLSB) != 0xc3))
|
||||
{
|
||||
grub_free (dev);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Use the IDENTIFY DEVICE command to query the device. */
|
||||
if (grub_ata_identify (dev))
|
||||
{
|
||||
grub_free (dev);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Register the device. */
|
||||
for (devp = &grub_ata_devices; *devp; devp = &(*devp)->next);
|
||||
*devp = dev;
|
||||
if (rega && regb)
|
||||
{
|
||||
grub_ata_device_initialize (i, 0, rega, regb);
|
||||
grub_ata_device_initialize (i, 1, rega, regb);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static grub_err_t
|
||||
grub_ata_initialize (void)
|
||||
{
|
||||
grub_pci_iterate (grub_ata_pciinit);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
grub_ata_setlba (struct grub_ata_device *dev, grub_disk_addr_t sector,
|
||||
grub_size_t size)
|
||||
|
|
Loading…
Reference in a new issue