Plan 9 from Bell Labs’s /usr/web/sources/extra/9hist/port/devscsi.c

Copyright © 2021 Plan 9 Foundation.
Distributed under the MIT License.
Download the Plan 9 distribution.


## diffname port/devscsi.c 1991/0110
## diff -e /dev/null /n/bootesdump/1991/0110/sys/src/9/68020/devscsi.c
0a
#include	"u.h"
#include	"lib.h"
#include	"mem.h"
#include	"dat.h"
#include	"fns.h"
#include	"errno.h"
#include	"devtab.h"
#include	"io.h"

#include	"port.h"
#include	"scsi.h"

int	scsiintr(void);

#define	DPRINT	if(debug)kprint

enum {
	Qdir, Qcmd, Qdata, Qdebug,
};

static Dirtab scsidir[]={
	"cmd",		{Qcmd},		0,	0600,
	"data",		{Qdata},	0,	0600,
	"debug",	{Qdebug},	1,	0600,
};

#define	NSCSI	(sizeof scsidir/sizeof(Dirtab))

static Scsi	staticcmd;	/* BUG */
static uchar	datablk[8192];	/* BUG */

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

static int
scsigen1(Chan *c, long qid, Dir *dp)
{
	if (qid == CHDIR)
		devdir(c, (Qid){qid,0}, ".", 0, 0500, dp);
	else if (qid == 1)
		devdir(c, (Qid){qid,0}, "id", 1, 0600, dp);
	else if (qid&CHDIR) {
		char name[2];
		name[0] = '0'+((qid>>4)&7), name[1] = 0;
		devdir(c, (Qid){qid,0}, name, 0, 0500, dp);
	} else {
		Dirtab *tab = &scsidir[(qid&7)-1];
		devdir(c, (Qid){qid,0}, tab->name, tab->length, tab->perm, dp);
	}
	return 1;
}

static int
scsigeno(Chan *c, Dirtab *tab, long ntab, long s, Dir *dp)
{
	return scsigen1(c, c->qid.path, dp);
}

static int
scsigen(Chan *c, Dirtab *tab, long ntab, long s, Dir *dp)
{
	if (c->qid.path == CHDIR) {
		if (0<=s && s<=7)
			return scsigen1(c, CHDIR|0x100|(s<<4), dp);
		else if (s == 8)
			return scsigen1(c, 1, dp);
		else
			return -1;
	}
	if (s >= NSCSI)
		return -1;
	return scsigen1(c, (c->qid.path&~CHDIR)+s+1, dp);
}

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

Chan *
scsiattach(char *param)
{
	return devattach('S', param);
}

Chan *
scsiclone(Chan *c, Chan *nc)
{
	return devclone(c, nc);
}

int
scsiwalk(Chan *c, char *name)
{
	return devwalk(c, name, 0, 0, scsigen);
}

void
scsistat(Chan *c, char *db)
{
	devstat(c, db, 0, 0, scsigen);
}

Chan *
scsiopen(Chan *c, int omode)
{
	return devopen(c, omode, 0, 0, scsigeno);
}

void
scsicreate(Chan *c, char *name, int omode, ulong perm)
{
	error(Eperm);
}

void
scsiclose(Chan *c)
{}

long
scsiread(Chan *c, char *a, long n)
{
	Scsi *cmd = &staticcmd;
	if (n == 0)
		return 0;
	if(c->qid.path & CHDIR)
		return devdirread(c, a, n, 0, 0, scsigen);
	if(c->qid.path==1){
		if(c->offset == 0){
			*a = ownid;
			n = 1;
		}else
			n = 0;
	}else switch((int)(c->qid.path & 0xf)){
	case Qcmd:
		if (n < 4)
			error(Ebadarg);
		/*if(canqlock(cmd)){
			qunlock(cmd);
			error(Egreg);
		}*/
		n = 4;
		*a++ = cmd->state>>8; *a++ = cmd->state;
		*a++ = cmd->status>>8; *a = cmd->status;
		/*qunlock(cmd);*/
		break;
	case Qdata:
		if (n > sizeof datablk)
			error(Ebadarg);
		cmd->data.base = datablk;
		cmd->data.lim = cmd->data.base + n;
		cmd->data.ptr = cmd->data.base;
		cmd->save = cmd->data.base;
		scsiexec(cmd, 1);
		n = cmd->data.ptr - cmd->data.base;
		memcpy(a, cmd->data.base, n);
		break;
	case Qdebug:
		if (c->offset == 0) {
			n=1;
			*a="01"[debugs[(c->qid.path>>4)&7]!=0];
		} else
			n = 0;
		break;
	default:
		panic("scsiread");
	}
	return n;
}

long
scsiwrite(Chan *c, char *a, long n)
{
	Scsi *cmd = &staticcmd;
	if(c->qid.path==1 && n>0){
		if(c->offset == 0){
			n = 1;
			ownid=*a;
			scsiinit();
		}else
			n = 0;
	}else switch ((int)c->qid.path & 0xf){
	case Qcmd:
		if (n < 6 || n > sizeof cmd->cmdblk)
			error(Ebadarg);
		/*qlock(cmd);*/
		cmd->cmd.base = cmd->cmdblk;
		memcpy(cmd->cmd.base, a, n);
		cmd->cmd.lim = cmd->cmd.base + n;
		cmd->cmd.ptr = cmd->cmd.base;
		cmd->target = (c->qid.path>>4)&7;
		cmd->lun = (a[1]>>5)&7;
		cmd->state = 0;
		cmd->status = 0xFFFF;
		break;
	case Qdata:
		if (n > sizeof datablk)
			error(Ebadarg);
		cmd->data.base = datablk;
		cmd->data.lim = cmd->data.base + n;
		cmd->data.ptr = cmd->data.base;
		cmd->save = cmd->data.base;
		memcpy(cmd->data.base, a, n);
		scsiexec(cmd, 0);
		n = cmd->data.ptr - cmd->data.base;
		break;
	case Qdebug:
		if (c->offset == 0) {
			debugs[(c->qid.path>>4)&7] = (*a=='1');
			n = 1;
		} else
			n = 0;
		break;
	default:
		panic("scsiwrite");
	}
	return n;
}

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

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

void
scsicmd(Scsi *cmd, int dev, int cmdbyte, uchar *buf, long size)
{
	qlock(cmd);
	cmd->target = dev>>3;
	cmd->lun = dev&7;
	cmd->cmd.base = cmd->cmdblk;
	cmd->data.base = buf;
	cmd->cmd.ptr = cmd->cmd.base;
	memset(cmd->cmdblk, 0, sizeof cmd->cmdblk);
	cmd->cmdblk[0] = cmdbyte;
	switch (cmdbyte>>5) {
	case 0:
		cmd->cmd.lim = &cmd->cmdblk[6]; break;
	case 1:
		cmd->cmd.lim = &cmd->cmdblk[10]; break;
	default:
		cmd->cmd.lim = &cmd->cmdblk[12]; break;
	}
	switch (cmdbyte) {
	case 0x00:	/* test unit ready */
		break;
	case 0x03:	/* read sense data */
		cmd->cmdblk[4] = size;
		break;
	case 0x25:	/* read capacity */
		break;
	}
	cmd->data.lim = cmd->data.base + size;
	cmd->data.ptr = cmd->data.base;
	cmd->save = cmd->data.base;
}

int
scsiready(int dev)
{
	static Scsi cmd;
	int status;
	scsicmd(&cmd, dev, 0x00, 0, 0);
	status = scsiexec(&cmd, 0);
	qunlock(&cmd);
	if ((status&0xff00) != 0x6000)
		error(Eio);
	return status&0xff;
}

int
scsisense(int dev, uchar *p)
{
	static Scsi cmd;
	static uchar buf[18];
	int status;
	scsicmd(&cmd, dev, 0x03, buf, sizeof buf);
	status = scsiexec(&cmd, 1);
	memcpy(p, buf, sizeof buf);
	qunlock(&cmd);
	if ((status&0xff00) != 0x6000)
		error(Eio);
	return status&0xff;
}

int
scsicap(int dev, uchar *p)
{
	static Scsi cmd;
	static uchar buf[8];
	int status;
	scsicmd(&cmd, dev, 0x25, buf, sizeof buf);
	status = scsiexec(&cmd, 1);
	memcpy(p, buf, sizeof buf);
	qunlock(&cmd);
	if ((status&0xff00) != 0x6000)
		error(Eio);
	return status&0xff;
}

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 QLock	scsilock;
static Rendez	scsirendez;
static uchar	*datap;
static long	debug, scsirflag, scsibusy, scsiinservice;

static void
nop(void)
{}

static int
scsidone(void *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;
	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
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);
	}
}

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;
}

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;
	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);
		}
	}
}
.
## diffname port/devscsi.c 1991/0112
## diff -e /n/bootesdump/1991/0110/sys/src/9/68020/devscsi.c /n/bootesdump/1991/0112/sys/src/9/68020/devscsi.c
473c
		uchar *p = 0;
.
321c
#define	WAIT	(poot=0, poot==0?0:poot)
.
## diffname port/devscsi.c 1991/0115
## diff -e /n/bootesdump/1991/0112/sys/src/9/68020/devscsi.c /n/bootesdump/1991/0115/sys/src/9/68020/devscsi.c
10,12d
## diffname port/devscsi.c 1991/0318
## diff -e /n/bootesdump/1991/0201/sys/src/9/68020/devscsi.c /n/bootesdump/1991/0318/sys/src/9/gnot/devscsi.c
300c
	memmove(p, buf, sizeof buf);
.
285c
	memmove(p, buf, sizeof buf);
.
202c
		memmove(cmd->data.base, a, n);
.
187c
		memmove(cmd->cmd.base, a, n);
.
155c
		memmove(a, cmd->data.base, n);
.
## diffname port/devscsi.c 1991/0411
## diff -e /n/bootesdump/1991/0318/sys/src/9/gnot/devscsi.c /n/bootesdump/1991/0411/sys/src/9/gnot/devscsi.c
207c
		if (offset == 0) {
.
175c
		if(offset == 0){
.
171c
scsiwrite(Chan *c, char *a, long n, ulong offset)
.
158c
		if (offset == 0) {
.
128c
		if(offset == 0){
.
120c
scsiread(Chan *c, char *a, long n, ulong offset)
.
## diffname port/devscsi.c 1991/0419
## diff -e /n/bootesdump/1991/0411/sys/src/9/gnot/devscsi.c /n/bootesdump/1991/0419/sys/src/9/gnot/devscsi.c
96a
Chan*
scsiclwalk(Chan *c, char *name)
{
	return devclwalk(c, name);
}

.
## diffname port/devscsi.c 1991/0423
## diff -e /n/bootesdump/1991/0419/sys/src/9/gnot/devscsi.c /n/bootesdump/1991/0423/sys/src/9/gnot/devscsi.c
383a
	p->rflag = rflag;
.
304,307c

	status = scsiexec(cmd, 1);
	memmove(p, cmd->data.base, 8);
	qunlock(cmd);
.
301,302c
	Scsi *cmd = scsicmd(dev, 0x25, 8);
.
299c
scsicap(int dev, void *p)
.
289,292c

	status = scsiexec(cmd, 1);
	memmove(p, cmd->data.base, 18);
	qunlock(cmd);
.
286,287c
	Scsi *cmd = scsicmd(dev, 0x03, 18);
.
284c
scsisense(int dev, void *p)
.
275,277c

	status = scsiexec(cmd, 0);
	qunlock(cmd);
.
273c
	Scsi *cmd = scsicmd(dev, 0x00, 0);
.
267a
	return cmd;
.
264a
	cmd->data.base = datablk;
.
256c
	switch(cmdbyte){
.
248c
	switch(cmdbyte>>5){
.
244d
239a
	Scsi *cmd = &staticcmd;

	if(size > DATASIZE)
		panic("scsicmd %d", size);
.
237,238c
Scsi *
scsicmd(int dev, int cmdbyte, long size)
.
202c
		if(canqlock(cmd)){
			qunlock(cmd);
			error(Egreg);
		}
		if(cmd->pid != u->p->pid)
			error(Egreg);
		if (n > DATASIZE)
.
198d
191c
		qlock(cmd);
		cmd->pid = u->p->pid;
.
184c
			scsireset();
.
153c
		if(canqlock(cmd)){
			qunlock(cmd);
			error(Egreg);
		}
		if(cmd->pid != u->p->pid)
			error(Egreg);
		if (n > DATASIZE)
.
150c
		cmd->pid = 0;
		qunlock(cmd);
.
148c
		*a++ = 0; *a++ = 0;
.
146c
		}
		if(cmd->pid != u->p->pid)
			error(Egreg);
.
143c
		if(canqlock(cmd)){
.
134a
			/*void scsidump(void); scsidump();*/
.
123c
{
	Scsi *cmd = &staticcmd;
	
	if((c->qid.path & CHDIR) || c->qid.path==1)
		return;
	if((c->qid.path & 0xf) == Qcmd){
		if(canqlock(cmd) || cmd->pid == u->p->pid){
			cmd->pid = 0;
			qunlock(cmd);
		}
	}
}
.
27c
#define	DATASIZE	(8*1024)
static uchar	datablk[DATASIZE];	/* BUG */
.
## diffname port/devscsi.c 1991/0427
## diff -e /n/bootesdump/1991/0423/sys/src/9/gnot/devscsi.c /n/bootesdump/1991/0427/sys/src/9/gnot/devscsi.c
98,103d
## diffname port/devscsi.c 1991/0514
## diff -e /n/bootesdump/1991/0427/sys/src/9/gnot/devscsi.c /n/bootesdump/1991/0514/sys/src/9/gnot/devscsi.c
33a
void *
dmaalloc(ulong n)
{
	return ialloc(n, 0);
}

.
## diffname port/devscsi.c 1991/0627
## diff -e /n/bootesdump/1991/0514/sys/src/9/gnot/devscsi.c /n/bootesdump/1991/0627/sys/src/9/gnot/devscsi.c
581a
		kprint("resetting...");
		PUT(Own_id, ownid);
		PUT(Cmd, Reset);
		break;
.
107c
	devstat(c, db, 0, 0, scsigeno);
.
## diffname port/devscsi.c 1991/0705
## diff -e /n/bootesdump/1991/0627/sys/src/9/gnot/devscsi.c /n/bootesdump/1991/0705/sys/src/9/gnot/devscsi.c
582,585d
107c
	devstat(c, db, 0, 0, scsigen);
.
## diffname port/devscsi.c 1991/0706
## diff -e /n/bootesdump/1991/0705/sys/src/9/gnot/devscsi.c /n/bootesdump/1991/0706/sys/src/9/gnot/devscsi.c
581a
		kprint("resetting...");
		PUT(Own_id, ownid);
		PUT(Cmd, Reset);
		break;
.
107c
	devstat(c, db, 0, 0, scsigeno);
.
## diffname port/devscsi.c 1991/0927
## diff -e /n/bootesdump/1991/0706/sys/src/9/gnot/devscsi.c /n/bootesdump/1991/0927/sys/src/9/gnot/devscsi.c
453,469d
396a
void
scsireset(void)
{
	static int alloced = 0;
	int i;

	addportintr(scsiintr);
	if(!alloced){
		for(i = 0; i < Nbuf; i++)
			scsifree(scsialloc(DATASIZE));
		alloced = 1;
	}
}

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);
	}
}

.
387a
static int	isscsi;
.
343a
int
scsibread(int dev, Scsibuf *b, long n, long blocksize, long blockno)
{
	Scsi *cmd;

	cmd = scsicmd(dev, ScsiRead, b, n*blocksize);
	if(waserror()){
		qunlock(cmd);
		nexterror();
	}
	cmd->cmdblk[1] = blockno >> 16;
	cmd->cmdblk[2] = blockno >> 8;
	cmd->cmdblk[3] = blockno;
	cmd->cmdblk[4] = n;
	scsiexec(cmd, ScsiIn);
	n = cmd->data.ptr - cmd->data.base;
	poperror();
	qunlock(cmd);
	return n;
}

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

	cmd = scsicmd(dev, ScsiWrite, b, n*blocksize);
	if(waserror()){
		qunlock(cmd);
		nexterror();
	}
	cmd->cmdblk[1] = blockno >> 16;
	cmd->cmdblk[2] = blockno >> 8;
	cmd->cmdblk[3] = blockno;
	cmd->cmdblk[4] = n;
	scsiexec(cmd, ScsiOut);
	n = cmd->data.ptr - cmd->data.base;
	poperror();
	qunlock(cmd);
	return n;
}

/*
 * allocate a scsi buf of any length
 * must be called at ialloc time and never freed
 */
Scsibuf *
scsialloc(ulong n)
{
	Scsibuf *b;
	uchar *x;
	long m;

	b = ialloc(sizeof *b, 0);
	b->virt = b->phys = ialloc(n, 0);
	return b;
}

/*
 * get a scsi io buffer of DATASIZE size
 */
Scsibuf *
scsibuf(void)
{
	Scsibuf *b;

	for(;;) {
		lock(&scsibufalloc);
		if(b = scsibufalloc.free) {
			scsibufalloc.free = b->next;
			unlock(&scsibufalloc);
			return b;
		}

		unlock(&scsibufalloc);
		resrcwait("no scsi buffers");
	}
}

void
scsifree(Scsibuf *b)
{
	lock(&scsibufalloc);
	b->next = scsibufalloc.free;
	scsibufalloc.free = b;
	unlock(&scsibufalloc);
}

.
339c
	if((status&0xff00) != 0x6000)
.
337a
	poperror();
	scsifree(cmd->b);
.
336c
	cmd = scsicmd(dev, ScsiGetcap, scsibuf(), 8);
	if(waserror()){
		scsifree(cmd->b);
		qunlock(cmd);
		nexterror();
	}
	status = scsiexec(cmd, ScsiIn);
.
333c
	Scsi *cmd;
.
325c
	if((status&0xff00) != 0x6000)
.
323a
	poperror();
	scsifree(cmd->b);
.
322c
	cmd = scsicmd(dev, ScsiExtsens, scsibuf(), 18);
	if(waserror()){
		scsifree(cmd->b);
		qunlock(cmd);
		nexterror();
	}
	status = scsiexec(cmd, ScsiIn);
.
319c
	Scsi *cmd;
.
311c
	if((status&0xff00) != 0x6000)
.
309c
	cmd = scsicmd(dev, ScsiTestunit, scsibuf(), 0);
	if(waserror()){
		scsifree(cmd->b);
		qunlock(cmd);
		nexterror();
	}
	status = scsiexec(cmd, ScsiOut);
	poperror();
	scsifree(cmd->b);
.
306c
	Scsi *cmd;
.
296c
	cmd->b = b;
	cmd->data.base = b->virt;
.
293c
	case ScsiGetcap:
.
290c
	case ScsiExtsens:
.
288c
	case ScsiTestunit:
.
285c
		cmd->cmd.lim = &cmd->cmdblk[12];
		break;
.
283c
		cmd->cmd.lim = &cmd->cmdblk[10];
		break;
.
281c
		cmd->cmd.lim = &cmd->cmdblk[6];
		break;
.
279c
	switch(cmdbyte >> 5){
.
273,274c
	cmd->target = dev >> 3;
	cmd->lun = dev & 7;
.
270,271d
266c
scsicmd(int dev, int cmdbyte, Scsibuf *b, long size)
.
244c
		}else
.
241c
		if(offset == 0){
.
238a
		poperror();
		scsifree(cmd->b);
.
237c
		scsiexec(cmd, ScsiOut);
.
232c
		cmd->b = scsibuf();
		cmd->data.base = cmd->b->virt;
		if(waserror()){
			scsifree(cmd->b);
			nexterror();
		}
.
211c
		if(n < 6 || n > sizeof cmd->cmdblk)
.
209c
	}else switch(c->qid.path & 0xf){
.
201a

.
189c
		}else
.
186c
		if(offset == 0){
.
183a
		poperror();
		scsifree(cmd->b);
.
181c
		scsiexec(cmd, ScsiIn);
.
177c
		cmd->b = scsibuf();
		cmd->data.base = cmd->b->virt;
		if(waserror()){
			scsifree(cmd->b);
			nexterror();
		}
.
163,164c
		*a++ = 0;
		*a++ = 0;
		*a++ = cmd->status >> 8;
		*a = cmd->status;
.
154c
		if(n < 4)
.
152c
	}else switch(c->qid.path & 0xf){
.
141c

	if(n == 0)
.
80,85d
34,38c
int	scsiexec(Scsi*, int);
int	scsiintr(void);
.
31d
26,29d
23d
17a
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 */

enum
{
	Qdir,
	Qcmd,
	Qdata,
	Qdebug,
};

.
14,15c
typedef struct Scsi	Scsi;
typedef struct Scsidata	Scsidata;

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

	/*
	 * data direction
	 */
	ScsiIn		= 1,
	ScsiOut		= 0,
.
10,11d
## diffname port/devscsi.c 1991/1112
## diff -e /n/bootesdump/1991/0927/sys/src/9/gnot/devscsi.c /n/bootesdump/1991/1112/sys/src/9/gnot/devscsi.c
95c
		devdir(c, (Qid){qid,0}, tab->name, tab->length, eve, tab->perm, dp);
.
92c
		devdir(c, (Qid){qid,0}, name, 0, eve, 0555, dp);
.
88c
		devdir(c, (Qid){qid,0}, "id", 1, eve, 0666, dp);
.
86c
		devdir(c, (Qid){qid,0}, ".", 0, eve, 0555, dp);
.
70,72c
	"cmd",		{Qcmd},		0,	0666,
	"data",		{Qdata},	0,	0666,
	"debug",	{Qdebug},	1,	0666,
.
## diffname port/devscsi.c 1991/1220
## diff -e /n/bootesdump/1991/1112/sys/src/9/gnot/devscsi.c /n/bootesdump/1991/1220/sys/src/9/gnot/devscsi.c
80a
void	scsireset(void);
.
## diffname port/devscsi.c 1992/0111
## diff -e /n/bootesdump/1991/1220/sys/src/9/gnot/devscsi.c /n/bootesdump/1992/0111/sys/src/9/gnot/devscsi.c
6c
#include	"../port/error.h"
.
## diffname port/devscsi.c 1992/0321
## diff -e /n/bootesdump/1992/0111/sys/src/9/gnot/devscsi.c /n/bootesdump/1992/0321/sys/src/9/gnot/devscsi.c
2c
#include	"../port/lib.h"
.
## diffname port/devscsi.c 1992/0625
## diff -e /n/bootesdump/1992/0321/sys/src/9/gnot/devscsi.c /n/bootesdump/1992/0625/sys/src/9/gnot/devscsi.c
574,578d
570,572d
507,510c
	free(b);
.
491,501c
	b = smalloc(sizeof(Scsibuf)+DATASIZE);
	b->phys = (void*)(b + 1);
	b->virt = b->phys;
	return b;
.
468,483d
54,58d
## diffname port/devscsi.c 1992/0711
## diff -e /n/bootesdump/1992/0625/sys/src/9/gnot/devscsi.c /n/bootesdump/1992/0711/sys/src/9/gnot/devscsi.c
561a
	USED(arg);
.
311a
	USED(c, dp);
.
305a
	USED(c);
.
150a
	USED(c, name, omode, perm);
.
104a
	USED(tab, ntab);
.
98a
	USED(tab, ntab, s);
.
## diffname port/devscsi.c 1992/0808
## diff -e /n/bootesdump/1992/0808/sys/src/9/gnot/devscsi.c /n/bootesdump/1992/0808/sys/src/9/port/devscsi.c
619,737c
	lock(&scsibufalloc);
	b->next = scsibufalloc.free;
	scsibufalloc.free = b;
	unlock(&scsibufalloc);
.
617c
scsifree(Scsibuf *b)
.
564,615d
561a
	return 0;		/* not reached */
.
481,560c
		unlock(&scsibufalloc);
		resrcwait("no scsi buffers");
.
475,479c
	for(;;) {
		lock(&scsibufalloc);
		if(b = scsibufalloc.free) {
			scsibufalloc.free = b->next;
			unlock(&scsibufalloc);
			return b;
		}
.
425a
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
.
421a
	if(status & 0xFF)
		scsisense(dev, p);
.
345a
	case ScsiModesense:
		cmd->cmdblk[2] = 1;
		/* fall through */
.
295c
			scsidebugs[(c->qid.path>>4)&7] = (*a=='1');
.
251c
			scsiownid=*a;
.
233c
			*a="01"[scsidebugs[(c->qid.path>>4)&7]!=0];
.
184c
			*a = scsiownid;
.
119a
void
scsireset(void)
{
	int i;

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

void
scsiinit(void)
{
	initscsi();
}

.
74,77d
71,72c
extern int	scsidebugs[];
extern int	scsiownid;
.
25,53d
15,23c
struct{
	Lock;
	Scsibuf	*free;
}scsibufalloc;
.
12,13c
#define Nbuf	2
#define DATASIZE	(32*512)
.
8d
## diffname port/devscsi.c 1992/0825
## diff -e /n/bootesdump/1992/0808/sys/src/9/port/devscsi.c /n/bootesdump/1992/0825/sys/src/9/port/devscsi.c
428a
}

int
scsimodesense(int dev, int page, void *p, int size)
{
	Scsi *cmd;
	int status;

	cmd = scsicmd(dev, ScsiModesense, scsibuf(), size);
	cmd->cmdblk[2] = page;
	if(waserror()){
		scsifree(cmd->b);
		qunlock(cmd);
		nexterror();
	}
	status = scsiexec(cmd, ScsiIn);
	memmove(p, cmd->data.base, size);
	poperror();
	scsifree(cmd->b);
	qunlock(cmd);
	if ((status&0xffff) != 0x6000)
		error(Eio);
	return status&0xff;
.
409a
scsiinquiry(int dev, void *p, int size)
{
	Scsi *cmd;
	int status;

	cmd = scsicmd(dev, ScsiInquiry, scsibuf(), size);
	if(waserror()){
		scsifree(cmd->b);
		qunlock(cmd);
		nexterror();
	}
	status = scsiexec(cmd, ScsiIn);
	memmove(p, cmd->data.base, size);
	poperror();
	scsifree(cmd->b);
	qunlock(cmd);
	if((status&0xff00) != 0x6000)
		error(Eio);
	if(status & 0xFF)
		scsisense(dev, p);
	return status&0xff;
}

int
.
328a
	case ScsiInquiry:
.
## diffname port/devscsi.c 1992/0829
## diff -e /n/bootesdump/1992/0825/sys/src/9/port/devscsi.c /n/bootesdump/1992/0829/sys/src/9/port/devscsi.c
12a
#undef DATASIZE
#define	DATASIZE	(64*1024)
.
## diffname port/devscsi.c 1992/0921
## diff -e /n/bootesdump/1992/0829/sys/src/9/port/devscsi.c /n/bootesdump/1992/0921/sys/src/9/port/devscsi.c
540c
		resrcwait(0);
.
538d
533c
		b = scsibufalloc.free;
		if(b != 0) {
.
## diffname port/devscsi.c 1992/1009
## diff -e /n/bootesdump/1992/0921/sys/src/9/port/devscsi.c /n/bootesdump/1992/1009/sys/src/9/port/devscsi.c
351a
	if(waserror()){
		scsifree(cmd->b);
		qunlock(cmd);
		nexterror();
	}
	status = scsiexec(cmd, ScsiOut);
	poperror();
	scsifree(cmd->b);
	qunlock(cmd);
	if((status&0xff00) != 0x6000)
		error(Eio);
	return status&0xff;
}

int
scsistartstop(int dev, int cmdbyte)
{
	Scsi *cmd;
	int status;

	cmd = scsicmd(dev, cmdbyte, scsibuf(), 0);
.
326a
	case ScsiStartunit:
		cmd->cmdblk[4] = 1;
		break;
.
## diffname port/devscsi.c 1992/1029
## diff -e /n/bootesdump/1992/1009/sys/src/9/port/devscsi.c /n/bootesdump/1992/1029/sys/src/9/port/devscsi.c
545,575d
86,91c
	scsibufreset(DATASIZE);
.
16,19d
11d
## diffname port/devscsi.c 1992/1209
## diff -e /n/bootesdump/1992/1029/sys/src/9/port/devscsi.c /n/bootesdump/1992/1209/sys/src/9/port/devscsi.c
469a
*/
	USED(dev);
	return 0;
.
452a
/* Device specific
.
15d
12,13d
## diffname port/devscsi.c 1992/1221
## diff -e /n/bootesdump/1992/1209/sys/src/9/port/devscsi.c /n/bootesdump/1992/1221/sys/src/9/port/devscsi.c
11c
#define DATASIZE	(64*512)
.
## diffname port/devscsi.c 1993/0407
## diff -e /n/bootesdump/1992/1221/sys/src/9/port/devscsi.c /n/bootesdump/1993/0407/sys/src/9/port/devscsi.c
527,530c
	switch(cmdbyte){
	case ScsiWrite:
		cmd->cmdblk[1] |= blockno >> 16;
		cmd->cmdblk[2] = blockno >> 8;
		cmd->cmdblk[3] = blockno;
		cmd->cmdblk[4] = n;
		break;
	default:
		cmd->cmdblk[2] = blockno >> 24;
		cmd->cmdblk[3] = blockno >> 16;
		cmd->cmdblk[4] = blockno >> 8;
		cmd->cmdblk[5] = blockno;
		cmd->cmdblk[7] = n>>8;
		cmd->cmdblk[8] = n;
		break;
	}
.
522c
	int cmdbyte;

	if(blockno <= 0x1fffff && n <= 256)
		cmdbyte = ScsiWrite;
	else
		cmdbyte = ScsiExtwrite;

	cmd = scsicmd(dev, cmdbyte, b, n*blocksize);
.
506,509c
	switch(cmdbyte){
	case ScsiRead:
		cmd->cmdblk[1] |= blockno >> 16;
		cmd->cmdblk[2] = blockno >> 8;
		cmd->cmdblk[3] = blockno;
		cmd->cmdblk[4] = n;
		break;
	default:
		cmd->cmdblk[2] = blockno >> 24;
		cmd->cmdblk[3] = blockno >> 16;
		cmd->cmdblk[4] = blockno >> 8;
		cmd->cmdblk[5] = blockno;
		cmd->cmdblk[7] = n>>8;
		cmd->cmdblk[8] = n;
		break;
	}
.
501c
	if(blockno <= 0x1fffff && n <= 256)
		cmdbyte = ScsiRead;
	else
		cmdbyte = ScsiExtread;

	cmd = scsicmd(dev, cmdbyte, b, n*blocksize);
.
499a
	int cmdbyte;
.
299a
	cmd->cmdblk[1] = cmd->lun << 5;
.
## diffname port/devscsi.c 1993/0501
## diff -e /n/bootesdump/1993/0407/sys/src/9/port/devscsi.c /n/fornaxdump/1993/0501/sys/src/brazil/port/devscsi.c
553,568c
	cmd->cmdblk[1] = blockno >> 16;
	cmd->cmdblk[2] = blockno >> 8;
	cmd->cmdblk[3] = blockno;
	cmd->cmdblk[4] = n;
.
541,548c
	cmd = scsicmd(dev, ScsiWrite, b, n*blocksize);
.
513,528c
	cmd->cmdblk[1] = blockno >> 16;
	cmd->cmdblk[2] = blockno >> 8;
	cmd->cmdblk[3] = blockno;
	cmd->cmdblk[4] = n;
.
503,508c
	cmd = scsicmd(dev, ScsiRead, b, n*blocksize);
.
501d
300d
242c
		if(cmd->pid != up->pid)
.
228c
		cmd->pid = up->pid;
.
179c
		if(cmd->pid != up->pid)
.
164c
		if(cmd->pid != up->pid)
.
133c
		if(canqlock(cmd) || cmd->pid == up->pid){
.
## diffname port/devscsi.c 1993/1124 # deleted
## diff -e /n/fornaxdump/1993/0501/sys/src/brazil/port/devscsi.c /n/fornaxdump/1993/1124/sys/src/brazil/port/devscsi.c
1,536d

Bell Labs OSI certified Powered by Plan 9

(Return to Plan 9 Home Page)

Copyright © 2021 Plan 9 Foundation. All Rights Reserved.
Comments to [email protected].