xref: /inferno-os/appl/lib/scsiio.b (revision a6011949be081a8fe1bec0713ce60c36beb3a351)
137da2899SCharles.Forsythimplement ScsiIO;
237da2899SCharles.Forsyth
337da2899SCharles.Forsyth# adapted from /sys/src/libdisk on Plan 9: subject to Lucent Public License 1.02
437da2899SCharles.Forsyth
537da2899SCharles.Forsythinclude "sys.m";
637da2899SCharles.Forsyth	sys: Sys;
737da2899SCharles.Forsyth
837da2899SCharles.Forsythinclude "bufio.m";
937da2899SCharles.Forsyth	bufio: Bufio;
1037da2899SCharles.Forsyth	Iobuf: import bufio;
1137da2899SCharles.Forsyth
1237da2899SCharles.Forsythinclude "daytime.m";
1337da2899SCharles.Forsyth	daytime: Daytime;
1437da2899SCharles.Forsyth
1537da2899SCharles.Forsythinclude "scsiio.m";
1637da2899SCharles.Forsyth
1737da2899SCharles.Forsythscsiverbose := 0;
1837da2899SCharles.Forsyth
1937da2899SCharles.ForsythCodefile: con "/lib/scsicodes";
2037da2899SCharles.Forsyth
2137da2899SCharles.ForsythCode: adt {
2237da2899SCharles.Forsyth	v:	int;	# (asc<<8) | ascq
2337da2899SCharles.Forsyth	s:	string;
2437da2899SCharles.Forsyth};
2537da2899SCharles.Forsythcodes: array of Code;
2637da2899SCharles.Forsyth
2737da2899SCharles.Forsythinit(verbose: int)
2837da2899SCharles.Forsyth{
2937da2899SCharles.Forsyth	sys = load Sys Sys->PATH;
3037da2899SCharles.Forsyth	bufio = load Bufio Bufio->PATH;
3137da2899SCharles.Forsyth	daytime = load Daytime Daytime->PATH;
3237da2899SCharles.Forsyth
3337da2899SCharles.Forsyth	scsiverbose = verbose;
3437da2899SCharles.Forsyth	getcodes();
3537da2899SCharles.Forsyth}
3637da2899SCharles.Forsyth
3737da2899SCharles.Forsythgetcodes()
3837da2899SCharles.Forsyth{
3937da2899SCharles.Forsyth	fd := bufio->open(Codefile, Sys->OREAD);
4037da2899SCharles.Forsyth	if(fd == nil)
4137da2899SCharles.Forsyth		return;
4237da2899SCharles.Forsyth
4337da2899SCharles.Forsyth	codes = array[256] of Code;
4437da2899SCharles.Forsyth	nc := 0;
4537da2899SCharles.Forsyth	while((s := fd.gets('\n')) != nil){
4637da2899SCharles.Forsyth		if(s[0] == '#' || s[0] == '\n')
4737da2899SCharles.Forsyth			continue;
4837da2899SCharles.Forsyth		s = s[0: len s-1];	# trim '\n'
4937da2899SCharles.Forsyth		m: string;
5037da2899SCharles.Forsyth		for(i := 0; i < len s; i++)
5137da2899SCharles.Forsyth			if(s[i] == ' '){
5237da2899SCharles.Forsyth				m = s[i+1:];
5337da2899SCharles.Forsyth				break;
5437da2899SCharles.Forsyth			}
5537da2899SCharles.Forsyth		c := Code(tohex(s), m);
5637da2899SCharles.Forsyth		if(nc >= len codes){
5737da2899SCharles.Forsyth			ct := array[nc + 20] of Code;
5837da2899SCharles.Forsyth			ct[0:] = codes;
5937da2899SCharles.Forsyth			codes = ct;
6037da2899SCharles.Forsyth		}
6137da2899SCharles.Forsyth		codes[nc++] = c;
6237da2899SCharles.Forsyth	}
6337da2899SCharles.Forsyth	codes = codes[0:nc];
6437da2899SCharles.Forsyth}
6537da2899SCharles.Forsyth
6637da2899SCharles.Forsythtohex(s: string): int
6737da2899SCharles.Forsyth{
6837da2899SCharles.Forsyth	n := 0;
6937da2899SCharles.Forsyth	j := 0;
7037da2899SCharles.Forsyth	for(i := 0; i < len s && j < 4; i++){
7137da2899SCharles.Forsyth		if(s[i] == '/')
7237da2899SCharles.Forsyth			continue;
7337da2899SCharles.Forsyth		d := hex(s[i]);
7437da2899SCharles.Forsyth		if(d < 0)
7537da2899SCharles.Forsyth			return -1;
7637da2899SCharles.Forsyth		n = (n<<4) | d;
7737da2899SCharles.Forsyth		j++;
7837da2899SCharles.Forsyth	}
7937da2899SCharles.Forsyth	return n;
8037da2899SCharles.Forsyth}
8137da2899SCharles.Forsyth
8237da2899SCharles.Forsythhex(c: int): int
8337da2899SCharles.Forsyth{
8437da2899SCharles.Forsyth	if(c >= '0' && c <= '9')
8537da2899SCharles.Forsyth		return c-'0';
8637da2899SCharles.Forsyth	if(c >= 'A' && c <= 'F')
8737da2899SCharles.Forsyth		return c-'A' + 10;
8837da2899SCharles.Forsyth	if(c >= 'a' && c <= 'f')
8937da2899SCharles.Forsyth		return c-'a' + 10;
9037da2899SCharles.Forsyth	return -1;
9137da2899SCharles.Forsyth}
9237da2899SCharles.Forsyth
9337da2899SCharles.Forsythscsierror(asc: int, ascq: int): string
9437da2899SCharles.Forsyth{
9537da2899SCharles.Forsyth	t := -1;
9637da2899SCharles.Forsyth	for(i := 0; i < len codes; i++){
9737da2899SCharles.Forsyth		if(codes[i].v == ((asc<<8) | ascq))
9837da2899SCharles.Forsyth			return codes[i].s;
9937da2899SCharles.Forsyth		if(codes[i].v == (asc<<8))
10037da2899SCharles.Forsyth			t = i;
10137da2899SCharles.Forsyth	}
10237da2899SCharles.Forsyth	if(t >= 0)
10337da2899SCharles.Forsyth		return sys->sprint("(ascq #%.2ux) %s", ascq, codes[t].s);
10437da2899SCharles.Forsyth	return sys->sprint("scsi #%.2ux %.2ux", asc, ascq);
10537da2899SCharles.Forsyth}
10637da2899SCharles.Forsyth
10737da2899SCharles.Forsyth_scsicmd(s: ref Scsi, cmd: array of byte, data: array of byte, io: int, dolock: int): int
10837da2899SCharles.Forsyth{
10937da2899SCharles.Forsyth	if(dolock)
11037da2899SCharles.Forsyth		qlock(s);
11137da2899SCharles.Forsyth	dcount := len data;
11237da2899SCharles.Forsyth	if(sys->write(s.rawfd, cmd, len cmd) != len cmd) {
11337da2899SCharles.Forsyth		sys->werrstr("cmd write: %r");
11437da2899SCharles.Forsyth		if(dolock)
11537da2899SCharles.Forsyth			qunlock(s);
11637da2899SCharles.Forsyth		return -1;
11737da2899SCharles.Forsyth	}
11837da2899SCharles.Forsyth
11937da2899SCharles.Forsyth	n: int;
12037da2899SCharles.Forsyth	resp := array[16] of byte;
12137da2899SCharles.Forsyth	case io {
12237da2899SCharles.Forsyth	Sread =>
12337da2899SCharles.Forsyth		n = sys->read(s.rawfd, data, dcount);
12437da2899SCharles.Forsyth		if(n < 0 && scsiverbose)
12537da2899SCharles.Forsyth			sys->fprint(sys->fildes(2), "dat read: %r: cmd %#2.2uX\n", int cmd[0]);
12637da2899SCharles.Forsyth	Swrite =>
12737da2899SCharles.Forsyth		n = sys->write(s.rawfd, data, dcount);
12837da2899SCharles.Forsyth		if(n != dcount && scsiverbose)
12937da2899SCharles.Forsyth			sys->fprint(sys->fildes(2), "dat write: %r: cmd %#2.2uX\n", int cmd[0]);
13037da2899SCharles.Forsyth	Snone or * =>
13137da2899SCharles.Forsyth		n = sys->write(s.rawfd, resp, 0);
13237da2899SCharles.Forsyth		if(n != 0 && scsiverbose)
13337da2899SCharles.Forsyth			sys->fprint(sys->fildes(2), "none write: %r: cmd %#2.2uX\n", int cmd[0]);
13437da2899SCharles.Forsyth	}
13537da2899SCharles.Forsyth
13637da2899SCharles.Forsyth	m := sys->read(s.rawfd, resp, len resp);
13737da2899SCharles.Forsyth	if(dolock)
13837da2899SCharles.Forsyth		qunlock(s);
13937da2899SCharles.Forsyth	if(m < 0){
14037da2899SCharles.Forsyth		sys->werrstr("resp read: %r\n");
14137da2899SCharles.Forsyth		return -1;
14237da2899SCharles.Forsyth	}
14337da2899SCharles.Forsyth	status := int string resp[0:m];
14437da2899SCharles.Forsyth	if(status == 0)
14537da2899SCharles.Forsyth		return n;
14637da2899SCharles.Forsyth
14737da2899SCharles.Forsyth	sys->werrstr(sys->sprint("cmd %2.2uX: status %uX dcount %d n %d", int cmd[0], status, dcount, n));
14837da2899SCharles.Forsyth	return -1;
14937da2899SCharles.Forsyth}
15037da2899SCharles.Forsyth
15137da2899SCharles.ForsythScsi.rawcmd(s: self ref Scsi, cmd: array of byte, data: array of byte, io: int): int
15237da2899SCharles.Forsyth{
15337da2899SCharles.Forsyth	return _scsicmd(s, cmd, data, io, 1);
15437da2899SCharles.Forsyth}
15537da2899SCharles.Forsyth
15637da2899SCharles.Forsyth_scsiready(s: ref Scsi, dolock: int): int
15737da2899SCharles.Forsyth{
15837da2899SCharles.Forsyth	if(dolock)
15937da2899SCharles.Forsyth		qlock(s);
16037da2899SCharles.Forsyth	for(i:=0; i<3; i++) {
16137da2899SCharles.Forsyth		cmd := array[6] of {0 => byte 16r00, * => byte 0};	# test unit ready
16237da2899SCharles.Forsyth		if(sys->write(s.rawfd, cmd, len cmd) != len cmd) {
16337da2899SCharles.Forsyth			if(scsiverbose)
16437da2899SCharles.Forsyth				sys->fprint(sys->fildes(2), "ur cmd write: %r\n");
16537da2899SCharles.Forsyth			continue;
16637da2899SCharles.Forsyth		}
16737da2899SCharles.Forsyth		resp := array[16] of byte;
16837da2899SCharles.Forsyth		sys->write(s.rawfd, resp, 0);
16937da2899SCharles.Forsyth		m := sys->read(s.rawfd, resp, len resp);
17037da2899SCharles.Forsyth		if(m < 0){
17137da2899SCharles.Forsyth			if(scsiverbose)
17237da2899SCharles.Forsyth				sys->fprint(sys->fildes(2), "ur resp read: %r\n");
17337da2899SCharles.Forsyth			continue;	# retry
17437da2899SCharles.Forsyth		}
17537da2899SCharles.Forsyth		status := int string resp[0:m];
17637da2899SCharles.Forsyth		if(status == 0 || status == 16r02) {
17737da2899SCharles.Forsyth			if(dolock)
17837da2899SCharles.Forsyth				qunlock(s);
17937da2899SCharles.Forsyth			return 0;
18037da2899SCharles.Forsyth		}
18137da2899SCharles.Forsyth		if(scsiverbose)
18237da2899SCharles.Forsyth			sys->fprint(sys->fildes(2), "target: bad status: %x\n", status);
18337da2899SCharles.Forsyth	}
18437da2899SCharles.Forsyth	if(dolock)
18537da2899SCharles.Forsyth		qunlock(s);
18637da2899SCharles.Forsyth	return -1;
18737da2899SCharles.Forsyth}
18837da2899SCharles.Forsyth
18937da2899SCharles.ForsythScsi.ready(s: self ref Scsi): int
19037da2899SCharles.Forsyth{
19137da2899SCharles.Forsyth	return _scsiready(s, 1);
19237da2899SCharles.Forsyth}
19337da2899SCharles.Forsyth
19437da2899SCharles.ForsythScsi.cmd(s: self ref Scsi, cmd: array of byte, data: array of byte, io: int): int
19537da2899SCharles.Forsyth{
19637da2899SCharles.Forsyth	dcount := len data;
19737da2899SCharles.Forsyth	code := 0;
19837da2899SCharles.Forsyth	key := 0;
19937da2899SCharles.Forsyth	qlock(s);
20037da2899SCharles.Forsyth	sense: array of byte;
20137da2899SCharles.Forsyth	for(tries:=0; tries<2; tries++) {
20237da2899SCharles.Forsyth		n := _scsicmd(s, cmd, data, io, 0);
20337da2899SCharles.Forsyth		if(n >= 0) {
20437da2899SCharles.Forsyth			qunlock(s);
20537da2899SCharles.Forsyth			return n;
20637da2899SCharles.Forsyth		}
20737da2899SCharles.Forsyth
20837da2899SCharles.Forsyth		#
20937da2899SCharles.Forsyth		# request sense
21037da2899SCharles.Forsyth		#
21137da2899SCharles.Forsyth		sense = array[255] of {* => byte 16rFF};	# TO DO: usb mass storage devices might inist on less
21237da2899SCharles.Forsyth		req := array[6] of {0 => byte 16r03, 4 => byte len sense, * => byte 0};
21337da2899SCharles.Forsyth		if((n=_scsicmd(s, req, sense, Sread, 0)) < 14)
21437da2899SCharles.Forsyth			if(scsiverbose)
21537da2899SCharles.Forsyth				sys->fprint(sys->fildes(2), "reqsense scsicmd %d: %r\n", n);
21637da2899SCharles.Forsyth
21737da2899SCharles.Forsyth		if(_scsiready(s, 0) < 0)
21837da2899SCharles.Forsyth			if(scsiverbose)
21937da2899SCharles.Forsyth				sys->fprint(sys->fildes(2), "unit not ready\n");
22037da2899SCharles.Forsyth
22137da2899SCharles.Forsyth		key = int sense[2];
22237da2899SCharles.Forsyth		code = int sense[12];
22337da2899SCharles.Forsyth		if(code == 16r17 || code == 16r18) {	# recovered errors
22437da2899SCharles.Forsyth			qunlock(s);
22537da2899SCharles.Forsyth			return dcount;
22637da2899SCharles.Forsyth		}
22737da2899SCharles.Forsyth		if(code == 16r28 && int cmd[0] == 16r43) {	# get info and media changed
22837da2899SCharles.Forsyth			s.nchange++;
22937da2899SCharles.Forsyth			s.changetime = daytime->now();
23037da2899SCharles.Forsyth			continue;
23137da2899SCharles.Forsyth		}
23237da2899SCharles.Forsyth	}
23337da2899SCharles.Forsyth
23437da2899SCharles.Forsyth	# drive not ready, or medium not present
23537da2899SCharles.Forsyth	if(cmd[0] == byte 16r43 && key == 2 && (code == 16r3a || code == 16r04)) {
23637da2899SCharles.Forsyth		s.changetime = 0;
23737da2899SCharles.Forsyth		qunlock(s);
23837da2899SCharles.Forsyth		return -1;
23937da2899SCharles.Forsyth	}
24037da2899SCharles.Forsyth	qunlock(s);
24137da2899SCharles.Forsyth
24237da2899SCharles.Forsyth	if(cmd[0] == byte 16r43 && key == 5 && code == 16r24)	# blank media
24337da2899SCharles.Forsyth		return -1;
24437da2899SCharles.Forsyth
24537da2899SCharles.Forsyth	p := scsierror(code, int sense[13]);
24637da2899SCharles.Forsyth
24737da2899SCharles.Forsyth	sys->werrstr(sys->sprint("cmd #%.2ux: %s", int cmd[0], p));
24837da2899SCharles.Forsyth
24937da2899SCharles.Forsyth	if(scsiverbose)
25037da2899SCharles.Forsyth		sys->fprint(sys->fildes(2), "scsi cmd #%.2ux: %.2ux %.2ux %.2ux: %s\n", int cmd[0], key, code, int sense[13], p);
25137da2899SCharles.Forsyth
25237da2899SCharles.Forsyth#	if(key == 0)
25337da2899SCharles.Forsyth#		return dcount;
25437da2899SCharles.Forsyth	return -1;
25537da2899SCharles.Forsyth}
25637da2899SCharles.Forsyth
25737da2899SCharles.ForsythScsi.open(dev: string): ref Scsi
25837da2899SCharles.Forsyth{
25937da2899SCharles.Forsyth	rawfd := sys->open(dev+"/raw", Sys->ORDWR);
26037da2899SCharles.Forsyth	if(rawfd == nil)
26137da2899SCharles.Forsyth		return nil;
26237da2899SCharles.Forsyth	ctlfd := sys->open(dev+"/ctl", Sys->ORDWR);
26337da2899SCharles.Forsyth	if(ctlfd == nil)
26437da2899SCharles.Forsyth		return nil;
26537da2899SCharles.Forsyth
26637da2899SCharles.Forsyth	buf := array[512] of byte;
267*a6011949SCharles.Forsyth	n := sys->readn(ctlfd, buf, len buf);
26837da2899SCharles.Forsyth	if(n < 8){
26937da2899SCharles.Forsyth		if(n >= 0)
27037da2899SCharles.Forsyth			sys->werrstr("error reading ctl file");
27137da2899SCharles.Forsyth		return nil;
27237da2899SCharles.Forsyth	}
27337da2899SCharles.Forsyth	ctlfd = nil;
27437da2899SCharles.Forsyth
27537da2899SCharles.Forsyth	for(i := 0; i < n; i++)
27637da2899SCharles.Forsyth		if(buf[i] == byte '\n')
27737da2899SCharles.Forsyth			break;
27837da2899SCharles.Forsyth	inq := string buf[0:i];
27937da2899SCharles.Forsyth	if(i >= n || inq[0:8] != "inquiry "){
28037da2899SCharles.Forsyth		sys->werrstr("invalid inquiry string");
28137da2899SCharles.Forsyth		return nil;
28237da2899SCharles.Forsyth	}
28337da2899SCharles.Forsyth	s := ref Scsi;
28437da2899SCharles.Forsyth	s.lock = chan[1] of int;
28537da2899SCharles.Forsyth	s.rawfd = rawfd;
28637da2899SCharles.Forsyth	s.inquire = inq[8:];
28737da2899SCharles.Forsyth	s.changetime = daytime->now();
28837da2899SCharles.Forsyth
28937da2899SCharles.Forsyth	if(s.ready() < 0)
29037da2899SCharles.Forsyth		return nil;
29137da2899SCharles.Forsyth
29237da2899SCharles.Forsyth	return s;
29337da2899SCharles.Forsyth}
29437da2899SCharles.Forsyth
29537da2899SCharles.Forsythqlock(s: ref Scsi)
29637da2899SCharles.Forsyth{
29737da2899SCharles.Forsyth	s.lock <-= 1;
29837da2899SCharles.Forsyth}
29937da2899SCharles.Forsyth
30037da2899SCharles.Forsythqunlock(s: ref Scsi)
30137da2899SCharles.Forsyth{
30237da2899SCharles.Forsyth	<-s.lock;
30337da2899SCharles.Forsyth}
304