⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 scsi.c

📁 这是一个同样来自贝尔实验室的和UNIX有着渊源的操作系统, 其简洁的设计和实现易于我们学习和理解
💻 C
字号:
#include "all.h"#include "io.h"#include "mem.h"extern Scsiio buslogic(int, ISAConf*);extern Scsiio ncr53c8xxreset(int, ISAConf*);static struct {	char*	type;	Scsiio	(*reset)(int, ISAConf*);} scsictlr[] = {	{ "aha1542", buslogic, },	{ "buslogic", buslogic, },	{ "mylex", buslogic, },		/* the name 9load knows */	{ "ncr53c8xx", ncr53c8xxreset, },	{ 0, },};enum {	Ninquiry	= 255,	Nsense		= 255,	CMDtest		= 0x00,	CMDreqsense	= 0x03,	CMDread6	= 0x08,	CMDwrite6	= 0x0A,	CMDinquiry	= 0x12,	CMDstart	= 0x1B,	CMDread10	= 0x28,	CMDwrite10	= 0x2A,};typedef struct {	ISAConf;	Scsiio	io;	Target	target[NTarget];} Ctlr;static Ctlr scsi[MaxScsi];static voidcmd_stat(int, char*[]){	Ctlr *ctlr;	int ctlrno, targetno;	Target *tp;	for(ctlrno = 0; ctlrno < MaxScsi; ctlrno++){		ctlr = &scsi[ctlrno];		if(ctlr->io == 0)			continue;		for(targetno = 0; targetno < NTarget; targetno++){			tp = &ctlr->target[targetno];			if(tp->fflag == 0)				continue;			print("\t%d.%d work =%7W%7W%7W xfrs\n",				ctlrno, targetno,				tp->work+0, tp->work+1, tp->work+2);			print("\t    rate =%7W%7W%7W tBps\n",				tp->rate+0, tp->rate+1, tp->rate+2);		}	}}voidscsiinit(void){	Ctlr *ctlr;	int ctlrno, n, targetno;	Target *tp;	for(ctlrno = 0; ctlrno < MaxScsi; ctlrno++){		ctlr = &scsi[ctlrno];		memset(ctlr, 0, sizeof(Ctlr));		if(!isaconfig("scsi", ctlrno, ctlr))			continue;		for(n = 0; scsictlr[n].type; n++) {			if(strcmp(scsictlr[n].type, ctlr->type))				continue;			if((ctlr->io = (*scsictlr[n].reset)(ctlrno, ctlr)) == 0)				break;			print("scsi#%d: %s: port 0x%lux irq %lud",				ctlrno, ctlr->type, ctlr->port,				ctlr->irq);			if(ctlr->mem)				print(" addr 0x%lux", ctlr->mem & ~KZERO);			if(ctlr->size)				print(" size 0x%lux", ctlr->size);			print("\n");			for(targetno = 0; targetno < NTarget; targetno++){				tp = &ctlr->target[targetno];				qlock(tp);				qunlock(tp);				sprint(tp->id, "scsi#%d.%d", ctlrno, targetno);				tp->name = tp->id;				tp->ctlrno = ctlrno;				tp->targetno = targetno;				tp->inquiry = ialloc(Ninquiry, 0);				tp->sense = ialloc(Nsense, 0);			}			break;		}		if(ctlr->io == 0)			print("scsi#%d: %s: port %lux Failed to INIT controller\n",				ctlrno, ctlr->type, ctlr->port);	}	cmd_install("statd", "-- scsi stats", cmd_stat);}static uchar lastcmd[16];static int lastcmdsz;static intscsiexec(Target* tp, int rw, uchar* cmd, int cbytes, void* data, int* dbytes){	int s;	/*	 * Call the device-specific I/O routine.	 */	switch(s = scsi[tp->ctlrno].io(tp, rw, cmd, cbytes, data, dbytes)){	case STcheck:		memmove(lastcmd, cmd, cbytes);		lastcmdsz = cbytes;		/*FALLTHROUGH*/	default:		/*		 * It's more complicated than this. There are conditions which		 * are 'ok' but for which the returned status code is not 'STok'.		 * Also, not all conditions require a reqsense, there may be a		 * need to do a reqsense here when necessary and making it		 * available to the caller somehow.		 *		 * Later.		 */		break;	}	return s;}static intscsitest(Target* tp, char lun){	uchar cmd[6];	memset(cmd, 0, sizeof(cmd));	cmd[0] = CMDtest;	cmd[1] = lun<<5;	return scsiexec(tp, SCSIread, cmd, sizeof(cmd), 0, 0);}static intscsistart(Target* tp, char lun, int start){	uchar cmd[6];	memset(cmd, 0, sizeof cmd);	cmd[0] = CMDstart;	cmd[1] = lun<<5;	if(start)		cmd[4] = 1;	return scsiexec(tp, SCSIread, cmd, sizeof(cmd), 0, 0);}static intscsiinquiry(Target* tp, char lun, int* nbytes){	uchar cmd[6];	memset(cmd, 0, sizeof cmd);	cmd[0] = CMDinquiry;	cmd[1] = lun<<5;	*nbytes = Ninquiry;	cmd[4] = *nbytes;	return scsiexec(tp, SCSIread, cmd, sizeof(cmd), tp->inquiry, nbytes);}static char *key[] ={	"no sense",	"recovered error",	"not ready",	"medium error",	"hardware error",	"illegal request",	"unit attention",	"data protect",	"blank check",	"vendor specific",	"copy aborted",	"aborted command",	"equal",	"volume overflow",	"miscompare",	"reserved"};static intscsireqsense(Target* tp, char lun, int* nbytes, int quiet){	char *s;	int n, status, try;	uchar cmd[6], *sense;	sense = tp->sense;	for(try = 0; try < 20; try++) {		memset(cmd, 0, sizeof(cmd));		cmd[0] = CMDreqsense;		cmd[1] = lun<<5;		cmd[4] = Ninquiry;		memset(sense, 0, Ninquiry);		*nbytes = Ninquiry;		status = scsiexec(tp, SCSIread, cmd, sizeof(cmd), sense, nbytes);		if(status != STok)			return status;		*nbytes = sense[0x07]+8;		switch(sense[2] & 0x0F){		case 6:						/* unit attention */			/*			 * 0x28 - not ready to ready transition,			 *	  medium may have changed.			 * 0x29 - power on, RESET or BUS DEVICE RESET occurred.			 */			if(sense[12] != 0x28 && sense[12] != 0x29)				goto buggery;			/*FALLTHROUGH*/		case 0:						/* no sense */		case 1:						/* recovered error */			return STok;		case 8:						/* blank data */			return STblank;		case 2:						/* not ready */			if(sense[12] == 0x3A)			/* medium not present */				goto buggery;			/*FALLTHROUGH*/		default:			/*			 * If unit is becoming ready, rather than not ready,			 * then wait a little then poke it again; should this			 * be here or in the caller?			 */			if((sense[12] == 0x04 && sense[13] == 0x01)){				waitsec(500);				scsitest(tp, lun);				break;			}			goto buggery;		}	}buggery:	if(quiet == 0){		s = key[sense[2]&0x0F];		print("%s: reqsense: '%s' code #%2.2ux #%2.2ux\n",			tp->id, s, sense[12], sense[13]);		print("%s: byte 2: #%2.2ux, bytes 15-17: #%2.2ux #%2.2ux #%2.2ux\n",			tp->id, sense[2], sense[15], sense[16], sense[17]);		print("lastcmd (%d): ", lastcmdsz);		for(n = 0; n < lastcmdsz; n++)			print(" #%2.2ux", lastcmd[n]);		print("\n");	}	return STcheck;}static Target*scsitarget(Device* d){	int ctlrno, targetno;	ctlrno = d->wren.ctrl;	if(ctlrno < 0 || ctlrno >= MaxScsi || scsi[ctlrno].io == 0)		return 0;	targetno = d->wren.targ;	if(targetno < 0 || targetno >= NTarget)		return 0;	return &scsi[ctlrno].target[targetno];}static voidscsiprobe(Device* d){	Target *tp;	int nbytes, s;	uchar *sense;	int acount;	if((tp = scsitarget(d)) == 0)		panic("scsiprobe: device = %Z\n", d);	acount = 0;again:	s = scsitest(tp, d->wren.lun);	if(s < STok){		print("%s: test, status %d\n", tp->id, s);		return;	}	/*	 * Determine if the drive exists and is not ready or	 * is simply not responding.	 * If the status is OK but the drive came back with a 'power on' or	 * 'reset' status, try the test again to make sure the drive is really	 * ready.	 * If the drive is not ready and requires intervention, try to spin it	 * up.	 */	s = scsireqsense(tp, d->wren.lun, &nbytes, acount);	sense = tp->sense;	switch(s){	case STok:		if((sense[2] & 0x0F) == 0x06 && (sense[12] == 0x28 || sense[12] == 0x29)){			if(acount == 0){				acount = 1;				goto again;			}		}		break;	case STcheck:		if((sense[2] & 0x0F) == 0x02){			if(sense[12] == 0x3A)				break;			if(sense[12] == 0x04 && sense[13] == 0x02){				print("%s: starting...\n", tp->id);				if(scsistart(tp, d->wren.lun, 1) == STok)					break;				s = scsireqsense(tp, d->wren.lun, &nbytes, 0);			}		}		/*FALLTHROUGH*/	default:		print("%s: unavailable, status %d\n", tp->id, s);		return;	}	/*	 * Inquire to find out what the device is.	 * Hardware drivers may need some of the info.	 */	s = scsiinquiry(tp, d->wren.lun, &nbytes);	if(s != STok) {		print("%s: inquiry failed, status %d\n", tp->id, s);		return;	}	print("%s: %s\n", tp->id, (char*)tp->inquiry+8);	tp->ok = 1;}intscsiio(Device* d, int rw, uchar* cmd, int cbytes, void* data, int dbytes){	Target *tp;	int e, nbytes, s;	if((tp = scsitarget(d)) == 0)		panic("scsiio: device = %Z\n", d);	qlock(tp);	if(tp->ok == 0)		scsiprobe(d);	if(tp->fflag == 0) {		/* last args were 1000, now 1 */		dofilter(tp->work+0, C0a, C0b, 1);		dofilter(tp->work+1, C1a, C1b, 1);		dofilter(tp->work+2, C2a, C2b, 1);		/* */		dofilter(tp->rate+0, C0a, C0b, 1);		dofilter(tp->rate+1, C1a, C1b, 1);		dofilter(tp->rate+2, C2a, C2b, 1);		tp->fflag = 1;	}	tp->work[0].count++;	tp->work[1].count++;	tp->work[2].count++;	tp->rate[0].count += dbytes;	tp->rate[1].count += dbytes;	tp->rate[2].count += dbytes;	qunlock(tp);	s = STinit;	for(e = 0; e < 10; e++){		for(;;){			nbytes = dbytes;			s = scsiexec(tp, rw, cmd, cbytes, data, &nbytes);			if(s == STok)				break;			s = scsireqsense(tp, d->wren.lun, &nbytes, 0);			if(s == STblank && rw == SCSIread) {				memset(data, 0, dbytes);				return STok;			}			if(s != STok)				break;		}		if(s == STok)			break;	}	if(e)		print("%s: retry %d cmd #%x\n", tp->id, e, cmd[0]);	return s;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -