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