|
|
1.1 root 1: /*
2: || dslib.c - library routines for /dev/scsi
3: ||
4: || Copyright 1988, 1989, by
5: || Gene Dronek (Vulcan Laboratory) and
6: || Rich Morin (Canta Forda Computer Laboratory).
7: || All rights reserved.
8: */
9: #ident "dslib.c: $Revision: 1.4 $"
10:
11: #include <stdio.h>
12: #include <sys/types.h>
13:
14: #include "dslib.h"
15: #ifdef aux
16: #include <sys/vio.h>
17: #include <sys/scsireq.h>
18: #endif aux
19:
20: int dsdebug=0;
21: long dsreqflags; /* flag bits always set by filldsreq */
22:
23: #define min(i,j) ( (i) < (j) ? (i) : (j) )
24:
25:
26: /*
27: || Startup/shutdown -----------------------------------------------
28: */
29:
30: static struct context *dsc[FDSIZ];
31:
32:
33: /*
34: || dsopen - open device, set up structures
35: */
36:
37: struct dsreq *
38: dsopen(opath, oflags)
39: char *opath;
40: int oflags;
41: {
42:
43: struct dsreq *dsp;
44: struct context *cp;
45: int fd;
46: DSDBG(fprintf(stderr,"dsopen(%s,%x) ", opath, oflags));
47:
48: fd = open(opath, oflags);
49: if (fd < 0)
50: return NULL; /* can't open */
51: if (dsc[fd] != NULL) /* already in use */
52: ds_zot("dsopen: fd already in use");
53:
54: cp = (struct context *) calloc(1, sizeof(struct context));
55: if (cp == NULL) /* can't allocate */
56: ds_zot("dsopen: can't allocate space");
57: dsc[fd] = cp;
58: cp->dsc_fd = fd;
59: dsp = &(cp->dsc_dsreq);
60:
61: dsp->ds_flags = 0;
62: dsp->ds_time = 10 * 1000; /* 10 second default timeout */
63: dsp->ds_private = (ulong) cp; /* pointer back to context */
64: dsp->ds_cmdbuf = cp->dsc_cmd;
65: dsp->ds_cmdlen = sizeof cp->dsc_cmd;
66: dsp->ds_databuf = 0;
67: dsp->ds_datalen = 0;
68: dsp->ds_sensebuf = cp->dsc_sense;
69: dsp->ds_senselen = sizeof cp->dsc_sense;
70: DSDBG(fprintf(stderr,"=>cp %x, dsp %x\n", cp, dsp));
71: return dsp;
72: }
73:
74:
75: /*
76: || dsclose - close device, release context struct.
77: */
78:
79: dsclose(dsp)
80: struct dsreq *dsp;
81: {
82: int fd;
83: struct context *cp;
84:
85: if (dsp == NULL)
86: ds_zot("dsclose: dsp is NULL");
87:
88: cp = (struct context *)dsp->ds_private;
89: fd = getfd(dsp);
90: if ( cp == NULL )
91: ds_zot("dsclose: private is NULL");
92:
93: cfree(cp);
94: dsc[fd] = (struct context *)NULL;
95: return;
96: }
97:
98:
99: /*
100: || Generic SCSI CCS Command functions ------------------------------------
101: ||
102: || dsp dsreq pointer
103: || data data buffer pointer
104: || datalen data buffer length
105: || lba logical block address
106: || vu vendor unique bits
107: */
108:
109: /*
110: || testunitready00 - issue group 0 "Test Unit Ready" command (0x00)
111: */
112:
113: testunitready00(dsp)
114: struct dsreq *dsp;
115: {
116: fillg0cmd(dsp, CMDBUF(dsp), G0_TEST, 0, 0, 0, 0, 0);
117: filldsreq(dsp, 0, 0, DSRQ_READ|DSRQ_SENSE);
118: return(doscsireq(getfd(dsp), dsp));
119: }
120:
121:
122: /*
123: || requestsense03 - issue group 0 "Request Sense" command (0x03)
124: */
125:
126: requestsense03(dsp, data, datalen, vu)
127: struct dsreq *dsp;
128: caddr_t data;
129: long datalen;
130: char vu;
131: {
132: fillg0cmd(dsp, CMDBUF(dsp), G0_REQU, 0, 0, 0, B1(datalen), B1(vu<<6));
133: filldsreq(dsp, data, datalen, DSRQ_READ);
134: return(doscsireq(getfd(dsp), dsp));
135: }
136:
137:
138: /*
139: || write0a - issue group 0 "Write" command (0x0a)
140: */
141:
142: write0a(dsp, data, datalen, lba, vu)
143: struct dsreq *dsp;
144: caddr_t data;
145: long datalen, lba;
146: char vu;
147: {
148: fillg0cmd(dsp, CMDBUF(dsp), G0_WRIT, B3(lba), B1(datalen), B1(vu<<6));
149: filldsreq(dsp, data, datalen, DSRQ_READ);
150: return(doscsireq(getfd(dsp), dsp));
151: }
152:
153:
154: /*
155: || inquiry12 - issue group 0 "Inquiry" command (0x12)
156: */
157:
158: inquiry12(dsp, data, datalen, vu)
159: struct dsreq *dsp;
160: caddr_t data;
161: long datalen;
162: char vu;
163: {
164: fillg0cmd(dsp, CMDBUF(dsp), G0_INQU, 0, 0, 0, B1(datalen), B1(vu<<6));
165: filldsreq(dsp, data, datalen, DSRQ_READ|DSRQ_SENSE);
166: return(doscsireq(getfd(dsp), dsp));
167: }
168:
169:
170: /*
171: || modeselect15 - issue group 0 "Mode Select" command (0x15)
172: ||
173: || save 0 - don't save saveable pages
174: || 1 - save saveable pages
175: */
176:
177: modeselect15(dsp, data, datalen, save, vu)
178: struct dsreq *dsp;
179: caddr_t data;
180: long datalen;
181: char save, vu;
182: {
183: fillg0cmd(dsp, CMDBUF(dsp), G0_MSEL, save&1, 0, 0, B1(datalen), B1(vu<<6));
184: filldsreq(dsp, data, datalen, DSRQ_WRITE|DSRQ_SENSE);
185: return(doscsireq(getfd(dsp), dsp));
186: }
187:
188:
189: /*
190: || modesense1a - issue group 0 "Mode Sense" command (0x1a)
191: ||
192: || pagectrl 0 - current values
193: || 1 - changeable values
194: || 2 - default values
195: || 3 - saved values
196: ||
197: || pagecode 0 - vendor unique
198: || 1 - error recovery
199: || 2 - disconnect/reconnect
200: || 3 - direct access dev. fmt.
201: || 4 - rigid disk geometry
202: || 5 - flexible disk
203: || 6-9 - see specific dev. types
204: || 0a - implemented options
205: || 0b - medium types supported
206: || 3f - return all pages
207: */
208:
209: modesense1a(dsp, data, datalen, pagectrl, pagecode, vu)
210: struct dsreq *dsp;
211: caddr_t data;
212: long datalen;
213: char pagectrl, pagecode, vu;
214: {
215: fillg0cmd(dsp, CMDBUF(dsp), G0_MSEN, 0x10,
216: ((pagectrl&3)<<6) | (pagecode&0x3F),
217: 0, B1(datalen), B1(vu<<6));
218: filldsreq(dsp, data, datalen, DSRQ_READ|DSRQ_SENSE);
219: return(doscsireq(getfd(dsp), dsp));
220: }
221:
222:
223: /*
224: || senddiagnostic1d - issue group 0 "Send Diagnostic" command (0x1d)
225: ||
226: || self 0 - run test, hold results
227: || 1 - run test, return status
228: ||
229: || dofl 0 - device online
230: || 1 - device offline
231: ||
232: || uofl 0 - unit online
233: || 1 - unit offline
234: */
235:
236: senddiagnostic1d(dsp, data, datalen, self, dofl, uofl, vu)
237: struct dsreq *dsp;
238: caddr_t data;
239: long datalen;
240: char self, dofl, uofl, vu;
241: {
242: fillg0cmd(dsp, CMDBUF(dsp), G0_MSEN,
243: (self&1)<<2 | (dofl&1)<<1 | (uofl&1),
244: 0, B2(datalen), B1(vu<<6));
245: filldsreq(dsp, data, datalen, DSRQ_READ|DSRQ_SENSE);
246: return(doscsireq(getfd(dsp), dsp));
247: }
248:
249:
250: /*
251: || readcapacity25 - issue group 1 "Read Capacity" command (0x25)
252: ||
253: || pmi 0 - return last logical block, entire unit
254: || 1 - return last logical block, current track
255: */
256:
257: readcapacity25(dsp, data, datalen, lba, pmi, vu)
258: struct dsreq *dsp;
259: caddr_t data;
260: long datalen, lba;
261: char pmi, vu;
262: {
263: fillg1cmd(dsp, CMDBUF(dsp), G1_RCAP, 0, B4(lba), 0, 0, pmi&1, B1(vu<<6));
264: filldsreq(dsp, data, datalen, DSRQ_READ|DSRQ_SENSE
265: /* |DSRQ_CTRL2 */ );
266: /* dsp->ds_time = 100; /* often takes a while */
267: return(doscsireq(getfd(dsp), dsp));
268: }
269:
270:
271: /*
272: || readextended28 - issue group 1 "Read Extended" command (0x28)
273: */
274:
275: readextended28(dsp, data, datalen, lba, vu)
276: struct dsreq *dsp;
277: caddr_t data;
278: long datalen, lba;
279: char vu;
280: {
281: fillg1cmd(dsp, CMDBUF(dsp), G1_READ, 0, B4(lba), 0, B2(datalen), B1(vu<<6));
282: filldsreq(dsp, data, datalen, DSRQ_READ|DSRQ_SENSE
283: /* |DSRQ_CTRL2 */ );
284: /* dsp->ds_time = 100; /* often takes a while */
285: return(doscsireq(getfd(dsp), dsp));
286: }
287:
288:
289: /*
290: || writeextended2a - issue group 1 "Write Extended" command (0x2a)
291: */
292:
293: writeextended2a(dsp, data, datalen, lba, vu)
294: struct dsreq *dsp;
295: caddr_t data;
296: long datalen, lba;
297: char vu;
298: {
299: fillg1cmd(dsp, CMDBUF(dsp), G1_WRIT, 0, B4(lba), 0, B2(datalen), B1(vu<<6));
300: filldsreq(dsp, data, datalen, DSRQ_READ|DSRQ_SENSE
301: /* |DSRQ_CTRL2 */ );
302: /* dsp->ds_time = 100; /* often takes a while */
303: return(doscsireq(getfd(dsp), dsp));
304: }
305:
306:
307: /*
308: || Support functions ----------------------------------------------------
309: */
310:
311: /*
312: || fillg0cmd - Fill a Group 0 command buffer
313: */
314:
315: fillg0cmd(dsp, cmd, b0,b1,b2,b3,b4,b5)
316: struct dsreq *dsp;
317: uchar_t *cmd, b0,b1,b2,b3,b4,b5;
318: {
319: uchar_t *c = cmd;
320: DSDBG(fprintf(stderr,"fillg0cmd(%x,%x, %02x %02x %02x %02x %02x %02x)\n",
321: dsp, cmd, b0,b1,b2,b3,b4,b5));
322: *c++ = b0, *c++ = b1, *c++ = b2, *c++ = b3, *c++ = b4, *c++ = b5;
323:
324: CMDBUF(dsp) = (caddr_t) cmd;
325: CMDLEN(dsp) = 6;
326: }
327:
328:
329: /*
330: || fillg1cmd - Fill a Group 1 command buffer
331: */
332:
333: fillg1cmd(dsp, cmd, b0,b1,b2,b3,b4,b5,b6,b7,b8,b9)
334: struct dsreq *dsp;
335: uchar_t *cmd, b0,b1,b2,b3,b4,b5,b6,b7,b8,b9;
336: {
337: uchar_t *c = cmd;
338: DSDBG(fprintf(stderr,
339: "fillg1cmd(%x,%x, %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x)\n",
340: dsp, cmd, b0,b1,b2,b3,b4,b5,b6,b7,b8,b9));
341:
342: *c++ = b0, *c++ = b1, *c++ = b2, *c++ = b3, *c++ = b4, *c++ = b5;
343: *c++ = b6, *c++ = b7, *c++ = b8, *c++ = b9;
344:
345: CMDBUF(dsp) = (caddr_t) cmd;
346: CMDLEN(dsp) = 10;
347: }
348:
349:
350: /*
351: || filldsreq - Fill a dsreq structure
352: */
353:
354: filldsreq(dsp,data,datalen,flags)
355: struct dsreq *dsp;
356: uchar_t *data;
357: {
358: DSDBG(fprintf(stderr,"filldsreq(%x,%x,%d,%x) cmdlen %d\n",
359: dsp,data,datalen,flags,CMDLEN(dsp)));
360: dsp->ds_flags = flags | dsreqflags |
361: (((dsdebug&1) ? DSRQ_TRACE : 0) |
362: ((dsdebug&2) ? DSRQ_PRINT : 0));
363: dsp->ds_time = 10 * 1000; /* default to 10 seconds */
364: dsp->ds_link = 0;
365: dsp->ds_synch = 0;
366: dsp->ds_ret = 0;
367:
368: DATABUF(dsp) = (caddr_t) data;
369: DATALEN(dsp) = datalen;
370: }
371:
372:
373: /*
374: || bprint - print array of bytes, in hex.
375: */
376:
377: #define hex(x) "0123456789ABCDEF" [ (x) & 0xF ]
378:
379: bprint(s,n,nperline,space)
380: char *s;
381: {
382: int i, x;
383: char *sp = (space) ? " ": "";
384:
385: for(i=0;i<n;i++) {
386: x = s[i];
387: fprintf(stderr,((i%4==3)?"%c%c%s%s":"%c%c%s"),
388: hex(x>>4), hex(x), sp, sp);
389: if ( i%nperline == (nperline - 1) )
390: fprintf(stderr,"\n");
391: }
392: if ( space )
393: fprintf(stderr,"\n");
394: }
395:
396:
397: /*
398: || doscsireq - issue scsi command, return status or -1 error.
399: */
400:
401: doscsireq( fd, dsp)
402: int fd; /* ioctl file descriptor */
403: struct dsreq *dsp; /* devscsi request packet */
404: {
405: int cc;
406: int retries = 4;
407: uchar_t sbyte;
408:
409: DSDBG(fprintf(stderr,"doscsireq(%d,%x) %x ---- %s\n",fd,dsp,
410: (CMDBUF(dsp))[0],
411: ds_vtostr( (CMDBUF(dsp))[0], cmdnametab)));
412:
413: /*
414: * loop, issuing command
415: * until done, or further retry pointless
416: */
417:
418: while ( --retries > 0 ) {
419:
420: caddr_t sp;
421:
422: sp = SENSEBUF(dsp);
423: DSDBG(fprintf(stderr,"cmdbuf = ");
424: bprint(CMDBUF(dsp),CMDLEN(dsp),16,1));
425: if ( (dsp->ds_flags & DSRQ_WRITE) )
426: DSDBG(bprint( DATABUF(dsp), min(50,DATALEN(dsp)),16,1 ));
427:
428: DSDBG(fprintf(stderr,"databuf datalen %x %d\n",DATABUF(dsp), DATALEN(dsp)));
429: cc = ioctl( fd, DS_ENTER, dsp);
430: if ( cc < 0) {
431: ds_panic(dsp, "cannot ioctl fd %d\n",fd);
432: }
433:
434: DSDBG(fprintf(stderr,"cmdlen after ioctl=%d\n",CMDLEN(dsp)));
435: DSDBG(fprintf(stderr,"ioctl=%d ret=%x %s",
436: cc, RET(dsp),
437: RET(dsp) ? ds_vtostr(RET(dsp),dsrtnametab) : ""));
438: DSDBG(if (SENSESENT(dsp)) fprintf(stderr," sensesent=%d",
439: SENSESENT(dsp)));
440:
441: DSDBG(fprintf(stderr,
442: " cmdsent=%d datasent=%d sbyte=%x %s\n",
443: CMDSENT(dsp), DATASENT(dsp), STATUS(dsp),
444: ds_vtostr(STATUS(dsp), cmdstatustab)));
445: DSDBG(if ( FLAGS(dsp) & DSRQ_READ )
446: bprint( DATABUF(dsp), min(16*16,DATASENT(dsp)), 16,1));
447:
448: #ifdef aux
449: /*
450: * check for AUX bus-error
451: * we retry with poll-dma
452: */
453: if ( RET(dsp) == DSRT_AGAIN ) {
454: int n = SDC_RDPOLL|SDC_WRPOLL;
455: DSDBG(fprintf(stderr,"setting rd/wr-poll"));
456: cc = ioctl( fd, DS_SET, n); /* set bits */
457: if ( cc != 0 )
458: return -1;
459: }
460: #endif aux
461:
462: if ( RET(dsp) == DSRT_NOSEL )
463: continue; /* retry noselect 3X */
464:
465: /* decode sense data returned */
466: if ( SENSESENT(dsp) ) {
467: DSDBG(
468: fprintf(stderr, "sense key %x - %s\n",
469: SENSEKEY(sp),
470: ds_vtostr( SENSEKEY(sp), sensekeytab));
471: bprint( SENSEBUF(dsp),
472: min(100, SENSESENT(dsp)),
473: 16,1);
474: );
475: }
476: DSDBG(fprintf(stderr, "sbyte %x\n", STATUS(dsp)));
477:
478: /* decode scsi command status byte */
479: sbyte = STATUS(dsp);
480: switch (sbyte) {
481: case 0x08: /* BUSY */
482: case 0x18: /* RESERV CONFLICT */
483: sleep(2);
484: continue;
485: case 0x00: /* GOOD */
486: case 0x02: /* CHECK CONDITION */
487: case 0x10: /* INTERM/GOOD */
488: default:
489: return sbyte;
490: }
491: }
492: return -1; /* fail retry limit */
493: }
494:
495:
496: /*
497: || opttovar - lookup option in table, return var addr (NULL if fail)
498: */
499:
500: int *
501: opttovar( ostr, table)
502: char *ostr;
503: struct opttab{
504: char *opt;
505: int *var;
506: } *table;
507: {
508: register struct opttab *tp;
509:
510: for (tp=table; (tp->var); tp++)
511: if ( strncmp( ostr, tp->opt, 3) == 0 )
512: break;
513:
514: if ( !tp->var )
515: fprintf(stderr,"unknown option %s", ostr);
516:
517: return (tp->var);
518: }
519:
520:
521: /*
522: || ds_vtostr - lookup value in table to return string pointer
523: */
524:
525: char *
526: ds_vtostr( v, table)
527: long v;
528: struct vtab *table;
529: {
530: register struct vtab *tp;
531:
532: for (tp=table; (tp->string); tp++)
533: if ( v == tp->val )
534: break;
535:
536: return (tp->string) ? tp->string : "";
537: }
538:
539:
540: /*
541: || ds_panic - yelp, leave...
542: */
543:
544: ds_panic( fmt, v)
545: char *fmt;
546: int v;
547: {
548: extern errno;
549:
550: fprintf(stderr,fmt,v);
551: fprintf(stderr,"\nerrno = %d\n",errno);
552: exit(1);
553: }
554:
555:
556: /*
557: || ds_zot - go away, with a message.
558: */
559:
560: ds_zot(message)
561: char *message;
562: {
563: fprintf(stderr, "%s\n", message);
564: exit(1);
565: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.