|
|
1.1 root 1: /* @(#)st.c 1.1 86/02/03 SMI */
2:
3: /*
4: * Copyright (c) 1985 by Sun Microsystems, Inc.
5: */
6:
7: #include "st.h"
8: #if NST > 0
9:
10: /*
11: * Driver for Sysgen SC400 and Emulex MT02 SCSI tape controller.
12: */
13:
14: #include "../h/param.h"
15: #include "../h/systm.h"
16: #include "../h/buf.h"
17: #include "../h/dir.h"
18: #include "../h/conf.h"
19: #include "../h/user.h"
20: #include "../h/file.h"
21: #include "../h/map.h"
22: #include "../h/vm.h"
23: #include "../h/mtio.h"
24: #include "../h/cmap.h"
25:
26: #include "../sun/dklabel.h"
27: #include "../sun/dkio.h"
28: #include "../machine/psl.h"
29: #include "../machine/mmu.h"
30: #include "../machine/cpu.h"
31: #include "../sundev/mbvar.h"
32: #include "../sundev/screg.h"
33: #include "../sundev/sireg.h"
34: #include "../sundev/scsi.h"
35: #include "../sundev/streg.h"
36:
37: #define INF 1000000000
38: /*
39: * Max # of buffers outstanding per unit.
40: */
41: #define MAXSTBUF 3
42:
43: /*
44: * Bits in minor device.
45: */
46: #define STUNIT(dev) (minor(dev) & 03)
47: #define T_NOREWIND 04
48: #define QIC_24 8
49:
50: extern struct scsi_unit stunits[];
51: extern struct scsi_unit_subr scsi_unit_subr[];
52: extern struct scsi_tape stape[];
53: extern int nstape;
54:
55: /*
56: * Return a pointer to this unit's unit structure.
57: */
58: stunitptr(md)
59: register struct mb_device *md;
60: {
61: return ((int)&stunits[md->md_unit]);
62: }
63:
64: /*
65: * Attach device (boot time).
66: */
67: stattach(md)
68: register struct mb_device *md;
69: {
70: register struct scsi_unit *un;
71: register struct scsi_tape *dsi;
72:
73: un = &stunits[md->md_unit];
74: dsi = &stape[md->md_unit];
75: un->un_md = md;
76: un->un_mc = md->md_mc;
77: un->un_unit = md->md_unit;
78: un->un_target = TARGET(md->md_slave);
79: un->un_lun = LUN(md->md_slave);
80: un->un_ss = &scsi_unit_subr[TYPE(md->md_flags)];
81: dsi->un_ctype = ST_TYPE_INVALID;
82: dsi->un_openf = CLOSED;
83: }
84:
85: stinit(dev)
86: dev_t dev;
87: {
88: register int unit;
89: register struct scsi_tape *dsi;
90:
91: unit = STUNIT(dev);
92: dsi = &stape[unit];
93:
94: dsi->un_ctype = 1;
95: dsi->un_openf = OPENING;
96: stcmd(dev, SC_TEST_UNIT_READY, 0);
97: if (stcmd(dev, SC_REQUEST_SENSE, 0) == 0 || dsi->un_openf != OPEN) {
98: dsi->un_openf = OPENING;
99: if (stcmd(dev, SC_REQUEST_SENSE, 0) == 0 ||
100: dsi->un_openf != OPEN) {
101: if (stcmd(dev, SC_REQUEST_SENSE, 0) == 0 ||
102: dsi->un_openf != OPEN) {
103: if (dsi->un_openf == OPEN_FAILED) {
104: uprintf("st%d: no cartridge loaded\n",
105: unit);
106: } else {
107: uprintf("st%d: tape not online \n",
108: unit);
109: }
110: dsi->un_openf = CLOSED;
111: dsi->un_ctype = ST_TYPE_INVALID;
112: return (0);
113: }
114: }
115: }
116: dsi->un_openf = CLOSED;
117: return (1);
118: }
119:
120: sctopen(dev, flag)
121: dev_t dev;
122: int flag;
123: {
124: register struct scsi_unit *un;
125: register int unit, s;
126: register struct scsi_tape *dsi;
127: register int i;
128:
129: unit = STUNIT(dev);
130: if (unit > nstape) {
131: u.u_error = ENXIO;
132: return;
133: }
134: un = &stunits[unit];
135: dsi = &stape[unit];
136: if (un->un_mc == 0) { /* never attached */
137: u.u_error = ENXIO;
138: return;
139: }
140:
141: /* determine type of tape controller */
142: if (dsi->un_ctype == ST_TYPE_INVALID) {
143: if (stinit(dev) == 0) {
144: u.u_error = EIO;
145: return;
146: }
147: }
148:
149: s = spl6();
150: if (dsi->un_openf != CLOSED) { /* already open */
151: (void) splx(s);
152: u.u_error = EBUSY;
153: return;
154: }
155: dsi->un_openf = OPEN;
156: (void) splx(s);
157: dsi->un_read_only = 0;
158:
159: /* must be qic 24 format */
160: if (!(minor(dev) & QIC_24)) {
161: dsi->un_openf = CLOSED;
162: u.u_error = EIO;
163: return;
164: }
165: if ((flag & FWRITE) && dsi->un_read_only) {
166: uprintf("st%d: cartridge is write protected \n", unit);
167: dsi->un_openf = CLOSED;
168: u.u_error = EIO;
169: return;
170: }
171: dsi->un_lastiow = 0;
172: dsi->un_lastior = 0;
173: dsi->un_next_block = 0;
174: dsi->un_last_block = INF;
175: /* if we reset these here they will never be preserved for "mt status"
176: dsi->un_retry_ct = 0;
177: dsi->un_underruns = 0;
178: */
179: u.u_error = 0;
180: return;
181: }
182:
183: /*ARGSUSED*/
184: sctclose(dev, flag)
185: register dev_t dev;
186: int flag;
187: {
188: register struct scsi_unit *un;
189: register struct scsi_tape *dsi;
190:
191: un = &stunits[STUNIT(dev)];
192: dsi = &stape[STUNIT(dev)];
193: dsi->un_openf = CLOSING;
194: if (dsi->un_lastiow) {
195: if (stcmd(dev, SC_WRITE_FILE_MARK, 0) == 0) {
196: printf("st%d: stclose failed to write file mark\n",
197: un - stunits);
198: }
199: }
200: if ((minor(dev) & T_NOREWIND) == 0) {
201: (void) stcmd(dev, SC_REWIND, -1);
202: }
203: dsi->un_openf = CLOSED;
204: }
205:
206: stcmd(dev, cmd, count)
207: dev_t dev;
208: int cmd, count;
209: {
210: register struct buf *bp;
211: register int s, error;
212: register struct scsi_unit *un;
213:
214: un = &stunits[STUNIT(dev)];
215: bp = &un->un_sbuf;
216: s = splx(pritospl(un->un_mc->mc_intpri));
217: while (bp->b_flags & B_BUSY) {
218: /*
219: * special test because B_BUSY never gets cleared in
220: * the non-waiting rewind case.
221: */
222: if (bp->b_bcount == -1 && (bp->b_flags & B_DONE)) {
223: break;
224: }
225: bp->b_flags |= B_WANTED;
226: sleep((caddr_t) bp, PRIBIO);
227: }
228: bp->b_flags = B_BUSY | B_READ;
229: (void) splx(s);
230: bp->b_dev = dev;
231: bp->b_bcount = count;
232: un->un_scmd = cmd;
233: ststrategy(bp);
234: /*
235: * In case of rewind on close, don't wait.
236: */
237: if (cmd == SC_REWIND && count == -1) {
238: return (1);
239: }
240: s = splx(pritospl(un->un_mc->mc_intpri));
241: while ((bp->b_flags & B_DONE) == 0) {
242: sleep((caddr_t) bp, PRIBIO);
243: }
244: (void) splx(s);
245: error = geterror(bp);
246: if (bp->b_flags & B_WANTED) {
247: wakeup((caddr_t) bp);
248: }
249: bp->b_flags &= B_ERROR; /* clears B_BUSY */
250: return (error == 0);
251: }
252:
253: ststrategy(bp)
254: register struct buf *bp;
255: {
256: register struct scsi_unit *un;
257: register int unit, s;
258: register struct buf *ap;
259: register struct scsi_tape *dsi;
260:
261: unit = STUNIT(bp->b_dev);
262: if (unit > nstape) {
263: printf("st%d: ststrategy: invalid unit %x\n", unit, unit);
264: bp->b_flags |= B_ERROR;
265: iodone(bp);
266: return;
267: }
268: un = &stunits[unit];
269: dsi = &stape[unit];
270: if (dsi->un_openf != OPEN && bp != &un->un_sbuf) {
271: bp->b_flags |= B_ERROR;
272: iodone(bp);
273: return;
274: }
275: s = splx(pritospl(un->un_mc->mc_intpri));
276: while (dsi->un_bufcnt >= MAXSTBUF) {
277: sleep((caddr_t) &dsi->un_bufcnt, PRIBIO);
278: }
279: dsi->un_bufcnt++;
280:
281: /*
282: * Put the block at the end of the queue.
283: * Should probably have a pointer to the end of
284: * the queue, but the queue can't get too long,
285: * so the added code complexity probably isn't
286: * worth it.
287: */
288: ap = &un->un_utab;
289: while (ap->b_actf != NULL) {
290: ap = ap->b_actf;
291: }
292: ap->b_actf = bp;
293: bp->b_actf = NULL;
294: if (un->un_utab.b_active == 0) {
295: (*un->un_c->c_ss->scs_ustart)(un);
296: bp = &un->un_mc->mc_tab;
297: if (bp->b_actf && bp->b_active == 0) {
298: (*un->un_c->c_ss->scs_start)(un);
299: }
300: }
301: (void) splx(s);
302: }
303:
304: /*
305: * Start the operation.
306: */
307: /*ARGSUSED*/
308: ststart(bp, un)
309: register struct buf *bp;
310: register struct scsi_unit *un;
311: {
312: register int bno;
313: register struct scsi_tape *dsi;
314:
315: dsi = &stape[STUNIT(bp->b_dev)];
316: /*
317: * Default is that last command was NOT a read/write command;
318: * if we issue a read/write command we will notice this in stintr().
319: */
320: dsi->un_lastiow = 0;
321: dsi->un_lastior = 0;
322: if (bp == &un->un_sbuf) {
323: un->un_cmd = un->un_scmd;
324: un->un_count = bp->b_bcount;
325: } else if (bp == &un->un_rbuf) {
326: if (bp->b_flags & B_READ) {
327: if (dsi->un_eof) {
328: bp->b_resid = bp->b_bcount;
329: iodone(bp);
330: if (dsi->un_bufcnt-- >= MAXSTBUF) {
331: wakeup((caddr_t) &dsi->un_bufcnt);
332: }
333: return (0);
334: }
335: un->un_cmd = SC_READ;
336: } else {
337: un->un_cmd = SC_WRITE;
338: }
339: un->un_count = howmany(bp->b_bcount, DEV_BSIZE);
340: un->un_flags |= SC_UNF_DVMA;
341: } else {
342: bno = bp->b_blkno;
343: if (bno > dsi->un_last_block && bp->b_flags & B_READ) {
344: /*
345: * Can't read past EOF.
346: */
347: bp->b_flags |= B_ERROR;
348: bp->b_error = EIO;
349: iodone(bp);
350: if (dsi->un_bufcnt-- >= MAXSTBUF) {
351: wakeup((caddr_t) &dsi->un_bufcnt);
352: }
353: return (0);
354: }
355: if (bno == dsi->un_last_block && bp->b_flags & B_READ) {
356: /*
357: * Reading at EOF returns 0 bytes.
358: */
359: bp->b_resid = bp->b_bcount;
360: iodone(bp);
361: if (dsi->un_bufcnt-- >= MAXSTBUF) {
362: wakeup((caddr_t) &dsi->un_bufcnt);
363: }
364: return (0);
365: }
366: if ((bp->b_flags & B_READ) == 0) {
367: /*
368: * Writing sets EOF.
369: */
370: dsi->un_last_block = bno + 1;
371: }
372: if (bno != dsi->un_next_block) {
373: /*
374: * Not the next record.
375: * In theory we could space forward, or even rewind
376: * and space forward, and maybe someday we will.
377: * For now, no one really needs this capability.
378: */
379: bp->b_flags |= B_ERROR;
380: bp->b_error = ENXIO;
381: iodone(bp);
382: if (dsi->un_bufcnt-- >= MAXSTBUF) {
383: wakeup((caddr_t) &dsi->un_bufcnt);
384: }
385: return (0);
386: }
387: /*
388: * Position OK, we can do the read or write.
389: */
390: if (bp->b_flags & B_READ) {
391: un->un_cmd = SC_READ;
392: } else {
393: un->un_cmd = SC_WRITE;
394: }
395: un->un_count = howmany(bp->b_bcount, DEV_BSIZE);
396: un->un_flags |= SC_UNF_DVMA;
397: }
398: bp->b_resid = 0;
399: return (1);
400: }
401:
402: /*
403: * Make a command description block.
404: */
405: stmkcdb(c, un)
406: register struct scsi_ctlr *c;
407: register struct scsi_unit *un;
408: {
409: register struct scsi_cdb *cdb;
410: register struct scsi_tape *dsi;
411: int density = 0;
412:
413: cdb = &c->c_cdb;
414: bzero((caddr_t)cdb, sizeof (*cdb));
415: cdb->cmd = un->un_cmd;
416: cdb->lun = un->un_lun;
417: un->un_dma_addr = un->un_dma_count = 0;
418: dsi = &stape[un->un_unit];
419:
420: switch (un->un_cmd) {
421:
422: case SC_WRITE_FILE_MARK:
423: case SC_LOAD:
424: cdb->count = 1;
425: break;
426:
427: case SC_TEST_UNIT_READY:
428: break;
429:
430: case SC_REWIND:
431: break;
432:
433: case SC_ERASE_CARTRIDGE:
434: cdb->t_code = 1;
435: break;
436:
437: case SC_REQUEST_SENSE:
438: un->un_dma_addr = (int)c->c_sense - (int)DVMA;
439: un->un_dma_count = cdb->count = sizeof (struct st_archive_sense);
440: break;
441:
442: case SC_READ:
443: case SC_WRITE:
444: cdb->t_code = 1;
445: cdb->high_count = un->un_count >> 16;
446: cdb->mid_count = (un->un_count >> 8) & 0xFF;
447: cdb->low_count = un->un_count & 0xFF;
448: un->un_dma_addr = un->un_baddr;
449: un->un_dma_count = un->un_count * DEV_BSIZE;
450: break;
451:
452: case SC_SPACE_FILE:
453: if (un->un_count == 0)
454: cdb->t_code = 3; /* space to end */
455: else
456: cdb->t_code = 1; /* space files, not records */
457: /* fall through ... */
458:
459: case SC_SPACE_REC:
460: cdb->cmd = SC_SPACE;
461: cdb->high_count = un->un_count >> 16;
462: cdb->mid_count = (un->un_count >> 8) & 0xFF;
463: cdb->low_count = un->un_count & 0xFF;
464: un->un_dma_addr = un->un_dma_count = 0;
465: break;
466:
467: default:
468: printf("st%d: stmkcdb: invalid command %x\n", un - stunits,
469: un->un_cmd);
470: break;
471: }
472: }
473:
474: stintr(c, resid, error)
475: register struct scsi_ctlr *c;
476: register int resid, error;
477: {
478: register struct scsi_unit *un;
479: register struct buf *bp;
480: register struct scsi_tape *dsi;
481: struct st_archive_sense *ars;
482:
483: un = c->c_un;
484: bp = un->un_mc->mc_tab.b_actf->b_actf;
485: dsi = &stape[STUNIT(bp->b_dev)];
486: ars = (struct st_archive_sense *)c->c_sense;
487:
488: /*
489: * We determine which tape controller we have by the number of
490: * sense bytes we get back.
491: */
492: if (dsi->un_openf == OPENING && un->un_cmd == SC_REQUEST_SENSE) {
493: if (resid || ST_NO_CART(dsi, c->c_sense)) {
494: dsi->un_openf = OPEN_FAILED;
495: } else {
496: dsi->un_openf = OPEN;
497: if (ST_WRITE_PROT(dsi, c->c_sense))
498: dsi->un_read_only = 1;
499: }
500: }
501:
502: if (c->c_scb.busy)
503: bp->b_flags |= B_ERROR;
504: else if (error || c->c_scb.chk || resid > 0) {
505: if (c->c_scb.chk && ST_RESET(dsi, c->c_sense)) {
506: /*
507: * Power on or reset occurred
508: */
509: dsi->un_reset_occurred = 1;
510: bp->b_flags |= B_ERROR;
511: } else if (c->c_scb.chk && ST_NO_CART(dsi, c->c_sense)) {
512: printf("st%d: no cartridge loaded \n",
513: un - stunits);
514: bp->b_flags |= B_ERROR;
515: } else if (c->c_scb.chk && ST_FILE_MARK(dsi, c->c_sense)) {
516: /*
517: * File mark detected.
518: */
519: dsi->un_eof = 1;
520: switch (un->un_cmd) {
521: case SC_READ:
522: dsi->un_next_block += un->un_count -
523: resid / DEV_BSIZE;
524: dsi->un_last_block = dsi->un_next_block;
525: break;
526: case SC_SPACE_REC:
527: dsi->un_last_block = dsi->un_next_block +=
528: un->un_count; /* a little high */
529: break;
530: default:
531: printf("st%d: scsi tape hit eof on cmd %x\n",
532: un - stunits, un->un_cmd);
533: break;
534: }
535: bp->b_resid = resid;
536: } else if ((un->un_cmd == SC_WRITE ||
537: un->un_cmd == SC_WRITE_FILE_MARK) &&
538: c->c_scb.chk && ST_WRITE_PROT(dsi, c->c_sense)) {
539: /*
540: * Write protected tape.
541: */
542: printf("st%d: tape is write protected \n, ",
543: un - stunits);
544: dsi->un_read_only = 1;
545: bp->b_flags |= B_ERROR;
546: } else if (c->c_scb.chk && ST_EOT(dsi, c->c_sense)) {
547: /*
548: * End of tape.
549: */
550: bp->b_resid = bp->b_bcount;
551: if (un->un_cmd == SC_WRITE) {
552: /*
553: * Setting this flag makes stclose()
554: * write a file mark before closing.
555: * Until a file mark is written, the
556: * tape will return invalid command
557: * indications and not respond to
558: * rewinds.
559: */
560: dsi->un_lastiow = 1;
561: }
562: } else if (c->c_scb.chk && ST_ILLEGAL(dsi, c->c_sense)) {
563: printf("st%d: illegal command 0x%x\n", un-stunits, un->un_cmd);
564: bp->b_flags |= B_ERROR;
565: } else if (ST_CORRECTABLE(dsi, c->c_sense))
566: goto success;
567: else if (ST_EOD(dsi, c->c_sense))
568: bp->b_flags |= B_ERROR;
569: else {
570: /*
571: * Some other error which we can't handle.
572: */
573: if ((c->c_scb.chk && dsi->un_openf == OPEN))
574: st_pr_sense(c, dsi);
575: bp->b_flags |= B_ERROR;
576: }
577: } else {
578: success:
579: switch (un->un_cmd) {
580:
581: case SC_REWIND:
582: case SC_ERASE_CARTRIDGE:
583: case SC_MODE_SELECT:
584: case SC_LOAD:
585: dsi->un_next_block = 0;
586: dsi->un_eof = 0;
587: break;
588:
589: case SC_WRITE:
590: dsi->un_lastiow = 1;
591: dsi->un_next_block += un->un_count;
592: break;
593:
594: case SC_READ:
595: dsi->un_lastior = 1;
596: dsi->un_next_block += un->un_count;
597: break;
598:
599: case SC_SPACE_FILE:
600: dsi->un_next_block = 0;
601: dsi->un_last_block = INF;
602: dsi->un_eof = 0;
603: break;
604:
605: case SC_SPACE_REC:
606: dsi->un_next_block += un->un_count;
607: break;
608:
609: case SC_REQUEST_SENSE:
610: dsi->un_status = ((char *)ars)[2];
611: /*
612: if (ars->ext_sense.add_len >= AR_ES_ADD_LEN) {
613: dsi->un_retry_ct +=
614: (ars->retries_msb << 8) +
615: ars->retries_lsb;
616: }
617: */
618: break;
619:
620: case SC_TEST_UNIT_READY:
621: break;
622:
623: case SC_WRITE_FILE_MARK:
624: dsi->un_next_block = 0;
625: dsi->un_last_block = 0; /* i.e. no reads allowed */
626: break;
627:
628: default:
629: printf("st%d: stintr: invalid command %x\n",
630: un - stunits, un->un_cmd);
631: break;
632: }
633: }
634: if (bp == &un->un_sbuf &&
635: ((un->un_flags & SC_UNF_DVMA) == 0)) {
636: (*c->c_ss->scs_done)(un->un_mc);
637: } else {
638: mbdone(un->un_mc);
639: un->un_flags &= ~SC_UNF_DVMA;
640: }
641: if (dsi->un_bufcnt-- >= MAXSTBUF) {
642: wakeup((caddr_t) &dsi->un_bufcnt);
643: }
644: }
645:
646: st_pr_sense(c, dsi)
647: register struct scsi_ctlr *c;
648: register struct scsi_tape *dsi;
649: {
650: register struct scsi_unit *un;
651: register u_char *cp;
652: register int i;
653:
654: un = c->c_un;
655: cp = (u_char *)c->c_sense;
656: printf("st%d: stintr: sense ", un - stunits);
657: for (i=0; i < sizeof (struct st_archive_sense); i++)
658: printf("%x ", *cp++);
659: printf("\n");
660: }
661:
662: sctread(dev)
663: register dev_t dev;
664: {
665: register struct scsi_unit *un;
666: register int unit, r, resid;
667: register struct scsi_tape *dsi;
668:
669: unit = STUNIT(dev);
670: if (unit > nstape) {
671: u.u_error = ENXIO;
672: return;
673: }
674: un = &stunits[unit];
675: dsi = &stape[unit];
676: if (u.u_count % DEV_BSIZE) {
677: u.u_error = ENXIO;
678: return; /* drive can't do it */
679: }
680: resid = u.u_count;
681: dsi->un_next_block = u.u_offset / DEV_BSIZE;
682: dsi->un_last_block = INF;
683: physio(ststrategy, &un->un_rbuf, dev, B_READ, minphys);
684: if (dsi->un_eof && u.u_count == resid) {
685: dsi->un_eof = 0; /* the user is really getting it */
686: }
687: }
688:
689: sctwrite(dev)
690: register dev_t dev;
691: {
692: register struct scsi_unit *un;
693: register int unit;
694: register struct scsi_tape *dsi;
695:
696: unit = STUNIT(dev);
697: if (unit > nstape) {
698: u.u_error = ENXIO;
699: return;
700: }
701: un = &stunits[unit];
702: dsi = &stape[unit];
703: dsi->un_next_block = u.u_offset / DEV_BSIZE;
704: dsi->un_last_block = INF;
705: physio(ststrategy, &un->un_rbuf, dev, B_WRITE, minphys);
706: }
707:
708: /*ARGSUSED*/
709: sctioctl(dev, cmd, data, flag)
710: register dev_t dev;
711: register int cmd;
712: register caddr_t data;
713: int flag;
714: {
715: register int fcount;
716: struct mtop mtop;
717: struct mtget mtget;
718: register int unit;
719: register struct scsi_tape *dsi;
720: static int ops[] = {
721: SC_WRITE_FILE_MARK, /* write tape mark */
722: SC_SPACE_FILE, /* forward space file */
723: SC_SPACE_FILE, /* backspace file */
724: SC_SPACE_REC, /* forward space record */
725: SC_SPACE_REC, /* backspace record */
726: SC_REWIND, /* rewind tape */
727: SC_REWIND, /* unload - we just rewind */
728: SC_REQUEST_SENSE, /* get status */
729: SC_REWIND, /* retension - rewind + vu_57 */
730: SC_ERASE_CARTRIDGE, /* erase entire tape */
731: };
732:
733: unit = STUNIT(dev);
734: if (unit > nstape) {
735: u.u_error = ENXIO;
736: return;
737: }
738: dsi = &stape[unit];
739: switch (cmd) {
740: case MTIOCTOP: /* tape operation */
741: if (copyin((caddr_t)data, (caddr_t)&mtop, sizeof(mtop))) {
742: u.u_error = EFAULT;
743: return;
744: }
745: switch (mtop.mt_op) {
746: case MTWEOF:
747: case MTERASE:
748: if (dsi->un_read_only) {
749: u.u_error = ENXIO;
750: return;
751: }
752: }
753:
754: switch (mtop.mt_op) {
755: case MTBSF:
756: case MTBSR:
757: fcount = -mtop.mt_count;
758: break;
759: case MTRETEN:
760: dsi->un_reten_rewind = 1;
761: /* FALL THRU */
762: case MTFSF:
763: fcount = mtop.mt_count;
764: if (fcount == -1)
765: fcount = 0;
766: case MTWEOF:
767: case MTREW:
768: case MTOFFL:
769: case MTNOP:
770: case MTERASE:
771: fcount = mtop.mt_count;
772: break;
773: default:
774: u.u_error = ENXIO;
775: return;
776: }
777: /*
778: * If eof_flag then we hit eof but didn't tell the user yet.
779: */
780: if (ops[mtop.mt_op] == SC_SPACE_FILE && dsi->un_eof) {
781: dsi->un_eof = 0;
782: if (mtop.mt_op == MTFSF)
783: fcount--;
784: }
785: if (stcmd(dev, ops[mtop.mt_op], fcount) == 0)
786: u.u_error = EIO;
787: return;
788:
789: case MTIOCGET:
790: if (stcmd(dev, SC_REQUEST_SENSE, 0) == 0) {
791: u.u_error = EIO;
792: return;
793: }
794: mtget.mt_type = MT_ISSC;
795: mtget.mt_erreg = dsi->un_status;
796: mtget.mt_fileno = dsi->un_retry_ct;
797: mtget.mt_blkno = dsi->un_underruns;
798: dsi->un_retry_ct = dsi->un_underruns = 0;
799: if (copyout((caddr_t)&mtget, data, sizeof(mtget)))
800: u.u_error = EFAULT;
801: return;
802:
803: default:
804: u.u_error = ENXIO;
805: return;
806: }
807: }
808: #endif NST > 0
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.