Annotation of src/sys/dev/qbus/ts.c, Revision 1.20.6.2
1.20.6.2! matt 1: /* $NetBSD: ts.c,v 1.20.6.1 2007/11/06 23:30:01 matt Exp $ */
1.1 ragge 2:
3: /*-
4: * Copyright (c) 1991 The Regents of the University of California.
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.
1.11 agc 15: * 3. Neither the name of the University nor the names of its contributors
1.1 ragge 16: * may be used to endorse or promote products derived from this software
17: * without specific prior written permission.
18: *
19: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29: * SUCH DAMAGE.
30: *
31: * @(#)tmscp.c 7.16 (Berkeley) 5/9/91
32: */
33:
34: /*
35: * sccsid = "@(#)tmscp.c 1.24 (ULTRIX) 1/21/86";
36: */
37:
38: /************************************************************************
39: * *
40: * Licensed from Digital Equipment Corporation *
41: * Copyright (c) *
42: * Digital Equipment Corporation *
43: * Maynard, Massachusetts *
44: * 1985, 1986 *
45: * All rights reserved. *
46: * *
47: * The Information in this software is subject to change *
48: * without notice and should not be construed as a commitment *
49: * by Digital Equipment Corporation. Digital makes no *
50: * representations about the suitability of this software for *
51: * any purpose. It is supplied "As Is" without expressed or *
52: * implied warranty. *
53: * *
54: * If the Regents of the University of California or its *
55: * licensees modify the software in a manner creating *
56: * derivative copyright rights, appropriate copyright *
57: * legends may be placed on the derivative work in addition *
58: * to that set forth above. *
59: * *
60: ************************************************************************/
61:
62: /*
63: * TSV05/TS05 device driver, written by Bertram Barth.
64: *
65: * should be TS11 compatible (untested)
66: */
1.3 lukem 67:
68: #include <sys/cdefs.h>
1.20.6.2! matt 69: __KERNEL_RCSID(0, "$NetBSD: ts.c,v 1.20.6.1 2007/11/06 23:30:01 matt Exp $");
1.1 ragge 70:
1.2 ragge 71: #undef TSDEBUG
1.1 ragge 72:
73: /*
1.2 ragge 74: * TODO:
1.1 ragge 75: *
1.2 ragge 76: * Keep track of tape position so that lseek et al works.
77: * Use tprintf to inform the user, not the system console.
1.1 ragge 78: */
79:
80:
81: #include <sys/param.h>
82: #include <sys/systm.h>
83: #include <sys/kernel.h>
84: #include <sys/buf.h>
1.12 yamt 85: #include <sys/bufq.h>
1.1 ragge 86: #include <sys/conf.h>
87: #include <sys/errno.h>
88: #include <sys/file.h>
89: #include <sys/syslog.h>
90: #include <sys/ioctl.h>
91: #include <sys/mtio.h>
92: #include <sys/uio.h>
93: #include <sys/proc.h>
94:
1.20.6.1 matt 95: #include <sys/bus.h>
1.1 ragge 96:
97: #include <dev/qbus/ubareg.h>
98: #include <dev/qbus/ubavar.h>
99:
1.2 ragge 100: #include <dev/qbus/tsreg.h>
1.1 ragge 101:
1.2 ragge 102: #include "ioconf.h"
1.1 ragge 103:
104: struct ts {
1.2 ragge 105: struct cmd cmd; /* command packet */
106: struct chr chr; /* characteristics packet */
107: struct status status; /* status packet */
108: };
1.1 ragge 109:
110: /*
111: * Software status, per controller.
112: * also status per tape-unit, since only one unit per controller
113: * (thus we have no struct ts_info)
114: */
115: struct ts_softc {
116: struct device sc_dev; /* Autoconf ... */
117: struct uba_unit sc_unit; /* Struct common for UBA to talk */
1.2 ragge 118: struct evcnt sc_intrcnt; /* Interrupt counting */
119: struct ubinfo sc_ui; /* mapping info for struct ts */
120: struct uba_unit sc_uu; /* Struct for UBA to communicate */
121: bus_space_tag_t sc_iot;
122: bus_addr_t sc_ioh;
123: bus_dma_tag_t sc_dmat;
124: bus_dmamap_t sc_dmam;
125: volatile struct ts *sc_vts; /* Memory address of ts struct */
126: struct ts *sc_bts; /* Unibus address of ts struct */
127: int sc_type; /* TS11 or TS05? */
128: short sc_waddr; /* Value to write to TSDB */
1.14 yamt 129: struct bufq_state *sc_bufq; /* pending I/O requests */
1.2 ragge 130:
1.1 ragge 131: short sc_mapped; /* Unibus map allocated ? */
132: short sc_state; /* see below: ST_xxx */
133: short sc_rtc; /* retry count for lcmd */
134: short sc_openf; /* lock against multiple opens */
135: short sc_liowf; /* last operation was write */
1.2 ragge 136: struct buf ts_cbuf; /* internal cmd buffer (for ioctls) */
1.1 ragge 137: };
138:
1.2 ragge 139: #define XNAME sc->sc_dev.dv_xname
140:
141: #define TS_WCSR(csr, val) \
142: bus_space_write_2(sc->sc_iot, sc->sc_ioh, csr, val)
143: #define TS_RCSR(csr) \
144: bus_space_read_2(sc->sc_iot, sc->sc_ioh, csr)
145:
146: #define LOWORD(x) ((int)(x) & 0xffff)
147: #define HIWORD(x) (((int)(x) >> 16) & 0x3f)
148:
149: #define TYPE_TS11 0
150: #define TYPE_TS05 1
151: #define TYPE_TU80 2
152:
153: #define TS_INVALID 0
154: #define TS_INIT 1
155: #define TS_RUNNING 2
156: #define TS_FASTREPOS 3
157:
158: static void tsintr(void *);
159: static void tsinit(struct ts_softc *);
160: static void tscommand(struct ts_softc *, dev_t, int, int);
161: static int tsstart(struct ts_softc *, int);
162: static void tswchar(struct ts_softc *);
163: static int tsreset(struct ts_softc *);
164: static int tsmatch(struct device *, struct cfdata *, void *);
165: static void tsattach(struct device *, struct device *, void *);
166: static int tsready(struct uba_unit *);
167:
1.8 thorpej 168: CFATTACH_DECL(ts, sizeof(struct ts_softc),
1.9 thorpej 169: tsmatch, tsattach, NULL, NULL);
1.5 gehenna 170:
171: dev_type_open(tsopen);
172: dev_type_close(tsclose);
173: dev_type_read(tsread);
174: dev_type_write(tswrite);
175: dev_type_ioctl(tsioctl);
176: dev_type_strategy(tsstrategy);
177: dev_type_dump(tsdump);
178:
179: const struct bdevsw ts_bdevsw = {
180: tsopen, tsclose, tsstrategy, tsioctl, tsdump, nosize, D_TAPE
181: };
182:
183: const struct cdevsw ts_cdevsw = {
184: tsopen, tsclose, tsread, tswrite, tsioctl,
1.10 jdolecek 185: nostop, notty, nopoll, nommap, nokqfilter, D_TAPE
1.1 ragge 186: };
187:
1.13 simonb 188: /* Bits in minor device */
1.1 ragge 189: #define TS_UNIT(dev) (minor(dev)&03)
190: #define TS_HIDENSITY 010
191:
192: #define TS_PRI LOG_INFO
193:
194:
195: /*
1.2 ragge 196: * Probe for device. If found, try to raise an interrupt.
1.1 ragge 197: */
1.2 ragge 198: int
199: tsmatch(struct device *parent, struct cfdata *match, void *aux)
200: {
201: struct ts_softc ssc;
202: struct ts_softc *sc = &ssc;
203: struct uba_attach_args *ua = aux;
204: int i;
1.1 ragge 205:
1.2 ragge 206: sc->sc_iot = ua->ua_iot;
207: sc->sc_ioh = ua->ua_ioh;
208: sc->sc_mapped = 0;
209: sc->sc_dev.dv_parent = parent;
210: strcpy(XNAME, "ts");
1.1 ragge 211:
1.2 ragge 212: /* Try to reset the device */
213: for (i = 0; i < 3; i++)
214: if (tsreset(sc) == 1)
215: break;
216:
217: if (i == 3)
218: return 0;
1.1 ragge 219:
1.2 ragge 220: tsinit(sc);
221: tswchar(sc); /* write charact. to enable interrupts */
222: /* completion of this will raise the intr. */
1.1 ragge 223:
1.2 ragge 224: DELAY(1000000); /* Wait for interrupt */
225: ubmemfree((void *)parent, &sc->sc_ui);
226: return 1;
1.1 ragge 227: }
228:
229: /*
230: */
1.2 ragge 231: void
232: tsattach(struct device *parent, struct device *self, void *aux)
1.1 ragge 233: {
1.17 thorpej 234: struct uba_softc *uh = device_private(parent);
235: struct ts_softc *sc = device_private(self);
1.2 ragge 236: struct uba_attach_args *ua = aux;
237: int error;
238: char *t;
239:
240: sc->sc_iot = ua->ua_iot;
241: sc->sc_ioh = ua->ua_ioh;
242: sc->sc_dmat = ua->ua_dmat;
1.13 simonb 243:
1.2 ragge 244: sc->sc_uu.uu_softc = sc;
245: sc->sc_uu.uu_ready = tsready;
1.1 ragge 246:
1.2 ragge 247: tsinit(sc); /* reset and map */
1.1 ragge 248:
1.2 ragge 249: if ((error = bus_dmamap_create(sc->sc_dmat, (64*1024), 16, (64*1024),
250: 0, BUS_DMA_NOWAIT, &sc->sc_dmam)))
251: return printf(": failed create DMA map %d\n", error);
1.1 ragge 252:
1.14 yamt 253: bufq_alloc(&sc->sc_bufq, "fcfs", 0);
1.1 ragge 254:
255: /*
1.2 ragge 256: * write the characteristics (again)
1.1 ragge 257: */
1.2 ragge 258: sc->sc_state = TS_INIT; /* tsintr() checks this ... */
259: tswchar(sc);
260: if (tsleep(sc, PRIBIO, "tsattach", 100))
261: return printf(": failed SET CHARACTERISTICS\n");
262:
263: sc->sc_state = TS_RUNNING;
264: if (uh->uh_type == UBA_UBA) {
265: if (sc->sc_vts->status.xst2 & TS_SF_TU80) {
266: sc->sc_type = TYPE_TU80;
267: t = "TU80";
268: } else {
269: sc->sc_type = TYPE_TS11;
270: t = "TS11";
1.1 ragge 271: }
1.2 ragge 272: } else {
273: sc->sc_type = TYPE_TS05;
274: t = "TS05";
1.1 ragge 275: }
276:
1.2 ragge 277: printf("\n%s: %s\n", XNAME, t);
278: printf("%s: rev %d, extended features %s, transport %s\n",
279: XNAME, (sc->sc_vts->status.xst2 & TS_SF_MCRL) >> 2,
280: (sc->sc_vts->status.xst2 & TS_SF_EFES ? "enabled" : "disabled"),
281: (TS_RCSR(TSSR) & TS_OFL ? "offline" : "online"));
282:
283: uba_intr_establish(ua->ua_icookie, ua->ua_cvec, tsintr,
284: sc, &sc->sc_intrcnt);
285: evcnt_attach_dynamic(&sc->sc_intrcnt, EVCNT_TYPE_INTR, ua->ua_evcnt,
286: sc->sc_dev.dv_xname, "intr");
287: }
288:
289: /*
290: * Initialize a TS device. Set up UBA mapping registers,
291: * initialize data structures, what else ???
292: */
1.13 simonb 293: void
1.2 ragge 294: tsinit(struct ts_softc *sc)
295: {
296: if (sc->sc_mapped == 0) {
297:
298: /*
299: * Map the communications area and command and message
300: * buffer into Unibus address space.
301: */
302: sc->sc_ui.ui_size = sizeof(struct ts);
1.16 thorpej 303: if ((ubmemalloc((void *)device_parent(&sc->sc_dev),
1.2 ragge 304: &sc->sc_ui, UBA_CANTWAIT)))
305: return;
306: sc->sc_vts = (void *)sc->sc_ui.ui_vaddr;
307: sc->sc_bts = (void *)sc->sc_ui.ui_baddr;
308: sc->sc_waddr = sc->sc_ui.ui_baddr |
309: ((sc->sc_ui.ui_baddr >> 16) & 3);
310: sc->sc_mapped = 1;
311: }
312: tsreset(sc);
1.1 ragge 313: }
314:
1.13 simonb 315: /*
1.1 ragge 316: * Execute a (ioctl) command on the tape drive a specified number of times.
317: * This routine sets up a buffer and calls the strategy routine which
318: * issues the command to the controller.
319: */
320: void
1.2 ragge 321: tscommand(struct ts_softc *sc, dev_t dev, int cmd, int count)
1.1 ragge 322: {
1.2 ragge 323: struct buf *bp;
1.1 ragge 324:
1.2 ragge 325: #ifdef TSDEBUG
326: printf("tscommand (%x, %d)\n", cmd, count);
327: #endif
328:
329: bp = &sc->ts_cbuf;
1.1 ragge 330:
1.20.6.2! matt 331: mutex_enter(&bufcache_lock);
! 332: while (bp->b_cflags & BC_BUSY) {
1.1 ragge 333: /*
1.20.6.2! matt 334: * This special check is because BC_BUSY never
1.1 ragge 335: * gets cleared in the non-waiting rewind case. ???
336: */
1.20.6.2! matt 337: if (bp->b_bcount == 0 && (bp->b_oflags & BO_DONE))
1.1 ragge 338: break;
1.20.6.2! matt 339: (void )bbusy(bp, false, 0);
1.1 ragge 340: /* check MOT-flag !!! */
341: }
1.20.6.2! matt 342: bp->b_flags = B_READ;
! 343: mutex_exit(&bufcache_lock);
1.1 ragge 344:
345: /*
346: * Load the buffer. The b_count field gets used to hold the command
347: * count. the b_resid field gets used to hold the command mneumonic.
348: * These 2 fields are "known" to be "safe" to use for this purpose.
349: * (Most other drivers also use these fields in this way.)
350: */
351: bp->b_dev = dev;
352: bp->b_bcount = count;
353: bp->b_resid = cmd;
354: bp->b_blkno = 0;
1.20.6.2! matt 355: bp->b_oflags = 0;
! 356: bp->b_objlock = &buffer_lock;
1.2 ragge 357: tsstrategy(bp);
1.1 ragge 358: /*
359: * In case of rewind from close, don't wait.
360: * This is the only case where count can be 0.
361: */
1.2 ragge 362: if (count == 0)
1.1 ragge 363: return;
1.2 ragge 364: biowait(bp);
1.20.6.2! matt 365: mutex_enter(&bufcache_lock);
! 366: cv_broadcast(&bp->b_busy);
! 367: bp->b_cflags = 0;
! 368: mutex_exit(&bufcache_lock);
1.1 ragge 369: }
370:
371: /*
372: * Start an I/O operation on TS05 controller
373: */
374: int
1.2 ragge 375: tsstart(struct ts_softc *sc, int isloaded)
1.1 ragge 376: {
1.2 ragge 377: struct buf *bp;
1.1 ragge 378: int cmd;
379:
1.14 yamt 380: bp = BUFQ_PEEK(sc->sc_bufq);
381: if (bp == NULL) {
1.2 ragge 382: return 0;
1.14 yamt 383: }
1.2 ragge 384: #ifdef TSDEBUG
385: printf("buf: %p bcount %ld blkno %d\n", bp, bp->b_bcount, bp->b_blkno);
386: #endif
1.1 ragge 387: /*
388: * Check if command is an ioctl or not (ie. read or write).
389: * If it's an ioctl then just set the flags for later use;
390: * For other commands attempt to setup a buffer pointer.
391: */
1.2 ragge 392: if (bp == &sc->ts_cbuf) {
1.1 ragge 393: switch ((int)bp->b_resid) {
394: case MTWEOF:
395: cmd = TS_CMD_WTM;
396: break;
397: case MTFSF:
398: cmd = TS_CMD_STMF;
1.2 ragge 399: sc->sc_vts->cmd.cw1 = bp->b_bcount;
1.1 ragge 400: break;
401: case MTBSF:
1.13 simonb 402: cmd = TS_CMD_STMR;
1.2 ragge 403: sc->sc_vts->cmd.cw1 = bp->b_bcount;
1.1 ragge 404: break;
405: case MTFSR:
406: cmd = TS_CMD_SRF;
1.2 ragge 407: sc->sc_vts->cmd.cw1 = bp->b_bcount;
1.1 ragge 408: break;
409: case MTBSR:
410: cmd = TS_CMD_SRR;
1.2 ragge 411: sc->sc_vts->cmd.cw1 = bp->b_bcount;
1.1 ragge 412: break;
413: case MTREW:
414: cmd = TS_CMD_RWND;
415: break;
416: case MTOFFL:
417: cmd = TS_CMD_RWUL;
418: break;
419: case MTNOP:
420: cmd = TS_CMD_STAT;
421: break;
422: default:
423: printf ("%s: bad ioctl %d\n", sc->sc_dev.dv_xname,
424: (int)bp->b_resid);
425: /* Need a no-op. get status */
426: cmd = TS_CMD_STAT;
427: } /* end switch (bp->b_resid) */
1.2 ragge 428: } else {
429: if (isloaded == 0) {
430: /*
431: * now we try to map the buffer into uba map space (???)
432: */
433: if (bus_dmamap_load(sc->sc_dmat, sc->sc_dmam,
434: bp->b_data,
435: bp->b_bcount, bp->b_proc, BUS_DMA_NOWAIT)) {
436: uba_enqueue(&sc->sc_uu);
437: return 0;
438: }
439: sc->sc_rtc = 0;
440: }
441: sc->sc_vts->cmd.cw1 = LOWORD(sc->sc_dmam->dm_segs[0].ds_addr);
442: sc->sc_vts->cmd.cw2 = HIWORD(sc->sc_dmam->dm_segs[0].ds_addr);
443: sc->sc_vts->cmd.cw3 = bp->b_bcount;
444: bp->b_error = 0; /* Used for error count */
445: #ifdef TSDEBUG
446: printf("tsstart-1: err %d\n", bp->b_error);
447: #endif
448: if (bp->b_flags & B_READ)
1.1 ragge 449: cmd = TS_CMD_RNF;
1.2 ragge 450: else
1.1 ragge 451: cmd = TS_CMD_WD;
452: }
453:
454: /*
455: * Now that the command-buffer is setup, give it to the controller
456: */
1.2 ragge 457: sc->sc_vts->cmd.cmdr = TS_CF_ACK | TS_CF_IE | cmd;
458: #ifdef TSDEBUG
459: printf("tsstart: sending cmdr %x\n", sc->sc_vts->cmd.cmdr);
460: #endif
461: TS_WCSR(TSDB, sc->sc_waddr);
1.1 ragge 462: }
463:
464: /*
1.2 ragge 465: * Called when there are free uba resources.
1.1 ragge 466: */
1.2 ragge 467: int
468: tsready(struct uba_unit *uu)
1.1 ragge 469: {
1.2 ragge 470: struct ts_softc *sc = uu->uu_softc;
1.14 yamt 471: struct buf *bp = BUFQ_PEEK(sc->sc_bufq);
1.1 ragge 472:
1.2 ragge 473: if (bus_dmamap_load(sc->sc_dmat, sc->sc_dmam, bp->b_data,
474: bp->b_bcount, bp->b_proc, BUS_DMA_NOWAIT))
475: return 0;
1.1 ragge 476:
1.2 ragge 477: tsstart(sc, 1);
478: return 1;
1.1 ragge 479: }
480:
481: /*
1.2 ragge 482: * initialize the controller by sending WRITE CHARACTERISTICS command.
483: * contents of command- and message-buffer are assembled during this
1.13 simonb 484: * function.
1.1 ragge 485: */
1.13 simonb 486: void
1.2 ragge 487: tswchar(struct ts_softc *sc)
1.1 ragge 488: {
489: /*
1.2 ragge 490: * assemble and send "WRITE CHARACTERISTICS" command
1.1 ragge 491: */
492:
1.2 ragge 493: sc->sc_vts->cmd.cmdr = TS_CF_ACK | TS_CF_IE | TS_CMD_WCHAR;
494: sc->sc_vts->cmd.cw1 = LOWORD(&sc->sc_bts->chr);
495: sc->sc_vts->cmd.cw2 = HIWORD(&sc->sc_bts->chr);
496: sc->sc_vts->cmd.cw3 = 010; /* size of charact.-data */
497:
498: sc->sc_vts->chr.sadrl = LOWORD(&sc->sc_bts->status);
499: sc->sc_vts->chr.sadrh = HIWORD(&sc->sc_bts->status);
500: sc->sc_vts->chr.onesix = (sc->sc_type == TYPE_TS05 ? 020 : 016);
501: sc->sc_vts->chr.chrw = TS_WC_ESS;
502: sc->sc_vts->chr.xchrw = TS_WCX_HSP|TS_WCX_RBUF|TS_WCX_WBUF;
503:
504: TS_WCSR(TSDB, sc->sc_waddr);
1.1 ragge 505: }
506:
507: /*
1.2 ragge 508: * Reset the TS11. Return 1 if failed, 0 if succeeded.
1.1 ragge 509: */
510: int
1.2 ragge 511: tsreset(struct ts_softc *sc)
1.1 ragge 512: {
1.2 ragge 513: int timeout;
1.1 ragge 514:
515: /*
1.2 ragge 516: * reset ctlr by writing into TSSR, then write characteristics
1.1 ragge 517: */
1.13 simonb 518: timeout = 0; /* timeout in 10 seconds */
1.2 ragge 519: TS_WCSR(TSSR, 0); /* start initialization */
520: while ((TS_RCSR(TSSR) & TS_SSR) == 0) {
1.1 ragge 521: DELAY(10000);
1.2 ragge 522: if (timeout++ > 1000)
523: return 0;
524: }
525: return 1;
1.1 ragge 526: }
527:
1.2 ragge 528: static void
529: prtstat(struct ts_softc *sc, int sr)
1.1 ragge 530: {
1.2 ragge 531: char buf[100];
1.1 ragge 532:
1.2 ragge 533: bitmask_snprintf(sr, TS_TSSR_BITS, buf, sizeof(buf));
534: printf("%s: TSSR=%s\n", XNAME, buf);
535: bitmask_snprintf(sc->sc_vts->status.xst0,TS_XST0_BITS,buf,sizeof(buf));
536: printf("%s: XST0=%s\n", XNAME, buf);
1.1 ragge 537: }
538:
539: /*
540: * TSV05/TS05 interrupt routine
541: */
1.2 ragge 542: static void
543: tsintr(void *arg)
1.1 ragge 544: {
1.2 ragge 545: struct ts_softc *sc = arg;
546: struct buf *bp;
1.1 ragge 547:
1.2 ragge 548: unsigned short sr = TS_RCSR(TSSR); /* save TSSR */
549: unsigned short mh = sc->sc_vts->status.hdr; /* and msg-header */
1.1 ragge 550: /* clear the message header ??? */
551:
1.2 ragge 552: short ccode = sc->sc_vts->cmd.cmdr & TS_CF_CCODE;
1.1 ragge 553:
1.2 ragge 554: #ifdef TSDEBUG
1.1 ragge 555: {
1.2 ragge 556: char buf[100];
557: bitmask_snprintf(sr, TS_TSSR_BITS, buf, sizeof(buf));
558: printf("tsintr: sr %x mh %x\n", sr, mh);
559: printf("srbits: %s\n", buf);
1.1 ragge 560: }
561: #endif
562: /*
563: * There are two different things which can (and should) be checked:
564: * the actual (internal) state and the device's result (tssr/msg.hdr)
1.13 simonb 565: *
1.1 ragge 566: * For each state there's only one "normal" interrupt. Anything else
567: * has to be checked more intensively. Thus in a first run according
568: * to the internal state the expected interrupt is checked/handled.
569: *
570: * In a second run the remaining (not yet handled) interrupts are
571: * checked according to the drive's result.
572: */
573: switch (sc->sc_state) {
574:
1.2 ragge 575: case TS_INVALID:
1.1 ragge 576: /*
577: * Ignore unsolicited interrupts.
578: */
1.13 simonb 579: log(LOG_WARNING, "%s: stray intr [%x,%x]\n",
1.1 ragge 580: sc->sc_dev.dv_xname, sr, mh);
581: return;
582:
1.2 ragge 583: case TS_INIT:
1.1 ragge 584: /*
1.2 ragge 585: * Init phase ready.
1.1 ragge 586: */
1.2 ragge 587: wakeup(sc);
1.1 ragge 588: return;
589:
1.2 ragge 590: case TS_RUNNING:
591: case TS_FASTREPOS:
1.1 ragge 592: /*
593: * Here we expect interrupts indicating the end of
594: * commands or indicating problems.
595: */
596: /*
597: * Anything else is handled outside this switch ...
598: */
599: break;
600:
601: default:
1.13 simonb 602: printf ("%s: unexpected interrupt during state %d [%x,%x]\n",
1.1 ragge 603: sc->sc_dev.dv_xname, sc->sc_state, sr, mh);
604: return;
605: }
606:
607: /*
608: * now we check the termination class.
609: */
610: switch (sr & TS_TC) {
611:
612: case TS_TC_NORM:
613: /*
614: * Normal termination -- The operation is completed
615: * witout incident.
616: */
1.2 ragge 617: if (sc->sc_state == TS_FASTREPOS) {
618: #ifdef TSDEBUG
619: printf("Fast repos interrupt\n");
620: #endif
621: /* Fast repos succeeded, start normal data xfer */
622: sc->sc_state = TS_RUNNING;
623: tsstart(sc, 1);
624: return;
625: }
1.1 ragge 626: sc->sc_liowf = (ccode == TS_CC_WRITE);
1.2 ragge 627: break;
1.1 ragge 628:
629: case TS_TC_ATTN:
630: /*
631: * Attention condition -- this code indicates that the
632: * drive has undergone a status change, such as going
633: * off-line or coming on-line.
634: * (Without EAI enabled, no Attention interrupts occur.
635: * drive status changes are signaled by the VCK flag.)
636: */
637: return;
638:
639: case TS_TC_TSA:
1.13 simonb 640: /*
1.1 ragge 641: * Tape Status Alert -- A status condition is encountered
642: * that may have significance to the program. Bits of
643: * interest in the extended status registers include
644: * TMK, EOT and RLL.
645: */
1.2 ragge 646: #ifdef TSDEBUG
647: {
648: char buf[100];
649: bitmask_snprintf(sc->sc_vts->status.xst0,
650: TS_XST0_BITS, buf, sizeof(buf));
651: printf("TSA: sr %x bits %s\n",
652: sc->sc_vts->status.xst0, buf);
653: }
654: #endif
655: if (sc->sc_vts->status.xst0 & TS_SF_TMK) {
656: /* Read to end-of-file. No error. */
657: break;
658: }
659: if (sc->sc_vts->status.xst0 & TS_SF_EOT) {
660: /* End of tape. Bad. */
661: #ifdef TSDEBUG
662: printf("TS_TC_TSA: EOT\n");
663: #endif
664: bp->b_error = EIO;
665: break;
666: }
667: if (sc->sc_vts->status.xst0 & TS_SF_RLS)
668: break;
669: if (sc->sc_vts->status.xst0 & TS_SF_TMK) {
670: #ifdef TSDEBUG
671: printf(("Tape Mark detected"));
672: #endif
673: }
674: if (sc->sc_vts->status.xst0 & TS_SF_EOT) {
675: #ifdef TSDEBUG
676: printf(("End of Tape"));
677: #endif
1.1 ragge 678: }
1.2 ragge 679: #ifndef TSDEBUG
680: {
681: char buf[100];
682: bitmask_snprintf(sc->sc_vts->status.xst0,
683: TS_XST0_BITS, buf, sizeof(buf));
684: printf("TSA: sr %x bits %s\n",
685: sc->sc_vts->status.xst0, buf);
1.1 ragge 686: }
1.2 ragge 687: #endif
1.1 ragge 688: break;
689:
1.13 simonb 690: case TS_TC_FR:
1.1 ragge 691: /*
692: * Function Reject -- The specified function was not
693: * initiated. Bits of interest include OFL, VCK, BOT,
694: * WLE, ILC and ILA.
695: */
1.2 ragge 696: if (sr & TS_OFL)
697: printf("tape is off-line.\n");
698: #ifdef TSDEBUG
699: {
700: char buf[100];
701: bitmask_snprintf(sc->sc_vts->status.xst0,
702: TS_XST0_BITS, buf, sizeof(buf));
703: printf("FR: sr %x bits %s\n",
704: sc->sc_vts->status.xst0, buf);
705: }
706: #endif
707: if (sc->sc_vts->status.xst0 & TS_SF_VCK)
708: printf("Volume check\n");
709: if (sc->sc_vts->status.xst0 & TS_SF_BOT)
710: printf("Start of tape.\n");
711: if (sc->sc_vts->status.xst0 & TS_SF_WLE)
712: printf("Write Lock Error\n");
713: if (sc->sc_vts->status.xst0 & TS_SF_EOT)
714: printf("End of tape.\n");
1.1 ragge 715: break;
716:
717: case TS_TC_TPD:
718: /*
719: * Recoverable Error -- Tape position is a record beyond
720: * what its position was when the function was initiated.
721: * Suggested recovery procedure is to log the error and
722: * issue the appropriate retry command.
1.2 ragge 723: *
724: * Do a fast repositioning one record back.
1.1 ragge 725: */
1.2 ragge 726: sc->sc_state = TS_FASTREPOS;
727: #ifdef TSDEBUG
728: printf("TS_TC_TPD: errcnt %d\n", sc->sc_rtc);
729: #endif
730: if (sc->sc_rtc++ == 8) {
731: printf("%s: failed 8 retries\n", XNAME);
732: prtstat(sc, sr);
733: bp->b_error = EIO;
734: break;
1.1 ragge 735: }
1.2 ragge 736: sc->sc_vts->cmd.cmdr = TS_CF_ACK | TS_CF_IE | TS_CMD_SRR;
737: sc->sc_vts->cmd.cw1 = 1;
738: TS_WCSR(TSDB, sc->sc_waddr);
739: return;
740:
1.1 ragge 741: break;
742:
743: case TS_TC_TNM:
744: /*
745: * Recoverable Error -- Tape position has not changed.
746: * Suggested recovery procedure is to log the error and
747: * reissue the original command.
748: */
1.2 ragge 749: if (sc->sc_rtc++ == 8) {
750: printf("%s: failed 8 retries\n", XNAME);
751: prtstat(sc, sr);
752: bp->b_error = EIO;
753: break;
1.1 ragge 754: }
1.2 ragge 755: tsstart(sc, 1);
756: return;
1.1 ragge 757:
758: case TS_TC_TPL:
759: /*
760: * Unrecoverable Error -- Tape position has been lost.
761: * No valid recovery procedures exist unless the tape
762: * has labels or sequence numbers.
763: */
1.13 simonb 764: printf("Tape position lost\n");
1.2 ragge 765: bp->b_error = EIO;
1.1 ragge 766: break;
767:
768: case TS_TC_FCE:
769: /*
770: * Fatal subsytem Error -- The subsytem is incapable
771: * of properly performing commands, or at least its
1.13 simonb 772: * integrity is seriously questionable. Refer to the
1.1 ragge 773: * fatal class code field in the TSSR register for
774: * additional information on the type of fatal error.
775: */
1.13 simonb 776: printf ("Fatal Controller Error\n");
1.2 ragge 777: prtstat(sc, sr);
778: break;
1.1 ragge 779:
780: default:
1.13 simonb 781: printf ("%s: error 0x%x, resetting controller\n",
1.1 ragge 782: sc->sc_dev.dv_xname, sr & TS_TC);
1.2 ragge 783: tsreset(sc);
1.1 ragge 784: }
1.14 yamt 785: if ((bp = BUFQ_GET(sc->sc_bufq)) != NULL) {
1.2 ragge 786: #ifdef TSDEBUG
1.14 yamt 787: printf("tsintr2: que %p\n", BUFQ_PEEK(sc->sc_bufq));
1.2 ragge 788: #endif
789: if (bp != &sc->ts_cbuf) { /* no ioctl */
790: bus_dmamap_unload(sc->sc_dmat, sc->sc_dmam);
1.16 thorpej 791: uba_done((void *)device_parent(&sc->sc_dev));
1.2 ragge 792: }
793: bp->b_resid = sc->sc_vts->status.rbpcr;
1.1 ragge 794: biodone (bp);
795: }
1.2 ragge 796: tsstart(sc, 0);
1.1 ragge 797: }
798:
799:
800: /*
801: * Open a ts device and set the unit online. If the controller is not
802: * in the run state, call init to initialize the ts controller first.
803: */
804: int
1.2 ragge 805: tsopen(dev_t dev, int flag, int type, struct proc *p)
1.1 ragge 806: {
1.2 ragge 807: struct ts_softc *sc;
808: int unit = TS_UNIT(dev);
1.1 ragge 809:
810: if (unit >= ts_cd.cd_ndevs)
811: return ENXIO;
812:
813: sc = ts_cd.cd_devs[unit];
814: if (sc == 0)
815: return ENXIO;
816:
1.2 ragge 817: if (sc->sc_state < TS_RUNNING)
818: return ENXIO;
819:
1.1 ragge 820: if (sc->sc_openf)
821: return EBUSY;
822: sc->sc_openf = 1;
823:
824: /*
825: * check if transport is really online.
826: * (without attention-interrupts enabled, we really don't know
827: * the actual state of the transport. Thus we call get-status
828: * (ie. MTNOP) once and check the actual status.)
829: */
1.2 ragge 830: if (TS_RCSR(TSSR) & TS_OFL) {
831: uprintf("%s: transport is offline.\n", XNAME);
1.1 ragge 832: sc->sc_openf = 0;
833: return EIO; /* transport is offline */
834: }
1.2 ragge 835: tscommand(sc, dev, MTNOP, 1);
836: if ((flag & FWRITE) && (sc->sc_vts->status.xst0 & TS_SF_WLK)) {
837: uprintf("%s: no write ring.\n", XNAME);
838: sc->sc_openf = 0;
839: return EROFS;
840: }
841: if (sc->sc_vts->status.xst0 & TS_SF_VCK) {
842: sc->sc_vts->cmd.cmdr = TS_CF_CVC|TS_CF_ACK;
843: TS_WCSR(TSDB, sc->sc_waddr);
844: }
845: tscommand(sc, dev, MTNOP, 1);
846: #ifdef TSDEBUG
847: {
848: char buf[100];
849: bitmask_snprintf(sc->sc_vts->status.xst0,
850: TS_XST0_BITS, buf, sizeof(buf));
851: printf("tsopen: xst0 %s\n", buf);
852: }
853: #endif
1.1 ragge 854: sc->sc_liowf = 0;
855: return 0;
856: }
857:
858:
859: /*
860: * Close tape device.
861: *
862: * If tape was open for writing or last operation was
863: * a write, then write two EOF's and backspace over the last one.
864: * Unless this is a non-rewinding special file, rewind the tape.
865: *
866: * Make the tape available to others, by clearing openf flag.
867: */
868: int
1.2 ragge 869: tsclose(dev_t dev, int flag, int type, struct proc *p)
1.1 ragge 870: {
1.2 ragge 871: struct ts_softc *sc = ts_cd.cd_devs[TS_UNIT(dev)];
1.1 ragge 872:
873: if (flag == FWRITE || ((flag & FWRITE) && sc->sc_liowf)) {
1.13 simonb 874: /*
1.1 ragge 875: * We are writing two tape marks (EOT), but place the tape
876: * before the second one, so that another write operation
877: * will overwrite the second one and leave and EOF-mark.
878: */
1.2 ragge 879: tscommand(sc, dev, MTWEOF, 1); /* Write Tape Mark */
880: tscommand(sc, dev, MTWEOF, 1); /* Write Tape Mark */
881: tscommand(sc, dev, MTBSF, 1); /* Skip Tape Marks Reverse */
1.1 ragge 882: }
883:
884: if ((dev & T_NOREWIND) == 0)
1.2 ragge 885: tscommand(sc, dev, MTREW, 0);
1.1 ragge 886:
887: sc->sc_openf = 0;
888: sc->sc_liowf = 0;
889: return 0;
890: }
891:
892:
893: /*
894: * Manage buffers and perform block mode read and write operations.
895: */
896: void
1.2 ragge 897: tsstrategy(struct buf *bp)
1.1 ragge 898: {
899: register int unit = TS_UNIT(bp->b_dev);
900: struct ts_softc *sc = (void *)ts_cd.cd_devs[unit];
1.2 ragge 901: int s, empty;
1.1 ragge 902:
1.2 ragge 903: #ifdef TSDEBUG
904: printf("buf: %p bcount %ld blkno %d\n", bp, bp->b_bcount, bp->b_blkno);
905: #endif
1.1 ragge 906: s = splbio ();
1.14 yamt 907: empty = (BUFQ_PEEK(sc->sc_bufq) == NULL);
908: BUFQ_PUT(sc->sc_bufq, bp);
1.2 ragge 909: if (empty)
910: tsstart(sc, 0);
1.1 ragge 911: splx(s);
912: }
913:
914:
915: /*
916: * Catch ioctl commands, and call the "command" routine to do them.
917: */
918: int
1.2 ragge 919: tsioctl(dev, cmd, data, flag, p)
1.1 ragge 920: dev_t dev;
921: u_long cmd;
1.19 christos 922: void *data;
1.1 ragge 923: int flag;
924: struct proc *p;
925: {
1.2 ragge 926: struct buf *bp;
927: struct ts_softc *sc;
928: struct mtop *mtop; /* mag tape cmd op to perform */
929: struct mtget *mtget; /* mag tape struct to get info in */
930: int callcount; /* number of times to call routine */
1.1 ragge 931: int scount; /* number of files/records to space */
932: int spaceop = 0; /* flag for skip/space operation */
933: int error = 0;
934:
1.2 ragge 935: #ifdef TSDEBUG
936: printf("tsioctl (%x, %lx, %p, %d)\n", dev, cmd, data, flag);
937: #endif
938:
939: sc = ts_cd.cd_devs[TS_UNIT(dev)];
940: bp = &sc->ts_cbuf;
1.1 ragge 941:
942: switch (cmd) {
943: case MTIOCTOP: /* do a mag tape op */
944: mtop = (struct mtop *)data;
945: switch (mtop->mt_op) {
946: case MTWEOF: /* write an end-of-file record */
947: callcount = mtop->mt_count;
948: scount = 1;
949: break;
950: case MTFSR: /* forward space record */
951: case MTBSR: /* backward space record */
952: spaceop = 1;
1.2 ragge 953: case MTFSF: /* forward space file */
954: case MTBSF: /* backward space file */
1.1 ragge 955: callcount = 1;
956: scount = mtop->mt_count;
957: break;
958: case MTREW: /* rewind */
959: case MTOFFL: /* rewind and put the drive offline */
960: case MTNOP: /* no operation, sets status only */
961: callcount = 1;
962: scount = 1; /* wait for this rewind */
963: break;
964: case MTRETEN: /* retension */
965: case MTERASE: /* erase entire tape */
966: case MTEOM: /* forward to end of media */
967: case MTNBSF: /* backward space to begin of file */
968: case MTCACHE: /* enable controller cache */
969: case MTNOCACHE: /* disable controller cache */
970: case MTSETBSIZ: /* set block size; 0 for variable */
971: case MTSETDNSTY: /* set density code for current mode */
1.2 ragge 972: printf("ioctl %d not implemented.\n", mtop->mt_op);
1.1 ragge 973: return (ENXIO);
974: default:
1.2 ragge 975: #ifdef TSDEBUG
976: printf("invalid ioctl %d\n", mtop->mt_op);
977: #endif
1.1 ragge 978: return (ENXIO);
979: } /* switch (mtop->mt_op) */
980:
981: if (callcount <= 0 || scount <= 0) {
1.2 ragge 982: #ifdef TSDEBUG
983: printf("invalid values %d/%d\n", callcount, scount);
984: #endif
1.1 ragge 985: return (EINVAL);
986: }
987: do {
1.2 ragge 988: tscommand(sc, dev, mtop->mt_op, scount);
1.1 ragge 989: if (spaceop && bp->b_resid) {
1.2 ragge 990: #ifdef TSDEBUG
991: printf(("spaceop didn't complete\n"));
992: #endif
1.1 ragge 993: return (EIO);
994: }
1.20 ad 995: if (bp->b_error != 0) {
1.2 ragge 996: #ifdef TSDEBUG
997: printf("error in ioctl %d\n", mtop->mt_op);
998: #endif
1.1 ragge 999: break;
1000: }
1001: } while (--callcount > 0);
1.20 ad 1002: if (bp->b_error != 0)
1003: error = bp->b_error;
1.13 simonb 1004: return (error);
1.1 ragge 1005:
1006: case MTIOCGET: /* get tape status */
1007: mtget = (struct mtget *)data;
1008: mtget->mt_type = MT_ISTS;
1.2 ragge 1009: mtget->mt_dsreg = TS_RCSR(TSSR);
1010: mtget->mt_erreg = sc->sc_vts->status.xst0;
1.1 ragge 1011: mtget->mt_resid = 0; /* ??? */
1012: mtget->mt_density = 0; /* ??? */
1013: break;
1014:
1015: case MTIOCIEOT: /* ignore EOT error */
1.2 ragge 1016: #ifdef TSDEBUG
1017: printf(("MTIOCIEOT not implemented.\n"));
1018: #endif
1.13 simonb 1019: return (ENXIO);
1.1 ragge 1020:
1021: case MTIOCEEOT: /* enable EOT error */
1.2 ragge 1022: #ifdef TSDEBUG
1023: printf(("MTIOCEEOT not implemented.\n"));
1024: #endif
1.1 ragge 1025: return (ENXIO);
1026:
1027: default:
1.2 ragge 1028: #ifdef TSDEBUG
1029: printf("invalid ioctl cmd 0x%lx\n", cmd);
1030: #endif
1.1 ragge 1031: return (ENXIO);
1032: }
1033:
1034: return (0);
1035: }
1036:
1037:
1038: /*
1.13 simonb 1039: *
1.1 ragge 1040: */
1041: int
1.2 ragge 1042: tsread(dev_t dev, struct uio *uio, int flag)
1.1 ragge 1043: {
1044: return (physio (tsstrategy, NULL, dev, B_READ, minphys, uio));
1045: }
1046:
1047: /*
1048: *
1049: */
1050: int
1.2 ragge 1051: tswrite(dev_t dev, struct uio *uio, int flag)
1.1 ragge 1052: {
1053: return (physio (tsstrategy, NULL, dev, B_WRITE, minphys, uio));
1054: }
1055:
1056: /*
1057: *
1058: */
1059: int
1060: tsdump(dev, blkno, va, size)
1061: dev_t dev;
1062: daddr_t blkno;
1.19 christos 1063: void *va;
1.1 ragge 1064: size_t size;
1065: {
1.2 ragge 1066: return EIO;
1.1 ragge 1067: }
CVSweb <webmaster@jp.NetBSD.org>