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

📄 scsireq.c

📁 这是一个同样来自贝尔实验室的和UNIX有着渊源的操作系统, 其简洁的设计和实现易于我们学习和理解
💻 C
字号:
#include <u.h>#include <libc.h>/* * BUGS: *	no luns *	and incomplete in many other ways */#include "scsireq.h"enum {	Debug = 0,};extern long maxiosize;/* * exabyte tape drives, at least old ones like the 8200 and 8505, * are dumb: you have to read the exact block size on the tape, * they don't take 10-byte SCSI commands, and various other fine points. */extern int exabyte, force6bytecmds;static int debug = Debug;longSRready(ScsiReq *rp){	uchar cmd[6];	memset(cmd, 0, sizeof(cmd));	rp->cmd.p = cmd;	rp->cmd.count = sizeof(cmd);	rp->data.p = cmd;	rp->data.count = 0;	rp->data.write = 1;	return SRrequest(rp);}longSRrewind(ScsiReq *rp){	uchar cmd[6];	memset(cmd, 0, sizeof(cmd));	cmd[0] = ScmdRewind;	rp->cmd.p = cmd;	rp->cmd.count = sizeof(cmd);	rp->data.p = cmd;	rp->data.count = 0;	rp->data.write = 1;	if(SRrequest(rp) >= 0){		rp->offset = 0;		return 0;	}	return -1;}longSRreqsense(ScsiReq *rp){	uchar cmd[6];	ScsiReq req;	long status;	if(rp->status == Status_SD){		rp->status = STok;		return 0;	}	memset(cmd, 0, sizeof(cmd));	cmd[0] = ScmdRsense;	cmd[4] = sizeof(req.sense);	memset(&req, 0, sizeof(req));	req.fd = rp->fd;	req.cmd.p = cmd;	req.cmd.count = sizeof(cmd);	req.data.p = rp->sense;	req.data.count = sizeof(rp->sense);	req.data.write = 0;	status = SRrequest(&req);	rp->status = req.status;	return status;}longSRformat(ScsiReq *rp){	uchar cmd[6];	memset(cmd, 0, sizeof(cmd));	cmd[0] = ScmdFormat;	rp->cmd.p = cmd;	rp->cmd.count = sizeof(cmd);	rp->data.p = cmd;	rp->data.count = 6;	rp->data.write = 0;	return SRrequest(rp);}longSRrblimits(ScsiReq *rp, uchar *list){	uchar cmd[6];	memset(cmd, 0, sizeof(cmd));	cmd[0] = ScmdRblimits;	rp->cmd.p = cmd;	rp->cmd.count = sizeof(cmd);	rp->data.p = list;	rp->data.count = 6;	rp->data.write = 0;	return SRrequest(rp);}static intdirdevrw(ScsiReq *rp, uchar *cmd, long nbytes){	long n;	n = nbytes/rp->lbsize;	if(rp->offset <= 0x1fffff && n <= 256 && (rp->flags & Frw10) == 0){		cmd[1] = rp->offset>>16;		cmd[2] = rp->offset>>8;		cmd[3] = rp->offset;		cmd[4] = n;		cmd[5] = 0;		return 6;	}	cmd[0] |= ScmdExtread;	cmd[1] = 0;	cmd[2] = rp->offset>>24;	cmd[3] = rp->offset>>16;	cmd[4] = rp->offset>>8;	cmd[5] = rp->offset;	cmd[6] = 0;	cmd[7] = n>>8;	cmd[8] = n;	cmd[9] = 0;	return 10;}static intseqdevrw(ScsiReq *rp, uchar *cmd, long nbytes){	long n;	cmd[1] = rp->flags&Fbfixed? 0x01: 0x00;	/* cmd[1]&2 is the SILI bit: don't report `incorrect' block lengths */	n = nbytes/rp->lbsize;	cmd[2] = n>>16;	cmd[3] = n>>8;	cmd[4] = n;	cmd[5] = 0;	return 6;}longSRread(ScsiReq *rp, void *buf, long nbytes){	uchar cmd[10];	long n;	if((nbytes % rp->lbsize) || nbytes > maxiosize){		rp->status = Status_BADARG;		return -1;	}	cmd[0] = ScmdRead;	if(rp->flags & Fseqdev)		rp->cmd.count = seqdevrw(rp, cmd, nbytes);	else		rp->cmd.count = dirdevrw(rp, cmd, nbytes);	rp->cmd.p = cmd;	rp->data.p = buf;	rp->data.count = nbytes;	rp->data.write = 0;	if((n = SRrequest(rp)) == -1){		/* maybe we just read a short record? */		if (exabyte) {			fprint(2, "read error\n");			rp->status = STcheck;			return n;		}		if(rp->status != Status_SD || (rp->sense[0] & 0x80) == 0)			return -1;		if (debug)			fprint(2, "SRread: SRrequest failed with sense data; reading byte count from sense\n");		n = ((rp->sense[3]<<24)		   | (rp->sense[4]<<16)		   | (rp->sense[5]<<8)		   | rp->sense[6])		   * rp->lbsize;		if(!(rp->flags & Fseqdev))			return -1;		if(rp->sense[2] == 0x80 || rp->sense[2] == 0x08)			rp->data.count = nbytes - n;		else if(rp->sense[2] == 0x20 && n > 0)			rp->data.count = nbytes - n;		else			return -1;		if (debug)			fprint(2, "SRread: computing byte count from sense\n");		n = rp->data.count;		rp->status = STok;	}	rp->offset += n/rp->lbsize;	return n;}longSRwrite(ScsiReq *rp, void *buf, long nbytes){	uchar cmd[10];	long n;	if((nbytes % rp->lbsize) || nbytes > maxiosize){		rp->status = Status_BADARG;		return -1;	}	cmd[0] = ScmdWrite;	if(rp->flags & Fseqdev)		rp->cmd.count = seqdevrw(rp, cmd, nbytes);	else		rp->cmd.count = dirdevrw(rp, cmd, nbytes);	rp->cmd.p = cmd;	rp->data.p = buf;	rp->data.count = nbytes;	rp->data.write = 1;	if((n = SRrequest(rp)) == -1){		if (exabyte) {			fprint(2, "write error\n");			rp->status = STcheck;			return n;		}		if(rp->status != Status_SD || rp->sense[2] != 0x40)			return -1;		if(rp->sense[0] & 0x80){			n -= ((rp->sense[3]<<24)			    | (rp->sense[4]<<16)			    | (rp->sense[5]<<8)			    | rp->sense[6])			    * rp->lbsize;			rp->data.count = nbytes - n;		}		else			rp->data.count = nbytes;		n = rp->data.count;	}	rp->offset += n/rp->lbsize;	return n;}longSRseek(ScsiReq *rp, long offset, int type){	uchar cmd[10];	switch(type){	case 0:		break;	case 1:		offset += rp->offset;		if(offset >= 0)			break;		/*FALLTHROUGH*/	default:		rp->status = Status_BADARG;		return -1;	}	if(offset <= 0x1fffff && (rp->flags & Frw10) == 0){		cmd[0] = ScmdSeek;		cmd[1] = (offset>>16) & 0x1F;		cmd[2] = offset>>8;		cmd[3] = offset;		cmd[4] = 0;		cmd[5] = 0;		rp->cmd.count = 6;	}else{		cmd[0] = ScmdExtseek;		cmd[1] = 0;		cmd[2] = offset>>24;		cmd[3] = offset>>16;		cmd[4] = offset>>8;		cmd[5] = offset;		cmd[6] = 0;		cmd[7] = 0;		cmd[8] = 0;		cmd[9] = 0;		rp->cmd.count = 10;	}	rp->cmd.p = cmd;	rp->data.p = cmd;	rp->data.count = 0;	rp->data.write = 1;	SRrequest(rp);	if(rp->status == STok)		return rp->offset = offset;	return -1;}longSRfilemark(ScsiReq *rp, ulong howmany){	uchar cmd[6];	cmd[0] = ScmdFmark;	cmd[1] = 0;	cmd[2] = howmany>>16;	cmd[3] = howmany>>8;	cmd[4] = howmany;	cmd[5] = 0;	rp->cmd.p = cmd;	rp->cmd.count = sizeof(cmd);	rp->data.p = cmd;	rp->data.count = 0;	rp->data.write = 1;	return SRrequest(rp);}longSRspace(ScsiReq *rp, uchar code, long howmany){	uchar cmd[6];	cmd[0] = ScmdSpace;	cmd[1] = code;	cmd[2] = howmany>>16;	cmd[3] = howmany>>8;	cmd[4] = howmany;	cmd[5] = 0;	rp->cmd.p = cmd;	rp->cmd.count = sizeof(cmd);	rp->data.p = cmd;	rp->data.count = 0;	rp->data.write = 1;	/*	 * what about rp->offset?	 */	return SRrequest(rp);}longSRinquiry(ScsiReq *rp){	uchar cmd[6];	memset(cmd, 0, sizeof(cmd));	cmd[0] = ScmdInq;	cmd[4] = sizeof(rp->inquiry);	rp->cmd.p = cmd;	rp->cmd.count = sizeof(cmd);	rp->data.p = rp->inquiry;	rp->data.count = sizeof(rp->inquiry);	rp->data.write = 0;	if(SRrequest(rp) >= 0){		rp->flags |= Finqok;		return 0;	}	rp->flags &= ~Finqok;	return -1;}longSRmodeselect6(ScsiReq *rp, uchar *list, long nbytes){	uchar cmd[6];	memset(cmd, 0, sizeof(cmd));	cmd[0] = ScmdMselect6;	if((rp->flags & Finqok) && (rp->inquiry[2] & 0x07) >= 2)		cmd[1] = 0x10;	cmd[4] = nbytes;	rp->cmd.p = cmd;	rp->cmd.count = sizeof(cmd);	rp->data.p = list;	rp->data.count = nbytes;	rp->data.write = 1;	return SRrequest(rp);}longSRmodeselect10(ScsiReq *rp, uchar *list, long nbytes){	uchar cmd[10];	memset(cmd, 0, sizeof(cmd));	if((rp->flags & Finqok) && (rp->inquiry[2] & 0x07) >= 2)		cmd[1] = 0x10;	cmd[0] = ScmdMselect10;	cmd[7] = nbytes>>8;	cmd[8] = nbytes;	rp->cmd.p = cmd;	rp->cmd.count = sizeof(cmd);	rp->data.p = list;	rp->data.count = nbytes;	rp->data.write = 1;	return SRrequest(rp);}longSRmodesense6(ScsiReq *rp, uchar page, uchar *list, long nbytes){	uchar cmd[6];	memset(cmd, 0, sizeof(cmd));	cmd[0] = ScmdMsense6;	cmd[2] = page;	cmd[4] = nbytes;	rp->cmd.p = cmd;	rp->cmd.count = sizeof(cmd);	rp->data.p = list;	rp->data.count = nbytes;	rp->data.write = 0;	return SRrequest(rp);}longSRmodesense10(ScsiReq *rp, uchar page, uchar *list, long nbytes){	uchar cmd[10];	memset(cmd, 0, sizeof(cmd));	cmd[0] = ScmdMsense10;	cmd[2] = page;	cmd[7] = nbytes>>8;	cmd[8] = nbytes;	rp->cmd.p = cmd;	rp->cmd.count = sizeof(cmd);	rp->data.p = list;	rp->data.count = nbytes;	rp->data.write = 0;	return SRrequest(rp);}longSRstart(ScsiReq *rp, uchar code){	uchar cmd[6];	memset(cmd, 0, sizeof(cmd));	cmd[0] = ScmdStart;	cmd[4] = code;	rp->cmd.p = cmd;	rp->cmd.count = sizeof(cmd);	rp->data.p = cmd;	rp->data.count = 0;	rp->data.write = 1;	return SRrequest(rp);}longSRrcapacity(ScsiReq *rp, uchar *data){	uchar cmd[10];	memset(cmd, 0, sizeof(cmd));	cmd[0] = ScmdRcapacity;	rp->cmd.p = cmd;	rp->cmd.count = sizeof(cmd);	rp->data.p = data;	rp->data.count = 8;	rp->data.write = 0;	return SRrequest(rp);}static longrequest(int fd, ScsiPtr *cmd, ScsiPtr *data, int *status){	long n, r;	char buf[16];	/* this was an experiment but it seems to be a good idea */	*status = STok;	/* send SCSI command */	if(write(fd, cmd->p, cmd->count) != cmd->count){		fprint(2, "scsireq: write cmd: %r\n");		*status = Status_SW;		return -1;	}	/* read or write actual data */	if(data->write)		n = write(fd, data->p, data->count);	else {		n = read(fd, data->p, data->count);		if (n < 0)			memset(data->p, 0, data->count);		else if (n < data->count)			memset(data->p + n, 0, data->count - n);	}	if (n != data->count && n <= 0)		fprint(2,	"request: tried to %s %ld bytes of data for cmd 0x%x but got %r\n",			(data->write? "write": "read"), data->count, cmd->p[0]);	else if (n != data->count && (data->write || debug))		fprint(2, "request: %s %ld of %ld bytes of actual data\n",			(data->write? "wrote": "read"), n, data->count);	/* read status */	buf[0] = '\0';	r = read(fd, buf, sizeof buf-1);	if(exabyte && r <= 0 || !exabyte && r < 0){		fprint(2, "scsireq: read status: %r\n");		*status = Status_SW;		return -1;	}	if (r >= 0)		buf[r] = '\0';	*status = atoi(buf);	if(n < 0 && (exabyte || *status != STcheck))		fprint(2, "scsireq: status 0x%2.2uX: data transfer: %r\n", *status);	return n;}longSRrequest(ScsiReq *rp){	long n;	int status;retry:	n = request(rp->fd, &rp->cmd, &rp->data, &status);	switch(rp->status = status){	case STok:		rp->data.count = n;		break;	case STcheck:		if(rp->cmd.p[0] != ScmdRsense && SRreqsense(rp) != -1)			rp->status = Status_SD;		if (exabyte)			fprint(2, "SRrequest: STcheck, returning -1\n");		return -1;	case STbusy:		sleep(1000);		goto retry;	default:		fprint(2, "status 0x%2.2uX\n", status);		return -1;	}	return n;}intSRclose(ScsiReq *rp){	if((rp->flags & Fopen) == 0){		rp->status = Status_BADARG;		return -1;	}	close(rp->fd);	rp->flags = 0;	return 0;}static intdirdevopen(ScsiReq *rp){	ulong blocks;	uchar data[8];	if(SRstart(rp, 1) == -1 || SRrcapacity(rp, data) == -1)		return -1;	rp->lbsize = (data[4]<<28)|(data[5]<<16)|(data[6]<<8)|data[7];	blocks =     (data[0]<<24)|(data[1]<<16)|(data[2]<<8)|data[3];	/* some newer dev's don't support 6-byte commands */	if(blocks > 0x1fffff && !force6bytecmds)		rp->flags |= Frw10;	return 0;}static intseqdevopen(ScsiReq *rp){	uchar mode[16], limits[6];	if(SRrblimits(rp, limits) == -1)		return -1;	if(limits[1] || limits[2] != limits[4] || limits[3] != limits[5]){		/*		 * On some older hardware the optional 10-byte		 * modeselect command isn't implemented.		 */		if (force6bytecmds)			rp->flags |= Fmode6;		if(!(rp->flags & Fmode6)){			/* try 10-byte command first */			memset(mode, 0, sizeof(mode));			mode[3] = 0x10;		/* device-specific param. */			mode[7] = 8;		/* block descriptor length */			/*			 * exabytes can't handle this, and			 * modeselect(10) is optional.			 */			if(SRmodeselect10(rp, mode, sizeof(mode)) != -1){				rp->lbsize = 1;				return 0;	/* success */			}			/* can't do 10-byte commands, back off to 6-byte ones */			rp->flags |= Fmode6;		}		/* 6-byte command */		memset(mode, 0, sizeof(mode));		mode[2] = 0x10;		/* device-specific param. */		mode[3] = 8;		/* block descriptor length */		/*		 * bsd sez exabytes need this bit (NBE) in vendor-specific		 * page (0), but so far we haven't needed it.		 */		if (0)			mode[12] |= 8;		if(SRmodeselect6(rp, mode, 4+8) == -1)			return -1;		rp->lbsize = 1;	}else{		rp->flags |= Fbfixed;		rp->lbsize = (limits[4]<<8)|limits[5];	}	return 0;}static intwormdevopen(ScsiReq *rp){	uchar list[MaxDirData];	long status;	if(SRstart(rp, 1) == -1)		return -1;	if((status = SRmodesense10(rp, 0x3F, list, sizeof(list))) == -1)		return -1;	if(((list[6]<<8)|list[3]) < 8)		rp->lbsize = 2048;	else		rp->lbsize = (list[13]<<8)|(list[14]<<8)|list[15];	return status;}intSRopenraw(ScsiReq *rp, char *unit){	char name[128];	if(rp->flags & Fopen){		rp->status = Status_BADARG;		return -1;	}	memset(rp, 0, sizeof(*rp));	rp->unit = unit;	sprint(name, "%s/raw", unit);	if((rp->fd = open(name, ORDWR)) == -1){		rp->status = STtimeout;		return -1;	}	rp->flags = Fopen;	return 0;}intSRopen(ScsiReq *rp, char *unit){	if(SRopenraw(rp, unit) == -1)		return -1;	SRready(rp);	if(SRinquiry(rp) >= 0){		switch(rp->inquiry[0]){		default:			fprint(2, "unknown device type 0x%.2x\n", rp->inquiry[0]);			rp->status = Status_SW;			break;		case 0x00:	/* Direct access (disk) */		case 0x05:	/* CD-ROM */		case 0x07:	/* rewriteable MO */			if(dirdevopen(rp) == -1)				break;			return 0;		case 0x01:	/* Sequential eg: tape */			rp->flags |= Fseqdev;			if(seqdevopen(rp) == -1)				break;			return 0;		case 0x02:	/* Printer */			rp->flags |= Fprintdev;			return 0;		case 0x04:	/* Worm */			rp->flags |= Fwormdev;			if(wormdevopen(rp) == -1)				break;			return 0;		case 0x08:	/* medium-changer */			rp->flags |= Fchanger;			return 0;		}	}	SRclose(rp);	return -1;}

⌨️ 快捷键说明

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