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