| 1 | /* |
| 2 | * Copyright (c) 1982, 1986 Regents of the University of California. |
| 3 | * All rights reserved. The Berkeley software License Agreement |
| 4 | * specifies the terms and conditions for redistribution. |
| 5 | * |
| 6 | * @(#)ut.c 7.4 (Berkeley) %G% |
| 7 | */ |
| 8 | |
| 9 | /* |
| 10 | * SI Model 9700 -- emulates TU45 on the UNIBUS |
| 11 | */ |
| 12 | #include "../machine/pte.h" |
| 13 | |
| 14 | #include "param.h" |
| 15 | #include "inode.h" |
| 16 | #include "fs.h" |
| 17 | |
| 18 | #include "../vaxuba/ubareg.h" |
| 19 | #include "../vaxuba/utreg.h" |
| 20 | |
| 21 | #include "saio.h" |
| 22 | #include "savax.h" |
| 23 | |
| 24 | #define MASKREG(reg) ((reg)&0xffff) |
| 25 | |
| 26 | #define MAXCTLR 1 /* all addresses must be specified */ |
| 27 | u_short utstd[MAXCTLR] = { 0172440 }; /* non-standard */ |
| 28 | |
| 29 | utopen(io) |
| 30 | register struct iob *io; |
| 31 | { |
| 32 | register int skip; |
| 33 | |
| 34 | if ((u_int)io->i_ctlr >= MAXCTLR) |
| 35 | return (ECTLR); |
| 36 | if (badaddr((char *)ubamem(io->i_unit, utstd[io->i_ctlr]), sizeof(short))) |
| 37 | return (ENXIO); |
| 38 | utstrategy(io, UT_REW); |
| 39 | for (skip = io->i_part; skip--;) |
| 40 | utstrategy(io, UT_SFORWF); |
| 41 | return (0); |
| 42 | } |
| 43 | |
| 44 | utclose(io) |
| 45 | register struct iob *io; |
| 46 | { |
| 47 | utstrategy(io, UT_REW); |
| 48 | } |
| 49 | |
| 50 | #define UTWAIT(addr) { \ |
| 51 | do \ |
| 52 | word = addr->utcs1; \ |
| 53 | while((word&UT_RDY) == 0); \ |
| 54 | } |
| 55 | |
| 56 | utstrategy(io, func) |
| 57 | register struct iob *io; |
| 58 | { |
| 59 | register struct utdevice *addr; |
| 60 | register u_short word; |
| 61 | register int errcnt; |
| 62 | int info, resid; |
| 63 | u_short dens; |
| 64 | |
| 65 | addr = (struct utdevice *)ubamem(io->i_unit, utstd[io->i_ctlr]); |
| 66 | dens = io->i_unit | PDP11FMT | UT_PE; |
| 67 | errcnt = 0; |
| 68 | retry: |
| 69 | utquiet(addr); |
| 70 | addr->uttc = dens; |
| 71 | info = ubasetup(io, 1); |
| 72 | addr->utwc = -((io->i_cc+1) >> 1); |
| 73 | addr->utfc = -io->i_cc; |
| 74 | if (func == READ) { |
| 75 | addr->utba = info; |
| 76 | addr->utcs1 = UT_RCOM | ((info>>8) & 0x30) | UT_GO; |
| 77 | } else if (func == WRITE) { |
| 78 | addr->utba = info; |
| 79 | addr->utcs1 = UT_WCOM | ((info>>8) & 0x30) | UT_GO; |
| 80 | } else if (func == UT_SREV) { |
| 81 | addr->utcs1 = UT_SREV | UT_GO; |
| 82 | return (0); |
| 83 | } else |
| 84 | addr->utcs1 = func | UT_GO; |
| 85 | UTWAIT(addr); |
| 86 | ubafree(io, info); |
| 87 | word = addr->utds; |
| 88 | if (word&(UTDS_EOT|UTDS_TM)) { |
| 89 | addr->utcs1 = UT_CLEAR | UT_GO; |
| 90 | goto done; |
| 91 | } |
| 92 | if ((word&UTDS_ERR) || (addr->utcs1&UT_TRE)) { |
| 93 | printf("ut error: cs1=%b er=%b cs2=%b ds=%b", |
| 94 | addr->utcs1, UT_BITS, addr->uter, UTER_BITS, |
| 95 | addr->utcs2, UTCS2_BITS, word, UTDS_BITS); |
| 96 | if (errcnt++ == 10) { |
| 97 | printf("ut: unrecovered error\n"); |
| 98 | return (-1); |
| 99 | } |
| 100 | if (addr->utcs1&UT_TRE) |
| 101 | addr->utcs2 |= UTCS2_CLR; |
| 102 | addr->utcs1 = UT_CLEAR | UT_GO; |
| 103 | utstrategy(io, UT_SREV); |
| 104 | utquiet(addr); |
| 105 | if (func == WRITE) { |
| 106 | addr->utcs1 = UT_ERASE | UT_GO; |
| 107 | UTWAIT(addr); |
| 108 | } |
| 109 | goto retry; |
| 110 | } |
| 111 | if (errcnt) |
| 112 | printf("ut: recovered by retry\n"); |
| 113 | done: |
| 114 | if (func == READ) { |
| 115 | resid = 0; |
| 116 | if (io->i_cc > MASKREG(addr->utfc)) |
| 117 | resid = io->i_cc - MASKREG(addr->utfc); |
| 118 | } else |
| 119 | resid = MASKREG(-addr->utfc); |
| 120 | return (io->i_cc - resid); |
| 121 | } |
| 122 | |
| 123 | static |
| 124 | utquiet(addr) |
| 125 | register struct utdevice *addr; |
| 126 | { |
| 127 | register u_short word; |
| 128 | |
| 129 | UTWAIT(addr); |
| 130 | do |
| 131 | word = addr->utds; |
| 132 | while ((word&UTDS_DRY) == 0 && (word&UTDS_PIP)); |
| 133 | } |