From: Robert Millan <rmh@aybabtu.com>
To: The development of GRUB 2 <grub-devel@gnu.org>
Subject: Re: [PATCH] (ata.mod) Fix ATAPI protocol
Date: Sun, 8 Feb 2009 19:37:41 +0100 [thread overview]
Message-ID: <20090208183741.GA23792@thorin> (raw)
In-Reply-To: <20090208180953.GA22285@thorin>
[-- Attachment #1: Type: text/plain, Size: 906 bytes --]
On Sun, Feb 08, 2009 at 07:09:53PM +0100, Robert Millan wrote:
> On Mon, Jan 19, 2009 at 11:15:41AM +0100, Marco Gerards wrote:
> > Perhaps my USB code might help in some occasions
> > for scsi.c, I am not completely sure if they are in sync. I sent in
> > the USB code earlier. This code can be committed, although endianess
> > is not handled correctly at all places.
Regarding scsi.c (and ata.c), there's more stuff in the other patch from Marco
at: http://mgerards.net/grub/grub_usb_2008-08-26.diff
It includes modifications that apply to revision 1830. I re-diffed them
against that version and am attaching them, just in case someone will find
them useful.
--
Robert Millan
The DRM opt-in fallacy: "Your data belongs to us. We will decide when (and
how) you may access your data; but nobody's threatening your freedom: we
still allow you to remove your data and not access it at all."
[-- Attachment #2: ata-scsi.diff --]
[-- Type: text/x-diff, Size: 15919 bytes --]
Index: disk/scsi.c
===================================================================
--- disk/scsi.c (revision 1830)
+++ disk/scsi.c (working copy)
@@ -111,6 +111,8 @@
scsi = disk->data;
+ grub_dprintf ("scsi", "READ10: sector=%lld, size=%d\n", sector, size);
+
rd.opcode = grub_scsi_cmd_read10;
rd.lun = scsi->lun << GRUB_SCSI_LUN_SHIFT;
rd.lba = grub_cpu_to_be32 (sector);
@@ -133,6 +135,8 @@
scsi = disk->data;
+ grub_dprintf ("scsi", "READ12: sector=%lld, size=%d\n", sector, size);
+
rd.opcode = grub_scsi_cmd_read12;
rd.lun = scsi->lun << GRUB_SCSI_LUN_SHIFT;
rd.lba = grub_cpu_to_be32 (sector);
@@ -143,7 +147,6 @@
return scsi->dev->read (scsi, sizeof (rd), (char *) &rd, size * 512, buf);
}
-#if 0
/* Send a SCSI request for DISK: write the data stored in BUF to SIZE
sectors starting with SECTOR. */
static grub_err_t
@@ -186,7 +189,6 @@
return scsi->dev->write (scsi, sizeof (wr), (char *) &wr, size * 512, buf);
}
-#endif
\f
static int
@@ -194,8 +196,6 @@
{
grub_scsi_dev_t p;
- auto int scsi_iterate (const char *name, int luns);
-
int scsi_iterate (const char *name, int luns)
{
char sname[40];
@@ -249,6 +249,7 @@
if (! p->open (name, scsi))
{
disk->id = (unsigned long) "scsi"; /* XXX */
+ disk->has_partitions = 1;
disk->data = scsi;
scsi->dev = p;
scsi->lun = lun;
@@ -274,19 +275,13 @@
/* Try to be conservative about the device types
supported. */
- if (scsi->devtype != grub_scsi_devtype_direct
- && scsi->devtype != grub_scsi_devtype_cdrom)
+ if (scsi->devtype != 0x00 && scsi->devtype != 0x05)
{
p->close (scsi);
return grub_error (GRUB_ERR_UNKNOWN_DEVICE,
"unknown SCSI device");
}
- if (scsi->devtype == grub_scsi_devtype_cdrom)
- disk->has_partitions = 0;
- else
- disk->has_partitions = 1;
-
err = grub_scsi_read_capacity (scsi);
if (err)
{
@@ -297,11 +292,12 @@
/* SCSI blocks can be something else than 512, although GRUB
wants 512 byte blocks. */
- disk->total_sectors = ((scsi->size * scsi->blocksize)
- << GRUB_DISK_SECTOR_BITS);
+/* disk->total_sectors = ((scsi->size) */
+/* << GRUB_DISK_SECTOR_BITS); */
+ disk->total_sectors = scsi->size;
grub_dprintf ("scsi", "capacity=%d, blksize=%d\n",
- (int) disk->total_sectors, scsi->blocksize);
+ scsi->size, scsi->blocksize);
return GRUB_ERR_NONE;
}
@@ -327,18 +323,15 @@
scsi = disk->data;
- /* SCSI sectors are variable in size. GRUB uses 512 byte
- sectors. */
sector = grub_divmod64 (sector, scsi->blocksize >> GRUB_DISK_SECTOR_BITS,
NULL);
- /* Depending on the type, select a read function. */
switch (scsi->devtype)
{
- case grub_scsi_devtype_direct:
+ case 0:
return grub_scsi_read10 (disk, sector, size, buf);
- case grub_scsi_devtype_cdrom:
+ case 0x05:
return grub_scsi_read12 (disk, sector, size, buf);
}
@@ -347,15 +340,14 @@
}
static grub_err_t
-grub_scsi_write (grub_disk_t disk __attribute((unused)),
- grub_disk_addr_t sector __attribute((unused)),
- grub_size_t size __attribute((unused)),
- const char *buf __attribute((unused)))
+grub_scsi_write (grub_disk_t disk __attribute((unused)), grub_disk_addr_t sector,
+ grub_size_t size, const char *buf)
{
#if 0
/* XXX: Not tested yet! */
/* XXX: This should depend on the device type? */
+ /* XXX: What is the sector size != 512? */
return grub_scsi_write10 (disk, sector, size, buf);
#endif
return GRUB_ERR_NOT_IMPLEMENTED_YET;
Index: disk/ata.c
===================================================================
--- disk/ata.c (revision 1830)
+++ disk/ata.c (working copy)
@@ -119,7 +119,7 @@
grub_outb (val, dev->ioaddress + reg);
}
-static inline grub_uint8_t
+static inline int
grub_ata_regget (struct grub_ata_device *dev, int reg)
{
return grub_inb (dev->ioaddress + reg);
@@ -131,51 +131,29 @@
grub_outb (val, dev->ioaddress2 + reg);
}
-static inline grub_uint8_t
+static inline int
grub_ata_regget2 (struct grub_ata_device *dev, int reg)
{
return grub_inb (dev->ioaddress2 + reg);
}
-static inline grub_err_t
-grub_ata_wait_status (struct grub_ata_device *dev,
- grub_uint8_t maskset, grub_uint8_t maskclear)
+/* Wait until the device DEV has the status set to ready. */
+static inline void
+grub_ata_wait_busy (struct grub_ata_device *dev)
{
- int i;
-
- for (i = 0; i < 1000; i++)
- {
- grub_uint8_t reg;
-
- reg = grub_ata_regget (dev, GRUB_ATA_REG_STATUS);
- if ((reg & maskset) == maskset && (reg & maskclear) == 0)
- return GRUB_ERR_NONE;
-
- grub_millisleep (1);
- }
-
- return grub_error (GRUB_ERR_TIMEOUT, "ata timeout");
+ while ((grub_ata_regget (dev, GRUB_ATA_REG_STATUS) & GRUB_ATA_STATUS_BUSY));
}
static inline void
-grub_ata_wait (void)
+grub_ata_wait_drq (struct grub_ata_device *dev)
{
- grub_millisleep (50);
+ while (! (grub_ata_regget (dev, GRUB_ATA_REG_STATUS) & GRUB_ATA_STATUS_DRQ));
}
-static grub_err_t
-grub_ata_cmd (struct grub_ata_device *dev, int cmd)
+static inline void
+grub_ata_wait (void)
{
- grub_err_t err;
-
- err = grub_ata_wait_status (dev, 0,
- GRUB_ATA_STATUS_DRQ | GRUB_ATA_STATUS_BUSY);
- if (err)
- return err;
-
- grub_ata_regset (dev, GRUB_ATA_REG_CMD, cmd);
-
- return GRUB_ERR_NONE;
+ grub_millisleep (1);
}
/* Byteorder has to be changed before strings can be read. */
@@ -191,7 +169,7 @@
dst[len] = '\0';
}
-static grub_err_t
+static int
grub_ata_pio_read (struct grub_ata_device *dev, char *buf,
grub_size_t size)
{
@@ -202,17 +180,16 @@
return grub_ata_regget (dev, GRUB_ATA_REG_ERROR);
/* Wait until the data is available. */
- if (grub_ata_wait_status (dev, GRUB_ATA_STATUS_DRQ, 0))
- return grub_errno;;
+ grub_ata_wait_drq (dev);
/* Read in the data, word by word. */
for (i = 0; i < size / 2; i++)
buf16[i] = grub_le_to_cpu16 (grub_inw(dev->ioaddress + GRUB_ATA_REG_DATA));
if (grub_ata_regget (dev, GRUB_ATA_REG_STATUS) & GRUB_ATA_STATUS_ERR)
- return grub_error (GRUB_ERR_READ_ERROR, "ATA read error");
+ return grub_ata_regget (dev, GRUB_ATA_REG_ERROR);
- return GRUB_ERR_NONE;
+ return 0;
}
static grub_err_t
@@ -225,18 +202,17 @@
if (grub_ata_regget (dev, GRUB_ATA_REG_STATUS) & GRUB_ATA_STATUS_ERR)
return grub_ata_regget (dev, GRUB_ATA_REG_ERROR);
- /* Wait until the data is available. */
- if (grub_ata_wait_status (dev, GRUB_ATA_STATUS_DRQ, 0))
- return 0;
+ /* Wait until the device is ready to write. */
+ grub_ata_wait_drq (dev);
/* Write the data, word by word. */
for (i = 0; i < size / 2; i++)
grub_outw(grub_cpu_to_le16 (buf16[i]), dev->ioaddress + GRUB_ATA_REG_DATA);
if (grub_ata_regget (dev, GRUB_ATA_REG_STATUS) & GRUB_ATA_STATUS_ERR)
- return grub_error (GRUB_ERR_WRITE_ERROR, "ATA write error");
+ return grub_ata_regget (dev, GRUB_ATA_REG_ERROR);
- return GRUB_ERR_NONE;
+ return 0;
}
static void
@@ -268,33 +244,22 @@
if (! info)
return grub_errno;
- if (grub_ata_wait_status (dev, 0, GRUB_ATA_STATUS_BUSY))
- {
- grub_free (info);
- return grub_errno;
- }
+ grub_ata_wait_busy (dev);
grub_ata_regset (dev, GRUB_ATA_REG_DISK, 0xE0 | dev->device << 4);
+ grub_ata_regset (dev, GRUB_ATA_REG_CMD,
+ GRUB_ATA_CMD_IDENTIFY_PACKET_DEVICE);
+ grub_ata_wait ();
- if (grub_ata_cmd (dev, GRUB_ATA_CMD_IDENTIFY_PACKET_DEVICE))
- {
- grub_free (info);
- return grub_errno;
- }
+ grub_ata_pio_read (dev, info, 256);
- if (grub_ata_pio_read (dev, info, 256))
- {
- grub_free (info);
- return grub_errno;
- }
-
dev->atapi = 1;
grub_ata_dumpinfo (dev, info);
grub_free (info);
- return GRUB_ERR_NONE;
+ return 0;
}
static grub_err_t
@@ -321,7 +286,7 @@
{
char *info;
grub_uint16_t *info16;
- int ataerr = 0;
+ int ataerr;
info = grub_malloc (GRUB_DISK_SECTOR_SIZE);
if (! info)
@@ -329,22 +294,13 @@
info16 = (grub_uint16_t *) info;
- if (grub_ata_wait_status (dev, 0, GRUB_ATA_STATUS_BUSY))
- {
- grub_free (info);
- return grub_errno;
- }
+ grub_ata_wait_busy (dev);
grub_ata_regset (dev, GRUB_ATA_REG_DISK, 0xE0 | dev->device << 4);
- if (grub_ata_cmd (dev, GRUB_ATA_CMD_IDENTIFY_DEVICE))
- {
- grub_free (info);
- return grub_errno;
- }
+ grub_ata_regset (dev, GRUB_ATA_REG_CMD, GRUB_ATA_CMD_IDENTIFY_DEVICE);
grub_ata_wait ();
- if (grub_ata_pio_read (dev, info, GRUB_DISK_SECTOR_SIZE))
- ataerr = grub_ata_regget (dev, GRUB_ATA_REG_ERROR);
+ ataerr = grub_ata_pio_read (dev, info, GRUB_DISK_SECTOR_SIZE);
if (ataerr & 4)
{
/* ATAPI device detected. */
@@ -409,8 +365,8 @@
/* Setup the device information. */
dev->port = port;
dev->device = device;
- dev->ioaddress = addr;
- dev->ioaddress2 = addr2;
+ 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,
@@ -429,11 +385,8 @@
/* Detect if the device is present by issuing a EXECUTE
DEVICE DIAGNOSTICS command. */
grub_ata_regset (dev, GRUB_ATA_REG_DISK, dev->device << 4);
- if (grub_ata_cmd (dev, GRUB_ATA_CMD_EXEC_DEV_DIAGNOSTICS))
- {
- grub_free (dev);
- return grub_errno;
- }
+ 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",
@@ -450,19 +403,19 @@
{
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)
+ 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", "ATA detected\n");
- }
- else
- {
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. */
@@ -480,8 +433,7 @@
}
static int
-grub_ata_pciinit (int bus, int device, int func,
- grub_pci_id_t pciid __attribute__((unused)))
+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;
@@ -491,7 +443,6 @@
int rega;
int regb;
int i;
- static int controller = 0;
/* Read class. */
addr = grub_pci_make_address (bus, device, func, 2);
@@ -540,13 +491,11 @@
if (rega && regb)
{
- grub_ata_device_initialize (controller * 2 + i, 0, rega, regb);
- grub_ata_device_initialize (controller * 2 + i, 1, rega, regb);
+ grub_ata_device_initialize (i, 0, rega, regb);
+ grub_ata_device_initialize (i, 1, rega, regb);
}
}
- controller++;
-
return 0;
}
@@ -574,8 +523,7 @@
grub_disk_addr_t sector,
grub_size_t size)
{
- if (grub_ata_wait_status (dev, 0, GRUB_ATA_STATUS_BUSY))
- return grub_errno;
+ grub_ata_wait_busy (dev);
switch (addressing)
{
@@ -671,31 +619,21 @@
if (rw == 0)
{
/* Read 256/65536 sectors. */
- if (grub_ata_cmd (dev, cmd))
- return grub_errno;
-
- /* Wait for the command to complete. */
- if (grub_ata_wait_status (dev, 0, GRUB_ATA_STATUS_BUSY))
- return grub_errno;
-
+ grub_ata_regset (dev, GRUB_ATA_REG_CMD, cmd);
+ grub_ata_wait ();
for (sect = 0; sect < batch; sect++)
{
if (grub_ata_pio_read (dev, buf,
GRUB_DISK_SECTOR_SIZE))
- return grub_errno;
+ return grub_error (GRUB_ERR_READ_ERROR, "ATA read error");
buf += GRUB_DISK_SECTOR_SIZE;
}
}
else
{
/* Write 256/65536 sectors. */
- if (grub_ata_cmd (dev, cmd))
- return grub_errno;
-
- /* Wait for the command to complete. */
- if (grub_ata_wait_status (dev, 0, GRUB_ATA_STATUS_BUSY))
- return grub_errno;
-
+ grub_ata_regset (dev, GRUB_ATA_REG_CMD, cmd_write);
+ grub_ata_wait ();
for (sect = 0; sect < batch; sect++)
{
if (grub_ata_pio_write (dev, buf,
@@ -714,28 +652,18 @@
if (rw == 0)
{
/* Read sectors. */
- if (grub_ata_cmd (dev, cmd))
- return grub_errno;
-
- /* Wait for the command to complete. */
- if (grub_ata_wait_status (dev, 0, GRUB_ATA_STATUS_BUSY))
- return grub_errno;
-
+ grub_ata_regset (dev, GRUB_ATA_REG_CMD, cmd);
+ grub_ata_wait ();
for (sect = 0; sect < (size % batch); sect++)
{
if (grub_ata_pio_read (dev, buf, GRUB_DISK_SECTOR_SIZE))
- return grub_errno;
+ return grub_error (GRUB_ERR_READ_ERROR, "ATA read error");
buf += GRUB_DISK_SECTOR_SIZE;
}
} else {
/* Write sectors. */
- if (grub_ata_cmd (dev, cmd))
- return grub_errno;
-
- /* Wait for the command to complete. */
- if (grub_ata_wait_status (dev, 0, GRUB_ATA_STATUS_BUSY))
- return grub_errno;
-
+ grub_ata_regset (dev, GRUB_ATA_REG_CMD, cmd_write);
+ grub_ata_wait ();
for (sect = 0; sect < (size % batch); sect++)
{
if (grub_ata_pio_write (dev, buf, GRUB_DISK_SECTOR_SIZE))
@@ -762,6 +690,9 @@
if (dev->atapi)
continue;
+ if (dev->atapi)
+ continue;
+
if (hook (devname))
return 1;
}
@@ -933,8 +864,105 @@
.write = grub_atapi_write
};
+
\f
+/* ATAPI code. */
+static int
+grub_atapi_iterate (int (*hook) (const char *name, int luns))
+{
+ struct grub_ata_device *dev;
+
+ for (dev = grub_ata_devices; dev; dev = dev->next)
+ {
+ char devname[5];
+ grub_sprintf (devname, "ata%d", dev->port * 2 + dev->device);
+
+ if (! dev->atapi)
+ continue;
+
+ if (hook (devname, 1))
+ return 1;
+ }
+
+ return 0;
+
+}
+
+static grub_err_t
+grub_atapi_read (struct grub_scsi *scsi, grub_size_t cmdsize, char *cmd,
+ grub_size_t size, char *buf)
+{
+ struct grub_ata_device *dev = (struct grub_ata_device *) scsi->data;
+
+ if (grub_atapi_packet (dev, cmd))
+ return grub_errno;
+
+ grub_ata_wait (); /* XXX */
+
+ return grub_ata_pio_read (dev, buf, size);
+}
+
+static grub_err_t
+grub_atapi_write (struct grub_scsi *scsi, grub_size_t cmdsize, char *cmd,
+ grub_size_t size, char *buf)
+{
+ struct grub_ata_device *dev = (struct grub_ata_device *) scsi->data;
+
+ if (grub_atapi_packet (dev, cmd))
+ return grub_errno;
+
+ grub_ata_wait (); /* XXX */
+
+ return grub_ata_pio_write (dev, buf, size);
+}
+
+static grub_err_t
+grub_atapi_open (const char *name, struct grub_scsi *scsi)
+{
+ struct grub_ata_device *dev;
+ struct grub_ata_device *devfnd;
+
+ for (dev = grub_ata_devices; dev; dev = dev->next)
+ {
+ char devname[5];
+ grub_sprintf (devname, "ata%d", dev->port * 2 + dev->device);
+
+ if (!grub_strcmp (devname, name))
+ {
+ devfnd = dev;
+ break;
+ }
+ }
+
+ if (! devfnd)
+ return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "No such ATAPI device");
+
+ scsi->data = devfnd;
+ scsi->name = grub_strdup (name);
+ scsi->luns = 1;
+
+ return GRUB_ERR_NONE;
+}
+
+static void
+grub_atapi_close (struct grub_scsi *scsi)
+{
+ grub_free (scsi->name);
+}
+
+static struct grub_scsi_dev grub_atapi_dev =
+ {
+ .name = "ATAPI",
+ .iterate = grub_atapi_iterate,
+ .open = grub_atapi_open,
+ .close = grub_atapi_close,
+ .read = grub_atapi_read,
+ .write = grub_atapi_write
+ };
+
+\f
+
GRUB_MOD_INIT(ata)
{
(void) mod; /* To stop warning. */
next prev parent reply other threads:[~2009-02-08 18:38 UTC|newest]
Thread overview: 9+ messages / expand[flat|nested] mbox.gz Atom feed top
2009-01-18 18:37 [PATCH] (ata.mod) Fix ATAPI protocol Christian Franke
2009-01-19 10:15 ` Marco Gerards
2009-01-19 12:44 ` Christian Franke
2009-01-19 20:50 ` Christian Franke
2009-01-20 9:00 ` Marco Gerards
2009-01-20 9:55 ` Christian Franke
2009-02-08 18:09 ` USB support merge (Re: [PATCH] (ata.mod) Fix ATAPI protocol) Robert Millan
2009-02-08 18:37 ` Robert Millan [this message]
2009-02-16 8:26 ` Marco Gerards
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=20090208183741.GA23792@thorin \
--to=rmh@aybabtu.com \
--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.