diff --git a/disk/ata.c b/disk/ata.c index 662fe71a7..b2291cd53 100644 --- a/disk/ata.c +++ b/disk/ata.c @@ -332,11 +332,38 @@ grub_ata_identify (struct grub_ata_device *dev) return 0; } +static grub_err_t +check_device (struct grub_ata_device *dev) +{ + grub_ata_regset (dev, GRUB_ATA_REG_DISK, dev->device << 4); + grub_ata_wait (); + + /* 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_SECTORS, 0x5A); + grub_ata_wait (); + grub_uint8_t sec = grub_ata_regget (dev, GRUB_ATA_REG_SECTORS); + grub_dprintf ("ata", "sectors=0x%x\n", sec); + if (sec != 0x5A) + return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "no device connected"); + + /* The above test may detect a second (slave) device + connected to a SATA controller which supports only one + (master) device. It is not safe to use the status register + READY bit to check for controller channel existence. Some + ATAPI commands (RESET, DIAGNOSTIC) may clear this bit. */ + + /* Use the IDENTIFY DEVICE command to query the device. */ + return grub_ata_identify (dev); +} + static grub_err_t grub_ata_device_initialize (int port, int device, int addr, int addr2) { struct grub_ata_device *dev; struct grub_ata_device **devp; + grub_err_t err; grub_dprintf ("ata", "detecting device %d,%d (0x%x, 0x%x)\n", port, device, addr, addr2); @@ -352,39 +379,14 @@ grub_ata_device_initialize (int port, int device, int addr, int addr2) dev->ioaddress2 = addr2 + GRUB_MACHINE_PCI_IO_BASE; dev->next = NULL; - grub_ata_regset (dev, GRUB_ATA_REG_DISK, dev->device << 4); - grub_ata_wait (); - - /* 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_SECTORS, 0x5A); - grub_ata_wait (); - grub_uint8_t sec = grub_ata_regget (dev, GRUB_ATA_REG_SECTORS); - grub_dprintf ("ata", "sectors=0x%x\n", sec); - if (sec != 0x5A) - { - grub_free(dev); - return 0; - } - - /* The above test may detect a second (slave) device - connected to a SATA controller which supports only one - (master) device. It is not safe to use the status register - READY bit to check for controller channel existence. Some - ATAPI commands (RESET, DIAGNOSTIC) may clear this bit. */ - - /* 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; + err = check_device (dev); + if (err) + grub_print_error (); + return 0; } @@ -667,6 +669,14 @@ grub_ata_iterate (int (*hook) (const char *name)) for (dev = grub_ata_devices; dev; dev = dev->next) { char devname[10]; + grub_err_t err; + + err = check_device (dev); + if (err) + { + grub_errno = GRUB_ERR_NONE; + continue; + } if (dev->atapi) continue; @@ -685,6 +695,7 @@ static grub_err_t grub_ata_open (const char *name, grub_disk_t disk) { struct grub_ata_device *dev; + grub_err_t err; for (dev = grub_ata_devices; dev; dev = dev->next) { @@ -701,6 +712,11 @@ grub_ata_open (const char *name, grub_disk_t disk) if (dev->atapi) return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "not an ATA harddisk"); + err = check_device (dev); + + if (err) + return err; + disk->total_sectors = dev->size; disk->id = (unsigned long) dev; @@ -757,6 +773,16 @@ grub_atapi_iterate (int (*hook) (const char *name, int luns)) for (dev = grub_ata_devices; dev; dev = dev->next) { char devname[10]; + + grub_err_t err; + + err = check_device (dev); + if (err) + { + grub_errno = GRUB_ERR_NONE; + continue; + } + grub_snprintf (devname, sizeof (devname), "ata%d", dev->port * 2 + dev->device); @@ -827,6 +853,7 @@ grub_atapi_open (const char *name, struct grub_scsi *scsi) { struct grub_ata_device *dev; struct grub_ata_device *devfnd = 0; + grub_err_t err; for (dev = grub_ata_devices; dev; dev = dev->next) { @@ -846,6 +873,13 @@ grub_atapi_open (const char *name, struct grub_scsi *scsi) if (! devfnd) return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "no such ATAPI device"); + err = check_device (devfnd); + if (err) + return err; + + if (! devfnd->atapi) + return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "no such ATAPI device"); + scsi->data = devfnd; return GRUB_ERR_NONE;