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