From: Marco Gerards <mgerards@xs4all.nl>
To: The development of GRUB <grub-devel@gnu.org>
Subject: PCI+ATA
Date: Sat, 02 Feb 2008 19:38:43 +0100 [thread overview]
Message-ID: <87ve57cifg.fsf@xs4all.nl> (raw)
[-- Attachment #1: Type: text/plain, Size: 1222 bytes --]
Hi,
Here is a patch for testing purposes. I hope people can test this on
actual hardware. Testing will help a lot for the development of the
ATA driver.
The code to reset the channel was removed, replace with something that
only queries the channel. Code for probing IDE Controllers on the PCI
bus is added. Channels in compatibility mode were supported and are
still supported. Now also more controllers should be used, but I
don't have boxes to test this on and qemu can't be used for this. So
please test.
Please tell me (read this before testing!):
1) Does it work perfectly (yes/no) as in, all devices are detected and
can be accessed. If no: what's the problem.
2) Did it work before applying this patch? (yes/no)
3) "rmmod ata", "insmod biosdisk" can you still access your disks
4) Same as 3, but before applying this patch
5) If there are problems, use:
set debug=ata
insmod ata
Please send me the output (photos are ok for me) and a description +
answers to these question
If the debug messages scroll to fast, use:
set pager=1
The driver is slow, mainly because a low resolution timer is used.
Perhaps we should use PIT channel 2 on i386-pc for the timer.
Thanks a lot for your help!
--
Marco
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: grub2_ata_pci.diff --]
[-- Type: text/x-diff, Size: 8325 bytes --]
? ascii.pff
? bus
? grub-emu
? grub_emu_init.c
? grub_emu_init.h
? unicode.pff
? commands/lspci.c
? include/grub/pci.h
? include/grub/i386/pc/pci.h
Index: disk/ata.c
===================================================================
RCS file: /sources/grub/grub2/disk/ata.c,v
retrieving revision 1.6
diff -u -p -u -p -r1.6 ata.c
--- disk/ata.c 5 Nov 2007 16:15:26 -0000 1.6
+++ disk/ata.c 2 Feb 2008 18:20:27 -0000
@@ -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>
@@ -62,7 +63,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
@@ -207,15 +209,13 @@ grub_ata_dumpinfo (struct grub_ata_devic
/* The device information was read, dump it for debugging. */
grub_ata_strncpy (text, info + 20, 20);
- grub_printf ("Serial: %s\n", text);
+ grub_dprintf ("ata", "Serial: %s\n", text);
grub_ata_strncpy (text, info + 46, 8);
- grub_printf ("Firmware: %s\n", text);
+ grub_dprintf ("ata", "Firmware: %s\n", text);
grub_ata_strncpy (text, info + 54, 40);
- grub_printf ("Model: %s\n", text);
-
- grub_printf ("Addressing: %d\n", dev->addr);
- grub_printf ("#sectors: %d\n", dev->size);
+ grub_dprintf ("ata", "Model: %s\n", text);
+ grub_dprintf ("ata", "Addressing: %d #sectors: %d\n", dev->addr, dev->size);
}
static grub_err_t
@@ -330,82 +330,163 @@ grub_ata_identify (struct grub_ata_devic
}
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++)
- {
- 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)
- {
- grub_free(dev);
- continue;
- }
+ grub_free(dev);
+ return 0;
+ }
- /* 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 ();
+ /* 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 ();
- /* 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;
- }
+ 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;
+ }
- /* Use the IDENTIFY DEVICE command to query the device. */
- if (grub_ata_identify (dev))
+ /* 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])
+ {
+ 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);
+
+ /* Check if the BARs describe an IO region. */
+ if ((bar1 & 1) && (bar2 & 1))
{
- grub_free (dev);
- continue;
+ rega = bar1 & ~3;
+ regb = bar2 & ~3;
}
+ }
- /* Register the device. */
- for (devp = &grub_ata_devices; *devp; devp = &(*devp)->next);
- *devp = dev;
+ grub_dprintf ("ata",
+ "PCI dev (%d,%d,%d) compat=%d rega=0x%x regb=0x%x\n",
+ bus, device, func, compat, rega, regb);
+
+ 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)
next reply other threads:[~2008-02-02 18:37 UTC|newest]
Thread overview: 5+ messages / expand[flat|nested] mbox.gz Atom feed top
2008-02-02 18:38 Marco Gerards [this message]
2008-02-02 22:25 ` PCI+ATA Robert Millan
2008-02-03 17:42 ` PCI+ATA walt
2008-02-03 18:42 ` PCI+ATA walt
-- strict thread matches above, loose matches on Subject: below --
2008-05-03 17:35 ata.c and sata disks Marco Vega Trucillo
2008-05-03 22:59 ` Pavel Roskin
2008-05-06 15:05 ` Robert Millan
2008-05-06 19:57 ` Marco Vega Trucillo
2008-05-06 20:38 ` PCI+ATA Marco Vega Trucillo
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=87ve57cifg.fsf@xs4all.nl \
--to=mgerards@xs4all.nl \
--cc=grub-devel@gnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.