1967 lines · 37.8 KB · C
RawDownload
/*  * This file is part of the UCB release of Plan 9. It is subject to the license * terms in the LICENSE file found in the top-level directory of this * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No * part of the UCB release of Plan 9, including this file, may be copied, * modified, propagated, or distributed except according to the terms contained * in the LICENSE file. */ #include <u.h>#include <libc.h>#include <bio.h>#include <disk.h>#include "scsireq.h" enum {					/* fundamental constants/defaults */	/*	 * default & maximum `maximum i/o size'; overridden by -m.	 * limits kernel memory consumption.	 * 240K is exabyte maximum block size.	 */	MaxIOsize	= 240*1024,}; #define MIN(a, b)	((a) < (b) ? (a): (b)) static char rwbuf[MaxIOsize];static int verbose = 1; Biobuf bin, bout;long maxiosize = MaxIOsize;int exabyte = 0;int force6bytecmds = 0; typedef struct {	char *name;	long (*f)(ScsiReq *, int, char *[]);	int open;	char *help;} ScsiCmd; static ScsiCmd scsicmds[]; static vlongvlmin(vlong a, vlong b){	if (a < b)		return a;	else		return b;} static longcmdready(ScsiReq *rp, int argc, char *argv[]){	USED(argc, argv);	return SRready(rp);} static longcmdrewind(ScsiReq *rp, int argc, char *argv[]){	USED(argc, argv);	return SRrewind(rp);} static longcmdreqsense(ScsiReq *rp, int argc, char *argv[]){	long nbytes; 	USED(argc, argv);	if((nbytes = SRreqsense(rp)) != -1)		makesense(rp);	return nbytes;} static longcmdformat(ScsiReq *rp, int argc, char *argv[]){	USED(argc, argv);	return SRformat(rp);} static longcmdrblimits(ScsiReq *rp, int argc, char *argv[]){	uchar l[6];	long n; 	USED(argc, argv);	if((n = SRrblimits(rp, l)) == -1)		return -1;	Bprint(&bout, " %2.2uX %2.2uX %2.2uX %2.2uX %2.2uX %2.2uX\n",		l[0], l[1], l[2], l[3], l[4], l[5]);	return n;} static intmkfile(char *file, int omode, int *pid){	int fd[2]; 	if(*file != '|'){		*pid = -1;		if(omode == OWRITE)			return create(file, OWRITE, 0666);		else if(omode == OREAD)			return open(file, OREAD);		return -1;	} 	file++;	if(*file == 0 || pipe(fd) == -1)		return -1;	if((*pid = fork()) == -1){		close(fd[0]);		close(fd[1]);		return -1;	}	if(*pid == 0){		switch(omode){ 		case OREAD:			dup(fd[0], 1);			break; 		case OWRITE:			dup(fd[0], 0);			break;		}		close(fd[0]);		close(fd[1]);		execl("/bin/rc", "rc", "-c", file, nil);		exits("exec");	}	close(fd[0]);	return fd[1];} intwaitfor(int pid){	int msg;	Waitmsg *w; 	while((w = wait()) != nil){		if(w->pid != pid){			free(w);			continue;		}		msg = (w->msg[0] != '\0');		free(w);		return msg;	}	return -1;} static longcmdread(ScsiReq *rp, int argc, char *argv[]){	long n, iosize, prevsize = 0;	vlong nbytes, total;	int fd, pid;	char *p; 	iosize = maxiosize;	nbytes = ~0ULL >> 1;	switch(argc){ 	default:		rp->status = Status_BADARG;		return -1; 	case 2:		nbytes = strtoll(argv[1], &p, 0);		if(nbytes == 0 && p == argv[1]){			rp->status = Status_BADARG;			return -1;		}		/*FALLTHROUGH*/ 	case 1:		if((fd = mkfile(argv[0], OWRITE, &pid)) == -1){			rp->status = Status_BADARG;			return -1;		}		break;	}	print("device native block size=%lud\n", rp->lbsize);	total = 0;	while(nbytes){		n = vlmin(nbytes, iosize);		if((n = SRread(rp, rwbuf, n)) == -1){			if(total == 0)				total = -1;			break;		}		if (n == 0)			break;		if (prevsize != n) {			print("tape block size=%ld\n", n);			prevsize = n;		}		if(write(fd, rwbuf, n) != n){			if(total == 0)				total = -1;			if(rp->status == STok)				rp->status = Status_SW;			break;		}		nbytes -= n;		total += n;	}	close(fd);	if(pid >= 0 && waitfor(pid)){		rp->status = Status_SW;		return -1;	}	return total;} static longcmdwrite(ScsiReq *rp, int argc, char *argv[]){	long n, prevsize = 0;	vlong nbytes, total;	int fd, pid;	char *p; 	nbytes = ~0ULL >> 1;	switch(argc){ 	default:		rp->status = Status_BADARG;		return -1; 	case 2:		nbytes = strtoll(argv[1], &p, 0);		if(nbytes == 0 && p == argv[1]){			rp->status = Status_BADARG;			return -1;		}		/*FALLTHROUGH*/ 	case 1:		if((fd = mkfile(argv[0], OREAD, &pid)) == -1){			rp->status = Status_BADARG;			return -1;		}		break;	}	total = 0;	while(nbytes){		n = vlmin(nbytes, maxiosize);		if((n = read(fd, rwbuf, n)) == -1){			if(total == 0)				total = -1;			break;		}		if (n == 0)			break;		if (prevsize != n) {			print("tape block size=%ld\n", n);			prevsize = n;		}		if(SRwrite(rp, rwbuf, n) != n){			if(total == 0)				total = -1;			if(rp->status == STok)				rp->status = Status_SW;			break;		}		nbytes -= n;		total += n;	}	close(fd);	if(pid >= 0 && waitfor(pid)){		rp->status = Status_SW;		return -1;	}	return total;} static longcmdseek(ScsiReq *rp, int argc, char *argv[]){	char *p;	long offset;	int type; 	type = 0;	switch(argc){ 	default:		rp->status = Status_BADARG;		return -1; 	case 2:		if((type = strtol(argv[1], &p, 0)) == 0 && p == argv[1]){			rp->status = Status_BADARG;			return -1;		}		/*FALLTHROUGH*/ 	case 1:		if((offset = strtol(argv[0], &p, 0)) == 0 && p == argv[0]){			rp->status = Status_BADARG;			return -1;		}		break;	}	return SRseek(rp, offset, type);} static longcmdfilemark(ScsiReq *rp, int argc, char *argv[]){	char *p;	ulong howmany; 	howmany = 1;	if(argc && (howmany = strtoul(argv[0], &p, 0)) == 0 && p == argv[0]){		rp->status = Status_BADARG;		return -1;	}	return SRfilemark(rp, howmany);} static longcmdspace(ScsiReq *rp, int argc, char *argv[]){	uchar code;	long howmany;	char option, *p; 	code = 0x00;	howmany = 1;	while(argc && (*argv)[0] == '-'){		while(option = *++argv[0]){			switch(option){ 			case '-':				break; 			case 'b':				code = 0x00;				break; 			case 'f':				code = 0x01;				break; 			default:				rp->status = Status_BADARG;				return -1;			}			break;		}		argc--; argv++;		if(option == '-')			break;	}	if(argc && ((howmany = strtol(argv[0], &p, 0)) == 0 && p == argv[0])){		rp->status = Status_BADARG;		return -1;	}	return SRspace(rp, code, howmany);} static longcmdinquiry(ScsiReq *rp, int argc, char *argv[]){	long status;	int i, n;	uchar *p; 	USED(argc, argv);	if((status = SRinquiry(rp)) != -1){		n = rp->inquiry[4]+4;		for(i = 0; i < MIN(8, n); i++)			Bprint(&bout, " %2.2uX", rp->inquiry[i]);		p = &rp->inquiry[8];		n = MIN(n, sizeof(rp->inquiry)-8);		while(n && (*p == ' ' || *p == '\t' || *p == '\n')){			n--;			p++;		}		Bprint(&bout, "\t%.*s\n", n, (char*)p);	}	return status;} static longcmdmodeselect6(ScsiReq *rp, int argc, char *argv[]){	uchar list[MaxDirData];	long nbytes, ul;	char *p; 	memset(list, 0, sizeof list);	for(nbytes = 0; argc; argc--, argv++, nbytes++){		if((ul = strtoul(argv[0], &p, 0)) == 0 && p == argv[0]){			rp->status = Status_BADARG;			return -1;		}		list[nbytes] = ul; 	}	if(!(rp->flags & Finqok) && SRinquiry(rp) == -1)		Bprint(&bout, "warning: couldn't determine whether SCSI-1/SCSI-2 mode");	return SRmodeselect6(rp, list, nbytes);} static longcmdmodeselect10(ScsiReq *rp, int argc, char *argv[]){	uchar list[MaxDirData];	long nbytes, ul;	char *p; 	memset(list, 0, sizeof list);	for(nbytes = 0; argc; argc--, argv++, nbytes++){		if((ul = strtoul(argv[0], &p, 0)) == 0 && p == argv[0]){			rp->status = Status_BADARG;			return -1;		}		list[nbytes] = ul; 	}	if(!(rp->flags & Finqok) && SRinquiry(rp) == -1)		Bprint(&bout, "warning: couldn't determine whether SCSI-1/SCSI-2 mode");	return SRmodeselect10(rp, list, nbytes);} static longcmdmodesense6(ScsiReq *rp, int argc, char *argv[]){	uchar list[MaxDirData], *lp, page;	long i, n, nbytes, status;	char *p; 	nbytes = sizeof list;	switch(argc){ 	default:		rp->status = Status_BADARG;		return -1; 	case 2:		if((nbytes = strtoul(argv[1], &p, 0)) == 0 && p == argv[1]){			rp->status = Status_BADARG;			return -1;		}		/*FALLTHROUGH*/ 	case 1:		if((page = strtoul(argv[0], &p, 0)) == 0 && p == argv[0]){			rp->status = Status_BADARG;			return -1;		}		break; 	case 0:		page = Allmodepages;		break;	}	if((status = SRmodesense6(rp, page, list, nbytes)) == -1)		return -1;	lp = list;	nbytes = list[0];	Bprint(&bout, " Header\n   ");	for(i = 0; i < 4; i++){				/* header */		Bprint(&bout, " %2.2uX", *lp);		lp++;	}	Bputc(&bout, '\n'); 	if(list[3]){					/* block descriptors */		for(n = 0; n < list[3]/8; n++){			Bprint(&bout, " Block %ld\n   ", n);			for(i = 0; i < 8; i++)				Bprint(&bout, " %2.2uX", lp[i]);			Bprint(&bout, "    (density %2.2uX", lp[0]);			Bprint(&bout, " blocks %d", (lp[1]<<16)|(lp[2]<<8)|lp[3]);			Bprint(&bout, " length %d)", (lp[5]<<16)|(lp[6]<<8)|lp[7]);			lp += 8;			nbytes -= 8;			Bputc(&bout, '\n');		}	} 	while(nbytes > 0){				/* pages */		i = *(lp+1);		nbytes -= i+2;		Bprint(&bout, " Page %2.2uX %d\n   ", *lp & 0x3F, *(lp+1));		lp += 2;		for(n = 0; n < i; n++){			if(n && ((n & 0x0F) == 0))				Bprint(&bout, "\n   ");

Lines 1–500 of 1967.