Annotation of sys/arch/vax/mscp/mscp_tape.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: mscp_tape.c,v 1.10 2007/06/06 17:15:13 deraadt Exp $ */
2: /* $NetBSD: mscp_tape.c,v 1.16 2001/11/13 07:38:28 lukem Exp $ */
3: /*
4: * Copyright (c) 1996 Ludd, University of Lule}, Sweden.
5: * All rights reserved.
6: *
7: * Redistribution and use in source and binary forms, with or without
8: * modification, are permitted provided that the following conditions
9: * are met:
10: * 1. Redistributions of source code must retain the above copyright
11: * notice, this list of conditions and the following disclaimer.
12: * 2. Redistributions in binary form must reproduce the above copyright
13: * notice, this list of conditions and the following disclaimer in the
14: * documentation and/or other materials provided with the distribution.
15: * 3. All advertising materials mentioning features or use of this software
16: * must display the following acknowledgement:
17: * This product includes software developed at Ludd, University of
18: * Lule}, Sweden and its contributors.
19: * 4. The name of the author may not be used to endorse or promote products
20: * derived from this software without specific prior written permission
21: *
22: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
23: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25: * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
26: * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
27: * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
31: * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32: */
33:
34:
35: /*
36: * MSCP tape device driver
37: */
38:
39: /*
40: * TODO
41: * Write status handling code.
42: */
43:
44: #include <sys/cdefs.h>
45:
46: #include <sys/param.h>
47: #include <sys/device.h>
48: #include <sys/kernel.h>
49: #include <sys/buf.h>
50: #include <sys/ioccom.h>
51: #include <sys/mtio.h>
52: #include <sys/fcntl.h>
53: #include <sys/malloc.h>
54: #include <sys/systm.h>
55: #include <sys/proc.h>
56:
57: #include <machine/bus.h>
58: #include <machine/cpu.h>
59:
60: #include <arch/vax/mscp/mscp.h>
61: #include <arch/vax/mscp/mscpreg.h>
62: #include <arch/vax/mscp/mscpvar.h>
63:
64: /*
65: * Drive status, per drive
66: */
67: struct mt_softc {
68: struct device mt_dev; /* Autoconf struct */
69: int mt_state; /* open/closed state */
70: int mt_hwunit; /* Hardware unit number */
71: int mt_inuse; /* Locks the tape drive for others */
72: int mt_waswrite; /* Last operation was a write op */
73: int mt_serex; /* Got serious exception */
74: int mt_ioctlerr; /* Error after last ioctl */
75: };
76:
77: #define MT_OFFLINE 0
78: #define MT_ONLINE 1
79:
80: int mtmatch(struct device *, struct cfdata *, void *);
81: void mtattach(struct device *, struct device *, void *);
82: void mtdgram(struct device *, struct mscp *, struct mscp_softc *);
83: void mtiodone(struct device *, struct buf *);
84: int mtonline(struct device *, struct mscp *);
85: int mtgotstatus(struct device *, struct mscp *);
86: int mtioerror(struct device *, struct mscp *, struct buf *);
87: void mtfillin(struct buf *, struct mscp *);
88: int mtopen(dev_t, int, int, struct proc *);
89: int mtclose(dev_t, int, int, struct proc *);
90: void mtstrategy(struct buf *);
91: int mtread(dev_t, struct uio *);
92: int mtwrite(dev_t, struct uio *);
93: int mtioctl(dev_t, int, caddr_t, int, struct proc *);
94: int mtdump(dev_t, daddr64_t, caddr_t, size_t);
95: int mtcmd(struct mt_softc *, int, int, int);
96: void mtcmddone(struct device *, struct mscp *);
97: int mt_putonline(struct mt_softc *);
98:
99: struct mscp_device mt_device = {
100: mtdgram,
101: mtiodone,
102: mtonline,
103: mtgotstatus,
104: 0,
105: mtioerror,
106: 0,
107: mtfillin,
108: mtcmddone,
109: };
110:
111: /* This is not good, should allow more than 4 tapes/device type */
112: #define mtunit(dev) (minor(dev) & T_UNIT)
113: #define mtnorewind(dev) (dev & T_NOREWIND)
114: #define mthdensity(dev) (dev & T_1600BPI)
115:
116: struct cfattach mt_ca = {
117: sizeof(struct mt_softc), (cfmatch_t)mtmatch, mtattach
118: };
119:
120: struct cfdriver mt_cd = {
121: NULL, "mt", DV_TAPE
122: };
123:
124: /*
125: * More driver definitions, for generic MSCP code.
126: */
127:
128: int
129: mtmatch(parent, cf, aux)
130: struct device *parent;
131: struct cfdata *cf;
132: void *aux;
133: {
134: struct drive_attach_args *da = aux;
135: struct mscp *mp = da->da_mp;
136:
137: if ((da->da_typ & MSCPBUS_TAPE) == 0)
138: return 0;
139: if (cf->cf_loc[0] != -1 && cf->cf_loc[0] != mp->mscp_unit)
140: return 0;
141: return 1;
142: }
143:
144: /*
145: * The attach routine only checks and prints drive type.
146: */
147: void
148: mtattach(parent, self, aux)
149: struct device *parent, *self;
150: void *aux;
151: {
152: struct mt_softc *mt = (void *)self;
153: struct drive_attach_args *da = aux;
154: struct mscp *mp = da->da_mp;
155: struct mscp_softc *mi = (void *)parent;
156:
157: mt->mt_hwunit = mp->mscp_unit;
158: mi->mi_dp[mp->mscp_unit] = self;
159:
160: disk_printtype(mp->mscp_unit, mp->mscp_guse.guse_mediaid);
161: }
162:
163: /*
164: * (Try to) put the drive online. This is done the first time the
165: * drive is opened, or if it has fallen offline.
166: */
167: int
168: mt_putonline(mt)
169: struct mt_softc *mt;
170: {
171: struct mscp *mp;
172: struct mscp_softc *mi = (struct mscp_softc *)mt->mt_dev.dv_parent;
173: volatile int i;
174:
175: (volatile int)mt->mt_state = MT_OFFLINE;
176: mp = mscp_getcp(mi, MSCP_WAIT);
177: mp->mscp_opcode = M_OP_ONLINE;
178: mp->mscp_unit = mt->mt_hwunit;
179: mp->mscp_cmdref = (long)&mt->mt_state;
180: *mp->mscp_addr |= MSCP_OWN | MSCP_INT;
181:
182: /* Poll away */
183: i = bus_space_read_2(mi->mi_iot, mi->mi_iph, 0);
184: if (tsleep(&mt->mt_state, PRIBIO, "mtonline", 240 * hz))
185: return MSCP_FAILED;
186:
187: if ((volatile int)mt->mt_state != MT_ONLINE)
188: return MSCP_FAILED;
189:
190: return MSCP_DONE;
191: }
192: /*
193: * Open a drive.
194: */
195: /*ARGSUSED*/
196: int
197: mtopen(dev, flag, fmt, p)
198: dev_t dev;
199: int flag, fmt;
200: struct proc *p;
201: {
202: struct mt_softc *mt;
203: int unit;
204:
205: /*
206: * Make sure this is a reasonable open request.
207: */
208: unit = mtunit(dev);
209: if (unit >= mt_cd.cd_ndevs)
210: return ENXIO;
211: mt = mt_cd.cd_devs[unit];
212: if (mt == 0)
213: return ENXIO;
214:
215: if (mt->mt_inuse)
216: return EBUSY;
217: mt->mt_inuse = 1;
218:
219: if (mt_putonline(mt) == MSCP_FAILED) {
220: mt->mt_inuse = 0;
221: return EIO;
222: }
223:
224: return 0;
225: }
226:
227: /* ARGSUSED */
228: int
229: mtclose(dev, flags, fmt, p)
230: dev_t dev;
231: int flags, fmt;
232: struct proc *p;
233: {
234: int unit = mtunit(dev);
235: struct mt_softc *mt = mt_cd.cd_devs[unit];
236:
237: /*
238: * If we just have finished a writing, write EOT marks.
239: */
240: if ((flags & FWRITE) && mt->mt_waswrite) {
241: mtcmd(mt, MTWEOF, 0, 0);
242: mtcmd(mt, MTWEOF, 0, 0);
243: mtcmd(mt, MTBSR, 1, 0);
244: }
245: if (mtnorewind(dev) == 0)
246: mtcmd(mt, MTREW, 0, 1);
247: if (mt->mt_serex)
248: mtcmd(mt, -1, 0, 0);
249:
250: mt->mt_inuse = 0; /* Release the tape */
251: return 0;
252: }
253:
254: void
255: mtstrategy(bp)
256: struct buf *bp;
257: {
258: int unit;
259: struct mt_softc *mt;
260: int s;
261:
262: /*
263: * Make sure this is a reasonable drive to use.
264: */
265: unit = mtunit(bp->b_dev);
266: if (unit >= mt_cd.cd_ndevs || (mt = mt_cd.cd_devs[unit]) == NULL) {
267: bp->b_error = ENXIO;
268: goto bad;
269: }
270:
271: mt->mt_waswrite = bp->b_flags & B_READ ? 0 : 1;
272: mscp_strategy(bp, mt->mt_dev.dv_parent);
273: return;
274:
275: bad:
276: bp->b_flags |= B_ERROR;
277: s = splbio();
278: biodone(bp);
279: splx(s);
280: }
281:
282: int
283: mtread(dev, uio)
284: dev_t dev;
285: struct uio *uio;
286: {
287:
288: return (physio(mtstrategy, NULL, dev, B_READ, minphys, uio));
289: }
290:
291: int
292: mtwrite(dev, uio)
293: dev_t dev;
294: struct uio *uio;
295: {
296:
297: return (physio(mtstrategy, NULL, dev, B_WRITE, minphys, uio));
298: }
299:
300: void
301: mtiodone(usc, bp)
302: struct device *usc;
303: struct buf *bp;
304: {
305: int s;
306:
307: s = splbio();
308: biodone(bp);
309: splx(s);
310: }
311:
312: /*
313: * Fill in drive addresses in a mscp packet waiting for transfer.
314: */
315: void
316: mtfillin(bp, mp)
317: struct buf *bp;
318: struct mscp *mp;
319: {
320: int unit = mtunit(bp->b_dev);
321: struct mt_softc *mt = mt_cd.cd_devs[unit];
322:
323: mp->mscp_unit = mt->mt_hwunit;
324: if (mt->mt_serex == 2) {
325: mp->mscp_modifier = M_MD_CLSEX;
326: mt->mt_serex = 0;
327: } else
328: mp->mscp_modifier = 0;
329:
330: mp->mscp_seq.seq_bytecount = bp->b_bcount;
331: }
332:
333: /*
334: * Handle an error datagram.
335: */
336: void
337: mtdgram(usc, mp, mi)
338: struct device *usc;
339: struct mscp *mp;
340: struct mscp_softc *mi;
341: {
342: if (mscp_decodeerror(usc == NULL?"unconf mt" : usc->dv_xname, mp, mi))
343: return;
344: }
345:
346: /*
347: * A drive came on line, make sure it really _is_ on line before
348: * trying to use it.
349: */
350: int
351: mtonline(usc, mp)
352: struct device *usc;
353: struct mscp *mp;
354: {
355: struct mt_softc *mt = (void *)usc;
356:
357: wakeup((caddr_t)&mt->mt_state);
358: if ((mp->mscp_status & M_ST_MASK) == M_ST_SUCCESS)
359: mt->mt_state = MT_ONLINE;
360:
361: return (MSCP_DONE);
362: }
363:
364: /*
365: * We got some (configured) unit's status. Return DONE.
366: */
367: int
368: mtgotstatus(usc, mp)
369: struct device *usc;
370: struct mscp *mp;
371: {
372: return (MSCP_DONE);
373: }
374:
375: static char *mt_ioerrs[] = {
376: "invalid command", /* 1 M_ST_INVALCMD */
377: "command aborted", /* 2 M_ST_ABORTED */
378: "unit offline", /* 3 M_ST_OFFLINE */
379: "unknown", /* 4 M_ST_AVAILABLE */
380: "unknown", /* 5 M_ST_MFMTERR */
381: "unit write protected", /* 6 M_ST_WRPROT */
382: "compare error", /* 7 M_ST_COMPERR */
383: "data error", /* 8 M_ST_DATAERR */
384: "host buffer access error", /* 9 M_ST_HOSTBUFERR */
385: "controller error", /* 10 M_ST_CTLRERR */
386: "drive error", /* 11 M_ST_DRIVEERR */
387: "formatter error", /* 12 M_ST_FORMATTERR */
388: "BOT encountered", /* 13 M_ST_BOT */
389: "tape mark encountered",/* 14 M_ST_TAPEMARK */
390: "unknown", /* 15 */
391: "record data truncated",/* 16 M_ST_RDTRUNC */
392: };
393:
394: /*
395: * An I/O error, may be because of a tapemark encountered.
396: * Check that before failing.
397: */
398: /*ARGSUSED*/
399: int
400: mtioerror(usc, mp, bp)
401: struct device *usc;
402: struct mscp *mp;
403: struct buf *bp;
404: {
405: struct mt_softc *mt = (void *)usc;
406: int st = mp->mscp_status & M_ST_MASK;
407:
408: if (mp->mscp_flags & M_EF_SEREX)
409: mt->mt_serex = 1;
410: if (st == M_ST_TAPEMARK)
411: mt->mt_serex = 2;
412: else {
413: if (st && st < 17)
414: printf("%s: error %d (%s)\n", mt->mt_dev.dv_xname, st,
415: mt_ioerrs[st-1]);
416: else
417: printf("%s: error %d\n", mt->mt_dev.dv_xname, st);
418: bp->b_flags |= B_ERROR;
419: bp->b_error = EROFS;
420: }
421:
422: return (MSCP_DONE);
423: }
424:
425: /*
426: * I/O controls.
427: */
428: int
429: mtioctl(dev, cmd, data, flag, p)
430: dev_t dev;
431: int cmd;
432: caddr_t data;
433: int flag;
434: struct proc *p;
435: {
436: int unit = mtunit(dev);
437: struct mt_softc *mt = mt_cd.cd_devs[unit];
438: struct mtop *mtop;
439: struct mtget *mtget;
440: int error = 0, count;
441:
442: count = mtop->mt_count;
443:
444: switch (cmd) {
445:
446: case MTIOCTOP:
447: mtop = (void *)data;
448: if (mtop->mt_op == MTWEOF) {
449: while (mtop->mt_count-- > 0)
450: if ((error = mtcmd(mt, mtop->mt_op, 0, 0)))
451: break;
452: } else
453: error = mtcmd(mt, mtop->mt_op, mtop->mt_count, 0);
454:
455: case MTIOCGET:
456: mtget = (void *)data;
457: mtget->mt_type = MT_ISTMSCP;
458: /* XXX we need to fill in more fields here */
459: break;
460:
461: default:
462: error = ENXIO;
463: break;
464: }
465: return (error);
466: }
467:
468: /*
469: * No crash dump support...
470: */
471: int
472: mtdump(dev, blkno, va, size)
473: dev_t dev;
474: daddr64_t blkno;
475: caddr_t va;
476: size_t size;
477: {
478: return -1;
479: }
480:
481: /*
482: * Send a command to the tape drive. Wait until the command is
483: * finished before returning.
484: * This routine must only be called when there are no data transfer
485: * active on this device. Can we be sure of this? Or does the ctlr
486: * queue up all command packets and take them in sequential order?
487: * It sure would be nice if my manual stated this... /ragge
488: */
489: int
490: mtcmd(mt, cmd, count, complete)
491: struct mt_softc *mt;
492: int cmd, count, complete;
493: {
494: struct mscp *mp;
495: struct mscp_softc *mi = (void *)mt->mt_dev.dv_parent;
496: volatile int i;
497:
498: mp = mscp_getcp(mi, MSCP_WAIT);
499:
500: mt->mt_ioctlerr = 0;
501: mp->mscp_unit = mt->mt_hwunit;
502: mp->mscp_cmdref = -1;
503: *mp->mscp_addr |= MSCP_OWN | MSCP_INT;
504:
505: switch (cmd) {
506: case MTWEOF:
507: mp->mscp_opcode = M_OP_WRITM;
508: break;
509:
510: case MTBSF:
511: mp->mscp_modifier = M_MD_REVERSE;
512: case MTFSF:
513: mp->mscp_opcode = M_OP_POS;
514: mp->mscp_seq.seq_buffer = count;
515: break;
516:
517: case MTBSR:
518: mp->mscp_modifier = M_MD_REVERSE;
519: case MTFSR:
520: mp->mscp_opcode = M_OP_POS;
521: mp->mscp_modifier |= M_MD_OBJCOUNT;
522: mp->mscp_seq.seq_bytecount = count;
523: break;
524:
525: case MTREW:
526: mp->mscp_opcode = M_OP_POS;
527: mp->mscp_modifier = M_MD_REWIND | M_MD_CLSEX;
528: if (complete)
529: mp->mscp_modifier |= M_MD_IMMEDIATE;
530: mt->mt_serex = 0;
531: break;
532:
533: case MTOFFL:
534: mp->mscp_opcode = M_OP_AVAILABLE;
535: mp->mscp_modifier = M_MD_UNLOAD | M_MD_CLSEX;
536: mt->mt_serex = 0;
537: break;
538:
539: case MTNOP:
540: mp->mscp_opcode = M_OP_GETUNITST;
541: break;
542:
543: case -1: /* Clear serious exception only */
544: mp->mscp_opcode = M_OP_POS;
545: mp->mscp_modifier = M_MD_CLSEX;
546: mt->mt_serex = 0;
547: break;
548:
549: default:
550: printf("Bad ioctl %x\n", cmd);
551: mp->mscp_opcode = M_OP_POS;
552: break;
553: }
554:
555: i = bus_space_read_2(mi->mi_iot, mi->mi_iph, 0);
556: tsleep(&mt->mt_inuse, PRIBIO, "mtioctl", 0);
557: return mt->mt_ioctlerr;
558: }
559:
560: /*
561: * Called from bus routines whenever a non-data transfer is finished.
562: */
563: void
564: mtcmddone(usc, mp)
565: struct device *usc;
566: struct mscp *mp;
567: {
568: struct mt_softc *mt = (void *)usc;
569:
570: if (mp->mscp_status) {
571: mt->mt_ioctlerr = EIO;
572: printf("%s: bad status %x\n", mt->mt_dev.dv_xname,
573: mp->mscp_status);
574: }
575: wakeup(&mt->mt_inuse);
576: }
CVSweb