FreeBSD/sys/boot/i386/libi386/bioscd.c
/* return negative value for an error, otherwise blocks read */
return negative value for an error, otherwise blocks read
return negative value for an error otherwise blocks read
static int
bc_read(int unit, daddr_t dblk, int blks, caddr_t dest)
{
	u_int maxfer, resid, result, retry, x;
	caddr_t bbuf, p, xp;
	static struct edd_packet packet;
	int biosdev;
#ifdef DISK_DEBUG
	int error;
#endif
	if (blks < 0)
		return (-1);
	if (blks == 0)
		return (0);
	if (VTOP(dest) >> 20 != 0) {
		x = min(CD_BOUNCEBUF, (unsigned)blks);
		bbuf = alloca(x * BIOSCD_SECSIZE);
		maxfer = x;
	} else {
		bbuf = NULL;
		maxfer = 0;
	}
	biosdev = bc_unit2bios(unit);
	resid = blks;
	p = dest;
	while (resid > 0) {
		if (bbuf)
			xp = bbuf;
		else
			xp = p;
		x = resid;
		if (maxfer > 0)
			x = min(x, maxfer);
		for (retry = 0; retry < 3; retry++) {
			if (retry > 0) {
				v86.ctl = V86_FLAGS;
				v86.addr = 0x13;
				v86.eax = 0;
				v86.edx = biosdev;
				v86int();
			}
			packet.len = sizeof(struct edd_packet);
			packet.count = x;
			packet.off = VTOPOFF(xp);
			packet.seg = VTOPSEG(xp);
			packet.lba = dblk;
			v86.ctl = V86_FLAGS;
			v86.addr = 0x13;
			v86.eax = 0x4200;
			v86.edx = biosdev;
			v86.ds = VTOPSEG(&packet);
			v86.esi = VTOPOFF(&packet);
			v86int();
			result = V86_CY(v86.efl);
			if (result == 0)
				break;
			x = 1;
		}
#ifdef DISK_DEBUG
		error = (v86.eax >> 8) & 0xff;
#endif
		DEBUG("%d sectors from %lld to %p (0x%x) %s", x, dblk, p,
		    VTOP(p), result ? "failed" : "ok");
		DEBUG("unit %d  status 0x%x", unit, error);
		if (result != 0)
			break;
		if (bbuf != NULL)
			bcopy(bbuf, p, x * BIOSCD_SECSIZE);
		p += (x * BIOSCD_SECSIZE);
		dblk += x;
		resid -= x;
	}
	if (blks - resid == 0)
		return (-1);		
	return (blks - resid);
}
static int bc_read ( int unit , daddr_t dblk , int blks , caddr_t dest ) { u_int maxfer , resid , result , retry , x ; caddr_t bbuf , p , xp ; static struct edd_packet packet ; int biosdev ; #ifdef DISK_DEBUG int error ; #endif if ( blks < 0 ) return ( -1 ) ; if ( blks == 0 ) return ( 0 ) ; if ( VTOP ( dest ) >> 20 != 0 ) { x = min ( CD_BOUNCEBUF , ( unsigned ) blks ) ; bbuf = alloca ( x * BIOSCD_SECSIZE ) ; maxfer = x ; } else { bbuf = NULL ; maxfer = 0 ; } biosdev = bc_unit2bios ( unit ) ; resid = blks ; p = dest ; while ( resid > 0 ) { if ( bbuf ) xp = bbuf ; else xp = p ; x = resid ; if ( maxfer > 0 ) x = min ( x , maxfer ) ; for ( retry = 0 ; retry < 3 ; retry ++ ) { if ( retry > 0 ) { v86 . ctl = V86_FLAGS ; v86 . addr = 0x13 ; v86 . eax = 0 ; v86 . edx = biosdev ; v86int ( ) ; } packet . len = sizeof ( struct edd_packet ) ; packet . count = x ; packet . off = VTOPOFF ( xp ) ; packet . seg = VTOPSEG ( xp ) ; packet . lba = dblk ; v86 . ctl = V86_FLAGS ; v86 . addr = 0x13 ; v86 . eax = 0x4200 ; v86 . edx = biosdev ; v86 . ds = VTOPSEG ( & packet ) ; v86 . esi = VTOPOFF ( & packet ) ; v86int ( ) ; result = V86_CY ( v86 . efl ) ; if ( result == 0 ) break ; x = 1 ; } #ifdef DISK_DEBUG error = ( v86 . eax >> 8 ) & 0xff ; #endif DEBUG ( " " , x , dblk , p , VTOP ( p ) , result ? " " : " " ) ; DEBUG ( " " , unit , error ) ; if ( result != 0 ) break ; if ( bbuf != NULL ) bcopy ( bbuf , p , x * BIOSCD_SECSIZE ) ; p += ( x * BIOSCD_SECSIZE ) ; dblk += x ; resid -= x ; } if ( blks - resid == 0 ) return ( -1 ) ; return ( blks - resid ) ; }
return negative value for an error, otherwise blocks read
return negative value for an error otherwise blocks read
/* Just in case some idiot actually tries to read -1 blocks... */ /* If nothing to do, just return succcess. */ /* Decide whether we have to bounce */ /* 
		 * The destination buffer is above first 1MB of
		 * physical memory so we have to arrange a suitable
		 * bounce buffer.
		 */ /*
		 * Loop retrying the operation a couple of times.  The BIOS
		 * may also retry.
		 */ /* If retrying, reset the drive */ /* fall back to 1 sector read */ /* still an error? break off */ /*	hexdump(dest, (blks * BIOSCD_SECSIZE)); */ /* read failed */