xref: /original-bsd/sys/tahoe/stand/vdformat/io.c (revision 2301fdfb)
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
360 indent()
361 {
362 	indent_count += 2;
363 }
364 
365 
366 /*
367 **
368 */
369 
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*/
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