|
|
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: * The philosophy of this driver is to support basic functions on
9: * the tape drive (read, write, retension, rewind, skip, etc). There
10: * are more features out there for all the SCSI tape drives out there
11: * than I know what to do with. I leave custom support for these
12: * drives to the people who have them. To this end this drive will
13: * blindly follow whatever information it can get using Mode Sense
14: * and Read Block Limits CDB's. These tests are done at open time.
15: * An application can change the operation of the driver by applying
16: * the mode select command through I/O Control mechanism.
17: *
18: * Copyright (c) 1993, Christopher Sean Hilton, All Rights Reserved.
19: *
20: * Last Modified: Mon Jul 26 17:18:59 1993 by [chris]
21: *
22: * $Id: haict.c,v 2.4 93/08/09 13:45:06 bin Exp Locker: bin $
23: *
24: * $Log: haict.c,v $
25: * Revision 2.4 93/08/09 13:45:06 bin
26: * Kernel 82 changes
27: *
28: */
29:
30: #include <stddef.h>
31: #include <sys/coherent.h>
32: #include <sys/buf.h>
33: #include <sys/inode.h>
34: #include <sys/stat.h>
35: #include <sys/sched.h>
36: #include <errno.h>
37: #include <sys/mtioctl.h>
38: #include <sys/file.h> /* Louis */
39:
40: #include <sys/haiscsi.h>
41: #include <sys/haiioctl.h>
42:
43: #define REWINDTAPE 0x01
44: #define IMMEDIATE 0x0010
45: #define REQSENSE 0x03
46: #define READBLKLMT 0x05
47: #define READ 0x08
48: #define WRITE 0x0a
49: #define WRITEFM 0x10
50: #define SPACE 0x11
51: #define SKIP_BLK 0x00
52: #define SKIP_FM 0x01
53: #define SKIP_SEQFM 0x02
54: #define SKIP_EOT 0x03
55: #define MODESELECT 0x15
56: #define ERASE 0x19
57: #define ERASE_BLOCK 0x0000
58: #define ERASE_TAPE 0x0001
59: #define MODESENSE 0x1a
60: #define LOAD 0x1b
61: #define RETENSION 0x0020
62:
63: /***********************************************************************
64: * The Tandberg TDC3600 requires special handling because it doesn't
65: * respond properly to a write when the tape is at the logical end
66: * of tape. Tape should be organized as follows:
67: *
68: * File 1 --------------| File 2-m
69: * DATA[1] | ...DATA[n] | FILEMARK | DATA[1-n] | FILEMARK | FILEMARK |
70: *
71: * The double file marks signify the Logical End of Tape. When a
72: * tape opened in write mode is written to and then closed on the
73: * no rewind device it is necessary to write a Logical End of tape
74: * and then skip backwards over one of the filemarks. This leaves
75: * the tape positioned between the two filemarks. When this happens
76: * on my Tandberg the drive will then lock up (nice huh?) and fail
77: * to do anything until the tape is rewound or retensioned.
78: */
79:
80:
81: #define CTDIRTY 0x0001
82: #define CTCLOSING 0x0002
83:
84: #define CTILI 0x0020 /* Sensekey's Illegal Length Indicator */
85: #define CTEOM 0x0040 /* Sensekey's End OF Media bit */
86: #define CTFILEMARK 0x0080 /* Sensekey's Filemark bit */
87: #define CTSKMASK (CTILI | CTEOM | CTFILEMARK)
88: #define CTRDMD 0x0100 /* we are reading from the tape */
89: #define CTWRTMD 0x0200 /* we are writing to the tape */
90:
91: #ifndef HAICACHESZ
92: /*
93: * There wasn't much of a difference in speed between 32 and 40 block
94: * in my experiance so save as much kalloc memory as possible.
95: */
96:
97: #define HAICACHESZ (32 * BSIZE)/* 32 Block Cache for each device */
98: #endif
99:
100: #ifndef HAICTVERBOSE
101: /*
102: * HAICTVERBOSE is done as a define because I wanted to be able to use two
103: * tape drives in my system at one time (why?!). ld complains if it is a
104: * patchable constant. This problem must be solved but products must also
105: * ship. [csh]
106: */
107:
108: #define HAICTVERBOSE 0x0001 /* Switch console messages on/off */
109: #endif
110:
111: typedef enum {
112: CTIDLE = 0,
113: CTINIT,
114: CTFBRD,
115: CTVBRD,
116: CTFBWRT,
117: CTVBWRT,
118: CTLASTWRT,
119: CTSENSE,
120: CTWRITEFM,
121: CTSPACE,
122: CTREWIND,
123: CTERASE,
124: CTLOADRETEN,
125: CTIOCTL
126: } ctstate_t;
127:
128: /* Block Descriptors in the mode sense command. */
129:
130: typedef struct blkdscr_s *blkdscr_p;
131:
132: typedef struct blkdscr_s {
133: union {
134: unsigned char mediatype;
135: unsigned long totalblocks;
136: } mt;
137: union {
138: unsigned char reserved;
139: unsigned long blocksize;
140: } rb;
141: } blkdscr_t;
142:
143: typedef struct blklim_s *blklim_p;
144:
145: typedef struct blklim_s {
146: unsigned blmax; /* Maximum size for Reads/Writes */
147: unsigned short blmin; /* Minimum size for Reads/Writes */
148: } blklim_t;
149:
150: typedef struct ctctrl_s *ctctrl_p;
151:
152: typedef struct ctctrl_s {
153: char *cache, /* Transfer Cache */
154: *start; /* Start of data in cache */
155: size_t cachesize, /* Size of cache */
156: avail; /* bytes availaible in cache */
157: ctstate_t state;
158: unsigned block, /* Block size of device */
159: blmax; /* Block limits maximum */
160: unsigned short blmin, /* Block Limits minimum */
161: flags, /* Flags from device */
162: inuse; /* In Use flag */
163: srb_t srb; /* SCSI Request block for transfers */
164: } ctctrl_t;
165:
166: static int ctinit(); /* Initialize a SCSI device at (id) */
167: static void ctopen(); /* Open SCSI tape at (dev) */
168: static void ctclose(); /* Close a SCSI tape at (dev) */
169: static void ctread(); /* Read from SCSI tape at (dev) */
170: static void ctwrite(); /* Write SCSI tape at (dev) */
171: static void ctioctl(); /* I/O Control routine */
172: static int fillcache(); /* Fill the tape cache */
173: static int flushcache(); /* Flush the tape cache */
174:
175: extern int nulldev();
176: extern int nonedev();
177:
178: #define min(a, b) ((a) < (b) ? (a) : (b))
179:
180: #ifdef TDC3600
181: #define ctdca haict3600
182: #endif
183:
184: dca_t ctdca = {
185: ctopen, /* Open */
186: ctclose, /* Close */
187: hainonblk, /* No Block point here but don't just drop Buffers */
188: ctread, /* Read */
189: ctwrite, /* Write */
190: ctioctl, /* Ioctl */
191: ctinit, /* Load */
192: nulldev, /* Unload */
193: nulldev /* Poll */
194: };
195:
196: static ctctrl_p ctdevs[MAXDEVS];
197:
198: /***********************************************************************
199: * Utility functions. *
200: ***********************************************************************/
201:
202: #define ctvmsg(l, cmd) { if (HAICTVERBOSE & (l)) { (cmd); } }
203:
204: /***********************************************************************
205: * ctbusywait()
206: *
207: * Wait for the tape drive state to return to idle. This is easy
208: * for two reasons: 1) With no block entry point its safe to sleep
209: * at any time. 2) We shouldn't really need this anyhow. This is
210: * unneccessary because without a block routine and with only one
211: * process able to open the tape drive at a time the state of the
212: * tape drive driver is well defined. So, why is it here you ask?
213: * because one day some user might fork a process that owns the tape
214: * drive. This would cause 40 days and nights worth of rain etc.
215: * Now all that will happen is both processes will be able to write/read
216: * from the tape drive and the data that they get will be complete
217: * garbage. However, the kernel will not break.
218: */
219:
220: static int ctbusywait(c, newstate)
221: register ctctrl_p c;
222: register ctstate_t newstate;
223: {
224: register int s;
225: int retval;
226:
227: s = sphi();
228: retval = 1;
229: while (c->state != CTIDLE)
230: if (x_sleep(&(c->srb. status), pritape, slpriSigCatch, "ctbsywt")) {
231: u. u_error = EINTR;
232: retval = 0;
233: break;
234: }
235: c->state = newstate;
236: spl(s);
237: return retval;
238: } /* ctbusywait() */
239:
240: /***********************************************************************
241: * loadtape()
242: *
243: * Move the tape to the load point.
244: */
245:
246: static int loadtape(c, opt)
247: register ctctrl_p c;
248: int opt;
249: {
250: register srb_p r = &(c->srb);
251: register g0cmd_p g0 = &(r->cdb. g0);
252:
253: if (!ctbusywait(c, CTLOADRETEN))
254: return 0;
255: r->buf. space = (int) r->buf. addr. caddr = r->buf. size = 0;
256: r->xferdir = 0;
257: r->timeout = 300;
258: memset(g0, 0, sizeof(cdb_t));
259: g0->opcode = LOAD;
260: g0->xfr_len = 1; /* Move tape to load point. */
261: if (opt & IMMEDIATE)
262: g0->lun_lba |= 1;
263: if (opt & RETENSION)
264: g0->xfr_len |= 2;
265: doscsi(r, 4, pritape, slpriSigCatch, "loadtape");
266: if (r->status != ST_GOOD && printerror(r, "Load failed"))
267: u. u_error = EIO;
268:
269: c->state = CTIDLE;
270: c->flags &= ~(CTFILEMARK | CTEOM);
271: return (r->status == ST_GOOD);
272: } /* loadtape() */
273:
274: /***********************************************************************
275: * writefm()
276: *
277: * Write Filemarks on the tape.
278: */
279:
280: static void writefm(c, count)
281: register ctctrl_p c;
282: int count;
283: {
284: register srb_p r = &(c->srb);
285: register g0cmd_p g0 = &(r->cdb. g0);
286:
287: if (!ctbusywait(c, CTWRITEFM))
288: return;
289: r->buf. space = (int) r->buf. addr. caddr = r->buf. size = 0;
290: r->xferdir = 0;
291: r->timeout = 40;
292: g0->opcode = WRITEFM;
293: g0->lun_lba = (r->lun << 5);
294: g0->lba_mid = ((unsigned char *) &count)[2];
295: g0->lba_low = ((unsigned char *) &count)[1];
296: g0->xfr_len = ((unsigned char *) &count)[0];
297: g0->control = 0;
298: doscsi(r, 4, pritape, slpriSigCatch, "writefm");
299: if (r->status != ST_GOOD && printerror(r, "Write filemarks failed"))
300: u. u_error = EIO;
301: c->state = CTIDLE;
302: } /* writefm() */
303:
304: /***********************************************************************
305: * space()
306: *
307: * Space over blocks/filemarks/etc.
308: */
309:
310: static void space(c, count, object)
311: register ctctrl_p c;
312: int count;
313: int object;
314: {
315: register srb_p r = &(c->srb);
316: register g0cmd_p g0 = &(r->cdb. g0);
317:
318: if (!ctbusywait(c, CTSPACE))
319: return;
320: r->buf. space = (int) r->buf. addr. caddr = r->buf. size = 0;
321: r->xferdir = 0;
322: r->timeout = 300;
323: g0->opcode = SPACE;
324: g0->lun_lba = (r->lun << 5) | (object & 3);
325: g0->lba_mid = ((unsigned char *) &count)[2];
326: g0->lba_low = ((unsigned char *) &count)[1];
327: g0->xfr_len = ((unsigned char *) &count)[0];
328: g0->control = 0;
329: doscsi(r, 2, pritape, slpriSigCatch, "space");
330: if (r->status != ST_GOOD && printerror(r, "Space failed"))
331: u. u_error = EIO;
332: c->state = CTIDLE;
333: } /* space() */
334:
335: /***********************************************************************
336: * rewind()
337: *
338: * Rewind the tape drive back to the load point.
339: */
340:
341: static void rewind(c, wait)
342: register ctctrl_p c;
343: int wait;
344: {
345: register srb_p r = &(c->srb);
346: register g0cmd_p g0 = &(r->cdb. g0);
347:
348: if (!ctbusywait(c, CTREWIND))
349: return;
350: r->buf. space = (int) r->buf. addr. caddr = r->buf. size = 0;
351: r->timeout = 300;
352: r->xferdir = 0;
353: memset(g0, 0, sizeof(cdb_t));
354: g0->opcode = REWINDTAPE;
355: if (!wait)
356: g0->lun_lba = (r->lun << 5) | 1;
357: doscsi(r, 2, pritape, slpriSigCatch, "rewind");
358: if (r->status != ST_GOOD && printerror(r, "Rewind failed"))
359: u. u_error = EIO;
360: c->flags = 0;
361: c->state = CTIDLE;
362: } /* rewind() */
363:
364: static void erase(c, to_eot)
365: register ctctrl_p c;
366: int to_eot;
367: {
368: register srb_p r = &(c->srb);
369: register g0cmd_p g0 = &(r->cdb. g0);
370:
371: if (!ctbusywait(c, CTERASE))
372: return;
373: r->buf. space = (int) r->buf. addr. caddr = r->buf. size = 0;
374: r->timeout = 300;
375: r->xferdir = 0;
376: memset(g0, 0, sizeof(cdb_t));
377: g0->opcode = ERASE;
378: g0->lun_lba = (r->lun << 5);
379: if (to_eot)
380: g0->lun_lba |= 1;
381: doscsi(r, 2, pritape, slpriSigCatch, "erase");
382: if (r->status != ST_GOOD && printerror(r, "Erase failed"))
383: u. u_error = EIO;
384: if (to_eot)
385: c->flags &= ~(CTFILEMARK | CTEOM | CTILI | CTDIRTY);
386: c->state = CTIDLE;
387: } /* erase() */
388:
389: /***********************************************************************
390: * Device Driver Entry Point routines. *
391: ***********************************************************************/
392:
393: /***********************************************************************
394: * ctinit()
395: *
396: * Initialize the tape device at (id). This doesn't do anything,
397: * not even verify that the drive is there because it could be powered
398: * off.
399: */
400:
401: static int ctinit(id)
402: register int id;
403: {
404: register ctctrl_p c = kalloc(sizeof(ctctrl_t));
405:
406: if (!c) {
407: printf("\tTape Driver: Could not allocate control structure.\n");
408: return 0;
409: }
410:
411: printf("\tCoherent SCSI Tape driver v1.1\n");
412: memset(c, 0, sizeof(ctctrl_t));
413: c->inuse = 0;
414: c->cache = c->start = NULL;
415: c->cachesize = HAICACHESZ;
416: c->srb. target = id;
417: c->srb. lun = 0;
418: c->state = CTIDLE;
419: ctdevs[id] = c;
420: return 1;
421: }
422:
423: static void ctopen(dev, mode)
424: dev_t dev;
425: int mode;
426: {
427: register ctctrl_p c = ctdevs[tid(dev)];
428: register srb_p r = &(c->srb);
429: register g0cmd_p g0 = &(r->cdb. g0);
430: int rblerf; /* read block limits error flag */
431: int s;
432: char buf[64];
433: blkdscr_p bd = (blkdscr_p) (buf + 4);
434: blklim_p bl = (blklim_p) (buf);
435:
436: if (!c) {
437: u. u_error = ENXIO;
438: return;
439: }
440: if ((mode != IPR) && (mode != IPW)) {
441: u. u_error = EINVAL;
442: return;
443: }
444:
445: s = sphi();
446:
447: if (c->inuse) {
448: u. u_error = EDBUSY;
449: goto done;
450: }
451:
452: c->inuse = 1;
453: c->state = CTINIT;
454: r->dev = dev; /* Save the rewind bit for close. */
455:
456: /***********************************************************************
457: * Repeat the test unit ready command to the tape drive. This tells
458: * the state of the tape drive. Repeating the command also clears out
459: * the request sense condition which comes after each time the user
460: * changes tapes.
461: */
462:
463: r->timeout = 2;
464: r->buf. space = (int) r->buf. addr. caddr = r->buf. size = 0;
465: r->xferdir = 0;
466: memset(g0, 0, sizeof(cdb_t)); /* Test Unit Ready */
467: memset(r->sensebuf, 0, sizeof(r->sensebuf));
468: doscsi(r, 4, pritape, slpriSigCatch, "ctopen");
469:
470: /***********************************************************************
471: * If the command fails there probably wasn't a tape in the drive.
472: */
473:
474: if (r->status != ST_GOOD) { /* Is there a tape in the drive? */
475: if (r->status != ST_USRABRT) {
476: /* Otherwise assume no tape. */
477: u. u_error = ENXIO;
478: devmsg(r->dev, "Tape drive not ready.");
479: goto openfailed;
480: }
481: }
482: #ifdef TDC3600
483:
484: /***********************************************************************
485: * TDC3600's do a retension after all bus device resets and tape changes
486: * so I block in the open routine waiting for that operation to complete.
487: * This is a kludge to fix the author's system. I anticipate that
488: * other host adapters may not be so kind about retrying commands
489: * until a device reports that it is no longer busy. Hence the error
490: * message when this command fails. All this really does is allows
491: * me to safely start applications while the initial retension is still
492: * happening [csh].
493: */
494:
495: else {
496: if (r->sensebuf[0] == 0x70 && r->sensebuf[2] == 0x06) {
497:
498: /* Yep, The user just put it there */
499:
500: r->buf. space = (int) r->buf. addr. caddr = r->buf. size = 0;
501: r->xferdir = 0;
502: r->timeout = 300;
503: memset(g0, 0, sizeof(cdb_t));
504: g0->opcode = LOAD;
505: g0->xfr_len = 1; /* Move tape to load point. */
506: doscsi(r, 4, pritape, slpriSigCatch, "ctopen");
507: if (r->status != ST_GOOD &&
508: printerror(r, "Load failed - TDC3600 not ready")) {
509: u. u_error = ENXIO;
510: goto openfailed;
511: }
512: }
513: }
514: #endif
515:
516: ctvmsg(0x0100, (devmsg(r->dev, "Read block limits.")));
517: #ifdef TDC3600
518: c->blmin = c->blmax = 512;
519: ctvmsg(0x0100, (devmsg(r->dev, "Tandberg TDC36XX - Block limits set")));
520: rblerf = 0;
521: #else
522: r->buf. space = KRNL_ADDR;
523: r->buf. addr. caddr = (caddr_t) bl;
524: r->buf. size = sizeof(blklim_t);
525: r->xferdir = DMAREAD;
526: r->timeout = 2;
527: memset(g0, 0, sizeof(cdb_t));
528: g0->opcode = READBLKLMT;
529: g0->xfr_len = 6;
530: doscsi(r, 3, pritape, slpriSigCatch, "ctopen");
531:
532: /***********************************************************************
533: * This is a bit oblique: The Read Block limits is used to determine
534: * what the tape drive that we have can do. I have yet to run into
535: * a tape drive that can do variable mode yet so I'm just winging
536: * this. In any case all I did was make it okay for the Archive Tape
537: * drives to say "I don't support that command".
538: */
539:
540: if (rblerf = (r->status != ST_GOOD)) {
541: ctvmsg(0x0010, (printerror(r, "Read Block LImits")));
542: c->blmax = c->blmin = 0;
543: }
544: else {
545: flip(bl->blmax); /* SCSI to INTEL order */
546: flip(bl->blmin); /* Ditto */
547: c->blmax = (bl->blmax & 0x00ffffff);
548: c->blmin = bl->blmin;
549: }
550: #endif
551:
552: /***********************************************************************
553: * Use mode sense to find out if the tape is write protected and also
554: * to find out what the current tape blocksize is.
555: */
556:
557: r->buf. space = KRNL_ADDR;
558: r->buf. addr. caddr = (caddr_t) buf;
559: r->buf. size = sizeof(buf);
560: r->xferdir = DMAREAD;
561: r->timeout = 2;
562: memset(g0, 0, sizeof(cdb_t));
563: g0->opcode = MODESENSE;
564: g0->xfr_len = sizeof(buf);
565: doscsi(r, 3, pritape, slpriSigCatch, "ctopen");
566: if (r->status != ST_GOOD) {
567: if (printerror(r, "Mode sense failed"))
568: u. u_error = EIO;
569: goto openfailed;
570: }
571:
572: /***********************************************************************
573: * If tape drive opened in write mode make sure the tape is not write
574: * protected now.
575: */
576:
577: if (mode == IPW && (buf[2] & 0x80) != 0) {
578: devmsg(dev, "Tape is write protected");
579: u. u_error = ENXIO;
580: goto openfailed;
581: }
582:
583: /***********************************************************************
584: * If mode sense returned any media descriptors take the first one,
585: * it's the default, and use it.
586: *
587: * There are two possible pitfalls here:
588: *
589: * 1) According to SCSI-1 it not an error to return zero block
590: * descriptors. If you're favorite drive returns zero block descriptors
591: * this driver will fail here.
592: *
593: * 2) I am assuming that the first media descriptor returned is
594: * the "current" media type which the drive expects to use. This
595: * works with SCSI-2 but SCSI-1 says that the first descriptor is
596: * the "default" media type. SCSI-1 is lacking in the definition
597: * of "default" for my conservative taste (when programming is
598: * concerned).
599: *
600: * I would like to put the issue of supporting real oddball tape drives
601: * like my Tandberg to rest and only have one source source file for
602: * scsi tape drives but I don't think that will work. In the future
603: * there will probably be two or maybe three if DAT proves to be as
604: * much fun as this is.
605: */
606:
607: if (buf[3]) { /* If mode sense returned any media descriptors */
608: bd->rb. blocksize &= 0xffffff00;
609: flip(bd->rb. blocksize);
610: c->block = bd->rb. blocksize;
611: if (c->block && c->cachesize % c->block)
612: c->cachesize -= (c->cachesize % c->block);
613: }
614: else {
615: devmsg(r->dev, "No media descriptors: Contact Mark Williams Tech support");
616: u. u_error = ENXIO;
617: goto openfailed;
618: }
619: ctvmsg(0x0001, devmsg(dev, "Blocksize: %d bytes.", c->block));
620:
621: /***********************************************************************
622: * One last check: If we aren't using block mode (!c->block)
623: * and we didn't get any block limits then we cannot support this
624: * drive.
625: */
626:
627: if (!c->block && rblerf) {
628: devmsg(r->dev, "<No block limits on variable mode tape drive>");
629: devmsg(r->dev, "<Contact Mark Williams Tech Support>");
630: u. u_error = ENXIO;
631: goto openfailed;
632: }
633:
634: c->flags = (mode == IPR) ? CTRDMD : CTWRTMD;
635: if (c->block) {
636: c->cache = kalloc(HAICACHESZ);
637: if (!c->cache) {
638: devmsg(dev, "Could not allocate tape cache");
639: u. u_error = ENOMEM;
640: goto openfailed;
641: }
642: c->avail = (c->flags & CTRDMD) ? 0 : HAICACHESZ;
643: c->start = c->cache;
644: }
645: c->state = CTIDLE;
646: goto done;
647:
648: openfailed:
649: c->state = CTIDLE;
650: c->inuse = 0;
651:
652: done:
653: spl(s);
654: } /* ctopen() */
655:
656: /***********************************************************************
657: * ctclose()
658: *
659: * Close the SCSI Device at (dev).
660: */
661:
662: static void ctclose(dev)
663: register dev_t dev;
664: {
665: register ctctrl_p c = ctdevs[tid(dev)];
666: register srb_p r = &(c->srb);
667: int s;
668:
669: if (!c) {
670: u. u_error = ENXIO;
671: return;
672: }
673:
674: s = sphi();
675: if (c->block && (c->flags & CTWRTMD)) {
676: if (ctbusywait(c, CTLASTWRT))
677: flushcache(c);
678: c->state = CTIDLE;
679: }
680: spl(s);
681: if (c->cache) {
682: kfree(c->cache);
683: c->cache = c->start = NULL;
684: c->avail = 0;
685: }
686:
687: #ifndef TDC3600
688: /*
689: * Write two filemarks (Logical End of Tape) and then skip backwards
690: * over one of them to ready for the another write operation on the
691: * no rewind device. This code guarantees properly formed tapes according
692: * to the wisened old nine-track hacker that I work with. The problem
693: * is that...
694: */
695: if (c->flags & CTDIRTY) {
696: writefm(c, 1); /* Write a file mark */
697: writefm(c, 1); /* Write another filemark */
698: space(c, -1, SKIP_FM); /* Go back to the first filemark */
699: }
700: #else
701: /*
702: * ... problem is that my Tandberg considers it an error to do anything
703: * after it has skipped past a filemark. So all commands except load and
704: * rewind fail after the previous code. The following will work in
705: * all situations but there is a risk that a user's tapes will only
706: * have one filemark at Logical End-of-Tape if the user isn't careful
707: * to use the rewind device the last time he uses tape drive. This is
708: * only a problem with drives which insist upon doing a Retension each
709: * time the tape is changed or the drive gets reset.
710: */
711: if (c->flags & CTDIRTY) {
712: writefm(c, 1);
713: if (r->dev & REWIND)
714: writefm(c, 1);
715: }
716: #endif
717:
718: if (r->dev & REWIND)
719: rewind(c, 0);
720:
721: c->inuse = 0;
722: return;
723: } /* ctclose() */
724:
725: /***********************************************************************
726: * fillcache() -- Read from the tape into the cache (really?)
727: *
728: * return 0 and set u. u_error on any errors.
729: */
730:
731: static int fillcache(c)
732: register ctctrl_p c;
733: {
734: register srb_p r = (&c->srb);
735: register g0cmd_p g0 = &(r->cdb. g0);
736: size_t blocks;
737: extsense_p e;
738: int info;
739: int retval = 0;
740:
741: r->buf. space = KRNL_ADDR;
742: r->buf. addr. caddr = (caddr_t) c->cache;
743: r->buf. size = HAICACHESZ;
744: r->xferdir = DMAREAD;
745: r->timeout = 30;
746: r->tries = 0;
747: g0->opcode = READ;
748: g0->lun_lba = (r->lun << 5) | 1;
749: blocks = HAICACHESZ / c->block;
750: g0->lba_mid = ((unsigned char *) &blocks)[2];
751: g0->lba_low = ((unsigned char *) &blocks)[1];
752: g0->xfr_len = ((unsigned char *) &blocks)[0];
753: g0->control = 0;
754: doscsi(r, 1, pritape, slpriSigCatch, "ctblkrd");
755: switch (r->status) {
756: case ST_GOOD:
757: c->start = c->cache;
758: c->avail = r->buf. size;
759: retval = 1;
760: break;
761: case ST_CHKCOND:
762: e = r->sensebuf;
763: if ((e->errorcode & 0x70) == 0x70) {
764: info = 0;
765: if (e->errorcode & 0x80) {
766: info = e->info;
767: flip(info);
768: }
769: if (e->sensekey & (CTFILEMARK | CTEOM)) {
770: c->flags |= (e->sensekey & (CTFILEMARK | CTEOM));
771: c->start = c->cache;
772: c->avail = HAICACHESZ - (info * c->block);
773: retval = 1;
774: break;
775: }
776: }
777: printsense(r->dev, "Read failed", r->sensebuf);
778: u. u_error = EIO;
779: retval = 0;
780: break;
781: case ST_USRABRT:
782: u. u_error = EINTR;
783: c->start = c->cache;
784: c->avail = 0;
785: retval = 0;
786: break;
787: default:
788: devmsg(r->dev, "Read failed: status (0x%x)", r->status);
789: u. u_error = EIO;
790: retval = 0;
791: break;
792: }
793: return retval;
794: } /* fillcache() */
795:
796: /***********************************************************************
797: * ctfbrd() -- Fixed block read handler. Reads from the tape
798: * drive through the cache when the tape drive is
799: * in fixed block mode.
800: */
801:
802: static void ctfbrd(c, iop)
803: register ctctrl_p c;
804: register IO *iop;
805: {
806: register size_t reqcount, /* Total bytes transfered toward request */
807: xfrsize; /* Current transfer size */
808: size_t total, /* System global memory total transfer size */
809: size; /* System global memory current transfer size */
810:
811: if (!ctbusywait(c, CTFBRD))
812: return;
813: reqcount = 0;
814: while (iop->io_ioc) {
815: xfrsize = min(c->avail, iop->io_ioc);
816: if (xfrsize > 0) {
817: switch (iop->io_seg) {
818: case IOSYS:
819: memcpy(iop->io. vbase + reqcount, c->start, xfrsize);
820: break;
821: case IOUSR:
822: kucopy(c->start, iop->io. vbase + reqcount, xfrsize);
823: break;
824: case IOPHY:
825: total = 0;
826: while (total < xfrsize) {
827: size = min(xfrsize - total, NBPC);
828: xpcopy(c->start + total,
829: iop->io. pbase + reqcount + total,
830: size,
831: SEG_386_KD | SEG_VIRT);
832: total += size;
833: }
834: break;
835: }
836: c->start += xfrsize;
837: c->avail -= xfrsize;
838: reqcount += xfrsize;
839: iop->io_ioc -= xfrsize;
840: }
841: if (iop->io_ioc) {
842: if (c->flags & CTFILEMARK) {
843: c->flags &= ~CTFILEMARK;
844: break;
845: }
846:
847: if (c->flags & CTEOM) {
848: u. u_error = EIO;
849: break;
850: }
851:
852: if (!fillcache(c))
853: break;
854: }
855: } /* while */
856: c->state = CTIDLE;
857: } /* ctfbrd() */
858:
859: /***********************************************************************
860: * ctvbrd() -- Variable block read entry point.
861: */
862:
863: static void ctvbrd(c, iop)
864: register ctctrl_p c;
865: IO *iop;
866: {
867: register srb_p r = &(c->srb);
868: register g0cmd_p g0 = &(r->cdb. g0);
869: size_t xfrsize;
870: extsense_p e;
871: int info;
872:
873: if (!ctbusywait(c, CTVBRD))
874: return;
875:
876: if (c->flags & CTEOM) {
877: u. u_error = EIO;
878: return;
879: }
880: if (c->flags & CTFILEMARK) {
881: c->flags &= ~CTFILEMARK;
882: return;
883: }
884: switch (iop->io_seg) {
885: case IOSYS:
886: r->buf. space = KRNL_ADDR;
887: r->buf. addr. caddr = iop->io. vbase;
888: break;
889: case IOUSR:
890: r->buf. space = USER_ADDR;
891: r->buf. addr. caddr = iop->io. vbase;
892: break;
893: case IOPHY:
894: r->buf. space = PHYS_ADDR;
895: r->buf. addr. paddr = iop->io. pbase;
896: break;
897: }
898: r->buf. size = xfrsize = iop->io_ioc;
899: r->xferdir = DMAREAD;
900: r->timeout = 30;
901: g0->opcode = READ;
902: g0->lun_lba = (r->lun << 5);
903: g0->lba_mid = ((unsigned char *) &xfrsize)[2];
904: g0->lba_low = ((unsigned char *) &xfrsize)[1];
905: g0->xfr_len = ((unsigned char *) &xfrsize)[0];
906: g0->control = 0;
907: doscsi(r, 1, pritape, slpriSigCatch, "ctvbrd");
908: switch (r->status) {
909: case ST_GOOD:
910: iop->io_ioc -= r->buf. size;
911: break;
912: case ST_CHKCOND:
913: e = r->sensebuf;
914: if ((e->errorcode & 0x70) == 0x70) {
915: info = 0;
916: if (e->errorcode & 0x80) {
917: info = (long) e->info;
918: flip(info);
919: }
920: if (e->sensekey & (CTFILEMARK | CTEOM)) {
921: c->flags |= (e->sensekey & (CTFILEMARK | CTEOM));
922: break;
923: }
924: else if (e->sensekey & CTILI) {
925: devmsg(r->dev,
926: "Read failed buffer size %d blocksize %d",
927: xfrsize,
928: xfrsize - info);
929: if (info > 0)
930: iop->io_ioc -= (xfrsize - info);
931: else
932: u. u_error = EIO;
933: break;
934: }
935: }
936: printsense(r->dev, "Read failed", r->sensebuf);
937: u. u_error = EIO;
938: break;
939: case ST_USRABRT:
940: break;
941: default:
942: devmsg(r->dev, "Read failed: status (0x%x)", r->status);
943: u. u_error = EIO;
944: break;
945: }
946: c->state = CTIDLE;
947: } /* ctvbrd() */
948:
949: /***********************************************************************
950: * ctread() -- OS Read entry point.
951: */
952:
953: static void ctread(dev, iop)
954: dev_t dev;
955: register IO *iop;
956: {
957: register ctctrl_p c = ctdevs[tid(dev)];
958:
959: if (!c) {
960: u. u_error = EINVAL;
961: return;
962: }
963:
964: if (c->block)
965: ctfbrd(c, iop);
966: else
967: ctvbrd(c, iop);
968: } /* ctread() */
969:
970: /***********************************************************************
971: * flushcache() -- flush the data in the cache to the tape.
972: *
973: * returns 0 and sets u. u_error on failure else returns 1.
974: */
975:
976: static int flushcache(c)
977: register ctctrl_p c;
978: {
979: register srb_p r = (&c->srb);
980: register g0cmd_p g0 = &(r->cdb. g0);
981: size_t xfrsize;
982: extsense_p e;
983: int info;
984: int retval = 0;
985:
986: if (c->avail >= HAICACHESZ)
987: return 1;
988:
989: r->buf. space = KRNL_ADDR;
990: r->buf. addr. caddr = (caddr_t) c->cache;
991: r->buf. size = xfrsize = HAICACHESZ - c->avail;
992: r->xferdir = DMAWRITE;
993: r->timeout = 30;
994: r->tries = 0;
995: g0->opcode = WRITE;
996: g0->lun_lba = (r->lun << 5);
997: if (c->block) {
998: g0->lun_lba |= 1;
999: xfrsize = (xfrsize + c->block - 1) / c->block;
1000: }
1001: g0->lba_mid = ((unsigned char *) &xfrsize)[2];
1002: g0->lba_low = ((unsigned char *) &xfrsize)[1];
1003: g0->xfr_len = ((unsigned char *) &xfrsize)[0];
1004: g0->control = 0;
1005: doscsi(r, 1, pritape, slpriSigCatch, "ctblkwrt");
1006: switch (r->status) {
1007: case ST_GOOD:
1008: c->start = c->cache;
1009: c->avail = HAICACHESZ;
1010: retval = 1;
1011: break;
1012: case ST_CHKCOND:
1013: e = r->sensebuf;
1014: if ((e->errorcode & 0x70) == 0x70) {
1015: info = 0;
1016: if (e->errorcode & 0x80) {
1017: info = e->info;
1018: flip(info);
1019: }
1020: if (e->sensekey & CTEOM) {
1021: c->flags |= CTEOM;
1022: devmsg(r->dev, "End of tape on block write");
1023: }
1024: }
1025: printsense(r->dev, "Read failed", r->sensebuf);
1026: u. u_error = EIO;
1027: retval = 0;
1028: break;
1029: case ST_USRABRT:
1030: retval = 0;
1031: break;
1032: default:
1033: devmsg(r->dev, "Read failed: status (0x%x)", r->status);
1034: u. u_error = EIO;
1035: retval = 0;
1036: break;
1037: }
1038: return retval;
1039: } /* flushcache() */
1040:
1041: /***********************************************************************
1042: * ctfbwrt() -- Fixed block write. This should be fast because
1043: * it uses the tapes drives optimum setting and it
1044: * goes through a cache.
1045: */
1046:
1047: static void ctfbwrt(c, iop)
1048: register ctctrl_p c;
1049: register IO *iop;
1050: {
1051: register size_t reqcount, /* Total bytes transfered */
1052: xfrsize; /* Current transfer size */
1053: size_t total, /* System global memory total transfer size */
1054: size; /* System global memory current transfer size */
1055:
1056: if (!ctbusywait(c, CTFBWRT))
1057: return;
1058:
1059: reqcount = 0;
1060: while (iop->io_ioc) {
1061: xfrsize = min(c->avail, iop->io_ioc);
1062: if (xfrsize) {
1063: switch (iop->io_seg) {
1064: case IOSYS:
1065: memcpy(c->start, iop->io. vbase + reqcount, xfrsize);
1066: break;
1067: case IOUSR:
1068: ukcopy(iop->io. vbase + reqcount, c->start, xfrsize);
1069: break;
1070: case IOPHY:
1071: total = 0;
1072: while (total < xfrsize) {
1073: size = min(xfrsize - total, NBPC);
1074: pxcopy(iop->io. pbase + reqcount + total,
1075: c->start + total,
1076: size,
1077: SEG_386_KD | SEG_VIRT);
1078: total += size;
1079: }
1080: break;
1081: }
1082: c->start += xfrsize;
1083: c->avail -= xfrsize;
1084: reqcount += xfrsize;
1085: iop->io_ioc -= xfrsize;
1086: }
1087: if (iop->io_ioc) {
1088: if (!flushcache(c))
1089: break;
1090: }
1091: } /* while */
1092: c->state = CTIDLE;
1093: } /* ctfbwrt() */
1094:
1095: /***********************************************************************
1096: * ctvbwrt() -- Variable block writes.
1097: */
1098:
1099: static void ctvbwrt(c, iop)
1100: register ctctrl_p c;
1101: register IO *iop;
1102: {
1103: register srb_p r = &(c->srb);
1104: register g0cmd_p g0 = &(r->cdb. g0);
1105: size_t xfrsize;
1106: extsense_p e;
1107: int info;
1108:
1109: if (!ctbusywait(c, CTVBWRT))
1110: return;
1111:
1112: if (c->blmax && iop->io_ioc > c->blmax) {
1113: devmsg(r->dev, "Tape Error: maximum read/write size is %d bytes.", c->blmax);
1114: u. u_error = EIO;
1115: return;
1116: }
1117: switch (iop->io_seg) {
1118: case IOSYS:
1119: r->buf. space = KRNL_ADDR;
1120: r->buf. addr. caddr = iop->io. vbase;
1121: break;
1122: case IOUSR:
1123: r->buf. space = USER_ADDR;
1124: r->buf. addr. caddr = iop->io. vbase;
1125: break;
1126: case IOPHY:
1127: r->buf. space = PHYS_ADDR;
1128: r->buf. addr. paddr = iop->io. pbase;
1129: break;
1130: }
1131: xfrsize = min(iop->io_ioc, c->blmin);
1132: r->buf. size = xfrsize;
1133: r->xferdir = DMAWRITE;
1134: r->timeout = 30;
1135: g0->opcode = WRITE;
1136: g0->lun_lba = (r->lun << 5);
1137: g0->lba_mid = ((unsigned char *) &xfrsize)[2];
1138: g0->lba_low = ((unsigned char *) &xfrsize)[1];
1139: g0->xfr_len = ((unsigned char *) &xfrsize)[0];
1140: g0->control = 0;
1141: doscsi(r, 1, pritape, slpriSigCatch, "ctvbwrt");
1142: switch (r->status) {
1143: case ST_GOOD:
1144: iop->io_ioc -= r->buf. size;
1145: break;
1146: case ST_CHKCOND:
1147: e = r->sensebuf;
1148: if ((e->errorcode & 0x70) == 0x70) {
1149: info = 0;
1150: if (e->errorcode & 0x80) {
1151: info = (long) e->info;
1152: flip(info);
1153: }
1154: if (e->sensekey & CTEOM) {
1155: c->flags |= CTEOM;
1156: devmsg(r->dev, "End of tape");
1157: }
1158: }
1159: printsense(r->dev, "Write failed", r->sensebuf);
1160: u. u_error = EIO;
1161: break;
1162: case ST_USRABRT:
1163: break;
1164: default:
1165: devmsg(r->dev, "Read failed: status (0x%x)", r->status);
1166: u. u_error = EIO;
1167: break;
1168: }
1169: c->state = CTIDLE;
1170: } /* ctvbwrt() */
1171:
1172: /***********************************************************************
1173: * ctwrite() -- Write entry point for tape drive.
1174: */
1175:
1176: static void ctwrite(dev, iop)
1177: register dev_t dev;
1178: register IO *iop;
1179: {
1180: register ctctrl_p c = ctdevs[tid(dev)];
1181:
1182: if (!c) {
1183: u. u_error = ENXIO;
1184: return;
1185: }
1186:
1187: c->flags |= CTDIRTY;
1188: if (c->block)
1189: ctfbwrt(c, iop);
1190: else
1191: ctvbwrt(c, iop);
1192: } /* ctwrite() */
1193:
1194: /***********************************************************************
1195: * ctioctl()
1196: *
1197: * I/O Control Entry point for Cartridge tape devices.
1198: *
1199: * This function had been modified to allow applications level programs
1200: * to select modes and features for the tape drive. As stated above,
1201: * the philosophy of this driver is to provide least common denominator
1202: * support for all tape drives. I know that you spend big bucks to
1203: * get that (insert your favorite drive brand/model). If I decide
1204: * to support everything out there on the market then I won't be able
1205: * to write network drivers, serial drivers, etc. So if you need
1206: * to do something to the tape drive to make it work (mode sense/select)
1207: * you can do it through this ctioctl as an applications program.
1208: */
1209:
1210: static void ctioctl(dev, cmd, vec)
1211: dev_t dev;
1212: register int cmd;
1213: char *vec;
1214: {
1215: register ctctrl_p c = ctdevs[tid(dev)];
1216: register srb_p r = &(c->srb);
1217: int s;
1218:
1219: if (!c) {
1220: u. u_error = EINVAL;
1221: return;
1222: }
1223:
1224: switch (cmd) {
1225: case MTREWIND: /* Rewind */
1226: rewind(c, 1);
1227: break;
1228: case MTWEOF: /* Write end of file mark */
1229: writefm(c, 1);
1230: break;
1231: case MTRSKIP: /* Record skip */
1232: space(c, 1, SKIP_BLK);
1233: break;
1234: case MTFSKIP: /* File skip */
1235: space(c, 1, SKIP_FM);
1236: break;
1237: case MTTENSE: /* Tension tape */
1238: loadtape(c, RETENSION);
1239: break;
1240: case MTERASE: /* Erase tape */
1241: erase(c, ERASE_TAPE);
1242: break;
1243: case MTDEC: /* DEC mode */
1244: case MTIBM: /* IBM mode */
1245: case MT800: /* 800 bpi */
1246: case MT1600: /* 1600 bpi */
1247: case MT6250: /* 6250 bpi */
1248: return;
1249: default:
1250: if (!ctbusywait(c, CTIOCTL))
1251: return;
1252: s = sphi();
1253: haiioctl(r, cmd, vec);
1254: c->state = CTIDLE;
1255: spl(s);
1256: break;
1257: }
1258: } /* ctioctl() */
1259:
1260: /* End of file */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.