|
|
1.1 root 1: /***********************************************************************
2: * Module: haict.c
3: *
4: * Unix device driver functions for accessing SCSI tape drives as
5: * character devices. Conforms to Mark Williams Coherent definition
6: * of the Unix Device Driver interface for Coherent v4.0.1.
7: *
8: * Copyright (c) 1993, Christopher Sean Hilton, All Rights Reserved.
9: *
10: * Last Modified: Thu Jul 15 19:59:42 1993 by [chris]
11: *
12: * $Id: haictexp,v 1.1 93/07/20 11:21:24 bin Exp Locker: bin $
13: */
14: /***********************************************************************
15: * READ THIS * READ THIS * READ THIS * READ THIS * READ THIS *
16: *
17: * This module is set up for my tape drive, a Tandberg TDC 3600 which
18: * is an oddball so here's why things are set up the way they are.
19: * This driver is set up for the possiblility that the tape drive
20: * is in an external cabinet from the PC. This means that the tape
21: * drive may not be turned on when Coherent comes up and runs through
22: * the init routines. Thus the init routine only prints a message
23: * to the effect that the driver is here. The open routine handles
24: * the details of initializing the tape drive. My TDC 3600 automatically
25: * retensions the tape cartridge after the tape is loaded and whenever
26: * the drive is reset. I've timed this process at about 160 seconds
27: * from start to finish. That is why the open routine will wait for
28: * 180 seconds testing the drive through the load/unload command with
29: * immediate return. This brings up the important fact that tape drives
30: * in general are slow devices and can take a long time to
31: * complete operations. During the time when a tape drive is busy
32: * handling some action the SCSI driver could be doing something
33: * else so use the immediate return options whenever possible.
34: */
35:
36: #include <stddef.h>
37: #include <sys/coherent.h>
38: #include <sys/buf.h>
39: #include <sys/file.h>
40: #include <sys/stat.h>
41: #include <sys/sched.h>
42: #include <errno.h>
43: #include <sys/mtioctl.h>
44:
45: #include <sys/haiscsi.h>
46:
47: #define TDC3600 /* Compensate for weirdness */
48: #define FIXED /* Fixed block length reads/writes okay */
49: /* #define VARIABLE Variable Block length reads/writes okay */
50: /* #define SHOWBLKSZ Report blocksize on first open */
51:
52: #define REWINDTAPE 0x01
53: #define IMMEDIATE 0x0010
54: #define REQSENSE 0x03
55: #define READBLKLMT 0x05
56: #define READ 0x08
57: #define WRITE 0x0a
58: #define WRITEFM 0x10
59: #define SPACE 0x11
60: #define SKIP_BLK 0x00
61: #define SKIP_FM 0x01
62: #define SKIP_SEQFM 0x02
63: #define SKIP_EOT 0x03
64: #define MODESELECT 0x15
65: #define ERASE 0x19
66: #define ERASE_BLOCK 0x0000
67: #define ERASE_TAPE 0x0001
68: #define MODESENSE 0x1a
69: #define LOAD 0x1b
70: #define RETENSION 0x0020
71:
72: /***********************************************************************
73: * The Tandberg TDC3600 requires special handling because it doesn't
74: * respond properly to a write when the tape is at the logical end
75: * of tape. Tape should be organized as follows:
76: *
77: * File 1 --------------| File 2-m
78: * DATA[1] | ...DATA[n] | FILEMARK | DATA[1-n] | FILEMARK | FILEMARK |
79: *
80: * The double file marks signify the Logical End of Tape. When a
81: * tape opened in write mode is written to and then closed on the
82: * no rewind device it is necessary to write a Logical End of tape
83: * and then skip backwards over one of the filemarks. This leaves
84: * the tape positioned between the two filemarks. When this happens
85: * on my Tandberg the drive will then lock up (nice huh?) and fail
86: * to do anything until the tape is rewound or retensioned.
87: */
88:
89:
90: #define CTDIRTY 0x0001
91: #define CTCLOSING 0x0002
92:
93: #define CTILI 0x0020 /* Sensekey's Illegal Length Indicator */
94: #define CTEOM 0x0040 /* Sensekey's End OF Media bit */
95: #define CTFILEMARK 0x0080 /* Sensekey's Filemark bit */
96: #define CTSKMASK (CTILI | CTEOM | CTFILEMARK)
97: #define CTRDMD 0x0100 /* We are reading from the tape */
98: #define CTWRTMD 0x0200 /* we are writeing to the tape */
99: int HAI_CACHESZ = 40 * BSIZE; /* 40 Block Cache for each device */
100:
101: typedef enum {
102: CTIDLE = 0,
103: CTINIT,
104: CTFBRD,
105: CTVBRD,
106: CTFBWRT,
107: CTVBWRT,
108: CTSENSE,
109: CTWRITEFM,
110: CTSPACE,
111: CTREWIND,
112: CTERASE,
113: CTLOADRETEN
114: } ctstate_t;
115:
116: typedef struct blkdscr_s *blkdscr_p;
117:
118: typedef struct blkdscr_s {
119: union {
120: unsigned char mediatype;
121: unsigned long totalblocks;
122: } mt;
123: union {
124: unsigned char reserved;
125: unsigned long blocksize;
126: } rb;
127: } blkdscr_t;
128:
129: typedef struct ctctrl_s *ctctrl_p;
130:
131: typedef struct ctctrl_s {
132: char *cache, /* Transfer Cache */
133: *start; /* Start of data in cache */
134: size_t avail; /* bytes availaible in cache */
135: ctstate_t state;
136: unsigned short inuse, /* In Use flag */
137: flags, /* Flags from device */
138: block; /* Block size of device */
139: srb_t srb; /* SCSI Request block for transfers */
140: } ctctrl_t;
141:
142: static int ctinit(); /* Initialize a SCSI device at (id) */
143: static void ctopen(); /* Open SCSI tape at (dev) */
144: static void ctclose(); /* Close a SCSI tape at (dev) */
145: static void ctread(); /* Read from SCSI tape at (dev) */
146: static void ctwrite(); /* Write SCSI tape at (dev) */
147: static void ctioctl(); /* I/O Control routine */
148:
149: extern int nulldev();
150: extern int nonedev();
151:
152: #define min(a, b) ((a) < (b) ? (a) : (b))
153:
154: dca_t ctdca = {
155: ctopen, /* Open */
156: ctclose, /* Close */
157: nonedev, /* Block No Block point here */
158: ctread, /* Read */
159: ctwrite, /* Write */
160: ctioctl, /* Ioctl */
161: ctinit, /* Load */
162: nulldev, /* Unload */
163: nulldev /* Poll */
164: };
165:
166: static ctctrl_p ctdevs[MAXDEVS];
167:
168: /***********************************************************************
169: * Utility functions. *
170: ***********************************************************************/
171:
172: /***********************************************************************
173: * loadtape()
174: *
175: * Move the tape to the load point.
176: */
177:
178: static int loadtape(c, opt)
179: register ctctrl_p c;
180: int opt;
181: {
182: register srb_p r = &(c->srb);
183: register g0cmd_p g0 = &(r->cdb. g0);
184:
185: c->state = CTLOADRETEN;
186: r->buf. space = r->buf. addr. vaddr = r->buf. size = 0;
187: r->xferdir = 0;
188: r->timeout = 300;
189: memset(g0, 0, sizeof(cdb_t));
190: g0->opcode = LOAD;
191: g0->xfr_len = 1;
192: if (opt & IMMEDIATE)
193: g0->lun_lba |= 1;
194: if (opt & RETENSION)
195: g0->xfr_len |= 2;
196: doscsi(r, 4, CVBLKIO, IVBLKIO, SVBLKIO, "loadtape");
197: if (r->status != ST_GOOD && printerror(r, "Load failed"))
198: u. u_error = EIO;
199:
200: c->state = CTIDLE;
201: c->flags &= ~(CTFILEMARK | CTEOM);
202: return (r->status == ST_GOOD);
203: } /* loadtape() */
204:
205: /***********************************************************************
206: * writefm()
207: *
208: * Write Filemarks on the tape.
209: */
210:
211: static void writefm(c, count)
212: register ctctrl_p c;
213: int count;
214: {
215: register srb_p r = &(c->srb);
216: register g0cmd_p g0 = &(r->cdb. g0);
217:
218: c->state = CTWRITEFM;
219: r->buf. space = r->buf. addr. vaddr = r->buf. size = 0;
220: r->xferdir = 0;
221: r->timeout = 40;
222: g0->opcode = WRITEFM;
223: g0->lun_lba = (r->lun << 5);
224: g0->lba_mid = ((unsigned char *) &count)[2];
225: g0->lba_low = ((unsigned char *) &count)[1];
226: g0->xfr_len = ((unsigned char *) &count)[0];
227: g0->control = 0;
228: doscsi(r, 4, CVBLKIO, IVBLKIO, SVBLKIO, "writefm");
229: if (r->status != ST_GOOD && printerror(r, "Write filemarks failed"))
230: u. u_error = EIO;
231: c->state = CTIDLE;
232: } /* writefm() */
233:
234: /***********************************************************************
235: * space()
236: *
237: * Space over blocks/filemarks/etc.
238: */
239:
240: static void space(c, count, object)
241: register ctctrl_p c;
242: int count;
243: int object;
244: {
245: register srb_p r = &(c->srb);
246: register g0cmd_p g0 = &(r->cdb. g0);
247:
248: c->state = CTSPACE;
249: r->buf. space = r->buf. addr. vaddr = r->buf. size = 0;
250: r->xferdir = 0;
251: r->timeout = 300;
252: g0->opcode = SPACE;
253: g0->lun_lba = (r->lun << 5) | (object & 3);
254: g0->lba_mid = ((unsigned char *) &count)[2];
255: g0->lba_low = ((unsigned char *) &count)[1];
256: g0->xfr_len = ((unsigned char *) &count)[0];
257: g0->control = 0;
258: doscsi(r, 2, CVBLKIO, IVBLKIO, SVBLKIO, "space");
259: if (r->status != ST_GOOD && printerror(r, "Space failed"))
260: u. u_error = EIO;
261: c->state = CTIDLE;
262: } /* space() */
263:
264: /***********************************************************************
265: * rewind()
266: *
267: * Rewind the tape drive back to the load point.
268: */
269:
270: static void rewind(c, wait)
271: register ctctrl_p c;
272: int wait;
273: {
274: register srb_p r = &(c->srb);
275: register g0cmd_p g0 = &(r->cdb. g0);
276:
277: c->state = CTREWIND;
278: r->buf. space = r->buf. addr. vaddr = r->buf. size = 0;
279: r->timeout = 300;
280: r->xferdir = 0;
281: memset(g0, 0, sizeof(cdb_t));
282: g0->opcode = REWINDTAPE;
283: if (!wait)
284: g0->lun_lba = (r->lun << 5) | 1;
285: doscsi(r, 2, CVBLKIO, IVBLKIO, SVBLKIO, "rewind");
286: if (r->status != ST_GOOD && printerror(r, "Rewind failed"))
287: u. u_error = EIO;
288: c->flags = 0;
289: c->state = CTIDLE;
290: } /* rewind() */
291:
292: static void erase(c, to_eot)
293: register ctctrl_p c;
294: int to_eot;
295: {
296: register srb_p r = &(c->srb);
297: register g0cmd_p g0 = &(r->cdb. g0);
298:
299: c->state = CTERASE;
300: r->buf. space = r->buf. addr. vaddr = r->buf. size = 0;
301: r->timeout = 300;
302: r->xferdir = 0;
303: memset(g0, 0, sizeof(cdb_t));
304: g0->opcode = ERASE;
305: g0->lun_lba = (r->lun << 5);
306: if (to_eot)
307: g0->lun_lba |= 1;
308: doscsi(r, 2, CVBLKIO, IVBLKIO, SVBLKIO, "erase");
309: if (r->status != ST_GOOD && printerror(r, "Erase failed"))
310: u. u_error = EIO;
311: if (to_eot)
312: c->flags &= ~(CTFILEMARK | CTEOM | CTILI | CTDIRTY);
313: c->state = CTIDLE;
314: } /* erase() */
315:
316: /***********************************************************************
317: * Device Driver Entry Point routines. *
318: ***********************************************************************/
319:
320: /***********************************************************************
321: * ctinit()
322: *
323: * Initialize the tape device at (id). This doesn't do anything,
324: * not even verify that the drive is there because it could be powered
325: * off.
326: */
327:
328: static int ctinit(id)
329: register int id;
330: {
331: register ctctrl_p c = kalloc(sizeof(ctctrl_t) /* + HAI_CACHESZ */);
332:
333: if (!c) {
334: printf("\tCould not allocate control structure.\n");
335: return 0;
336: }
337:
338: printf("\tCoherent SCSI Tape driver v1.1\n");
339: memset(c, 0, sizeof(ctctrl_t));
340: c->inuse = 0;
341: c->cache = NULL; /* ((char *) c) + sizeof(ctctrl_t); */
342: c->srb. target = id;
343: c->srb. lun = 0;
344: c->state = CTIDLE;
345: ctdevs[id] = c;
346: return 1;
347: }
348:
349: static void ctopen(dev, mode)
350: dev_t dev;
351: int mode;
352: {
353: register ctctrl_p c = ctdevs[tid(dev)];
354: register srb_p r = &(c->srb);
355: register g0cmd_p g0 = &(r->cdb. g0);
356: int s;
357: unsigned long blim;
358: char buf[64];
359: blkdscr_p bd = (blkdscr_p) (buf + 4);
360:
361: if (!c) {
362: u. u_error = ENXIO;
363: return;
364: }
365: if ((mode != IPR) && (mode != IPW)) {
366: u. u_error = EINVAL;
367: return;
368: }
369:
370: s = sphi();
371:
372: if (c->inuse) {
373: u. u_error = EDBUSY;
374: goto done;
375: }
376:
377: c->inuse = 1;
378: c->state = CTINIT;
379: r->dev = dev; /* Save the rewind bit for close. */
380:
381: /***********************************************************************
382: * Repeat the test unit ready command to the tape drive. This should
383: * return one of three ways:
384: *
385: * Either there isn't a tape in the drive and the test unit ready
386: * will fail all the time: Sense Key 70 00 02 (Not Ready),
387: *
388: * Or there is a tape in the drive and the user just put it in
389: * there: Sense Key 70 00 06 (Unit Attention - tape changed)
390: *
391: * Or there is a tape in the drive and it's been in use for a
392: * used (No Sense Key data at all).
393: *
394: * If there is a new tape in the drive then do the load command
395: * to make sure that it is ready to go.
396: */
397:
398: r->timeout = 2;
399: r->buf. space = r->buf. addr. vaddr = r->buf. size = 0;
400: r->xferdir = 0;
401: memset(g0, 0, sizeof(cdb_t)); /* Test Unit Ready */
402: memset(r->sensebuf, 0, sizeof(r->sensebuf));
403: doscsi(r, 4, CVBLKIO, IVBLKIO, SVBLKIO, "ctopen");
404:
405: /***********************************************************************
406: * If the command fails there probably wasn't a tape in the drive.
407: */
408:
409: if (r->status != ST_GOOD) {
410: if (r->status != ST_USRABRT)
411: u. u_error = ENXIO;
412: goto openfailed;
413: }
414:
415: /***********************************************************************
416: * Command Passed: check for sense data which would say that the tape
417: * was just loaded. If it was then block here because it is very
418: * inconvienent to do so in the block routine. (loadtape needs to
419: * use v_sleep).
420: */
421:
422: else if (r->sensebuf[0] == 0x70 && r->sensebuf[2] == 0x06) {
423: if (!loadtape(c, 0))
424: goto openfailed;
425: }
426:
427: /***********************************************************************
428: * Do a mode sense right now to check if the tape is write protected
429: * and the user asked for write access. Also need to figure out block
430: * size for reads and writes. This will end this fixed/variable
431: * nonsense. If you need to use variable block mode I will provide
432: * an IO control to swap it. Also this way my Tandberg will be supported
433: * just like any other tape drive.
434: */
435:
436: r->buf. space = KRNL_ADDR;
437: r->buf. addr. vaddr = (vaddr_t) buf;
438: r->buf. size = sizeof(buf);
439: r->xferdir = DMAREAD;
440: r->timeout = 2;
441: memset(g0, 0, sizeof(cdb_t));
442: g0->opcode = MODESENSE;
443: g0->xfr_len = sizeof(buf);
444: doscsi(r, 3, CVBLKIO, IVBLKIO, SVBLKIO, "ctopen");
445: if (r->status != ST_GOOD) {
446: if (printerror(r, "Mode sense failed"))
447: u. u_error = EIO;
448: goto openfailed;
449: }
450:
451: /***********************************************************************
452: * If tape drive opened in write mode make sure the tape is not write
453: * protected now.
454: */
455:
456: if (mode == IPW && (buf[2] & 0x80) != 0) {
457: devmsg(dev, "Tape is write protected");
458: u. u_error = ENXIO;
459: goto openfailed;
460: }
461:
462: /***********************************************************************
463: * If mode sense returned any media descriptors take the first one
464: * and use it. This should be the default media type.
465: */
466:
467: if (buf[3]) { /* If mode sense returned any media descriptors */
468: blim = (bd->rb. blocksize & 0xffffff00);
469: flip(blim);
470: c->block = blim;
471: if (c->block && HAI_CACHESZ % c->block) {
472: HAI_CACHESZ -= (HAI_CACHESZ % c->block);
473: devmsg(r->dev, "HAI_CACHESZ adjusted to %d bytes", HAI_CACHESZ);
474: }
475: }
476: else {
477: u. u_error = ENXIO;
478: goto openfailed;
479: }
480: #ifdef SHOWBLKSZ
481: devmsg(dev, "Using blocksize %d bytes", c->block);
482: #endif
483:
484: c->flags = (mode == IPR) ? CTRDMD : CTWRTMD;
485: if (c->block) {
486: c->cache = kalloc(HAI_CACHESZ);
487: if (!c->cache) {
488: devmsg(dev, "Could not allocate tape cache");
489: u. u_error = ENOMEM;
490: goto openfailed;
491: }
492: c->avail = (c->flags & CTRDMD) ? 0 : HAI_CACHESZ;
493: c->start = c->cache;
494: }
495: c->state = CTIDLE;
496: goto done;
497:
498: openfailed:
499: c->state = CTIDLE;
500: c->inuse = 0;
501:
502: done:
503: spl(s);
504: } /* ctopen() */
505:
506: /***********************************************************************
507: * ctclose()
508: *
509: * Close the SCSI Device at (dev).
510: */
511:
512: static void ctclose(dev)
513: register dev_t dev;
514: {
515: register ctctrl_p c = ctdevs[tid(dev)];
516: register srb_p r = &(c->srb);
517: int s;
518:
519: if (!c) {
520: u. u_error = EINVAL;
521: return;
522: }
523:
524: s = sphi();
525: c->flags |= CTCLOSING;
526: flushcache(c);
527: while (c->state != CTIDLE) {
528: /* x_sleep(&(c->flags), ...); */
529: v_sleep(&(c->flags), CVBLKIO, IVBLKIO, SVBLKIO, "ctclose");
530: if (nondsig()) {
531: u. u_error = EINTR;
532: break;
533: }
534: }
535: spl(s);
536: if (c->cache) {
537: kfree(c->cache);
538: c->cache = c->start = NULL;
539: c->avail = 0;
540: }
541:
542: #ifndef TDC3600
543: /***********************************************************************
544: * Write two filemarks (Logical End of Tape) and then skip backwards
545: * over one of them to ready for the another write operation on the
546: * no rewind device. This code guarantees properly formed tapes according
547: * to the wisened old nine-track hacker that I work with. The problem
548: * is that...
549: */
550: if (c->flags & CTDIRTY) {
551: writefm(c, 1); /* Write a file mark */
552: writefm(c, 1); /* Write another filemark */
553: space(c, -1, SKIP_FM); /* Go back to the first filemark */
554: }
555: #else
556: /*
557: * ... problem is that my Tandberg considers it an error to do anything
558: * after it has skipped past a filemark. So all commands except load and
559: * rewind fail after the the previous code. The following will work in
560: * all situations but there is a risk that a user's tapes will only
561: * have one filemark at Logical End-of-Tape if the user isn't careful
562: * to use the rewind device the last time he uses tape drive. This is
563: * only a problem with drives which insist upon doing a Retension each
564: * time the tape is changed or the drive gets reset.
565: */
566: if (c->flags & CTDIRTY) {
567: writefm(c, 1);
568: if (r->dev & REWIND)
569: writefm(c, 1);
570: }
571: #endif
572:
573: if (r->dev & REWIND)
574: rewind(c, 0);
575:
576: c->inuse = 0;
577: return;
578: } /* ctclose() */
579:
580: /***********************************************************************
581: * fillcache() -- Read from the tape into the cache (really?)
582: *
583: * return 0 and set u. u_error on any errors.
584: */
585:
586: static int fillcache(c)
587: register ctctrl_p c;
588: {
589: register srb_p r = (&c->srb);
590: register g0cmd_p g0 = &(r->cdb. g0);
591: size_t xfrsize;
592: extsense_p e;
593: int info;
594: int retval = 0;
595:
596: r->buf. space = KRNL_ADDR;
597: r->buf. addr. vaddr = (vaddr_t) c->cache;
598: r->buf. size = xfrsize = HAI_CACHESZ;
599: r->xferdir = DMAREAD;
600: r->timeout = 30;
601: r->tries = 0;
602: g0->opcode = READ;
603: g0->lun_lba = (r->lun << 5);
604: if (c->block) {
605: g0->lun_lba |= 1;
606: xfrsize = (xfrsize + c->block - 1) / c->block;
607: }
608: g0->lba_mid = ((unsigned char *) &xfrsize)[2];
609: g0->lba_low = ((unsigned char *) &xfrsize)[1];
610: g0->xfr_len = ((unsigned char *) &xfrsize)[0];
611: g0->control = 0;
612: doscsi(r, 1, CVBLKIO, IVBLKIO, SVBLKIO, "ctblkrd");
613: switch (r->status) {
614: case ST_GOOD:
615: c->start = c->cache;
616: c->avail = r->buf. size;
617: retval = 1;
618: break;
619: case ST_CHKCOND:
620: e = r->sensebuf;
621: if ((e->errorcode & 0x70) == 0x70) {
622: info = 0;
623: if (e->errorcode & 0x80) {
624: info = e->info;
625: flip(info);
626: }
627: if (e->sensekey & (CTFILEMARK | CTEOM)) {
628: c->flags |= (e->sensekey & (CTFILEMARK | CTEOM));
629: c->start = c->cache;
630: c->avail = HAI_CACHESZ - (info * c->block);
631: retval = 1;
632: break;
633: }
634: }
635: printsense(r->dev, "Read failed", r->sensebuf);
636: u. u_error = EIO;
637: retval = 0;
638: break;
639: case ST_USRABRT:
640: retval = 0;
641: break;
642: default:
643: devmsg(r->dev, "Read failed: status (0x%x)", r->status);
644: u. u_error = EIO;
645: retval = 0;
646: break;
647: }
648: c->state = CTIDLE;
649: return retval;
650: } /* fillcache() */
651:
652: /***********************************************************************
653: * ctfbrd() -- Fixed block read handler. Reads from the tape
654: * drive through the cache when the tape drive is
655: * in fixed block mode.
656: */
657:
658: static void ctfbrd(c, iop)
659: register ctctrl_p c;
660: register IO *iop;
661: {
662: register size_t reqcount, /* Total bytes transfered */
663: xfrsize; /* Current transfer size */
664: size_t total, /* System global memory total transfer size */
665: size; /* System global memory current transfer size */
666:
667: reqcount = 0;
668: while (iop->io_ioc) {
669: xfrsize = min(c->avail, iop->io_ioc);
670: if (xfrsize) {
671: switch (iop->io_seg) {
672: case IOSYS:
673: memcpy(iop->io. vbase + reqcount, c->start, xfrsize);
674: break;
675: case IOUSR:
676: kucopy(c->start, iop->io. vbase + reqcount, xfrsize);
677: break;
678: case IOPHY:
679: total = 0;
680: while (total < xfrsize) {
681: size = min(xfrsize - total, NBPC);
682: xpcopy(c->start + total,
683: iop->io. pbase + reqcount + total,
684: size,
685: SEG_386_KD | SEG_VIRT);
686: total += size;
687: }
688: break;
689: }
690: c->start += xfrsize;
691: c->avail -= xfrsize;
692: reqcount += xfrsize;
693: iop->io_ioc -= xfrsize;
694: }
695: if (iop->io_ioc) {
696: if (c->flags & CTFILEMARK) {
697: c->flags &= ~CTFILEMARK;
698: break;
699: }
700:
701: if (c->flags & CTEOM) {
702: u. u_error = EIO;
703: break;
704: }
705:
706: if (!fillcache(c))
707: break;
708: }
709: } /* while */
710: } /* ctfbrd() */
711:
712: /***********************************************************************
713: * ctvbrd() -- Variable block read entry point.
714: */
715:
716: static void ctvbrd(c, iop)
717: register ctctrl_p c;
718: register IO *iop;
719: {
720: register srb_p r = &(c->srb);
721: register g0cmd_p g0 = &(r->cdb. g0);
722: size_t xfrsize;
723: extsense_p e;
724: int info;
725:
726: if (c->flags & CTEOM) {
727: u. u_error = EIO;
728: return;
729: }
730: if (c->flags & CTFILEMARK) {
731: c->flags &= ~CTFILEMARK;
732: return;
733: }
734: c->state = CTVBRD;
735: switch (iop->io_seg) {
736: case IOSYS:
737: r->buf. space = KRNL_ADDR;
738: r->buf. addr. vaddr = iop->io. vbase;
739: break;
740: case IOUSR:
741: r->buf. space = USER_ADDR;
742: r->buf. addr. vaddr = iop->io. vbase;
743: break;
744: case IOPHY:
745: r->buf. space = PHYS_ADDR;
746: r->buf. addr. paddr = iop->io. pbase;
747: break;
748: }
749: r->buf. size = xfrsize = iop->io_ioc;
750: r->xferdir = DMAREAD;
751: r->timeout = 30;
752: g0->opcode = READ;
753: g0->lun_lba = (r->lun << 5);
754: g0->lba_mid = ((unsigned char *) &xfrsize)[2];
755: g0->lba_low = ((unsigned char *) &xfrsize)[1];
756: g0->xfr_len = ((unsigned char *) &xfrsize)[0];
757: g0->control = 0;
758: doscsi(r, 1, CVBLKIO, IVBLKIO, SVBLKIO, "ctvbrd");
759: switch (r->status) {
760: case ST_GOOD:
761: iop->io_ioc -= r->buf. size;
762: break;
763: case ST_CHKCOND:
764: e = r->sensebuf;
765: if ((e->errorcode & 0x70) == 0x70) {
766: info = 0;
767: if (e->errorcode & 0x80) {
768: info = (long) e->info;
769: flip(info);
770: }
771: if (e->sensekey & (CTFILEMARK | CTEOM)) {
772: c->flags |= (e->sensekey & (CTFILEMARK | CTEOM));
773: break;
774: }
775: else if (e->sensekey & CTILI) {
776: devmsg(r->dev,
777: "Read failed buffer size %d blocksize %d",
778: xfrsize,
779: xfrsize - info);
780: if (info > 0)
781: iop->io_ioc -= (xfrsize - info);
782: else
783: u. u_error = EIO;
784: break;
785: }
786: }
787: printsense(r->dev, "Read failed", r->sensebuf);
788: u. u_error = EIO;
789: break;
790: case ST_USRABRT:
791: break;
792: default:
793: devmsg(r->dev, "Read failed: status (0x%x)", r->status);
794: u. u_error = EIO;
795: break;
796: }
797: c->state = CTIDLE;
798: } /* ctvbrd() */
799:
800: /***********************************************************************
801: * ctread() -- OS Read entry point.
802: */
803:
804: static void ctread(dev, iop)
805: dev_t dev;
806: register IO *iop;
807: {
808: register ctctrl_p c = ctdevs[tid(dev)];
809:
810: if (!c) {
811: u. u_error = EINVAL;
812: return;
813: }
814:
815: if (c->block)
816: ctfbrd(c, iop);
817: else
818: ctvbrd(c, iop);
819: } /* ctread() */
820:
821: /***********************************************************************
822: * flushcache() -- flush the data in the cache to the tape.
823: *
824: * returns 0 and sets u. u_error on failure else returns 1.
825: */
826:
827: static int flushcache(c)
828: register ctctrl_p c;
829: {
830: register srb_p r = (&c->srb);
831: register g0cmd_p g0 = &(r->cdb. g0);
832: size_t xfrsize;
833: extsense_p e;
834: int info;
835: int retval = 0;
836:
837: r->buf. space = KRNL_ADDR;
838: r->buf. addr. vaddr = (vaddr_t) c->cache;
839: r->buf. size = xfrsize = HAI_CACHESZ - c->avail;
840: r->xferdir = DMAWRITE;
841: r->timeout = 30;
842: r->tries = 0;
843: g0->opcode = WRITE;
844: g0->lun_lba = (r->lun << 5);
845: if (c->block) {
846: g0->lun_lba |= 1;
847: xfrsize = (xfrsize + c->block - 1) / c->block;
848: }
849: g0->lba_mid = ((unsigned char *) &xfrsize)[2];
850: g0->lba_low = ((unsigned char *) &xfrsize)[1];
851: g0->xfr_len = ((unsigned char *) &xfrsize)[0];
852: g0->control = 0;
853: doscsi(r, 1, CVBLKIO, IVBLKIO, SVBLKIO, "ctblkwrt");
854: switch (r->status) {
855: case ST_GOOD:
856: c->start = c->cache;
857: c->avail = HAI_CACHESZ;
858: retval = 1;
859: break;
860: case ST_CHKCOND:
861: e = r->sensebuf;
862: if ((e->errorcode & 0x70) == 0x70) {
863: info = 0;
864: if (e->errorcode & 0x80) {
865: info = e->info;
866: flip(info);
867: }
868: if (e->sensekey & CTEOM) {
869: c->flags |= CTEOM;
870: devmsg(r->dev, "End of tape on block write");
871: }
872: }
873: printsense(r->dev, "Read failed", r->sensebuf);
874: u. u_error = EIO;
875: retval = 0;
876: break;
877: case ST_USRABRT:
878: retval = 0;
879: break;
880: default:
881: devmsg(r->dev, "Read failed: status (0x%x)", r->status);
882: u. u_error = EIO;
883: retval = 0;
884: break;
885: }
886: c->state = CTIDLE;
887: return retval;
888: } /* flushcache() */
889:
890: /***********************************************************************
891: * ctfbwrt() -- Fixed block write. This should be fast because
892: * it uses the tapes drives optimum setting and it
893: * goes through a cache.
894: */
895:
896: static void ctfbwrt(c, iop)
897: register ctctrl_p c;
898: register IO *iop;
899: {
900: register size_t reqcount, /* Total bytes transfered */
901: xfrsize; /* Current transfer size */
902: size_t total, /* System global memory total transfer size */
903: size; /* System global memory current transfer size */
904:
905: reqcount = 0;
906: while (iop->io_ioc) {
907: xfrsize = min(c->avail, iop->io_ioc);
908: if (xfrsize) {
909: switch (iop->io_seg) {
910: case IOSYS:
911: memcpy(c->start, iop->io. vbase + reqcount, xfrsize);
912: break;
913: case IOUSR:
914: ukcopy(iop->io. vbase + reqcount, c->start, xfrsize);
915: break;
916: case IOPHY:
917: total = 0;
918: while (total < xfrsize) {
919: size = min(xfrsize - total, NBPC);
920: pxcopy(iop->io. pbase + reqcount + total,
921: c->start + total,
922: size,
923: SEG_386_KD | SEG_VIRT);
924: total += size;
925: }
926: break;
927: }
928: c->start += xfrsize;
929: c->avail -= xfrsize;
930: reqcount += xfrsize;
931: iop->io_ioc -= xfrsize;
932: }
933: if (iop->io_ioc) {
934: if (!flushcache(c))
935: break;
936: }
937: } /* while */
938: } /* ctfbwrt() */
939:
940: /***********************************************************************
941: * ctvbwrt() -- Variable block writes.
942: */
943:
944:
945: static void ctvbwrt(c, iop)
946: register ctctrl_p c;
947: register IO *iop;
948: {
949: register srb_p r = &(c->srb);
950: register g0cmd_p g0 = &(r->cdb. g0);
951: size_t xfrsize;
952: extsense_p e;
953: int info;
954:
955: c->state = CTVBWRT;
956: switch (iop->io_seg) {
957: case IOSYS:
958: r->buf. space = KRNL_ADDR;
959: r->buf. addr. vaddr = iop->io. vbase;
960: break;
961: case IOUSR:
962: r->buf. space = USER_ADDR;
963: r->buf. addr. vaddr = iop->io. vbase;
964: break;
965: case IOPHY:
966: r->buf. space = PHYS_ADDR;
967: r->buf. addr. paddr = iop->io. pbase;
968: break;
969: }
970: xfrsize = iop->io_ioc;
971: r->buf. size = xfrsize;
972: r->xferdir = DMAWRITE;
973: r->timeout = 30;
974: g0->opcode = WRITE;
975: g0->lun_lba = (r->lun << 5);
976: g0->lba_mid = ((unsigned char *) &xfrsize)[2];
977: g0->lba_low = ((unsigned char *) &xfrsize)[1];
978: g0->xfr_len = ((unsigned char *) &xfrsize)[0];
979: g0->control = 0;
980: doscsi(r, 1, CVBLKIO, IVBLKIO, SVBLKIO, "ctvbwrt");
981: switch (r->status) {
982: case ST_GOOD:
983: iop->io_ioc -= r->buf. size;
984: break;
985: case ST_CHKCOND:
986: e = r->sensebuf;
987: if ((e->errorcode & 0x70) == 0x70) {
988: info = 0;
989: if (e->errorcode & 0x80) {
990: info = (long) e->info;
991: flip(info);
992: }
993: if (e->sensekey & CTEOM) {
994: c->flags |= CTEOM;
995: devmsg(r->dev, "End of tape");
996: }
997: }
998: printsense(r->dev, "Write failed", r->sensebuf);
999: u. u_error = EIO;
1000: break;
1001: case ST_USRABRT:
1002: break;
1003: default:
1004: devmsg(r->dev, "Read failed: status (0x%x)", r->status);
1005: u. u_error = EIO;
1006: break;
1007: }
1008: c->state = CTIDLE;
1009: } /* ctvbwrt() */
1010:
1011: /***********************************************************************
1012: * ctwrite() -- Write entry point for tape drive.
1013: */
1014:
1015: static void ctwrite(dev, iop)
1016: register dev_t dev;
1017: register IO *iop;
1018: {
1019: register ctctrl_p c = ctdevs[tid(dev)];
1020:
1021: if (!c) {
1022: u. u_error = EINVAL;
1023: return;
1024: }
1025:
1026: if (c->block)
1027: ctfbwrt(c, iop);
1028: else
1029: ctvbwrt(c, iop);
1030: } /* ctwrite() */
1031:
1032: /***********************************************************************
1033: * ctioctl()
1034: *
1035: * I/O Control Entry point for Cartridge tape devices.
1036: */
1037:
1038: static void ctioctl(dev, cmd /*, vec */)
1039: register dev_t dev;
1040: register int cmd;
1041: /* char *vec; */
1042: {
1043: register ctctrl_p c = ctdevs[tid(dev)];
1044:
1045: if (!c) {
1046: u. u_error = EINVAL;
1047: return;
1048: }
1049:
1050: switch (cmd) {
1051: case MTREWIND: /* Rewind */
1052: rewind(c, 1);
1053: break;
1054: case MTWEOF: /* Write end of file mark */
1055: writefm(c, 1);
1056: break;
1057: case MTRSKIP: /* Record skip */
1058: space(c, 1, SKIP_BLK);
1059: break;
1060: case MTFSKIP: /* File skip */
1061: space(c, 1, SKIP_FM);
1062: break;
1063: case MTTENSE: /* Tension tape */
1064: loadtape(c, RETENSION);
1065: break;
1066: case MTERASE: /* Erase tape */
1067: erase(c, ERASE_TAPE);
1068: break;
1069: case MTDEC: /* DEC mode */
1070: case MTIBM: /* IBM mode */
1071: case MT800: /* 800 bpi */
1072: case MT1600: /* 1600 bpi */
1073: case MT6250: /* 6250 bpi */
1074: return;
1075: default:
1076: u. u_error = ENXIO;
1077: break;
1078: }
1079: } /* ctioctl() */
1080:
1081: /* End of file */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.