[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[1952] 2009-01-19 Christian Franke <address@hidden>
From: |
Christian Franke |
Subject: |
[1952] 2009-01-19 Christian Franke <address@hidden> |
Date: |
Mon, 19 Jan 2009 20:39:57 +0000 |
Revision: 1952
http://svn.sv.gnu.org/viewvc/?view=rev&root=grub&revision=1952
Author: chrfranke
Date: 2009-01-19 20:39:57 +0000 (Mon, 19 Jan 2009)
Log Message:
-----------
2009-01-19 Christian Franke <address@hidden>
* disk/ata.c (GRUB_ATAPI_REG_*): New defines.
(GRUB_ATAPI_IREASON_*): Likewise.
(grub_ata_pio_write): Fix timeout error return.
(grub_atapi_identify): Add grub_ata_wait () after cmd.
(grub_atapi_wait_drq): New function.
(grub_atapi_packet): New parameter `size'.
Use grub_atapi_wait_drq () and direct write instead of
grub_ata_pio_write ().
(grub_atapi_read): Replace grub_ata_pio_read () by a loop which
reads the number of bytes requested by the device for each DRQ
assertion.
(grub_atapi_write): Remove old implementation, return not
implemented instead.
Modified Paths:
--------------
trunk/grub2/ChangeLog
trunk/grub2/disk/ata.c
Modified: trunk/grub2/ChangeLog
===================================================================
--- trunk/grub2/ChangeLog 2009-01-19 20:27:54 UTC (rev 1951)
+++ trunk/grub2/ChangeLog 2009-01-19 20:39:57 UTC (rev 1952)
@@ -1,5 +1,21 @@
2009-01-19 Christian Franke <address@hidden>
+ * disk/ata.c (GRUB_ATAPI_REG_*): New defines.
+ (GRUB_ATAPI_IREASON_*): Likewise.
+ (grub_ata_pio_write): Fix timeout error return.
+ (grub_atapi_identify): Add grub_ata_wait () after cmd.
+ (grub_atapi_wait_drq): New function.
+ (grub_atapi_packet): New parameter `size'.
+ Use grub_atapi_wait_drq () and direct write instead of
+ grub_ata_pio_write ().
+ (grub_atapi_read): Replace grub_ata_pio_read () by a loop which
+ reads the number of bytes requested by the device for each DRQ
+ assertion.
+ (grub_atapi_write): Remove old implementation, return not
+ implemented instead.
+
+2009-01-19 Christian Franke <address@hidden>
+
* disk/scsi.c (grub_scsi_read10): Use scsi->blocksize instead
of 512 to calculate data size.
(grub_scsi_read12): Likewise.
Modified: trunk/grub2/disk/ata.c
===================================================================
--- trunk/grub2/disk/ata.c 2009-01-19 20:27:54 UTC (rev 1951)
+++ trunk/grub2/disk/ata.c 2009-01-19 20:39:57 UTC (rev 1952)
@@ -44,12 +44,15 @@
#define GRUB_ATA_REG_ERROR 1
#define GRUB_ATA_REG_FEATURES 1
#define GRUB_ATA_REG_SECTORS 2
+#define GRUB_ATAPI_REG_IREASON 2
#define GRUB_ATA_REG_SECTNUM 3
#define GRUB_ATA_REG_CYLLSB 4
#define GRUB_ATA_REG_CYLMSB 5
#define GRUB_ATA_REG_LBALOW 3
#define GRUB_ATA_REG_LBAMID 4
+#define GRUB_ATAPI_REG_CNTLOW 4
#define GRUB_ATA_REG_LBAHIGH 5
+#define GRUB_ATAPI_REG_CNTHIGH 5
#define GRUB_ATA_REG_DISK 6
#define GRUB_ATA_REG_CMD 7
#define GRUB_ATA_REG_STATUS 7
@@ -65,6 +68,13 @@
#define GRUB_ATA_STATUS_READY 0x40
#define GRUB_ATA_STATUS_BUSY 0x80
+/* ATAPI interrupt reason values (I/O, D/C bits). */
+#define GRUB_ATAPI_IREASON_MASK 0x3
+#define GRUB_ATAPI_IREASON_DATA_OUT 0x0
+#define GRUB_ATAPI_IREASON_CMD_OUT 0x1
+#define GRUB_ATAPI_IREASON_DATA_IN 0x2
+#define GRUB_ATAPI_IREASON_ERROR 0x3
+
enum grub_ata_commands
{
GRUB_ATA_CMD_READ_SECTORS = 0x20,
@@ -229,7 +239,7 @@
/* Wait until drive is ready to read data. */
if (grub_ata_wait_status (dev, GRUB_ATA_STATUS_DRQ, 0, milliseconds))
- return 0;
+ return grub_errno;
/* Write the data, word by word. */
for (i = 0; i < size / 2; i++)
@@ -283,6 +293,7 @@
grub_free (info);
return grub_errno;
}
+ grub_ata_wait ();
if (grub_ata_pio_read (dev, info, GRUB_DISK_SECTOR_SIZE, GRUB_ATA_TOUT_STD))
{
@@ -300,21 +311,65 @@
}
static grub_err_t
-grub_atapi_packet (struct grub_ata_device *dev, char *packet)
+grub_atapi_wait_drq (struct grub_ata_device *dev,
+ grub_uint8_t ireason,
+ int milliseconds)
{
+ grub_millisleep (1); /* ATA allows 400ns to assert BSY. */
+
+ if (grub_ata_wait_status (dev, 0, GRUB_ATA_STATUS_BUSY, milliseconds))
+ return grub_errno;
+
+ grub_uint8_t sts = grub_ata_regget (dev, GRUB_ATA_REG_STATUS);
+ grub_uint8_t irs = grub_ata_regget (dev, GRUB_ATAPI_REG_IREASON);
+
+ /* OK if DRQ is asserted and interrupt reason is as expected. */
+ if ((sts & GRUB_ATA_STATUS_DRQ)
+ && (irs & GRUB_ATAPI_IREASON_MASK) == ireason)
+ return GRUB_ERR_NONE;
+
+ /* No DRQ implies error condition. */
+ grub_dprintf("ata", "atapi error: status=0x%x, ireason=0x%x, error=0x%x\n",
+ sts, irs, grub_ata_regget (dev, GRUB_ATA_REG_ERROR));
+
+ if (! (sts & GRUB_ATA_STATUS_DRQ)
+ && (irs & GRUB_ATAPI_IREASON_MASK) == GRUB_ATAPI_IREASON_ERROR)
+ {
+ if (ireason == GRUB_ATAPI_IREASON_CMD_OUT)
+ return grub_error (GRUB_ERR_READ_ERROR, "ATA PACKET command error");
+ else
+ return grub_error (GRUB_ERR_READ_ERROR, "ATAPI read error");
+ }
+
+ return grub_error (GRUB_ERR_READ_ERROR, "ATAPI protocol error");
+}
+
+static grub_err_t
+grub_atapi_packet (struct grub_ata_device *dev, char *packet,
+ grub_size_t size)
+{
+ if (grub_ata_wait_status(dev, 0, GRUB_ATA_STATUS_BUSY, GRUB_ATA_TOUT_STD))
+ return grub_errno;
+
+ /* Send ATA PACKET command. */
grub_ata_regset (dev, GRUB_ATA_REG_DISK, dev->device << 4);
grub_ata_regset (dev, GRUB_ATA_REG_FEATURES, 0);
- grub_ata_regset (dev, GRUB_ATA_REG_SECTORS, 0);
- grub_ata_regset (dev, GRUB_ATA_REG_LBAHIGH, 0xFF);
- grub_ata_regset (dev, GRUB_ATA_REG_LBAMID, 0xFF);
+ grub_ata_regset (dev, GRUB_ATAPI_REG_IREASON, 0);
+ grub_ata_regset (dev, GRUB_ATAPI_REG_CNTHIGH, size >> 8);
+ grub_ata_regset (dev, GRUB_ATAPI_REG_CNTLOW, size & 0xFF);
grub_ata_regset (dev, GRUB_ATA_REG_CMD, GRUB_ATA_CMD_PACKET);
- grub_ata_wait ();
-
- if (grub_ata_pio_write (dev, packet, 12, GRUB_ATA_TOUT_STD))
+ /* Wait for !BSY, DRQ, !I/O, C/D. */
+ if (grub_atapi_wait_drq (dev, GRUB_ATAPI_IREASON_CMD_OUT, GRUB_ATA_TOUT_STD))
return grub_errno;
+ /* Write the packet. */
+ grub_uint16_t *buf16 = (grub_uint16_t *) packet;
+ unsigned i;
+ for (i = 0; i < 12 / 2; i++)
+ grub_outw (grub_cpu_to_le16 (buf16[i]), dev->ioaddress +
GRUB_ATA_REG_DATA);
+
return GRUB_ERR_NONE;
}
@@ -847,27 +902,51 @@
{
struct grub_ata_device *dev = (struct grub_ata_device *) scsi->data;
- if (grub_atapi_packet (dev, cmd))
+ grub_dprintf("ata", "grub_atapi_read (size=%u)\n", size);
+
+ if (grub_atapi_packet (dev, cmd, size))
return grub_errno;
- grub_ata_wait (); /* XXX */
+ grub_size_t nread = 0;
+ while (nread < size)
+ {
+ /* Wait for !BSY, DRQ, I/O, !C/D. */
+ if (grub_atapi_wait_drq (dev, GRUB_ATAPI_IREASON_DATA_IN,
GRUB_ATA_TOUT_DATA))
+ return grub_errno;
- return grub_ata_pio_read (dev, buf, size, GRUB_ATA_TOUT_DATA);
+ /* Get byte count for this DRQ assertion. */
+ unsigned cnt = grub_ata_regget (dev, GRUB_ATAPI_REG_CNTHIGH) << 8
+ | grub_ata_regget (dev, GRUB_ATAPI_REG_CNTLOW);
+ grub_dprintf("ata", "DRQ count=%u\n", cnt);
+
+ /* Count of last transfer may be uneven. */
+ if (! (0 < cnt && cnt <= size - nread && (! (cnt & 1) || cnt == size -
nread)))
+ return grub_error (GRUB_ERR_READ_ERROR, "Invalid ATAPI transfer count");
+
+ /* Read the data. */
+ grub_uint16_t *buf16 = (grub_uint16_t *) (buf + nread);
+ unsigned i;
+ for (i = 0; i < cnt / 2; i++)
+ buf16[i] = grub_le_to_cpu16 (grub_inw (dev->ioaddress +
GRUB_ATA_REG_DATA));
+
+ if (cnt & 1)
+ buf[nread + cnt - 1] = (char) grub_le_to_cpu16 (grub_inw
(dev->ioaddress + GRUB_ATA_REG_DATA));
+
+ nread += cnt;
+ }
+
+ return GRUB_ERR_NONE;
}
static grub_err_t
-grub_atapi_write (struct grub_scsi *scsi,
+grub_atapi_write (struct grub_scsi *scsi __attribute__((unused)),
grub_size_t cmdsize __attribute__((unused)),
- char *cmd, grub_size_t size, char *buf)
+ char *cmd __attribute__((unused)),
+ grub_size_t size __attribute__((unused)),
+ char *buf __attribute__((unused)))
{
- 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, GRUB_ATA_TOUT_DATA);
+ // XXX: scsi.mod does not use write yet.
+ return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, "ATAPI write not
implemented");
}
static grub_err_t
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [1952] 2009-01-19 Christian Franke <address@hidden>,
Christian Franke <=