xref: /plan9/sys/src/cmd/usb/disk/scsireq.c (revision fd362a73ff89ae80075dd82c9aad2a3468f0f3c9)
1906943f9SDavid du Colombier /*
2906943f9SDavid du Colombier  * This is /sys/src/cmd/scuzz/scsireq.c
3906943f9SDavid du Colombier  * changed to add more debug support, to keep
4906943f9SDavid du Colombier  * disk compiling without a scuzz that includes these changes.
5906943f9SDavid du Colombier  * Also, this includes minor tweaks for usb:
6906943f9SDavid du Colombier  *	we set req.lun/unit to rp->lun/unit in SRreqsense
7906943f9SDavid du Colombier  *	we set the rp->sense[0] bit Sd0valid in SRreqsense
8906943f9SDavid du Colombier  * This does not use libdisk to retrieve the scsi error to make
97d7728c9SDavid du Colombier  * user see the diagnostics if we boot with debug enabled.
10906943f9SDavid du Colombier  *
11906943f9SDavid du Colombier  * BUGS:
12906943f9SDavid du Colombier  *	no luns
13906943f9SDavid du Colombier  *	and incomplete in many other ways
14906943f9SDavid du Colombier  */
157d7728c9SDavid du Colombier 
167d7728c9SDavid du Colombier #include <u.h>
177d7728c9SDavid du Colombier #include <libc.h>
183a827ddcSDavid du Colombier #include <fcall.h>
19*fd362a73SDavid du Colombier #include <disk.h>
20906943f9SDavid du Colombier #include "scsireq.h"
21906943f9SDavid du Colombier 
22906943f9SDavid du Colombier enum {
23906943f9SDavid du Colombier 	Debug = 0,
24906943f9SDavid du Colombier };
25906943f9SDavid du Colombier 
26906943f9SDavid du Colombier /*
27906943f9SDavid du Colombier  * exabyte tape drives, at least old ones like the 8200 and 8505,
28906943f9SDavid du Colombier  * are dumb: you have to read the exact block size on the tape,
29906943f9SDavid du Colombier  * they don't take 10-byte SCSI commands, and various other fine points.
30906943f9SDavid du Colombier  */
31906943f9SDavid du Colombier extern int exabyte, force6bytecmds;
32906943f9SDavid du Colombier 
33906943f9SDavid du Colombier static int debug = Debug;
34906943f9SDavid du Colombier 
35906943f9SDavid du Colombier static char *scmdnames[256] = {
36906943f9SDavid du Colombier [ScmdTur]	"Tur",
37906943f9SDavid du Colombier [ScmdRewind]	"Rewind",
38906943f9SDavid du Colombier [ScmdRsense]	"Rsense",
39906943f9SDavid du Colombier [ScmdFormat]	"Format",
40906943f9SDavid du Colombier [ScmdRblimits]	"Rblimits",
41906943f9SDavid du Colombier [ScmdRead]	"Read",
42906943f9SDavid du Colombier [ScmdWrite]	"Write",
43906943f9SDavid du Colombier [ScmdSeek]	"Seek",
44906943f9SDavid du Colombier [ScmdFmark]	"Fmark",
45906943f9SDavid du Colombier [ScmdSpace]	"Space",
46906943f9SDavid du Colombier [ScmdInq]	"Inq",
47906943f9SDavid du Colombier [ScmdMselect6]	"Mselect6",
48906943f9SDavid du Colombier [ScmdMselect10]	"Mselect10",
49906943f9SDavid du Colombier [ScmdMsense6]	"Msense6",
50906943f9SDavid du Colombier [ScmdMsense10]	"Msense10",
51906943f9SDavid du Colombier [ScmdStart]	"Start",
52906943f9SDavid du Colombier [ScmdRcapacity]	"Rcapacity",
53906943f9SDavid du Colombier [ScmdRcapacity16]	"Rcap16",
54906943f9SDavid du Colombier [ScmdExtread]	"Extread",
55906943f9SDavid du Colombier [ScmdExtwrite]	"Extwrite",
56906943f9SDavid du Colombier [ScmdExtseek]	"Extseek",
57906943f9SDavid du Colombier 
58906943f9SDavid du Colombier [ScmdSynccache]	"Synccache",
59906943f9SDavid du Colombier [ScmdRTOC]	"RTOC",
60906943f9SDavid du Colombier [ScmdRdiscinfo]	"Rdiscinfo",
61906943f9SDavid du Colombier [ScmdRtrackinfo]	"Rtrackinfo",
62906943f9SDavid du Colombier [ScmdReserve]	"Reserve",
63906943f9SDavid du Colombier [ScmdBlank]	"Blank",
64906943f9SDavid du Colombier 
65906943f9SDavid du Colombier [ScmdCDpause]	"CDpause",
66906943f9SDavid du Colombier [ScmdCDstop]	"CDstop",
67906943f9SDavid du Colombier [ScmdCDplay]	"CDplay",
68906943f9SDavid du Colombier [ScmdCDload]	"CDload",
69906943f9SDavid du Colombier [ScmdCDscan]	"CDscan",
70906943f9SDavid du Colombier [ScmdCDstatus]	"CDstatus",
71906943f9SDavid du Colombier [Scmdgetconf]	"getconf",
72906943f9SDavid du Colombier };
73906943f9SDavid du Colombier 
74906943f9SDavid du Colombier long
SRready(ScsiReq * rp)75906943f9SDavid du Colombier SRready(ScsiReq *rp)
76906943f9SDavid du Colombier {
77906943f9SDavid du Colombier 	uchar cmd[6];
78906943f9SDavid du Colombier 
79906943f9SDavid du Colombier 	memset(cmd, 0, sizeof cmd);
80906943f9SDavid du Colombier 	rp->cmd.p = cmd;
81906943f9SDavid du Colombier 	rp->cmd.count = sizeof cmd;
82906943f9SDavid du Colombier 	rp->data.p = cmd;
83906943f9SDavid du Colombier 	rp->data.count = 0;
84906943f9SDavid du Colombier 	rp->data.write = 1;
85906943f9SDavid du Colombier 	return SRrequest(rp);
86906943f9SDavid du Colombier }
87906943f9SDavid du Colombier 
88906943f9SDavid du Colombier long
SRrewind(ScsiReq * rp)89906943f9SDavid du Colombier SRrewind(ScsiReq *rp)
90906943f9SDavid du Colombier {
91906943f9SDavid du Colombier 	uchar cmd[6];
92906943f9SDavid du Colombier 
93906943f9SDavid du Colombier 	memset(cmd, 0, sizeof cmd);
94906943f9SDavid du Colombier 	cmd[0] = ScmdRewind;
95906943f9SDavid du Colombier 	rp->cmd.p = cmd;
96906943f9SDavid du Colombier 	rp->cmd.count = sizeof cmd;
97906943f9SDavid du Colombier 	rp->data.p = cmd;
98906943f9SDavid du Colombier 	rp->data.count = 0;
99906943f9SDavid du Colombier 	rp->data.write = 1;
100906943f9SDavid du Colombier 	if(SRrequest(rp) >= 0){
101906943f9SDavid du Colombier 		rp->offset = 0;
102906943f9SDavid du Colombier 		return 0;
103906943f9SDavid du Colombier 	}
104906943f9SDavid du Colombier 	return -1;
105906943f9SDavid du Colombier }
106906943f9SDavid du Colombier 
107906943f9SDavid du Colombier long
SRreqsense(ScsiReq * rp)108906943f9SDavid du Colombier SRreqsense(ScsiReq *rp)
109906943f9SDavid du Colombier {
110906943f9SDavid du Colombier 	uchar cmd[6];
111906943f9SDavid du Colombier 	ScsiReq req;
112906943f9SDavid du Colombier 	long status;
113906943f9SDavid du Colombier 
114906943f9SDavid du Colombier 	if(rp->status == Status_SD){
115906943f9SDavid du Colombier 		rp->status = STok;
116906943f9SDavid du Colombier 		return 0;
117906943f9SDavid du Colombier 	}
118906943f9SDavid du Colombier 	memset(cmd, 0, sizeof cmd);
119906943f9SDavid du Colombier 	cmd[0] = ScmdRsense;
120906943f9SDavid du Colombier 	cmd[4] = sizeof(req.sense);
121906943f9SDavid du Colombier 	memset(&req, 0, sizeof(req));
122906943f9SDavid du Colombier 	if(rp->flags&Fusb)
123906943f9SDavid du Colombier 		req.flags |= Fusb;
124906943f9SDavid du Colombier 	req.lun = rp->lun;
125906943f9SDavid du Colombier 	req.unit = rp->unit;
126906943f9SDavid du Colombier 	req.fd = rp->fd;
127906943f9SDavid du Colombier 	req.umsc = rp->umsc;
128906943f9SDavid du Colombier 	req.cmd.p = cmd;
129906943f9SDavid du Colombier 	req.cmd.count = sizeof cmd;
130906943f9SDavid du Colombier 	req.data.p = rp->sense;
131906943f9SDavid du Colombier 	req.data.count = sizeof(rp->sense);
132906943f9SDavid du Colombier 	req.data.write = 0;
133906943f9SDavid du Colombier 	status = SRrequest(&req);
134906943f9SDavid du Colombier 	rp->status = req.status;
135906943f9SDavid du Colombier 	if(status != -1)
136906943f9SDavid du Colombier 		rp->sense[0] |= Sd0valid;
137906943f9SDavid du Colombier 	return status;
138906943f9SDavid du Colombier }
139906943f9SDavid du Colombier 
140906943f9SDavid du Colombier long
SRformat(ScsiReq * rp)141906943f9SDavid du Colombier SRformat(ScsiReq *rp)
142906943f9SDavid du Colombier {
143906943f9SDavid du Colombier 	uchar cmd[6];
144906943f9SDavid du Colombier 
145906943f9SDavid du Colombier 	memset(cmd, 0, sizeof cmd);
146906943f9SDavid du Colombier 	cmd[0] = ScmdFormat;
147906943f9SDavid du Colombier 	rp->cmd.p = cmd;
148906943f9SDavid du Colombier 	rp->cmd.count = sizeof cmd;
149906943f9SDavid du Colombier 	rp->data.p = cmd;
150906943f9SDavid du Colombier 	rp->data.count = 6;
151906943f9SDavid du Colombier 	rp->data.write = 0;
152906943f9SDavid du Colombier 	return SRrequest(rp);
153906943f9SDavid du Colombier }
154906943f9SDavid du Colombier 
155906943f9SDavid du Colombier long
SRrblimits(ScsiReq * rp,uchar * list)156906943f9SDavid du Colombier SRrblimits(ScsiReq *rp, uchar *list)
157906943f9SDavid du Colombier {
158906943f9SDavid du Colombier 	uchar cmd[6];
159906943f9SDavid du Colombier 
160906943f9SDavid du Colombier 	memset(cmd, 0, sizeof cmd);
161906943f9SDavid du Colombier 	cmd[0] = ScmdRblimits;
162906943f9SDavid du Colombier 	rp->cmd.p = cmd;
163906943f9SDavid du Colombier 	rp->cmd.count = sizeof cmd;
164906943f9SDavid du Colombier 	rp->data.p = list;
165906943f9SDavid du Colombier 	rp->data.count = 6;
166906943f9SDavid du Colombier 	rp->data.write = 0;
167906943f9SDavid du Colombier 	return SRrequest(rp);
168906943f9SDavid du Colombier }
169906943f9SDavid du Colombier 
170906943f9SDavid du Colombier static int
dirdevrw(ScsiReq * rp,uchar * cmd,long nbytes)171906943f9SDavid du Colombier dirdevrw(ScsiReq *rp, uchar *cmd, long nbytes)
172906943f9SDavid du Colombier {
173906943f9SDavid du Colombier 	long n;
174906943f9SDavid du Colombier 
175906943f9SDavid du Colombier 	n = nbytes / rp->lbsize;
176906943f9SDavid du Colombier 	if(rp->offset <= Max24off && n <= 256 && (rp->flags & Frw10) == 0){
177906943f9SDavid du Colombier 		PUTBE24(cmd+1, rp->offset);
178906943f9SDavid du Colombier 		cmd[4] = n;
179906943f9SDavid du Colombier 		cmd[5] = 0;
180906943f9SDavid du Colombier 		return 6;
181906943f9SDavid du Colombier 	}
182906943f9SDavid du Colombier 	cmd[0] |= ScmdExtread;
183906943f9SDavid du Colombier 	cmd[1] = 0;
184906943f9SDavid du Colombier 	PUTBELONG(cmd+2, rp->offset);
185906943f9SDavid du Colombier 	cmd[6] = 0;
186906943f9SDavid du Colombier 	cmd[7] = n>>8;
187906943f9SDavid du Colombier 	cmd[8] = n;
188906943f9SDavid du Colombier 	cmd[9] = 0;
189906943f9SDavid du Colombier 	return 10;
190906943f9SDavid du Colombier }
191906943f9SDavid du Colombier 
192906943f9SDavid du Colombier static int
seqdevrw(ScsiReq * rp,uchar * cmd,long nbytes)193906943f9SDavid du Colombier seqdevrw(ScsiReq *rp, uchar *cmd, long nbytes)
194906943f9SDavid du Colombier {
195906943f9SDavid du Colombier 	long n;
196906943f9SDavid du Colombier 
197906943f9SDavid du Colombier 	/* don't set Cmd1sili; we want the ILI bit instead of a fatal error */
198906943f9SDavid du Colombier 	cmd[1] = rp->flags&Fbfixed? Cmd1fixed: 0;
199906943f9SDavid du Colombier 	n = nbytes / rp->lbsize;
200906943f9SDavid du Colombier 	PUTBE24(cmd+2, n);
201906943f9SDavid du Colombier 	cmd[5] = 0;
202906943f9SDavid du Colombier 	return 6;
203906943f9SDavid du Colombier }
204906943f9SDavid du Colombier 
2057d7728c9SDavid du Colombier extern int diskdebug;
2067d7728c9SDavid du Colombier 
207906943f9SDavid du Colombier long
SRread(ScsiReq * rp,void * buf,long nbytes)208906943f9SDavid du Colombier SRread(ScsiReq *rp, void *buf, long nbytes)
209906943f9SDavid du Colombier {
210906943f9SDavid du Colombier 	uchar cmd[10];
211906943f9SDavid du Colombier 	long n;
212906943f9SDavid du Colombier 
2133a827ddcSDavid du Colombier 	if(rp->lbsize == 0 || (nbytes % rp->lbsize) || nbytes > Maxiosize){
2147d7728c9SDavid du Colombier 		if(diskdebug)
2157d7728c9SDavid du Colombier 			if (nbytes % rp->lbsize)
2167d7728c9SDavid du Colombier 				fprint(2, "disk: i/o size %ld %% %ld != 0\n",
2177d7728c9SDavid du Colombier 					nbytes, rp->lbsize);
2187d7728c9SDavid du Colombier 			else
2193a827ddcSDavid du Colombier 				fprint(2, "disk: i/o size %ld > %d\n",
2203a827ddcSDavid du Colombier 					nbytes, Maxiosize);
221906943f9SDavid du Colombier 		rp->status = Status_BADARG;
222906943f9SDavid du Colombier 		return -1;
223906943f9SDavid du Colombier 	}
224906943f9SDavid du Colombier 
225906943f9SDavid du Colombier 	/* set up scsi read cmd */
226906943f9SDavid du Colombier 	cmd[0] = ScmdRead;
227906943f9SDavid du Colombier 	if(rp->flags & Fseqdev)
228906943f9SDavid du Colombier 		rp->cmd.count = seqdevrw(rp, cmd, nbytes);
229906943f9SDavid du Colombier 	else
230906943f9SDavid du Colombier 		rp->cmd.count = dirdevrw(rp, cmd, nbytes);
231906943f9SDavid du Colombier 	rp->cmd.p = cmd;
232906943f9SDavid du Colombier 	rp->data.p = buf;
233906943f9SDavid du Colombier 	rp->data.count = nbytes;
234906943f9SDavid du Colombier 	rp->data.write = 0;
235906943f9SDavid du Colombier 
236906943f9SDavid du Colombier 	/* issue it */
237906943f9SDavid du Colombier 	n = SRrequest(rp);
238906943f9SDavid du Colombier 	if(n != -1){			/* it worked? */
239906943f9SDavid du Colombier 		rp->offset += n / rp->lbsize;
240906943f9SDavid du Colombier 		return n;
241906943f9SDavid du Colombier 	}
242906943f9SDavid du Colombier 
243906943f9SDavid du Colombier 	/* request failed; maybe we just read a short record? */
244906943f9SDavid du Colombier 	if (exabyte) {
245906943f9SDavid du Colombier 		fprint(2, "read error\n");
246906943f9SDavid du Colombier 		rp->status = STcheck;
247906943f9SDavid du Colombier 		return n;
248906943f9SDavid du Colombier 	}
249906943f9SDavid du Colombier 	if(rp->status != Status_SD || !(rp->sense[0] & Sd0valid))
250906943f9SDavid du Colombier 		return -1;
251906943f9SDavid du Colombier 	/* compute # of bytes not read */
252906943f9SDavid du Colombier 	n = GETBELONG(rp->sense+3) * rp->lbsize;
253906943f9SDavid du Colombier 	if(!(rp->flags & Fseqdev))
254906943f9SDavid du Colombier 		return -1;
255906943f9SDavid du Colombier 
256906943f9SDavid du Colombier 	/* device is a tape or something similar */
257906943f9SDavid du Colombier 	if (rp->sense[2] == Sd2filemark || rp->sense[2] == 0x08 ||
258906943f9SDavid du Colombier 	    rp->sense[2] & Sd2ili && n > 0)
259906943f9SDavid du Colombier 		rp->data.count = nbytes - n;
260906943f9SDavid du Colombier 	else
261906943f9SDavid du Colombier 		return -1;
262906943f9SDavid du Colombier 	n = rp->data.count;
263906943f9SDavid du Colombier 	if (!rp->readblock++ || debug)
264906943f9SDavid du Colombier 		fprint(2, "SRread: tape data count %ld%s\n", n,
265906943f9SDavid du Colombier 			(rp->sense[2] & Sd2ili? " with ILI": ""));
266906943f9SDavid du Colombier 	rp->status = STok;
267906943f9SDavid du Colombier 	rp->offset += n / rp->lbsize;
268906943f9SDavid du Colombier 	return n;
269906943f9SDavid du Colombier }
270906943f9SDavid du Colombier 
271906943f9SDavid du Colombier long
SRwrite(ScsiReq * rp,void * buf,long nbytes)272906943f9SDavid du Colombier SRwrite(ScsiReq *rp, void *buf, long nbytes)
273906943f9SDavid du Colombier {
274906943f9SDavid du Colombier 	uchar cmd[10];
275906943f9SDavid du Colombier 	long n;
276906943f9SDavid du Colombier 
2773a827ddcSDavid du Colombier 	if(rp->lbsize == 0 || (nbytes % rp->lbsize) || nbytes > Maxiosize){
2787d7728c9SDavid du Colombier 		if(diskdebug)
2797d7728c9SDavid du Colombier 			if (nbytes % rp->lbsize)
2807d7728c9SDavid du Colombier 				fprint(2, "disk: i/o size %ld %% %ld != 0\n",
2817d7728c9SDavid du Colombier 					nbytes, rp->lbsize);
2827d7728c9SDavid du Colombier 			else
2833a827ddcSDavid du Colombier 				fprint(2, "disk: i/o size %ld > %d\n",
2843a827ddcSDavid du Colombier 					nbytes, Maxiosize);
285906943f9SDavid du Colombier 		rp->status = Status_BADARG;
286906943f9SDavid du Colombier 		return -1;
287906943f9SDavid du Colombier 	}
288906943f9SDavid du Colombier 
289906943f9SDavid du Colombier 	/* set up scsi write cmd */
290906943f9SDavid du Colombier 	cmd[0] = ScmdWrite;
291906943f9SDavid du Colombier 	if(rp->flags & Fseqdev)
292906943f9SDavid du Colombier 		rp->cmd.count = seqdevrw(rp, cmd, nbytes);
293906943f9SDavid du Colombier 	else
294906943f9SDavid du Colombier 		rp->cmd.count = dirdevrw(rp, cmd, nbytes);
295906943f9SDavid du Colombier 	rp->cmd.p = cmd;
296906943f9SDavid du Colombier 	rp->data.p = buf;
297906943f9SDavid du Colombier 	rp->data.count = nbytes;
298906943f9SDavid du Colombier 	rp->data.write = 1;
299906943f9SDavid du Colombier 
300906943f9SDavid du Colombier 	/* issue it */
301906943f9SDavid du Colombier 	if((n = SRrequest(rp)) == -1){
302906943f9SDavid du Colombier 		if (exabyte) {
303906943f9SDavid du Colombier 			fprint(2, "write error\n");
304906943f9SDavid du Colombier 			rp->status = STcheck;
305906943f9SDavid du Colombier 			return n;
306906943f9SDavid du Colombier 		}
307906943f9SDavid du Colombier 		if(rp->status != Status_SD || rp->sense[2] != Sd2eom)
308906943f9SDavid du Colombier 			return -1;
309906943f9SDavid du Colombier 		if(rp->sense[0] & Sd0valid){
310906943f9SDavid du Colombier 			n -= GETBELONG(rp->sense+3) * rp->lbsize;
311906943f9SDavid du Colombier 			rp->data.count = nbytes - n;
312906943f9SDavid du Colombier 		}
313906943f9SDavid du Colombier 		else
314906943f9SDavid du Colombier 			rp->data.count = nbytes;
315906943f9SDavid du Colombier 		n = rp->data.count;
316906943f9SDavid du Colombier 	}
317906943f9SDavid du Colombier 	rp->offset += n / rp->lbsize;
318906943f9SDavid du Colombier 	return n;
319906943f9SDavid du Colombier }
320906943f9SDavid du Colombier 
321906943f9SDavid du Colombier long
SRseek(ScsiReq * rp,long offset,int type)322906943f9SDavid du Colombier SRseek(ScsiReq *rp, long offset, int type)
323906943f9SDavid du Colombier {
324906943f9SDavid du Colombier 	uchar cmd[10];
325906943f9SDavid du Colombier 
326906943f9SDavid du Colombier 	switch(type){
327906943f9SDavid du Colombier 
328906943f9SDavid du Colombier 	case 0:
329906943f9SDavid du Colombier 		break;
330906943f9SDavid du Colombier 
331906943f9SDavid du Colombier 	case 1:
332906943f9SDavid du Colombier 		offset += rp->offset;
333906943f9SDavid du Colombier 		if(offset >= 0)
334906943f9SDavid du Colombier 			break;
335906943f9SDavid du Colombier 		/*FALLTHROUGH*/
336906943f9SDavid du Colombier 
337906943f9SDavid du Colombier 	default:
3387d7728c9SDavid du Colombier 		if(diskdebug)
3397d7728c9SDavid du Colombier 			fprint(2, "disk: seek failed\n");
340906943f9SDavid du Colombier 		rp->status = Status_BADARG;
341906943f9SDavid du Colombier 		return -1;
342906943f9SDavid du Colombier 	}
343906943f9SDavid du Colombier 	memset(cmd, 0, sizeof cmd);
344906943f9SDavid du Colombier 	if(offset <= Max24off && (rp->flags & Frw10) == 0){
345906943f9SDavid du Colombier 		cmd[0] = ScmdSeek;
346906943f9SDavid du Colombier 		PUTBE24(cmd+1, offset & Max24off);
347906943f9SDavid du Colombier 		rp->cmd.count = 6;
348906943f9SDavid du Colombier 	}else{
349906943f9SDavid du Colombier 		cmd[0] = ScmdExtseek;
350906943f9SDavid du Colombier 		PUTBELONG(cmd+2, offset);
351906943f9SDavid du Colombier 		rp->cmd.count = 10;
352906943f9SDavid du Colombier 	}
353906943f9SDavid du Colombier 	rp->cmd.p = cmd;
354906943f9SDavid du Colombier 	rp->data.p = cmd;
355906943f9SDavid du Colombier 	rp->data.count = 0;
356906943f9SDavid du Colombier 	rp->data.write = 1;
357906943f9SDavid du Colombier 	SRrequest(rp);
3583a827ddcSDavid du Colombier 	if(rp->status == STok) {
3593a827ddcSDavid du Colombier 		rp->offset = offset;
3603a827ddcSDavid du Colombier 		return offset;
3613a827ddcSDavid du Colombier 	}
362906943f9SDavid du Colombier 	return -1;
363906943f9SDavid du Colombier }
364906943f9SDavid du Colombier 
365906943f9SDavid du Colombier long
SRfilemark(ScsiReq * rp,ulong howmany)366906943f9SDavid du Colombier SRfilemark(ScsiReq *rp, ulong howmany)
367906943f9SDavid du Colombier {
368906943f9SDavid du Colombier 	uchar cmd[6];
369906943f9SDavid du Colombier 
370906943f9SDavid du Colombier 	memset(cmd, 0, sizeof cmd);
371906943f9SDavid du Colombier 	cmd[0] = ScmdFmark;
372906943f9SDavid du Colombier 	PUTBE24(cmd+2, howmany);
373906943f9SDavid du Colombier 	rp->cmd.p = cmd;
374906943f9SDavid du Colombier 	rp->cmd.count = sizeof cmd;
375906943f9SDavid du Colombier 	rp->data.p = cmd;
376906943f9SDavid du Colombier 	rp->data.count = 0;
377906943f9SDavid du Colombier 	rp->data.write = 1;
378906943f9SDavid du Colombier 	return SRrequest(rp);
379906943f9SDavid du Colombier }
380906943f9SDavid du Colombier 
381906943f9SDavid du Colombier long
SRspace(ScsiReq * rp,uchar code,long howmany)382906943f9SDavid du Colombier SRspace(ScsiReq *rp, uchar code, long howmany)
383906943f9SDavid du Colombier {
384906943f9SDavid du Colombier 	uchar cmd[6];
385906943f9SDavid du Colombier 
386906943f9SDavid du Colombier 	memset(cmd, 0, sizeof cmd);
387906943f9SDavid du Colombier 	cmd[0] = ScmdSpace;
388906943f9SDavid du Colombier 	cmd[1] = code;
389906943f9SDavid du Colombier 	PUTBE24(cmd+2, howmany);
390906943f9SDavid du Colombier 	rp->cmd.p = cmd;
391906943f9SDavid du Colombier 	rp->cmd.count = sizeof cmd;
392906943f9SDavid du Colombier 	rp->data.p = cmd;
393906943f9SDavid du Colombier 	rp->data.count = 0;
394906943f9SDavid du Colombier 	rp->data.write = 1;
395906943f9SDavid du Colombier 	/*
396906943f9SDavid du Colombier 	 * what about rp->offset?
397906943f9SDavid du Colombier 	 */
398906943f9SDavid du Colombier 	return SRrequest(rp);
399906943f9SDavid du Colombier }
400906943f9SDavid du Colombier 
401906943f9SDavid du Colombier long
SRinquiry(ScsiReq * rp)402906943f9SDavid du Colombier SRinquiry(ScsiReq *rp)
403906943f9SDavid du Colombier {
404906943f9SDavid du Colombier 	uchar cmd[6];
405906943f9SDavid du Colombier 
406906943f9SDavid du Colombier 	memset(cmd, 0, sizeof cmd);
407906943f9SDavid du Colombier 	cmd[0] = ScmdInq;
408906943f9SDavid du Colombier 	cmd[4] = sizeof rp->inquiry;
409906943f9SDavid du Colombier 	rp->cmd.p = cmd;
410906943f9SDavid du Colombier 	rp->cmd.count = sizeof cmd;
411906943f9SDavid du Colombier 	memset(rp->inquiry, 0, sizeof rp->inquiry);
412906943f9SDavid du Colombier 	rp->data.p = rp->inquiry;
413906943f9SDavid du Colombier 	rp->data.count = sizeof rp->inquiry;
414906943f9SDavid du Colombier 	rp->data.write = 0;
415906943f9SDavid du Colombier 	if(SRrequest(rp) >= 0){
416906943f9SDavid du Colombier 		rp->flags |= Finqok;
417906943f9SDavid du Colombier 		return 0;
418906943f9SDavid du Colombier 	}
419906943f9SDavid du Colombier 	rp->flags &= ~Finqok;
420906943f9SDavid du Colombier 	return -1;
421906943f9SDavid du Colombier }
422906943f9SDavid du Colombier 
423906943f9SDavid du Colombier long
SRmodeselect6(ScsiReq * rp,uchar * list,long nbytes)424906943f9SDavid du Colombier SRmodeselect6(ScsiReq *rp, uchar *list, long nbytes)
425906943f9SDavid du Colombier {
426906943f9SDavid du Colombier 	uchar cmd[6];
427906943f9SDavid du Colombier 
428906943f9SDavid du Colombier 	memset(cmd, 0, sizeof cmd);
429906943f9SDavid du Colombier 	cmd[0] = ScmdMselect6;
430906943f9SDavid du Colombier 	if((rp->flags & Finqok) && (rp->inquiry[2] & 0x07) >= 2)
431906943f9SDavid du Colombier 		cmd[1] = 0x10;
432906943f9SDavid du Colombier 	cmd[4] = nbytes;
433906943f9SDavid du Colombier 	rp->cmd.p = cmd;
434906943f9SDavid du Colombier 	rp->cmd.count = sizeof cmd;
435906943f9SDavid du Colombier 	rp->data.p = list;
436906943f9SDavid du Colombier 	rp->data.count = nbytes;
437906943f9SDavid du Colombier 	rp->data.write = 1;
438906943f9SDavid du Colombier 	return SRrequest(rp);
439906943f9SDavid du Colombier }
440906943f9SDavid du Colombier 
441906943f9SDavid du Colombier long
SRmodeselect10(ScsiReq * rp,uchar * list,long nbytes)442906943f9SDavid du Colombier SRmodeselect10(ScsiReq *rp, uchar *list, long nbytes)
443906943f9SDavid du Colombier {
444906943f9SDavid du Colombier 	uchar cmd[10];
445906943f9SDavid du Colombier 
446906943f9SDavid du Colombier 	memset(cmd, 0, sizeof cmd);
447906943f9SDavid du Colombier 	if((rp->flags & Finqok) && (rp->inquiry[2] & 0x07) >= 2)
448906943f9SDavid du Colombier 		cmd[1] = 0x10;
449906943f9SDavid du Colombier 	cmd[0] = ScmdMselect10;
450906943f9SDavid du Colombier 	cmd[7] = nbytes>>8;
451906943f9SDavid du Colombier 	cmd[8] = nbytes;
452906943f9SDavid du Colombier 	rp->cmd.p = cmd;
453906943f9SDavid du Colombier 	rp->cmd.count = sizeof cmd;
454906943f9SDavid du Colombier 	rp->data.p = list;
455906943f9SDavid du Colombier 	rp->data.count = nbytes;
456906943f9SDavid du Colombier 	rp->data.write = 1;
457906943f9SDavid du Colombier 	return SRrequest(rp);
458906943f9SDavid du Colombier }
459906943f9SDavid du Colombier 
460906943f9SDavid du Colombier long
SRmodesense6(ScsiReq * rp,uchar page,uchar * list,long nbytes)461906943f9SDavid du Colombier SRmodesense6(ScsiReq *rp, uchar page, uchar *list, long nbytes)
462906943f9SDavid du Colombier {
463906943f9SDavid du Colombier 	uchar cmd[6];
464906943f9SDavid du Colombier 
465906943f9SDavid du Colombier 	memset(cmd, 0, sizeof cmd);
466906943f9SDavid du Colombier 	cmd[0] = ScmdMsense6;
467906943f9SDavid du Colombier 	cmd[2] = page;
468906943f9SDavid du Colombier 	cmd[4] = nbytes;
469906943f9SDavid du Colombier 	rp->cmd.p = cmd;
470906943f9SDavid du Colombier 	rp->cmd.count = sizeof cmd;
471906943f9SDavid du Colombier 	rp->data.p = list;
472906943f9SDavid du Colombier 	rp->data.count = nbytes;
473906943f9SDavid du Colombier 	rp->data.write = 0;
474906943f9SDavid du Colombier 	return SRrequest(rp);
475906943f9SDavid du Colombier }
476906943f9SDavid du Colombier 
477906943f9SDavid du Colombier long
SRmodesense10(ScsiReq * rp,uchar page,uchar * list,long nbytes)478906943f9SDavid du Colombier SRmodesense10(ScsiReq *rp, uchar page, uchar *list, long nbytes)
479906943f9SDavid du Colombier {
480906943f9SDavid du Colombier 	uchar cmd[10];
481906943f9SDavid du Colombier 
482906943f9SDavid du Colombier 	memset(cmd, 0, sizeof cmd);
483906943f9SDavid du Colombier 	cmd[0] = ScmdMsense10;
484906943f9SDavid du Colombier 	cmd[2] = page;
485906943f9SDavid du Colombier 	cmd[7] = nbytes>>8;
486906943f9SDavid du Colombier 	cmd[8] = nbytes;
487906943f9SDavid du Colombier 	rp->cmd.p = cmd;
488906943f9SDavid du Colombier 	rp->cmd.count = sizeof cmd;
489906943f9SDavid du Colombier 	rp->data.p = list;
490906943f9SDavid du Colombier 	rp->data.count = nbytes;
491906943f9SDavid du Colombier 	rp->data.write = 0;
492906943f9SDavid du Colombier 	return SRrequest(rp);
493906943f9SDavid du Colombier }
494906943f9SDavid du Colombier 
495906943f9SDavid du Colombier long
SRstart(ScsiReq * rp,uchar code)496906943f9SDavid du Colombier SRstart(ScsiReq *rp, uchar code)
497906943f9SDavid du Colombier {
498906943f9SDavid du Colombier 	uchar cmd[6];
499906943f9SDavid du Colombier 
500906943f9SDavid du Colombier 	memset(cmd, 0, sizeof cmd);
501906943f9SDavid du Colombier 	cmd[0] = ScmdStart;
502906943f9SDavid du Colombier 	cmd[4] = code;
503906943f9SDavid du Colombier 	rp->cmd.p = cmd;
504906943f9SDavid du Colombier 	rp->cmd.count = sizeof cmd;
505906943f9SDavid du Colombier 	rp->data.p = cmd;
506906943f9SDavid du Colombier 	rp->data.count = 0;
507906943f9SDavid du Colombier 	rp->data.write = 1;
508906943f9SDavid du Colombier 	return SRrequest(rp);
509906943f9SDavid du Colombier }
510906943f9SDavid du Colombier 
511906943f9SDavid du Colombier long
SRrcapacity(ScsiReq * rp,uchar * data)512906943f9SDavid du Colombier SRrcapacity(ScsiReq *rp, uchar *data)
513906943f9SDavid du Colombier {
514906943f9SDavid du Colombier 	uchar cmd[10];
515906943f9SDavid du Colombier 
516906943f9SDavid du Colombier 	memset(cmd, 0, sizeof cmd);
517906943f9SDavid du Colombier 	cmd[0] = ScmdRcapacity;
518906943f9SDavid du Colombier 	rp->cmd.p = cmd;
519906943f9SDavid du Colombier 	rp->cmd.count = sizeof cmd;
520906943f9SDavid du Colombier 	rp->data.p = data;
521906943f9SDavid du Colombier 	rp->data.count = 8;
522906943f9SDavid du Colombier 	rp->data.write = 0;
523906943f9SDavid du Colombier 	return SRrequest(rp);
524906943f9SDavid du Colombier }
525906943f9SDavid du Colombier 
526906943f9SDavid du Colombier long
SRrcapacity16(ScsiReq * rp,uchar * data)527906943f9SDavid du Colombier SRrcapacity16(ScsiReq *rp, uchar *data)
528906943f9SDavid du Colombier {
529906943f9SDavid du Colombier 	uchar cmd[16];
530906943f9SDavid du Colombier 	uint i;
531906943f9SDavid du Colombier 
532906943f9SDavid du Colombier 	i = 32;
533906943f9SDavid du Colombier 	memset(cmd, 0, sizeof cmd);
534906943f9SDavid du Colombier 	cmd[0] = ScmdRcapacity16;
535906943f9SDavid du Colombier 	cmd[1] = 0x10;
536906943f9SDavid du Colombier 	cmd[10] = i>>24;
537906943f9SDavid du Colombier 	cmd[11] = i>>16;
538906943f9SDavid du Colombier 	cmd[12] = i>>8;
539906943f9SDavid du Colombier 	cmd[13] = i;
540906943f9SDavid du Colombier 
541906943f9SDavid du Colombier 	rp->cmd.p = cmd;
542906943f9SDavid du Colombier 	rp->cmd.count = sizeof cmd;
543906943f9SDavid du Colombier 	rp->data.p = data;
544906943f9SDavid du Colombier 	rp->data.count = i;
545906943f9SDavid du Colombier 	rp->data.write = 0;
546906943f9SDavid du Colombier 	return SRrequest(rp);
547906943f9SDavid du Colombier }
548906943f9SDavid du Colombier 
549906943f9SDavid du Colombier void
scsidebug(int d)550906943f9SDavid du Colombier scsidebug(int d)
551906943f9SDavid du Colombier {
552906943f9SDavid du Colombier 	debug = d;
553906943f9SDavid du Colombier 	if(debug)
554906943f9SDavid du Colombier 		fprint(2, "scsidebug on\n");
555906943f9SDavid du Colombier }
556906943f9SDavid du Colombier 
557906943f9SDavid du Colombier static long
request(int fd,ScsiPtr * cmd,ScsiPtr * data,int * status)558906943f9SDavid du Colombier request(int fd, ScsiPtr *cmd, ScsiPtr *data, int *status)
559906943f9SDavid du Colombier {
560906943f9SDavid du Colombier 	long n, r;
561906943f9SDavid du Colombier 	char buf[16];
562906943f9SDavid du Colombier 
563906943f9SDavid du Colombier 	/* this was an experiment but it seems to be a good idea */
564906943f9SDavid du Colombier 	*status = STok;
565906943f9SDavid du Colombier 
566906943f9SDavid du Colombier 	/* send SCSI command */
567906943f9SDavid du Colombier 	if(write(fd, cmd->p, cmd->count) != cmd->count){
568906943f9SDavid du Colombier 		fprint(2, "scsireq: write cmd: %r\n");
569906943f9SDavid du Colombier 		*status = Status_SW;
570906943f9SDavid du Colombier 		return -1;
571906943f9SDavid du Colombier 	}
572906943f9SDavid du Colombier 
573906943f9SDavid du Colombier 	/* read or write actual data */
574906943f9SDavid du Colombier 	werrstr("");
5753a827ddcSDavid du Colombier //	alarm(5*1000);
576906943f9SDavid du Colombier 	if(data->write)
577906943f9SDavid du Colombier 		n = write(fd, data->p, data->count);
578906943f9SDavid du Colombier 	else {
579906943f9SDavid du Colombier 		n = read(fd, data->p, data->count);
580906943f9SDavid du Colombier 		if (n < 0)
581906943f9SDavid du Colombier 			memset(data->p, 0, data->count);
582906943f9SDavid du Colombier 		else if (n < data->count)
583906943f9SDavid du Colombier 			memset(data->p + n, 0, data->count - n);
584906943f9SDavid du Colombier 	}
5853a827ddcSDavid du Colombier //	alarm(0);
586906943f9SDavid du Colombier 	if (n != data->count && n <= 0) {
587906943f9SDavid du Colombier 		if (debug)
588906943f9SDavid du Colombier 			fprint(2,
589906943f9SDavid du Colombier 	"request: tried to %s %ld bytes of data for cmd 0x%x but got %r\n",
590906943f9SDavid du Colombier 				(data->write? "write": "read"),
591906943f9SDavid du Colombier 				data->count, cmd->p[0]);
592906943f9SDavid du Colombier 	} else if (n != data->count && (data->write || debug))
593906943f9SDavid du Colombier 		fprint(2, "request: %s %ld of %ld bytes of actual data\n",
594906943f9SDavid du Colombier 			(data->write? "wrote": "read"), n, data->count);
595906943f9SDavid du Colombier 
596906943f9SDavid du Colombier 	/* read status */
597906943f9SDavid du Colombier 	buf[0] = '\0';
598906943f9SDavid du Colombier 	r = read(fd, buf, sizeof buf-1);
599906943f9SDavid du Colombier 	if(exabyte && r <= 0 || !exabyte && r < 0){
600906943f9SDavid du Colombier 		fprint(2, "scsireq: read status: %r\n");
601906943f9SDavid du Colombier 		*status = Status_SW;
602906943f9SDavid du Colombier 		return -1;
603906943f9SDavid du Colombier 	}
604906943f9SDavid du Colombier 	if (r >= 0)
605906943f9SDavid du Colombier 		buf[r] = '\0';
606906943f9SDavid du Colombier 	*status = atoi(buf);
607906943f9SDavid du Colombier 	if(n < 0 && (exabyte || *status != STcheck))
608906943f9SDavid du Colombier 		fprint(2, "scsireq: status 0x%2.2uX: data transfer: %r\n",
609906943f9SDavid du Colombier 			*status);
610906943f9SDavid du Colombier 	return n;
611906943f9SDavid du Colombier }
612906943f9SDavid du Colombier 
613906943f9SDavid du Colombier static char*
seprintcmd(char * s,char * e,char * cmd,int count,int args)614906943f9SDavid du Colombier seprintcmd(char *s, char* e, char *cmd, int count, int args)
615906943f9SDavid du Colombier {
616906943f9SDavid du Colombier 	uint c;
617906943f9SDavid du Colombier 
618906943f9SDavid du Colombier 	if(count < 6)
619906943f9SDavid du Colombier 		return seprint(s, e, "<short cmd>");
620906943f9SDavid du Colombier 	c = cmd[0];
621906943f9SDavid du Colombier 	if(scmdnames[c] != nil)
622906943f9SDavid du Colombier 		s = seprint(s, e, "%s", scmdnames[c]);
623906943f9SDavid du Colombier 	else
624906943f9SDavid du Colombier 		s = seprint(s, e, "cmd:%#02uX", c);
625906943f9SDavid du Colombier 	if(args != 0)
626906943f9SDavid du Colombier 		switch(c){
627906943f9SDavid du Colombier 		case ScmdRsense:
628906943f9SDavid du Colombier 		case ScmdInq:
629906943f9SDavid du Colombier 		case ScmdMselect6:
630906943f9SDavid du Colombier 		case ScmdMsense6:
631906943f9SDavid du Colombier 			s = seprint(s, e, " sz %d", cmd[4]);
632906943f9SDavid du Colombier 			break;
633906943f9SDavid du Colombier 		case ScmdSpace:
634906943f9SDavid du Colombier 			s = seprint(s, e, " code %d", cmd[1]);
635906943f9SDavid du Colombier 			break;
636906943f9SDavid du Colombier 		case ScmdStart:
637906943f9SDavid du Colombier 			s = seprint(s, e, " code %d", cmd[4]);
638906943f9SDavid du Colombier 			break;
639906943f9SDavid du Colombier 
640906943f9SDavid du Colombier 		}
641906943f9SDavid du Colombier 	return s;
642906943f9SDavid du Colombier }
643906943f9SDavid du Colombier 
644906943f9SDavid du Colombier static char*
seprintdata(char * s,char * se,uchar * p,int count)645906943f9SDavid du Colombier seprintdata(char *s, char *se, uchar *p, int count)
646906943f9SDavid du Colombier {
647906943f9SDavid du Colombier 	int i;
648906943f9SDavid du Colombier 
649906943f9SDavid du Colombier 	if(count == 0)
650906943f9SDavid du Colombier 		return s;
651906943f9SDavid du Colombier 	for(i = 0; i < 20 && i < count; i++)
652906943f9SDavid du Colombier 		s = seprint(s, se, " %02x", p[i]);
653906943f9SDavid du Colombier 	return s;
654906943f9SDavid du Colombier }
655906943f9SDavid du Colombier 
656906943f9SDavid du Colombier static void
SRdumpReq(ScsiReq * rp)657906943f9SDavid du Colombier SRdumpReq(ScsiReq *rp)
658906943f9SDavid du Colombier {
659906943f9SDavid du Colombier 	char buf[128];
660906943f9SDavid du Colombier 	char *s;
661906943f9SDavid du Colombier 	char *se;
662906943f9SDavid du Colombier 
663906943f9SDavid du Colombier 	se = buf+sizeof(buf);
664906943f9SDavid du Colombier 	s = seprint(buf, se, "lun %d ", rp->lun);
665906943f9SDavid du Colombier 	s = seprintcmd(s, se, (char*)rp->cmd.p, rp->cmd.count, 1);
666906943f9SDavid du Colombier 	s = seprint(s, se, " [%ld]", rp->data.count);
667906943f9SDavid du Colombier 	if(rp->cmd.write)
668906943f9SDavid du Colombier 		seprintdata(s, se, rp->data.p, rp->data.count);
669906943f9SDavid du Colombier 	fprint(2, "scsi⇒ %s\n", buf);
670906943f9SDavid du Colombier }
671906943f9SDavid du Colombier 
672906943f9SDavid du Colombier static void
SRdumpRep(ScsiReq * rp)673906943f9SDavid du Colombier SRdumpRep(ScsiReq *rp)
674906943f9SDavid du Colombier {
675906943f9SDavid du Colombier 	char buf[128];
676906943f9SDavid du Colombier 	char *s;
677906943f9SDavid du Colombier 	char *se;
678906943f9SDavid du Colombier 
679906943f9SDavid du Colombier 	se = buf+sizeof(buf);
680906943f9SDavid du Colombier 	s = seprint(buf, se, "lun %d ", rp->lun);
681906943f9SDavid du Colombier 	s = seprintcmd(s, se, (char*)rp->cmd.p, rp->cmd.count, 0);
682906943f9SDavid du Colombier 	switch(rp->status){
683906943f9SDavid du Colombier 	case STok:
684906943f9SDavid du Colombier 		s = seprint(s, se, " good [%ld] ", rp->data.count);
685906943f9SDavid du Colombier 		if(rp->cmd.write == 0)
686906943f9SDavid du Colombier 			s = seprintdata(s, se, rp->data.p, rp->data.count);
687906943f9SDavid du Colombier 		break;
688906943f9SDavid du Colombier 	case STnomem:
689906943f9SDavid du Colombier 		s = seprint(s, se, " buffer allocation failed");
690906943f9SDavid du Colombier 		break;
691906943f9SDavid du Colombier 	case STharderr:
692906943f9SDavid du Colombier 		s = seprint(s, se, " controller error");
693906943f9SDavid du Colombier 		break;
694906943f9SDavid du Colombier 	case STtimeout:
695906943f9SDavid du Colombier 		s = seprint(s, se, " bus timeout");
696906943f9SDavid du Colombier 		break;
697906943f9SDavid du Colombier 	case STcheck:
698906943f9SDavid du Colombier 		s = seprint(s, se, " check condition");
699906943f9SDavid du Colombier 		break;
700906943f9SDavid du Colombier 	case STcondmet:
701906943f9SDavid du Colombier 		s = seprint(s, se, " condition met/good");
702906943f9SDavid du Colombier 		break;
703906943f9SDavid du Colombier 	case STbusy:
704906943f9SDavid du Colombier 		s = seprint(s, se, " busy");
705906943f9SDavid du Colombier 		break;
706906943f9SDavid du Colombier 	case STintok:
707906943f9SDavid du Colombier 		s = seprint(s, se, " intermediate/good");
708906943f9SDavid du Colombier 		break;
709906943f9SDavid du Colombier 	case STintcondmet:
710906943f9SDavid du Colombier 		s = seprint(s, se, " intermediate/condition met/good");
711906943f9SDavid du Colombier 		break;
712906943f9SDavid du Colombier 	case STresconf:
713906943f9SDavid du Colombier 		s = seprint(s, se, " reservation conflict");
714906943f9SDavid du Colombier 		break;
715906943f9SDavid du Colombier 	case STterminated:
716906943f9SDavid du Colombier 		s = seprint(s, se, " command terminated");
717906943f9SDavid du Colombier 		break;
718906943f9SDavid du Colombier 	case STqfull:
719906943f9SDavid du Colombier 		s = seprint(s, se, " queue full");
720906943f9SDavid du Colombier 		break;
721906943f9SDavid du Colombier 	default:
722906943f9SDavid du Colombier 		s = seprint(s, se, " sts=%#x", rp->status);
723906943f9SDavid du Colombier 	}
724906943f9SDavid du Colombier 	USED(s);
725906943f9SDavid du Colombier 	fprint(2, "scsi← %s\n", buf);
726906943f9SDavid du Colombier }
727906943f9SDavid du Colombier 
728906943f9SDavid du Colombier static char*
scsierr(ScsiReq * rp)729906943f9SDavid du Colombier scsierr(ScsiReq *rp)
730906943f9SDavid du Colombier {
731906943f9SDavid du Colombier 	int ec;
732906943f9SDavid du Colombier 
733906943f9SDavid du Colombier 	switch(rp->status){
734906943f9SDavid du Colombier 	case 0:
735906943f9SDavid du Colombier 		return "";
736906943f9SDavid du Colombier 	case Status_SD:
737906943f9SDavid du Colombier 		ec = (rp->sense[12] << 8) | rp->sense[13];
738906943f9SDavid du Colombier 		return scsierrmsg(ec);
739906943f9SDavid du Colombier 	case Status_SW:
740906943f9SDavid du Colombier 		return "software error";
741906943f9SDavid du Colombier 	case Status_BADARG:
742906943f9SDavid du Colombier 		return "bad argument";
743906943f9SDavid du Colombier 	case Status_RO:
744906943f9SDavid du Colombier 		return "device is read only";
745906943f9SDavid du Colombier 	default:
746906943f9SDavid du Colombier 		return "unknown";
747906943f9SDavid du Colombier 	}
748906943f9SDavid du Colombier }
749906943f9SDavid du Colombier 
750906943f9SDavid du Colombier static void
SRdumpErr(ScsiReq * rp)751906943f9SDavid du Colombier SRdumpErr(ScsiReq *rp)
752906943f9SDavid du Colombier {
753906943f9SDavid du Colombier 	char buf[128];
754906943f9SDavid du Colombier 	char *se;
755906943f9SDavid du Colombier 
756906943f9SDavid du Colombier 	se = buf+sizeof(buf);
757906943f9SDavid du Colombier 	seprintcmd(buf, se, (char*)rp->cmd.p, rp->cmd.count, 0);
7582806980eSDavid du Colombier 	fprint(2, "\t%s status: %s\n", buf, scsierr(rp));
759906943f9SDavid du Colombier }
760906943f9SDavid du Colombier 
761906943f9SDavid du Colombier long
SRrequest(ScsiReq * rp)762906943f9SDavid du Colombier SRrequest(ScsiReq *rp)
763906943f9SDavid du Colombier {
764906943f9SDavid du Colombier 	long n;
765906943f9SDavid du Colombier 	int status;
766906943f9SDavid du Colombier 
767906943f9SDavid du Colombier retry:
768906943f9SDavid du Colombier 	if(debug)
769906943f9SDavid du Colombier 		SRdumpReq(rp);
770906943f9SDavid du Colombier 	if(rp->flags&Fusb)
771906943f9SDavid du Colombier 		n = umsrequest(rp->umsc, &rp->cmd, &rp->data, &status);
772906943f9SDavid du Colombier 	else
773906943f9SDavid du Colombier 		n = request(rp->fd, &rp->cmd, &rp->data, &status);
774906943f9SDavid du Colombier 	rp->status = status;
775906943f9SDavid du Colombier 	if(status == STok)
776906943f9SDavid du Colombier 		rp->data.count = n;
777906943f9SDavid du Colombier 	if(debug)
778906943f9SDavid du Colombier 		SRdumpRep(rp);
779906943f9SDavid du Colombier 	switch(status){
780906943f9SDavid du Colombier 	case STok:
781906943f9SDavid du Colombier 		break;
782906943f9SDavid du Colombier 	case STcheck:
783906943f9SDavid du Colombier 		if(rp->cmd.p[0] != ScmdRsense && SRreqsense(rp) != -1)
784906943f9SDavid du Colombier 			rp->status = Status_SD;
785906943f9SDavid du Colombier 		if(debug || exabyte)
786906943f9SDavid du Colombier 			SRdumpErr(rp);
787906943f9SDavid du Colombier 		werrstr("%s", scsierr(rp));
788906943f9SDavid du Colombier 		return -1;
789906943f9SDavid du Colombier 	case STbusy:
7903a827ddcSDavid du Colombier 		sleep(1000);		/* TODO: try a shorter sleep? */
791906943f9SDavid du Colombier 		goto retry;
792906943f9SDavid du Colombier 	default:
793906943f9SDavid du Colombier 		if(debug || exabyte)
794906943f9SDavid du Colombier 			SRdumpErr(rp);
795906943f9SDavid du Colombier 		werrstr("%s", scsierr(rp));
796906943f9SDavid du Colombier 		return -1;
797906943f9SDavid du Colombier 	}
798906943f9SDavid du Colombier 	return n;
799906943f9SDavid du Colombier }
800906943f9SDavid du Colombier 
801906943f9SDavid du Colombier int
SRclose(ScsiReq * rp)802906943f9SDavid du Colombier SRclose(ScsiReq *rp)
803906943f9SDavid du Colombier {
804906943f9SDavid du Colombier 	if((rp->flags & Fopen) == 0){
8057d7728c9SDavid du Colombier 		if(diskdebug)
8067d7728c9SDavid du Colombier 			fprint(2, "disk: closing closed file\n");
807906943f9SDavid du Colombier 		rp->status = Status_BADARG;
808906943f9SDavid du Colombier 		return -1;
809906943f9SDavid du Colombier 	}
810906943f9SDavid du Colombier 	close(rp->fd);
811906943f9SDavid du Colombier 	rp->flags = 0;
812906943f9SDavid du Colombier 	return 0;
813906943f9SDavid du Colombier }
814906943f9SDavid du Colombier 
815906943f9SDavid du Colombier static int
dirdevopen(ScsiReq * rp)816906943f9SDavid du Colombier dirdevopen(ScsiReq *rp)
817906943f9SDavid du Colombier {
8187d7728c9SDavid du Colombier 	uvlong blocks;
8197d7728c9SDavid du Colombier 	uchar data[8+4+20];	/* 16-byte result: lba, blksize, reserved */
820906943f9SDavid du Colombier 
8217d7728c9SDavid du Colombier 	memset(data, 0, sizeof data);
822906943f9SDavid du Colombier 	if(SRstart(rp, 1) == -1 || SRrcapacity(rp, data) == -1)
823906943f9SDavid du Colombier 		return -1;
824906943f9SDavid du Colombier 	rp->lbsize = GETBELONG(data+4);
825906943f9SDavid du Colombier 	blocks =     GETBELONG(data);
8267d7728c9SDavid du Colombier 	if(debug)
8277d7728c9SDavid du Colombier 		fprint(2, "disk: dirdevopen: 10-byte logical block size %lud, "
8287d7728c9SDavid du Colombier 			"# blocks %llud\n", rp->lbsize, blocks);
829906943f9SDavid du Colombier 	if(blocks == 0xffffffff){
830906943f9SDavid du Colombier 		if(SRrcapacity16(rp, data) == -1)
831906943f9SDavid du Colombier 			return -1;
832906943f9SDavid du Colombier 		rp->lbsize = GETBELONG(data + 8);
833906943f9SDavid du Colombier 		blocks = (vlong)GETBELONG(data)<<32 | GETBELONG(data + 4);
8347d7728c9SDavid du Colombier 		if(debug)
8357d7728c9SDavid du Colombier 			fprint(2, "disk: dirdevopen: 16-byte logical block size"
8367d7728c9SDavid du Colombier 				" %lud, # blocks %llud\n", rp->lbsize, blocks);
837906943f9SDavid du Colombier 	}
838906943f9SDavid du Colombier 	/* some newer dev's don't support 6-byte commands */
839906943f9SDavid du Colombier 	if(blocks > Max24off && !force6bytecmds)
840906943f9SDavid du Colombier 		rp->flags |= Frw10;
841906943f9SDavid du Colombier 	return 0;
842906943f9SDavid du Colombier }
843906943f9SDavid du Colombier 
844906943f9SDavid du Colombier static int
seqdevopen(ScsiReq * rp)845906943f9SDavid du Colombier seqdevopen(ScsiReq *rp)
846906943f9SDavid du Colombier {
847906943f9SDavid du Colombier 	uchar mode[16], limits[6];
848906943f9SDavid du Colombier 
849906943f9SDavid du Colombier 	if(SRrblimits(rp, limits) == -1)
850906943f9SDavid du Colombier 		return -1;
851906943f9SDavid du Colombier 	if(limits[1] == 0 && limits[2] == limits[4] && limits[3] == limits[5]){
852906943f9SDavid du Colombier 		rp->flags |= Fbfixed;
853906943f9SDavid du Colombier 		rp->lbsize = limits[4]<<8 | limits[5];
8547d7728c9SDavid du Colombier 		if(debug)
8557d7728c9SDavid du Colombier 			fprint(2, "disk: seqdevopen: 10-byte logical block size %lud\n",
8567d7728c9SDavid du Colombier 				rp->lbsize);
857906943f9SDavid du Colombier 		return 0;
858906943f9SDavid du Colombier 	}
859906943f9SDavid du Colombier 	/*
860906943f9SDavid du Colombier 	 * On some older hardware the optional 10-byte
861906943f9SDavid du Colombier 	 * modeselect command isn't implemented.
862906943f9SDavid du Colombier 	 */
863906943f9SDavid du Colombier 	if (force6bytecmds)
864906943f9SDavid du Colombier 		rp->flags |= Fmode6;
865906943f9SDavid du Colombier 	if(!(rp->flags & Fmode6)){
866906943f9SDavid du Colombier 		/* try 10-byte command first */
867906943f9SDavid du Colombier 		memset(mode, 0, sizeof mode);
868906943f9SDavid du Colombier 		mode[3] = 0x10;		/* device-specific param. */
869906943f9SDavid du Colombier 		mode[7] = 8;		/* block descriptor length */
870906943f9SDavid du Colombier 		/*
871906943f9SDavid du Colombier 		 * exabytes can't handle this, and
872906943f9SDavid du Colombier 		 * modeselect(10) is optional.
873906943f9SDavid du Colombier 		 */
874906943f9SDavid du Colombier 		if(SRmodeselect10(rp, mode, sizeof mode) != -1){
875906943f9SDavid du Colombier 			rp->lbsize = 1;
876906943f9SDavid du Colombier 			return 0;	/* success */
877906943f9SDavid du Colombier 		}
878906943f9SDavid du Colombier 		/* can't do 10-byte commands, back off to 6-byte ones */
879906943f9SDavid du Colombier 		rp->flags |= Fmode6;
880906943f9SDavid du Colombier 	}
881906943f9SDavid du Colombier 
882906943f9SDavid du Colombier 	/* 6-byte command */
883906943f9SDavid du Colombier 	memset(mode, 0, sizeof mode);
884906943f9SDavid du Colombier 	mode[2] = 0x10;		/* device-specific param. */
885906943f9SDavid du Colombier 	mode[3] = 8;		/* block descriptor length */
886906943f9SDavid du Colombier 	/*
887906943f9SDavid du Colombier 	 * bsd sez exabytes need this bit (NBE: no busy enable) in
888906943f9SDavid du Colombier 	 * vendor-specific page (0), but so far we haven't needed it.
889906943f9SDavid du Colombier 	mode[12] |= 8;
890906943f9SDavid du Colombier 	 */
891906943f9SDavid du Colombier 	if(SRmodeselect6(rp, mode, 4+8) == -1)
892906943f9SDavid du Colombier 		return -1;
893906943f9SDavid du Colombier 	rp->lbsize = 1;
894906943f9SDavid du Colombier 	return 0;
895906943f9SDavid du Colombier }
896906943f9SDavid du Colombier 
897906943f9SDavid du Colombier static int
wormdevopen(ScsiReq * rp)898906943f9SDavid du Colombier wormdevopen(ScsiReq *rp)
899906943f9SDavid du Colombier {
900906943f9SDavid du Colombier 	long status;
901906943f9SDavid du Colombier 	uchar list[MaxDirData];
902906943f9SDavid du Colombier 
903906943f9SDavid du Colombier 	if (SRstart(rp, 1) == -1 ||
904906943f9SDavid du Colombier 	    (status = SRmodesense10(rp, Allmodepages, list, sizeof list)) == -1)
905906943f9SDavid du Colombier 		return -1;
906906943f9SDavid du Colombier 	/* nbytes = list[0]<<8 | list[1]; */
907906943f9SDavid du Colombier 
908906943f9SDavid du Colombier 	/* # of bytes of block descriptors of 8 bytes each; not even 1? */
909906943f9SDavid du Colombier 	if((list[6]<<8 | list[7]) < 8)
910906943f9SDavid du Colombier 		rp->lbsize = 2048;
911906943f9SDavid du Colombier 	else
912906943f9SDavid du Colombier 		/* last 3 bytes of block 0 descriptor */
913906943f9SDavid du Colombier 		rp->lbsize = GETBE24(list+13);
9147d7728c9SDavid du Colombier 	if(debug)
9157d7728c9SDavid du Colombier 		fprint(2, "disk: wormdevopen: 10-byte logical block size %lud\n",
9167d7728c9SDavid du Colombier 			rp->lbsize);
917906943f9SDavid du Colombier 	return status;
918906943f9SDavid du Colombier }
919906943f9SDavid du Colombier 
920906943f9SDavid du Colombier int
SRopenraw(ScsiReq * rp,char * unit)921906943f9SDavid du Colombier SRopenraw(ScsiReq *rp, char *unit)
922906943f9SDavid du Colombier {
923906943f9SDavid du Colombier 	char name[128];
924906943f9SDavid du Colombier 
925906943f9SDavid du Colombier 	if(rp->flags & Fopen){
9267d7728c9SDavid du Colombier 		if(diskdebug)
9277d7728c9SDavid du Colombier 			fprint(2, "disk: opening open file\n");
928906943f9SDavid du Colombier 		rp->status = Status_BADARG;
929906943f9SDavid du Colombier 		return -1;
930906943f9SDavid du Colombier 	}
931906943f9SDavid du Colombier 	memset(rp, 0, sizeof *rp);
932906943f9SDavid du Colombier 	rp->unit = unit;
933906943f9SDavid du Colombier 
934e9b54818SDavid du Colombier 	snprint(name, sizeof name, "%s/raw", unit);
935906943f9SDavid du Colombier 	if((rp->fd = open(name, ORDWR)) == -1){
936906943f9SDavid du Colombier 		rp->status = STtimeout;
937906943f9SDavid du Colombier 		return -1;
938906943f9SDavid du Colombier 	}
939906943f9SDavid du Colombier 	rp->flags = Fopen;
940906943f9SDavid du Colombier 	return 0;
941906943f9SDavid du Colombier }
942906943f9SDavid du Colombier 
943906943f9SDavid du Colombier int
SRopen(ScsiReq * rp,char * unit)944906943f9SDavid du Colombier SRopen(ScsiReq *rp, char *unit)
945906943f9SDavid du Colombier {
946906943f9SDavid du Colombier 	if(SRopenraw(rp, unit) == -1)
947906943f9SDavid du Colombier 		return -1;
948906943f9SDavid du Colombier 	SRready(rp);
949906943f9SDavid du Colombier 	if(SRinquiry(rp) >= 0){
950906943f9SDavid du Colombier 		switch(rp->inquiry[0]){
951906943f9SDavid du Colombier 
952906943f9SDavid du Colombier 		default:
953906943f9SDavid du Colombier 			fprint(2, "unknown device type 0x%.2x\n", rp->inquiry[0]);
954906943f9SDavid du Colombier 			rp->status = Status_SW;
955906943f9SDavid du Colombier 			break;
956906943f9SDavid du Colombier 
957d5789509SDavid du Colombier 		case Devdir:
958d5789509SDavid du Colombier 		case Devcd:
959d5789509SDavid du Colombier 		case Devmo:
960906943f9SDavid du Colombier 			if(dirdevopen(rp) == -1)
961906943f9SDavid du Colombier 				break;
962906943f9SDavid du Colombier 			return 0;
963906943f9SDavid du Colombier 
964d5789509SDavid du Colombier 		case Devseq:
965906943f9SDavid du Colombier 			rp->flags |= Fseqdev;
966906943f9SDavid du Colombier 			if(seqdevopen(rp) == -1)
967906943f9SDavid du Colombier 				break;
968906943f9SDavid du Colombier 			return 0;
969906943f9SDavid du Colombier 
970d5789509SDavid du Colombier 		case Devprint:
971906943f9SDavid du Colombier 			rp->flags |= Fprintdev;
972906943f9SDavid du Colombier 			return 0;
973906943f9SDavid du Colombier 
974d5789509SDavid du Colombier 		case Devworm:
975906943f9SDavid du Colombier 			rp->flags |= Fwormdev;
976906943f9SDavid du Colombier 			if(wormdevopen(rp) == -1)
977906943f9SDavid du Colombier 				break;
978906943f9SDavid du Colombier 			return 0;
979906943f9SDavid du Colombier 
980d5789509SDavid du Colombier 		case Devjuke:
981906943f9SDavid du Colombier 			rp->flags |= Fchanger;
982906943f9SDavid du Colombier 			return 0;
983906943f9SDavid du Colombier 		}
984906943f9SDavid du Colombier 	}
985906943f9SDavid du Colombier 	SRclose(rp);
986906943f9SDavid du Colombier 	return -1;
987906943f9SDavid du Colombier }
988