[LinuxBIOS] trying to boot Gigabyte M575SLI
Peter Stuge
stuge-linuxbios at cdy.org
Mon Jun 4 17:58:51 CEST 2007
On Fri, Jun 01, 2007 at 11:14:55AM -0400, Ward Vandewege wrote:
> > -I had to use the delay in filo.c (cmp.
> > http://www.linuxbios.org/GIGABYTE_GA-M57SLI-S4_Build_Tutorial)
>
> Yes.
>
> > -it takes quite long to load vmlinuz and the initrd.img. Probably
> > due to: IDE_DISK_POLL_DELAY = 1 (?)
>
> Yes. Peter Stuge was working on a patch to speedup FILO. We should
> revisit that.
I would appreciate any feedback I can get on the patch. It needs more
testing.
As far as I know, it has been confirmed to work on M57SLI by Ward and
fail on VMware by Corey.
It should apply cleanly to svn FILO.
Please enable DEBUG_TIMER, _BLOCKDEV, _IDE and _EXT2 in Config if it
does not work and send the output to the list.
//Peter
-------------- next part --------------
Index: include/fs.h
===================================================================
--- include/fs.h (revision 34)
+++ include/fs.h (working copy)
@@ -7,6 +7,7 @@
#ifdef IDE_DISK
int ide_probe(int drive);
+int ide_readmany(int drive, sector_t sector, sector_t num_sectors, void *buffer);
int ide_read(int drive, sector_t sector, void *buffer);
#endif
@@ -22,6 +23,7 @@
int devopen(const char *name, int *reopen);
int devread(unsigned long sector, unsigned long byte_offset,
unsigned long byte_len, void *buf);
+int devreadmany(void *buf, unsigned long first_sector, unsigned long num_sectors);
int file_open(const char *filename);
int file_read(void *buf, unsigned long len);
Index: defconfig
===================================================================
--- defconfig (revision 34)
+++ defconfig (working copy)
@@ -25,6 +25,10 @@
# Driver for hard disk, CompactFlash, and CD-ROM on IDE bus
IDE_DISK = 1
+# Use 32-bit PIO for increased transfer speed
+# Not supported by all IDE controllers
+IDE_32BIT_PIO = 1
+
# Add a short delay when polling status registers
# (required on some broken SATA controllers)
# NOTE: Slows down access significantly, so disable
@@ -90,4 +94,5 @@
#DEBUG_IDE = 1
#DEBUG_USB = 1
#DEBUG_ELTORITO = 1
+#DEBUG_EXT2 = 1
Index: fs/fsys_ext2fs.c
===================================================================
--- fs/fsys_ext2fs.c (revision 34)
+++ fs/fsys_ext2fs.c (working copy)
@@ -1,6 +1,9 @@
/*
- * GRUB -- GRand Unified Bootloader
+ * FILO ext2fs driver
+ *
+ * Mostly code from GRUB -- GRand Unified Bootloader
* Copyright (C) 1999, 2001 Free Software Foundation, Inc.
+ * Copyright (C) 2007 Peter Stuge <peter at stuge.se>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -22,6 +25,9 @@
#include "shared.h"
#include "filesys.h"
+#define DEBUG_THIS DEBUG_EXT2
+#include <debug.h>
+
static int mapblock1, mapblock2;
/* sizes are always in bytes, BLOCK values are always in DEV_BSIZE (sectors) */
@@ -386,6 +392,8 @@
[logical_block & (EXT2_ADDR_PER_BLOCK (SUPERBLOCK) - 1)];
}
+#define E2_BSIZE (EXT2_BLOCK_SIZE (SUPERBLOCK))
+
/* preconditions: all preconds of ext2fs_block_map */
int
ext2fs_read (char *buf, int len)
@@ -395,26 +403,96 @@
int map;
int ret = 0;
int size = 0;
+ int manylen, manypos, blocks, firstmapped = 0;
-#ifdef E2DEBUG
- static char hexdigit[] = "0123456789abcdef";
- unsigned char *i;
- for (i = (unsigned char *) INODE;
- i < ((unsigned char *) INODE + sizeof (struct ext2_inode));
- i++)
+ /* read one full or partial block */
+ int ext2fs_read_one(void) {
+ int res;
+ debug ("block %d offset=%d len=%d ret=%d\n", map, offset, len, ret);
+ if (map < 0)
+ return 1;
+ size = E2_BSIZE;
+ size -= offset;
+ if (size > len)
+ size = len;
+ disk_read_func = disk_read_hook;
+ res = devread (map * (E2_BSIZE/DEV_BSIZE), offset, size, buf);
+ disk_read_func = NULL;
+ if (!res)
+ return 1;
+ buf += size;
+ len -= size;
+ filepos += size;
+ ret += size;
+ return 0;
+ }
+
+ /* read many fs blocks at once */
+ int ext2fs_read_many(int first_block, int num_blocks) {
+ int first_devblock, num_devblocks, res;
+ debug ("%3d block%c %d - %d len=%d ret=%d\n", num_blocks, 1 == num_blocks ? ' ' : 's', first_block, first_block + num_blocks - 1, len, ret);
+ if (offset)
+ debug ("can't read many blocks with non-zero offset %d\n", offset);
+ if (first_block < 0 || num_blocks < 0 || offset)
+ return 1;
+ if (!num_blocks)
+ return 0;
+ first_devblock = first_block * (E2_BSIZE/DEV_BSIZE);
+ num_devblocks = num_blocks * (E2_BSIZE/DEV_BSIZE);
+ disk_read_func = disk_read_hook;
+ res = devreadmany (buf, first_devblock, num_devblocks);
+ disk_read_func = NULL;
+ if (!res)
+ return 1;
+ size = num_blocks * E2_BSIZE;
+ buf += size;
+ len -= size;
+ filepos += size;
+ ret += size;
+ return 0;
+ }
+
+ /* read many blocks at once? */
+ if (len > E2_BSIZE)
{
- printf ("%c", hexdigit[*i >> 4]);
- printf ("%c", hexdigit[*i % 16]);
- if (!((i + 1 - (unsigned char *) INODE) % 16))
- {
- printf ("\n");
- }
- else
- {
- printf (" ");
- }
+ offset = filepos & (E2_BSIZE-1);
+ if (offset)
+ {
+ logical_block = filepos >> EXT2_BLOCK_SIZE_BITS(SUPERBLOCK);
+ map = ext2fs_block_map (logical_block);
+ if (ext2fs_read_one ())
+ goto err;
+ offset = 0;
+ }
+ while (len > 0)
+ {
+ manylen = len;
+ manypos = filepos;
+ for (blocks = 0; manylen > 0; blocks++)
+ {
+ map = ext2fs_block_map (manypos >> EXT2_BLOCK_SIZE_BITS (SUPERBLOCK));
+ if (blocks > 0 && map != firstmapped + blocks)
+ break;
+ if (!blocks)
+ firstmapped = map;
+ if (manylen < E2_BSIZE)
+ continue;
+ manypos += E2_BSIZE;
+ manylen -= E2_BSIZE;
+ }
+ if (ext2fs_read_many (firstmapped, blocks))
+ goto err;
+ }
+ if (len < 0)
+ {
+ debug ("discarding %d surplus bytes\n", -len);
+ ret += len;
+ filepos += len;
+ len = 0;
+ }
+ debug ("done reading many len=%d ret=%d\n", len, ret);
}
-#endif /* E2DEBUG */
+
while (len > 0)
{
/* find the (logical) block component of our location */
@@ -424,27 +502,14 @@
#ifdef E2DEBUG
printf ("map=%d\n", map);
#endif /* E2DEBUG */
- if (map < 0)
- break;
+ if (ext2fs_read_one ())
+ break;
+ }
- size = EXT2_BLOCK_SIZE (SUPERBLOCK);
- size -= offset;
- if (size > len)
- size = len;
+err:
+ if (len)
+ debug ("returning %d with len=%d ret=%d errnum=%d\n", errnum ? 0 : ret, len, ret, errnum);
- disk_read_func = disk_read_hook;
-
- devread (map * (EXT2_BLOCK_SIZE (SUPERBLOCK) / DEV_BSIZE),
- offset, size, buf);
-
- disk_read_func = NULL;
-
- buf += size;
- len -= size;
- filepos += size;
- ret += size;
- }
-
if (errnum)
ret = 0;
Index: fs/blockdev.c
===================================================================
--- fs/blockdev.c (revision 34)
+++ fs/blockdev.c (working copy)
@@ -335,6 +335,58 @@
return 0;
}
+/* reads many sectors from opened device into memory */
+static unsigned long read_manysectors(char *buf, unsigned long first_sector, unsigned long num_sectors)
+{
+ int n;
+
+ /* If reading memory, just copy it */
+ if (dev_type == DISK_MEM) {
+ unsigned long phys = first_sector << 9;
+ char *virt;
+ //debug("mem: %#lx\n", phys);
+ virt = phys_to_virt(phys);
+ memcpy(buf, virt, num_sectors * 512);
+ return num_sectors;
+ }
+
+ switch (dev_type) {
+#ifdef IDE_DISK
+ case DISK_IDE:
+ do {
+ n = num_sectors <= 256 ? num_sectors : 256;
+ if (ide_readmany(dev_drive, first_sector, n, buf) != 0)
+ goto readerr;
+ first_sector += n;
+ num_sectors -= n;
+ buf += 512 * n;
+ } while (num_sectors);
+ break;
+#endif
+#ifdef USB_DISK
+ case DISK_USB:
+ while (num_sectors) {
+ if (usb_read(dev_drive, first_sector, buf) != 0)
+ goto readerr;
+ first_sector++;
+ num_sectors--;
+ buf += 512;
+ }
+ break;
+#endif
+ default:
+ printf("read_manysectors: device not open\n");
+ return 0;
+ }
+ return 1;
+
+readerr:
+ printf("Disk readmany error dev=%d drive=%d first_sector=%lu num_sectors=%lu\n",
+ dev_type, dev_drive, first_sector, num_sectors);
+ dev_name[0] = '\0'; /* force re-open the device next time */
+ return 0;
+}
+
int devread(unsigned long sector, unsigned long byte_offset,
unsigned long byte_len, void *buf)
{
@@ -369,3 +421,22 @@
}
return 1;
}
+
+/* reads many sectors from opened partition into memory */
+int devreadmany(void *buf,unsigned long first_sector, unsigned long num_sectors)
+{
+ char *dest = buf;
+ unsigned long last_sector = first_sector + num_sectors - 1;
+
+ if (last_sector > part_length) {
+ printf("Attempt to readmany out of device/partition\n");
+ debug("part_length=%lu last_sector=%lu\n", part_length, last_sector);
+ return 0;
+ }
+
+ debug("sectors %lu - %lu (%3lu) to %p\n", first_sector, last_sector, num_sectors, buf);
+ if (!read_manysectors (dest, part_start + first_sector, num_sectors))
+ return 0;
+
+ return 1;
+}
Index: i386/timer.c
===================================================================
--- i386/timer.c (revision 34)
+++ i386/timer.c (working copy)
@@ -44,7 +44,7 @@
/* Timers tick over at this rate */
#define CLOCK_TICK_RATE 1193180U
-#define TICKS_PER_MS (CLOCK_TICK_RATE/1000)
+#define TICKS_PER_MS 1
/* Parallel Peripheral Controller Port B */
#define PPC_PORTB 0x61
Index: i386/include/timer.h
===================================================================
--- i386/include/timer.h (revision 34)
+++ i386/include/timer.h (working copy)
@@ -37,8 +37,9 @@
#define BCD_COUNT 0x01
/* Timers tick over at this rate */
-#define CLOCK_TICK_RATE 1193180U
-#define TICKS_PER_MS (CLOCK_TICK_RATE/1000)
+#define CLOCK_TICK_RATE 1193180U
+#define TICKS_PER_MS 1
+#define TICKS_PER_SEC (1000*TICKS_PER_MS)
/* Parallel Peripheral Controller Port B */
#define PPC_PORTB 0x61
@@ -54,6 +55,4 @@
extern void mdelay(unsigned int msecs);
extern unsigned long currticks(void);
-#define TICKS_PER_SEC 1000
-
#endif /* TIMER_H */
Index: drivers/ide.c
===================================================================
--- drivers/ide.c (revision 34)
+++ drivers/ide.c (working copy)
@@ -1,4 +1,7 @@
-/* Derived from Etherboot 5.1 */
+/*
+ * FILO IDE driver
+ * Derived from Etherboot 5.1
+ */
#include <lib.h>
#include <fs.h>
@@ -19,6 +22,7 @@
* UBL, The Universal Talkware Boot Loader
* Copyright (C) 2000 Universal Talkware Inc.
* Copyright (C) 2002 Eric Biederman
+ * Copyright (C) 2007 Peter Stuge <peter at stuge.se>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -39,6 +43,7 @@
struct controller {
uint16_t cmd_base;
uint16_t ctrl_base;
+ uint8_t stat;
};
struct harddisk_info {
@@ -227,24 +232,26 @@
static unsigned char ide_buffer[IDE_SECTOR_SIZE];
-static int await_ide(int (*done)(struct controller *ctrl),
- struct controller *ctrl, unsigned long timeout)
+static int bsy(struct controller *ctrl);
+static int drq(struct controller *ctrl);
+static int not_bsy(struct controller *ctrl);
+
+#define AWAIT_IDE(done, ctrl, timeout) await_ide(done, #done, ctrl, timeout)
+static int await_ide(int (*done)(struct controller *ctrl),
+ const char donename[], struct controller *ctrl, unsigned long timeout)
{
int result;
- for(;;) {
+ unsigned long start = currticks();
+ do {
result = done(ctrl);
#if IDE_DISK_POLL_DELAY
mdelay(1);
#endif
- if (result) {
+ if (result)
return 0;
- }
- //poll_interruptions();
- if ((timeout == 0) || (currticks() > timeout)) {
- break;
- }
- }
- printf("IDE time out\n");
+ } while ((timeout != 0) && (currticks() < start + timeout));
+
+ printf("IDE timeout after %lu ms while waiting for %s()\n", (timeout / TICKS_PER_MS), donename);
return -1;
}
@@ -252,21 +259,30 @@
* So if any IDE commands takes this long we know we have problems.
*/
#define IDE_TIMEOUT (32*TICKS_PER_SEC)
+#define IDE_TIMEOUT_50ms (TICKS_PER_SEC/20)
static int not_bsy(struct controller *ctrl)
{
- return !(inb(IDE_REG_STATUS(ctrl)) & IDE_STATUS_BSY);
+ ctrl->stat = inb(IDE_REG_ALTSTATUS(ctrl));
+ return !(ctrl->stat & IDE_STATUS_BSY);
}
/* IDE drives assert BSY bit within 400 nsec when SRST is set.
* Use 2 msec since our tick is 1 msec */
-#define IDE_RESET_PULSE (2*TICKS_PER_SEC / 1000)
+#define IDE_RESET_PULSE (TICKS_PER_SEC)
static int bsy(struct controller *ctrl)
{
- return inb(IDE_REG_STATUS(ctrl)) & IDE_STATUS_BSY;
+ ctrl->stat = inb(IDE_REG_STATUS(ctrl));
+ return ctrl->stat & IDE_STATUS_BSY;
}
+static int drq(struct controller *ctrl)
+{
+ ctrl->stat = inb(IDE_REG_STATUS(ctrl));
+ return ctrl->stat & IDE_STATUS_DRQ;
+}
+
#if !BSY_SET_DURING_SPINUP
static int timeout(struct controller *ctrl)
{
@@ -292,7 +308,7 @@
*/
debug("Waiting for ide%d to become ready for reset... ",
ctrl - controllers);
- if (await_ide(not_bsy, ctrl, currticks() + IDE_TIMEOUT) < 0) {
+ if (AWAIT_IDE(not_bsy, ctrl, IDE_TIMEOUT) < 0) {
debug("failed\n");
return -1;
}
@@ -302,12 +318,12 @@
outb(IDE_CTRL_HD15 | IDE_CTRL_SRST | IDE_CTRL_NIEN,
IDE_REG_DEVICE_CONTROL(ctrl));
/* If BSY bit is not asserted within 400ns, no device there */
- if (await_ide(bsy, ctrl, currticks() + IDE_RESET_PULSE) < 0) {
+ if (AWAIT_IDE(bsy, ctrl, IDE_RESET_PULSE) < 0) {
return -1;
}
outb(IDE_CTRL_HD15 | IDE_CTRL_NIEN, IDE_REG_DEVICE_CONTROL(ctrl));
mdelay(2);
- if (await_ide(not_bsy, ctrl, currticks() + IDE_TIMEOUT) < 0) {
+ if (AWAIT_IDE(not_bsy, ctrl, IDE_TIMEOUT) < 0) {
return -1;
}
return 0;
@@ -348,13 +364,15 @@
static int pio_non_data(struct controller *ctrl, const struct ide_pio_command *cmd)
{
/* Wait until the busy bit is clear */
- if (await_ide(not_bsy, ctrl, currticks() + IDE_TIMEOUT) < 0) {
+ if (AWAIT_IDE(not_bsy, ctrl, IDE_TIMEOUT) < 0) {
+ debug("Device not ready before sending command\n");
return -1;
}
pio_set_registers(ctrl, cmd);
ndelay(400);
- if (await_ide(not_bsy, ctrl, currticks() + IDE_TIMEOUT) < 0) {
+ if (AWAIT_IDE(not_bsy, ctrl, IDE_TIMEOUT) < 0) {
+ debug("Device not ready after sending command\n");
return -1;
}
/* FIXME is there more error checking I could do here? */
@@ -364,31 +382,59 @@
static int pio_data_in(struct controller *ctrl, const struct ide_pio_command *cmd,
void *buffer, size_t bytes)
{
+ int drive;
+ size_t count;
unsigned int status;
- /* FIXME handle commands with multiple blocks */
+ for(drive = 0; drive < IDE_MAX_DRIVES; drive++)
+ if(ctrl == harddisk_info[drive].ctrl)
+ break;
+ if(IDE_MAX_DRIVES == drive) {
+ debug("Invalid controller, not used for any drive\n");
+ return -1;
+ }
+
/* Wait until the busy bit is clear */
- if (await_ide(not_bsy, ctrl, currticks() + IDE_TIMEOUT) < 0) {
+ if (AWAIT_IDE(not_bsy, ctrl, IDE_TIMEOUT) < 0) {
+ debug("Device not ready before sending command\n");
return -1;
}
/* How do I tell if INTRQ is asserted? */
pio_set_registers(ctrl, cmd);
ndelay(400);
- if (await_ide(not_bsy, ctrl, currticks() + IDE_TIMEOUT) < 0) {
- return -1;
- }
- status = inb(IDE_REG_STATUS(ctrl));
- if (!(status & IDE_STATUS_DRQ)) {
- print_status(ctrl);
- return -1;
- }
- insw(IDE_REG_DATA(ctrl), buffer, bytes/2);
- status = inb(IDE_REG_STATUS(ctrl));
- if (status & IDE_STATUS_DRQ) {
- print_status(ctrl);
- return -1;
- }
+
+ /* multi block capable logic inspired by OpenBIOS ide.c
+ * ob_ide_pio_data_in() */
+ do {
+ count = bytes;
+ if (count > harddisk_info[drive].hw_sector_size)
+ count = harddisk_info[drive].hw_sector_size;
+ if (AWAIT_IDE(not_bsy, ctrl, IDE_TIMEOUT) < 0) {
+ debug("Device not ready before reading data\n");
+ return -1;
+ }
+ if (ctrl->stat & (IDE_STATUS_WFT | IDE_STATUS_ERR)) {
+ debug("IDE error before reading data\n");
+ print_status(ctrl);
+ return -1;
+ }
+ if (!(ctrl->stat & IDE_STATUS_DRQ))
+ if (AWAIT_IDE(drq, ctrl, IDE_TIMEOUT_50ms) < 0) {
+ debug("No DRQ from device after read command\n");
+ print_status(ctrl);
+ return -1;
+ }
+#ifdef IDE_32BIT_PIO
+ insl(IDE_REG_DATA(ctrl), buffer, count/4);
+#else
+ insw(IDE_REG_DATA(ctrl), buffer, count/2);
+#endif
+ buffer += count;
+ bytes -= count;
+ ndelay(400);
+ } while (bytes);
+
return 0;
}
@@ -402,7 +448,7 @@
memset(&cmd, 0, sizeof(cmd));
/* Wait until the busy bit is clear */
- if (await_ide(not_bsy, info->ctrl, currticks() + IDE_TIMEOUT) < 0) {
+ if (AWAIT_IDE(not_bsy, info->ctrl, IDE_TIMEOUT) < 0) {
return -1;
}
@@ -413,7 +459,7 @@
cmd.command = IDE_CMD_PACKET;
pio_set_registers(info->ctrl, &cmd);
ndelay(400);
- if (await_ide(not_bsy, info->ctrl, currticks() + IDE_TIMEOUT) < 0) {
+ if (AWAIT_IDE(not_bsy, info->ctrl, IDE_TIMEOUT) < 0) {
return -1;
}
status = inb(IDE_REG_STATUS(info->ctrl));
@@ -426,7 +472,7 @@
/* Send the packet */
outsw(IDE_REG_DATA(info->ctrl), packet, packet_len/2);
- if (await_ide(not_bsy, info->ctrl, currticks() + IDE_TIMEOUT) < 0) {
+ if (AWAIT_IDE(not_bsy, info->ctrl, IDE_TIMEOUT) < 0) {
return -1;
}
status = inb(IDE_REG_STATUS(info->ctrl));
@@ -445,19 +491,27 @@
return -1;
}
+#ifdef IDE_32BIT_PIO
+ insl(IDE_REG_DATA(info->ctrl), buffer, buffer_len/4);
+#else
insw(IDE_REG_DATA(info->ctrl), buffer, buffer_len/2);
-
+#endif
status = inb(IDE_REG_STATUS(info->ctrl));
if (status & IDE_STATUS_DRQ) {
+#ifdef IDE_32BIT_PIO
+ debug("drq after insl\n");
+#else
debug("drq after insw\n");
+#endif
print_status(info->ctrl);
return -1;
}
return 0;
}
-static inline int ide_read_sector_chs(
- struct harddisk_info *info, void *buffer, unsigned long sector)
+static inline int ide_read_sectors_chs(
+ struct harddisk_info *info, void *buffer, unsigned long sector,
+ unsigned long num_sectors)
{
struct ide_pio_command cmd;
unsigned int track;
@@ -465,8 +519,11 @@
unsigned int cylinder;
memset(&cmd, 0, sizeof(cmd));
- cmd.sector_count = 1;
+ if (num_sectors > 256)
+ return -1;
+ cmd.sector_count = 256 == num_sectors ? 0 : num_sectors;
+
//debug("ide_read_sector_chs: sector= %ld.\n",sector);
track = sector / info->sectors_per_track;
@@ -481,16 +538,20 @@
info->slave |
IDE_DH_CHS;
cmd.command = IDE_CMD_READ_SECTORS;
- return pio_data_in(info->ctrl, &cmd, buffer, IDE_SECTOR_SIZE);
+ return pio_data_in(info->ctrl, &cmd, buffer, IDE_SECTOR_SIZE * num_sectors);
}
-static inline int ide_read_sector_lba(
- struct harddisk_info *info, void *buffer, unsigned long sector)
+static inline int ide_read_sectors_lba(
+ struct harddisk_info *info, void *buffer, unsigned long sector,
+ unsigned long num_sectors)
{
struct ide_pio_command cmd;
memset(&cmd, 0, sizeof(cmd));
- cmd.sector_count = 1;
+ if (num_sectors > 256)
+ return -1;
+ cmd.sector_count = 256 == num_sectors ? 0 : num_sectors;
+
cmd.lba_low = sector & 0xff;
cmd.lba_mid = (sector >> 8) & 0xff;
cmd.lba_high = (sector >> 16) & 0xff;
@@ -500,17 +561,20 @@
IDE_DH_LBA;
cmd.command = IDE_CMD_READ_SECTORS;
//debug("%s: sector= %ld, device command= 0x%x.\n",__FUNCTION__,(unsigned long) sector, cmd.device);
- return pio_data_in(info->ctrl, &cmd, buffer, IDE_SECTOR_SIZE);
+ return pio_data_in(info->ctrl, &cmd, buffer, IDE_SECTOR_SIZE * num_sectors);
}
-static inline int ide_read_sector_lba48(
- struct harddisk_info *info, void *buffer, sector_t sector)
+static inline int ide_read_sectors_lba48(
+ struct harddisk_info *info, void *buffer, sector_t sector, sector_t num_sectors)
{
struct ide_pio_command cmd;
memset(&cmd, 0, sizeof(cmd));
//debug("ide_read_sector_lba48: sector= %ld.\n",(unsigned long) sector);
- cmd.sector_count = 1;
+ if (num_sectors > 256)
+ return -1;
+ cmd.sector_count = 256 == num_sectors ? 0 : num_sectors;
+
cmd.lba_low = sector & 0xff;
cmd.lba_mid = (sector >> 8) & 0xff;
cmd.lba_high = (sector >> 16) & 0xff;
@@ -519,7 +583,7 @@
cmd.lba_high2 = (sector >> 40) & 0xff;
cmd.device = info->slave | IDE_DH_LBA;
cmd.command = IDE_CMD_READ_SECTORS_EXT;
- return pio_data_in(info->ctrl, &cmd, buffer, IDE_SECTOR_SIZE);
+ return pio_data_in(info->ctrl, &cmd, buffer, IDE_SECTOR_SIZE * num_sectors);
}
static inline int ide_read_sector_packet(
@@ -567,27 +631,39 @@
return 0;
}
-int ide_read(int drive, sector_t sector, void *buffer)
+int ide_readmany(int drive, sector_t first_sector, sector_t num_sectors, void *buffer)
{
struct harddisk_info *info = &harddisk_info[drive];
int result;
+ sector_t i, last_sector = first_sector + num_sectors - 1;
- //debug("drive=%d, sector=%ld\n",drive,(unsigned long) sector);
- /* Report the buffer is empty */
- if (sector > info->sectors) {
+ if (0 == num_sectors) {
+ debug("0 sectors requested, nothing read\n");
+ return 0;
+ }
+ if (1 == num_sectors)
+ debug("sector %Lu to 0x%p\n", first_sector, buffer);
+ else
+ debug("sectors %Lu - %Lu (%3Lu) to 0x%p\n", first_sector, last_sector, num_sectors, buffer);
+ if (last_sector > info->sectors) {
+ debug("attempt to read past end of device");
return -1;
}
if (info->address_mode == ADDRESS_MODE_CHS) {
- result = ide_read_sector_chs(info, buffer, sector);
+ result = ide_read_sectors_chs(info, buffer, first_sector, num_sectors);
}
else if (info->address_mode == ADDRESS_MODE_LBA) {
- result = ide_read_sector_lba(info, buffer, sector);
+ result = ide_read_sectors_lba(info, buffer, first_sector, num_sectors);
}
else if (info->address_mode == ADDRESS_MODE_LBA48) {
- result = ide_read_sector_lba48(info, buffer, sector);
+ result = ide_read_sectors_lba48(info, buffer, first_sector, num_sectors);
}
else if (info->address_mode == ADDRESS_MODE_PACKET) {
- result = ide_read_sector_packet(info, buffer, sector);
+ for(i = 0; i < num_sectors; i++) {
+ result = ide_read_sector_packet(info, buffer, first_sector + i);
+ if (-1 == result)
+ return result;
+ }
}
else {
result = -1;
@@ -595,6 +671,11 @@
return result;
}
+int ide_read(int drive, sector_t sector, void *buffer)
+{
+ return ide_readmany(drive, sector, 1, buffer);
+}
+
static int init_drive(struct harddisk_info *info, struct controller *ctrl,
int slave, int drive, unsigned char *buffer, int ident_command)
{
@@ -864,7 +945,7 @@
*
*/
#if !BSY_SET_DURING_SPINUP
- if (await_ide(timeout, ctrl, currticks() + IDE_TIMEOUT) < 0) {
+ if (AWAIT_IDE(timeout, ctrl, IDE_TIMEOUT) < 0) {
return -1;
}
#endif
More information about the coreboot
mailing list