1 #ifndef lint
2 static char sccsid[] = "@(#)io.c 1.7 (Berkeley/CCI) 06/07/88";
3 #endif
4
5 #include "vdfmt.h"
6 #include "cmd.h"
7
8
9 /*
10 **
11 */
12
13 static cmd_text_element nul_table[] = {
14 { 0, "", "" }
15 };
16
17 int wait_for_char;
18 int vdtimeout;
19 char *clean_up = "Cleaning up... Please wait.\n";
20
21
22 /*
23 **
24 */
25
poll(wait)26 poll(wait)
27 int wait;
28 {
29 register struct vddevice *addr = C_INFO->addr;
30 int tokens[10];
31
32 if (kill_processes == false)
33 wait_for_char = 0;
34 vdtimeout = wait*1000;
35 for (;;) {
36 uncache(&(dcb.operrsta));
37 if (dcb.operrsta & (DCBS_DONE | DCBS_ABORT))
38 break;
39 if (kill_processes == false && input()) {
40 get_text_cmd(nul_table, tokens);
41 if (kill_processes == true) {
42 indent();
43 print(clean_up);
44 exdent(1);
45 }
46 }
47 if (vdtimeout-- <= 0) {
48 if(C_INFO->type == VDTYPE_VDDC)
49 printf("\nVDDC");
50 else
51 printf("\nSMD-E");
52 printf(": Controller timeout");
53 abort:
54 VDABORT(addr, C_INFO->type);
55 DELAY(30000);
56 break;
57 }
58 DELAY(1000);
59 }
60 if ((vdtimeout > 0)) {
61 if (C_INFO->type == VDTYPE_SMDE) {
62 for (;;) {
63 uncache(&(addr->vdcsr));
64 if ((addr->vdcsr & CS_GO) == 0)
65 break;
66 DELAY(1000);
67 if (vdtimeout-- <= 0) {
68 printf("\nSMD-E timed out clearing GO");
69 goto abort;
70 }
71 }
72 DELAY(300);
73 }
74 DELAY(500);
75 }
76 DELAY(200);
77 if((dcb.opcode == VDOP_RD) || (dcb.opcode == VDOP_RDRAW))
78 mtpr(PADC, 0);
79 uncache(&(dcb.operrsta));
80 uncache(&(dcb.err_code));
81 wait_for_char = 1;
82 }
83
84
85 /*
86 ** Access_with_no_trailer is used to perform controller functions which
87 ** require no data movement.
88 */
89
access_with_no_trailer(function,wait_time)90 access_with_no_trailer(function, wait_time)
91 int function, wait_time;
92 {
93 dcb.opcode = function; /* command */
94 dcb.intflg = DCBINT_NONE;
95 dcb.nxtdcb = (struct dcb *)0; /* end of chain */
96 dcb.operrsta = 0;
97 dcb.devselect = (function == VDOP_START) ? 0 :
98 ((char)cur.drive | lab->d_devflags);
99 dcb.trailcnt = (char)0;
100 mdcb.mdcb_head = &dcb;
101 mdcb.mdcb_status = 0;
102 VDGO(C_INFO->addr, (u_long)&mdcb, C_INFO->type);
103 poll(wait_time);
104 if(vdtimeout <= 0) {
105 printf(" during startup operation.\n");
106 _longjmp(abort_environ, 1);
107 }
108 return dcb.operrsta;
109 }
110
vread(sn,buf,seccnt)111 vread(sn, buf, seccnt)
112 int sn, seccnt;
113 char *buf;
114 {
115 int ret;
116
117 ret = vrdwr(sn, buf, seccnt, VDOP_RD);
118 if (ret == 0)
119 vd_error("read");
120 return (ret);
121 }
122
vwrite(sn,buf,seccnt)123 vwrite(sn, buf, seccnt)
124 int sn, seccnt;
125 char *buf;
126 {
127 int ret;
128
129 ret = vrdwr(sn, buf, seccnt, VDOP_WD);
130 if (ret == 0)
131 vd_error("write");
132 return (ret);
133 };
134
vrdwr(sn,buf,seccnt,op)135 vrdwr(sn, buf, seccnt, op)
136 int sn, seccnt, op;
137 char *buf;
138 {
139 dskadr dskaddr;
140
141 dskaddr.cylinder = sn / lab->d_secpercyl;
142 sn %= lab->d_secpercyl;
143 dskaddr.track = sn / lab->d_nsectors;
144 dskaddr.sector = sn % lab->d_nsectors;
145 if (access_dsk(buf, &dskaddr, op, seccnt, 1) & DCBS_HARD)
146 return (0);
147 return (seccnt);
148 }
149
150 /*
151 ** access_dsk is used by other routines to do reads and writes to the disk.
152 ** The status of the read / write is returned to the caller for processing.
153 */
154
access_dsk(buf,dskaddr,func,count,wait)155 access_dsk(buf, dskaddr, func, count, wait)
156 char *buf;
157 dskadr *dskaddr;
158 int func, count, wait;
159 {
160 cur.daddr.cylinder = dskaddr->cylinder;
161 cur.daddr.track = dskaddr->track;
162 wait_for_char = 0;
163 dcb.opcode = func; /* format sector command */
164 dcb.intflg = DCBINT_NONE;
165 dcb.nxtdcb = (struct dcb *)0; /* end of chain */
166 dcb.operrsta = 0;
167 dcb.devselect = (char)cur.drive | lab->d_devflags;
168 if(func == VDOP_SEEK) {
169 dcb.trailcnt = (char)(sizeof(struct trseek) / sizeof(long));
170 dcb.trail.sktrail.skaddr.cylinder = dskaddr->cylinder;
171 dcb.trail.sktrail.skaddr.track = dskaddr->track;
172 dcb.trail.sktrail.skaddr.sector = dskaddr->sector;
173 } else {
174 dcb.trailcnt = (char)(sizeof(struct trrw) / sizeof(long));
175 dcb.trail.rwtrail.memadr = (u_long)buf;
176 dcb.trail.rwtrail.wcount=count*(lab->d_secsize/sizeof(short));
177 dcb.trail.rwtrail.disk.cylinder = dskaddr->cylinder;
178 dcb.trail.rwtrail.disk.track = dskaddr->track;
179 dcb.trail.rwtrail.disk.sector = dskaddr->sector;
180 }
181 mdcb.mdcb_head = &dcb;
182 mdcb.mdcb_status = 0;
183 VDGO(C_INFO->addr, (u_long)&mdcb, C_INFO->type);
184 if(wait) {
185 poll(10);
186 if(vdtimeout <= 0) {
187 printf(" in access_dsk.\n");
188 _longjmp(abort_environ, 1);
189 }
190 }
191 wait_for_char = 1;
192 return dcb.operrsta;
193 }
194
195
196 /*
197 ** Spin_up_drive starts the drives on a controller and waits around for
198 ** the drive to spin up if it is not already spinning.
199 */
200
spin_up_drive()201 spin_up_drive()
202 {
203 register struct vddevice *addr = C_INFO->addr;
204
205 VDRESET(addr, C_INFO->type);
206 if(C_INFO->type == VDTYPE_SMDE) {
207 addr->vdcsr = 0;
208 addr->vdtcf_mdcb = AM_ENPDA;
209 addr->vdtcf_dcb = AM_ENPDA;
210 addr->vdtcf_trail = AM_ENPDA;
211 addr->vdtcf_data = AM_ENPDA;
212 addr->vdccf = CCF_SEN | 0x8 | CCF_STS |
213 XMD_32BIT | BSZ_16WRD | CCF_ERR |
214 CCF_ENP | CCF_EPE | CCF_EDE | CCF_ECE;
215 }
216 access_with_no_trailer(VDOP_INIT, 10);
217 access_with_no_trailer(VDOP_DIAG, 20);
218 configure_drive(0);
219 }
220
221 /*
222 ** Configure_drive tells the controller what kind of drive is attached
223 ** on a particular line.
224 */
225
configure_drive(pass)226 configure_drive(pass)
227 int pass;
228 {
229 register struct vddevice *addr = C_INFO->addr;
230 register i;
231
232 top:
233 dcb.opcode = VDOP_CONFIG; /* command */
234 dcb.intflg = DCBINT_NONE;
235 dcb.nxtdcb = (struct dcb *)0; /* end of chain */
236 dcb.operrsta = 0;
237 dcb.devselect = cur.drive | lab->d_devflags;
238 dcb.trail.rstrail.ncyl = lab->d_ncylinders;
239 dcb.trail.rstrail.nsurfaces = lab->d_ntracks;
240 if(C_INFO->type == VDTYPE_VDDC)
241 dcb.trailcnt = (char)2;
242 else {
243 dcb.trailcnt = sizeof (struct treset)/sizeof (long);
244 dcb.trail.rstrail.nsectors = lab->d_nsectors;
245 dcb.trail.rstrail.slip_sec = lab->d_sparespertrack;
246 dcb.trail.rstrail.recovery = VDRF_NONE;
247 addr->vdcylskew = lab->d_cylskew;
248 addr->vdtrackskew = lab->d_trackskew;
249 addr->vdsecsize = lab->d_secsize/sizeof(short);
250 }
251 mdcb.mdcb_head = &dcb;
252 mdcb.mdcb_status = 0;
253 VDGO(addr, (u_long)&mdcb, C_INFO->type);
254 poll(5);
255 if(vdtimeout <= 0) {
256 printf(" during drive configuration.\n");
257 goto bad;
258 }
259 if(dcb.operrsta & VDERR_HARD) {
260 if (C_INFO->type == VDTYPE_SMDE) {
261 if (lab->d_devflags == 0) {
262 lab->d_devflags = VD_ESDI;
263 goto top;
264 }
265 #ifdef notdef
266 printf("vdstatus %x\n", addr->vdstatus[cur.drive]);
267 if ((addr->vdstatus[cur.drive] & STA_US) == 0) {
268 printf("Drive not present\n\n");
269 goto bad;
270 }
271 #endif
272 }
273 if ((dcb.operrsta & (DCBS_OCYL|DCBS_NRDY)) == 0) {
274 printf("drive config error\n");
275 goto bad;
276 }
277 if(pass) {
278 printf("\nDrive failed to start!\n\n");
279 goto bad;
280 }
281 printf("\ndrive not ready, attempting to spin up...");
282 access_with_no_trailer(VDOP_START, 62);
283 for (i = 0; i < 620; i++) {
284 if (C_INFO->type == VDTYPE_SMDE &&
285 addr->vdstatus[cur.drive] & STA_UR)
286 break;
287 DELAY(100000);
288 }
289 printf(" retrying drive configuration\n");
290 pass++;
291 lab->d_devflags = 0;
292 goto top;
293 }
294 D_INFO->alive = u_true;
295 return;
296 bad:
297 D_INFO->alive = u_false;
298 _longjmp(abort_environ, -1);
299 }
300
301
302 /*
303 ** data_ok checks an error status word for bit patterns
304 ** associated with error conditions from the VDDC controller. If a hardware
305 ** error is present then the problem is reported on the console.
306 ** If a data error is present the a zero is returned.
307 ** If everything is OK then a 1 is returned.
308 */
309
data_ok()310 data_ok()
311 {
312 register int status = dcb.operrsta;
313
314 if(status & HARD_ERROR){
315 vd_error("data transfer");
316 printf(" op = 0x%x\n", dcb.opcode);
317 reset_controller();
318 dcb.operrsta &= HEADER_ERROR;
319 }
320 return (int)(!(status & (DATA_ERROR | HEADER_ERROR)));
321 }
322
vd_error(s)323 vd_error(s)
324 char *s;
325 {
326 register int status = dcb.operrsta;
327
328 print("%s error at sector %d (cyl %d trk %d sect %d),\n",
329 s, to_sector(cur.daddr), dcb.err_cyl & 0xfff, dcb.err_trk,
330 dcb.err_sec);
331 print(" status=%b", dcb.operrsta, VDERRBITS);
332 if (C_INFO->type == VDTYPE_SMDE)
333 printf(", ecode=0x%x", dcb.err_code);
334 printf(".\n");
335 }
336
337
338 /*
339 **
340 */
341
reset_controller()342 reset_controller()
343 {
344 printf("Resetting controller. Please wait...\n");
345 spin_up_drive();
346 printf("Controller was reset successfully.\n");
347 }
348
349 /*
350 **
351 */
352
353 static int indent_count;
354
355
356 /*
357 **
358 */
359
indent()360 indent()
361 {
362 indent_count += 2;
363 }
364
365
366 /*
367 **
368 */
369
exdent(count)370 exdent(count)
371 int count;
372 {
373 if(count == -1)
374 indent_count = 0;
375 else
376 indent_count -= count * 2;
377 if(indent_count < 0)
378 indent_count = 0;
379 }
380
381
382 /*
383 **
384 */
385 /*VARARGS1*/
print(par0,par1,par2,par3,par4,par5,par6)386 print(par0, par1, par2, par3, par4, par5, par6)
387 char *par0, *par1, *par2, *par3, *par4, *par5, *par6;
388 {
389 register int count = indent_count;
390
391 while(count--)
392 printf(" ");
393 printf(par0, par1, par2, par3, par4, par5, par6);
394 DELAY((strlen(par0) + 20) * 9000);
395 }
396