xref: /plan9/sys/src/libdisk/scsi.c (revision 2752240283b2037f93a98c5bab11217cae887208)
180ee5cbfSDavid du Colombier /*
280ee5cbfSDavid du Colombier  * Now thread-safe.
380ee5cbfSDavid du Colombier  *
480ee5cbfSDavid du Colombier  * The codeqlock guarantees that once codes != nil, that pointer will never
580ee5cbfSDavid du Colombier  * change nor become invalid.
680ee5cbfSDavid du Colombier  *
780ee5cbfSDavid du Colombier  * The QLock in the Scsi structure moderates access to the raw device.
880ee5cbfSDavid du Colombier  * We should probably export some of the already-locked routines, but
980ee5cbfSDavid du Colombier  * there hasn't been a need.
1080ee5cbfSDavid du Colombier  */
1180ee5cbfSDavid du Colombier 
127dd7cddfSDavid du Colombier #include <u.h>
137dd7cddfSDavid du Colombier #include <libc.h>
147dd7cddfSDavid du Colombier #include <disk.h>
157dd7cddfSDavid du Colombier 
1614cc0f53SDavid du Colombier enum {
178673b4daSDavid du Colombier 	/* commands */
188673b4daSDavid du Colombier 	Testrdy		= 0x00,
198673b4daSDavid du Colombier 	Reqsense	= 0x03,
208673b4daSDavid du Colombier 	Write10		= 0x2a,
21*27522402SDavid du Colombier 	Writever10	= 0x2e,
2214cc0f53SDavid du Colombier 	Readtoc		= 0x43,
238673b4daSDavid du Colombier 
248673b4daSDavid du Colombier 	/* sense[2] (key) sense codes */
258673b4daSDavid du Colombier 	Sensenone	= 0,
268673b4daSDavid du Colombier 	Sensenotrdy	= 2,
278673b4daSDavid du Colombier 	Sensebadreq	= 5,
288673b4daSDavid du Colombier 
298673b4daSDavid du Colombier 	/* sense[12] (asc) sense codes */
308673b4daSDavid du Colombier 	Lunnotrdy	= 0x04,
318673b4daSDavid du Colombier 	Recovnoecc	= 0x17,
328673b4daSDavid du Colombier 	Recovecc	= 0x18,
338673b4daSDavid du Colombier 	Badcdb		= 0x24,
348673b4daSDavid du Colombier 	Newmedium	= 0x28,
358673b4daSDavid du Colombier 	Nomedium	= 0x3a,
3614cc0f53SDavid du Colombier };
3714cc0f53SDavid du Colombier 
387dd7cddfSDavid du Colombier int scsiverbose;
397dd7cddfSDavid du Colombier 
407dd7cddfSDavid du Colombier #define codefile "/sys/lib/scsicodes"
417dd7cddfSDavid du Colombier 
427dd7cddfSDavid du Colombier static char *codes;
4380ee5cbfSDavid du Colombier static QLock codeqlock;
4480ee5cbfSDavid du Colombier 
457dd7cddfSDavid du Colombier static void
getcodes(void)467dd7cddfSDavid du Colombier getcodes(void)
477dd7cddfSDavid du Colombier {
489a747e4fSDavid du Colombier 	Dir *d;
497dd7cddfSDavid du Colombier 	int n, fd;
507dd7cddfSDavid du Colombier 
517dd7cddfSDavid du Colombier 	if(codes != nil)
527dd7cddfSDavid du Colombier 		return;
537dd7cddfSDavid du Colombier 
5480ee5cbfSDavid du Colombier 	qlock(&codeqlock);
5580ee5cbfSDavid du Colombier 	if(codes != nil) {
5680ee5cbfSDavid du Colombier 		qunlock(&codeqlock);
577dd7cddfSDavid du Colombier 		return;
5880ee5cbfSDavid du Colombier 	}
5980ee5cbfSDavid du Colombier 
609a747e4fSDavid du Colombier 	if((d = dirstat(codefile)) == nil || (fd = open(codefile, OREAD)) < 0) {
6180ee5cbfSDavid du Colombier 		qunlock(&codeqlock);
6280ee5cbfSDavid du Colombier 		return;
6380ee5cbfSDavid du Colombier 	}
647dd7cddfSDavid du Colombier 
659a747e4fSDavid du Colombier 	codes = malloc(1+d->length+1);
6659cc4ca5SDavid du Colombier 	if(codes == nil) {
6759cc4ca5SDavid du Colombier 		close(fd);
6880ee5cbfSDavid du Colombier 		qunlock(&codeqlock);
699a747e4fSDavid du Colombier 		free(d);
7059cc4ca5SDavid du Colombier 		return;
7159cc4ca5SDavid du Colombier 	}
7259cc4ca5SDavid du Colombier 
737dd7cddfSDavid du Colombier 	codes[0] = '\n';	/* for searches */
749a747e4fSDavid du Colombier 	n = readn(fd, codes+1, d->length);
757dd7cddfSDavid du Colombier 	close(fd);
769a747e4fSDavid du Colombier 	free(d);
777dd7cddfSDavid du Colombier 
787dd7cddfSDavid du Colombier 	if(n < 0) {
797dd7cddfSDavid du Colombier 		free(codes);
807dd7cddfSDavid du Colombier 		codes = nil;
8180ee5cbfSDavid du Colombier 		qunlock(&codeqlock);
827dd7cddfSDavid du Colombier 		return;
837dd7cddfSDavid du Colombier 	}
847dd7cddfSDavid du Colombier 	codes[n] = '\0';
8580ee5cbfSDavid du Colombier 	qunlock(&codeqlock);
867dd7cddfSDavid du Colombier }
877dd7cddfSDavid du Colombier 
887dd7cddfSDavid du Colombier char*
scsierror(int asc,int ascq)897dd7cddfSDavid du Colombier scsierror(int asc, int ascq)
907dd7cddfSDavid du Colombier {
917dd7cddfSDavid du Colombier 	char *p, *q;
927dd7cddfSDavid du Colombier 	static char search[32];
937dd7cddfSDavid du Colombier 	static char buf[128];
947dd7cddfSDavid du Colombier 
957dd7cddfSDavid du Colombier 	getcodes();
967dd7cddfSDavid du Colombier 
977dd7cddfSDavid du Colombier 	if(codes) {
988673b4daSDavid du Colombier 		snprint(search, sizeof search, "\n%.2ux%.2ux ", asc, ascq);
997dd7cddfSDavid du Colombier 		if(p = strstr(codes, search)) {
1007dd7cddfSDavid du Colombier 			p += 6;
1017dd7cddfSDavid du Colombier 			if((q = strchr(p, '\n')) == nil)
1027dd7cddfSDavid du Colombier 				q = p+strlen(p);
1037dd7cddfSDavid du Colombier 			snprint(buf, sizeof buf, "%.*s", (int)(q-p), p);
1047dd7cddfSDavid du Colombier 			return buf;
1057dd7cddfSDavid du Colombier 		}
1067dd7cddfSDavid du Colombier 
1078673b4daSDavid du Colombier 		snprint(search, sizeof search, "\n%.2ux00", asc);
1087dd7cddfSDavid du Colombier 		if(p = strstr(codes, search)) {
1097dd7cddfSDavid du Colombier 			p += 6;
1107dd7cddfSDavid du Colombier 			if((q = strchr(p, '\n')) == nil)
1117dd7cddfSDavid du Colombier 				q = p+strlen(p);
1127dd7cddfSDavid du Colombier 			snprint(buf, sizeof buf, "(ascq #%.2ux) %.*s", ascq, (int)(q-p), p);
1137dd7cddfSDavid du Colombier 			return buf;
1147dd7cddfSDavid du Colombier 		}
1157dd7cddfSDavid du Colombier 	}
1167dd7cddfSDavid du Colombier 
1178673b4daSDavid du Colombier 	snprint(buf, sizeof buf, "scsi #%.2ux %.2ux", asc, ascq);
1187dd7cddfSDavid du Colombier 	return buf;
1197dd7cddfSDavid du Colombier }
1207dd7cddfSDavid du Colombier 
1217dd7cddfSDavid du Colombier 
12280ee5cbfSDavid du Colombier static int
_scsicmd(Scsi * s,uchar * cmd,int ccount,void * data,int dcount,int io,int dolock)12380ee5cbfSDavid du Colombier _scsicmd(Scsi *s, uchar *cmd, int ccount, void *data, int dcount, int io, int dolock)
1247dd7cddfSDavid du Colombier {
1257dd7cddfSDavid du Colombier 	uchar resp[16];
1267dd7cddfSDavid du Colombier 	int n;
1277dd7cddfSDavid du Colombier 	long status;
1287dd7cddfSDavid du Colombier 
12980ee5cbfSDavid du Colombier 	if(dolock)
13080ee5cbfSDavid du Colombier 		qlock(s);
1317dd7cddfSDavid du Colombier 	if(write(s->rawfd, cmd, ccount) != ccount) {
1327dd7cddfSDavid du Colombier 		werrstr("cmd write: %r");
13380ee5cbfSDavid du Colombier 		if(dolock)
13480ee5cbfSDavid du Colombier 			qunlock(s);
1357dd7cddfSDavid du Colombier 		return -1;
1367dd7cddfSDavid du Colombier 	}
1377dd7cddfSDavid du Colombier 
1387dd7cddfSDavid du Colombier 	switch(io){
1397dd7cddfSDavid du Colombier 	case Sread:
1407dd7cddfSDavid du Colombier 		n = read(s->rawfd, data, dcount);
14114cc0f53SDavid du Colombier 		/* read toc errors are frequent and not very interesting */
14214cc0f53SDavid du Colombier 		if(n < 0 && (scsiverbose == 1 ||
14314cc0f53SDavid du Colombier 		    scsiverbose == 2 && cmd[0] != Readtoc))
1447dd7cddfSDavid du Colombier 			fprint(2, "dat read: %r: cmd 0x%2.2uX\n", cmd[0]);
1457dd7cddfSDavid du Colombier 		break;
1467dd7cddfSDavid du Colombier 	case Swrite:
1477dd7cddfSDavid du Colombier 		n = write(s->rawfd, data, dcount);
1487dd7cddfSDavid du Colombier 		if(n != dcount && scsiverbose)
1497dd7cddfSDavid du Colombier 			fprint(2, "dat write: %r: cmd 0x%2.2uX\n", cmd[0]);
1507dd7cddfSDavid du Colombier 		break;
1517dd7cddfSDavid du Colombier 	default:
1527dd7cddfSDavid du Colombier 	case Snone:
1537dd7cddfSDavid du Colombier 		n = write(s->rawfd, resp, 0);
1547dd7cddfSDavid du Colombier 		if(n != 0 && scsiverbose)
1557dd7cddfSDavid du Colombier 			fprint(2, "none write: %r: cmd 0x%2.2uX\n", cmd[0]);
1567dd7cddfSDavid du Colombier 		break;
1577dd7cddfSDavid du Colombier 	}
1587dd7cddfSDavid du Colombier 
1597dd7cddfSDavid du Colombier 	memset(resp, 0, sizeof(resp));
1607dd7cddfSDavid du Colombier 	if(read(s->rawfd, resp, sizeof(resp)) < 0) {
1617dd7cddfSDavid du Colombier 		werrstr("resp read: %r\n");
16280ee5cbfSDavid du Colombier 		if(dolock)
16380ee5cbfSDavid du Colombier 			qunlock(s);
1647dd7cddfSDavid du Colombier 		return -1;
1657dd7cddfSDavid du Colombier 	}
16680ee5cbfSDavid du Colombier 	if(dolock)
16780ee5cbfSDavid du Colombier 		qunlock(s);
1687dd7cddfSDavid du Colombier 
1697dd7cddfSDavid du Colombier 	resp[sizeof(resp)-1] = '\0';
1707dd7cddfSDavid du Colombier 	status = atoi((char*)resp);
1717dd7cddfSDavid du Colombier 	if(status == 0)
1727dd7cddfSDavid du Colombier 		return n;
1737dd7cddfSDavid du Colombier 
1747dd7cddfSDavid du Colombier 	werrstr("cmd %2.2uX: status %luX dcount %d n %d", cmd[0], status, dcount, n);
1757dd7cddfSDavid du Colombier 	return -1;
1767dd7cddfSDavid du Colombier }
1777dd7cddfSDavid du Colombier 
1787dd7cddfSDavid du Colombier int
scsicmd(Scsi * s,uchar * cmd,int ccount,void * data,int dcount,int io)17980ee5cbfSDavid du Colombier scsicmd(Scsi *s, uchar *cmd, int ccount, void *data, int dcount, int io)
18080ee5cbfSDavid du Colombier {
18180ee5cbfSDavid du Colombier 	return _scsicmd(s, cmd, ccount, data, dcount, io, 1);
18280ee5cbfSDavid du Colombier }
18380ee5cbfSDavid du Colombier 
18480ee5cbfSDavid du Colombier static int
_scsiready(Scsi * s,int dolock)18580ee5cbfSDavid du Colombier _scsiready(Scsi *s, int dolock)
1867dd7cddfSDavid du Colombier {
187194f7e8cSDavid du Colombier 	char err[ERRMAX];
1887dd7cddfSDavid du Colombier 	uchar cmd[6], resp[16];
1897dd7cddfSDavid du Colombier 	int status, i;
1907dd7cddfSDavid du Colombier 
19180ee5cbfSDavid du Colombier 	if(dolock)
19280ee5cbfSDavid du Colombier 		qlock(s);
193194f7e8cSDavid du Colombier 	werrstr("");
1947dd7cddfSDavid du Colombier 	for(i=0; i<3; i++) {
1957dd7cddfSDavid du Colombier 		memset(cmd, 0, sizeof(cmd));
1968673b4daSDavid du Colombier 		cmd[0] = Testrdy;	/* unit ready */
1977dd7cddfSDavid du Colombier 		if(write(s->rawfd, cmd, sizeof(cmd)) != sizeof(cmd)) {
1987dd7cddfSDavid du Colombier 			if(scsiverbose)
1997dd7cddfSDavid du Colombier 				fprint(2, "ur cmd write: %r\n");
200194f7e8cSDavid du Colombier 			werrstr("short unit-ready raw write");
2018673b4daSDavid du Colombier 			continue;
2027dd7cddfSDavid du Colombier 		}
2037dd7cddfSDavid du Colombier 		write(s->rawfd, resp, 0);
2047dd7cddfSDavid du Colombier 		if(read(s->rawfd, resp, sizeof(resp)) < 0) {
2057dd7cddfSDavid du Colombier 			if(scsiverbose)
2067dd7cddfSDavid du Colombier 				fprint(2, "ur resp read: %r\n");
2078673b4daSDavid du Colombier 			continue;
2087dd7cddfSDavid du Colombier 		}
2097dd7cddfSDavid du Colombier 		resp[sizeof(resp)-1] = '\0';
2107dd7cddfSDavid du Colombier 		status = atoi((char*)resp);
21180ee5cbfSDavid du Colombier 		if(status == 0 || status == 0x02) {
21280ee5cbfSDavid du Colombier 			if(dolock)
21380ee5cbfSDavid du Colombier 				qunlock(s);
2147dd7cddfSDavid du Colombier 			return 0;
21580ee5cbfSDavid du Colombier 		}
2167dd7cddfSDavid du Colombier 		if(scsiverbose)
2177dd7cddfSDavid du Colombier 			fprint(2, "target: bad status: %x\n", status);
2187dd7cddfSDavid du Colombier 	}
219194f7e8cSDavid du Colombier 	rerrstr(err, sizeof err);
220194f7e8cSDavid du Colombier 	if(err[0] == '\0')
221194f7e8cSDavid du Colombier 		werrstr("unit did not become ready");
22280ee5cbfSDavid du Colombier 	if(dolock)
22380ee5cbfSDavid du Colombier 		qunlock(s);
2247dd7cddfSDavid du Colombier 	return -1;
2257dd7cddfSDavid du Colombier }
2267dd7cddfSDavid du Colombier 
2277dd7cddfSDavid du Colombier int
scsiready(Scsi * s)22880ee5cbfSDavid du Colombier scsiready(Scsi *s)
22980ee5cbfSDavid du Colombier {
23080ee5cbfSDavid du Colombier 	return _scsiready(s, 1);
23180ee5cbfSDavid du Colombier }
23280ee5cbfSDavid du Colombier 
23380ee5cbfSDavid du Colombier int
scsi(Scsi * s,uchar * cmd,int ccount,void * v,int dcount,int io)2347dd7cddfSDavid du Colombier scsi(Scsi *s, uchar *cmd, int ccount, void *v, int dcount, int io)
2357dd7cddfSDavid du Colombier {
2367dd7cddfSDavid du Colombier 	uchar req[6], sense[255], *data;
2377dd7cddfSDavid du Colombier 	int tries, code, key, n;
2387dd7cddfSDavid du Colombier 	char *p;
2397dd7cddfSDavid du Colombier 
2407dd7cddfSDavid du Colombier 	data = v;
2417dd7cddfSDavid du Colombier 	SET(key, code);
24280ee5cbfSDavid du Colombier 	qlock(s);
2437dd7cddfSDavid du Colombier 	for(tries=0; tries<2; tries++) {
24480ee5cbfSDavid du Colombier 		n = _scsicmd(s, cmd, ccount, data, dcount, io, 0);
24580ee5cbfSDavid du Colombier 		if(n >= 0) {
24680ee5cbfSDavid du Colombier 			qunlock(s);
2477dd7cddfSDavid du Colombier 			return n;
24880ee5cbfSDavid du Colombier 		}
2497dd7cddfSDavid du Colombier 
2507dd7cddfSDavid du Colombier 		/*
2517dd7cddfSDavid du Colombier 		 * request sense
2527dd7cddfSDavid du Colombier 		 */
2537dd7cddfSDavid du Colombier 		memset(req, 0, sizeof(req));
2548673b4daSDavid du Colombier 		req[0] = Reqsense;
2557dd7cddfSDavid du Colombier 		req[4] = sizeof(sense);
2567dd7cddfSDavid du Colombier 		memset(sense, 0xFF, sizeof(sense));
25780ee5cbfSDavid du Colombier 		if((n=_scsicmd(s, req, sizeof(req), sense, sizeof(sense), Sread, 0)) < 14)
2587dd7cddfSDavid du Colombier 			if(scsiverbose)
2597dd7cddfSDavid du Colombier 				fprint(2, "reqsense scsicmd %d: %r\n", n);
2607dd7cddfSDavid du Colombier 
26180ee5cbfSDavid du Colombier 		if(_scsiready(s, 0) < 0)
2627dd7cddfSDavid du Colombier 			if(scsiverbose)
2637dd7cddfSDavid du Colombier 				fprint(2, "unit not ready\n");
2647dd7cddfSDavid du Colombier 
2658673b4daSDavid du Colombier 		key = sense[2] & 0xf;
2668673b4daSDavid du Colombier 		code = sense[12];			/* asc */
2678673b4daSDavid du Colombier 		if(code == Recovnoecc || code == Recovecc) { /* recovered errors */
26880ee5cbfSDavid du Colombier 			qunlock(s);
2697dd7cddfSDavid du Colombier 			return dcount;
27080ee5cbfSDavid du Colombier 		}
2718673b4daSDavid du Colombier 
2728673b4daSDavid du Colombier 		/* retry various odd cases */
2738673b4daSDavid du Colombier 		if(code == Newmedium && cmd[0] == Readtoc) {
27414cc0f53SDavid du Colombier 			/* read toc and media changed */
2757dd7cddfSDavid du Colombier 			s->nchange++;
2767dd7cddfSDavid du Colombier 			s->changetime = time(0);
277*27522402SDavid du Colombier 		} else if((cmd[0] == Write10 || cmd[0] == Writever10) &&
278*27522402SDavid du Colombier 		    key == Sensenotrdy &&
2798673b4daSDavid du Colombier 		    code == Lunnotrdy && sense[13] == 0x08) {
2808673b4daSDavid du Colombier 			/* long write in progress, per mmc-6 */
2818673b4daSDavid du Colombier 			tries = 0;
2828673b4daSDavid du Colombier 			sleep(1);
2837dd7cddfSDavid du Colombier 		}
2847dd7cddfSDavid du Colombier 	}
2857dd7cddfSDavid du Colombier 
2867dd7cddfSDavid du Colombier 	/* drive not ready, or medium not present */
2878673b4daSDavid du Colombier 	if(cmd[0] == Readtoc && key == Sensenotrdy &&
2888673b4daSDavid du Colombier 	    (code == Nomedium || code == Lunnotrdy)) {
2897dd7cddfSDavid du Colombier 		s->changetime = 0;
29080ee5cbfSDavid du Colombier 		qunlock(s);
2917dd7cddfSDavid du Colombier 		return -1;
2927dd7cddfSDavid du Colombier 	}
29380ee5cbfSDavid du Colombier 	qunlock(s);
2947dd7cddfSDavid du Colombier 
2958673b4daSDavid du Colombier 	if(cmd[0] == Readtoc && key == Sensebadreq && code == Badcdb)
2968673b4daSDavid du Colombier 		return -1;			/* blank media */
2977dd7cddfSDavid du Colombier 
2987dd7cddfSDavid du Colombier 	p = scsierror(code, sense[13]);
2997dd7cddfSDavid du Colombier 
3007dd7cddfSDavid du Colombier 	werrstr("cmd #%.2ux: %s", cmd[0], p);
3017dd7cddfSDavid du Colombier 
3027dd7cddfSDavid du Colombier 	if(scsiverbose)
30314cc0f53SDavid du Colombier 		fprint(2, "scsi cmd #%.2ux: %.2ux %.2ux %.2ux: %s\n",
30414cc0f53SDavid du Colombier 			cmd[0], key, code, sense[13], p);
3057dd7cddfSDavid du Colombier 
3068673b4daSDavid du Colombier //	if(key == Sensenone)
3077dd7cddfSDavid du Colombier //		return dcount;
3087dd7cddfSDavid du Colombier 	return -1;
3097dd7cddfSDavid du Colombier }
3107dd7cddfSDavid du Colombier 
3117dd7cddfSDavid du Colombier Scsi*
openscsi(char * dev)3127dd7cddfSDavid du Colombier openscsi(char *dev)
3137dd7cddfSDavid du Colombier {
3147dd7cddfSDavid du Colombier 	Scsi *s;
3157dd7cddfSDavid du Colombier 	int rawfd, ctlfd, l, n;
3167dd7cddfSDavid du Colombier 	char *name, *p, buf[512];
3177dd7cddfSDavid du Colombier 
3187dd7cddfSDavid du Colombier 	l = strlen(dev)+1+3+1;
31959cc4ca5SDavid du Colombier 	name = malloc(l);
32059cc4ca5SDavid du Colombier 	if(name == nil)
32159cc4ca5SDavid du Colombier 		return nil;
3227dd7cddfSDavid du Colombier 
3237dd7cddfSDavid du Colombier 	snprint(name, l, "%s/raw", dev);
32459cc4ca5SDavid du Colombier 	if((rawfd = open(name, ORDWR)) < 0) {
32559cc4ca5SDavid du Colombier 		free(name);
3267dd7cddfSDavid du Colombier 		return nil;
32759cc4ca5SDavid du Colombier 	}
3287dd7cddfSDavid du Colombier 
3297dd7cddfSDavid du Colombier 	snprint(name, l, "%s/ctl", dev);
3307dd7cddfSDavid du Colombier 	if((ctlfd = open(name, ORDWR)) < 0) {
3317dd7cddfSDavid du Colombier 	Error:
332194f7e8cSDavid du Colombier 		free(name);
3337dd7cddfSDavid du Colombier 		close(rawfd);
3347dd7cddfSDavid du Colombier 		return nil;
3357dd7cddfSDavid du Colombier 	}
3367dd7cddfSDavid du Colombier 
3377dd7cddfSDavid du Colombier 	n = readn(ctlfd, buf, sizeof buf);
3387dd7cddfSDavid du Colombier 	close(ctlfd);
339194f7e8cSDavid du Colombier 	if(n <= 0) {
340194f7e8cSDavid du Colombier 		if(n == 0)
341194f7e8cSDavid du Colombier 			werrstr("eof on %s", name);
3427dd7cddfSDavid du Colombier 		goto Error;
343194f7e8cSDavid du Colombier 	}
3447dd7cddfSDavid du Colombier 
345194f7e8cSDavid du Colombier 	if(strncmp(buf, "inquiry ", 8) != 0 || (p = strchr(buf, '\n')) == nil) {
346194f7e8cSDavid du Colombier 		werrstr("inquiry mal-formatted in %s", name);
3477dd7cddfSDavid du Colombier 		goto Error;
348194f7e8cSDavid du Colombier 	}
3497dd7cddfSDavid du Colombier 	*p = '\0';
350194f7e8cSDavid du Colombier 	free(name);
351194f7e8cSDavid du Colombier 	name = nil;
3527dd7cddfSDavid du Colombier 
3537dd7cddfSDavid du Colombier 	if((p = strdup(buf+8)) == nil)
3547dd7cddfSDavid du Colombier 		goto Error;
3557dd7cddfSDavid du Colombier 
356766ccd67SDavid du Colombier 	s = mallocz(sizeof(*s), 1);
35759cc4ca5SDavid du Colombier 	if(s == nil) {
35859cc4ca5SDavid du Colombier 	Error1:
35959cc4ca5SDavid du Colombier 		free(p);
36059cc4ca5SDavid du Colombier 		goto Error;
36159cc4ca5SDavid du Colombier 	}
36259cc4ca5SDavid du Colombier 
3637dd7cddfSDavid du Colombier 	s->rawfd = rawfd;
3647dd7cddfSDavid du Colombier 	s->inquire = p;
3657dd7cddfSDavid du Colombier 	s->changetime = time(0);
3667dd7cddfSDavid du Colombier 
36759cc4ca5SDavid du Colombier 	if(scsiready(s) < 0)
36859cc4ca5SDavid du Colombier 		goto Error1;
3697dd7cddfSDavid du Colombier 
3707dd7cddfSDavid du Colombier 	return s;
3717dd7cddfSDavid du Colombier }
372af6a38e6SDavid du Colombier 
373af6a38e6SDavid du Colombier void
closescsi(Scsi * s)374af6a38e6SDavid du Colombier closescsi(Scsi *s)
375af6a38e6SDavid du Colombier {
376af6a38e6SDavid du Colombier 	close(s->rawfd);
377af6a38e6SDavid du Colombier 	free(s->inquire);
378af6a38e6SDavid du Colombier 	free(s);
379af6a38e6SDavid du Colombier }
380