uuclose and watchdog rewritten, silenced 'read stalled', and major cleanup
[unix-history] / usr / src / sys / vax / uba / uu.c
CommitLineData
5f334c5b 1/* uu.c 4.9 83/07/24 */
2a6e4a22 2
03d12a3f 3#include "uu.h"
fc231bc6 4#if NUU > 0
2a6e4a22 5/*
c3963d4e 6 * TU58 DECtape II/DL11 device driver
fc231bc6 7 *
b1084c70
HS
8 * The TU58 is treated as a block device (only). Error detection and
9 * recovery is not very extensive, but sufficient to handle the most
5f334c5b
HS
10 * common errors. It is assumed that the TU58 will follow the RSP
11 * protocol exactly, very few protocol errors are checked for.
12 *
13 * To reduce interrupt latency, `options UUDMA' should be specified
14 * in the config file to make sure the `pseudo-DMA' code in locore.s
15 * will be compiled into the system. Otherwise overrun errors will
16 * occur frequently (these errors are not reported).
17 *
18 * TODO:
19 *
20 * - Add ioctl code to wind/rewind cassette
21 *
2a6e4a22 22 */
c3963d4e 23
03d12a3f 24#include "../machine/pte.h"
c3963d4e 25
2a6e4a22
HS
26#include "../h/param.h"
27#include "../h/systm.h"
28#include "../h/buf.h"
29#include "../h/conf.h"
03d12a3f 30#include "../h/time.h"
2a6e4a22 31#include "../h/kernel.h"
c3963d4e 32#include "../h/errno.h"
c3963d4e 33#include "../h/file.h"
2a6e4a22
HS
34
35#include "../vax/cpu.h"
03d12a3f 36#include "../vax/nexus.h"
ecb04cd7 37#include "../vax/rsp.h"
03d12a3f 38
c3963d4e
HS
39#include "../vaxuba/ubavar.h"
40#include "../vaxuba/ubareg.h"
41#include "../vaxuba/uureg.h"
2a6e4a22 42
2a6e4a22 43#define NTUBLK 512 /* number of blocks on a TU58 cassette */
fc231bc6 44#define WRV 01 /* bit in minor dev => write w. read verify */
03d12a3f 45#define NDPC 02 /* drives per controller */
fc231bc6 46#define NUX NDPC * NUU /* number of drives */
5f334c5b 47#define NUUQ 02 /* # of block which can be queued up */
fc231bc6 48#define UMASK 01 /* unit number mask */
ecb04cd7 49#define UUIPL 0x14 /* ipl level to use */
2a6e4a22 50
fc231bc6
HS
51struct packet uucmd[NUU]; /* a command sent to the TU58 */
52struct packet uudata[NUU]; /* a command or data returned from TU58 */
53struct buf uitab[NUU]; /* buffer queue headers */
2a6e4a22
HS
54
55/*
ecb04cd7 56 * Driver soft carrier structure
2a6e4a22 57 */
ecb04cd7
HS
58struct uu_softc {
59 u_char *tu_rbptr; /* pointer to buffer for read */
60 int tu_rcnt; /* how much to read */
61 u_char *tu_wbptr; /* pointer to buffer for write */
62 int tu_wcnt; /* how much to write */
63 int tu_state; /* current state of tansfer operation */
64 int tu_flag; /* read in progress flag */
65 char *tu_addr; /* real buffer data address */
66 int tu_count; /* real requested count */
67 int tu_serrs; /* count of soft errors */
68 int tu_cerrs; /* count of checksum errors */
69 int tu_herrs; /* count of hard errors */
70 char tu_dopen[2]; /* drive is open */
a73ada79 71} uu_softc[NUU];
ecb04cd7
HS
72
73#if defined(VAX750) || defined(VAX730)
74extern char *tustates[];
75#else
76char *tustates[TUS_NSTATES] = {
2a6e4a22 77 "INIT1", "INIT2", "IDLE", "SENDH", "SENDD", "SENDC", "SENDR",
a73ada79 78 "SENDW", "GETH", "GETD", "GETC", "GET", "WAIT", "RCVERR", "CHKERR"
2a6e4a22 79};
ecb04cd7 80#endif
03d12a3f 81
fc231bc6 82#define UNIT(dev) (minor(dev)>>1)
2a6e4a22 83
5f334c5b 84u_char uunull[2] = { 0, 0 }; /* nulls to send for initialization */
c3963d4e
HS
85u_char uuinit[2] = { TUF_INITF, TUF_INITF }; /* inits to send */
86
87struct uba_device *uudinfo[NUU];
c3963d4e 88
fc231bc6
HS
89int uuprobe(), uuattach(), uurintr(), uuxintr(), uuwatch();
90u_short uustd[] = { 0176500 };
91struct uba_driver uudriver =
92 { uuprobe, 0, uuattach, 0, uustd, "uu", uudinfo };
c3963d4e
HS
93
94int uuwstart;
5f334c5b 95static char uu_pcnt[NUX]; /* pee/vee counters, one per drive */
2a6e4a22 96
2a6e4a22 97/*ARGSUSED*/
c3963d4e
HS
98uuprobe(reg)
99 caddr_t reg;
2a6e4a22 100{
c3963d4e
HS
101 register int br, cvec; /* value result */
102 struct uudevice *uuaddr = (struct uudevice *)reg;
2a6e4a22
HS
103
104#ifdef lint
c3963d4e
HS
105 br = 0; cvec = br; br = cvec;
106 uurintr(0); uuxintr(0);
2a6e4a22 107#endif
fc231bc6
HS
108 uuaddr->tcs = UUCS_INTR;
109 DELAY(1000);
110 uuaddr->tcs = 0;
111 cvec -= 4; /* since we are using the xmitter intrpt */
c3963d4e
HS
112 return(sizeof (*uuaddr));
113}
114
c3963d4e 115uuattach(ui)
fc231bc6 116 register struct uba_device *ui;
c3963d4e 117{
c3963d4e
HS
118}
119
120/*ARGSUSED1*/
121uuopen(dev, flag)
122 dev_t dev;
123 int flag;
124{
125 register struct uba_device *ui;
a73ada79 126 register struct uu_softc *uuc;
c3963d4e 127 register struct uudevice *uuaddr;
03d12a3f 128 int ctlr, unit = UNIT(dev), s;
c3963d4e 129
fc231bc6
HS
130 ctlr = unit / NDPC;
131 if (unit >= NUX || (ui = uudinfo[ctlr]) == 0 || ui->ui_alive == 0)
2a6e4a22 132 return (ENXIO);
ecb04cd7
HS
133 uuc = &uu_softc[ctlr];
134 if (uuc->tu_dopen[unit&UMASK])
c3963d4e
HS
135 return (EBUSY);
136 if (uuwstart++ == 0)
137 timeout(uuwatch, (caddr_t)0, hz);
138
ecb04cd7 139 uuc->tu_dopen[unit&UMASK]++;
fc231bc6
HS
140 uuaddr = (struct uudevice *)ui->ui_addr;
141 s = splx(UUIPL);
a73ada79
HS
142 /*
143 * If the other device on this controller
5f334c5b 144 * is already active, no need to initialize
a73ada79
HS
145 */
146 if (uuc->tu_dopen[0] && uuc->tu_dopen[1])
b1084c70 147 goto ok;
a73ada79 148
2a6e4a22 149 /*
c3963d4e 150 * If the unit already initialized,
2a6e4a22
HS
151 * just enable interrupts and return.
152 */
ecb04cd7 153 if (uuc->tu_state == TUS_IDLE) {
c3963d4e 154 uuaddr->rcs = UUCS_INTR;
ecb04cd7 155 goto ok;
2a6e4a22
HS
156 }
157
158 /*
159 * Must initialize, reset the cassette
160 * and wait for things to settle down.
161 */
c3963d4e
HS
162 uureset(ctlr);
163 sleep((caddr_t)uuc, PZERO+1);
fc231bc6 164 uitab[ctlr].b_active = NULL;
ecb04cd7
HS
165 if (uuc->tu_state != TUS_IDLE) {
166 uuc->tu_state = TUS_INIT1;
167 uuc->tu_dopen[unit&UMASK] = 0;
168 uuc->tu_rcnt = uuc->tu_wcnt = 0;
c3963d4e
HS
169 uuaddr->rcs = 0;
170 uuaddr->tcs = 0;
171 splx(s);
ecb04cd7 172 return (EIO);
2a6e4a22 173 }
ecb04cd7 174ok:
2a6e4a22
HS
175 splx(s);
176 return (0);
177}
178
5f334c5b
HS
179/*
180 * Wait for all outstanding IO on this drive
181 * complete, before closing. If both drives on
182 * this controller are idle, mark the controller
183 * `inactive'.
184 */
185
c3963d4e
HS
186uuclose(dev, flag)
187 dev_t dev;
188 int flag;
2a6e4a22 189{
5f334c5b
HS
190 int s, unit = UNIT(dev);
191 register struct uu_softc *uuc = &uu_softc[unit/NDPC];
192 struct buf *bp, *last = NULL;
193 struct uudevice *uuaddr = (struct uudevice *)uudinfo[unit/NDPC]->ui_addr;
c3963d4e 194
5f334c5b
HS
195 s = splx(UUIPL);
196 while (uu_pcnt[unit])
197 sleep(&uu_pcnt[unit], PRIBIO);
198 /*
199 * No more writes are pending, scan the
200 * buffer queue for oustanding reads from
201 * this unit.
202 */
203 for (bp = uitab[unit/NDPC].b_actf; bp; bp = bp->b_actf)
204 if (bp->b_dev == dev)
205 last = bp;
206 if (last)
207 iowait(last);
208 uuc->tu_dopen[unit&UMASK] = 0;
209 if (!uuc->tu_dopen[0] && !uuc->tu_dopen[1]) {
210 uuc->tu_flag = 0;
211 uuaddr->rcs = 0;
212 /*
213 * Make sure the device is left in a
214 * known state....
215 */
216 if (uuc->tu_state != TUS_IDLE)
217 uuc->tu_state = TUS_INIT1;
218 }
219 splx(s);
2a6e4a22
HS
220}
221
c3963d4e
HS
222uureset(ctlr)
223 int ctlr;
2a6e4a22 224{
a73ada79 225 register struct uu_softc *uuc = &uu_softc[ctlr];
03d12a3f 226 register struct packet *cmd = &uucmd[ctlr];
fc231bc6
HS
227 struct uba_device *ui = uudinfo[ctlr];
228 register struct uudevice *uuaddr = (struct uudevice *)ui->ui_addr;
c3963d4e 229
fc231bc6 230 uitab[ctlr].b_active++;
ecb04cd7
HS
231 uuc->tu_state = TUS_INIT1;
232 uuc->tu_wbptr = uunull;
233 uuc->tu_wcnt = sizeof (uunull);
5f334c5b 234 uuc->tu_rcnt = 0;
c3963d4e 235 cmd->pk_flag = TUF_CMD;
03d12a3f 236 cmd->pk_mcount = sizeof (*cmd) - 4;
c3963d4e
HS
237 cmd->pk_mod = 0;
238 cmd->pk_seq = 0;
03d12a3f 239 cmd->pk_sw = 0;
c3963d4e
HS
240 uuaddr->rcs = 0;
241 uuaddr->tcs = UUCS_INTR | UUCS_BREAK;
242 uuxintr(ctlr); /* start output */
2a6e4a22
HS
243}
244
245/*
246 * Strategy routine for block I/O
247 */
c3963d4e 248uustrategy(bp)
2a6e4a22
HS
249 register struct buf *bp;
250{
03d12a3f 251 register struct buf *uutab;
c3963d4e 252 struct uba_device *ui;
5f334c5b 253 int s, unit = UNIT(bp->b_dev);
c3963d4e 254
5f334c5b 255 if ((unit > NUX) || (bp->b_blkno >= NTUBLK))
c3963d4e 256 goto bad;
fc231bc6 257 ui = uudinfo[unit/NDPC];
c3963d4e
HS
258 if (ui == 0 || ui->ui_alive == 0)
259 goto bad;
fc231bc6 260 uutab = &uitab[unit/NDPC]; /* one request queue per controller */
b1084c70 261 s = splx(UUIPL);
03d12a3f 262 if ((bp->b_flags&B_READ) == 0)
5f334c5b
HS
263 tu_pee(&uu_pcnt[unit]);
264 bp->b_actf = NULL;
03d12a3f
HS
265 if (uutab->b_actf == NULL)
266 uutab->b_actf = bp;
267 else
5f334c5b 268 uutab->b_actl->b_actf = bp;
03d12a3f
HS
269 uutab->b_actl = bp;
270 if (uutab->b_active == 0)
fc231bc6 271 uustart(ui);
2a6e4a22 272 splx(s);
c3963d4e
HS
273 return;
274
275bad:
276 bp->b_flags |= B_ERROR;
03d12a3f 277 bp->b_error = ENXIO;
c3963d4e
HS
278 iodone(bp);
279 return;
2a6e4a22
HS
280}
281
282/*
283 * Start the transfer
284 */
fc231bc6
HS
285uustart(ui)
286 register struct uba_device *ui;
2a6e4a22
HS
287{
288 register struct buf *bp;
a73ada79 289 register struct uu_softc *uuc;
c3963d4e 290 struct packet *cmd;
fc231bc6 291 int ctlr = ui->ui_unit;
2a6e4a22 292
fc231bc6 293 if ((bp = uitab[ctlr].b_actf) == NULL)
2a6e4a22 294 return;
ecb04cd7 295 uuc = &uu_softc[ctlr];
ecb04cd7 296 if (uuc->tu_state != TUS_IDLE) {
03d12a3f 297 uureset(ctlr);
2a6e4a22
HS
298 return;
299 }
5f334c5b 300 cmd = &uucmd[ctlr];
fc231bc6 301 uitab[ctlr].b_active++;
ecb04cd7
HS
302 uitab[ctlr].b_errcnt = 0;
303 uuc->tu_addr = bp->b_un.b_addr;
304 uuc->tu_count = cmd->pk_count = bp->b_bcount;
305 cmd->pk_block = bp->b_blkno;
306 if (bp->b_flags&B_READ) {
307 cmd->pk_op = TUOP_READ;
308 cmd->pk_mod = 0;
309 uuc->tu_state = TUS_SENDR;
310 } else {
311 cmd->pk_op = TUOP_WRITE;
312 cmd->pk_mod = minor(bp->b_dev)&WRV ? TUMD_WRV : 0;
313 uuc->tu_state = TUS_SENDW;
314 }
5f334c5b 315 cmd->pk_unit = UNIT(bp->b_dev)&UMASK;
03d12a3f 316 cmd->pk_sw = 0;
c3963d4e 317 cmd->pk_chksum =
ecb04cd7
HS
318 tuchk(*((short *)cmd), (u_short *)&cmd->pk_op, (int)cmd->pk_mcount);
319 uuc->tu_wbptr = (u_char *)cmd;
320 uuc->tu_wcnt = sizeof (*cmd);
03d12a3f 321 uuxintr(ctlr);
2a6e4a22
HS
322}
323
324/*
5f334c5b
HS
325 * TU58 receiver interrupt, handles whatever condition the
326 * pseudo DMA routine in locore is unable to handle,
327 * or, if UUDMA is undefined, handle all receiver interrupt
328 * processing.
2a6e4a22 329 */
03d12a3f
HS
330uurintr(ctlr)
331 int ctlr;
2a6e4a22 332{
fc231bc6 333 struct uba_device *ui = uudinfo[ctlr];
a73ada79 334 register struct uu_softc *uuc = &uu_softc[ctlr];
fc231bc6
HS
335 register struct uudevice *uuaddr = (struct uudevice *)ui->ui_addr;
336 register struct buf *uutab = &uitab[ctlr];
03d12a3f 337 struct packet *data, *cmd;
ecb04cd7
HS
338 struct buf *bp;
339 int c, unit;
03d12a3f 340
fc231bc6 341 c = uuaddr->rdb;
ecb04cd7 342 data = &uudata[ctlr];
a73ada79
HS
343 cmd = &uucmd[ctlr];
344#if !defined(UUDMA)
345 if (c & UURDB_ERROR)
346 uuc->tu_state = TUS_RCVERR;
347 else {
348 if (uuc->tu_rcnt) {
349 *uuc->tu_rbptr++ = c;
350 if (--uuc->tu_rcnt)
351 return;
352 }
353 }
354#endif
355
356 /*
357 * Switch on the tu_state of the transfer.
358 */
359 switch(uuc->tu_state) {
360
361 /*
362 * A data error occured in uudma
363 * (either overrun or break)
364 */
365 case TUS_RCVERR:
b1084c70
HS
366 if ((c & UURDB_ORUN) == 0)
367 printf("uu%d: break received, transfer restarted\n",
401769ad 368 data->pk_unit);
5f334c5b
HS
369#ifdef UUDEBUG
370 else
371 printf("uu%d: data overrun, recovered\n",
372 data->pk_unit);
373#endif
b1084c70 374 uuc->tu_serrs++;
a73ada79
HS
375 uu_restart(ctlr, ui);
376 break;
2a6e4a22
HS
377
378 /*
379 * If we get an unexpected "continue",
380 * start all over again...
381 */
ecb04cd7
HS
382 case TUS_INIT2:
383 uuc->tu_state = c == TUF_CONT ? TUS_IDLE : TUS_INIT1;
384 uuc->tu_flag = 0;
03d12a3f 385 wakeup((caddr_t)uuc);
fc231bc6 386 uustart(ui);
2a6e4a22
HS
387 break;
388
389 /*
390 * Only transition from this state
391 * is on a "continue", so if we don't
392 * get it, reset the world.
393 */
ecb04cd7 394 case TUS_WAIT: /* waiting for continue */
03d12a3f
HS
395 switch(c) {
396 case TUF_CONT: /* got the expected continue */
ecb04cd7 397 uuc->tu_flag = 0;
03d12a3f 398 data->pk_flag = TUF_DATA;
ecb04cd7 399 data->pk_mcount = MIN(128, uuc->tu_count);
03d12a3f 400 data->pk_chksum =
ecb04cd7 401 tuchk(*((short *)data), (caddr_t)uuc->tu_addr,
03d12a3f 402 (int)data->pk_mcount);
ecb04cd7
HS
403 uuc->tu_state = TUS_SENDH;
404 uuc->tu_wbptr = (u_char *)data;
405 uuc->tu_wcnt = 2;
fc231bc6 406 uuxintr(ctlr);
03d12a3f
HS
407 break;
408
409 case TUF_CMD: /* sending us an END packet...error */
ecb04cd7
HS
410 uuc->tu_state = TUS_GET;
411 uuc->tu_rbptr = (u_char *)data;
a73ada79 412 uuc->tu_rcnt = sizeof (*data) - 1;
ecb04cd7 413 uuc->tu_flag = 1;
03d12a3f 414 uuaddr->tcs = 0;
a73ada79
HS
415 *uuc->tu_rbptr++ = c & UUDB_DMASK;
416 break;
03d12a3f
HS
417
418 case TUF_INITF:
fc231bc6 419 uureset(ctlr);
03d12a3f
HS
420 break;
421
422 default: /* something random...bad news */
ecb04cd7 423 uuc->tu_state = TUS_INIT1;
2a6e4a22
HS
424 break;
425 }
2a6e4a22
HS
426 break;
427
ecb04cd7
HS
428 case TUS_SENDW:
429 if (c != TUF_CONT && c != TUF_INITF)
2a6e4a22 430 goto bad;
a73ada79 431 uu_restart(ctlr, ui);
2a6e4a22
HS
432 break;
433
434 /*
435 * Got header, now get data; amount to
c3963d4e 436 * fetch is included in packet.
a73ada79
HS
437 * (data packets are handled entirely
438 * in uudma)
2a6e4a22 439 */
ecb04cd7 440 case TUS_GETH:
b1084c70
HS
441#ifndef UUDMA
442 if (data->pk_flag == TUF_DATA)
443 uuc->tu_rbptr = (u_char *)uuc->tu_addr;
444#endif
ecb04cd7
HS
445 uuc->tu_rcnt = data->pk_mcount;
446 uuc->tu_state = TUS_GETD;
2a6e4a22
HS
447 break;
448
449 /*
450 * Got the data, now fetch the checksum.
451 */
ecb04cd7
HS
452 case TUS_GETD:
453 uuc->tu_rbptr = (u_char *)&data->pk_chksum;
454 uuc->tu_rcnt = sizeof (data->pk_chksum);
455 uuc->tu_state = TUS_GETC;
2a6e4a22
HS
456 break;
457
ecb04cd7 458 case TUS_GETC:
2a6e4a22 459 /* got entire packet */
03d12a3f 460 if (data->pk_chksum !=
ecb04cd7 461 tuchk(*((short *)data), (u_short *)
a73ada79 462 (data->pk_flag == TUF_DATA ?
b1084c70 463 (u_short *) uuc->tu_addr : (u_short *)&data->pk_op),
03d12a3f 464 (int)data->pk_mcount))
a73ada79 465 case TUS_CHKERR:
ecb04cd7 466 uuc->tu_cerrs++;
a73ada79 467 case TUS_GET:
03d12a3f 468 if (data->pk_flag == TUF_DATA) {
2a6e4a22 469 /* data packet, advance to next */
ecb04cd7
HS
470 uuc->tu_addr += data->pk_mcount;
471 uuc->tu_count -= data->pk_mcount;
472 uuc->tu_state = TUS_GETH;
473 uuc->tu_rbptr = (u_char *)data; /* next packet */
474 uuc->tu_rcnt = 2;
03d12a3f 475 } else if (data->pk_flag==TUF_CMD && data->pk_op==TUOP_END) {
2a6e4a22 476 /* end packet, idle and reenable transmitter */
ecb04cd7
HS
477 uuc->tu_state = TUS_IDLE;
478 uuc->tu_flag = 0;
479 uuaddr->tcs = UUCS_INTR;
480 if ((bp = uutab->b_actf) == NULL) {
b1084c70 481 printf("uu%d: no bp, active %d\n",
401769ad 482 data->pk_unit, uitab[ctlr].b_active);
fc231bc6 483 uustart(ui);
2a6e4a22
HS
484 return;
485 }
5f334c5b 486 unit = UNIT(bp->b_dev);
03d12a3f 487 if (data->pk_mod > 1) { /* hard error */
a73ada79 488 printf("uu%d: hard error bn%d,", unit,
401769ad 489 bp->b_blkno);
5f334c5b 490 printf(" pk_mod 0%o\n", data->pk_mod&0xff);
2a6e4a22 491 bp->b_flags |= B_ERROR;
ecb04cd7 492 uuc->tu_herrs++;
5f334c5b 493 } else if (data->pk_mod) /* soft error */
ecb04cd7 494 uuc->tu_serrs++;
03d12a3f 495 uutab->b_active = NULL;
5f334c5b 496 uutab->b_actf = bp->b_actf;
ecb04cd7 497 bp->b_resid = uuc->tu_count;
2a6e4a22 498 if ((bp->b_flags&B_READ) == 0)
5f334c5b 499 tu_vee(&uu_pcnt[unit]);
2a6e4a22 500 iodone(bp);
fc231bc6 501 uustart(ui);
2a6e4a22 502 } else {
b1084c70
HS
503 /*
504 * Neither data nor end: data was lost
5f334c5b 505 * somehow, flush and restart the transfer.
b1084c70 506 */
5f334c5b 507 uuaddr->rcs = 0;
a73ada79 508 uu_restart(ctlr, ui);
b1084c70 509 uuc->tu_serrs++;
2a6e4a22
HS
510 }
511 break;
512
ecb04cd7
HS
513 case TUS_IDLE:
514 case TUS_INIT1:
2a6e4a22
HS
515 break;
516
517 default:
518bad:
519 if (c == TUF_INITF) {
b1084c70 520 printf("uu%d protocol error, state=", data->pk_unit);
ecb04cd7 521 printstate(uuc->tu_state);
2a6e4a22 522 printf(", op=%x, cnt=%d, block=%d\n",
03d12a3f
HS
523 cmd->pk_op, cmd->pk_count, cmd->pk_block);
524 uutab->b_active = NULL;
525 if (bp = uutab->b_actf) {
2a6e4a22 526 bp->b_flags |= B_ERROR;
5f334c5b 527 uutab->b_actf = bp->b_actf;
2a6e4a22 528 if ((bp->b_flags&B_READ) == 0)
5f334c5b 529 tu_vee(&uu_pcnt[unit]);
2a6e4a22
HS
530 iodone(bp);
531 }
ecb04cd7 532 uuc->tu_state = TUS_INIT1;
2a6e4a22 533 } else {
03d12a3f 534 printf("uu%d receive state error, state=",
b1084c70 535 data->pk_unit);
ecb04cd7 536 printstate(uuc->tu_state);
a73ada79 537 printf(", byte=%x\n", c & 0xff);
2a6e4a22 538#ifdef notdef
ecb04cd7 539 uuc->tu_state = TUS_INIT1;
2a6e4a22 540#endif
03d12a3f 541 wakeup((caddr_t)uuc);
2a6e4a22
HS
542 }
543 }
544}
545
ecb04cd7 546
2a6e4a22
HS
547/*
548 * TU58 transmitter interrupt
549 */
03d12a3f
HS
550uuxintr(ctlr)
551 int ctlr;
2a6e4a22 552{
a73ada79 553 register struct uu_softc *uuc = &uu_softc[ctlr];
fc231bc6 554 register struct uudevice *uuaddr;
03d12a3f 555 register struct packet *data;
fc231bc6 556 struct uba_device *ui = uudinfo[ctlr];
03d12a3f 557 int c;
2a6e4a22 558
fc231bc6
HS
559 data = &uudata[ctlr];
560 uuaddr = (struct uudevice *) ui->ui_addr;
2a6e4a22 561top:
5f334c5b 562 if (uuc->tu_wcnt > 0) {
2a6e4a22 563 /* still stuff to send, send one byte */
03d12a3f 564 while ((uuaddr->tcs & UUCS_READY) == 0)
2a6e4a22 565 ;
ecb04cd7
HS
566 uuaddr->tdb = *uuc->tu_wbptr++;
567 uuc->tu_wcnt--;
2a6e4a22
HS
568 return;
569 }
570
571 /*
572 * Last message byte was sent out.
ecb04cd7 573 * Switch on tu_state of transfer.
2a6e4a22 574 */
ecb04cd7 575 switch(uuc->tu_state) {
2a6e4a22
HS
576
577 /*
578 * Two nulls have been sent, remove break, and send inits
579 */
ecb04cd7 580 case TUS_INIT1:
5f334c5b 581 uuc->tu_flag = 0;
03d12a3f 582 uuaddr->tcs = UUCS_INTR;
ecb04cd7
HS
583 uuc->tu_state = TUS_INIT2;
584 uuc->tu_wbptr = uuinit;
585 uuc->tu_wcnt = sizeof (uuinit);
2a6e4a22
HS
586 goto top;
587
588 /*
589 * Inits have been sent, wait for a continue msg.
590 */
ecb04cd7 591 case TUS_INIT2:
fc231bc6 592 c = uuaddr->rdb; /* prevent overrun error */
03d12a3f 593 uuaddr->rcs = UUCS_INTR;
ecb04cd7 594 uuc->tu_flag = 1;
2a6e4a22
HS
595 break;
596
2a6e4a22
HS
597 /*
598 * Read cmd packet sent, get ready for data
599 */
ecb04cd7
HS
600 case TUS_SENDR:
601 uuc->tu_state = TUS_GETH;
602 uuc->tu_rbptr = (u_char *)data;
603 uuc->tu_rcnt = 2;
604 uuc->tu_flag = 1;
5f334c5b 605 uuaddr->tcs = 0;
ecb04cd7 606 uuaddr->rcs = UUCS_INTR;
2a6e4a22
HS
607 break;
608
609 /*
610 * Write cmd packet sent, wait for continue
611 */
ecb04cd7
HS
612 case TUS_SENDW:
613 uuc->tu_state = TUS_WAIT;
614 uuc->tu_flag = 1;
03d12a3f 615 if ((uuaddr->rcs&UUCS_INTR) == 0) {
2a6e4a22 616 printf("NO IE\n");
03d12a3f 617 uuaddr->rcs = UUCS_INTR;
2a6e4a22
HS
618 }
619 break;
620
621 /*
622 * Header sent, send data.
623 */
ecb04cd7
HS
624 case TUS_SENDH:
625 uuc->tu_state = TUS_SENDD;
626 uuc->tu_wbptr = (u_char *)uuc->tu_addr;
627 uuc->tu_wcnt = data->pk_mcount;
2a6e4a22
HS
628 goto top;
629
630 /*
631 * Data sent, follow with checksum.
632 */
ecb04cd7
HS
633 case TUS_SENDD:
634 uuc->tu_state = TUS_SENDC;
635 uuc->tu_wbptr = (u_char *)&data->pk_chksum;
5f334c5b 636 uuc->tu_wcnt = 2;
2a6e4a22
HS
637 goto top;
638
639 /*
640 * Checksum sent, wait for continue.
641 */
ecb04cd7 642 case TUS_SENDC:
2a6e4a22 643 /*
ecb04cd7 644 * Update buffer address and count.
2a6e4a22 645 */
ecb04cd7
HS
646 uuc->tu_addr += data->pk_mcount;
647 uuc->tu_count -= data->pk_mcount;
5f334c5b 648 if (uuc->tu_count > 0) {
ecb04cd7
HS
649 uuc->tu_state = TUS_WAIT;
650 uuc->tu_flag = 1;
2a6e4a22
HS
651 break;
652 }
653
654 /*
655 * End of transmission, get ready for end packet.
656 */
ecb04cd7
HS
657 uuc->tu_state = TUS_GET;
658 uuc->tu_rbptr = (u_char *)data;
659 uuc->tu_rcnt = sizeof (*data);
660 uuc->tu_flag = 1;
5f334c5b 661 uuaddr->tcs = 0;
2a6e4a22
HS
662 break;
663
664 /*
03d12a3f 665 * Random interrupt
2a6e4a22 666 */
b1084c70
HS
667 case TUS_IDLE: /* stray interrupt? */
668
2a6e4a22
HS
669 default:
670 break;
671 }
ecb04cd7
HS
672}
673
674uuwatch()
675{
a73ada79 676 register struct uu_softc *uuc;
ecb04cd7
HS
677 register struct uudevice *uuaddr;
678 struct uba_device *ui;
679 struct buf *bp, *uutab;
680 int s, ctlr, active = 0;
681
682 for (ctlr=0; ctlr<NUU; ctlr++) {
683 int i;
684
685 uuc = &uu_softc[ctlr];
5f334c5b
HS
686
687 if (uuc->tu_dopen[0] || uuc->tu_dopen[1])
688 active++;
689 if (uuc->tu_flag == 0)
b1084c70 690 /*
5f334c5b
HS
691 * If no read is in progress
692 * just skip
b1084c70 693 */
ecb04cd7 694 continue;
5f334c5b
HS
695
696 ui = uudinfo[ctlr];
697 uuaddr = (struct uudevice *)ui->ui_addr;
698 uutab = &uitab[ctlr];
699 if (uuc->tu_flag++ < 40)
ecb04cd7 700 continue;
b1084c70 701 printf("uu%d: read stalled\n", uudata[ctlr].pk_unit);
5f334c5b 702#ifdef UUDEBUG
ecb04cd7 703 printf("%X %X %X %X %X %X %X\n", uuc->tu_rbptr, uuc->tu_rcnt,
b1084c70
HS
704 uuc->tu_wbptr, uuc->tu_wcnt, uuc->tu_state, uuc->tu_addr,
705 uuc->tu_count);
401769ad 706#endif
ecb04cd7 707 s = splx(UUIPL);
5f334c5b 708 uuc->tu_flag = 0;
ecb04cd7
HS
709 i = uuaddr->rdb; /* dummy */
710 uuaddr->rcs = UUCS_INTR; /* in case we were flushing */
711 uuaddr->tcs = UUCS_INTR;
712 uuc->tu_state = TUS_IDLE;
713 if (!uutab->b_active) {
714 wakeup((caddr_t)uuc);
715 goto retry;
716 }
717 if (++uutab->b_errcnt <= 1) {
718 uustart(ui);
719 goto retry;
720 }
721 if (bp = uutab->b_actf) {
722 bp->b_flags |= B_ERROR;
723 if ((bp->b_flags&B_READ) == 0)
5f334c5b 724 tu_vee(&uu_pcnt[UNIT(bp->b_dev)]);
ecb04cd7
HS
725 iodone(bp);
726 }
727retry:
728 (void) splx(s);
2a6e4a22 729 }
ecb04cd7
HS
730 if (active)
731 timeout(uuwatch, (caddr_t)0, hz);
732 else
733 uuwstart = 0;
734 return;
2a6e4a22
HS
735}
736
ecb04cd7 737#if !defined(VAX750) && !defined(VAX730)
2a6e4a22
HS
738/*
739 * Compute checksum TU58 fashion
740 */
741#ifdef lint
ecb04cd7 742tuchk(word, cp, n)
2a6e4a22
HS
743 register word;
744 register unsigned short *cp;
745 int n;
746{
747 register int c = n >> 1;
748 register long temp;
749
750 do {
751 temp = *cp++; /* temp, only because vax cc won't *r++ */
752 word += temp;
753 } while (--c > 0);
754 if (n & 1)
755 word += *(unsigned char *)cp;
756 while (word & 0xffff0000)
757 word = (word & 0xffff) + ((word >> 16) & 0xffff);
758 return (word);
759}
760#else
ecb04cd7 761tuchk(word0, wp, n)
c3963d4e
HS
762 register int word0; /* r11 */
763 register char *wp; /* r10 */
764 register int n; /* r9 */
2a6e4a22
HS
765{
766 asm("loop:");
c3963d4e
HS
767 asm(" addw2 (r10)+,r11"); /* add a word to sum */
768 asm(" adwc $0,r11"); /* add in carry, end-around */
2a6e4a22 769 asm(" acbl $2,$-2,r9,loop"); /* done yet? */
c3963d4e
HS
770 asm(" blbc r9,ok"); /* odd byte count? */
771 asm(" movzbw (r10),r10"); /* yes, get last byte */
772 asm(" addw2 r10,r11"); /* add it in */
773 asm(" adwc $0,r11"); /* and the carry */
2a6e4a22 774 asm("ok:");
c3963d4e 775 asm(" movl r11,r0"); /* return sum */
2a6e4a22
HS
776}
777#endif
778
5f334c5b
HS
779/*
780 * Make sure this incredibly slow device
781 * doesn't eat up all the buffers in the
782 * system by putting the requesting process
783 * (remember: this device is 'single-user')
784 * to sleep if the write-behind queue grows
785 * larger than NUUQ.
786 */
ecb04cd7 787tu_pee(cp)
5f334c5b 788 char *cp;
03d12a3f
HS
789{
790 register int s;
791
fc231bc6 792 s = splx(UUIPL);
5f334c5b 793 if (++(*cp) > NUUQ)
03d12a3f 794 sleep(cp, PRIBIO);
03d12a3f
HS
795 splx(s);
796}
797
ecb04cd7 798tu_vee(cp)
5f334c5b 799 char *cp;
03d12a3f
HS
800{
801 register int s;
802
fc231bc6 803 s = splx(UUIPL);
5f334c5b 804 if (--(*cp) <= NUUQ)
03d12a3f 805 wakeup(cp);
2a6e4a22 806 splx(s);
2a6e4a22
HS
807}
808#endif
03d12a3f 809
ecb04cd7
HS
810uuioctl(dev, cmd, data, flag)
811 dev_t dev;
812 caddr_t data;
813{
814 /*
b1084c70 815 * add code to wind/rewind cassette here
ecb04cd7
HS
816 */
817 return (ENXIO);
818}
819
a73ada79
HS
820uu_restart(ctlr, ui)
821 int ctlr;
822 struct uba_device *ui;
823{
824 uureset(ctlr);
825 timeout(uustart, (caddr_t)ui, hz * 3);
826}
5f334c5b
HS
827
828#endif