1 /* pro_rd.c: RD hard drive controller
2 
3    Copyright (c) 1997-2003, Tarik Isani (xhomer@isani.org)
4 
5    This file is part of Xhomer.
6 
7    Xhomer is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License version 2
9    as published by the Free Software Foundation.
10 
11    Xhomer is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15 
16    You should have received a copy of the GNU General Public License
17    along with Xhomer; if not, write to the Free Software
18    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19 */
20 
21 
22 /* TBD:
23 		-check byte enables?
24 		-read verify not implemented
25 */
26 
27 #ifdef PRO
28 #include "pdp11_defs.h"
29 #include <sys/stat.h>
30 #include <unistd.h>
31 
32 
33 char		*pro_rd_dir;
34 char		*pro_rd_file;
35 
36 int		pro_rd_heads = 0;
37 int		pro_rd_cyls = 0;
38 int		pro_rd_secs = 0;
39 
40 LOCAL FILE	*pro_rd_fptr = NULL;
41 
42 LOCAL unsigned char PRO_RD_SECBUF[512];
43 
44 LOCAL int 	pro_rd_secbuf_ptr;
45 
46 LOCAL int	pro_rd_ep;
47 LOCAL int	pro_rd_sec;
48 LOCAL int	pro_rd_cyl;
49 LOCAL int	pro_rd_head;
50 LOCAL int	pro_rd_s2c;
51 LOCAL int	pro_rd_status;
52 
53 /* Known hard drive geometries */
54 
55 #define NUMGEOM	12	/* number of defined geometries */
56 
57 LOCAL const int	pro_rd_geom[NUMGEOM][3] = {{4,  615, 16},	/* RD31 21M */
58 	                                   {4,  615, 17},
59 	                                   {6,  820, 16},	/* RD32 43M */
60 	                                   {6,  820, 17},
61 	                                   {4,  153, 16},	/* RD50 5M */
62 	                                   {4,  153, 17},
63 	                                   {4,  306, 16},	/* RD51 10M */
64 	                                   {4,  306, 17},
65 	                                   {8,  512, 16},	/* RD52 36M */
66 	                                   {8,  512, 17},
67 	                                   {8, 1024, 16},	/* RD53 71M */
68 	                                   {8, 1024, 17}};
69 
70 
71 /* Trigger interrupt A */
72 
pro_rd_inta()73 LOCAL void pro_rd_inta ()
74 {
75 	/* Signal end of operation */
76 
77 	pro_rd_status = pro_rd_status | PRO_RD_OPENDED;
78 
79 	/* XXX use better int name */
80 
81 	pro_int_set(PRO_INT_0A);
82 }
83 
84 
85 /* Trigger interrupt B */
86 
pro_rd_intb()87 LOCAL void pro_rd_intb ()
88 {
89 	/* Set DRQ bits */
90 
91 	pro_rd_status = pro_rd_status | PRO_RD_DRQ;
92 	pro_rd_s2c = pro_rd_s2c | PRO_RD_DATAREQ;
93 
94 	/* XXX use better int name */
95 
96 	pro_int_set(PRO_INT_0B);
97 }
98 
99 
100 /* Signal error condition */
101 
pro_rd_error()102 LOCAL void pro_rd_error ()
103 {
104 	pro_rd_status = pro_rd_status & (~PRO_RD_BUSY);
105 	pro_rd_s2c = pro_rd_s2c | PRO_RD_ERROR;
106 
107 	/* XXX Currently only handles sector not found errors */
108 
109 	pro_rd_ep = pro_rd_ep | PRO_RD_IDNF;
110 
111 	/* XXX is this ok? */
112 
113 	pro_rd_inta();
114 }
115 
116 
117 /* Event scheduler */
118 
pro_rd_sched()119 LOCAL void pro_rd_sched ()
120 {
121 	/* A 4-5 instruction delay is needed to pass diagnostics */
122 
123 	pro_eq_sched(PRO_EVENT_RD, PRO_EQ_RD);
124 }
125 
126 /* Event queue handler */
127 
pro_rd_eq()128 void pro_rd_eq ()
129 {
130 	/* Trigger interrupt */
131 
132 	pro_rd_intb();
133 }
134 
135 
136 /* RD registers */
137 
pro_rd_rd(int pa)138 int pro_rd_rd (int pa)
139 {
140 int	data;
141 
142 	switch (pa & 017777776)
143 	{
144 	  case 017774000:
145 	    data = PRO_ID_RD;
146 	    break;
147 
148 	  case 017774004:
149 	    data = pro_rd_ep;
150 	    break;
151 
152 	  case 017774006:
153 	    data = pro_rd_sec;
154 	    break;
155 
156 	  case 017774010:
157 	    data = PRO_RD_SECBUF[pro_rd_secbuf_ptr+1] * 256
158 	           + PRO_RD_SECBUF[pro_rd_secbuf_ptr];
159 
160 	    if ((pro_rd_status & PRO_RD_DRQ) != 0)
161 	    {
162 	      if (pro_rd_secbuf_ptr < 510)
163 	      {
164 	        pro_rd_secbuf_ptr += 2;
165 
166 	        /* Trigger interrupt for next transfer */
167 
168 	        pro_rd_intb();
169 	      }
170 	      else
171 	      {
172 	        /* Reset data request bits */
173 
174 	        pro_rd_status = pro_rd_status & (~PRO_RD_DRQ);
175 	        pro_rd_s2c = pro_rd_s2c & (~PRO_RD_DATAREQ);
176 
177 	        /* Signal end of operation */
178 
179 	        pro_rd_inta();
180 	      }
181 	    }
182 
183 	    break;
184 
185 	  case 017774012:
186 	    data = pro_rd_cyl;
187 	    break;
188 
189 	  case 017774014:
190 	    data = pro_rd_head;
191 	    break;
192 
193 	  case 017774016:
194 	    data = pro_rd_s2c;
195 
196 	    /* XXX should OPENDED really be cleared? */
197 
198 	    pro_rd_status = pro_rd_status & (~PRO_RD_OPENDED);
199 
200 	    break;
201 
202 	  case 017774020:
203 	    data = pro_rd_status;
204 	    break;
205 
206 	  default:
207 	    data = 0;
208 	    break;
209 	}
210 
211 	return data;
212 }
213 
pro_rd_wr(int data,int pa,int access)214 void pro_rd_wr (int data, int pa, int access)
215 {
216 int	i, head, cyl, sec, offset;
217 
218 	switch (pa & 017777776)
219 	{
220 	  case 017774004:
221 	    WRITE_W(pro_rd_ep, PRO_RD_EP_W);
222 	    break;
223 
224 	  case 017774006:
225 	    WRITE_W(pro_rd_sec, PRO_RD_SEC_W);
226 	    break;
227 
228 	  case 017774010:
229 	    if ((pro_rd_status & PRO_RD_DRQ) != 0)
230 	    {
231 	      PRO_RD_SECBUF[pro_rd_secbuf_ptr] = data & 0377;
232 	      PRO_RD_SECBUF[pro_rd_secbuf_ptr+1] = (data & 0177400) >> 8;
233 
234 	      if (pro_rd_secbuf_ptr < 510)
235 	      {
236 	        pro_rd_secbuf_ptr += 2;
237 
238 	        /* Trigger interrupt for next transfer */
239 
240 	        pro_rd_intb();
241 	      }
242 	      else
243 	      {
244 	        /* Perform write or format command */
245 
246 	        head = pro_rd_head;
247 
248 	        cyl = pro_rd_cyl;
249 
250 	        sec = pro_rd_sec & PRO_RD_SEC;
251 
252 	        switch (pro_rd_s2c & PRO_RD_CMD)
253 	        {
254 	          case PRO_RD_CMD_FORMAT:
255 	            offset = (cyl * pro_rd_heads * pro_rd_secs + head * pro_rd_secs) * 512;
256 
257 	            fseek(pro_rd_fptr, offset, 0);
258 
259 	            /* Use last character of secbuf as padding character */
260 
261 	            for(i=0; i<(512*pro_rd_secs); i++)
262 	              putc(PRO_RD_SECBUF[511], pro_rd_fptr);
263 
264 	            fflush(pro_rd_fptr);
265 
266 	            break;
267 
268 	          case PRO_RD_CMD_WRITE:
269 	            offset = (cyl * pro_rd_heads * pro_rd_secs + head * pro_rd_secs + sec) * 512;
270 
271 	            fseek(pro_rd_fptr, offset, 0);
272 
273 	            for(i=0; i<512; i+=2)
274 	            {
275 	              putc(PRO_RD_SECBUF[i], pro_rd_fptr);
276 	              putc(PRO_RD_SECBUF[i+1], pro_rd_fptr);
277 	            }
278 
279 	            fflush(pro_rd_fptr);
280 
281 	            break;
282 
283 	          default:
284 	            break;
285 	        }
286 
287 	        /* Reset data request bits */
288 
289 	        pro_rd_status = pro_rd_status & (~PRO_RD_DRQ);
290 	        pro_rd_s2c = pro_rd_s2c & (~PRO_RD_DATAREQ);
291 
292 	        /* Signal end of operation */
293 
294 	        pro_rd_inta();
295 	      }
296 	    }
297 
298 	    break;
299 
300 	  case 017774012:
301 	    WRITE_W(pro_rd_cyl, PRO_RD_CYL_W);
302 	    break;
303 
304 	  case 017774014:
305 	    WRITE_W(pro_rd_head, PRO_RD_HEAD_W);
306 	    break;
307 
308 	  case 017774016:
309 	    WRITE_W(pro_rd_s2c, PRO_RD_S2C_W);
310 
311 	    head = pro_rd_head;
312 
313 	    cyl = pro_rd_cyl;
314 
315 	    sec = pro_rd_sec & PRO_RD_SEC;
316 
317 	    offset = (cyl * pro_rd_heads * pro_rd_secs + head * pro_rd_secs + sec) * 512;
318 
319 	    /* Clear error conditions */
320 
321 	    pro_rd_s2c = pro_rd_s2c & (~PRO_RD_ERROR);
322 	    pro_rd_ep = pro_rd_ep & (~PRO_RD_ERRORS);
323 
324 	    /* Clear data transfer requests */
325 
326 	    pro_rd_s2c = pro_rd_s2c & (~PRO_RD_DATAREQ);
327 	    pro_rd_status = pro_rd_status & (~PRO_RD_DRQ);
328 
329 	    /* Clear operation ended bit */
330 
331 	    pro_rd_status = pro_rd_status & (~PRO_RD_OPENDED);
332 
333 	    /* Execute command */
334 
335 	    switch (pro_rd_s2c & PRO_RD_CMD)
336 	    {
337 	      case PRO_RD_CMD_RESTORE:
338 /* XXX
339 	        printf("RD restore command\r\n");
340 */
341 
342 	        /* Set operation ended bit */
343 
344 	        pro_rd_inta();
345 
346 	        break;
347 
348 	      case PRO_RD_CMD_READ:
349 /* XXX
350 	        printf("RD read  head = %d cyl = %d sec = %d\r\n", pro_rd_head, pro_rd_cyl, pro_rd_sec);
351 */
352 
353 	        if ((head >= pro_rd_heads) || (cyl >= pro_rd_cyls) || (sec >= pro_rd_secs))
354 	          pro_rd_error();
355 	        else
356 	        {
357 	          fseek(pro_rd_fptr, offset, 0);
358 
359 	          for(i=0; i<512; i++)
360 	            PRO_RD_SECBUF[i] = getc(pro_rd_fptr);
361 
362 	          pro_rd_secbuf_ptr = 0;
363 
364 	          /* Schedule first DRQ */
365 
366 	          pro_rd_sched();
367 	        }
368 	        break;
369 
370 	      case PRO_RD_CMD_WRITE:
371 /* XXX
372 	        printf("RD write  head = %d cyl = %d sec = %d\r\n", pro_rd_head, pro_rd_cyl, pro_rd_sec);
373 */
374 
375 	        if ((head >= pro_rd_heads) || (cyl >= pro_rd_cyls) || (sec >= pro_rd_secs))
376 	          pro_rd_error();
377 	        else
378 	        {
379 	          pro_rd_secbuf_ptr = 0;
380 
381 	          /* Trigger first DRQ interrupt */
382 
383 	          pro_rd_intb();
384 	        }
385 
386 	        break;
387 
388 	      case PRO_RD_CMD_FORMAT:
389 /* XXX
390 	        printf("RD format  head = %d cyl = %d\r\n", pro_rd_head, pro_rd_cyl);
391 */
392 
393 	        if ((head >= pro_rd_heads) || (cyl >= pro_rd_cyls))
394 	          pro_rd_error();
395 	        else
396 	        {
397 	          pro_rd_secbuf_ptr = 0;
398 
399 	          /* Trigger first DRQ interrupt */
400 
401 	          pro_rd_intb();
402 	        }
403 	        break;
404 
405 	      default:
406 	        printf("RD illegal command\r\n");
407 	        break;
408 	    }
409 
410 	    break;
411 
412 	  case 017774020:
413 	    /* XXX watch for reset command */
414 
415 	    break;
416 
417 	  default:
418 	    break;
419 	}
420 }
421 
pro_rd_reset()422 void pro_rd_reset ()
423 {
424 struct stat	statbuf;
425 int		i, fsize, gfound;
426 char		*fname;
427 
428 
429 	/* Construct filename */
430 
431 	fname = malloc(strlen(pro_rd_dir) + strlen(pro_rd_file) + 1);
432 	strcpy(fname, pro_rd_dir);
433 	strcat(fname, pro_rd_file);
434 
435 	/* Clear 512-byte sector buffer */
436 
437         memset(&PRO_RD_SECBUF, 0, sizeof(PRO_RD_SECBUF));
438 
439 	/* Open disk image file */
440 
441         if (pro_rd_fptr) fclose(pro_rd_fptr);
442 	pro_rd_fptr = fopen(fname, "r+");
443 
444 	gfound = 0;
445 
446 	if (pro_rd_fptr == NULL)
447 	  printf("Unable to open rd image %s\n", fname);
448 	else
449 	{
450 	  /* Get filesize */
451 
452 	  stat(fname, &statbuf);
453 
454 	  fsize = (int)statbuf.st_size;
455 
456 	  /* Check if geometry was forced in config file */
457 
458 	  if ((pro_rd_heads != 0) || (pro_rd_cyls != 0) || (pro_rd_secs != 0))
459 	  {
460 	    if (pro_rd_heads*pro_rd_cyls*pro_rd_secs*512 == fsize)
461 	      gfound = 1;
462 	    else
463 	      printf("Geometry %d %d %d does not match rd filesize %d\n",
464 	              pro_rd_heads, pro_rd_cyls, pro_rd_secs, fsize);
465 	  }
466 	  else
467 
468 	  /* Scan geometry table for a match */
469 
470 	  {
471 	    for(i=0; i<NUMGEOM; i++)
472 	      if (pro_rd_geom[i][0]*pro_rd_geom[i][1]
473 	          *pro_rd_geom[i][2]*512 == fsize)
474 	      {
475 	        pro_rd_heads = pro_rd_geom[i][0];
476 	        pro_rd_cyls = pro_rd_geom[i][1];
477 	        pro_rd_secs = pro_rd_geom[i][2];
478 	        gfound = 1;
479 	        break;
480 	      }
481 
482 	    if (gfound == 0)
483 	      printf("Unable to determine rd geometry for filesize %d bytes\n", fsize);
484 	  }
485 
486 	  /* Close image file if geometry does not match filesize */
487 
488 	  if (gfound == 0)
489 	    fclose(pro_rd_fptr);
490 	}
491 
492 	if (gfound == 0)
493 	{
494 	  pro_rd_heads = 0;
495 	  pro_rd_cyls = 0;
496 	  pro_rd_secs = 0;
497 	}
498 
499 	pro_rd_secbuf_ptr = 0;
500 
501 	pro_rd_ep = 0;
502 	pro_rd_sec = 0;
503 	pro_rd_cyl = 0;
504 	pro_rd_head = 0;
505 	pro_rd_s2c = PRO_RD_DRDY | PRO_RD_SEEKC; /* XXX plus SEEKC? */
506 	pro_rd_status = PRO_RD_OPENDED;
507 
508 	free(fname);
509 }
510 
511 
512 /* Exit routine */
513 
pro_rd_exit()514 void pro_rd_exit ()
515 {
516         if (pro_rd_fptr!=NULL)
517         {
518           fclose(pro_rd_fptr);
519           pro_rd_fptr = NULL;
520 	}
521 }
522 #endif
523