~kris/9p

9hist

0751abb748fe12c6a2d306670c7fcd3948e675e9 — David du Colombier 35 years ago 31e6bc5
Plan 9 from Bell Labs 1991-08-23
7 files changed, 271 insertions(+), 270 deletions(-)

M pc/clock.c
M pc/devfloppy.c
M pc/devuart.c
M pc/kbd.c
M pc/main.c
M pc/trap.c
M port/devwren.c
M pc/clock.c => pc/clock.c +0 -1
@@ 62,7 62,6 @@ clock(Ureg *ur)
	m->ticks++;

	checkalarms();
	mouseclock();

	/*
	 *  process time accounting

M pc/devfloppy.c => pc/devfloppy.c +6 -29
@@ 31,12 31,6 @@ enum

	DMAchan=	2,	/* floppy dma channel */

	/* sector size encodings */
	S128=		0,
	S256=		1,
	S512=		2,
	S1024=		3,

	/* status 0 byte */
	Drivemask=	3<<0,
	Seekend=	1<<5,


@@ 45,7 39,6 @@ enum
	/* file types */
	Qdir=		0,
	Qdata=		(1<<2),
	Qstruct=	(2<<2),
	Qmask=		(3<<2),
};



@@ 163,14 156,10 @@ static long	floppyxfer(Drive*, int, void*, long, long);
static void	floppyintr(Ureg*);

Dirtab floppydir[]={
	"fd0data",		{Qdata + 0},	0,	0600,
	"fd0struct",		{Qstruct + 0},	8,	0600,
	"fd1data",		{Qdata + 1},	0,	0600,
	"fd1struct",		{Qstruct + 1},	8,	0600,
	"fd2data",		{Qdata + 2},	0,	0600,
	"fd2struct",		{Qstruct + 2},	8,	0600,
	"fd3data",		{Qdata + 3},	0,	0600,
	"fd3struct",		{Qstruct + 3},	8,	0600,
	"fd0disk",		{Qdata + 0},	0,	0600,
	"fd1disk",		{Qdata + 1},	0,	0600,
	"fd2disk",		{Qdata + 2},	0,	0600,
	"fd3disk",		{Qdata + 3},	0,	0600,
};
#define NFDIR	2	/* directory entries/drive */



@@ 337,15 326,6 @@ floppyread(Chan *c, void *a, long n)
			memmove(aa+rv, dp->ccache + (sec-1)*dp->t->bytes, len);
		}
		break;
	case Qstruct:
		if (n < 2*sizeof(ulong))
			error(Ebadarg);
		if (c->offset >= 2*sizeof(ulong))
			return 0;
		rv = 2*sizeof(ulong);
		ul2user((uchar*)a, dp->t->cap);
		ul2user((uchar*)a+sizeof(ulong), dp->t->bytes);
		break;
	default:
		panic("floppyread: bad qid");
	}


@@ 369,9 349,6 @@ floppywrite(Chan *c, void *a, long n)
				break;
		}
		break;
	case Qstruct:
		error(Eperm);
		break;
	default:
		panic("floppywrite: bad qid");
	}


@@ 733,7 710,7 @@ floppyxfer(Drive *dp, int cmd, void *a, long off, long n)
	if(floppyseek(dp) < 0)
		errors("seeking floppy");

print("tcyl %d, thead %d, tsec %d, addr %lux, n %d\n",
/*print("tcyl %d, thead %d, tsec %d, addr %lux, n %d\n",
		dp->tcyl, dp->thead, dp->tsec, addr, n);/**/

	/*


@@ 797,7 774,7 @@ print("new offset %d instead of %d\n", offset, off+dp->len);
static void
floppyintr(Ureg *ur)
{
print("floppy intr\n");
/*print("floppy intr\n");/**/
	floppy.intr = 1;
	wakeup(&floppy.r);
}

M pc/devuart.c => pc/devuart.c +32 -10
@@ 1,4 1,4 @@

#include	"u.h"
#include	"u.h"
#include	"lib.h"
#include	"mem.h"
#include	"dat.h"


@@ 18,6 18,10 @@ enum
	 */
	Data=	0,		/* xmit/rcv buffer */
	Iena=	1,		/* interrupt enable */
	 Ircv=	(1<<0),		/*  for char rcv'd */
	 Ixmt=	(1<<1),		/*  for xmit buffer empty */
	 Irstat=(1<<2),		/*  for change in rcv'er status */
	 Imstat=(1<<3),		/*  for change in modem status */
	Istat=	2,		/* interrupt flag (read) */
	Tctl=	2,		/* test control (write) */
	Format=	3,		/* byte format */


@@ 36,7 40,9 @@ enum
	 Loop=	(1<<4),		/*  loop bask */
	Lstat=	5,		/* line status */
	 Inready=(1<<0),	/*  receive buffer full */
	 Overrun=(1<<1),	/*  we lost an input char */
	 Oerror=(1<<1),		/*  receiver overrun */
	 Perror=(1<<2),		/*  receiver parity error */
	 Ferror=(1<<3),		/*  rcv framing error */
	 Outready=(1<<5),	/*  output buffer full */
	Mstat=	6,		/* modem status */
	Scratch=7,		/* scratchpad */


@@ 67,6 73,10 @@ struct Uart
	Alarm	*a;		/* alarm for waking the kernel process */
 	int	kstarted;	/* kproc started */
	uchar	delim[256/8];	/* characters that act as delimiters */

	/* error statistics */
	ulong	frame;
	ulong	overrun;
};

Uart uart[2];


@@ 213,14 223,15 @@ uartintr(Uart *up)
	IOQ *cq;
	int s, l;

	/*
	 *  the for loop takes care of multiple events per interrupt
	 */
	for(;;){
		s = uartrdreg(up, Istat);
		switch(s){
		case 6:	/* receiver line status */
			l = uartrdreg(up, Lstat);
			if(l & Ferror)
				up->frame++;
			if(l & Oerror)
				up->overrun++;
			break;
	
		case 4:	/* received data available */


@@ 233,9 244,6 @@ uartintr(Uart *up)
				if(up->delim[ch/8] & (1<<(ch&7)) )
					wakeup(&cq->r);
			}
			l = uartrdreg(up, Lstat);
			if(l & Overrun)
				screenputc('!');
			break;
	
		case 2:	/* transmitter empty */


@@ 257,7 265,7 @@ uartintr(Uart *up)
		default:
			if(s&1)
				return;
			print("weird modem interrupt\n");
/*			print("weird modem interrupt\n");/**/
			break;
		}
	}


@@ 290,6 298,11 @@ uartenable(Uart *up)
	}

	/*
	 *  speed up the clock to poll the uart
	fclockinit();
	 */

	/*
	 *  set up i/o routines
	 */
	if(up->oq){


@@ 304,7 317,7 @@ uartenable(Uart *up)
	/*
 	 *  turn on interrupts
	 */
	up->sticky[Iena] = 0x7;
	up->sticky[Iena] = Ircv | Ixmt | Irstat;
	uartwrreg(up, Iena, 0);

	/*


@@ 514,6 527,7 @@ uartkproc(void *a)
	IOQ *cq = up->iq;
	Block *bp;
	int n;
	ulong frame, overrun;

	if(waserror())
		print("uartkproc got an error\n");


@@ 531,6 545,14 @@ uartkproc(void *a)
			PUTNEXT(RD(up->wq), bp);
		}
		qunlock(up);
		if(up->frame != frame){
			kprint("uart%d: %d framing\n", up-uart, up->frame);
			frame = up->frame;
		}
		if(up->overrun != overrun){
			kprint("uart%d: %d overruns\n", up-uart, up->overrun);
			overrun = up->overrun;
		}
	}
}


M pc/kbd.c => pc/kbd.c +1 -0
@@ 359,6 359,7 @@ mymouseputc(int c)
		mouse.dx = msg[1];
		mouse.dy = -msg[2];
		mouse.track = 1;
		spllo();		/* mouse tracking kills uart0 */
		mouseclock();
	}
}

M pc/main.c => pc/main.c +11 -12
@@ 18,6 18,7 @@ main(void)
	confinit();
	screeninit();
	printinit();
	print("%lud K bytes of physical memory\n", 1024 + conf.npage1*BY2PG/1024);
	mmuinit();
	trapinit();
	kbdinit();


@@ 141,7 142,15 @@ confinit(void)
	int mul;

	/*
	 *  size memory
	 *  the first 640k is the standard useful memory
	 *  the next 128K is the display
	 *  the last 256k belongs to the roms
	 */
	conf.npage0 = 640/4;
	conf.base0 = 0;

	/*
	 *  size the non-standard memory
	 */
	x = 0x12345678;
	for(i=1; i<16; i++){


@@ 165,17 174,7 @@ confinit(void)
			break;
		x += 0x3141526;
	}

	/*
	 *  the first 640k is the standard useful memory
	 */
	conf.npage0 = 640/4;
	conf.base0 = 0;

	/*
	 *  the last 128k belongs to the roms
	 */
	conf.npage1 = (i-1)*1024/4;
	conf.npage1 = (i-2)*1024/4;
	conf.base1 = 1024*1024;

	conf.npage = conf.npage0 + conf.npage1;

M pc/trap.c => pc/trap.c +19 -24
@@ 79,27 79,27 @@ trapinit(void)
	 *  set all interrupts to panics
	 */
	for(i = 32; i < 256; i++)
		sethvec(i, intrbad, SEGIG, 0);
		sethvec(i, intrbad, SEGTG, 0);

	/*
	 *  set the standard traps
	 */
	sethvec(0, intr0, SEGIG, 0);
	sethvec(1, intr1, SEGIG, 0);
	sethvec(2, intr2, SEGIG, 0);
	sethvec(3, intr3, SEGIG, 0);
	sethvec(4, intr4, SEGIG, 0);
	sethvec(5, intr5, SEGIG, 0);
	sethvec(6, intr6, SEGIG, 0);
	sethvec(7, intr7, SEGIG, 0);
	sethvec(8, intr8, SEGIG, 0);
	sethvec(9, intr9, SEGIG, 0);
	sethvec(10, intr10, SEGIG, 0);
	sethvec(11, intr11, SEGIG, 0);
	sethvec(12, intr12, SEGIG, 0);
	sethvec(13, intr13, SEGIG, 0);
	sethvec(14, intr14, SEGIG, 0);
	sethvec(15, intr15, SEGIG, 0);
	sethvec(0, intr0, SEGTG, 0);
	sethvec(1, intr1, SEGTG, 0);
	sethvec(2, intr2, SEGTG, 0);
	sethvec(3, intr3, SEGTG, 0);
	sethvec(4, intr4, SEGTG, 0);
	sethvec(5, intr5, SEGTG, 0);
	sethvec(6, intr6, SEGTG, 0);
	sethvec(7, intr7, SEGTG, 0);
	sethvec(8, intr8, SEGTG, 0);
	sethvec(9, intr9, SEGTG, 0);
	sethvec(10, intr10, SEGTG, 0);
	sethvec(11, intr11, SEGTG, 0);
	sethvec(12, intr12, SEGTG, 0);
	sethvec(13, intr13, SEGTG, 0);
	sethvec(14, intr14, SEGTG, 0);
	sethvec(15, intr15, SEGTG, 0);

	/*
	 *  set the standard devices


@@ 188,15 188,11 @@ trap(Ureg *ur)
		if(c == Int1vec)
			outb(Int1ctl, EOI);
		outb(Int0ctl, EOI);
		if(v != Uart0vec)
			uartintr0(ur);
	}

	/*
	 *  check for a waiting character, the uart is at too low
	 *  a priority level to work correctly at 9600 baud.
	 */
	uartintr0(ur);

	/*
	 *  call the trap routine
	 */
	(*ivec[v])(ur);


@@ 270,7 266,6 @@ syscall(Ureg *ur)
	u->p->pc = ur->pc;
	if((ur->cs)&0xffff == KESEL)
		panic("recursive system call");
	spllo();

	/*
	 *  do something about floating point!!!

M port/devwren.c => port/devwren.c +202 -194
@@ 7,41 7,41 @@
#include	"devtab.h"
#include	"io.h"

typedef struct Part	Part;
typedef struct Disk	Disk;
typedef struct Partition	Partition;
typedef struct Drive		Drive;

enum {
	Npart=		2,	/* maximum partitions per disk */
	Npart=		8+2,	/* 8 sub partitions, disk, and partition */
	Ndisk=		64,	/* maximum disks */

	/* file types */
	Qdir=		0,
	Qdata=		16,
	Qstruct=	32,

	Mask=		0x7,
};
#define PART(x)		((x)&0xF)
#define DRIVE(x)	(((x)>>4)&0x7)
#define MKQID(d,p)	(((d)<<4) | (p))

static Dirtab *wrendir;
#define	NWREN	(2*(Npart+1))

struct Part
struct Partition
{
	ulong 	firstblock;
	ulong 	maxblock;
	ulong	start;
	ulong	end;
	char	name[NAMELEN+1];
};
struct Disk

struct Drive
{
	ulong	blocksize;
	Part	p[Npart];
	ulong		bytes;			/* bytes per block */
	int		npart;			/* actual number of partitions */
	int		drive;
	Partition	p[Npart];
};

static Disk	wren[Ndisk];

void	wrenint(uchar*, ulong);
static Drive	wren[Ndisk];

#define	DATASIZE	(8*1024)	/* BUG */

#define	BGLONG(p)	(((((((p)[0]<<8)|(p)[1])<<8)|(p)[2])<<8)|(p)[3])
static void	wrenpart(int);
static long	wrenio(Drive *, Partition *, int, char *, ulong, ulong);

/*
 *  accepts [0-7].[0-7], or abbreviation


@@ 50,21 50,22 @@ static int
wrendev(char *p)
{
	int dev = 0;
	if (p==0 || p[0]==0)

	if(p == 0 || p[0] == 0)
		goto out;
	if (p[0]<'0' || p[0]>'7')
	if(p[0] < '0' || p[0] > '7')
		goto cant;
	dev = (p[0]-'0')<<3;
	if (p[1]==0)
	dev = (p[0] - '0') << 3;
	if(p[1] == 0)
		goto out;
	if (p[1]!='.')
	if(p[1] != '.')
		goto cant;
	if (p[2]==0)
	if(p[2] == 0)
		goto out;
	if (p[2]<'0' || p[2]>'7')
	if(p[2] < '0' || p[2] > '7')
		goto cant;
	dev |= p[2]-'0';
	if (p[3]!=0)
	dev |= p[2] - '0';
	if(p[3] != 0)
		goto cant;
out:
	if(dev >= Ndisk)


@@ 75,58 76,43 @@ cant:
}

static int
wrengen(Chan *c, Dirtab *tab, long ntab, long s, Dir *dp)
wrengen(Chan *c, Dirtab *tab, long ntab, long s, Dir *dirp)
{
	long l;
	Part *p;
	Disk *d;

	if(s >= ntab)
		return -1;
	if(c->dev >= Ndisk)
	Qid qid;
	int drive;
	char name[NAMELEN+4];
	Drive *dp;
	Partition *pp;
	ulong l;

	qid.vers = 0;
	drive = s/Npart;
	s = s % Npart;
	if(drive >= Ndisk)
		return -1;
	dp = &wren[drive];

	tab += s;
	d = &wren[c->dev];
	p = &d->p[tab->qid.path&Mask];
	if((tab->qid.path&~Mask) == Qdata)
		l = d->blocksize * (p->maxblock - p->firstblock);
	else
		l = 8;
	devdir(c, tab->qid, tab->name, l, tab->perm, dp);
	if(s >= dp->npart)
		return 0;

	pp = &dp->p[s];
	sprint(name, "hd%d%s", drive, pp->name);
	name[NAMELEN] = 0;
	qid.path = MKQID(drive, s);
	l = (pp->end - pp->start) * dp->bytes;
	devdir(c, qid, name, l, 0600, dirp);
	return 1;
}

void
wrenreset(void)
{
	Dirtab *p;
	int i;

	p = wrendir = ialloc((Npart+1) * 2 * sizeof(Dirtab), 0);
	for(i = 0; i < Npart; i++){
		sprint(p->name, "data%d", i);
		p->qid.path = Qdata + i;
		p->perm = 0600;
		p++->length = 0;
		sprint(p->name, "struct%d", i);
		p->qid.path = Qstruct + i;
		p->perm = 0600;
		p++->length = 0;
	}
	strcpy(p->name, "data");
	p->qid.path = Qdata + Npart;
	p->perm = 0600;
	p++->length = 0;
	strcpy(p->name, "struct");
	p->qid.path = Qstruct + Npart;
	p->perm = 0600;
	p->length = 0;
}

void
wreninit(void)
{}
{
}

/*
 *  param is #r<target>.<lun>


@@ 134,34 120,17 @@ wreninit(void)
Chan *
wrenattach(char *param)
{
	uchar buf[32];
	int dev;
	Chan *c;
	Disk *d;
	ulong plen;
	int i;
	int drive;

	dev = wrendev(param);
	scsiready(dev);
	scsisense(dev, buf);
	scsicap(dev, buf);
	drive = wrendev(param);
	wrenpart(drive);
	c = devattach('r', param);
	c->dev = dev;
	d = &wren[dev];
	d->blocksize = BGLONG(&buf[4]);

	plen = BGLONG(&buf[0])+1;
	d->p[Npart].firstblock = 0;
	d->p[Npart].maxblock = plen;
	plen = plen/Npart;
	for(i = 0; i < Npart; i++){
		d->p[i].firstblock = i*plen;
		d->p[i].maxblock = (i+1)*plen;
	}
	c->dev = drive;
	return c;
}

Chan *
Chan*
wrenclone(Chan *c, Chan *nc)
{
	return devclone(c, nc);


@@ 170,21 139,19 @@ wrenclone(Chan *c, Chan *nc)
int
wrenwalk(Chan *c, char *name)
{
	return devwalk(c, name, wrendir, NWREN, wrengen);
	return devwalk(c, name, 0, 0, wrengen);
}

void
wrenstat(Chan *c, char *db)
wrenstat(Chan *c, char *dp)
{
	devstat(c, db, wrendir, NWREN, wrengen);
	devstat(c, dp, 0, 0, wrengen);
}

Chan *
Chan*
wrenopen(Chan *c, int omode)
{
	if (c->qid.path == Qdata && scsiready(c->dev) != 0)
		error(Eio);
	return devopen(c, omode, wrendir, NWREN, wrengen);
	return devopen(c, omode, 0, 0, wrengen);
}

void


@@ 195,123 162,164 @@ wrencreate(Chan *c, char *name, int omode, ulong perm)

void
wrenclose(Chan *c)
{}
{
}

void
wrenremove(Chan *c)
{
	error(Eperm);
}

void
wrenwstat(Chan *c, char *dp)
{
	error(Eperm);
}

long
wrenread(Chan *c, char *a, long n, ulong offset)
{
	Scsi *cmd;
	ulong lbn;
	Part *p;
	Disk *d;
	Drive *d;
	Partition *p;

	if (n == 0)
		return 0;

	if(c->qid.path == CHDIR)
		return devdirread(c, a, n, wrendir, NWREN, wrengen);

	d = &wren[c->dev];
	p = &(d->p[Mask&c->qid.path]);
	switch ((int)(c->qid.path & ~Mask)) {
	case Qdata:
		if (n % d->blocksize || offset % d->blocksize)
			error(Ebadarg);
		lbn = (offset/d->blocksize) + p->firstblock;
		if (lbn >= p->maxblock)
			error(Ebadarg);
		if (n > DATASIZE)
			n = DATASIZE;
		cmd = scsicmd(c->dev, 0x08, n);
		if (waserror()) {
			qunlock(cmd);
			nexterror();
		}
		cmd->cmdblk[1] = lbn>>16;
		cmd->cmdblk[2] = lbn>>8;
		cmd->cmdblk[3] = lbn;
		cmd->cmdblk[4] = n/d->blocksize;
		scsiexec(cmd, 1);
		n = cmd->data.ptr - cmd->data.base;
		memmove(a, cmd->data.base, n);
		qunlock(cmd);
		poperror();
		break;
	case Qstruct:
		if (n < 2*sizeof(ulong))
			error(Ebadarg);
		if (offset >= 2*sizeof(ulong))
			return 0;
		n = 2*sizeof(ulong);
		wrenint((uchar*)a, p->maxblock - p->firstblock);
		wrenint((uchar*)a+sizeof(ulong), d->blocksize);
		break;
	default:
		panic("wrenread");
	}
	return n;
		return devdirread(c, a, n, 0, 0, wrengen);

	d = &wren[DRIVE(c->qid.path)];
	p = &d->p[PART(c->qid.path)];
	return wrenio(d, p, 0, a, n, offset);
}

long
wrenwrite(Chan *c, char *a, long n, ulong offset)
{
	Drive *d;
	Partition *p;

	d = &wren[DRIVE(c->qid.path)];
	p = &d->p[PART(c->qid.path)];
	return wrenio(d, p, 1, a, n, offset);
}

static long
wrenio(Drive *d, Partition *p, int write, char *a, ulong n, ulong offset)
{
	Scsi *cmd;
	ulong lbn;
	Part *p;
	Disk *d;
	void *b;
	ulong block;

	if (n == 0)
	if(n % d->bytes || offset % d->bytes)
		error(Ebadarg);
	block = offset / d->bytes + p->start;
	if(block >= p->end)
		return 0;

	d = &wren[c->dev];
	p = &(d->p[Mask&c->qid.path]);
	switch ((int)(c->qid.path & ~Mask)) {
	case Qdata:
		if (n % d->blocksize || offset % d->blocksize)
			error(Ebadarg);
		lbn = offset/d->blocksize + p->firstblock;
		if (lbn >= p->maxblock)
			error(Ebadarg);
		if (n > DATASIZE)
			n = DATASIZE;
		cmd = scsicmd(c->dev, 0x0a, n);
		if (waserror()) {
			qunlock(cmd);
			nexterror();
		}
		cmd->cmdblk[1] = lbn>>16;
		cmd->cmdblk[2] = lbn>>8;
		cmd->cmdblk[3] = lbn;
		cmd->cmdblk[4] = n/d->blocksize;
		memmove(cmd->data.base, a, n);
		scsiexec(cmd, 0);
		n = cmd->data.ptr - cmd->data.base;
	if(n > DATASIZE)
		n = DATASIZE;
	n /= d->bytes;
	if(block + n > p->end)
		n = p->end - block;
	if(n == 0)
		return 0;
	if(write)
		cmd = scsicmd(d->drive, 0x0a, n*d->bytes);
	else
		cmd = scsicmd(d->drive, 0x08, n*d->bytes);
	if(waserror()){
		qunlock(cmd);
		poperror();
		break;
	default:
		panic("wrenwrite");
		nexterror();
	}
	cmd->cmdblk[1] = block>>16;
	cmd->cmdblk[2] = block>>8;
	cmd->cmdblk[3] = block;
	cmd->cmdblk[4] = n;
	if(write)
		memmove(cmd->data.base, a, n*d->bytes);
	scsiexec(cmd, !write);
	n = cmd->data.ptr - cmd->data.base;
	if(!write)
		memmove(a, cmd->data.base, n);
	qunlock(cmd);
	poperror();
	return n;
}

void
wrenremove(Chan *c)
{
	error(Eperm);
}

void
wrenwstat(Chan *c, char *dp)
/*
 *  read partition table.  The partition table is just ascii strings.
 */
#define MAGIC "plan9 partitions"
static void
wrenpart(int dev)
{
	error(Eperm);
}
	Scsi *cmd;
	Drive *dp;
	Partition *pp;
	uchar buf[32];
	char *b;
	char *line[Npart+1];
	char *field[3];
	ulong n;
	int i;

void
wrenint(uchar *a, ulong x)
{
	a[0] = x >> 24;
	a[1] = x >> 16;
	a[2] = x >> 8;
	a[3] = x;
	scsiready(dev);
	scsisense(dev, buf);
	scsicap(dev, buf);
	dp = &wren[dev];
	dp->drive = dev;
	if(dp->npart)
		return;
	/*
	 *  we always have a partition for the whole disk
	 *  and one for the partition table
	 */
	dp->bytes = (buf[4]<<24)+(buf[5]<<16)+(buf[6]<<8)+(buf[7]);
	pp = &dp->p[0];
	strcpy(pp->name, "disk");
	pp->start = 0;
	pp->end = (buf[0]<<24)+(buf[1]<<16)+(buf[2]<<8)+(buf[3]) + 1;
	pp++;
	strcpy(pp->name, "partition");
	pp->start = dp->p[0].end - 1;
	pp->end = dp->p[0].end;
	dp->npart = 2;

	/*
	 *  read partition table from disk, null terminate
	 */
	cmd = scsicmd(dev, 0x08, dp->bytes);
	if(waserror()){
		qunlock(cmd);
		nexterror();
	}
	n = dp->p[0].end-1;
	cmd->cmdblk[1] = n>>16;
	cmd->cmdblk[2] = n>>8;
	cmd->cmdblk[3] = n;
	cmd->cmdblk[4] = 1;
	scsiexec(cmd, 1);
	cmd->data.base[dp->bytes-1] = 0;

	/*
	 *  parse partition table.
	 */
	n = getfields((char *)cmd->data.base, line, Npart+1, '\n');
	if(strncmp(line[0], MAGIC, sizeof(MAGIC)-1) != 0)
		goto out;
	for(i = 1; i < n; i++){
		pp++;
		if(getfields(line[i], field, 3, ' ') != 3){
			break;
		}
		strncpy(pp->name, field[0], NAMELEN);
		pp->start = strtoul(field[1], 0, 0);
		pp->end = strtoul(field[2], 0, 0);
		if(pp->start > pp->end || pp->start >= dp->p[0].end){
			break;
		}
		dp->npart++;
	}
out:
	qunlock(cmd);
	poperror();
}