~kris/9p

9hist

c25663f25265cbe3c0c7acf29156c7795cfd6549 — David du Colombier 34 years ago 1efdb88
Plan 9 from Bell Labs 1992-08-08
M boot/settime.c => boot/settime.c +0 -1
@@ 12,7 12,6 @@ settime(int islocal)
	int timeset;
	Dir dir;
	char dirbuf[DIRLEN];
	char *srvname;

	print("time...");
	timeset = 0;

M gnot/dat.h => gnot/dat.h +0 -7
@@ 8,7 8,6 @@ typedef struct MMU	MMU;
typedef struct Mach	Mach;
typedef struct PMMU	PMMU;
typedef struct Portpage	Portpage;
typedef struct Scsibuf	Scsibuf;
typedef struct Ureg	Ureg;
typedef struct User	User;



@@ 139,12 138,6 @@ struct Portpage

extern int	portispaged;

struct Scsibuf
{
	void	*virt;
	void	*phys;
};

#define	NERR	25
#define	NNOTE	5
struct User

M gnot/devport.c => gnot/devport.c +1 -1
@@ 34,7 34,7 @@ Dirtab portdir[]={

#define	Nportservice	8
static	int (*portservice[Nportservice])(void);
static	Portpage portpage;
	Portpage portpage;
static	Lock intrlock;

int

M gnot/fns.h => gnot/fns.h +0 -9
@@ 36,15 36,6 @@ void	restfpregs(FPsave*);
void	screeninit(void);
void	screenputc(int);
void	screenputs(char*, int);
Scsibuf	*scsialloc(ulong);
int	scsibread(int, Scsibuf*, long, long, long);
int	scsibwrite(int, Scsibuf*, long, long, long);
Scsibuf	*scsibuf(void);
int	scsicap(int, void*);
void	scsifree(Scsibuf*);
int	scsiready(int);
int	scsisense(int, void *);
int	scsicap(int, uchar *);
void	scsictrlintr(void);
void	scsidmaintr(void);
uchar*	scsirecv(uchar *);

A gnot/scsi.c => gnot/scsi.c +309 -0
@@ 0,0 1,309 @@
#include	"u.h"
#include	"../port/lib.h"
#include	"mem.h"
#include	"dat.h"
#include	"fns.h"
#include	"../port/error.h"
#include	"devtab.h"
#include	"io.h"

int	scsiintr(void);

#define	DPRINT	if(debug)kprint

int	scsidebugs[8];
int	scsiownid = 0x08|7; /* enable advanced features */

Scsibuf *
scsialloc(ulong n)
{
	Scsibuf *b;

	b = xalloc(sizeof(Scsibuf));
	b->virt = b->phys = xalloc(n);
	return b;
}

typedef struct Scsictl {
	uchar	asr;
	uchar	data;
	uchar	stat;
	uchar	dma;
} Scsictl;

#define	Scsiaddr	48
#define	DEV	((Scsictl *)&PORT[Scsiaddr])

static long	poot;
#define	WAIT	(poot=0, poot==0?0:poot)

#define	PUT(a,d)	(DEV->asr=(a), WAIT, DEV->data=(d))
#define	GET(a)		(DEV->asr=(a), WAIT, DEV->data)

enum Int_status {
	Inten = 0x01, Scsirst = 0x02,
	INTRQ = 0x01, DMA = 0x02,
};

enum SBIC_regs {
	Own_id=0x00, Control=0x01, CDB=0x03, Target_LUN=0x0f,
	Cmd_phase=0x10, Tc_hi=0x12,
	Dest_id=0x15, Src_id=0x16, SCSI_Status=0x17,
	Cmd=0x18, Data=0x19,
};

enum Commands {
	Reset = 0x00,
	Assert_ATN = 0x02,
	Negate_ACK = 0x03,
	Select_with_ATN = 0x06,
	Select_with_ATN_and_Xfr = 0x08,
	Select_and_Xfr = 0x09,
	Transfer_Info = 0x20,
	SBT = 0x80,		/* modifier for single-byte transfer */
};

enum Aux_status {
	INT=0x80, LCI=0x40, BSY=0x20, CIP=0x10,
	PE=0x02, DBR=0x01,
};

static int	isscsi;
static QLock	scsilock;
static Rendez	scsirendez;
static uchar *	datap;
static uchar *	datalim;
static long	debug, scsirflag, scsibusy, scsiinservice;

static void
nop(void)
{}

void
resetscsi(void)
{
	static int inited;

	if(!inited)
		addportintr(scsiintr);
	inited = 1;
}

void
initscsi(void)
{
	isscsi = portprobe("scsi", -1, Scsiaddr, -1, 0L);
	if (isscsi >= 0) {
		DEV->stat = Scsirst;
		delay(100);
		DEV->stat = Inten;
		while (DEV->stat & (INTRQ|DMA))
			nop();
		scsiownid &= 0x0f; /* possibly advanced features */
		scsiownid |= 0x80; /* 16MHz */
		PUT(Own_id, scsiownid);
		PUT(Cmd, Reset);
	}
}

static int
scsidone(void *arg)
{
	USED(arg);
	return (scsibusy == 0);
}

int
scsiexec(Scsi *p, int rflag)
{
	long n;

	debug = scsidebugs[p->target&7];
	DPRINT("scsi %d.%d %2.2ux ", p->target, p->lun, *(p->cmd.ptr));
	qlock(&scsilock);
	if(waserror()){
		qunlock(&scsilock);
		DPRINT(" error return\n");
		nexterror();
	}
	scsirflag = rflag;
	p->rflag = rflag;
	datap = p->data.base;
	datalim = p->data.lim;
	if ((scsiownid & 0x08) && rflag)
		PUT(Dest_id, 0x40|p->target);
	else
		PUT(Dest_id, p->target);
	PUT(Target_LUN, p->lun);
	n = p->data.lim - p->data.base;
	PUT(Tc_hi, n>>16);
	DEV->data = n>>8;
	DEV->data = n;
	if (scsiownid & 0x08) {
		n = p->cmd.lim - p->cmd.ptr;
		DPRINT("len=%d ", n);
		PUT(Own_id, n);
	}
	PUT(CDB, *(p->cmd.ptr)++);
	while (p->cmd.ptr < p->cmd.lim)
		DEV->data = *(p->cmd.ptr)++;
	scsibusy = 1;
	PUT(Cmd, Select_and_Xfr);
	/*PUT(Cmd, Select_with_ATN_and_Xfr);*/
	DPRINT("S<");
	sleep(&scsirendez, scsidone, 0);
	DPRINT(">\n");
	p->data.ptr = datap;
	p->status = GET(Target_LUN);
	p->status |= DEV->data<<8;
	poperror();
	qunlock(&scsilock);
	debug = 0;
	return p->status;
}

void
scsirun(void)
{
	wakeup(&scsirendez);
	scsibusy = 0;
}

void
scsireset0(void)
{
/*	PUT(Control, 0x29);	/* burst DMA, halt on parity error */
	PUT(Control, 0x28);	/* burst DMA, allow parity errors */
	PUT(Control+1, 0xff);	/* timeout */
	PUT(Src_id, 0x80);	/* enable reselection */
	scsirun();
	/*qunlock(&scsilock);*/
}

int
scsiintr(void)
{
	int status, s;

	if(isscsi < 0 || scsiinservice
		|| !((status = DEV->stat) & (DMA|INTRQ)))
			return 0;
	DEV->stat = 0;
	scsiinservice = 1;
	s = spl1();
	DPRINT("i%x ", status);
	do{
		if (status & DMA)
			scsidmaintr();
		if (status & INTRQ)
			scsictrlintr();
	}while ((status = DEV->stat) & (DMA|INTRQ));
	splx(s);
	scsiinservice = 0;
	DEV->stat = Inten;
	return 1;
}

void
scsidmaintr(void)
{
	uchar *p = 0;
/*
 *	if (scsirflag) {
 *		unsigned char *p;
 *		DPRINT("R", p=datap);
 *		do
 *			*datap++ = DEV->dma;
 *		while (DEV->stat & DMA);
 *		DPRINT("%d ", datap-p);
 *	} else {
 *		unsigned char *p;
 *		DPRINT("W", p=datap);
 *		do
 *			DEV->dma = *datap++;
 *		while (DEV->stat & DMA);
 *		DPRINT("%d ", datap-p);
 *	}
 */
	if(scsirflag){
		DPRINT("R", p=datap);
		datap = scsirecv(datap);
		DPRINT("%d ", datap-p);
	}else{
		DPRINT("X", p=datap);
		datap = scsixmit(datap);
		DPRINT("%d ", datap-p);
	}
}

void
scsictrlintr(void)
{
	int status, phase;
	long n;

	status = GET(SCSI_Status);
	DPRINT("I%2.2x ", status);
	switch(status){
	case 0x00:			/* reset by command or power-up */
	case 0x01:			/* reset by command or power-up */
		scsireset0();
		break;
	case 0x21:			/* Save Data Pointers message received */
		n = GET(Tc_hi);
		n = (n<<8)|DEV->data;
		n = (n<<8)|DEV->data;
		datap = datalim - n;
		PUT(Cmd_phase, 0x41);
		PUT(Cmd, Select_and_Xfr);
		break;
	case 0x16:			/* select-and-transfer completed */
	case 0x42:			/* timeout during select */
		scsirun();
		break;
	case 0x4b:			/* unexpected status phase */
		DEV->asr = Target_LUN;
		kprint("lun/status 0x%ux\n", DEV->data);
		phase = DEV->data;
		kprint("phase 0x%ux\n", phase);
		PUT(Tc_hi, 0);
		DEV->data = 0;
		DEV->data = 0;
		switch(phase){
		case 0x50:
		case 0x60:
			break;
		default:
			phase = 0x46;
			break;
		}
		PUT(Cmd_phase, phase);
		PUT(Cmd, Select_and_Xfr);
		break;
	default:
		kprint("scsintr 0x%ux\n", status);
		DEV->asr = Target_LUN;
		kprint("lun/status 0x%ux\n", DEV->data);
		kprint("phase 0x%ux\n", DEV->data);
		switch (status&0xf0) {
		case 0x00:
		case 0x10:
		case 0x20:
		case 0x40:
		case 0x80:
			if(status & 0x08){
				kprint("count 0x%ux", GET(Tc_hi));
				kprint(" 0x%ux", DEV->data);
				kprint(" 0x%ux\n", DEV->data);
			}
			scsirun();
			break;
		default:
			panic("scsi status 0x%2.2ux", status);
		}
		kprint("resetting...");
		PUT(Own_id, scsiownid);
		PUT(Cmd, Reset);
		break;
	}
}

M pc/main.c => pc/main.c +1 -1
@@ 7,7 7,7 @@
#include	"ureg.h"
#include	"init.h"

int machtype;
int machtype;	/* machine type, mostly for power management */
uchar	*sp;	/* stack pointer for /boot */

void

M port/devscsi.c => port/devscsi.c +72 -308
@@ 5,51 5,16 @@
#include	"fns.h"
#include	"../port/error.h"
#include	"devtab.h"
#include	"io.h"

#define	DPRINT	if(debug)kprint

typedef struct Scsi	Scsi;
typedef struct Scsidata	Scsidata;
#define Nbuf	2
#define DATASIZE	(32*512)

#define Nbuf	4
#define DATASIZE (8*1024)
enum
{
	ScsiTestunit	= 0x00,
	ScsiExtsens	= 0x03,
	ScsiGetcap	= 0x25,
	ScsiRead	= 0x08,
	ScsiWrite	= 0x0a,

	/*
	 * data direction
	 */
	ScsiIn		= 1,
	ScsiOut		= 0,
};

struct Scsidata
{
	uchar	*base;
	uchar	*lim;
	uchar	*ptr;
};

struct Scsi
{
	QLock;
	ulong	pid;
	ushort	target;
	ushort	lun;
	ushort	rflag;
	ushort	status;
	Scsidata cmd;
	Scsidata data;
	Scsibuf	*b;
	uchar	*save;
	uchar	cmdblk[16];
};
struct{
	Lock;
	Scsibuf	*free;
}scsibufalloc;

static Scsi	staticcmd;	/* BUG: should be one per scsi device */



@@ 68,12 33,8 @@ static Dirtab scsidir[]={
};
#define	NSCSI	(sizeof scsidir/sizeof(Dirtab))

static int	debugs[8];
static int	ownid = 0x08|7; /* enable advanced features */

int	scsiexec(Scsi*, int);
int	scsiintr(void);
void	scsireset(void);
extern int	scsidebugs[];
extern int	scsiownid;

static int
scsigen1(Chan *c, long qid, Dir *dp)


@@ 117,6 78,24 @@ scsigen(Chan *c, Dirtab *tab, long ntab, long s, Dir *dp)
	return scsigen1(c, (c->qid.path&~CHDIR)+s+1, dp);
}

void
scsireset(void)
{
	int i;

	for(i = 0; i < Nbuf; i++)
		scsifree(scsialloc(DATASIZE));
	lock(&scsibufalloc);
	unlock(&scsibufalloc);
	resetscsi();
}

void
scsiinit(void)
{
	initscsi();
}

Chan *
scsiattach(char *param)
{


@@ 181,7 160,7 @@ scsiread(Chan *c, char *a, long n, ulong offset)
	if(c->qid.path==1){
		if(offset == 0){
			/*void scsidump(void); scsidump();*/
			*a = ownid;
			*a = scsiownid;
			n = 1;
		}else
			n = 0;


@@ 230,7 209,7 @@ scsiread(Chan *c, char *a, long n, ulong offset)
	case Qdebug:
		if(offset == 0){
			n=1;
			*a="01"[debugs[(c->qid.path>>4)&7]!=0];
			*a="01"[scsidebugs[(c->qid.path>>4)&7]!=0];
		}else
			n = 0;
		break;


@@ 248,7 227,7 @@ scsiwrite(Chan *c, char *a, long n, ulong offset)
	if(c->qid.path==1 && n>0){
		if(offset == 0){
			n = 1;
			ownid=*a;
			scsiownid=*a;
			scsireset();
		}else
			n = 0;


@@ 292,7 271,7 @@ scsiwrite(Chan *c, char *a, long n, ulong offset)
		break;
	case Qdebug:
		if(offset == 0){
			debugs[(c->qid.path>>4)&7] = (*a=='1');
			scsidebugs[(c->qid.path>>4)&7] = (*a=='1');
			n = 1;
		}else
			n = 0;


@@ 343,6 322,9 @@ scsicmd(int dev, int cmdbyte, Scsibuf *b, long size)
	switch(cmdbyte){
	case ScsiTestunit:
		break;
	case ScsiModesense:
		cmd->cmdblk[2] = 1;
		/* fall through */
	case ScsiExtsens:
		cmd->cmdblk[4] = size;
		break;


@@ 419,10 401,34 @@ scsicap(int dev, void *p)
	qunlock(cmd);
	if((status&0xff00) != 0x6000)
		error(Eio);
	if(status & 0xFF)
		scsisense(dev, p);
	return status&0xff;
}

int
scsiwp(int dev)
{
	Scsi *cmd;
	int r, status;

	cmd = scsicmd(dev, ScsiModesense, scsibuf(), 12);
	if(waserror()){
		scsifree(cmd->b);
		qunlock(cmd);
		nexterror();
	}
	status = scsiexec(cmd, ScsiIn);
	r = cmd->data.base[2] & 0x80;
	poperror();
	scsifree(cmd->b);
	qunlock(cmd);
	if ((status&0xffff) != 0x6000)
		error(Eio);
	return r;
}

int
scsibread(int dev, Scsibuf *b, long n, long blocksize, long blockno)
{
	Scsi *cmd;


@@ 472,267 478,25 @@ scsibuf(void)
{
	Scsibuf *b;

	b = smalloc(sizeof(Scsibuf)+DATASIZE);
	b->phys = (void*)(b + 1);
	b->virt = b->phys;
	return b;
}

void
scsifree(Scsibuf *b)
{
	free(b);
}

typedef struct Scsictl {
	uchar	asr;
	uchar	data;
	uchar	stat;
	uchar	dma;
} Scsictl;

#define	Scsiaddr	48
#define	DEV	((Scsictl *)&PORT[Scsiaddr])

static long	poot;
#define	WAIT	(poot=0, poot==0?0:poot)

#define	PUT(a,d)	(DEV->asr=(a), WAIT, DEV->data=(d))
#define	GET(a)		(DEV->asr=(a), WAIT, DEV->data)

enum Int_status {
	Inten = 0x01, Scsirst = 0x02,
	INTRQ = 0x01, DMA = 0x02,
};

enum SBIC_regs {
	Own_id=0x00, Control=0x01, CDB=0x03, Target_LUN=0x0f,
	Cmd_phase=0x10, Tc_hi=0x12,
	Dest_id=0x15, Src_id=0x16, SCSI_Status=0x17,
	Cmd=0x18, Data=0x19,
};

enum Commands {
	Reset = 0x00,
	Assert_ATN = 0x02,
	Negate_ACK = 0x03,
	Select_with_ATN = 0x06,
	Select_with_ATN_and_Xfr = 0x08,
	Select_and_Xfr = 0x09,
	Transfer_Info = 0x20,
	SBT = 0x80,		/* modifier for single-byte transfer */
};

enum Aux_status {
	INT=0x80, LCI=0x40, BSY=0x20, CIP=0x10,
	PE=0x02, DBR=0x01,
};

static int	isscsi;
static QLock	scsilock;
static Rendez	scsirendez;
static uchar	*datap;
static long	debug, scsirflag, scsibusy, scsiinservice;

static void
nop(void)
{}

void
scsireset(void)
{
	addportintr(scsiintr);
}

void
scsiinit(void)
{
	isscsi = portprobe("scsi", -1, Scsiaddr, -1, 0L);
	if (isscsi >= 0) {
		DEV->stat = Scsirst;
		WAIT; nop(); WAIT;
		DEV->stat = Inten;
		while (DEV->stat & (INTRQ|DMA))
			nop();
		ownid &= 0x0f; /* possibly advanced features */
		ownid |= 0x80; /* 16MHz */
		PUT(Own_id, ownid);
		PUT(Cmd, Reset);
	}
}

static int
scsidone(void *arg)
{
	USED(arg);
	return (scsibusy == 0);
}

int
scsiexec(Scsi *p, int rflag)
{
	long n;
	debug = debugs[p->target&7];
	DPRINT("scsi %d.%d ", p->target, p->lun);
	qlock(&scsilock);
	if(waserror()){
		qunlock(&scsilock);
		nexterror();
	}
	scsirflag = rflag;
	p->rflag = rflag;
	datap = p->data.base;
	if ((ownid & 0x08) && rflag)
		PUT(Dest_id, 0x40|p->target);
	else
		PUT(Dest_id, p->target);
	PUT(Target_LUN, p->lun);
	n = p->data.lim - p->data.base;
	PUT(Tc_hi, n>>16);
	DEV->data = n>>8;
	DEV->data = n;
	if (ownid & 0x08) {
		n = p->cmd.lim - p->cmd.ptr;
		DPRINT("len=%d ", n);
		PUT(Own_id, n);
	}
	PUT(CDB, *(p->cmd.ptr)++);
	while (p->cmd.ptr < p->cmd.lim)
		DEV->data = *(p->cmd.ptr)++;
	scsibusy = 1;
	PUT(Cmd, Select_and_Xfr);
	DPRINT("S<");
	sleep(&scsirendez, scsidone, 0);
	DPRINT(">");
	p->data.ptr = datap;
	p->status = GET(Target_LUN);
	p->status |= DEV->data<<8;
	poperror();
	qunlock(&scsilock);
	debug = 0;
	return p->status;
}

void
scsirun(void)
{
	wakeup(&scsirendez);
	scsibusy = 0;
}

void
scsireset0(void)
{
	PUT(Control, 0x29);	/* burst DMA, halt on parity error */
	PUT(Control+1, 0xff);	/* timeout */
	PUT(Src_id, 0x80);	/* enable reselection */
	scsirun();
	/*qunlock(&scsilock);*/
}

int
scsiintr(void)
{
	int status, s;
	if (isscsi < 0 || scsiinservice
		|| !((status = DEV->stat) & (DMA|INTRQ)))
			return 0;
	DEV->stat = 0;
	scsiinservice = 1;
	s = spl1();
	DPRINT("i%x ", status);
	do {
		if (status & DMA)
			scsidmaintr();
		if (status & INTRQ)
			scsictrlintr();
	} while ((status = DEV->stat) & (DMA|INTRQ));
	splx(s);
	scsiinservice = 0;
	DEV->stat = Inten;
	return 1;
}
	for(;;) {
		lock(&scsibufalloc);
		if(b = scsibufalloc.free) {
			scsibufalloc.free = b->next;
			unlock(&scsibufalloc);
			return b;
		}

void
scsidmaintr(void)
{
		uchar *p = 0;
/*
 *	if (scsirflag) {
 *		unsigned char *p;
 *		DPRINT("R", p=datap);
 *		do
 *			*datap++ = DEV->dma;
 *		while (DEV->stat & DMA);
 *		DPRINT("%d ", datap-p);
 *	} else {
 *		unsigned char *p;
 *		DPRINT("W", p=datap);
 *		do
 *			DEV->dma = *datap++;
 *		while (DEV->stat & DMA);
 *		DPRINT("%d ", datap-p);
 *	}
 */
	if (scsirflag) {
		DPRINT("R", p=datap);
		datap = scsirecv(datap);
		DPRINT("%d ", datap-p);
	} else {
		DPRINT("X", p=datap);
		datap = scsixmit(datap);
		DPRINT("%d ", datap-p);
		unlock(&scsibufalloc);
		resrcwait("no scsi buffers");
	}
	return 0;		/* not reached */
}

void
scsictrlintr(void)
scsifree(Scsibuf *b)
{
	int status;
	status = GET(SCSI_Status);
	DPRINT("I%2.2x ", status);
	switch(status){
	case 0x00:			/* reset by command or power-up */
	case 0x01:			/* reset by command or power-up */
		scsireset0();
		break;
	case 0x21:			/* Save Data Pointers message received */
		break;
	case 0x16:			/* select-and-transfer completed */
	case 0x42:			/* timeout during select */
		scsirun();
		break;
	case 0x4b:			/* unexpected status phase */
		PUT(Tc_hi, 0);
		DEV->data = 0;
		DEV->data = 0;
		PUT(Cmd_phase, 0x46);
		PUT(Cmd, Select_and_Xfr);
		break;
	default:
		kprint("scsintr 0x%ux\n", status);
		DEV->asr = Target_LUN;
		kprint("lun/status 0x%ux\n", DEV->data);
		kprint("phase 0x%ux\n", DEV->data);
		switch (status&0xf0) {
		case 0x00:
		case 0x10:
		case 0x20:
		case 0x40:
		case 0x80:
			if (status & 0x08) {
				kprint("count 0x%ux", GET(Tc_hi));
				kprint(" 0x%ux", DEV->data);
				kprint(" 0x%ux\n", DEV->data);
			}
			scsirun();
			break;
		default:
			panic("scsi status 0x%2.2ux", status);
		}
		kprint("resetting...");
		PUT(Own_id, ownid);
		PUT(Cmd, Reset);
		break;
	}
	lock(&scsibufalloc);
	b->next = scsibufalloc.free;
	scsibufalloc.free = b;
	unlock(&scsibufalloc);
}

M port/devwren.c => port/devwren.c +24 -26
@@ 37,7 37,7 @@ struct Drive
	ulong		bytes;			/* bytes per block */
	int		npart;			/* actual number of partitions */
	int		drive;
	int		ready;			/* true if ever ready */
	int		readonly;
	Partition	p[Npart];
};



@@ 96,7 96,7 @@ wrengen(Chan *c, Dirtab *tab, long ntab, long s, Dir *dirp)
	name[NAMELEN] = 0;
	qid.path = MKQID(drive, s);
	l = (pp->end - pp->start) * dp->bytes;
	devdir(c, qid, name, l, eve, 0666, dirp);
	devdir(c, qid, name, l, eve, dp->readonly ? 0444 : 0666, dirp);
	return 1;
}



@@ 111,7 111,7 @@ wreninit(void)
}

/*
 *  param is #r<target>.<lun>
 *  param is #w<target>.<lun>
 */
Chan *
wrenattach(char *param)


@@ 273,28 273,26 @@ wrenpart(int dev)
		nexterror();
	}
	qlock(dp);
	if(!dp->ready){
		scsiready(dev);
		scsisense(dev, buf);
		if (scsicap(dev, buf))
			error(Eio);
		dp->drive = dev;
		dp->ready = 1;

		/*
		 *  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;
	}
	scsiready(dev);
	scsisense(dev, buf);
	if(scsicap(dev, buf))
		error(Eio);
	dp->drive = dev;
	dp->readonly = scsiwp(dev);

	/*
	 *  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;

	/*
	 *  read partition table from disk, null terminate


@@ 313,7 311,7 @@ wrenpart(int dev)
	 */
	pp = &dp->p[2];
	n = getfields(rawpart, line, Npart+1, '\n');
	if(strncmp(line[0], MAGIC, sizeof(MAGIC)-1) == 0){
	if(n > 0 && strncmp(line[0], MAGIC, sizeof(MAGIC)-1) == 0){
		for(i = 1; i < n; i++){
			if(getfields(line[i], field, 3, ' ') != 3)
				break;

M port/portdat.h => port/portdat.h +50 -0
@@ 33,6 33,9 @@ typedef struct Ref	Ref;
typedef struct Rendez	Rendez;
typedef struct RWlock	RWlock;
typedef struct Sargs	Sargs;
typedef struct Scsi	Scsi;
typedef struct Scsibuf	Scsibuf;
typedef struct Scsidata	Scsidata;
typedef struct Segment	Segment;
typedef struct Stream	Stream;
typedef struct Talarm	Talarm;


@@ 218,6 221,53 @@ struct Etherpkt
#define ETHERHDRSIZE	14		/* size of an ethernet header */

/*
 *  SCSI devices.
 */
enum
{
	ScsiTestunit	= 0x00,
	ScsiExtsens	= 0x03,
	ScsiModesense	= 0x1a,
	ScsiGetcap	= 0x25,
	ScsiRead	= 0x08,
	ScsiWrite	= 0x0a,

	/*
	 * data direction
	 */
	ScsiIn		= 1,
	ScsiOut		= 0,
};

struct Scsibuf
{
	void *	virt;
	void *	phys;
	Scsibuf *next;
};

struct Scsidata
{
	uchar *	base;
	uchar *	lim;
	uchar *	ptr;
};

struct Scsi
{
	QLock;
	ulong	pid;
	ushort	target;
	ushort	lun;
	ushort	rflag;
	ushort	status;
	Scsidata cmd;
	Scsidata data;
	Scsibuf	*b;
	uchar	*save;
	uchar	cmdblk[16];
};
/*
 *  character based IO (mouse, keyboard, console screen)
 */
#define NQ	4096

M port/portfns.h => port/portfns.h +14 -0
@@ 26,6 26,7 @@ void		closemount(Mount*);
void		closepgrp(Pgrp*);
long		clrfpintr(void);
void		confinit(void);
void		confinit1(int);
int		consactive(void);
void		consdebug(void);
Block*		copyb(Block*, int);


@@ 82,6 83,7 @@ int		hwcursset(uchar*, uchar*, int, int);
long		ibrk(ulong, int);
int		incref(Ref*);
void		initq(IOQ*);
void		initscsi(void);
void		initseg(void);
void		invalidateu(void);
void		isdir(Chan*);


@@ 181,6 183,7 @@ int		readstr(ulong, char*, ulong, char*);
void		ready(Proc*);
void		relocateseg(Segment*, ulong);
void		resched(char*);
void		resetscsi(void);
void		resrcwait(char*);
int		return0(void*);
void		rlock(RWlock*);


@@ 194,6 197,17 @@ void		sccspecial(int, IOQ*, IOQ*, int);
void		sched(void);
void		schedinit(void);
int		screenbits(void);
Scsibuf*	scsialloc(ulong);
int		scsibread(int, Scsibuf*, long, long, long);
Scsibuf*	scsibuf(void);
int		scsibwrite(int, Scsibuf*, long, long, long);
int		scsicap(int, void*);
Scsi*		scsicmd(int, int, Scsibuf*, long);
int		scsiexec(Scsi*, int);
void		scsifree(Scsibuf*);
int		scsiready(int);
int		scsisense(int, void*);
int		scsiwp(int);
long		seconds(void);
ulong		segattach(Proc*, ulong, char *, ulong, ulong);
void		segpage(Segment*, Page*);

M ss/dat.h => ss/dat.h +0 -48
@@ 7,9 7,6 @@ typedef struct Lancemem	Lancemem;
typedef struct Label	Label;
typedef struct Lock	Lock;
typedef struct PMMU	PMMU;
typedef struct Scsi	Scsi;
typedef struct Scsibuf	Scsibuf;
typedef struct Scsidata	Scsidata;
typedef struct Mach	Mach;
typedef struct Ureg	Ureg;
typedef struct User	User;


@@ 214,48 211,3 @@ struct
	short	machs;
	short	exiting;
}active;

enum
{
	ScsiTestunit	= 0x00,
	ScsiExtsens	= 0x03,
	ScsiModesense	= 0x1a,
	ScsiGetcap	= 0x25,
	ScsiRead	= 0x08,
	ScsiWrite	= 0x0a,

	/*
	 * data direction
	 */
	ScsiIn		= 1,
	ScsiOut		= 0,
};

struct Scsibuf
{
	void	*virt;
	void	*phys;
	Scsibuf	*next;
};

struct Scsidata
{
	uchar	*base;
	uchar	*lim;
	uchar	*ptr;
};

struct Scsi
{
	QLock;
	ulong	pid;
	ushort	target;
	ushort	lun;
	ushort	rflag;
	ushort	status;
	Scsidata cmd;
	Scsidata data;
	Scsibuf	*b;
	uchar	*save;
	uchar	cmdblk[16];
};

M ss/fns.h => ss/fns.h +1 -8
@@ 1,6 1,7 @@
#include "../port/portfns.h"

void	cacheinit(void);
ulong	call(void*, ...);
void	clearftt(ulong);
#define	clearmmucache()
void	clockinit(void);


@@ 56,15 57,7 @@ void	restfpregs(FPsave*, ulong);
void	screeninit(void);
void	screenputc(int);
void	screenputs(char*, int);
Scsibuf	*scsialloc(ulong);
int	scsibread(int, Scsibuf*, long, long, long);
int	scsibwrite(int, Scsibuf*, long, long, long);
Scsibuf	*scsibuf(void);
int	scsicap(int, void*);
void	scsifree(Scsibuf*);
void	scsiintr(void);
int	scsiready(int);
int	scsisense(int, void *);
void	spldone(void);
ulong	tas(ulong*);
void	touser(ulong);

M ss/l.s => ss/l.s +23 -1
@@ 22,7 22,7 @@ TEXT	start(SB), $-4

TEXT	startvirt(SB), $-4

	MOVW	$romvec(SB), R7
	MOVW	$rom(SB), R7
	MOVW	R8, (R7)	/* romvec passed in %i0==R8 */

	MOVW	$BOOTSTACK, R1


@@ 453,3 453,25 @@ TEXT	clearftt(SB), $0

GLOBL	mach0+0(SB), $MACHSIZE
GLOBL	fsr+0(SB), $BY2WD

/*
 * Interface to ROM.  Must save and restore state because
 * of different calling conventions.
 */

TEXT	call(SB), $16
	MOVW	R1, R14		/* save my SP in their SP */
	MOVW	R2, sb-4(SP)
	MOVW	R(MACH), mach-8(SP)
	MOVW	R(USER), user-12(SP)
	MOVW	param1+4(FP), R8
	MOVW	param2+8(FP), R9
	MOVW	param3+12(FP), R10
	MOVW	param4+16(FP), R11
	JMPL	(R7)
	MOVW	R14, R1		/* restore my SP */
	MOVW	user-12(SP), R(USER)
	MOVW	mach-8(SP), R(MACH)
	MOVW	sb-4(SP), R2
	MOVW	R8, R7		/* move their return value into mine */
	RETURN

M ss/main.c => ss/main.c +117 -39
@@ 5,6 5,7 @@
#include	"fns.h"
#include	"io.h"
#include	"init.h"
#include	"rom.h"

#include	<libg.h>
#include	<gnot.h>


@@ 12,10 13,12 @@
uchar	*intrreg;
int	model;
uchar	idprom[32];
ulong	romvec;		/* open boot rom vector */
ROM	*rom;		/* open boot rom vector */
int	cpuserver;
ulong	romputcxsegm;
void	(*romputcxsegm)(int, ulong, int);
ulong	bank[2];
char	rombuf[20000];
char	mempres[256];

void
main(void)


@@ 114,6 117,7 @@ init0(void)
	kproc("alarm", alarmkproc, 0);
	chandevinit();


	if(!waserror()){
		ksetterm("sun %s");
		ksetenv("cputype", "sparc");


@@ 204,34 208,86 @@ exit(void)
	systemreset();
}

int
banksize(ulong addr, ulong nbytes)
void
scanmem(char *mempres, int n)
{
	int i;
	ulong min, max, t;
	ulong va, pa;
	ulong nmeg;
	ulong va, addr;

	nmeg = nbytes/MB;
	va = 1*MB-2*BY2PG;
	for(i=0; i<nmeg; i++){
		pa = addr+i*MB;
		putw4(va, PPN(pa)|PTEVALID|PTEKERNEL|PTENOCACHE|PTEWRITE|PTEMAINMEM);
		*(ulong*)va = pa;
	for(i=0; i<n; i++){
		mempres[i] = 0;
		addr = i*MB;
		putw4(va, PPN(addr)|PTEVALID|PTEKERNEL|PTENOCACHE|PTEWRITE|PTEMAINMEM);
		*(ulong*)va = addr;
		if(*(ulong*)va == addr){
			addr = ~addr;
			*(ulong*)va = addr;
			if(*(ulong*)va == addr){
				mempres[i] = 1;
				*(ulong*)va = i + '0';
			}
		}
	}
	min = ~0;
	max = 0;
	for(i=0; i<nmeg; i++){
		pa = addr+i*MB;
		putw4(va, PPN(pa)|PTEVALID|PTEKERNEL|PTENOCACHE|PTEWRITE|PTEMAINMEM);
		t = *(ulong*)va;
		if(min > t)
			min = t;
		if(max < t)
			max = t;
	for(i=0; i<n; i++)
		if(mempres[i]){
			addr = i*MB;
			putw4(va, PPN(addr)|PTEVALID|PTEKERNEL|PTENOCACHE|PTEWRITE|PTEMAINMEM);
			mempres[i] = *(ulong*)va;
		}else
			mempres[i] = 0;
}

char name[1024];

void
romprops(ulong d, char *namep, ulong p)
{
	static ulong romp;
	uchar buf[128];
	int i, n;

	romp += sprint(rombuf+romp, "romprops %lux %lux\n", d, p);
	while(p && *(char*)p){
		n = call(rom->conf->getproplen, d, p);
		if(n>=0 && n<sizeof buf){
			call(rom->conf->getprop, d, p, buf);
			if(strcmp((char*)p, "name")==0){
				strcpy(namep, (char*)buf);
				romp += sprint(rombuf+romp, "`%s'\n", name);
			}else{
				romp += sprint(rombuf+romp, "%lux: %s: ", d, p);
				for(i=0; i<n; i++)
					romp += sprint(rombuf+romp, "%.2ux ", buf[i]);
				romp += sprint(rombuf+romp, "\n");
			}
		}else
			romp += sprint(rombuf+romp, "%lux: %s(%d)\n", d, p, n);
		p = call(rom->conf->nextprop, d, p);
	}
}

void
romwalk(ulong d, char* namep)
{
	char *endp;

	*namep++ = '/';
	*namep = 0;
	while(d){
		romprops(d, namep, call(rom->conf->nextprop, d, 0));
		endp = namep+strlen(namep);
		romwalk(call(rom->conf->child, d), endp);
		*endp = 0;
		d = call(rom->conf->next, d);
	}
	putw4(va, INVALIDPTE);
	return (max-min)/MB+1;
}

void
fuck(void)
{
	name[0] = 0;
	romwalk(call(rom->conf->next, 0), name);
}

Conf	conf;


@@ 240,8 296,8 @@ void
confinit(void)
{
	int mul;
	ulong i;
	ulong ktop, va, mbytes;
	ulong i, j;
	ulong ktop, va, mbytes, nmeg, npg, v;

	conf.nmach = 1;
	if(conf.nmach > MAXMACH)


@@ 256,8 312,14 @@ confinit(void)
	putw4(va, INVALIDPTE);

	switch(idprom[1]){
	case 0x51:		/* sparcstation 1 */
	case 0x54:		/* slc */

	/* sparcstation 1+ BUG: unknown! */
	case 0x52:		/* IPC 4/40 */
	case 0x53:		/* sparcstation 1+ 4/65 */
		/* fall through */
	/* sparcstation 1 */
	case 0x51:		/* sparcstation 1 4/60 */
	case 0x54:		/* slc 4/20 */
	default:
		conf.ss2 = 0;
		conf.vacsize = 65536;


@@ 266,11 328,13 @@ confinit(void)
		conf.npmeg = 128;
		conf.ss2cachebug = 0;
		conf.monitor = 1;		/* BUG */
		conf.base0 = 0;
		conf.base1 = 32*MB;
		nmeg = 64;
		break;

	case 0x55:		/* sparcstation 2 */
	/* sparcstation 2 */
	case 0x55:		/* sparcstation 2 4/75 */
	case 0x56:		/* ELC 4/25 */
	case 0x57:		/* IPX 4/50 */
		conf.ss2 = 1;
		conf.vacsize = 65536;
		conf.vaclinesize = 32;


@@ 278,18 342,30 @@ confinit(void)
		conf.npmeg = 256;
		conf.ss2cachebug = 1;
		conf.monitor = 0;		/* BUG */
		conf.base0 = 0;
		conf.base1 = 16*MB;
		nmeg = 64;
		break;
	}

	bank[0] = banksize(conf.base0, 16*MB);
	bank[1] = banksize(conf.base1, 16*MB);
	conf.npage0 = (bank[0]*MB)/BY2PG;
	conf.npage1 = (bank[1]*MB)/BY2PG;

	romputcxsegm = *(ulong*)(romvec+260);
	scanmem(mempres, nmeg);
	for(i=0; i<nmeg; i++)
		if(mempres[i]){
			v = mempres[i];
			for(j=i+1; j<nmeg && mempres[j]>v; j++)
				v = mempres[j];
			npg = ((v+1)-mempres[i])*MB/BY2PG;
			if(conf.npage0 == 0){
				conf.base0 = i*MB;
				conf.npage0 = npg;
			}else if(conf.npage1 < npg){
				conf.base1 = i*MB;
				conf.npage1 = npg;
			}
			i = v-'0';
		}

	bank[0] = conf.npage0*BY2PG/MB;
	bank[1] = conf.npage1*BY2PG/MB;
	
	conf.npage = conf.npage0+conf.npage1;
	conf.upages = (conf.npage*70)/100;
	if(cpuserver){


@@ 298,6 374,8 @@ confinit(void)
			conf.upages +=  i - ((6*MB)/BY2PG);
	}

	romputcxsegm = rom->putcxsegm;

	ktop = PGROUND((ulong)end);
	ktop = PADDR(ktop);
	conf.npage0 -= ktop/BY2PG;

M ss/rom.h => ss/rom.h +3 -1
@@ 34,7 34,8 @@ struct ROM
	uint	(*seek)(uint, uint, uint);
	void	(*chain)(void*, uint, void*, void*, uint);
	void	(*release)(void*, uint);
	uint	pad5[16];
	uint	pad4[15];
	void	(*putcxsegm)(int, ulong, int);
	int	(*startcpu)(uint, uint, uint, uint);
	int	(*stopcpu)(uint);
	int	(*idlecpu)(uint);


@@ 47,6 48,7 @@ struct ROMconf
	uint	(*child)(uint);
	int	(*getproplen)(uint, void*);
	int	(*getprop)(uint, void*, void*);
	int	(*setprop)(uint, void*, void*);
	void*	(*nextprop)(uint, void*);	
};


M ss/scsi.c => ss/scsi.c +25 -5
@@ 7,7 7,10 @@
#include	"devtab.h"
#include	"io.h"

static int	ownid = 7;
int	scsiownid = 7;
int	scsidebugs[8];

static int	dmatype;

Scsibuf *
scsialloc(ulong n)


@@ 92,7 95,7 @@ resetscsi(void)
	dev->timeout = 146;
	dev->syncperiod = 0;
	dev->syncoffset = 0;
	dev->config = 0x10|(ownid&7);
	dev->config = 0x10|(scsiownid&7);
	dev->cmd = Dma|Nop;

	dma->csr = Dma_Reset;


@@ 100,6 103,8 @@ resetscsi(void)
	dma->csr = Int_en;
	dma->count = 0;

	dmatype = (dma->csr>>28) & 0xF;

	putenab(getenab()|ENABDMA); /**/
}



@@ 251,9 256,23 @@ scsiintr(void)
			goto Done;
		}

		if(p->rflag)
			while(dma->csr & Pack_cnt)
				;
		if(p->rflag){
			switch(dmatype){

			case 8:
				dma->csr = Drain|Int_en;
				/*FALLTHROUGH*/

			case 9:
				while(dma->csr & Pack_cnt)
					;
				break;

			default:
				break;
			}
		}


		dev->cmd = Cmdcomplete;
		return;


@@ 261,6 280,7 @@ scsiintr(void)
	case 0x46:	/* Cmdcomplete was issued */
		p->status = 0x6000|dev->fifo;
		m = dev->fifo;
		USED(m);
		dev->cmd = Msgaccept;
		return;