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