[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