Charles.Forsyth20070714-11427a6ecc419 years agoHistory
303 lines · 6.0 KB · Brainfuck
RawDownload
implement ScsiIO; # adapted from /sys/src/libdisk on Plan 9: subject to Lucent Public License 1.02 include "sys.m";	sys: Sys; include "bufio.m";	bufio: Bufio;	Iobuf: import bufio; include "daytime.m";	daytime: Daytime; include "scsiio.m"; scsiverbose := 0; Codefile: con "/lib/scsicodes"; Code: adt {	v:	int;	# (asc<<8) | ascq	s:	string;};codes: array of Code; init(verbose: int){	sys = load Sys Sys->PATH;	bufio = load Bufio Bufio->PATH;	daytime = load Daytime Daytime->PATH; 	scsiverbose = verbose;	getcodes();} getcodes(){	fd := bufio->open(Codefile, Sys->OREAD);	if(fd == nil)		return; 	codes = array[256] of Code;	nc := 0;	while((s := fd.gets('\n')) != nil){		if(s[0] == '#' || s[0] == '\n')			continue;		s = s[0: len s-1];	# trim '\n'		m: string;		for(i := 0; i < len s; i++)			if(s[i] == ' '){				m = s[i+1:];				break;			}		c := Code(tohex(s), m);		if(nc >= len codes){			ct := array[nc + 20] of Code;			ct[0:] = codes;			codes = ct;		}		codes[nc++] = c;	}	codes = codes[0:nc];} tohex(s: string): int{	n := 0;	j := 0;	for(i := 0; i < len s && j < 4; i++){		if(s[i] == '/')			continue;		d := hex(s[i]);		if(d < 0)			return -1;		n = (n<<4) | d;		j++;	}	return n;} hex(c: int): int{	if(c >= '0' && c <= '9')		return c-'0';	if(c >= 'A' && c <= 'F')		return c-'A' + 10;	if(c >= 'a' && c <= 'f')		return c-'a' + 10;	return -1;} scsierror(asc: int, ascq: int): string{	t := -1;	for(i := 0; i < len codes; i++){		if(codes[i].v == ((asc<<8) | ascq))			return codes[i].s;		if(codes[i].v == (asc<<8))			t = i;	}	if(t >= 0)		return sys->sprint("(ascq #%.2ux) %s", ascq, codes[t].s);	return sys->sprint("scsi #%.2ux %.2ux", asc, ascq);} _scsicmd(s: ref Scsi, cmd: array of byte, data: array of byte, io: int, dolock: int): int{	if(dolock)		qlock(s);	dcount := len data;	if(sys->write(s.rawfd, cmd, len cmd) != len cmd) {		sys->werrstr("cmd write: %r");		if(dolock)			qunlock(s);		return -1;	} 	n: int;	resp := array[16] of byte;	case io {	Sread =>		n = sys->read(s.rawfd, data, dcount);		if(n < 0 && scsiverbose)			sys->fprint(sys->fildes(2), "dat read: %r: cmd %#2.2uX\n", int cmd[0]);	Swrite =>		n = sys->write(s.rawfd, data, dcount);		if(n != dcount && scsiverbose)			sys->fprint(sys->fildes(2), "dat write: %r: cmd %#2.2uX\n", int cmd[0]);	Snone or * =>		n = sys->write(s.rawfd, resp, 0);		if(n != 0 && scsiverbose)			sys->fprint(sys->fildes(2), "none write: %r: cmd %#2.2uX\n", int cmd[0]);	} 	m := sys->read(s.rawfd, resp, len resp);	if(dolock)		qunlock(s);	if(m < 0){		sys->werrstr("resp read: %r\n");		return -1;	}	status := int string resp[0:m];	if(status == 0)		return n; 	sys->werrstr(sys->sprint("cmd %2.2uX: status %uX dcount %d n %d", int cmd[0], status, dcount, n));	return -1;} Scsi.rawcmd(s: self ref Scsi, cmd: array of byte, data: array of byte, io: int): int{	return _scsicmd(s, cmd, data, io, 1);} _scsiready(s: ref Scsi, dolock: int): int{	if(dolock)		qlock(s);	for(i:=0; i<3; i++) {		cmd := array[6] of {0 => byte 16r00, * => byte 0};	# test unit ready		if(sys->write(s.rawfd, cmd, len cmd) != len cmd) {			if(scsiverbose)				sys->fprint(sys->fildes(2), "ur cmd write: %r\n");			continue;		}		resp := array[16] of byte;		sys->write(s.rawfd, resp, 0);		m := sys->read(s.rawfd, resp, len resp);		if(m < 0){			if(scsiverbose)				sys->fprint(sys->fildes(2), "ur resp read: %r\n");			continue;	# retry		}		status := int string resp[0:m];		if(status == 0 || status == 16r02) {			if(dolock)				qunlock(s);			return 0;		}		if(scsiverbose)			sys->fprint(sys->fildes(2), "target: bad status: %x\n", status);	}	if(dolock)		qunlock(s);	return -1;} Scsi.ready(s: self ref Scsi): int{	return _scsiready(s, 1);} Scsi.cmd(s: self ref Scsi, cmd: array of byte, data: array of byte, io: int): int{	dcount := len data;	code := 0;	key := 0;	qlock(s);	sense: array of byte;	for(tries:=0; tries<2; tries++) {		n := _scsicmd(s, cmd, data, io, 0);		if(n >= 0) {			qunlock(s);			return n;		} 		#		# request sense		#		sense = array[255] of {* => byte 16rFF};	# TO DO: usb mass storage devices might inist on less		req := array[6] of {0 => byte 16r03, 4 => byte len sense, * => byte 0};		if((n=_scsicmd(s, req, sense, Sread, 0)) < 14)			if(scsiverbose)				sys->fprint(sys->fildes(2), "reqsense scsicmd %d: %r\n", n);			if(_scsiready(s, 0) < 0)			if(scsiverbose)				sys->fprint(sys->fildes(2), "unit not ready\n");			key = int sense[2];		code = int sense[12];		if(code == 16r17 || code == 16r18) {	# recovered errors			qunlock(s);			return dcount;		}		if(code == 16r28 && int cmd[0] == 16r43) {	# get info and media changed			s.nchange++;			s.changetime = daytime->now();			continue;		}	} 	# drive not ready, or medium not present	if(cmd[0] == byte 16r43 && key == 2 && (code == 16r3a || code == 16r04)) {		s.changetime = 0;		qunlock(s);		return -1;	}	qunlock(s); 	if(cmd[0] == byte 16r43 && key == 5 && code == 16r24)	# blank media		return -1; 	p := scsierror(code, int sense[13]); 	sys->werrstr(sys->sprint("cmd #%.2ux: %s", int cmd[0], p)); 	if(scsiverbose)		sys->fprint(sys->fildes(2), "scsi cmd #%.2ux: %.2ux %.2ux %.2ux: %s\n", int cmd[0], key, code, int sense[13], p); #	if(key == 0)#		return dcount;	return -1;} Scsi.open(dev: string): ref Scsi{	rawfd := sys->open(dev+"/raw", Sys->ORDWR);	if(rawfd == nil)		return nil;	ctlfd := sys->open(dev+"/ctl", Sys->ORDWR);	if(ctlfd == nil)		return nil; 	buf := array[512] of byte;	n := sys->readn(ctlfd, buf, len buf);	if(n < 8){		if(n >= 0)			sys->werrstr("error reading ctl file");		return nil;	}	ctlfd = nil; 	for(i := 0; i < n; i++)		if(buf[i] == byte '\n')			break;	inq := string buf[0:i];	if(i >= n || inq[0:8] != "inquiry "){		sys->werrstr("invalid inquiry string");		return nil;	}	s := ref Scsi;	s.lock = chan[1] of int;	s.rawfd = rawfd;	s.inquire = inq[8:];	s.changetime = daytime->now(); 	if(s.ready() < 0)		return nil; 	return s;} qlock(s: ref Scsi){	s.lock <-= 1;} qunlock(s: ref Scsi){	<-s.lock;}