xref: /plan9/sys/src/cmd/cdfs/scsi.c (revision 39b91b2bea1bdc6d8e213fc7f7a2911875f95d28)
1*39b91b2bSDavid du Colombier /*
2*39b91b2bSDavid du Colombier  * Now thread-safe.
3*39b91b2bSDavid du Colombier  *
4*39b91b2bSDavid du Colombier  * The codeqlock guarantees that once codes != nil, that pointer will never
5*39b91b2bSDavid du Colombier  * change nor become invalid.
6*39b91b2bSDavid du Colombier  *
7*39b91b2bSDavid du Colombier  * The QLock in the Scsi structure moderates access to the raw device.
8*39b91b2bSDavid du Colombier  * We should probably export some of the already-locked routines, but
9*39b91b2bSDavid du Colombier  * there hasn't been a need.
10*39b91b2bSDavid du Colombier  */
11*39b91b2bSDavid du Colombier 
12*39b91b2bSDavid du Colombier #include <u.h>
13*39b91b2bSDavid du Colombier #include <libc.h>
14*39b91b2bSDavid du Colombier #include <disk.h>
15*39b91b2bSDavid du Colombier 
16*39b91b2bSDavid du Colombier enum {
17*39b91b2bSDavid du Colombier 	/* commands */
18*39b91b2bSDavid du Colombier 	Testrdy		= 0x00,
19*39b91b2bSDavid du Colombier 	Reqsense	= 0x03,
20*39b91b2bSDavid du Colombier 	Write10		= 0x2a,
21*39b91b2bSDavid du Colombier 	Writever10	= 0x2e,
22*39b91b2bSDavid du Colombier 	Readtoc		= 0x43,
23*39b91b2bSDavid du Colombier 
24*39b91b2bSDavid du Colombier 	/* sense[2] (key) sense codes */
25*39b91b2bSDavid du Colombier 	Sensenone	= 0,
26*39b91b2bSDavid du Colombier 	Sensenotrdy	= 2,
27*39b91b2bSDavid du Colombier 	Sensebadreq	= 5,
28*39b91b2bSDavid du Colombier 
29*39b91b2bSDavid du Colombier 	/* sense[12] (asc) sense codes */
30*39b91b2bSDavid du Colombier 	Lunnotrdy	= 0x04,
31*39b91b2bSDavid du Colombier 	Recovnoecc	= 0x17,
32*39b91b2bSDavid du Colombier 	Recovecc	= 0x18,
33*39b91b2bSDavid du Colombier 	Badcdb		= 0x24,
34*39b91b2bSDavid du Colombier 	Newmedium	= 0x28,
35*39b91b2bSDavid du Colombier 	Nomedium	= 0x3a,
36*39b91b2bSDavid du Colombier };
37*39b91b2bSDavid du Colombier 
38*39b91b2bSDavid du Colombier int scsiverbose;
39*39b91b2bSDavid du Colombier 
40*39b91b2bSDavid du Colombier #define codefile "/sys/lib/scsicodes"
41*39b91b2bSDavid du Colombier 
42*39b91b2bSDavid du Colombier static char *codes;
43*39b91b2bSDavid du Colombier static QLock codeqlock;
44*39b91b2bSDavid du Colombier 
45*39b91b2bSDavid du Colombier static void
getcodes(void)46*39b91b2bSDavid du Colombier getcodes(void)
47*39b91b2bSDavid du Colombier {
48*39b91b2bSDavid du Colombier 	Dir *d;
49*39b91b2bSDavid du Colombier 	int n, fd;
50*39b91b2bSDavid du Colombier 
51*39b91b2bSDavid du Colombier 	if(codes != nil)
52*39b91b2bSDavid du Colombier 		return;
53*39b91b2bSDavid du Colombier 
54*39b91b2bSDavid du Colombier 	qlock(&codeqlock);
55*39b91b2bSDavid du Colombier 	if(codes != nil) {
56*39b91b2bSDavid du Colombier 		qunlock(&codeqlock);
57*39b91b2bSDavid du Colombier 		return;
58*39b91b2bSDavid du Colombier 	}
59*39b91b2bSDavid du Colombier 
60*39b91b2bSDavid du Colombier 	if((d = dirstat(codefile)) == nil || (fd = open(codefile, OREAD)) < 0) {
61*39b91b2bSDavid du Colombier 		qunlock(&codeqlock);
62*39b91b2bSDavid du Colombier 		return;
63*39b91b2bSDavid du Colombier 	}
64*39b91b2bSDavid du Colombier 
65*39b91b2bSDavid du Colombier 	codes = malloc(1+d->length+1);
66*39b91b2bSDavid du Colombier 	if(codes == nil) {
67*39b91b2bSDavid du Colombier 		close(fd);
68*39b91b2bSDavid du Colombier 		qunlock(&codeqlock);
69*39b91b2bSDavid du Colombier 		free(d);
70*39b91b2bSDavid du Colombier 		return;
71*39b91b2bSDavid du Colombier 	}
72*39b91b2bSDavid du Colombier 
73*39b91b2bSDavid du Colombier 	codes[0] = '\n';	/* for searches */
74*39b91b2bSDavid du Colombier 	n = readn(fd, codes+1, d->length);
75*39b91b2bSDavid du Colombier 	close(fd);
76*39b91b2bSDavid du Colombier 	free(d);
77*39b91b2bSDavid du Colombier 
78*39b91b2bSDavid du Colombier 	if(n < 0) {
79*39b91b2bSDavid du Colombier 		free(codes);
80*39b91b2bSDavid du Colombier 		codes = nil;
81*39b91b2bSDavid du Colombier 		qunlock(&codeqlock);
82*39b91b2bSDavid du Colombier 		return;
83*39b91b2bSDavid du Colombier 	}
84*39b91b2bSDavid du Colombier 	codes[n] = '\0';
85*39b91b2bSDavid du Colombier 	qunlock(&codeqlock);
86*39b91b2bSDavid du Colombier }
87*39b91b2bSDavid du Colombier 
88*39b91b2bSDavid du Colombier char*
scsierror(int asc,int ascq)89*39b91b2bSDavid du Colombier scsierror(int asc, int ascq)
90*39b91b2bSDavid du Colombier {
91*39b91b2bSDavid du Colombier 	char *p, *q;
92*39b91b2bSDavid du Colombier 	static char search[32];
93*39b91b2bSDavid du Colombier 	static char buf[128];
94*39b91b2bSDavid du Colombier 
95*39b91b2bSDavid du Colombier 	getcodes();
96*39b91b2bSDavid du Colombier 
97*39b91b2bSDavid du Colombier 	if(codes) {
98*39b91b2bSDavid du Colombier 		snprint(search, sizeof search, "\n%.2ux%.2ux ", asc, ascq);
99*39b91b2bSDavid du Colombier 		if(p = strstr(codes, search)) {
100*39b91b2bSDavid du Colombier 			p += 6;
101*39b91b2bSDavid du Colombier 			if((q = strchr(p, '\n')) == nil)
102*39b91b2bSDavid du Colombier 				q = p+strlen(p);
103*39b91b2bSDavid du Colombier 			snprint(buf, sizeof buf, "%.*s", (int)(q-p), p);
104*39b91b2bSDavid du Colombier 			return buf;
105*39b91b2bSDavid du Colombier 		}
106*39b91b2bSDavid du Colombier 
107*39b91b2bSDavid du Colombier 		snprint(search, sizeof search, "\n%.2ux00", asc);
108*39b91b2bSDavid du Colombier 		if(p = strstr(codes, search)) {
109*39b91b2bSDavid du Colombier 			p += 6;
110*39b91b2bSDavid du Colombier 			if((q = strchr(p, '\n')) == nil)
111*39b91b2bSDavid du Colombier 				q = p+strlen(p);
112*39b91b2bSDavid du Colombier 			snprint(buf, sizeof buf, "(ascq #%.2ux) %.*s", ascq, (int)(q-p), p);
113*39b91b2bSDavid du Colombier 			return buf;
114*39b91b2bSDavid du Colombier 		}
115*39b91b2bSDavid du Colombier 	}
116*39b91b2bSDavid du Colombier 
117*39b91b2bSDavid du Colombier 	snprint(buf, sizeof buf, "scsi #%.2ux %.2ux", asc, ascq);
118*39b91b2bSDavid du Colombier 	return buf;
119*39b91b2bSDavid du Colombier }
120*39b91b2bSDavid du Colombier 
121*39b91b2bSDavid du Colombier 
122*39b91b2bSDavid du Colombier static int
_scsicmd(Scsi * s,uchar * cmd,int ccount,void * data,int dcount,int io,int dolock)123*39b91b2bSDavid du Colombier _scsicmd(Scsi *s, uchar *cmd, int ccount, void *data, int dcount, int io, int dolock)
124*39b91b2bSDavid du Colombier {
125*39b91b2bSDavid du Colombier 	uchar resp[16];
126*39b91b2bSDavid du Colombier 	int n;
127*39b91b2bSDavid du Colombier 	long status;
128*39b91b2bSDavid du Colombier 
129*39b91b2bSDavid du Colombier 	if(dolock)
130*39b91b2bSDavid du Colombier 		qlock(s);
131*39b91b2bSDavid du Colombier 	if(write(s->rawfd, cmd, ccount) != ccount) {
132*39b91b2bSDavid du Colombier 		werrstr("cmd write: %r");
133*39b91b2bSDavid du Colombier 		if(dolock)
134*39b91b2bSDavid du Colombier 			qunlock(s);
135*39b91b2bSDavid du Colombier 		return -1;
136*39b91b2bSDavid du Colombier 	}
137*39b91b2bSDavid du Colombier 
138*39b91b2bSDavid du Colombier 	switch(io){
139*39b91b2bSDavid du Colombier 	case Sread:
140*39b91b2bSDavid du Colombier 		n = read(s->rawfd, data, dcount);
141*39b91b2bSDavid du Colombier 		/* read toc errors are frequent and not very interesting */
142*39b91b2bSDavid du Colombier 		if(n < 0 && (scsiverbose == 1 ||
143*39b91b2bSDavid du Colombier 		    scsiverbose == 2 && cmd[0] != Readtoc))
144*39b91b2bSDavid du Colombier 			fprint(2, "dat read: %r: cmd 0x%2.2uX\n", cmd[0]);
145*39b91b2bSDavid du Colombier 		break;
146*39b91b2bSDavid du Colombier 	case Swrite:
147*39b91b2bSDavid du Colombier 		n = write(s->rawfd, data, dcount);
148*39b91b2bSDavid du Colombier 		if(n != dcount && scsiverbose)
149*39b91b2bSDavid du Colombier 			fprint(2, "dat write: %r: cmd 0x%2.2uX\n", cmd[0]);
150*39b91b2bSDavid du Colombier 		break;
151*39b91b2bSDavid du Colombier 	default:
152*39b91b2bSDavid du Colombier 	case Snone:
153*39b91b2bSDavid du Colombier 		n = write(s->rawfd, resp, 0);
154*39b91b2bSDavid du Colombier 		if(n != 0 && scsiverbose)
155*39b91b2bSDavid du Colombier 			fprint(2, "none write: %r: cmd 0x%2.2uX\n", cmd[0]);
156*39b91b2bSDavid du Colombier 		break;
157*39b91b2bSDavid du Colombier 	}
158*39b91b2bSDavid du Colombier 
159*39b91b2bSDavid du Colombier 	memset(resp, 0, sizeof(resp));
160*39b91b2bSDavid du Colombier 	if(read(s->rawfd, resp, sizeof(resp)) < 0) {
161*39b91b2bSDavid du Colombier 		werrstr("resp read: %r\n");
162*39b91b2bSDavid du Colombier 		if(dolock)
163*39b91b2bSDavid du Colombier 			qunlock(s);
164*39b91b2bSDavid du Colombier 		return -1;
165*39b91b2bSDavid du Colombier 	}
166*39b91b2bSDavid du Colombier 	if(dolock)
167*39b91b2bSDavid du Colombier 		qunlock(s);
168*39b91b2bSDavid du Colombier 
169*39b91b2bSDavid du Colombier 	resp[sizeof(resp)-1] = '\0';
170*39b91b2bSDavid du Colombier 	status = atoi((char*)resp);
171*39b91b2bSDavid du Colombier 	if(status == 0)
172*39b91b2bSDavid du Colombier 		return n;
173*39b91b2bSDavid du Colombier 
174*39b91b2bSDavid du Colombier 	werrstr("cmd %2.2uX: status %luX dcount %d n %d", cmd[0], status, dcount, n);
175*39b91b2bSDavid du Colombier 	return -1;
176*39b91b2bSDavid du Colombier }
177*39b91b2bSDavid du Colombier 
178*39b91b2bSDavid du Colombier int
scsicmd(Scsi * s,uchar * cmd,int ccount,void * data,int dcount,int io)179*39b91b2bSDavid du Colombier scsicmd(Scsi *s, uchar *cmd, int ccount, void *data, int dcount, int io)
180*39b91b2bSDavid du Colombier {
181*39b91b2bSDavid du Colombier 	return _scsicmd(s, cmd, ccount, data, dcount, io, 1);
182*39b91b2bSDavid du Colombier }
183*39b91b2bSDavid du Colombier 
184*39b91b2bSDavid du Colombier static int
_scsiready(Scsi * s,int dolock)185*39b91b2bSDavid du Colombier _scsiready(Scsi *s, int dolock)
186*39b91b2bSDavid du Colombier {
187*39b91b2bSDavid du Colombier 	char err[ERRMAX];
188*39b91b2bSDavid du Colombier 	uchar cmd[6], resp[16];
189*39b91b2bSDavid du Colombier 	int status, i;
190*39b91b2bSDavid du Colombier 
191*39b91b2bSDavid du Colombier 	if(dolock)
192*39b91b2bSDavid du Colombier 		qlock(s);
193*39b91b2bSDavid du Colombier 	werrstr("");
194*39b91b2bSDavid du Colombier 	for(i=0; i<3; i++) {
195*39b91b2bSDavid du Colombier 		memset(cmd, 0, sizeof(cmd));
196*39b91b2bSDavid du Colombier 		cmd[0] = Testrdy;	/* unit ready */
197*39b91b2bSDavid du Colombier 		if(write(s->rawfd, cmd, sizeof(cmd)) != sizeof(cmd)) {
198*39b91b2bSDavid du Colombier 			if(scsiverbose)
199*39b91b2bSDavid du Colombier 				fprint(2, "ur cmd write: %r\n");
200*39b91b2bSDavid du Colombier 			werrstr("short unit-ready raw write");
201*39b91b2bSDavid du Colombier 			continue;
202*39b91b2bSDavid du Colombier 		}
203*39b91b2bSDavid du Colombier 		write(s->rawfd, resp, 0);
204*39b91b2bSDavid du Colombier 		if(read(s->rawfd, resp, sizeof(resp)) < 0) {
205*39b91b2bSDavid du Colombier 			if(scsiverbose)
206*39b91b2bSDavid du Colombier 				fprint(2, "ur resp read: %r\n");
207*39b91b2bSDavid du Colombier 			continue;
208*39b91b2bSDavid du Colombier 		}
209*39b91b2bSDavid du Colombier 		resp[sizeof(resp)-1] = '\0';
210*39b91b2bSDavid du Colombier 		status = atoi((char*)resp);
211*39b91b2bSDavid du Colombier 		if(status == 0 || status == 0x02) {
212*39b91b2bSDavid du Colombier 			if(dolock)
213*39b91b2bSDavid du Colombier 				qunlock(s);
214*39b91b2bSDavid du Colombier 			return 0;
215*39b91b2bSDavid du Colombier 		}
216*39b91b2bSDavid du Colombier 		if(scsiverbose)
217*39b91b2bSDavid du Colombier 			fprint(2, "target: bad status: %x\n", status);
218*39b91b2bSDavid du Colombier 	}
219*39b91b2bSDavid du Colombier 	rerrstr(err, sizeof err);
220*39b91b2bSDavid du Colombier 	if(err[0] == '\0')
221*39b91b2bSDavid du Colombier 		werrstr("unit did not become ready");
222*39b91b2bSDavid du Colombier 	if(dolock)
223*39b91b2bSDavid du Colombier 		qunlock(s);
224*39b91b2bSDavid du Colombier 	return -1;
225*39b91b2bSDavid du Colombier }
226*39b91b2bSDavid du Colombier 
227*39b91b2bSDavid du Colombier int
scsiready(Scsi * s)228*39b91b2bSDavid du Colombier scsiready(Scsi *s)
229*39b91b2bSDavid du Colombier {
230*39b91b2bSDavid du Colombier 	return _scsiready(s, 1);
231*39b91b2bSDavid du Colombier }
232*39b91b2bSDavid du Colombier 
233*39b91b2bSDavid du Colombier int
scsi(Scsi * s,uchar * cmd,int ccount,void * v,int dcount,int io)234*39b91b2bSDavid du Colombier scsi(Scsi *s, uchar *cmd, int ccount, void *v, int dcount, int io)
235*39b91b2bSDavid du Colombier {
236*39b91b2bSDavid du Colombier 	uchar req[6], sense[255], *data;
237*39b91b2bSDavid du Colombier 	int tries, code, key, n;
238*39b91b2bSDavid du Colombier 	char *p;
239*39b91b2bSDavid du Colombier 
240*39b91b2bSDavid du Colombier 	data = v;
241*39b91b2bSDavid du Colombier 	SET(key, code);
242*39b91b2bSDavid du Colombier 	qlock(s);
243*39b91b2bSDavid du Colombier 	for(tries=0; tries<2; tries++) {
244*39b91b2bSDavid du Colombier 		n = _scsicmd(s, cmd, ccount, data, dcount, io, 0);
245*39b91b2bSDavid du Colombier 		if(n >= 0) {
246*39b91b2bSDavid du Colombier 			qunlock(s);
247*39b91b2bSDavid du Colombier 			return n;
248*39b91b2bSDavid du Colombier 		}
249*39b91b2bSDavid du Colombier 
250*39b91b2bSDavid du Colombier 		/*
251*39b91b2bSDavid du Colombier 		 * request sense
252*39b91b2bSDavid du Colombier 		 */
253*39b91b2bSDavid du Colombier 		memset(req, 0, sizeof(req));
254*39b91b2bSDavid du Colombier 		req[0] = Reqsense;
255*39b91b2bSDavid du Colombier 		req[4] = sizeof(sense);
256*39b91b2bSDavid du Colombier 		memset(sense, 0xFF, sizeof(sense));
257*39b91b2bSDavid du Colombier 		if((n=_scsicmd(s, req, sizeof(req), sense, sizeof(sense), Sread, 0)) < 14)
258*39b91b2bSDavid du Colombier 			if(scsiverbose)
259*39b91b2bSDavid du Colombier 				fprint(2, "reqsense scsicmd %d: %r\n", n);
260*39b91b2bSDavid du Colombier 
261*39b91b2bSDavid du Colombier 		if(_scsiready(s, 0) < 0)
262*39b91b2bSDavid du Colombier 			if(scsiverbose)
263*39b91b2bSDavid du Colombier 				fprint(2, "unit not ready\n");
264*39b91b2bSDavid du Colombier 
265*39b91b2bSDavid du Colombier 		key = sense[2] & 0xf;
266*39b91b2bSDavid du Colombier 		code = sense[12];			/* asc */
267*39b91b2bSDavid du Colombier 		if(code == Recovnoecc || code == Recovecc) { /* recovered errors */
268*39b91b2bSDavid du Colombier 			qunlock(s);
269*39b91b2bSDavid du Colombier 			return dcount;
270*39b91b2bSDavid du Colombier 		}
271*39b91b2bSDavid du Colombier 
272*39b91b2bSDavid du Colombier 		/* retry various odd cases */
273*39b91b2bSDavid du Colombier 		if(code == Newmedium && cmd[0] == Readtoc) {
274*39b91b2bSDavid du Colombier 			/* read toc and media changed */
275*39b91b2bSDavid du Colombier 			s->nchange++;
276*39b91b2bSDavid du Colombier 			s->changetime = time(0);
277*39b91b2bSDavid du Colombier 		} else if((cmd[0] == Write10 || cmd[0] == Writever10) &&
278*39b91b2bSDavid du Colombier 		    key == Sensenotrdy &&
279*39b91b2bSDavid du Colombier 		    code == Lunnotrdy && sense[13] == 0x08) {
280*39b91b2bSDavid du Colombier 			/* long write in progress, per mmc-6 */
281*39b91b2bSDavid du Colombier 			tries = 0;
282*39b91b2bSDavid du Colombier 			sleep(1);
283*39b91b2bSDavid du Colombier 		} else if(cmd[0] == Write10 || cmd[0] == Writever10)
284*39b91b2bSDavid du Colombier 			break;		/* don't retry worm writes */
285*39b91b2bSDavid du Colombier 	}
286*39b91b2bSDavid du Colombier 
287*39b91b2bSDavid du Colombier 	/* drive not ready, or medium not present */
288*39b91b2bSDavid du Colombier 	if(cmd[0] == Readtoc && key == Sensenotrdy &&
289*39b91b2bSDavid du Colombier 	    (code == Nomedium || code == Lunnotrdy)) {
290*39b91b2bSDavid du Colombier 		s->changetime = 0;
291*39b91b2bSDavid du Colombier 		qunlock(s);
292*39b91b2bSDavid du Colombier 		return -1;
293*39b91b2bSDavid du Colombier 	}
294*39b91b2bSDavid du Colombier 	qunlock(s);
295*39b91b2bSDavid du Colombier 
296*39b91b2bSDavid du Colombier 	if(cmd[0] == Readtoc && key == Sensebadreq && code == Badcdb)
297*39b91b2bSDavid du Colombier 		return -1;			/* blank media */
298*39b91b2bSDavid du Colombier 
299*39b91b2bSDavid du Colombier 	p = scsierror(code, sense[13]);
300*39b91b2bSDavid du Colombier 
301*39b91b2bSDavid du Colombier 	werrstr("cmd #%.2ux: %s", cmd[0], p);
302*39b91b2bSDavid du Colombier 
303*39b91b2bSDavid du Colombier 	if(scsiverbose)
304*39b91b2bSDavid du Colombier 		fprint(2, "scsi cmd #%.2ux: %.2ux %.2ux %.2ux: %s\n",
305*39b91b2bSDavid du Colombier 			cmd[0], key, code, sense[13], p);
306*39b91b2bSDavid du Colombier 
307*39b91b2bSDavid du Colombier //	if(key == Sensenone)
308*39b91b2bSDavid du Colombier //		return dcount;
309*39b91b2bSDavid du Colombier 	return -1;
310*39b91b2bSDavid du Colombier }
311*39b91b2bSDavid du Colombier 
312*39b91b2bSDavid du Colombier Scsi*
openscsi(char * dev)313*39b91b2bSDavid du Colombier openscsi(char *dev)
314*39b91b2bSDavid du Colombier {
315*39b91b2bSDavid du Colombier 	Scsi *s;
316*39b91b2bSDavid du Colombier 	int rawfd, ctlfd, l, n;
317*39b91b2bSDavid du Colombier 	char *name, *p, buf[512];
318*39b91b2bSDavid du Colombier 
319*39b91b2bSDavid du Colombier 	l = strlen(dev)+1+3+1;
320*39b91b2bSDavid du Colombier 	name = malloc(l);
321*39b91b2bSDavid du Colombier 	if(name == nil)
322*39b91b2bSDavid du Colombier 		return nil;
323*39b91b2bSDavid du Colombier 
324*39b91b2bSDavid du Colombier 	snprint(name, l, "%s/raw", dev);
325*39b91b2bSDavid du Colombier 	if((rawfd = open(name, ORDWR)) < 0) {
326*39b91b2bSDavid du Colombier 		free(name);
327*39b91b2bSDavid du Colombier 		return nil;
328*39b91b2bSDavid du Colombier 	}
329*39b91b2bSDavid du Colombier 
330*39b91b2bSDavid du Colombier 	snprint(name, l, "%s/ctl", dev);
331*39b91b2bSDavid du Colombier 	if((ctlfd = open(name, ORDWR)) < 0) {
332*39b91b2bSDavid du Colombier 	Error:
333*39b91b2bSDavid du Colombier 		free(name);
334*39b91b2bSDavid du Colombier 		close(rawfd);
335*39b91b2bSDavid du Colombier 		return nil;
336*39b91b2bSDavid du Colombier 	}
337*39b91b2bSDavid du Colombier 
338*39b91b2bSDavid du Colombier 	n = readn(ctlfd, buf, sizeof buf);
339*39b91b2bSDavid du Colombier 	close(ctlfd);
340*39b91b2bSDavid du Colombier 	if(n <= 0) {
341*39b91b2bSDavid du Colombier 		if(n == 0)
342*39b91b2bSDavid du Colombier 			werrstr("eof on %s", name);
343*39b91b2bSDavid du Colombier 		goto Error;
344*39b91b2bSDavid du Colombier 	}
345*39b91b2bSDavid du Colombier 
346*39b91b2bSDavid du Colombier 	if(strncmp(buf, "inquiry ", 8) != 0 || (p = strchr(buf, '\n')) == nil) {
347*39b91b2bSDavid du Colombier 		werrstr("inquiry mal-formatted in %s", name);
348*39b91b2bSDavid du Colombier 		goto Error;
349*39b91b2bSDavid du Colombier 	}
350*39b91b2bSDavid du Colombier 	*p = '\0';
351*39b91b2bSDavid du Colombier 	free(name);
352*39b91b2bSDavid du Colombier 	name = nil;
353*39b91b2bSDavid du Colombier 
354*39b91b2bSDavid du Colombier 	if((p = strdup(buf+8)) == nil)
355*39b91b2bSDavid du Colombier 		goto Error;
356*39b91b2bSDavid du Colombier 
357*39b91b2bSDavid du Colombier 	s = mallocz(sizeof(*s), 1);
358*39b91b2bSDavid du Colombier 	if(s == nil) {
359*39b91b2bSDavid du Colombier 	Error1:
360*39b91b2bSDavid du Colombier 		free(p);
361*39b91b2bSDavid du Colombier 		goto Error;
362*39b91b2bSDavid du Colombier 	}
363*39b91b2bSDavid du Colombier 
364*39b91b2bSDavid du Colombier 	s->rawfd = rawfd;
365*39b91b2bSDavid du Colombier 	s->inquire = p;
366*39b91b2bSDavid du Colombier 	s->changetime = time(0);
367*39b91b2bSDavid du Colombier 
368*39b91b2bSDavid du Colombier 	if(scsiready(s) < 0)
369*39b91b2bSDavid du Colombier 		goto Error1;
370*39b91b2bSDavid du Colombier 
371*39b91b2bSDavid du Colombier 	return s;
372*39b91b2bSDavid du Colombier }
373*39b91b2bSDavid du Colombier 
374*39b91b2bSDavid du Colombier void
closescsi(Scsi * s)375*39b91b2bSDavid du Colombier closescsi(Scsi *s)
376*39b91b2bSDavid du Colombier {
377*39b91b2bSDavid du Colombier 	close(s->rawfd);
378*39b91b2bSDavid du Colombier 	free(s->inquire);
379*39b91b2bSDavid du Colombier 	free(s);
380*39b91b2bSDavid du Colombier }
381