d3588cfd0349e00d0ba10b85b5dbf7590bc9fb96
1 /* s3_disk.c: IBM 5444 Disk Drives
3 Copyright (c) 2001-2005, Charles E. Owen
5 Permission is hereby granted, free of charge, to any person obtaining a
6 copy of this software and associated documentation files (the "Software"),
7 to deal in the Software without restriction, including without limitation
8 the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 and/or sell copies of the Software, and to permit persons to whom the
10 Software is furnished to do so, subject to the following conditions:
12 The above copyright notice and this permission notice shall be included in
13 all copies or substantial portions of the Software.
15 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19 IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 Except as contained in this notice, the name of Charles E. Owen shall not be
23 used in advertising or otherwise to promote the sale, use or other dealings
24 in this Software without prior written authorization from Charles E. Owen.
31 25-Apr-03 RMS Revised for extended file support
32 08-Oct-02 RMS Added impossible function catcher
39 extern int32 IAR
[], level
;
41 extern int32 debug_reg
;
42 char dbuf
[DSK_SECTSIZE
]; /* Disk buffer */
43 int32
dsk (int32 disk
, int32 op
, int32 m
, int32 n
, int32 data
);
44 int32
read_sector(UNIT
*uptr
, char *dbuf
, int32 sect
);
45 int32
write_sector(UNIT
*uptr
, char *dbuf
, int32 sect
);
46 t_stat
r1_svc (UNIT
*uptr
);
47 t_stat
r1_boot (int32 unitno
, DEVICE
*dptr
);
48 t_stat
r1_attach (UNIT
*uptr
, char *cptr
);
49 t_stat
r1_reset (DEVICE
*dptr
);
50 t_stat
f1_svc (UNIT
*uptr
);
51 t_stat
f1_boot (int32 unitno
, DEVICE
*dptr
);
52 t_stat
f1_attach (UNIT
*uptr
, char *cptr
);
53 t_stat
f1_reset (DEVICE
*dptr
);
54 t_stat
r2_svc (UNIT
*uptr
);
55 t_stat
r2_boot (int32 unitno
, DEVICE
*dptr
);
56 t_stat
r2_attach (UNIT
*uptr
, char *cptr
);
57 t_stat
r2_reset (DEVICE
*dptr
);
58 t_stat
f2_svc (UNIT
*uptr
);
59 t_stat
f2_boot (int32 unitno
, DEVICE
*dptr
);
60 t_stat
f2_attach (UNIT
*uptr
, char *cptr
);
61 t_stat
f2_reset (DEVICE
*dptr
);
62 extern int32
GetMem(int32 addr
);
63 extern int32
PutMem(int32 addr
, int32 data
);
65 char opstr
[5][5] = { "SIO", "LIO", "TIO", "SNS", "APL" };
67 int32 DDAR
[2]; /* Data address register */
68 int32 DCAR
[2]; /* Disk Control Address Register */
69 int32 diskerr
[2] = { 0, 0 }; /* Error status */
70 int32 notrdy
[2] = { 0, 0 }; /* Not ready error */
71 int32 seekbusy
[2] = { 0, 0 }; /* Drive busy flags */
72 int32 seekhead
[2] = { 0, 0 }; /* Disk head 0,1 */
73 int32 found
[2] = { 0, 0 }; /* Scan found bit */
74 int32 RIDsect
[2] = { 0, 0 }; /* for Read ID */
76 /* Disk data structures
79 xy_unit CDR unit descriptor
80 xy_reg CDR register list
86 UNIT r1_unit
= { UDATA (&r1_svc
, UNIT_FIX
+UNIT_ATTABLE
, 0), 100 };
89 { FLDATA (NOTRDY
, notrdy
[0], 0) },
90 { FLDATA (SEEK
, seekbusy
[0], 0) },
91 { HRDATA (DAR
, DDAR
[0], 16) },
92 { HRDATA (CAR
, DCAR
[0], 16) },
93 { HRDATA (ERR
, diskerr
[0], 16) },
94 { DRDATA (CYL
, r1_unit
.u3
, 8) },
95 { DRDATA (HEAD
, seekhead
[0], 8) },
96 { DRDATA (POS
, r1_unit
.pos
, T_ADDR_W
), PV_LEFT
},
97 { DRDATA (TIME
, r1_unit
.wait
, 24), PV_LEFT
},
98 { BRDATA (BUF
, dbuf
, 8, 8, 256) },
103 "R1", &r1_unit
, r1_reg
, NULL
,
105 NULL
, NULL
, &r1_reset
,
106 &r1_boot
, &r1_attach
, NULL
109 UNIT f1_unit
= { UDATA (&f1_svc
, UNIT_FIX
+UNIT_ATTABLE
, 0), 100 };
112 { FLDATA (NOTRDY
, notrdy
[0], 0) },
113 { FLDATA (SEEK
, seekbusy
[0], 0) },
114 { HRDATA (DAR
, DDAR
[0], 16) },
115 { HRDATA (CAR
, DCAR
[0], 16) },
116 { HRDATA (ERR
, diskerr
[0], 16) },
117 { DRDATA (CYL
, f1_unit
.u3
, 8) },
118 { DRDATA (HEAD
, seekhead
[0], 8) },
119 { DRDATA (POS
, f1_unit
.pos
, 32), PV_LEFT
},
120 { DRDATA (TIME
, f1_unit
.wait
, 24), PV_LEFT
},
121 { BRDATA (BUF
, dbuf
, 8, 8, 256) },
126 "F1", &f1_unit
, f1_reg
, NULL
,
128 NULL
, NULL
, &f1_reset
,
129 &f1_boot
, &f1_attach
, NULL
132 UNIT r2_unit
= { UDATA (&r2_svc
, UNIT_FIX
+UNIT_ATTABLE
, 0), 100 };
135 { FLDATA (NOTRDY
, notrdy
[1], 0) },
136 { FLDATA (SEEK
, seekbusy
[1], 0) },
137 { HRDATA (DAR
, DDAR
[1], 16) },
138 { HRDATA (CAR
, DCAR
[1], 16) },
139 { HRDATA (ERR
, diskerr
[1], 16) },
140 { DRDATA (CYL
, r2_unit
.u3
, 8) },
141 { DRDATA (HEAD
, seekhead
[1], 8) },
142 { DRDATA (POS
, r2_unit
.pos
, 32), PV_LEFT
},
143 { DRDATA (TIME
, r2_unit
.wait
, 24), PV_LEFT
},
144 { BRDATA (BUF
, dbuf
, 8, 8, 256) },
149 "R2", &r2_unit
, r2_reg
, NULL
,
151 NULL
, NULL
, &r2_reset
,
152 &r2_boot
, &r2_attach
, NULL
155 UNIT f2_unit
= { UDATA (&f2_svc
, UNIT_FIX
+UNIT_ATTABLE
, 0), 100 };
158 { FLDATA (NOTRDY
, notrdy
[1], 0) },
159 { FLDATA (SEEK
, seekbusy
[1], 0) },
160 { HRDATA (DAR
, DDAR
[1], 16) },
161 { HRDATA (CAR
, DCAR
[1], 16) },
162 { HRDATA (ERR
, diskerr
[1], 16) },
163 { DRDATA (CYL
, f2_unit
.u3
, 8) },
164 { DRDATA (HEAD
, seekhead
[1], 8) },
165 { DRDATA (POS
, f2_unit
.pos
, 32), PV_LEFT
},
166 { DRDATA (TIME
, f2_unit
.wait
, 24), PV_LEFT
},
167 { BRDATA (BUF
, dbuf
, 8, 8, 256) },
172 "F2", &f2_unit
, f2_reg
, NULL
,
174 NULL
, NULL
, &f2_reset
,
175 &f2_boot
, &f2_attach
, NULL
178 /* -------------------------------------------------------------------- */
180 /* 5444: master routines */
182 int32
dsk1 (int32 op
, int32 m
, int32 n
, int32 data
)
186 r
= dsk(0, op
, m
, n
, data
);
190 int32
dsk2 (int32 op
, int32 m
, int32 n
, int32 data
)
194 r
= dsk(1, op
, m
, n
, data
);
198 /* 5444: operational routine */
200 int32
dsk (int32 disk
, int32 op
, int32 m
, int32 n
, int32 data
)
202 int32 iodata
, i
, j
, u
, sect
, nsects
, addr
, r
, c
, res
;
203 int32 F
, C
, S
, N
, usave
;
207 if (disk
== 1) u
+= 2;
208 F
= GetMem(DCAR
[disk
]+0); /* Flag bits */
209 C
= GetMem(DCAR
[disk
]+1); /* Cylinder */
210 S
= GetMem(DCAR
[disk
]+2); /* Sector */
211 N
= GetMem(DCAR
[disk
]+3); /* Number of sectors */
228 if (debug_reg
& 0x02)
229 fprintf(trace
, "==> %04X %s %01X,%d,%04X DAR=%04X CAR=%04X C=%02X, S=%02X, N=%02X\n",
241 if ((uptr
->flags
& UNIT_ATT
) == 0)
243 diskerr
[disk
] = 0; /* SIO resets errors */
244 found
[disk
] = 0; /* ... and found bit */
247 case 0x00: /* Seek */
259 if (uptr
-> u3
> 203) {
261 diskerr
[disk
] |= 0x0100;
262 if (debug_reg
& 0x02)
263 fprintf(trace
, "==> Seek Past End of Disk\n");
266 /*sim_activate(uptr, uptr -> wait);*/
267 sim_activate(uptr
, 1);
269 /* Seek arms are the same for both disks on a drive:
270 update the other arm */
273 if (u
== 0) uptr
= f1_dev
.units
;
274 if (u
== 1) uptr
= r1_dev
.units
;
275 if (u
== 2) uptr
= f2_dev
.units
;
276 if (u
== 3) uptr
= r2_dev
.units
;
283 case 0x01: /* Read */
285 case 0: /* Read data */
286 sect
= (S
>> 2) & 0x3F;
290 for (i
= 0; i
< nsects
; i
++) {
291 r
= read_sector(uptr
, dbuf
, sect
);
292 if (r
!= 1 || uptr
->u3
!= C
) {
293 diskerr
[disk
] |= 0x0800;
296 for (j
= 0; j
< DSK_SECTSIZE
; j
++) {
297 PutMem(addr
, dbuf
[j
]);
301 if ((sect
== 55) ) { /* HJS MODS */
304 if (N
> -1) diskerr
[disk
] |= 0x0020; /* end of cyl. */
305 DDAR
[disk
] = addr
& 0xFFFF; /* HJS mod */
306 PutMem(DCAR
[disk
]+2, S
<< 2);
307 PutMem(DCAR
[disk
]+3, N
);
308 sim_activate(uptr
, 1);
319 DDAR
[disk
] = addr
& 0xFFFF; /* HJS mod */
320 PutMem(DCAR
[disk
]+2, S
<< 2);
321 PutMem(DCAR
[disk
]+3, N
);
322 /*sim_activate(uptr, uptr -> wait);*/
323 sim_activate(uptr
, 1);
326 case 1: /* Read ID */
327 if (uptr
-> u3
> 0 && uptr
-> u3
< 4)
328 PutMem(DCAR
[disk
], 1);
330 PutMem(DCAR
[disk
], 0);
331 PutMem(DCAR
[disk
]+1, uptr
-> u3
);
332 PutMem(DCAR
[disk
]+2, RIDsect
[disk
]);
334 if (RIDsect
[disk
] > 23)
336 if (RIDsect
[disk
] > 55)
339 case 2: /* Read Diagnostic */
340 iodata
= STOP_INVDEV
;
343 sect
= (S
>> 2) & 0x3F;
346 for (i
= 0; i
< nsects
; i
++) {
347 r
= read_sector(uptr
, dbuf
, sect
);
348 if (r
!= 1 || uptr
->u3
!= C
) {
349 diskerr
[disk
] |= 0x0800;
352 if ((sect
== 55) ) { /* HJS MODS */
355 if (N
> -1) diskerr
[disk
] |= 0x0020; /* end of cyl. */
356 DDAR
[disk
] = addr
& 0xFFFF;
357 PutMem(DCAR
[disk
]+2, S
<< 2);
358 PutMem(DCAR
[disk
]+3, N
);
359 sim_activate(uptr
, 1);
369 DDAR
[disk
] = addr
& 0xFFFF;
370 PutMem(DCAR
[disk
]+2, S
<< 2);
371 PutMem(DCAR
[disk
]+3, N
);
372 /*sim_activate(uptr, uptr -> wait);*/
373 sim_activate(uptr
, 1);
379 case 0x02: /* Write */
381 case 0: /* Write Data */
382 sect
= (S
>> 2) & 0x3F;
385 for (i
= 0; i
< nsects
; i
++) {
386 for (j
= 0; j
< DSK_SECTSIZE
; j
++) {
387 dbuf
[j
] = GetMem(addr
);
390 r
= write_sector(uptr
, dbuf
, sect
);
391 if (r
!= 1 || uptr
->u3
!= C
) {
392 diskerr
[disk
] |= 0x0400;
395 if ((sect
== 55) ) { /* HJS MODS */
398 if (N
> -1) diskerr
[disk
] |= 0x0020; /* end of cyl. */
399 DDAR
[disk
] = addr
& 0xFFFF;
400 PutMem(DCAR
[disk
]+2, S
<< 2);
401 PutMem(DCAR
[disk
]+3, N
);
402 sim_activate(uptr
, 1);
412 DDAR
[disk
] = addr
& 0xFFFF; /* HJS mod */
413 PutMem(DCAR
[disk
]+2, S
<< 2);
414 PutMem(DCAR
[disk
]+3, N
);
415 /*sim_activate(uptr, uptr -> wait);*/
416 sim_activate(uptr
, 1);
418 case 1: /* Write identifier */
419 if (seekhead
[disk
] == 0)
425 sect
= (S
>> 2) & 0x3F;
428 for (i
= 0; i
< nsects
; i
++) {
429 for (j
= 0; j
< DSK_SECTSIZE
; j
++) {
430 dbuf
[j
] = GetMem(addr
);
432 r
= write_sector(uptr
, dbuf
, sect
);
434 diskerr
[disk
] |= 0x0400;
440 if (N
> 0) diskerr
[disk
] |= 0x0020;
441 DDAR
[disk
] = addr
& 0xFFFF;
442 PutMem(DCAR
[disk
]+2, S
<< 2);
443 PutMem(DCAR
[disk
]+3, N
);
444 sim_activate(uptr
, 1);
454 DDAR
[disk
] = addr
& 0xFFFF;
455 PutMem(DCAR
[disk
]+2, S
<< 2);
456 PutMem(DCAR
[disk
]+3, N
);
457 /*sim_activate(uptr, uptr -> wait);*/
458 sim_activate(uptr
, 1);
464 case 0x03: /* Scan */
465 sect
= (S
>> 2) & 0x3F;
468 for (i
= 0; i
< nsects
; i
++) {
469 r
= read_sector(uptr
, dbuf
, sect
);
470 if (r
!= 1 || uptr
->u3
!= C
) {
471 diskerr
[disk
] |= 0x0800;
475 for (j
= 0; j
< DSK_SECTSIZE
; j
++) {
489 if ((sect
== 55) ) { /* HJS MODS */
492 if (N
> -1) diskerr
[disk
] |= 0x0020; /* end of cyl. */
493 DDAR
[disk
] = addr
& 0xFFFF;
494 PutMem(DCAR
[disk
]+2, S
<< 2);
495 PutMem(DCAR
[disk
]+3, N
);
496 sim_activate(uptr
, 1);
506 PutMem(DCAR
[disk
]+2, S
<< 2);
507 PutMem(DCAR
[disk
]+3, N
);
508 /*sim_activate(uptr, uptr -> wait);*/
509 sim_activate(uptr
, 1);
518 if ((uptr
->flags
& UNIT_ATT
) == 0)
521 case 0x04: /* Data Addr */
524 case 0x06: /* Control Addr */
533 if ((uptr
->flags
& UNIT_ATT
) == 0)
534 return SCPE_UNATT
<< 16;
537 case 0x00: /* Error */
538 if (diskerr
[disk
] || notrdy
[disk
])
540 if ((uptr
-> flags
& UNIT_ATT
) == 0)
543 case 0x02: /* Busy */
544 if (sim_is_active (uptr
))
552 return (STOP_INVDEV
<< 16);
554 return ((SCPE_OK
<< 16) | iodata
);
558 if ((uptr
->flags
& UNIT_ATT
) == 0)
559 return SCPE_UNATT
<< 16;
565 iodata
= diskerr
[disk
];
568 if ((uptr
-> flags
& UNIT_ATT
) == 0)
585 return (STOP_INVDEV
<< 16);
587 iodata
|= ((SCPE_OK
<< 16) & 0xffff0000);
592 if ((uptr
->flags
& UNIT_ATT
) == 0)
593 return SCPE_UNATT
<< 16;
596 case 0x00: /* Error */
597 if (diskerr
[disk
] || notrdy
[disk
])
599 if ((uptr
-> flags
& UNIT_ATT
) == 0)
602 case 0x02: /* Busy */
603 if (sim_is_active (uptr
))
607 return (STOP_INVDEV
<< 16);
609 return ((SCPE_OK
<< 16) | iodata
);
613 printf (">>DSK%d non-existent function %d\n", disk
, op
);
617 /* Disk unit service. If a stacker select is active, copy to the
618 selected stacker. Otherwise, copy to the normal stacker. If the
619 unit is unattached, simply exit.
622 t_stat
r1_svc (UNIT
*uptr
)
627 t_stat
f1_svc (UNIT
*uptr
)
632 t_stat
r2_svc (UNIT
*uptr
)
637 t_stat
f2_svc (UNIT
*uptr
)
646 t_stat
r1_reset (DEVICE
*dptr
)
648 diskerr
[0] = notrdy
[0] = seekbusy
[0] = 0; /* clear indicators */
650 sim_cancel (&r1_unit
); /* clear event */
651 r1_unit
.u3
= 0; /* cylinder 0 */
654 t_stat
f1_reset (DEVICE
*dptr
)
656 diskerr
[0] = notrdy
[0] = seekbusy
[0] = 0; /* clear indicators */
658 sim_cancel (&f1_unit
); /* clear event */
659 f1_unit
.u3
= 0; /* cylinder 0 */
662 t_stat
r2_reset (DEVICE
*dptr
)
664 diskerr
[1] = notrdy
[1] = seekbusy
[1] = 0; /* clear indicators */
666 sim_cancel (&r2_unit
); /* clear event */
667 r2_unit
.u3
= 0; /* cylinder 0 */
670 t_stat
f2_reset (DEVICE
*dptr
)
672 diskerr
[1] = notrdy
[1] = seekbusy
[1] = 0; /* clear indicators */
674 sim_cancel (&f2_unit
); /* clear event */
675 f2_unit
.u3
= 0; /* cylinder 0 */
679 /* Disk unit attach */
681 t_stat
r1_attach (UNIT
*uptr
, char *cptr
)
683 diskerr
[0] = notrdy
[0] = seekbusy
[0] = 0; /* clear status */
685 uptr
-> u3
= 0; /* cylinder 0 */
686 return attach_unit (uptr
, cptr
);
688 t_stat
f1_attach (UNIT
*uptr
, char *cptr
)
690 diskerr
[0] = notrdy
[0] = seekbusy
[0] = 0; /* clear status */
692 uptr
-> u3
= 0; /* cylinder 0 */
693 return attach_unit (uptr
, cptr
);
695 t_stat
r2_attach (UNIT
*uptr
, char *cptr
)
697 diskerr
[1] = notrdy
[1] = seekbusy
[1] = 0; /* clear status */
699 uptr
-> u3
= 0; /* cylinder 0 */
700 return attach_unit (uptr
, cptr
);
702 t_stat
f2_attach (UNIT
*uptr
, char *cptr
)
704 diskerr
[1] = notrdy
[1] = seekbusy
[1] = 0; /* clear status */
706 uptr
-> u3
= 0; /* cylinder 0 */
707 return attach_unit (uptr
, cptr
);
710 /* Bootstrap routine */
712 t_stat
r1_boot (int32 unitno
, DEVICE
*dptr
)
716 read_sector(r1_dev
.units
, dbuf
, 0);
717 for (i
= 0; i
< 256; i
++) {
722 t_stat
f1_boot (int32 unitno
, DEVICE
*dptr
)
726 read_sector(f1_dev
.units
, dbuf
, 0);
727 for (i
= 0; i
< 256; i
++) {
732 t_stat
r2_boot (int32 unitno
, DEVICE
*dptr
)
736 read_sector(r2_dev
.units
, dbuf
, 0);
737 for (i
= 0; i
< 256; i
++) {
742 t_stat
f2_boot (int32 unitno
, DEVICE
*dptr
)
746 read_sector(f2_dev
.units
, dbuf
, 0);
747 for (i
= 0; i
< 256; i
++) {
754 /* Raw Disk Data In/Out */
756 int32
read_sector(UNIT
*uptr
, char *dbuf
, int32 sect
)
758 static int32 rtn
, realsect
;
761 /* calculate real sector no */
766 /* physically read the sector */
767 pos
= DSK_CYLSIZE
* uptr
-> u3
;
768 pos
+= DSK_SECTSIZE
* realsect
;
769 rtn
= fseek(uptr
-> fileref
, pos
, 0);
770 rtn
= fread(dbuf
, DSK_SECTSIZE
, 1, uptr
-> fileref
);
774 int32
write_sector(UNIT
*uptr
, char *dbuf
, int32 sect
)
776 static int32 rtn
, realsect
;
779 /* calculate real sector no */
784 if (uptr
-> u3
== 0 && realsect
== 32)
786 /* physically write the sector */
787 pos
= DSK_CYLSIZE
* uptr
-> u3
;
788 pos
+= DSK_SECTSIZE
* realsect
;
789 rtn
= fseek(uptr
-> fileref
, pos
, 0);
790 rtn
= fwrite(dbuf
, DSK_SECTSIZE
, 1, uptr
-> fileref
);