Warning: Attempt to read property "date" on null in /usr/local/www/websvn.planix.org/blame.php on line 247

Warning: Attempt to read property "msg" on null in /usr/local/www/websvn.planix.org/blame.php on line 247
WebSVN – planix.SVN – Blame – /os/branches/feature_tlsv12/sys/src/libdisk/scsi.c – Rev 2

Subversion Repositories planix.SVN

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

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