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