blob: 60c4e707eb7e49ebc0ab4eeeb885f9ec4daac071 [file] [log] [blame]
/*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
* Copyright (C) Hewlett-Packard (Paul Bame) paul_bame@hp.com
*/
#include <stddef.h>
#include <asm/pdc.h>
#include "bootloader.h"
#undef PAGE0
#define PAGE0 ((struct zeropage *)0x00000000)
/*
* Sequential seekread from boot device.
* Return -1 if failed, or 0 if successful.
*/
static int pdc_bootdev_read(int fd,
char *dest,
unsigned int n,
__u64 seek)
{
unsigned long nbytes = 0;
static __u64 devaddr = 0;
if (1 && Debug) printf("pdc_bootdev_read(fd:%d, dest:0x%p, n:%u, seek:0x%llx)\n",
fd, dest, n, seek);
if ((unsigned int)dest & 0x3f) {
printf("\nERROR: Boot device I/O buffer not properly aligned.\n");
return -1;
} else if (n % FW_BLOCKSIZE) {
printf("\nERROR: Boot device read size not a multiple of 2048.\n");
return -1;
}
if (PAGE0->mem_boot.cl_class == CL_RANDOM)
{
devaddr = seek;
}
else
{
/* check for rewind semantic */
if (seek < devaddr)
{
printf("NOTE: pdc_bootdev_read() asked to seek to 0x%llx from 0x%llx, rewinding...\n", seek, devaddr);
/* IODC needs devaddr 0 to do a rewind */
devaddr = 0;
}
while (devaddr < seek)
{
__u64 nseek = seek - devaddr;
int count;
if (nseek > n)
nseek = n;
if ((count = pdc_iodc_bootin(devaddr, dest, nseek)) < 0)
{
die("pdc_iodc_bootin() died during seekread\r\n");
devaddr += nseek;
if (devaddr > 30*1024*1024) /* 30MB */
printf("If you boot via tftp you probably reached the 32MB limit.\n");
pdc_do_reset();
return -1;
}
devaddr += count;
}
}
while (nbytes < n)
{
int count;
/* how many bytes should be read? */
count = n - nbytes;
if (Debug) printf("pdc_iodc_bootin(dev:0x%llx, buf:0x%p, count:%u) = ",
devaddr, dest+nbytes, count);
count = pdc_iodc_bootin(devaddr, dest + nbytes, count);
if (Debug) printf("%d\r\n", count);
if (0 && Debug)
{
int i;
for (i = 0; i < 16; i++)
printf(" %02x", dest[nbytes + i] & 0xff);
printf("\n");
}
if (count == 0)
{
break;
}
else if (count > 0)
{
if (devaddr >= seek)
{
/* normal seekread */
nbytes += count;
}
devaddr += count;
}
else
{
/* this could happen after a partial good seekread, which will */
/* essentially be lost right now */
if (Debug) printf("\nERROR: Read from boot device failed (status = %d).\n",
count);
devaddr += (n - nbytes);
return -1;
}
}
return nbytes;
}
static void pdc_bootdev_describe(int fd, int *bufalign,
int *blocksize)
{
if (bufalign != 0)
*bufalign = disk_2gb_limit ? 64 : FW_BLOCKSIZE;
if (blocksize != 0)
*blocksize = FW_BLOCKSIZE;
}
/* returns true if OK */
int pdc_bootdev_open()
{
return fileio_open(pdc_bootdev_describe, pdc_bootdev_read);
}