fixes from ernie
[unix-history] / usr / src / sys / vax / uba / ts.c
CommitLineData
30e0abb3 1/* ts.c 4.8 81/03/21 */
9bad5ea5 2
66b4fb09 3#include "ts.h"
9bad5ea5 4#if NTS > 0
30e0abb3
BJ
5#define printd if(tsdebug)printf
6int tsdebug;
9bad5ea5
BJ
7/*
8 * TS11 tape driver
30a7bcbf
BJ
9 *
10 * TODO:
11 * test driver with more than one controller
12 * test reset code
13 * test dump code
14 * test rewinds without hanging in driver
15 * what happens if you offline tape during rewind?
16 * test using file system on tape
9bad5ea5 17 */
9bad5ea5
BJ
18#include "../h/param.h"
19#include "../h/systm.h"
20#include "../h/buf.h"
9bad5ea5 21#include "../h/dir.h"
30a7bcbf 22#include "../h/conf.h"
9bad5ea5 23#include "../h/user.h"
30a7bcbf 24#include "../h/file.h"
9bad5ea5 25#include "../h/map.h"
30a7bcbf 26#include "../h/pte.h"
e1b765e1 27#include "../h/vm.h"
30a7bcbf
BJ
28#include "../h/ubareg.h"
29#include "../h/ubavar.h"
30#include "../h/mtio.h"
31#include "../h/ioctl.h"
32#include "../h/cmap.h"
33#include "../h/cpu.h"
34
35#include "../h/tsreg.h"
36
37/*
38 * There is a ctsbuf per tape controller.
39 * It is used as the token to pass to the internal routines
40 * to execute tape ioctls.
41 * In particular, when the tape is rewinding on close we release
42 * the user process but any further attempts to use the tape drive
43 * before the rewind completes will hang waiting for ctsbuf.
44 */
45struct buf ctsbuf[NTS];
46
47/*
48 * Raw tape operations use rtsbuf. The driver
49 * notices when rtsbuf is being used and allows the user
50 * program to continue after errors and read records
51 * not of the standard length (BSIZE).
52 */
53struct buf rtsbuf[NTS];
54
55/*
56 * Driver unibus interface routines and variables.
57 */
58int tsprobe(), tsslave(), tsattach(), tsdgo(), tsintr();
59struct uba_ctlr *tsminfo[NTS];
60struct uba_device *tsdinfo[NTS];
30e0abb3 61struct buf tsbuf[NTS];
30a7bcbf
BJ
62u_short tsstd[] = { 0772520, 0 };
63/*** PROBABLY DON'T NEED ALL THESE SINCE CONTROLLER == DRIVE ***/
64struct uba_driver zsdriver =
30e0abb3 65 { tsprobe, tsslave, tsattach, tsdgo, tsstd, "ts", tsdinfo, "zs", tsminfo, 0 };
30a7bcbf
BJ
66
67/* bits in minor device */
68#define TSUNIT(dev) (minor(dev)&03)
69#define T_NOREWIND 04
9bad5ea5 70
30a7bcbf 71#define INF (daddr_t)1000000L
9bad5ea5 72
30a7bcbf
BJ
73/*
74 * Software state per tape transport.
75 * Also contains hardware state in message packets.
76 *
77 * 1. A tape drive is a unique-open device; we refuse opens when it is already.
78 * 2. We keep track of the current position on a block tape and seek
79 * before operations by forward/back spacing if necessary.
80 * 3. We remember if the last operation was a write on a tape, so if a tape
81 * is open read write and the last thing done is a write we can
82 * write a standard end of tape mark (two eofs).
83 * 4. We remember the status registers after the last command, using
84 * then internally and returning them to the SENSE ioctl.
85 */
86struct ts_softc {
87 char sc_openf; /* lock against multiple opens */
88 char sc_lastiow; /* last op was a write */
30e0abb3 89 short sc_resid; /* copy of last bc */
30a7bcbf
BJ
90 daddr_t sc_blkno; /* block number, for block device tape */
91 daddr_t sc_nxrec; /* position of end of tape, if known */
30a7bcbf
BJ
92 struct ts_cmd sc_cmd; /* the command packet - ADDR MUST BE 0 MOD 4 */
93 struct ts_sts sc_sts; /* status packet, for returned status */
94 struct ts_char sc_char; /* characteristics packet */
95 u_short sc_uba; /* Unibus addr of cmd pkt for tsdb */
96} ts_softc[NTS];
97
98struct ts_softc *ts_ubaddr; /* Unibus address of ts_softc */
99
100/*
101 * States for um->um_tab.b_active, the per controller state flag.
102 * This is used to sequence control in the driver.
103 */
104#define SSEEK 1 /* seeking */
105#define SIO 2 /* doing seq i/o */
106#define SCOM 3 /* sending control command */
107#define SREW 4 /* sending a drive rewind */
108
109/*
110 * Determine if there is a controller for
111 * a ts at address reg. Our goal is to make the
112 * device interrupt.
113 */
114tsprobe(reg)
115 caddr_t reg;
116{
117 register int br, cvec; /* must be r11,r10; value-result */
118
119#ifdef lint
120 br = 0; cvec = br; br = cvec;
121#endif
122 /****************/
123 /* */
124 /* K L U D G E */
125 /* */
126 /****************/
127
128 /* IT'S TOO HARD TO MAKE THIS THING INTERRUPT
129 JUST TO FIND ITS VECTOR */
130 cvec = 0224;
131 br = 0x15;
132}
133
134/*
135 * TS11 only supports one drive per controller;
136 * check for ui_slave == 0.
137 *
138 * DO WE REALLY NEED THIS ROUTINE???
139 */
140/*ARGSUSED*/
141tsslave(ui, reg)
142 struct uba_device *ui;
143 caddr_t reg;
144{
145
146 if (ui->ui_slave) /* non-zero slave not allowed */
147 return(0);
148 return (1);
149}
150
151/*
152 * Record attachment of the unit to the controller.
153 *
154 * SHOULD THIS ROUTINE DO ANYTHING???
155 */
156/*ARGSUSED*/
157tsattach(ui)
158 struct uba_device *ui;
159{
160
161}
162
163/*
164 * Open the device. Tapes are unique open
165 * devices, so we refuse if it is already open.
166 * We also check that a tape is available, and
167 * don't block waiting here; if you want to wait
168 * for a tape you should timeout in user code.
169 */
9bad5ea5 170tsopen(dev, flag)
30a7bcbf
BJ
171 dev_t dev;
172 int flag;
9bad5ea5 173{
30a7bcbf
BJ
174 register int tsunit;
175 register struct uba_device *ui;
176 register struct ts_softc *sc;
9bad5ea5 177
30a7bcbf
BJ
178 tsunit = TSUNIT(dev);
179 if (tsunit>=NTS || (sc = &ts_softc[tsunit])->sc_openf ||
180 (ui = tsdinfo[tsunit]) == 0 || ui->ui_alive == 0) {
9bad5ea5
BJ
181 u.u_error = ENXIO;
182 return;
183 }
30a7bcbf 184 if (tsinit(tsunit)) {
9bad5ea5 185 u.u_error = ENXIO;
30e0abb3 186 printd("init failed\n");
9bad5ea5
BJ
187 return;
188 }
30e0abb3 189 printd("init ok\n");
30a7bcbf 190 tscommand(dev, TS_SENSE, 1);
30e0abb3 191 printd("sense xs0 %o\n", sc->sc_sts.s_xs0);
30a7bcbf
BJ
192 if ((sc->sc_sts.s_xs0&TS_ONL) == 0 || ((flag&(FREAD|FWRITE)) ==
193 FWRITE && (sc->sc_sts.s_xs0&TS_WLK))) {
194 /*
195 * Not online or write locked.
196 */
197 u.u_error = EIO;
198 return;
9bad5ea5 199 }
30a7bcbf
BJ
200 sc->sc_openf = 1;
201 sc->sc_blkno = (daddr_t)0;
202 sc->sc_nxrec = INF;
203 sc->sc_lastiow = 0;
9bad5ea5
BJ
204}
205
30a7bcbf
BJ
206/*
207 * Close tape device.
208 *
209 * If tape was open for writing or last operation was
210 * a write, then write two EOF's and backspace over the last one.
211 * Unless this is a non-rewinding special file, rewind the tape.
212 * Make the tape available to others.
213 */
9bad5ea5 214tsclose(dev, flag)
30a7bcbf
BJ
215 register dev_t dev;
216 register flag;
9bad5ea5 217{
30a7bcbf
BJ
218 register struct ts_softc *sc = &ts_softc[TSUNIT(dev)];
219
220 if (flag == FWRITE || (flag&FWRITE) && sc->sc_lastiow) {
221 tscommand(dev, TS_WEOF, 1);
222 tscommand(dev, TS_WEOF, 1);
223 tscommand(dev, TS_SREV, 1);
224 }
225 if ((minor(dev)&T_NOREWIND) == 0)
226 /*
227 * 0 count means don't hang waiting for rewind complete
228 * rather ctsbuf stays busy until the operation completes
229 * preventing further opens from completing by
230 * preventing a TS_SENSE from completing.
231 */
232 tscommand(dev, TS_REW, 0);
233 sc->sc_openf = 0;
234}
9bad5ea5 235
30a7bcbf
BJ
236/*
237 * Initialize the TS11. Set up Unibus mapping for command
238 * packets and set device characteristics.
239 */
240tsinit(unit)
241 register int unit;
242{
243 register struct ts_softc *sc = &ts_softc[unit];
244 register struct uba_ctlr *um = tsminfo[unit];
245 register struct device *addr = (struct device *)um->um_addr;
246 register int i;
247
248 /*
249 * Map the command and message packets into Unibus
250 * address space. We do all the command and message
251 * packets at once to minimize the amount of Unibus
252 * mapping necessary.
253 */
254 if (ts_ubaddr == 0) {
255 ctsbuf[unit].b_un.b_addr = (caddr_t)ts_softc;
256 ctsbuf[unit].b_bcount = sizeof(ts_softc);
257 i = ubasetup(um->um_ubanum, &ctsbuf[unit], 0);
258 i &= 0777777;
259 ts_ubaddr = (struct ts_softc *)i;
260 /* MAKE SURE WE DON'T GET UNIBUS ADDRESS ZERO */
261 if (ts_ubaddr == 0)
262 printf("ts%d: zero ubaddr\n", unit);
263 }
264 /*
265 * Now initialize the TS11 controller.
266 * Set the characteristics.
267 */
268 if (addr->tssr & TS_NBA) {
269 addr->tssr = 0; /* subsystem initialize */
270 tswait(addr);
271 i = (int)&ts_ubaddr[unit].sc_cmd; /* Unibus addr of cmd */
30e0abb3
BJ
272 if (i&3) {
273 printf("addr mod 4 != 0\n");
274 return(1);
275 }
30a7bcbf
BJ
276 sc->sc_uba = (u_short)(i + ((i>>16)&3));
277 sc->sc_char.char_addr = (int)&ts_ubaddr[unit].sc_sts;
278 sc->sc_char.char_size = sizeof(struct ts_sts);
279 sc->sc_char.char_mode = TS_ESS;
280 sc->sc_cmd.c_cmd = TS_ACK | TS_SETCHR;
30e0abb3
BJ
281 i = (int)&ts_ubaddr[unit].sc_char;
282 sc->sc_cmd.c_loba = i;
283 sc->sc_cmd.c_hiba = (i>>16)&3;
30a7bcbf
BJ
284 sc->sc_cmd.c_size = sizeof(struct ts_char);
285 addr->tsdb = sc->sc_uba;
286 tswait(addr);
30e0abb3
BJ
287/*
288 printd("%o %o %o %o %o %o %o %o\n", addr->tssr, sc->sc_sts.s_sts, sc->sc_sts.s_len, sc->sc_sts.s_rbpcr, sc->sc_sts.s_xs0, sc->sc_sts.s_xs1,sc->sc_sts.s_xs1,sc->sc_sts.s_xs2,sc->sc_sts.s_xs3);
289*/
290 if (addr->tssr & TS_NBA)
291 return(1);
9bad5ea5 292 }
30a7bcbf 293 return(0);
9bad5ea5
BJ
294}
295
30a7bcbf
BJ
296/*
297 * Execute a command on the tape drive
298 * a specified number of times.
299 */
300tscommand(dev, com, count)
301 dev_t dev;
302 int com, count;
9bad5ea5
BJ
303{
304 register struct buf *bp;
305
30a7bcbf
BJ
306 bp = &ctsbuf[TSUNIT(dev)];
307 (void) spl5();
308 while (bp->b_flags&B_BUSY) {
309 /*
310 * This special check is because B_BUSY never
311 * gets cleared in the non-waiting rewind case.
312 */
313 if (bp->b_repcnt == 0 && (bp->b_flags&B_DONE))
314 break;
9bad5ea5
BJ
315 bp->b_flags |= B_WANTED;
316 sleep((caddr_t)bp, PRIBIO);
317 }
9bad5ea5 318 bp->b_flags = B_BUSY|B_READ;
30a7bcbf 319 (void) spl0();
30e0abb3 320 printd("command %o dev %x count %d\n", com, dev, count);
30a7bcbf
BJ
321 bp->b_dev = dev;
322 bp->b_repcnt = count;
323 bp->b_command = com;
324 bp->b_blkno = 0;
9bad5ea5 325 tsstrategy(bp);
30a7bcbf
BJ
326 /*
327 * In case of rewind from close, don't wait.
328 * This is the only case where count can be 0.
329 */
330 if (count == 0)
331 return;
9bad5ea5 332 iowait(bp);
30a7bcbf 333 if (bp->b_flags&B_WANTED)
9bad5ea5 334 wakeup((caddr_t)bp);
30a7bcbf 335 bp->b_flags &= B_ERROR;
9bad5ea5
BJ
336}
337
30a7bcbf
BJ
338/*
339 * Queue a tape operation.
340 */
9bad5ea5 341tsstrategy(bp)
30a7bcbf 342 register struct buf *bp;
9bad5ea5 343{
30a7bcbf
BJ
344 int tsunit = TSUNIT(bp->b_dev);
345 register struct uba_ctlr *um;
30e0abb3 346 register struct buf *dp;
30a7bcbf
BJ
347
348 /*
349 * Put transfer at end of controller queue
350 */
9bad5ea5 351 bp->av_forw = NULL;
30a7bcbf 352 um = tsdinfo[tsunit]->ui_mi;
30e0abb3 353 dp = &tsbuf[tsunit];
30a7bcbf 354 (void) spl5();
30e0abb3
BJ
355 if (dp->b_actf == NULL)
356 dp->b_actf = bp;
9bad5ea5 357 else
30e0abb3
BJ
358 dp->b_actl->av_forw = bp;
359 dp->b_actl = bp;
360 um->um_tab.b_actf = um->um_tab.b_actl = dp;
30a7bcbf
BJ
361 /*
362 * If the controller is not busy, get
363 * it going.
364 */
365 if (um->um_tab.b_active == 0)
366 tsstart(um);
367 (void) spl0();
9bad5ea5
BJ
368}
369
30a7bcbf
BJ
370/*
371 * Start activity on a ts controller.
372 */
373tsstart(um)
374 register struct uba_ctlr *um;
9bad5ea5
BJ
375{
376 register struct buf *bp;
30a7bcbf
BJ
377 register struct device *addr = (struct device *)um->um_addr;
378 register struct ts_softc *sc;
379 register struct ts_cmd *tc;
380 register struct uba_device *ui;
381 int tsunit, cmd;
9bad5ea5
BJ
382 daddr_t blkno;
383
30a7bcbf
BJ
384 /*
385 * Start the controller if there is something for it to do.
386 */
387loop:
30e0abb3 388 if ((bp = um->um_tab.b_actf->b_actf) == NULL)
9bad5ea5 389 return;
30a7bcbf
BJ
390 tsunit = TSUNIT(bp->b_dev);
391 ui = tsdinfo[tsunit];
392 sc = &ts_softc[tsunit];
393 tc = &sc->sc_cmd;
394 /*
395 * Default is that last command was NOT a write command;
396 * if we do a write command we will notice this in tsintr().
397 */
398 sc->sc_lastiow = 1;
399 if (sc->sc_openf < 0 || (addr->tssr&TS_OFL)) {
400 /*
401 * Have had a hard error on a non-raw tape
402 * or the tape unit is now unavailable
403 * (e.g. taken off line).
404 */
405 bp->b_flags |= B_ERROR;
406 goto next;
407 }
408 if (bp == &ctsbuf[TSUNIT(bp->b_dev)]) {
409 /*
410 * Execute control operation with the specified count.
411 */
412 um->um_tab.b_active =
413 bp->b_command == TS_REW ? SREW : SCOM;
414 tc->c_repcnt = bp->b_repcnt;
30e0abb3 415 printd("strat: do cmd\n");
30a7bcbf
BJ
416 goto dobpcmd;
417 }
418 /*
419 * The following checks handle boundary cases for operation
420 * on non-raw tapes. On raw tapes the initialization of
421 * sc->sc_nxrec by tsphys causes them to be skipped normally
422 * (except in the case of retries).
423 */
424 if (dbtofsb(bp->b_blkno) > sc->sc_nxrec) {
425 /*
426 * Can't read past known end-of-file.
427 */
428 bp->b_flags |= B_ERROR;
429 bp->b_error = ENXIO;
430 goto next;
431 }
432 if (dbtofsb(bp->b_blkno) == sc->sc_nxrec &&
433 bp->b_flags&B_READ) {
434 /*
435 * Reading at end of file returns 0 bytes.
436 */
437 bp->b_resid = bp->b_bcount;
438 clrbuf(bp);
439 goto next;
440 }
441 if ((bp->b_flags&B_READ) == 0)
442 /*
443 * Writing sets EOF
444 */
445 sc->sc_nxrec = dbtofsb(bp->b_blkno) + 1;
446 /*
447 * If the data transfer command is in the correct place,
448 * set up all the registers except the csr, and give
449 * control over to the UNIBUS adapter routines, to
450 * wait for resources to start the i/o.
451 */
452 if ((blkno = sc->sc_blkno) == dbtofsb(bp->b_blkno)) {
453 tc->c_size = bp->b_bcount;
454 if ((bp->b_flags&B_READ) == 0)
455 cmd = TS_WCOM;
9bad5ea5 456 else
30a7bcbf
BJ
457 cmd = TS_RCOM;
458 if (um->um_tab.b_errcnt)
459 cmd |= TS_RETRY;
460 um->um_tab.b_active = SIO;
30e0abb3
BJ
461 tc->c_cmd = TS_ACK | TS_CVC | TS_IE | cmd;
462 printd("r/w %o size %d\n", tc->c_cmd, tc->c_size);
30a7bcbf
BJ
463 (void) ubago(ui);
464 return;
465 }
466 /*
467 * Tape positioned incorrectly;
468 * set to seek forwards or backwards to the correct spot.
469 * This happens for raw tapes only on error retries.
470 */
471 um->um_tab.b_active = SSEEK;
30e0abb3 472 printd("seek blkno %d b_blkno %d\n", blkno, bp->b_blkno);
30a7bcbf
BJ
473 if (blkno < dbtofsb(bp->b_blkno)) {
474 bp->b_command = TS_SFORW;
475 tc->c_repcnt = dbtofsb(bp->b_blkno) - blkno;
9bad5ea5 476 } else {
30a7bcbf
BJ
477 bp->b_command = TS_SREV;
478 tc->c_repcnt = blkno - dbtofsb(bp->b_blkno);
9bad5ea5 479 }
30a7bcbf
BJ
480dobpcmd:
481 /*
482 * Do the command in bp.
483 */
30e0abb3 484 tc->c_cmd = TS_ACK | TS_CVC | TS_IE | bp->b_command;
30a7bcbf 485 addr->tsdb = sc->sc_uba;
9bad5ea5
BJ
486 return;
487
30a7bcbf
BJ
488next:
489 /*
490 * Done with this operation due to error or
491 * the fact that it doesn't do anything.
492 * Release UBA resources (if any), dequeue
493 * the transfer and continue processing this slave.
494 */
495 if (um->um_ubinfo)
496 ubadone(um);
497 um->um_tab.b_errcnt = 0;
30e0abb3 498 um->um_tab.b_actf->b_actf = bp->av_forw;
9bad5ea5
BJ
499 iodone(bp);
500 goto loop;
501}
502
30a7bcbf
BJ
503/*
504 * The UNIBUS resources we needed have been
505 * allocated to us; start the device.
506 */
507tsdgo(um)
508 register struct uba_ctlr *um;
509{
510 register struct device *addr = (struct device *)um->um_addr;
511 register struct ts_softc *sc = &ts_softc[um->um_ctlr];
30e0abb3 512 register int i;
30a7bcbf 513
30e0abb3
BJ
514 i = um->um_ubinfo & 0777777;
515 printd("dgo addr %o\n", i);
516 sc->sc_cmd.c_loba = i;
517 sc->sc_cmd.c_hiba = (i>>16)&3;
30a7bcbf
BJ
518 addr->tsdb = sc->sc_uba;
519}
520
521/*
522 * Ts interrupt routine.
523 */
524/*ARGSUSED*/
525tsintr(ts11)
526 int ts11;
9bad5ea5
BJ
527{
528 register struct buf *bp;
30a7bcbf
BJ
529 register struct uba_ctlr *um = tsminfo[ts11];
530 register struct device *addr;
531 register struct ts_softc *sc;
532 int tsunit;
533 register state;
9bad5ea5 534
30e0abb3
BJ
535 printd("intr\n");
536 if ((bp = um->um_tab.b_actf->b_actf) == NULL)
9bad5ea5 537 return;
30a7bcbf
BJ
538 tsunit = TSUNIT(bp->b_dev);
539 addr = (struct device *)tsdinfo[tsunit]->ui_addr;
540 /*
541 * If last command was a rewind, and tape is still
542 * rewinding, wait for the rewind complete interrupt.
543 *
544 * SHOULD NEVER GET AN INTERRUPT IN THIS STATE.
545 */
546 if (um->um_tab.b_active == SREW) {
547 um->um_tab.b_active = SCOM;
548 if ((addr->tssr&TS_SSR) == 0)
549 return;
550 }
551 /*
552 * An operation completed... record status
553 */
30e0abb3 554 printd(" ok1\n");
30a7bcbf
BJ
555 sc = &ts_softc[tsunit];
556 if ((bp->b_flags & B_READ) == 0)
557 sc->sc_lastiow = 1;
558 state = um->um_tab.b_active;
559 um->um_tab.b_active = 0;
560 /*
561 * Check for errors.
562 */
563 if (addr->tssr&TS_SC) {
564 switch (addr->tssr & TS_TC) {
565 case TS_UNREC: /* unrecoverable */
566 case TS_FATAL: /* fatal error */
567 case TS_ATTN: /* attention (shouldn't happen) */
568 case TS_RECNM: /* recoverable, no motion */
569 break;
570
571 case TS_SUCC: /* success termination */
572 printf("ts%d: success\n", TSUNIT(minor(bp->b_dev)));
573 goto ignoreerr;
574
575 case TS_ALERT: /* tape status alert */
576 /*
577 * If we hit the end of the tape file,
578 * update our position.
579 */
580 if (sc->sc_sts.s_xs0 & (TS_TMK|TS_EOT)) {
581 tsseteof(bp); /* set blkno and nxrec */
582 state = SCOM; /* force completion */
583 /*
584 * Stuff bc so it will be unstuffed correctly
585 * later to get resid.
586 */
587 sc->sc_sts.s_rbpcr = bp->b_bcount;
588 goto opdone;
589 }
590 /*
591 * If we were reading raw tape and the record was too long
592 * or too short, then we don't consider this an error.
593 */
594 if (bp == &rtsbuf[TSUNIT(bp->b_dev)] && (bp->b_flags&B_READ) &&
595 sc->sc_sts.s_xs0&(TS_RLS|TS_RLL))
596 goto ignoreerr;
597 case TS_RECOV: /* recoverable, tape moved */
598 /*
599 * If this was an i/o operation retry up to 8 times.
600 */
601 if (state==SIO) {
602 if (++um->um_tab.b_errcnt < 7) {
603 ubadone(um);
604 goto opcont;
605 } else
606 sc->sc_blkno++;
607 } else {
608 /*
609 * Non-i/o errors on non-raw tape
610 * cause it to close.
611 */
612 if (sc->sc_openf>0 && bp != &rtsbuf[TSUNIT(bp->b_dev)])
613 sc->sc_openf = -1;
614 }
9bad5ea5 615 break;
30a7bcbf
BJ
616
617 case TS_REJECT: /* function reject */
618 if (state == SIO && sc->sc_sts.s_xs0 & TS_WLE)
619 printf("ts%d: write locked\n", TSUNIT(bp->b_dev));
620 if ((sc->sc_sts.s_xs0 & TS_ONL) == 0)
621 printf("ts%d: offline\n", TSUNIT(bp->b_dev));
9bad5ea5
BJ
622 break;
623 }
30a7bcbf
BJ
624 /*
625 * Couldn't recover error
626 */
627 printf("ts%d: hard error bn%d xs0=%b\n", TSUNIT(bp->b_dev),
628 bp->b_blkno, sc->sc_sts.s_xs0, TSXS0_BITS);
629 bp->b_flags |= B_ERROR;
630 goto opdone;
9bad5ea5 631 }
30a7bcbf
BJ
632 /*
633 * Advance tape control FSM.
634 */
635ignoreerr:
636 switch (state) {
637
9bad5ea5 638 case SIO:
30a7bcbf
BJ
639 /*
640 * Read/write increments tape block number
641 */
642 sc->sc_blkno++;
643 goto opdone;
644
9bad5ea5 645 case SCOM:
30a7bcbf
BJ
646 /*
647 * For forward/backward space record update current position.
648 */
649 if (bp == &ctsbuf[TSUNIT(bp->b_dev)])
650 switch (bp->b_command) {
651
652 case TS_SFORW:
653 sc->sc_blkno += bp->b_repcnt;
654 break;
9bad5ea5 655
30a7bcbf
BJ
656 case TS_SREV:
657 sc->sc_blkno -= bp->b_repcnt;
658 break;
659 }
660 goto opdone;
661
662 case SSEEK:
663 sc->sc_blkno = dbtofsb(bp->b_blkno);
664 goto opcont;
9bad5ea5
BJ
665
666 default:
30a7bcbf 667 panic("tsintr");
9bad5ea5 668 }
30a7bcbf
BJ
669opdone:
670 /*
671 * Reset error count and remove
672 * from device queue.
673 */
674 um->um_tab.b_errcnt = 0;
30e0abb3 675 um->um_tab.b_actf->b_actf = bp->av_forw;
30a7bcbf
BJ
676 bp->b_resid = sc->sc_sts.s_rbpcr;
677 ubadone(um);
30e0abb3 678 printd(" iodone\n");
30a7bcbf 679 iodone(bp);
30e0abb3 680 if (um->um_tab.b_actf->b_actf == 0)
30a7bcbf
BJ
681 return;
682opcont:
683 tsstart(um);
684}
685
686tsseteof(bp)
687 register struct buf *bp;
688{
689 register int tsunit = TSUNIT(bp->b_dev);
690 register struct ts_softc *sc = &ts_softc[tsunit];
691
692 if (bp == &ctsbuf[TSUNIT(bp->b_dev)]) {
693 if (sc->sc_blkno > dbtofsb(bp->b_blkno)) {
694 /* reversing */
695 sc->sc_nxrec = dbtofsb(bp->b_blkno) - sc->sc_sts.s_rbpcr;
696 sc->sc_blkno = sc->sc_nxrec;
697 } else {
698 /* spacing forward */
699 sc->sc_blkno = dbtofsb(bp->b_blkno) + sc->sc_sts.s_rbpcr;
700 sc->sc_nxrec = sc->sc_blkno - 1;
9bad5ea5 701 }
30a7bcbf
BJ
702 return;
703 }
704 /* eof on read */
705 sc->sc_nxrec = dbtofsb(bp->b_blkno);
9bad5ea5
BJ
706}
707
708tsread(dev)
30a7bcbf 709 dev_t dev;
9bad5ea5 710{
30a7bcbf 711
9bad5ea5 712 tsphys(dev);
30a7bcbf
BJ
713 if (u.u_error)
714 return;
715 physio(tsstrategy, &rtsbuf[TSUNIT(dev)], dev, B_READ, minphys);
9bad5ea5
BJ
716}
717
718tswrite(dev)
30a7bcbf 719 dev_t dev;
9bad5ea5 720{
30a7bcbf 721
9bad5ea5 722 tsphys(dev);
30a7bcbf
BJ
723 if (u.u_error)
724 return;
725 physio(tsstrategy, &rtsbuf[TSUNIT(dev)], dev, B_WRITE, minphys);
9bad5ea5
BJ
726}
727
30a7bcbf
BJ
728/*
729 * Check that a raw device exists.
730 * If it does, set up sc_blkno and sc_nxrec
731 * so that the tape will appear positioned correctly.
732 */
9bad5ea5 733tsphys(dev)
30a7bcbf 734 dev_t dev;
9bad5ea5 735{
30a7bcbf
BJ
736 register int tsunit = TSUNIT(dev);
737 register daddr_t a;
738 register struct ts_softc *sc;
739 register struct uba_device *ui;
9bad5ea5 740
30a7bcbf
BJ
741 if (tsunit >= NTS || (ui=tsdinfo[tsunit]) == 0 || ui->ui_alive == 0) {
742 u.u_error = ENXIO;
743 return;
744 }
745 sc = &ts_softc[tsunit];
746 a = dbtofsb(u.u_offset >> 9);
747 sc->sc_blkno = a;
748 sc->sc_nxrec = a + 1;
9bad5ea5 749}
f0a3ddbd 750
30a7bcbf
BJ
751tsreset(uban)
752 int uban;
f0a3ddbd 753{
30a7bcbf
BJ
754 register struct uba_ctlr *um;
755 register ts11;
756 register struct buf *dp;
757
758 for (ts11 = 0; ts11 < NTS; ts11++) {
759 if ((um = tsminfo[ts11]) == 0 || um->um_alive == 0 ||
760 um->um_ubanum != uban)
761 continue;
762 printf(" ts%d", ts11);
763 um->um_tab.b_active = 0;
764 um->um_tab.b_actf = um->um_tab.b_actl = 0;
765 ts_softc[ts11].sc_openf = -1;
766 if (um->um_ubinfo) {
767 printf("<%d>", (um->um_ubinfo>>28)&0xf);
768 ubadone(um);
769 }
770 tsinit(ts11);
771 tsstart(um);
f0a3ddbd 772 }
f0a3ddbd
BJ
773}
774
30a7bcbf
BJ
775/*ARGSUSED*/
776tsioctl(dev, cmd, addr, flag)
777 caddr_t addr;
778 dev_t dev;
f0a3ddbd 779{
30a7bcbf
BJ
780 int tsunit = TSUNIT(dev);
781 register struct ts_softc *sc = &ts_softc[tsunit];
782 register struct buf *bp = &ctsbuf[TSUNIT(dev)];
783 register callcount;
784 int fcount;
785 struct mtop mtop;
786 struct mtget mtget;
787 /* we depend of the values and order of the MT codes here */
788 static tsops[] =
789 {TS_WEOF,TS_SFORW,TS_SREV,TS_SFORWF,TS_SREVF,TS_REW,TS_OFFL,TS_SENSE};
790
791 switch (cmd) {
792 case MTIOCTOP: /* tape operation */
793 if (copyin((caddr_t)addr, (caddr_t)&mtop, sizeof(mtop))) {
794 u.u_error = EFAULT;
795 return;
796 }
797 switch(mtop.mt_op) {
798 case MTWEOF:
799 callcount = mtop.mt_count;
800 fcount = 1;
801 break;
802 case MTFSF: case MTBSF:
803 case MTFSR: case MTBSR:
804 callcount = 1;
805 fcount = mtop.mt_count;
806 break;
807 case MTREW: case MTOFFL: case MTNOP:
808 callcount = 1;
809 fcount = 1;
810 break;
811 default:
812 u.u_error = ENXIO;
813 return;
814 }
815 if (callcount <= 0 || fcount <= 0) {
816 u.u_error = ENXIO;
817 return;
818 }
819 while (--callcount >= 0) {
820 tscommand(dev, tsops[mtop.mt_op], fcount);
821 if ((mtop.mt_op == MTFSR || mtop.mt_op == MTBSR) &&
822 bp->b_resid) {
823 u.u_error = EIO;
824 break;
825 }
826 if ((bp->b_flags&B_ERROR) || sc->sc_sts.s_xs0&TS_BOT)
827 break;
828 }
829 geterror(bp);
830 return;
831 case MTIOCGET:
832 mtget.mt_dsreg = 0;
833 mtget.mt_erreg = sc->sc_sts.s_xs0;
834 mtget.mt_resid = sc->sc_resid;
835 if (copyout((caddr_t)&mtget, addr, sizeof(mtget)))
836 u.u_error = EFAULT;
837 return;
838 default:
839 u.u_error = ENXIO;
840 }
f0a3ddbd
BJ
841}
842
30a7bcbf 843#define DBSIZE 20
f0a3ddbd 844
30a7bcbf
BJ
845tsdump()
846{
847 register struct uba_device *ui;
848 register struct uba_regs *up;
849 register struct device *addr;
850 int blk, num;
851 int start;
852
853 start = 0;
854 num = maxfree;
855#define phys(a,b) ((b)((int)(a)&0x7fffffff))
856 if (tsdinfo[0] == 0)
857 return (ENXIO);
858 ui = phys(tsdinfo[0], struct uba_device *);
859 up = phys(ui->ui_hd, struct uba_hd *)->uh_physuba;
30e0abb3 860 ubainit(up);
30a7bcbf
BJ
861 DELAY(1000000);
862 addr = (struct device *)ui->ui_physaddr;
863 addr->tssr = 0;
864 tswait(addr);
865 while (num > 0) {
866 blk = num > DBSIZE ? DBSIZE : num;
867 tsdwrite(start, blk, addr, up);
868 start += blk;
869 num -= blk;
870 }
871 tseof(addr);
872 tseof(addr);
873 tswait(addr);
874 if (addr->tssr&TS_SC)
875 return (EIO);
876 addr->tssr = 0;
877 tswait(addr);
878 return (0);
f0a3ddbd
BJ
879}
880
30a7bcbf
BJ
881tsdwrite(dbuf, num, addr, up)
882 register dbuf, num;
883 register struct device *addr;
884 struct uba_regs *up;
f0a3ddbd 885{
30a7bcbf
BJ
886 register struct pte *io;
887 register int npf;
888
889 tswait(addr);
890 io = up->uba_map;
891 npf = num+1;
892 while (--npf != 0)
893 *(int *)io++ = (dbuf++ | (1<<UBAMR_DPSHIFT) | UBAMR_MRV);
894 *(int *)io = 0;
895#ifdef notyet
896 addr->tsbc = -(num*NBPG);
897 addr->tsba = 0;
898 addr->tscs = TS_WCOM | TM_GO;
899#endif
f0a3ddbd
BJ
900}
901
30a7bcbf
BJ
902tswait(addr)
903 register struct device *addr;
f0a3ddbd 904{
30a7bcbf 905 register s;
f0a3ddbd 906
30a7bcbf
BJ
907 do
908 s = addr->tssr;
909 while ((s & TS_SSR) == 0);
f0a3ddbd
BJ
910}
911
30a7bcbf
BJ
912tseof(addr)
913 struct device *addr;
f0a3ddbd 914{
30a7bcbf
BJ
915
916 tswait(addr);
917#ifdef notyet
918 addr->tscs = TS_WEOF | TM_GO;
919#endif
f0a3ddbd 920}
9bad5ea5 921#endif