git: 9front

ref: 332f070e5a51e5fcc1f2f17f15f67aa98a01b5f4
dir: /sys/src/boot/pc/sdbios.c/

View raw version
/*
 * boot driver for BIOS devices with partitions.
 * devbios must be initialised first.
 */
#include "u.h"
#include "lib.h"
#include "mem.h"
#include "dat.h"
#include "fns.h"
#include "io.h"
#include "ureg.h"
#include "error.h"

#include "sd.h"
#include "fs.h"

long	biosread(Fs *, void *, long);
vlong	biosseek(Fs *fs, vlong off);

extern SDifc sdbiosifc;

uchar *
putbeul(ulong ul, uchar *p)
{
	*p++ = ul >> 24;
	*p++ = ul >> 16;
	*p++ = ul >> 8;
	*p++ = ul;
	return p;
}

uchar *
putbeuvl(uvlong uvl, uchar *p)
{
	*p++ = uvl >> 56;
	*p++ = uvl >> 48;
	*p++ = uvl >> 40;
	*p++ = uvl >> 32;
	*p++ = uvl >> 24;
	*p++ = uvl >> 16;
	*p++ = uvl >> 8;
	*p++ = uvl;
	return p;
}

int
biosverify(SDunit* )
{
	if (onlybios0 || !biosinited)
		return 0;
	return 1;
}

int
biosonline(SDunit* unit)
{
	if (onlybios0 || !biosinited || !unit)
		return 0;
	unit->secsize = 512;			/* conventional */
	unit->sectors = ~0ULL / unit->secsize;	/* all of them, and then some */
	return 1;
}

static int
biosrio(SDreq* r)
{
	int nb;
	long got;
	vlong off;
	uchar *p;
	Fs fs;			/* just for fs->dev, which is zero */

	if (onlybios0 || !biosinited)
		return SDeio;
	/*
	 * Most SCSI commands can be passed unchanged except for
	 * the padding on the end. The few which require munging
	 * are not used internally. Mode select/sense(6) could be
	 * converted to the 10-byte form but it's not worth the
	 * effort. Read/write(6) are easy.
	 */
	r->rlen = 0;
	r->status = SDok;
	switch(r->cmd[0]){
	case 0x08:			/* read */
	case 0x28:			/* read */
		if (r->cmd[0] == 0x08)
			panic("biosrio: 0x08 read op");
		off = r->cmd[2]<<24 | r->cmd[3]<<16 | r->cmd[4]<<8 | r->cmd[5];
		nb =  r->cmd[7]<<8  | r->cmd[8];	/* often 4 */
		USED(nb);			/* is nb*512 == r->dlen? */
		memset(&fs, 0, sizeof fs);
		biosseek(&fs, off*512);
		got = biosread(&fs, r->data, r->dlen);
		if (got < 0)
			r->status = SDeio;
		else
			r->rlen = got;
		break;
	case 0x0A:			/* write */
	case 0x2A:			/* write */
		r->status = SDeio;	/* boot programs don't write */
		break;

		/*
		 * Read capacity returns the LBA of the last sector.
		 */
	case 0x25:			/* read capacity */
		p = putbeul(r->unit->sectors - 1, r->data);
		r->data = putbeul(r->unit->secsize, p);
		return SDok;
	case 0x9E:			/* long read capacity */
		p = putbeuvl(r->unit->sectors - 1, r->data);
		r->data = putbeul(r->unit->secsize, p);
		return SDok;
	/* ignore others */
	}
	return r->status;
}

SDev*
biosid(SDev* sdev)
{
	for (; sdev; sdev = sdev->next)
		if (sdev->ifc == &sdbiosifc)
			sdev->idno = 'B';
	return sdev;
}

static SDev*
biospnp(void)
{
	SDev *sdev;

	/* 9pxeload can't use bios int 13 calls; they wedge the machine */
	if (pxe || !biosload || onlybios0 || !biosinited)
		return nil;
	if((sdev = malloc(sizeof(SDev))) != nil) {
		sdev->ifc = &sdbiosifc;
		sdev->index = -1;
		sdev->nunit = 1;
	}
	return sdev;
}

SDifc sdbiosifc = {
	"bios",				/* name */

	biospnp,			/* pnp */
	nil,				/* legacy */
	biosid,				/* id */
	nil,				/* enable */
	nil,				/* disable */

	biosverify,			/* verify */
	biosonline,			/* online */
	biosrio,			/* rio */
	nil,				/* rctl */
	nil,				/* wctl */

	scsibio,			/* bio */
};