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