Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 1
#include "u.h"
2
#include "../port/lib.h"
3
#include "mem.h"
4
#include "dat.h"
5
#include "fns.h"
6
#include "io.h"
7
#include "ureg.h"
8
#include "../port/error.h"
9
 
10
#include "../port/sd.h"
11
 
12
static int
13
scsitest(SDreq* r)
14
{
15
	r->write = 0;
16
	memset(r->cmd, 0, sizeof(r->cmd));
17
	r->cmd[1] = r->lun<<5;
18
	r->clen = 6;
19
	r->data = nil;
20
	r->dlen = 0;
21
	r->flags = 0;
22
 
23
	r->status = ~0;
24
 
25
	return r->unit->dev->ifc->rio(r);
26
}
27
 
28
int
29
scsiverify(SDunit* unit)
30
{
31
	SDreq *r;
32
	int i, status;
33
	uchar *inquiry;
34
 
35
	if((r = malloc(sizeof(SDreq))) == nil)
36
		return 0;
37
	if((inquiry = sdmalloc(sizeof(unit->inquiry))) == nil){
38
		free(r);
39
		return 0;
40
	}
41
	r->unit = unit;
42
	r->lun = 0;		/* ??? */
43
 
44
	memset(unit->inquiry, 0, sizeof(unit->inquiry));
45
	r->write = 0;
46
	r->cmd[0] = 0x12;
47
	r->cmd[1] = r->lun<<5;
48
	r->cmd[4] = sizeof(unit->inquiry)-1;
49
	r->clen = 6;
50
	r->data = inquiry;
51
	r->dlen = sizeof(unit->inquiry)-1;
52
	r->flags = 0;
53
 
54
	r->status = ~0;
55
	if(unit->dev->ifc->rio(r) != SDok){
56
		free(r);
57
		return 0;
58
	}
59
	memmove(unit->inquiry, inquiry, r->dlen);
60
	free(inquiry);
61
 
62
	SET(status);
63
	for(i = 0; i < 3; i++){
64
		while((status = scsitest(r)) == SDbusy)
65
			;
66
		if(status == SDok || status != SDcheck)
67
			break;
68
		if(!(r->flags & SDvalidsense))
69
			break;
70
		if((r->sense[2] & 0x0F) != 0x02)
71
			continue;
72
 
73
		/*
74
		 * Unit is 'not ready'.
75
		 * If it is in the process of becoming ready or needs
76
		 * an initialising command, set status so it will be spun-up
77
		 * below.
78
		 * If there's no medium, that's OK too, but don't
79
		 * try to spin it up.
80
		 */
81
		if(r->sense[12] == 0x04){
82
			if(r->sense[13] == 0x02 || r->sense[13] == 0x01){
83
				status = SDok;
84
				break;
85
			}
86
		}
87
		if(r->sense[12] == 0x3A)
88
			break;
89
	}
90
 
91
	if(status == SDok){
92
		/*
93
		 * Try to ensure a direct-access device is spinning.
94
		 * Don't wait for completion, ignore the result.
95
		 */
96
		if((unit->inquiry[0] & SDinq0periphtype) == SDperdisk){
97
			memset(r->cmd, 0, sizeof(r->cmd));
98
			r->write = 0;
99
			r->cmd[0] = 0x1B;
100
			r->cmd[1] = (r->lun<<5)|0x01;
101
			r->cmd[4] = 1;
102
			r->clen = 6;
103
			r->data = nil;
104
			r->dlen = 0;
105
			r->flags = 0;
106
 
107
			r->status = ~0;
108
			unit->dev->ifc->rio(r);
109
		}
110
	}
111
	free(r);
112
 
113
	if(status == SDok || status == SDcheck)
114
		return 1;
115
	return 0;
116
}
117
 
118
static int
119
scsirio(SDreq* r)
120
{
121
	/*
122
	 * Perform an I/O request, returning
123
	 *	-1	failure
124
	 *	 0	ok
125
	 *	 1	no medium present
126
	 *	 2	retry
127
	 * The contents of r may be altered so the
128
	 * caller should re-initialise if necesary.
129
	 */
130
	r->status = ~0;
131
	switch(r->unit->dev->ifc->rio(r)){
132
	default:
133
		break;
134
	case SDcheck:
135
		if(!(r->flags & SDvalidsense))
136
			break;
137
		switch(r->sense[2] & 0x0F){
138
		case 0x00:		/* no sense */
139
		case 0x01:		/* recovered error */
140
			return 2;
141
		case 0x06:		/* check condition */
142
			/*
143
			 * 0x28 - not ready to ready transition,
144
			 *	  medium may have changed.
145
			 * 0x29 - power on or some type of reset.
146
			 */
147
			if(r->sense[12] == 0x28 && r->sense[13] == 0)
148
				return 2;
149
			if(r->sense[12] == 0x29)
150
				return 2;
151
			break;
152
		case 0x02:		/* not ready */
153
			/*
154
			 * If no medium present, bail out.
155
			 * If unit is becoming ready, rather than not
156
			 * not ready, wait a little then poke it again. 				 */
157
			if(r->sense[12] == 0x3A)
158
				break;
159
			if(r->sense[12] != 0x04 || r->sense[13] != 0x01)
160
				break;
161
 
162
			while(waserror())
163
				;
164
			tsleep(&up->sleep, return0, 0, 500);
165
			poperror();
166
			scsitest(r);
167
			return 2;
168
		default:
169
			break;
170
		}
171
		break;
172
	case SDok:
173
		return 0;
174
	}
175
	return -1;
176
}
177
 
178
int
179
scsionline(SDunit* unit)
180
{
181
	SDreq *r;
182
	uchar *p;
183
	int ok, retries;
184
 
185
	if((r = malloc(sizeof(SDreq))) == nil)
186
		return 0;
187
	if((p = sdmalloc(8)) == nil){
188
		free(r);
189
		return 0;
190
	}
191
 
192
	ok = 0;
193
 
194
	r->unit = unit;
195
	r->lun = 0;				/* ??? */
196
	for(retries = 0; retries < 10; retries++){
197
		/*
198
		 * Read-capacity is mandatory for DA, WORM, CD-ROM and
199
		 * MO. It may return 'not ready' if type DA is not
200
		 * spun up, type MO or type CD-ROM are not loaded or just
201
		 * plain slow getting their act together after a reset.
202
		 */
203
		r->write = 0;
204
		memset(r->cmd, 0, sizeof(r->cmd));
205
		r->cmd[0] = 0x25;
206
		r->cmd[1] = r->lun<<5;
207
		r->clen = 10;
208
		r->data = p;
209
		r->dlen = 8;
210
		r->flags = 0;
211
 
212
		r->status = ~0;
213
		switch(scsirio(r)){
214
		default:
215
			break;
216
		case 0:
217
			unit->sectors = (p[0]<<24)|(p[1]<<16)|(p[2]<<8)|p[3];
218
			unit->secsize = (p[4]<<24)|(p[5]<<16)|(p[6]<<8)|p[7];
219
 
220
			/*
221
			 * Some ATAPI CD readers lie about the block size.
222
			 * Since we don't read audio via this interface
223
			 * it's okay to always fudge this.
224
			 */
225
			if(unit->secsize == 2352)
226
				unit->secsize = 2048;
227
			/*
228
			 * Devices with removable media may return 0 sectors
229
			 * when they have empty media (e.g. sata dvd writers);
230
			 * if so, keep the count zero.
231
			 *
232
			 * Read-capacity returns the LBA of the last sector,
233
			 * therefore the number of sectors must be incremented.
234
			 */
235
			if(unit->sectors != 0)
236
				unit->sectors++;
237
			ok = 1;
238
			break;
239
		case 1:
240
			ok = 1;
241
			break;
242
		case 2:
243
			continue;
244
		}
245
		break;
246
	}
247
	free(p);
248
	free(r);
249
 
250
	if(ok)
251
		return ok+retries;
252
	else
253
		return 0;
254
}
255
 
256
int
257
scsiexec(SDunit* unit, int write, uchar* cmd, int clen, void* data, int* dlen)
258
{
259
	SDreq *r;
260
	int status;
261
 
262
	if((r = malloc(sizeof(SDreq))) == nil)
263
		return SDmalloc;
264
	r->unit = unit;
265
	r->lun = cmd[1]>>5;		/* ??? */
266
	r->write = write;
267
	memmove(r->cmd, cmd, clen);
268
	r->clen = clen;
269
	r->data = data;
270
	if(dlen)
271
		r->dlen = *dlen;
272
	r->flags = 0;
273
 
274
	r->status = ~0;
275
 
276
	/*
277
	 * Call the device-specific I/O routine.
278
	 * There should be no calls to 'error()' below this
279
	 * which percolate back up.
280
	 */
281
	switch(status = unit->dev->ifc->rio(r)){
282
	case SDok:
283
		if(dlen)
284
			*dlen = r->rlen;
285
		/*FALLTHROUGH*/
286
	case SDcheck:
287
		/*FALLTHROUGH*/
288
	default:
289
		/*
290
		 * It's more complicated than this. There are conditions
291
		 * which are 'ok' but for which the returned status code
292
		 * is not 'SDok'.
293
		 * Also, not all conditions require a reqsense, might
294
		 * need to do a reqsense here and make it available to the
295
		 * caller somehow.
296
		 *
297
		 * MaƱana.
298
		 */
299
		break;
300
	}
301
	sdfree(r);
302
 
303
	return status;
304
}
305
 
306
static void
307
scsifmt10(SDreq *r, int write, int lun, ulong nb, uvlong bno)
308
{
309
	uchar *c;
310
 
311
	c = r->cmd;
312
	if(write == 0)
313
		c[0] = 0x28;
314
	else
315
		c[0] = 0x2A;
316
	c[1] = lun<<5;
317
	c[2] = bno>>24;
318
	c[3] = bno>>16;
319
	c[4] = bno>>8;
320
	c[5] = bno;
321
	c[6] = 0;
322
	c[7] = nb>>8;
323
	c[8] = nb;
324
	c[9] = 0;
325
 
326
	r->clen = 10;
327
}
328
 
329
static void
330
scsifmt16(SDreq *r, int write, int lun, ulong nb, uvlong bno)
331
{
332
	uchar *c;
333
 
334
	c = r->cmd;
335
	if(write == 0)
336
		c[0] = 0x88;
337
	else
338
		c[0] = 0x8A;
339
	c[1] = lun<<5;		/* so wrong */
340
	c[2] = bno>>56;
341
	c[3] = bno>>48;
342
	c[4] = bno>>40;
343
	c[5] = bno>>32;
344
	c[6] = bno>>24;
345
	c[7] = bno>>16;
346
	c[8] = bno>>8;
347
	c[9] = bno;
348
	c[10] = nb>>24;
349
	c[11] = nb>>16;
350
	c[12] = nb>>8;
351
	c[13] = nb;
352
	c[14] = 0;
353
	c[15] = 0;
354
 
355
	r->clen = 16;
356
}
357
 
358
long
359
scsibio(SDunit* unit, int lun, int write, void* data, long nb, uvlong bno)
360
{
361
	SDreq *r;
362
	long rlen;
363
 
364
	if((r = malloc(sizeof(SDreq))) == nil)
365
		error(Enomem);
366
	r->unit = unit;
367
	r->lun = lun;
368
again:
369
	r->write = write;
370
	if(bno >= (1ULL<<32))
371
		scsifmt16(r, write, lun, nb, bno);
372
	else
373
		scsifmt10(r, write, lun, nb, bno);
374
	r->data = data;
375
	r->dlen = nb*unit->secsize;
376
	r->flags = 0;
377
 
378
	r->status = ~0;
379
	switch(scsirio(r)){
380
	default:
381
		rlen = -1;
382
		break;
383
	case 0:
384
		rlen = r->rlen;
385
		break;
386
	case 2:
387
		rlen = -1;
388
		if(!(r->flags & SDvalidsense))
389
			break;
390
		switch(r->sense[2] & 0x0F){
391
		default:
392
			break;
393
		case 0x01:		/* recovered error */
394
			print("%s: recovered error at sector %llud\n",
395
				unit->name, bno);
396
			rlen = r->rlen;
397
			break;
398
		case 0x06:		/* check condition */
399
			/*
400
			 * Check for a removeable media change.
401
			 * If so, mark it by zapping the geometry info
402
			 * to force an online request.
403
			 */
404
			if(r->sense[12] != 0x28 || r->sense[13] != 0)
405
				break;
406
			if(unit->inquiry[1] & SDinq1removable)
407
				unit->sectors = 0;
408
			break;
409
		case 0x02:		/* not ready */
410
			/*
411
			 * If unit is becoming ready,
412
			 * rather than not not ready, try again.
413
			 */
414
			if(r->sense[12] == 0x04 && r->sense[13] == 0x01)
415
				goto again;
416
			break;
417
		}
418
		break;
419
	}
420
	free(r);
421
 
422
	return rlen;
423
}
424