Commit | Line | Data |
---|---|---|
8e292a1d | 1 | |
cf703c6c | 2 | /* @(#)tmscp.c 7.3 (Berkeley) %G% */ |
8e292a1d KD |
3 | |
4 | /**************************************************************** | |
5 | * * | |
6 | * Licensed from Digital Equipment Corporation * | |
7 | * Copyright (c) * | |
8 | * Digital Equipment Corporation * | |
9 | * Maynard, Massachusetts * | |
10 | * 1985, 1986 * | |
11 | * All rights reserved. * | |
12 | * * | |
13 | * The Information in this software is subject to change * | |
14 | * without notice and should not be construed as a commitment * | |
15 | * by Digital Equipment Corporation. Digital makes no * | |
16 | * representations about the suitability of this software for * | |
17 | * any purpose. It is supplied "As Is" without expressed or * | |
18 | * implied warranty. * | |
19 | * * | |
20 | * If the Regents of the University of California or its * | |
21 | * licensees modify the software in a manner creating * | |
22 | * diriviative copyright rights, appropriate copyright * | |
23 | * legends may be placed on the drivative work in addition * | |
24 | * to that set forth above. * | |
25 | ***************************************************************/ | |
26 | /* | |
27 | * tmscp.c - TMSCP (TK50/TU81) standalone driver | |
28 | */ | |
29 | ||
30 | # ifndef lint | |
31 | static char *sccsid = "@(#)tmscp.c 1.5 (ULTRIX) 4/18/86"; | |
32 | # endif not lint | |
33 | ||
34 | /* ------------------------------------------------------------------------ | |
35 | * Modification History: /sys/stand/tmscp.c | |
36 | * | |
37 | * 3-15-85 afd | |
38 | * Don't ask for an interrupt when commands are issued and | |
39 | * check ownership bit in the response descriptor to detect when a | |
40 | * command is complete. Necessary due to the TU81's failure to set | |
41 | * the response interrupt field in the communications area. | |
42 | * | |
43 | * ------------------------------------------------------------------------ | |
44 | */ | |
45 | ||
39c71180 MK |
46 | #include "param.h" |
47 | #include "inode.h" | |
48 | #include "fs.h" | |
49 | ||
50 | #include "../vax/pte.h" | |
51 | ||
8e292a1d | 52 | #include "savax.h" |
8e292a1d KD |
53 | #include "saio.h" |
54 | ||
55 | /* | |
56 | * Parameters for the communications area | |
57 | * (Only 1 cmd & 1 rsp packet) | |
58 | */ | |
59 | #define NRSPL2 0 | |
60 | #define NCMDL2 0 | |
61 | #define NRSP (1<<NRSPL2) | |
62 | #define NCMD (1<<NCMDL2) | |
63 | ||
64 | #include "../vaxuba/tmscpreg.h" | |
65 | #include "../vaxuba/ubareg.h" | |
66 | #include "../vax/tmscp.h" | |
67 | ||
cf703c6c KB |
68 | #define MAXCTLR 1 /* all addresses must be specified */ |
69 | u_short tmscpstd[MAXCTLR] = { 0174500 }; | |
8e292a1d KD |
70 | |
71 | struct iob ctmscpbuf; | |
72 | ||
73 | struct tmscpdevice *tmscpaddr = 0; | |
74 | ||
75 | struct tmscp { | |
76 | struct tmscpca tmscp_ca; | |
77 | struct mscp tmscp_rsp; | |
78 | struct mscp tmscp_cmd; | |
cf703c6c | 79 | } tmscp; |
8e292a1d KD |
80 | |
81 | struct tmscp *tmscp_ubaddr; /* Unibus address of tmscp structure */ | |
82 | ||
83 | struct mscp *tmscpcmd(); | |
84 | ||
85 | int tmscp_offline = 1; /* Flag to prevent multiple STCON */ | |
86 | int tms_offline[4] = {1,1,1,1}; /* Flag to prevent multiple ONLIN */ | |
87 | ||
8e292a1d KD |
88 | /* |
89 | * Open a tmscp device. Initialize the controller and set the unit online. | |
90 | */ | |
91 | tmscpopen(io) | |
92 | register struct iob *io; | |
93 | { | |
94 | register struct mscp *mp; | |
95 | int i; | |
96 | ||
cf703c6c KB |
97 | if ((u_int)io->i_ctlr >= MAXCTLR) |
98 | return (ECTLR); | |
8e292a1d KD |
99 | /* |
100 | * Have the tmscp controller characteristics already been set up | |
101 | * (STCON)? | |
102 | */ | |
cf703c6c | 103 | if (tmscp_offline) { |
8e292a1d | 104 | if (tmscpaddr == 0) |
cf703c6c KB |
105 | tmscpaddr = (struct tmscpdevice *)ubamem(io->i_adapt, tmscpstd[0]); |
106 | if (tmscp_ubaddr == 0) { | |
8e292a1d KD |
107 | ctmscpbuf.i_unit = io->i_unit; |
108 | ctmscpbuf.i_ma = (caddr_t)&tmscp; | |
109 | ctmscpbuf.i_cc = sizeof(tmscp); | |
110 | tmscp_ubaddr = (struct tmscp *)ubasetup(&ctmscpbuf, 2); | |
cf703c6c | 111 | } |
8e292a1d KD |
112 | /* |
113 | * Initialize the tmscp device and wait for the 4 steps | |
114 | * to complete. | |
115 | */ | |
116 | tmscpaddr->tmscpip = 0; | |
cf703c6c | 117 | while ((tmscpaddr->tmscpsa & TMSCP_STEP1) == 0); |
8e292a1d KD |
118 | tmscpaddr->tmscpsa =TMSCP_ERR|(NCMDL2<<11)|(NRSPL2<<8); |
119 | ||
cf703c6c | 120 | while ((tmscpaddr->tmscpsa & TMSCP_STEP2) == 0); |
8e292a1d KD |
121 | # define STEP1MASK 0174377 |
122 | # define STEP1GOOD (TMSCP_STEP2|TMSCP_IE|(NCMDL2<<3)|NRSPL2) | |
123 | if ((tmscpaddr->tmscpsa&STEP1MASK) != STEP1GOOD) | |
124 | printf("tmscpopen: step 1 not successful sa=%o\n",tmscpaddr->tmscpsa&0xffff); | |
125 | tmscpaddr->tmscpsa = (short)&tmscp_ubaddr->tmscp_ca.ca_ringbase; | |
126 | ||
cf703c6c | 127 | while ((tmscpaddr->tmscpsa & TMSCP_STEP3) == 0); |
8e292a1d KD |
128 | # define STEP2MASK 0174377 |
129 | # define STEP2GOOD (TMSCP_STEP3) | |
130 | if ((tmscpaddr->tmscpsa&STEP2MASK) != STEP2GOOD) | |
131 | printf("tmscpopen: step 2 not successful sa=%o\n",tmscpaddr->tmscpsa&0xffff); | |
132 | tmscpaddr->tmscpsa = (short)(((int)&tmscp_ubaddr->tmscp_ca.ca_ringbase) >> 16); | |
133 | ||
cf703c6c | 134 | while ((tmscpaddr->tmscpsa & TMSCP_STEP4) == 0); |
8e292a1d KD |
135 | # define STEP3MASK 0174000 |
136 | # define STEP3GOOD TMSCP_STEP4 | |
137 | if ((tmscpaddr->tmscpsa&STEP3MASK) != STEP3GOOD) | |
138 | printf("tmscpopen: step 3 not successful sa=%o\n",tmscpaddr->tmscpsa&0xffff); | |
139 | tmscpaddr->tmscpsa = TMSCP_GO; | |
140 | ||
141 | /* | |
142 | * Init cmd & rsp area | |
143 | */ | |
144 | tmscp.tmscp_ca.ca_cmddsc[0] = (long)&tmscp_ubaddr->tmscp_cmd.mscp_cmdref; | |
145 | tmscp.tmscp_cmd.mscp_dscptr = tmscp.tmscp_ca.ca_cmddsc; | |
146 | tmscp.tmscp_cmd.mscp_header.tmscp_vcid = 1; /* for tape */ | |
147 | ||
148 | tmscp.tmscp_ca.ca_rspdsc[0] = (long)&tmscp_ubaddr->tmscp_rsp.mscp_cmdref; | |
149 | tmscp.tmscp_rsp.mscp_dscptr = tmscp.tmscp_ca.ca_rspdsc; | |
150 | tmscp.tmscp_cmd.mscp_cntflgs = 0; | |
cf703c6c | 151 | if (tmscpcmd(M_OP_STCON, 0) == 0) { |
39c71180 MK |
152 | printf("tms: open error, STCON\n"); |
153 | return (EIO); | |
8e292a1d | 154 | } |
cf703c6c KB |
155 | tmscp_offline = 0; |
156 | } | |
8e292a1d KD |
157 | tmscp.tmscp_cmd.mscp_unit = io->i_unit&03; |
158 | /* | |
159 | * Has this unit been issued an ONLIN? | |
160 | */ | |
cf703c6c KB |
161 | if (tms_offline[tmscp.tmscp_cmd.mscp_unit]) { |
162 | if ((mp = tmscpcmd(M_OP_ONLIN, 0)) == 0) { | |
39c71180 MK |
163 | _stop("tms: open error, ONLIN\n"); |
164 | return (EIO); | |
8e292a1d | 165 | } |
cf703c6c | 166 | tms_offline[tmscp.tmscp_cmd.mscp_unit] = 0; |
39c71180 | 167 | } |
cf703c6c KB |
168 | /* |
169 | * This makes no sense, but I could be wrong... KB | |
170 | * | |
171 | * if ((u_int)io->i_part > 3) | |
172 | * return (EPART); | |
173 | */ | |
174 | if (io->i_part) { | |
8e292a1d KD |
175 | /* |
176 | * Skip forward the appropriate number of files on the tape. | |
177 | */ | |
cf703c6c KB |
178 | tmscp.tmscp_cmd.mscp_tmkcnt = io->i_part; |
179 | (void)tmscpcmd(M_OP_REPOS, 0); | |
8e292a1d | 180 | tmscp.tmscp_cmd.mscp_tmkcnt = 0; |
cf703c6c | 181 | } |
39c71180 | 182 | return (0); |
8e292a1d KD |
183 | } |
184 | ||
8e292a1d KD |
185 | /* |
186 | * Close the device (rewind it to BOT) | |
187 | */ | |
188 | tmscpclose(io) | |
189 | register struct iob *io; | |
190 | { | |
cf703c6c | 191 | (void)tmscpcmd(M_OP_REPOS, M_MD_REWND); |
8e292a1d KD |
192 | } |
193 | ||
8e292a1d KD |
194 | /* |
195 | * Set up tmscp command packet. Cause the controller to poll to pick up | |
196 | * the command. | |
197 | */ | |
198 | struct mscp * | |
199 | tmscpcmd(op,mod) | |
200 | int op, mod; /* opcode and modifier (usu 0) */ | |
201 | { | |
202 | struct mscp *mp; /* ptr to cmd packet */ | |
203 | int i; /* read into to init polling */ | |
204 | ||
205 | tmscp.tmscp_cmd.mscp_opcode = op; | |
206 | tmscp.tmscp_cmd.mscp_modifier = mod; | |
207 | tmscp.tmscp_cmd.mscp_header.tmscp_msglen = mscp_msglen; | |
208 | tmscp.tmscp_ca.ca_cmddsc[0] |= TMSCP_OWN; /* | TMSCP_INT */ | |
209 | tmscp.tmscp_rsp.mscp_header.tmscp_msglen = mscp_msglen; | |
210 | tmscp.tmscp_ca.ca_rspdsc[0] |= TMSCP_OWN; /* | TMSCP_INT */ | |
211 | ||
212 | i = tmscpaddr->tmscpip; | |
cf703c6c KB |
213 | for (;;) { |
214 | if (tmscpaddr->tmscpsa & TMSCP_ERR) { | |
8e292a1d KD |
215 | printf("tmscpcmd: Fatal error sa=%o\n", tmscpaddr->tmscpsa & 0xffff); |
216 | return(0); | |
cf703c6c | 217 | } |
8e292a1d KD |
218 | |
219 | if (tmscp.tmscp_ca.ca_cmdint) | |
220 | tmscp.tmscp_ca.ca_cmdint = 0; | |
221 | /* | |
222 | * This is to handle the case of devices not setting the | |
223 | * interrupt field in the communications area. Some | |
224 | * devices (early TU81's) only clear the ownership field | |
225 | * in the Response Descriptor. | |
cf703c6c KB |
226 | * |
227 | * | |
228 | * if (tmscp.tmscp_ca.ca_rspint) | |
229 | * break; | |
8e292a1d | 230 | */ |
8e292a1d KD |
231 | if (!(tmscp.tmscp_ca.ca_rspdsc[0] & (TMSCP_OWN))) |
232 | break; | |
cf703c6c | 233 | } |
8e292a1d KD |
234 | tmscp.tmscp_ca.ca_rspint = 0; |
235 | mp = &tmscp.tmscp_rsp; | |
236 | if (mp->mscp_opcode != (op|M_OP_END) || | |
cf703c6c KB |
237 | (mp->mscp_status&M_ST_MASK) != M_ST_SUCC) { |
238 | /* | |
239 | * Detect hitting tape mark. This signifies the end of the | |
8e292a1d KD |
240 | * tape mini-root file. We don't want to return an error |
241 | * condition to the strategy routine. | |
242 | */ | |
cf703c6c KB |
243 | if ((mp->mscp_status & M_ST_MASK) != M_ST_TAPEM) |
244 | return(0); | |
245 | } | |
8e292a1d KD |
246 | return(mp); |
247 | } | |
248 | ||
8e292a1d KD |
249 | /* |
250 | * Set up to do reads and writes; call tmscpcmd to issue the cmd. | |
251 | */ | |
252 | tmscpstrategy(io, func) | |
253 | register struct iob *io; | |
254 | int func; | |
255 | { | |
256 | register struct mscp *mp; | |
257 | int ubinfo; | |
258 | ||
259 | ubinfo = ubasetup(io, 1); | |
260 | mp = &tmscp.tmscp_cmd; | |
261 | mp->mscp_lbn = io->i_bn; | |
262 | mp->mscp_unit = io->i_unit&03; | |
263 | mp->mscp_bytecnt = io->i_cc; | |
264 | mp->mscp_buffer = (ubinfo & 0x3fffff) | (((ubinfo>>28)&0xf)<<24); | |
cf703c6c | 265 | if ((mp = tmscpcmd(func == READ ? M_OP_READ : M_OP_WRITE, 0)) == 0) { |
8e292a1d KD |
266 | ubafree(io, ubinfo); |
267 | printf("tms: I/O error\n"); | |
268 | return(-1); | |
cf703c6c | 269 | } |
8e292a1d KD |
270 | ubafree(io, ubinfo); |
271 | /* | |
272 | * Detect hitting tape mark so we do it gracefully and return a | |
273 | * character count of 0 to signify end of copy. Rewind the tape | |
274 | * before returning. | |
275 | */ | |
276 | if ((mp->mscp_status & M_ST_MASK) == M_ST_TAPEM) | |
277 | return(0); | |
278 | return(io->i_cc); | |
279 | } |