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